File: CommonDialog.sml

package info (click to toggle)
polyml 5.8.1-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 57,736 kB
  • sloc: cpp: 44,918; ansic: 26,921; asm: 13,495; sh: 4,670; makefile: 610; exp: 525; python: 253; awk: 91
file content (1533 lines) | stat: -rw-r--r-- 62,415 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
(*
    Copyright (c) 2001, 2015, 2019
        David C.J. Matthews

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License version 2.1 as published by the Free Software Foundation.
    
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.
    
    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*)
(* Common dialogues. *)
structure CommonDialog :
  sig
    type HWND and HDC and COLORREF = Color.COLORREF and HINSTANCE
    type POINT = { x: int, y: int }
    type RECT =  { left: int, top: int, right: int, bottom: int }

    (* Error codes *)
    datatype CDERR =
            DIALOGFAILURE
        |   GENERALCODES
        |   STRUCTSIZE
        |   INITIALIZATION
        |   NOTEMPLATE
        |   NOHINSTANCE
        |   LOADSTRFAILURE
        |   FINDRESFAILURE
        |   LOADRESFAILURE
        |   LOCKRESFAILURE
        |   MEMALLOCFAILURE
        |   MEMLOCKFAILURE
        |   NOHOOK
        |   REGISTERMSGFAIL

        |   PRINTERCODES
        |   SETUPFAILURE
        |   PARSEFAILURE
        |   RETDEFFAILURE
        |   LOADDRVFAILURE
        |   GETDEVMODEFAIL
        |   INITFAILURE
        |   NODEVICES
        |   NODEFAULTPRN
        |   DNDMMISMATCH
        |   CREATEICFAILURE
        |   PRINTERNOTFOUND
        |   DEFAULTDIFFERENT

        |   CHOOSEFONTCODES
        |   NOFONTS
        |   MAXLESSTHANMIN

        |   FILENAMECODES
        |   SUBCLASSFAILURE
        |   INVALIDFILENAME
        |   BUFFERTOOSMALL

        |   FINDREPLACECODES
        |   BUFFERLENGTHZERO

        |   CHOOSECOLORCODES

    val CommDlgExtendedError : unit -> CDERR

    (* ChooseColor *)
(*
    structure ChooseColorFlags :
      sig
        include BIT_FLAGS
        val CC_ANYCOLOR : flags
        val CC_FULLOPEN : flags
        val CC_PREVENTFULLOPEN : flags
        val CC_RGBINIT : flags
        val CC_SHOWHELP : flags
        val CC_SOLIDCOLOR : flags
      end

    type CHOOSECOLOR =
    {
        owner: HWND option,
        result: COLORREF,
        customColors: COLORREF list,
        flags: ChooseColorFlags.flags
    }

    val ChooseColor : CHOOSECOLOR -> CHOOSECOLOR option


    (* ChooseFont *)

    structure ChooseFontFlags :
      sig
        include BIT_FLAGS
        val CF_ANSIONLY : flags
        val CF_APPLY : flags
        val CF_BOTH : flags
        val CF_EFFECTS : flags
        val CF_FIXEDPITCHONLY : flags
        val CF_FORCEFONTEXIST : flags
        val CF_NOFACESEL : flags
        val CF_NOOEMFONTS : flags
        val CF_NOSCRIPTSEL : flags
        val CF_NOSIMULATIONS : flags
        val CF_NOSIZESEL : flags
        val CF_NOSTYLESEL : flags
        val CF_NOVECTORFONTS : flags
        val CF_NOVERTFONTS : flags
        val CF_PRINTERFONTS : flags
        val CF_SCALABLEONLY : flags
        val CF_SCREENFONTS : flags
        val CF_SCRIPTSONLY : flags
        val CF_SELECTSCRIPT : flags
        val CF_SHOWHELP : flags
        val CF_TTONLY : flags
        val CF_WYSIWYG : flags
      end

    structure ChooseFontTypes :
      sig
        include BIT_FLAGS
        val BOLD_FONTTYPE : flags
        val ITALIC_FONTTYPE : flags
        val PRINTER_FONTTYPE : flags
        val REGULAR_FONTTYPE : flags
        val SCREEN_FONTTYPE : flags
        val SIMULATED_FONTTYPE : flags
      end

    type CHOOSEFONT =
    {
        owner: HWND option,
        context: HDC option,
        logFont: Font.LOGFONT option,
        pointSize: int,
        flags: ChooseFontFlags.flags,
        colors: COLORREF,
        style: string option,
        fontType: ChooseFontTypes.flags,
        size: {min: int, max: int} option
    }

    val ChooseFont : CHOOSEFONT -> CHOOSEFONT option
    *)

    (* FindText and ReplaceText *)
    structure FindReplaceFlags :
      sig
        include BIT_FLAGS
        val FR_DIALOGTERM : flags
        val FR_DOWN : flags
        val FR_FINDNEXT : flags
        val FR_HIDEMATCHCASE : flags
        val FR_HIDEUPDOWN : flags
        val FR_HIDEWHOLEWORD : flags
        val FR_MATCHCASE : flags
        val FR_NOMATCHCASE : flags
        val FR_NOUPDOWN : flags
        val FR_NOWHOLEWORD : flags
        val FR_REPLACE : flags
        val FR_REPLACEALL : flags
        val FR_SHOWHELP : flags
        val FR_WHOLEWORD : flags
      end

    datatype
      TemplateType =
          TemplateDefault
        | TemplateHandle of Dialog.DLGTEMPLATE
        | TemplateResource of HINSTANCE * Resource.RESID

    type FINDREPLACE =
    {
        owner : HWND,
        template: TemplateType,
        flags: FindReplaceFlags.flags,
        findWhat: string,
        replaceWith: string,
        bufferSize: int
    }

    val FindText : FINDREPLACE -> HWND
    val ReplaceText : FINDREPLACE -> HWND
 

    (* GetOpenFileName and GetSaveFileName *)

    structure OpenFileFlags :
      sig
        include BIT_FLAGS
        val OFN_ALLOWMULTISELECT : flags
        val OFN_CREATEPROMPT : flags
        val OFN_EXPLORER : flags
        val OFN_EXTENSIONDIFFERENT : flags
        val OFN_FILEMUSTEXIST : flags
        val OFN_HIDEREADONLY : flags
        val OFN_LONGNAMES : flags
        val OFN_NOCHANGEDIR : flags
        val OFN_NODEREFERENCELINKS : flags
        val OFN_NOLONGNAMES : flags
        val OFN_NONETWORKBUTTON : flags
        val OFN_NOREADONLYRETURN : flags
        val OFN_NOTESTFILECREATE : flags
        val OFN_NOVALIDATE : flags
        val OFN_OVERWRITEPROMPT : flags
        val OFN_PATHMUSTEXIST : flags
        val OFN_READONLY : flags
        val OFN_SHAREAWARE : flags
        val OFN_SHOWHELP : flags
      end

    type OPENFILENAME =
    {
        owner: HWND option,
        template: TemplateType,
        filter: (string * string) list,
        customFilter: (string * string) option,
        filterIndex: int,
        file: string,   (* Initial value of file and returned result. *)
        maxFile: int,   (* Max size of expected file name. *)
        fileTitle : string,
        initialDir: string option,
        title: string option, (* Optional title - default is Save or Open. *)
        flags: OpenFileFlags.flags,
        defExt: string option
    }

    val GetFileTitle : string -> string
    val GetOpenFileName : OPENFILENAME -> OPENFILENAME option
    val GetSaveFileName : OPENFILENAME -> OPENFILENAME option

    (* PageSetupDlg *)
    structure PageSetupFlags :
      sig
        include BIT_FLAGS
        val PSD_DEFAULTMINMARGINS : flags
        val PSD_DISABLEMARGINS : flags
        val PSD_DISABLEORIENTATION : flags
        val PSD_DISABLEPAGEPAINTING : flags
        val PSD_DISABLEPAPER : flags
        val PSD_DISABLEPRINTER : flags
        val PSD_INHUNDREDTHSOFMILLIMETERS : flags
        val PSD_INTHOUSANDTHSOFINCHES : flags
        val PSD_MARGINS : flags
        val PSD_MINMARGINS : flags
        val PSD_NONETWORKBUTTON : flags
        val PSD_NOWARNING : flags
        val PSD_RETURNDEFAULT : flags
        val PSD_SHOWHELP : flags
      end

    type PAGESETUPDLG =
    {
        owner: HWND option,
        devMode: DeviceContext.DEVMODE option,
        devNames: DeviceContext.DEVNAMES option,
        flags: PageSetupFlags.flags,
        paperSize: POINT,
        minMargin: RECT,
        margin: RECT
        (* For the moment we ignore the other options. *)
    }

    val PageSetupDlg : PAGESETUPDLG -> PAGESETUPDLG option

    (* PrintDlg *)
    structure PrintDlgFlags :
      sig
        include BIT_FLAGS
        val PD_ALLPAGES : flags
        val PD_COLLATE : flags
        val PD_DISABLEPRINTTOFILE : flags
        val PD_HIDEPRINTTOFILE : flags
        val PD_NONETWORKBUTTON : flags
        val PD_NOPAGENUMS : flags
        val PD_NOSELECTION : flags
        val PD_NOWARNING : flags
        val PD_PAGENUMS : flags
        val PD_PRINTSETUP : flags
        val PD_PRINTTOFILE : flags
        val PD_RETURNDC : flags
        val PD_RETURNDEFAULT : flags
        val PD_RETURNIC : flags
        val PD_SELECTION : flags
        val PD_SHOWHELP : flags
        val PD_USEDEVMODECOPIES : flags
        val PD_USEDEVMODECOPIESANDCOLLATE : flags
     end

    type PRINTDLG =
    {
        owner: HWND option,
        devMode: DeviceContext.DEVMODE option,
        devNames: DeviceContext.DEVNAMES option,
        context: HDC option,
        flags: PrintDlgFlags.flags,
        fromPage: int,
        toPage: int,
        minPage: int,
        maxPage: int,
        copies: int
        (* For the moment we ignore the other options. *)
    }

    val PrintDlg : PRINTDLG -> PRINTDLG option
  end
 =
struct
    local
        open Foreign
        open Globals
        open Base
        open DeviceContext Color Font GdiBase
        
        val stringToBuf = copyStringToMem

        fun allocAndInitialise(space: int, str: string) =
        let
            open Memory
            val space = Int.max(space, size str) + 1
            val buf = malloc(Word.fromInt space)
        in
            stringToBuf(buf, 0, str);
            buf
        end

    in
        type HWND = HWND and HDC = HDC and COLORREF = COLORREF and HINSTANCE = HINSTANCE
        type RECT = RECT and POINT = POINT

        datatype CDERR =
            DIALOGFAILURE    (* 0xffff *)
        |   GENERALCODES     (* 0x0000 *)
        |   STRUCTSIZE       (* 0x0001 *)
        |   INITIALIZATION   (* 0x0002 *)
        |   NOTEMPLATE       (* 0x0003 *)
        |   NOHINSTANCE      (* 0x0004 *)
        |   LOADSTRFAILURE   (* 0x0005 *)
        |   FINDRESFAILURE   (* 0x0006 *)
        |   LOADRESFAILURE   (* 0x0007 *)
        |   LOCKRESFAILURE   (* 0x0008 *)
        |   MEMALLOCFAILURE  (* 0x0009 *)
        |   MEMLOCKFAILURE   (* 0x000A *)
        |   NOHOOK           (* 0x000B *)
        |   REGISTERMSGFAIL  (* 0x000C *)

        |   PRINTERCODES     (* 0x1000 *)
        |   SETUPFAILURE     (* 0x1001 *)
        |   PARSEFAILURE     (* 0x1002 *)
        |   RETDEFFAILURE    (* 0x1003 *)
        |   LOADDRVFAILURE   (* 0x1004 *)
        |   GETDEVMODEFAIL   (* 0x1005 *)
        |   INITFAILURE      (* 0x1006 *)
        |   NODEVICES        (* 0x1007 *)
        |   NODEFAULTPRN     (* 0x1008 *)
        |   DNDMMISMATCH     (* 0x1009 *)
        |   CREATEICFAILURE  (* 0x100A *)
        |   PRINTERNOTFOUND  (* 0x100B *)
        |   DEFAULTDIFFERENT (* 0x100C *)

        |   CHOOSEFONTCODES  (* 0x2000 *)
        |   NOFONTS          (* 0x2001 *)
        |   MAXLESSTHANMIN   (* 0x2002 *)

        |   FILENAMECODES    (* 0x3000 *)
        |   SUBCLASSFAILURE  (* 0x3001 *)
        |   INVALIDFILENAME  (* 0x3002 *)
        |   BUFFERTOOSMALL   (* 0x3003 *)

        |   FINDREPLACECODES (* 0x4000 *)
        |   BUFFERLENGTHZERO (* 0x4001 *)

        |   CHOOSECOLORCODES (* 0x5000 *)


        local
            val commDlgExtendedError = winCall0 (commdlg "CommDlgExtendedError") () cDWORD
        in
            fun CommDlgExtendedError () =
                case commDlgExtendedError () of
                    0x0000  => GENERALCODES
                |   0x0001  => STRUCTSIZE
            
                |   0x0002  => INITIALIZATION
                |   0x0003  => NOTEMPLATE
                |   0x0004  => NOHINSTANCE
                |   0x0005  => LOADSTRFAILURE
                |   0x0006  => FINDRESFAILURE
                |   0x0007  => LOADRESFAILURE
                |   0x0008  => LOCKRESFAILURE
                |   0x0009  => MEMALLOCFAILURE
                |   0x000A  => MEMLOCKFAILURE
                |   0x000B  => NOHOOK
                |   0x000C  => REGISTERMSGFAIL
            
                |   0x1000  => PRINTERCODES
                |   0x1001  => SETUPFAILURE
                |   0x1002  => PARSEFAILURE
                |   0x1003  => RETDEFFAILURE
                |   0x1004  => LOADDRVFAILURE
                |   0x1005  => GETDEVMODEFAIL
                |   0x1006  => INITFAILURE
                |   0x1007  => NODEVICES
                |   0x1008  => NODEFAULTPRN
                |   0x1009  => DNDMMISMATCH
                |   0x100A  => CREATEICFAILURE
                |   0x100B  => PRINTERNOTFOUND
                |   0x100C  => DEFAULTDIFFERENT
            
                |   0x2000  => CHOOSEFONTCODES
                |   0x2001  => NOFONTS
                |   0x2002  => MAXLESSTHANMIN
            
                |   0x3000  => FILENAMECODES
                |   0x3001  => SUBCLASSFAILURE
                |   0x3002  => INVALIDFILENAME
                |   0x3003  => BUFFERTOOSMALL
            
                |   0x4000  => FINDREPLACECODES
                |   0x4001  => BUFFERLENGTHZERO
                |   _       => DIALOGFAILURE
        end;

        (* As always there are a number of ways of matching the C types to
           ML.  Since functions such as GetOpenFileName update their
           parameters, probably the easiest way to deal with them is
           as functions which return an updated parameter set. *)
        datatype TemplateType =
            TemplateHandle of Dialog.DLGTEMPLATE
        |   TemplateResource of HINSTANCE * Resource.RESID
        |   TemplateDefault

        structure OpenFileFlags:>
          sig
            include BIT_FLAGS
            val OFN_ALLOWMULTISELECT : flags
            val OFN_CREATEPROMPT : flags
            val OFN_EXPLORER : flags
            val OFN_EXTENSIONDIFFERENT : flags
            val OFN_FILEMUSTEXIST : flags
            val OFN_HIDEREADONLY : flags
            val OFN_LONGNAMES : flags
            val OFN_NOCHANGEDIR : flags
            val OFN_NODEREFERENCELINKS : flags
            val OFN_NOLONGNAMES : flags
            val OFN_NONETWORKBUTTON : flags
            val OFN_NOREADONLYRETURN : flags
            val OFN_NOTESTFILECREATE : flags
            val OFN_NOVALIDATE : flags
            val OFN_OVERWRITEPROMPT : flags
            val OFN_PATHMUSTEXIST : flags
            val OFN_READONLY : flags
            val OFN_SHAREAWARE : flags
            val OFN_SHOWHELP : flags
            
            val cConvert: flags conversion
          end
        =
        struct
            open Word32
            type flags = word
            val toWord = toLargeWord
            and fromWord = fromLargeWord
            val flags = List.foldl (fn (a, b) => orb(a,b)) 0w0
            fun allSet (fl1, fl2) = andb(fl1, fl2) = fl1
            fun anySet (fl1, fl2) = andb(fl1, fl2) <> 0w0
            fun clear (fl1, fl2) = andb(notb fl1, fl2)
    
            val OFN_READONLY                 = 0wx00000001
            val OFN_OVERWRITEPROMPT          = 0wx00000002
            val OFN_HIDEREADONLY             = 0wx00000004
            val OFN_NOCHANGEDIR              = 0wx00000008
            val OFN_SHOWHELP                 = 0wx00000010
            val OFN_NOVALIDATE               = 0wx00000100
            val OFN_ALLOWMULTISELECT         = 0wx00000200
            val OFN_EXTENSIONDIFFERENT       = 0wx00000400
            val OFN_PATHMUSTEXIST            = 0wx00000800
            val OFN_FILEMUSTEXIST            = 0wx00001000
            val OFN_CREATEPROMPT             = 0wx00002000
            val OFN_SHAREAWARE               = 0wx00004000
            val OFN_NOREADONLYRETURN         = 0wx00008000
            val OFN_NOTESTFILECREATE         = 0wx00010000
            val OFN_NONETWORKBUTTON          = 0wx00020000
            val OFN_NOLONGNAMES              = 0wx00040000 (* force no long names for 4.x modules*)
            val OFN_EXPLORER                 = 0wx00080000 (* new look commdlg*)
            val OFN_NODEREFERENCELINKS       = 0wx00100000
            val OFN_LONGNAMES                = 0wx00200000 (* force long names for 3.x modules*)
    
            val all = flags[OFN_READONLY, OFN_OVERWRITEPROMPT, OFN_HIDEREADONLY,
                            OFN_NOCHANGEDIR, OFN_SHOWHELP,
                            OFN_NOVALIDATE, OFN_ALLOWMULTISELECT, OFN_EXTENSIONDIFFERENT,
                            OFN_PATHMUSTEXIST, OFN_FILEMUSTEXIST, OFN_CREATEPROMPT,
                            OFN_SHAREAWARE, OFN_NOREADONLYRETURN, OFN_NOTESTFILECREATE,
                            OFN_NONETWORKBUTTON, OFN_NOLONGNAMES, OFN_EXPLORER,
                            OFN_NODEREFERENCELINKS, OFN_LONGNAMES]
    
            val intersect = List.foldl (fn (a, b) => andb(a,b)) all
            
            val cConvert = cDWORDw
        end

        (* These flags are local only. *)
        (*val OFN_ENABLEHOOK               = OpenFileFlags.fromWord 0wx00000020 *)
        val OFN_ENABLETEMPLATE           = OpenFileFlags.fromWord 0wx00000040
        val OFN_ENABLETEMPLATEHANDLE     = OpenFileFlags.fromWord 0wx00000080

        type OPENFILENAME =
        {
            owner: HWND option,
            template: TemplateType,
            filter: (string * string) list,
            customFilter: (string * string) option,
            filterIndex: int,
            file: string,   (* Initial value of file and returned result. *)
            maxFile: int,   (* Max size of expected file name. *)
            fileTitle : string,
            initialDir: string option,
            title: string option, (* Optional title - default is Save or Open. *)
            flags: OpenFileFlags.flags,
            defExt: string option
        }

        local
            val OPENFILENAME =
                cStruct20(cDWORD, cHWNDOPT, cPointer (*HINSTANCE*), cPointer (* LPCTSTR*), cPointer (*LPTSTR*),
                    cDWORD, cDWORD, cPointer (*LPTSTR*), cDWORD, cPointer (*LPTSTR*), cDWORD, STRINGOPT, STRINGOPT,
                    OpenFileFlags.cConvert, cWORD, cWORD, STRINGOPT, cLPARAM, cPointer (* LPOFNHOOKPROC *),
                    cPointer (* LPCTSTR*) (* cPointer, DWORD, DWORD*))
            val {load=loadOFN, store=fromOFN, ctype={size=sizeOfnStruct, ...}, ...} = breakConversion OPENFILENAME

            fun getOpenSave doCall (arg: OPENFILENAME): OPENFILENAME option =
            let
                val {
                    owner: HWND option,
                    template: TemplateType,
                    filter: (string * string) list,
                    customFilter: (string * string) option,
                    filterIndex: int,
                    file: string,
                    maxFile: int,
                    fileTitle : string,
                    initialDir: string option,
                    title: string option,
                    flags: OpenFileFlags.flags,
                    defExt: string option, ...} = arg
                open Memory
                infix 6 ++
                val (f1, inst, templ, toFree) =
                    case template of
                        TemplateHandle dlgTemp =>
                            let
                                val dlg = toCWord8vec(Dialog.compileTemplate dlgTemp)
                            in
                                (OFN_ENABLETEMPLATEHANDLE, dlg, null, dlg)
                            end
                    |   TemplateResource(hInst, IdAsInt wb) =>
                            (
                            OFN_ENABLETEMPLATE,
                            voidStarOfHandle hInst,
                            Memory.sysWord2VoidStar(SysWord.fromInt wb),
                            null
                            )
                    |   TemplateResource(hInst, IdAsString str) =>
                            let
                                val s = toCstring str
                            in
                                (OFN_ENABLETEMPLATE, voidStarOfHandle hInst, s, s)
                            end
                    |   TemplateDefault => (OpenFileFlags.fromWord 0w0, null, null, null)

                val lpstrFilter =
                    case filter of
                        nil => Memory.null
                    |   _ =>
                        let
                            (* The filter strings are pairs of strings with a final
                               terminating null.  That implies that the strings cannot be empty.
                               Should we check that?
                               Get the store needed for the strings, including the null
                               terminations and the final null. *)
                            val filterSize =
                                List.foldl (fn((s1,s2),n) => size s1 + size s2 + n + 2) 1 filter
                            open Memory
                            infix 6 ++
                            val buf = malloc (Word.fromInt filterSize)

                            fun copyToBuf((s1,s2), n) =
                            let
                                val ss1 = size s1 and ss2 = size s2
                            in
                                stringToBuf(buf, n, s1);
                                stringToBuf(buf, n+ss1+1, s2);
                                n+ss1+ss2+2 (* Result is the next offset. *)
                            end

                            val lastAddr = List.foldl copyToBuf 0 filter
                            val _ = set8(buf, Word.fromInt lastAddr, 0w0)
                        in
                            buf
                        end

                val (lpstrCustomFilter, nMaxCustFilter) =
                    case customFilter of
                        NONE => (null, 0)
                    |   SOME (dispString, pattern) =>
                        let
                            (* Make sure we have enough space. 100 is probably big enough. *)
                            val space = Int.max(size dispString + size pattern + 2, 100)
                            val buf = Memory.malloc(Word.fromInt space)
                        in
                            stringToBuf(buf, 0, dispString);
                            stringToBuf(buf, size dispString + 1, pattern);
                            (buf, space)
                        end

                val lpstrFile = (* Full name of file including path. *)
                    allocAndInitialise(maxFile, file)
                val lpstrFileTitle = (* Name excluding the path. *)
                    allocAndInitialise(maxFile, fileTitle)

                val ofn = malloc sizeOfnStruct
                val args = (Word.toInt sizeOfnStruct, (* lStructSize *)
                      owner, (* hwndOwner *)
                      inst, (* hInstance *)
                      lpstrFilter,
                      lpstrCustomFilter,
                      nMaxCustFilter,
                      filterIndex,
                      lpstrFile,
                      maxFile+1, (* nMaxFile *)
                      lpstrFileTitle,
                      maxFile+1, (* nMaxFileTitle *)
                      initialDir,
                      title,
                      OpenFileFlags.flags[f1, flags], (* Flags *)
                      0, (* nFileOffset *)
                      0, (* nFileExtension *)
                      defExt,
                      0, (* lCustData *)
                      null, (* lpfnHook *)
                      templ) (* lpTemplateName *)
                val freeOfn = fromOFN(ofn, args) (* Copy into the memory *)
                fun freeAll() =
                    (
                        freeOfn();
                        List.app free [ofn, toFree, lpstrFilter, lpstrCustomFilter, lpstrFile, lpstrFileTitle]
                    )
                val result =
                    doCall ofn handle ex => (freeAll(); raise ex)
            in
                (if result
                then
                let
                    (* Most of the fields are unchanged so we're better off extracting
                       them from the original.  If we've passed in a template we have
                       to get it from the original because we can only convert a
                       memory object to a Word8Vector.vector if we know its length. *)

                    val (_, _, _, _, lpstrCustomFilter, _, nFilterIndex, lpstrFile,
                         _, lpstrFileTitle, _, _, _, flagBits, _, _, _, _, _, _) = loadOFN ofn

                    val customFilter =
                        if lpstrCustomFilter = null
                        then NONE
                        else
                        let
                            (* The dialogue box copies the selected filter into the section of
                               this string after the first string. *)
                            val s1 = fromCstring lpstrCustomFilter
                            val s2 = fromCstring (lpstrCustomFilter ++ Word.fromInt(size s1 +1))
                        in
                            SOME(s1, s2)
                        end
                in
                    SOME 
                    {
                        owner = owner,
                        template = template,
                        filter = filter,
                        customFilter = customFilter,
                        filterIndex = nFilterIndex,
                        file = fromCstring lpstrFile,
                        maxFile = maxFile,
                        fileTitle = fromCstring lpstrFileTitle,
                        initialDir = initialDir,
                        title = title,
                            (* Mask off the template flags. *)
                        flags = let open OpenFileFlags in clear(fromWord 0wxE0, flagBits) end,
                        defExt = defExt
                    }
                end
                else NONE) before freeAll()
            end

        in
            val GetOpenFileName =
                getOpenSave (winCall1 (commdlg "GetOpenFileNameA") cPointer cBool)
            and GetSaveFileName =
                getOpenSave (winCall1 (commdlg "GetSaveFileNameA") cPointer cBool)
        end (* local *)

        local
            val getFileTitle = winCall3(commdlg "GetFileTitleA") (cString, cPointer, cWORD) cShort
        in
            fun GetFileTitle(file: string): string =
            let
                fun gft (m, n) = getFileTitle(file, m, n)
            in
                getStringWithNullIsLength gft
            end
        end

        (* This is a bit messy.  It creates a modeless dialogue box
           and sends messages to the parent window.  The only problem is that
           the message identifier is not a constant.  It has to be obtained
           by a call to RegisterWindowMessage. *)
        (* We also have to ensure that the memory containing the FINDREPLACE
           structure is not freed until the dialogue window is destroyed. *)

        structure FindReplaceFlags = FindReplaceFlags

        (* These flags are local only. *)
        (*val FR_ENABLEHOOK                 = FindReplaceFlags.fromWord 0wx00000100*)
        val FR_ENABLETEMPLATE             = FindReplaceFlags.fromWord 0wx00000200
        val FR_ENABLETEMPLATEHANDLE       = FindReplaceFlags.fromWord 0wx00002000

        (* The address of this structure is passed in messages.  That all looks
           extremely messy. *)
        type FINDREPLACE =
        {
            owner : HWND, (* NOT an option. *)
            template: TemplateType,
            flags: FindReplaceFlags.flags,
            findWhat: string,
            replaceWith: string,
            bufferSize: int
        }

        local
            val FINDREPLACE =
                cStruct11(cDWORD, cHWND, cPointer (*HINSTANCE*), FindReplaceFlags.cFindReplaceFlags,
                          cPointer, cPointer, cWORD, cWORD, cLPARAM, cPointer (* LPFRHOOKPROC *), cPointer)
            val {store=fromOFR, ctype={size=sizeFR, ...}, ...} = breakConversion FINDREPLACE

            val findText = winCall1 (commdlg "FindTextA") cPointer cHWND
            and replaceText = winCall1 (commdlg "ReplaceTextA") cPointer cHWND

            fun findReplace doCall (arg: FINDREPLACE): HWND =
            let
                val {
                        owner : HWND, (* NOT an option. *)
                        template: TemplateType,
                        flags: FindReplaceFlags.flags,
                        findWhat: string,
                        replaceWith: string,
                        bufferSize: int
                    } = arg
                open Memory
                val (f1, inst, templ, toFree) =
                    case template of
                        TemplateHandle dlgTemp =>
                            let
                                val dlg = toCWord8vec(Dialog.compileTemplate dlgTemp)
                            in
                                (FR_ENABLETEMPLATEHANDLE, dlg, null, dlg)
                            end
                    |   TemplateResource(hInst, IdAsInt wb) =>
                            (
                            FR_ENABLETEMPLATE,
                            voidStarOfHandle hInst,
                            Memory.sysWord2VoidStar(SysWord.fromInt wb),
                            null
                            )
                    |   TemplateResource(hInst, IdAsString str) =>
                            let
                                val s = toCstring str
                            in
                                (FR_ENABLETEMPLATE, voidStarOfHandle hInst, s, s)
                            end
                    |   TemplateDefault => (FindReplaceFlags.fromWord 0w0, null, null, null)
                val lpstrFindWhat = allocAndInitialise(bufferSize, findWhat)
                val lpstrReplaceWith = allocAndInitialise(bufferSize, replaceWith)
                val m = malloc sizeFR
                val args =
                    (Word.toInt sizeFR, (* lStructSize *)
                      owner, (* hwndOwner *)
                      inst, (* hInstance *)
                      FindReplaceFlags.flags[f1, flags], (* Flags *)
                      lpstrFindWhat,
                      lpstrReplaceWith,
                      bufferSize,
                      bufferSize,
                      0, (* lCustData *)
                      null, (* lpfnHook *)
                      templ) (* lpTemplateName *)
                val freeOfr = fromOFR(m, args)
                fun freeAll() =
                (
                    freeOfr();
                    List.app free [m, toFree, lpstrFindWhat, lpstrReplaceWith]
                )
                val result = doCall m handle ex => (freeAll(); raise ex)
                val () =
                    checkResult(not(isHNull result)) handle ex => (freeAll(); raise ex)
            in
                (*  The memory cannot be released until the dialogue is dismissed. Also,
                    since this is a modeless dialogue we have to add it to the modeless 
                    dialogue list so that keyboard functions work. *)
                (* TODO: There may be better ways of ensuring the memory is freed. *)
                (Message.addModelessDialogue(result, SOME freeAll); result)
            end
        in
            val FindText = findReplace findText
            and ReplaceText = findReplace replaceText
        end

        structure PageSetupFlags :>
          sig
            include BIT_FLAGS
            val PSD_DEFAULTMINMARGINS : flags
            val PSD_DISABLEMARGINS : flags
            val PSD_DISABLEORIENTATION : flags
            val PSD_DISABLEPAGEPAINTING : flags
            val PSD_DISABLEPAPER : flags
            val PSD_DISABLEPRINTER : flags
            val PSD_INHUNDREDTHSOFMILLIMETERS : flags
            val PSD_INTHOUSANDTHSOFINCHES : flags
            val PSD_MARGINS : flags
            val PSD_MINMARGINS : flags
            val PSD_NONETWORKBUTTON : flags
            val PSD_NOWARNING : flags
            val PSD_RETURNDEFAULT : flags
            val PSD_SHOWHELP : flags
            val cConvert: flags conversion
          end
         =
        struct
            open Word32
            type flags = word
            val toWord = toLargeWord
            and fromWord = fromLargeWord
            val flags = List.foldl (fn (a, b) => orb(a,b)) 0w0
            fun allSet (fl1, fl2) = andb(fl1, fl2) = fl1
            fun anySet (fl1, fl2) = andb(fl1, fl2) <> 0w0
            fun clear (fl1, fl2) = andb(notb fl1, fl2)
    
            val PSD_DEFAULTMINMARGINS             = 0wx00000000 (* default (printer's) *)
            (*val PSD_INWININIINTLMEASURE           = 0wx00000000 *)(* 1st of 4 possible *)
            
            val PSD_MINMARGINS                    = 0wx00000001 (* use caller's *)
            val PSD_MARGINS                       = 0wx00000002 (* use caller's *)
            val PSD_INTHOUSANDTHSOFINCHES         = 0wx00000004 (* 2nd of 4 possible *)
            val PSD_INHUNDREDTHSOFMILLIMETERS     = 0wx00000008 (* 3rd of 4 possible *)
            val PSD_DISABLEMARGINS                = 0wx00000010
            val PSD_DISABLEPRINTER                = 0wx00000020
            val PSD_NOWARNING                     = 0wx00000080
            val PSD_DISABLEORIENTATION            = 0wx00000100
            val PSD_RETURNDEFAULT                 = 0wx00000400
            val PSD_DISABLEPAPER                  = 0wx00000200
            val PSD_SHOWHELP                      = 0wx00000800
            (*
            val PSD_ENABLEPAGESETUPHOOK           = 0wx00002000
            val PSD_ENABLEPAGESETUPTEMPLATE       = 0wx00008000
            val PSD_ENABLEPAGESETUPTEMPLATEHANDLE = 0wx00020000
            val PSD_ENABLEPAGEPAINTHOOK           = 0wx00040000 *)

            val PSD_DISABLEPAGEPAINTING           = 0wx00080000
            val PSD_NONETWORKBUTTON               = 0wx00200000
    
            val all = flags[PSD_DEFAULTMINMARGINS, PSD_MINMARGINS, PSD_MARGINS,
                            PSD_INTHOUSANDTHSOFINCHES, PSD_INHUNDREDTHSOFMILLIMETERS,
                            PSD_DISABLEMARGINS, PSD_DISABLEPRINTER, PSD_NOWARNING,
                            PSD_DISABLEORIENTATION, PSD_RETURNDEFAULT, PSD_DISABLEPAPER,
                            PSD_SHOWHELP, PSD_DISABLEPAGEPAINTING, PSD_NONETWORKBUTTON]
    
            val intersect = List.foldl (fn (a, b) => andb(a,b)) all
            
            val cConvert = cDWORDw
        end

        structure PrintDlgFlags :>
          sig
            include BIT_FLAGS
            val PD_ALLPAGES : flags
            val PD_COLLATE : flags
            val PD_DISABLEPRINTTOFILE : flags
            val PD_HIDEPRINTTOFILE : flags
            val PD_NONETWORKBUTTON : flags
            val PD_NOPAGENUMS : flags
            val PD_NOSELECTION : flags
            val PD_NOWARNING : flags
            val PD_PAGENUMS : flags
            val PD_PRINTSETUP : flags
            val PD_PRINTTOFILE : flags
            val PD_RETURNDC : flags
            val PD_RETURNDEFAULT : flags
            val PD_RETURNIC : flags
            val PD_SELECTION : flags
            val PD_SHOWHELP : flags
            val PD_USEDEVMODECOPIES : flags
            val PD_USEDEVMODECOPIESANDCOLLATE : flags
            val cConvert: flags conversion
          end
     =
        struct
            open Word32
            type flags = word
            val toWord = toLargeWord
            and fromWord = fromLargeWord
            val flags = List.foldl (fn (a, b) => orb(a,b)) 0w0
            fun allSet (fl1, fl2) = andb(fl1, fl2) = fl1
            fun anySet (fl1, fl2) = andb(fl1, fl2) <> 0w0
            fun clear (fl1, fl2) = andb(notb fl1, fl2)
    
            val PD_ALLPAGES                  = 0wx00000000
            val PD_SELECTION                 = 0wx00000001
            val PD_PAGENUMS                  = 0wx00000002
            val PD_NOSELECTION               = 0wx00000004
            val PD_NOPAGENUMS                = 0wx00000008
            val PD_COLLATE                   = 0wx00000010
            val PD_PRINTTOFILE               = 0wx00000020
            val PD_PRINTSETUP                = 0wx00000040
            val PD_NOWARNING                 = 0wx00000080
            val PD_RETURNDC                  = 0wx00000100
            val PD_RETURNIC                  = 0wx00000200
            val PD_RETURNDEFAULT             = 0wx00000400
            val PD_SHOWHELP                  = 0wx00000800
            (*val PD_ENABLEPRINTHOOK           = 0wx00001000
            val PD_ENABLESETUPHOOK           = 0wx00002000
            val PD_ENABLEPRINTTEMPLATE       = 0wx00004000
            val PD_ENABLESETUPTEMPLATE       = 0wx00008000
            val PD_ENABLEPRINTTEMPLATEHANDLE = 0wx00010000
            val PD_ENABLESETUPTEMPLATEHANDLE = 0wx00020000 *)
            val PD_USEDEVMODECOPIES          = 0wx00040000
            val PD_USEDEVMODECOPIESANDCOLLATE = 0wx00040000
            val PD_DISABLEPRINTTOFILE        = 0wx00080000
            val PD_HIDEPRINTTOFILE           = 0wx00100000
            val PD_NONETWORKBUTTON           = 0wx00200000

    
            val all = flags[PD_ALLPAGES, PD_SELECTION, PD_PAGENUMS, PD_NOSELECTION, PD_NOPAGENUMS,
                            PD_COLLATE, PD_PRINTTOFILE, PD_PRINTSETUP, PD_NOWARNING, PD_RETURNDC,
                            PD_RETURNIC, PD_RETURNDEFAULT, PD_SHOWHELP, PD_USEDEVMODECOPIES,
                            PD_USEDEVMODECOPIESANDCOLLATE, PD_DISABLEPRINTTOFILE,
                            PD_HIDEPRINTTOFILE, PD_NONETWORKBUTTON]
    
            val intersect = List.foldl (fn (a, b) => andb(a,b)) all
            
            val cConvert = cDWORDw
        end

        type PAGESETUPDLG =
        {
            owner: HWND option,
            devMode: DEVMODE option,
            devNames: DEVNAMES option,
            flags: PageSetupFlags.flags,
            paperSize: POINT,
            minMargin: RECT,
            margin: RECT
            (* For the moment we ignore the other options. *)
        }

        type PRINTDLG =
        {
            owner: HWND option,
            devMode: DEVMODE option,
            devNames: DEVNAMES option,
            context: HDC option,
            flags: PrintDlgFlags.flags,
            fromPage: int,
            toPage: int,
            minPage: int,
            maxPage: int,
            copies: int
            (* For the moment we ignore the other options. *)
        }

        local
            (* A DEVNAMES structure is a structure containing offsets followed by
               the actual strings. *)
            val DEVNAMES = cStruct4(cWORD, cWORD, cWORD, cWORD)
            val {load=toDN, store=fromDN, ctype={size=sizeDevN, ...}, ...} = breakConversion DEVNAMES
            val DN_DEFAULTPRN      = 0x0001

            (* Allocate global memory for the devnames if necessary *)
            fun toDevNames NONE = hNull
            |   toDevNames (SOME{driver, device, output, default}) =
                let
                    (* We need memory for the DEVNAMES structure plus the strings plus
                       their terminating nulls. *)
                    val devnameSize = Word.toInt sizeDevN
                    val sizeDriver = size driver
                    and sizeDevice = size device
                    and sizeOutput = size output
                    val space = devnameSize + sizeDriver + sizeDevice + sizeOutput + 3
                    val mHandle = GlobalAlloc(0, space)
                    val buff = GlobalLock mHandle
                    (* Copy in the strings and calculate the next offset. *)
                    open Memory
                    infix 6 ++
                    fun copyString b str =
                    (
                        stringToBuf(b, 0, str);
                        b ++ Word.fromInt(size str+1)
                    );
                    val off1 = copyString (buff ++ sizeDevN) driver;
                    val off2 = copyString off1 device
                    val _ = copyString off2 output
                in
                    ignore(fromDN(buff, (devnameSize, devnameSize+sizeDriver+1,
                                 devnameSize+sizeDriver+sizeDevice+2,
                                 if default then DN_DEFAULTPRN else 0)));
                    GlobalUnlock mHandle;
                    mHandle
                end

            (* Convert a DevNames structure. *)
            fun fromDevNames v =
                if isHNull v then NONE
                else
                let
                    val buff = GlobalLock v
                    val (off0, off1, off2, def) = toDN buff
                    open Memory
                    infix 6 ++
                    val driver = fromCstring(buff ++ Word.fromInt off0)
                    val device = fromCstring(buff ++ Word.fromInt off1)
                    val output = fromCstring(buff ++ Word.fromInt off2)
                    val default = Word.andb(Word.fromInt def, Word.fromInt DN_DEFAULTPRN) <> 0w0
                in
                    GlobalUnlock v;
                    SOME {driver=driver, device=device, output=output, default=default}
                end

            val PAGESETUPDLG =
                cStruct14(cDWORD, cHWNDOPT, cHGLOBAL, cHGLOBAL, PageSetupFlags.cConvert, cPoint,
                          cRect, cRect, cHINSTANCE, cLPARAM, cPointer, cPointer, cPointer, cPointer)
            val {load=toPSD, store=fromPSD, ctype={size=sizePageSD, ...}, ...} = breakConversion PAGESETUPDLG

            (* This is a bit of a mess.  It seems that it uses structure packing on 32-bits
               which means that the fields after the five shorts are not aligned onto
               4-byte boundaries.  We currently don't use them so we just define this as
               the structure as far as we use it and set the length explicitly.
               This problem doesn't arise with PrintDlgEx so that might be preferable. *)
            val PRINTDLG = cStruct11(cDWORD, cHWNDOPT, cHGLOBAL, cHGLOBAL, cHDC, PrintDlgFlags.cConvert, cWORD,
                                    cWORD, cWORD, cWORD, cWORD)
            val {load=toPRD, store=fromPRD, ...} = breakConversion PRINTDLG
            val printDlgSize =
                if #size LowLevel.cTypePointer = 0w4 then 0w66 else 0w120

            val pageSetupDlg = winCall1 (commdlg "PageSetupDlgA") cPointer cBool
            and printDlg = winCall1 (commdlg "PrintDlgA") cPointer cBool
        in
            fun PageSetupDlg (arg: PAGESETUPDLG): PAGESETUPDLG option =
            let
                val {
                    owner: HWND option,
                    devMode: DEVMODE option,
                    devNames: {driver: string, device: string, output: string, default: bool} option,
                    flags: PageSetupFlags.flags,
                    paperSize: POINT,
                    minMargin: RECT,
                    margin: RECT} = arg
                val devnames = toDevNames devNames
                val devmode =
                    case devMode of
                        NONE => hNull
                    |   SOME dv =>
                        let
                            (* This has to be in global memory *)
                            open DeviceBase
                            val hGlob = GlobalAlloc(0, Word.toInt(devModeSize dv))
                            val mem = GlobalLock hGlob
                            val () = setCDevMode(mem, dv)
                        in
                            GlobalUnlock hGlob;
                            hGlob
                        end
                open Memory
                val mem = malloc sizePageSD
                val str = (Word.toInt sizePageSD, owner, devmode, devnames, flags,
                           paperSize, minMargin, margin, hinstanceNull, 0, null, null, null, null)
                val freePsd = fromPSD(mem, str) (* Set the PAGESETUPDLG struct *)

                fun freeAll() =
                let
                    (* We can only free the handles after we've reloaded them. *)
                    val (_, _, hgDevMode, hgDevNames, _, _, _, _, _, _, _, _, _, _) = toPSD mem
                in
                    if isHNull hgDevNames then () else ignore(GlobalFree hgDevNames);
                    if isHNull hgDevMode then () else ignore(GlobalFree hgDevMode);
                    free mem; freePsd()
                end

                val result = pageSetupDlg mem handle ex => (freeAll(); raise ex)
                val (_, owner, hgDevMode, hgDevNames, flags, paperSize, minMargin, margin,
                     _, _, _, _, _, _) = toPSD mem
                val devMode =
                    if isHNull hgDevMode
                    then NONE
                    else
                    let
                        val r = SOME(DeviceBase.getCDevMode(GlobalLock hgDevMode))
                    in
                        GlobalUnlock hgDevMode;
                        r
                    end;
                val devNames = fromDevNames hgDevNames
                val newArg =
                    { owner = owner, devMode = devMode, devNames = devNames,
                      flags = flags,
                      paperSize = paperSize, minMargin = minMargin, margin = margin }
                val () = freeAll()
            in
                if result
                then SOME newArg
                else NONE
            end

            and PrintDlg (arg: PRINTDLG): PRINTDLG option =
            let
                val {
                    owner: HWND option,
                    devMode: DEVMODE option,
                    devNames: {driver: string, device: string, output: string, default: bool} option,
                    context: HDC option,
                    flags: PrintDlgFlags.flags,
                    fromPage: int,
                    toPage: int,
                    minPage: int,
                    maxPage: int,
                    copies: int} = arg
                val devnames = toDevNames devNames
                val devmode =
                    case devMode of
                        NONE => hNull
                    |   SOME dv =>
                        let
                            (* This has to be in global memory *)
                            open DeviceBase
                            val hGlob = GlobalAlloc(0, Word.toInt(devModeSize dv))
                            val mem = GlobalLock hGlob
                            val () = setCDevMode(mem, dv)
                        in
                            GlobalUnlock hGlob;
                            hGlob
                        end
                open Memory
                val mem = malloc printDlgSize
                (* Since we're not going to set all of it we need to zero it. *)
                local
                    fun zero n = if n = printDlgSize then () else (set8(mem, n, 0w0); zero(n+0w1))
                in
                    val () = zero 0w0
                end
                val freePRD =
                    fromPRD(mem, (Word.toInt printDlgSize, owner, devmode, devnames, getOpt(context, hdcNull),
                        flags, fromPage, toPage, minPage, maxPage, copies)) 

                fun freeAll() =
                let
                    (* We can only free the handles after we've reloaded them. *)
                    val (_, _, hgDevMode, hgDevNames, _, _, _, _, _, _, _) = toPRD mem
                in
                    if isHNull hgDevNames then () else ignore(GlobalFree hgDevNames);
                    if isHNull hgDevMode then () else ignore(GlobalFree hgDevMode);
                    free mem; freePRD()
                end
                
                val result = printDlg mem handle ex => (freeAll(); raise ex)
                (* Convert the result.  We have to do this even if the result is
                   false to make sure we call GlobalFree on any global handles. *)
                val (_, owner, hgDevMode, hgDevNames, hdc, flags, fromPage, toPage, minPage,
                     maxPage, copies) = toPRD mem
                val devMode =
                    if isHNull hgDevMode
                    then NONE
                    else
                    let
                        val r = SOME(DeviceBase.getCDevMode(GlobalLock hgDevMode))
                    in
                        GlobalUnlock hgDevMode;
                        r
                    end;
                val devNames = fromDevNames hgDevNames
                val newArg =
                    { owner = owner, devMode = devMode, devNames = devNames,
                      context = if isHdcNull hdc then NONE else SOME hdc,
                      flags = flags, fromPage = fromPage, toPage = toPage,
                      minPage = minPage, maxPage = maxPage, copies = copies }
                val () = freeAll()
            in
                if result
                then SOME newArg
                else NONE
            end
        end
(*
        structure ChooseFontFlags :>
          sig
            include BIT_FLAGS
            val CF_ANSIONLY : flags
            val CF_APPLY : flags
            val CF_BOTH : flags
            val CF_EFFECTS : flags
            val CF_FIXEDPITCHONLY : flags
            val CF_FORCEFONTEXIST : flags
            val CF_NOFACESEL : flags
            val CF_NOOEMFONTS : flags
            val CF_NOSCRIPTSEL : flags
            val CF_NOSIMULATIONS : flags
            val CF_NOSIZESEL : flags
            val CF_NOSTYLESEL : flags
            val CF_NOVECTORFONTS : flags
            val CF_NOVERTFONTS : flags
            val CF_PRINTERFONTS : flags
            val CF_SCALABLEONLY : flags
            val CF_SCREENFONTS : flags
            val CF_SCRIPTSONLY : flags
            val CF_SELECTSCRIPT : flags
            val CF_SHOWHELP : flags
            val CF_TTONLY : flags
            val CF_WYSIWYG : flags
          end
     =
        struct
            type flags = SysWord.word
            fun toWord f = f
            fun fromWord f = f
            val flags = List.foldl (fn (a, b) => SysWord.orb(a,b)) 0w0
            fun allSet (fl1, fl2) = SysWord.andb(fl1, fl2) = fl1
            fun anySet (fl1, fl2) = SysWord.andb(fl1, fl2) <> 0w0
            fun clear (fl1, fl2) = SysWord.andb(SysWord.notb fl1, fl2)
    
            val CF_SCREENFONTS             = 0wx00000001
            val CF_PRINTERFONTS            = 0wx00000002
            val CF_BOTH                    = 0wx00000003: flags
            val CF_SHOWHELP                = 0wx00000004
            (*
            val CF_ENABLEHOOK              = 0wx00000008
            val CF_ENABLETEMPLATE          = 0wx00000010
            val CF_ENABLETEMPLATEHANDLE    = 0wx00000020
            *)
            (*val CF_INITTOLOGFONTSTRUCT     = 0wx00000040*)
            (*val CF_USESTYLE                = 0wx00000080*)
            val CF_EFFECTS                 = 0wx00000100
            val CF_APPLY                   = 0wx00000200
            val CF_ANSIONLY                = 0wx00000400
            val CF_SCRIPTSONLY             = CF_ANSIONLY
            val CF_NOVECTORFONTS           = 0wx00000800
            val CF_NOOEMFONTS              = CF_NOVECTORFONTS
            val CF_NOSIMULATIONS           = 0wx00001000
            (*val CF_LIMITSIZE               = 0wx00002000*)
            val CF_FIXEDPITCHONLY          = 0wx00004000
            val CF_WYSIWYG                 = 0wx00008000
            val CF_FORCEFONTEXIST          = 0wx00010000
            val CF_SCALABLEONLY            = 0wx00020000
            val CF_TTONLY                  = 0wx00040000
            val CF_NOFACESEL               = 0wx00080000
            val CF_NOSTYLESEL              = 0wx00100000
            val CF_NOSIZESEL               = 0wx00200000
            val CF_SELECTSCRIPT            = 0wx00400000
            val CF_NOSCRIPTSEL             = 0wx00800000
            val CF_NOVERTFONTS             = 0wx01000000
    
            val all = flags[CF_SCREENFONTS, CF_PRINTERFONTS, CF_SHOWHELP,
                            CF_EFFECTS, CF_APPLY, CF_ANSIONLY, CF_NOVECTORFONTS,
                            CF_NOSIMULATIONS, CF_FIXEDPITCHONLY, CF_WYSIWYG, CF_FORCEFONTEXIST,
                            CF_SCALABLEONLY, CF_TTONLY, CF_NOFACESEL, CF_NOSTYLESEL, CF_NOSIZESEL,
                            CF_SELECTSCRIPT, CF_NOSCRIPTSEL, CF_NOVERTFONTS]
    
            val intersect = List.foldl (fn (a, b) => SysWord.andb(a,b)) all
        end

        structure ChooseFontTypes :>
          sig
            include BIT_FLAGS
            val BOLD_FONTTYPE : flags
            val ITALIC_FONTTYPE : flags
            val PRINTER_FONTTYPE : flags
            val REGULAR_FONTTYPE : flags
            val SCREEN_FONTTYPE : flags
            val SIMULATED_FONTTYPE : flags
          end
     =
        struct
            type flags = SysWord.word
            fun toWord f = f
            fun fromWord f = f
            val flags = List.foldl (fn (a, b) => SysWord.orb(a,b)) 0w0
            fun allSet (fl1, fl2) = SysWord.andb(fl1, fl2) = fl1
            fun anySet (fl1, fl2) = SysWord.andb(fl1, fl2) <> 0w0
            fun clear (fl1, fl2) = SysWord.andb(SysWord.notb fl1, fl2)
    
            val SIMULATED_FONTTYPE    = 0wx8000
            val PRINTER_FONTTYPE      = 0wx4000
            val SCREEN_FONTTYPE       = 0wx2000
            val BOLD_FONTTYPE         = 0wx0100
            val ITALIC_FONTTYPE       = 0wx0200
            val REGULAR_FONTTYPE      = 0wx0400
    
            val all = flags[SIMULATED_FONTTYPE, PRINTER_FONTTYPE, SCREEN_FONTTYPE,
                            BOLD_FONTTYPE, ITALIC_FONTTYPE, REGULAR_FONTTYPE]
    
            val intersect = List.foldl (fn (a, b) => SysWord.andb(a,b)) all
        end

        type CHOOSEFONT = {
            owner: HWND option,
            context: HDC option,
            logFont: LOGFONT option,
            pointSize: int,
            flags: ChooseFontFlags.flags,
            colors: COLORREF,
            style: string option,
            fontType: ChooseFontTypes.flags,
            size: {min: int, max: int} option
            }

        local
            val CHOOSEFONT = cStruct16(UINT, HWNDOPT, HDC, POINTER, INT, WORD, COLORREF,
                                INT, INT, INT, INT, POINTER, SHORT, SHORT, INT, INT)
            val (toCF, fromCF, cfStruct) = breakConversion CHOOSEFONT
            val (toLF, fromLF, lfStruct) = breakConversion FontBase.LOGFONT
            val CF_LIMITSIZE               = 0wx00002000
            val CF_INITTOLOGFONTSTRUCT     = 0wx00000040
            val CF_USESTYLE                = 0wx00000080

            fun toCChooseFont({
                owner: HWND option,
                context: HDC option,
                logFont: LOGFONT option,
                pointSize: int,
                flags: ChooseFontFlags.flags,
                colors: COLORREF,
                style: string option,
                fontType: ChooseFontTypes.flags,
                size: {min: int, max: int} option
                }) =
            let
                (* Use the supplied logFont otherwise allocate store for a new one. *)
                val logf =
                    case logFont of
                        SOME logf => address(fromLF logf)
                    |   NONE => address(alloc 1 lfStruct)
                (* Copy any style to the buffer - I don't know why this is 64. *)
                val lpszStyle = allocAndInitialise(64, getOpt(style, ""))
                val (min, max) = case size of SOME {min, max} => (min, max) | NONE => (0,0)
                val f1 = case size of SOME _ => CF_LIMITSIZE | _ => 0w0
                val f2 = case logFont of SOME _ => CF_INITTOLOGFONTSTRUCT | _ => 0w0
                val f3 = case style of SOME _ => CF_USESTYLE | _ => 0w0
                val flags = List.foldl LargeWord.orb 0w0 [ChooseFontFlags.toWord flags, f1, f2, f3]
            in
                address(
                    fromCF(sizeof cfStruct, owner, getOpt(context, hdcNull), logf, pointSize,
                        flags, colors, 0, 0, 0, 0, lpszStyle,
                        LargeWord.toInt (ChooseFontTypes.toWord fontType), 0, min, max))
            end

            fun fromCChooseFont v : CHOOSEFONT =
            let
                val (_, owner, hdc, logf, pointSize, flags, colors, _, _, _, _, style,
                     types, _, min, max) = toCF(deref v)
                val minMax =
                    if LargeWord.andb(flags, CF_LIMITSIZE) = 0w0
                    then NONE
                    else SOME{min=min, max=max}
                val style =
                    if LargeWord.andb(flags, CF_USESTYLE) = 0w0
                    then NONE
                    else SOME(fromCstring style)
            in
                { owner = owner, context = if isHdcNull hdc then NONE else SOME hdc,
                  logFont = SOME(toLF(deref logf)), pointSize = pointSize,
                  (* Remove CF_LIMITSIZE and/or CF_INITTOLOGFONTSTRUCT *)
                  flags = ChooseFontFlags.intersect[ChooseFontFlags.fromWord flags],
                  colors = colors, style = style,
                  fontType =
                     ChooseFontTypes.fromWord(LargeWord.andb(LargeWord.fromInt types, 0wxffff)),
                  size = minMax}
            end
        in
            fun ChooseFont (arg: CHOOSEFONT): CHOOSEFONT option =
            let
                val converted = toCChooseFont arg
                val result =
                    winCall1 (commdlg "ChooseFontA") POINTER BOOL converted
            in
                if result
                then SOME(fromCChooseFont converted)
                else NONE
            end

        end

        structure ChooseColorFlags :>
          sig
            include BIT_FLAGS
            val CC_ANYCOLOR : flags
            val CC_FULLOPEN : flags
            val CC_PREVENTFULLOPEN : flags
            val CC_RGBINIT : flags
            val CC_SHOWHELP : flags
            val CC_SOLIDCOLOR : flags
          end
     =
        struct
            type flags = SysWord.word
            fun toWord f = f
            fun fromWord f = f
            val flags = List.foldl (fn (a, b) => SysWord.orb(a,b)) 0w0
            fun allSet (fl1, fl2) = SysWord.andb(fl1, fl2) = fl1
            fun anySet (fl1, fl2) = SysWord.andb(fl1, fl2) <> 0w0
            fun clear (fl1, fl2) = SysWord.andb(SysWord.notb fl1, fl2)
    
            val CC_RGBINIT               = 0wx00000001
            val CC_FULLOPEN              = 0wx00000002
            val CC_PREVENTFULLOPEN       = 0wx00000004
            val CC_SHOWHELP              = 0wx00000008
            (*val CC_ENABLEHOOK            = 0wx00000010
            val CC_ENABLETEMPLATE        = 0wx00000020
            val CC_ENABLETEMPLATEHANDLE  = 0wx00000040*)
            val CC_SOLIDCOLOR            = 0wx00000080
            val CC_ANYCOLOR              = 0wx00000100
    
            val all = flags[CC_RGBINIT, CC_FULLOPEN, CC_PREVENTFULLOPEN,
                            CC_SHOWHELP, CC_SOLIDCOLOR, CC_ANYCOLOR]
    
            val intersect = List.foldl (fn (a, b) => SysWord.andb(a,b)) all
        end

        type CHOOSECOLOR =
        {
            owner: HWND option,
            result: COLORREF,
            customColors: COLORREF list,
            flags: ChooseColorFlags.flags
        }

        local
            val CHOOSECOLOR = cStruct9(UINT, HWNDOPT, INT, COLORREF, POINTER, WORD,
                                      INT, INT, INT)
            (* The custom colours are held in an array of 16 elements. *)
            val CUSTOM = cStruct16(COLORREF, COLORREF, COLORREF, COLORREF,
                                  COLORREF, COLORREF, COLORREF, COLORREF, 
                                  COLORREF, COLORREF, COLORREF, COLORREF, 
                                  COLORREF, COLORREF, COLORREF, COLORREF)
            val (toCC, fromCC, ccStruct) = breakConversion CHOOSECOLOR
            val (toM, fromM, mStruct) = breakConversion CUSTOM
            val (toCR, fromCR, cref) = breakConversion COLORREF

            fun toCChooseColor {
                owner: HWND option,
                result: COLORREF,
                customColors: COLORREF list,
                flags: ChooseColorFlags.flags
            } =
            let
                val custom = alloc 1 mStruct
                val black = fromCR(RGB{red=0, green=0, blue=0})
                fun fillCustom(_, 16) = ()
                 |  fillCustom([], i) =
                        (assign cref (offset i cref custom) black; fillCustom([], i+1))
                 |  fillCustom(hd::tl, i) =
                        (assign cref (offset i cref custom) (fromCR hd); fillCustom(tl, i+1))
            in
                fillCustom(customColors, 0);
                address(
                    fromCC(sizeof ccStruct, owner, 0, result, address custom,
                        ChooseColorFlags.toWord flags, 0, 0, 0))
            end

            fun fromCChooseColor v : CHOOSECOLOR =
            let
                val (_, owner, _, result, custom, flags, _, _, _) = toCC(deref v)
                val custom =
                    List.tabulate(16, fn i => toCR(offset i cref(deref custom)))
            in
                { owner = owner, flags = ChooseColorFlags.fromWord flags,
                  customColors = custom, result = result}
            end
        in
            fun ChooseColor (arg: CHOOSECOLOR): CHOOSECOLOR option =
            let
                val converted = toCChooseColor arg
                val result =
                    winCall1 (commdlg "ChooseColorA") POINTER BOOL converted
            in
                if result
                then SOME(fromCChooseColor converted)
                else NONE
            end
        end
*)
(*
typedef struct tagCHOOSECOLORA {
   DWORD        lStructSize;
   HWND         hwndOwner;
   HWND         hInstance;
   COLORREF     rgbResult;
   COLORREF*    lpCustColors;
   DWORD        Flags;
   LPARAM       lCustData;
   LPCCHOOKPROC lpfnHook;
   LPCSTR       lpTemplateName;
} CHOOSECOLORA, *LPCHOOSECOLORA;

*)
(*
ChooseColor  
PrintDlgEx  - NT 5.0 and later only

The following application-defined hook procedures are used with common dialog boxes. 

CCHookProc   
CFHookProc   
FRHookProc   
OFNHookProc   
OFNHookProcOldStyle   
PagePaintHook   
PageSetupHook   
PrintHookProc   
SetupHookProc  
*)
    end
end;