1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 2<html> 3 4<head> 5<title>Source for mlEdit example </title> 6</head> 7 8<body><pre>(* 9 Copyright (c) 2001-7 10 David C.J. Matthews 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 2.1 of the License, or (at your option) any later version. 16 17 This library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; if not, write to the Free Software 24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25*) 26(* Example text editor. *) 27fun mlEdit () = 28let 29 open Window Message Menu Edit Class Dialog CommonDialog MessageBox Caret 30 open DeviceContext Font Printing Transform Painting Color 31 open Keyboard 32 33 (* Define values to be delivered when the menu items are selected. 34 The Id is delivered as part of a WM_COMMAND message. *) 35 val menuOpen = 1 36 and menuQuit = 2 37 and menuSave = 3 38 and menuSaveAs = 4 39 and menuCut = 5 40 and menuCopy = 6 41 and menuPaste = 7 42 and menuFind = 8 43 and menuPageSetup = 9 44 and menuPrint = 10 45 and menuAbout = 11 46 47 val app = Globals.ApplicationInstance() 48 49 (* Borrow the Poly icon from the application program. It happens to 50 be icon id 102. If this doesn't work return NULL. *) 51 val polyIcon = 52 Icon.LoadIcon(app, Resource.MAKEINTRESOURCE 102) handle _ => Globals.hNull; 53 54 local 55 (* Create sub-menus. *) 56 val fileMenu = 57 let 58 val fileMenu = CreateMenu(); 59 in 60 AppendMenu(fileMenu, [], MenuId menuOpen, MFT_STRING "&Open"); 61 AppendMenu(fileMenu, [], MenuId menuSave, MFT_STRING "&Save"); 62 AppendMenu(fileMenu, [], MenuId menuSaveAs, MFT_STRING "Save &As..."); 63 AppendMenu(fileMenu, [], MenuId 0, MFT_SEPARATOR); 64 AppendMenu(fileMenu, [], MenuId menuPageSetup, MFT_STRING "Page Set&up..."); 65 AppendMenu(fileMenu, [], MenuId menuPrint, MFT_STRING "P&rint..."); 66 AppendMenu(fileMenu, [], MenuId 0, MFT_SEPARATOR); 67 AppendMenu(fileMenu, [], MenuId menuQuit, MFT_STRING "&Quit"); 68 fileMenu 69 end; 70 71 val editMenu = 72 let 73 val editMenu = CreateMenu(); 74 in 75 AppendMenu(editMenu, [], MenuId menuCut, MFT_STRING "Cu&t"); 76 AppendMenu(editMenu, [], MenuId menuCopy, MFT_STRING "&Copy"); 77 AppendMenu(editMenu, [], MenuId menuPaste, MFT_STRING "&Paste"); 78 AppendMenu(editMenu, [], MenuId menuFind, MFT_STRING "&Find"); 79 editMenu 80 end; 81 82 val helpMenu = 83 let 84 val helpMenu = CreateMenu() 85 in 86 AppendMenu(helpMenu, [], MenuId menuAbout, MFT_STRING "&About mlEdit..."); 87 helpMenu 88 end 89 90 in 91 (* Create the main menu and append the sub-menus. *) 92 val menu = CreateMenu(); 93 val _ = AppendMenu(menu, [], MenuHandle fileMenu, MFT_STRING "&File"); 94 val _ = AppendMenu(menu, [], MenuHandle editMenu, MFT_STRING "&Edit") 95 val _ = AppendMenu(menu, [], MenuHandle helpMenu, MFT_STRING "&Help") 96 end; 97 98 (* The "state" of the editor. *) 99 type state = { 100 edit: HWND, (* Handle to the edit window. *) 101 devMode: DEVMODE option, devNames: DEVNAMES option, (* Printer settings *) 102 fileName: string 103 } 104 105 fun wndProc(hw: HWND, msg: Message, NONE): LRESULT * state option = 106 ( 107 case msg of 108 WM_CREATE _ => (* Create an edit window and return it as the state. *) 109 let 110 val edit = 111 CreateWindow{class = Class.Edit, name = "", 112 (* The style does not include horizontal scrolling. That causes us to use word-wrapping. *) 113 style = Edit.Style.flags[Edit.Style.WS_CHILD, Edit.Style.WS_VISIBLE, Edit.Style.WS_VSCROLL, 114 (*Edit.Style.WS_HSCROLL, *)Edit.Style.ES_LEFT, Edit.Style.ES_MULTILINE, 115 Edit.Style.ES_AUTOVSCROLL(*, Edit.Style.ES_AUTOHSCROLL*)], 116 x = 0, y = 0, height = 0, width = 0, relation = ChildWindow{parent=hw, id=99}, 117 instance = Globals.ApplicationInstance(), init = ()} 118 119 (* Create a 10 point Courier font. *) 120 val hDC = GetDC edit; 121 val height = ~10 * GetDeviceCaps(hDC, LOGPIXELSY) div 72; 122 val _ = ReleaseDC(edit, hDC); 123 val hFont = CreateFont{height=height, width=0, escapement=0, orientation=0, 124 weight=FW_DONTCARE, italic=false, underline=false, strikeOut=false, 125 charSet=ANSI_CHARSET, outputPrecision=OUT_DEFAULT_PRECIS, 126 clipPrecision=CLIP_DEFAULT_PRECIS, quality=DEFAULT_QUALITY, 127 pitch=FIXED_PITCH, family=FF_MODERN, faceName="Courier"} 128 in 129 SendMessage(edit, WM_SETFONT{font=hFont, redrawflag=false}); 130 (LRESINT 0, SOME{edit=edit, devMode=NONE, devNames = NONE, fileName=""}) 131 end 132 133 | _ => (DefWindowProc(hw, msg), NONE) 134 ) 135 136 | wndProc(hw: HWND, 137 msg: Message, 138 state: state option as SOME{edit, devMode, devNames, fileName, ...}) = 139 case msg of 140 WM_SETFOCUS _ => 141 (* If we get a focus request we set the focus to the edit window. *) 142 (SetFocus(SOME edit); (DefWindowProc(hw, msg), state)) 143 144 | WM_SIZE{height, width, ...} => 145 (* If we get a size change we set the size of the edit window. *) 146 (MoveWindow{hWnd=edit, x=0, y=0, height=height, width=width, repaint=true}; (DefWindowProc(hw, msg), state)) 147 148 | WM_NCDESTROY => 149 (* When the window is closed we send a QUIT message which exits from the application loop. *) 150 (PostQuitMessage 0; (DefWindowProc(hw, msg), state)) 151 152 | WM_CLOSE => 153 (* User has pressed the Close box. If it's ok to close we could call 154 DestroyWindow ourselves. Just as an example we return NONE which 155 passes it to the default window procedure and does it for us. *) 156 (if checkForSave(hw, edit, fileName) then DefWindowProc(hw, msg) else LRESINT 0, state) 157 158 | WM_COMMAND{notifyCode = 0, wId, control} => 159 (* Menu selections arrive here. *) 160 161 if wId = menuQuit 162 then 163 ( 164 if checkForSave(hw, edit, fileName) then DestroyWindow hw else (); 165 (LRESINT 0, state) 166 ) 167 168 else if wId = menuOpen 169 then 170 let 171 val on = { 172 owner = SOME hw, 173 template = TemplateDefault, 174 filter = 175 [("Text Files (*.txt)", "*.txt"), 176 ("ML Files (*.sml)", "*.sml"), 177 ("All Files (*.*)", "*.*")], 178 customFilter = NONE, 179 filterIndex = 1, 180 file = "", 181 maxFile = 1000, 182 fileTitle = "", 183 initialDir = NONE, 184 title = NONE, 185 flags = OpenFileFlags.flags[OpenFileFlags.OFN_HIDEREADONLY], 186 defExt = NONE 187 } 188 in 189 case GetOpenFileName on of 190 NONE => (LRESINT 0, state) 191 | SOME {file, ...} => 192 (* If it's been modified we need to ask before overwriting. *) 193 if checkForSave(hw, edit, fileName) 194 then 195 (let 196 val f = TextIO.openIn file 197 (* Text input will convert CRNL to \n. We need to 198 reverse the process. *) 199 fun nlToCrnl s = 200 String.translate(fn #"\n" => "\r\n" | c => String.str c) s 201 in 202 (* Should we save any existing file? *) 203 SetWindowText(edit, nlToCrnl(TextIO.inputAll f)); 204 TextIO.closeIn f; 205 SendMessage(edit, EM_SETMODIFY{modified=false}); 206 (LRESINT 0, SOME{edit=edit, devMode=devMode, devNames=devNames, 207 fileName=file}) 208 end) handle exn => 209 (MessageBox(SOME hw, 210 concat["Unable to open - ", file, "\n"(*, exnMessage exn*)], 211 "Open failure", MessageBoxStyle.MB_OK); 212 (LRESINT 0, state)) 213 else (LRESINT 0, state) 214 end 215 216 else if wId = menuSave andalso fileName <> "" 217 then (* Save to the original file name if there is one. *) 218 ( 219 saveDocument(hw, fileName, edit); 220 (LRESINT 0, state) 221 ) 222 223 else if wId = menuSaveAs orelse wId = menuSave (* andalso fileName = "" *) 224 then 225 ( 226 case saveAsDocument(hw, edit) of 227 NONE => (LRESINT 0, state) 228 | SOME newName => 229 (LRESINT 0, (* Use the selected file name. *) 230 SOME{edit=edit, devMode=devMode, devNames=devNames, 231 fileName=newName}) 232 ) 233 234 else if wId = menuFind 235 then 236 let 237 open FindReplaceFlags 238 (* Create a "Find" dialogue. *) 239 val find = 240 FindText{owner = hw, template = TemplateDefault, 241 flags=flags[FR_DOWN, FR_HIDEWHOLEWORD], 242 findWhat="", replaceWith="", bufferSize = 100} 243 in 244 ShowWindow(find, SW_SHOW); 245 (LRESINT 0, state) 246 end 247 248 (* Cut, Copy and Paste are all handled by the Edit window. *) 249 else if wId = menuCut 250 then (SendMessage(edit, WM_CUT); (LRESINT 0, state)) 251 else if wId = menuCopy 252 then (SendMessage(edit, WM_COPY); (LRESINT 0, state)) 253 else if wId = menuPaste 254 then (SendMessage(edit, WM_PASTE); (LRESINT 0, state)) 255 256 else if wId = menuPageSetup 257 then 258 ( 259 (* Put up the dialogue and change the settings if necessary. *) 260 case PageSetupDlg {owner=SOME hw, devMode=devMode, devNames=devNames, 261 flags=PageSetupFlags.flags[], paperSize={x=0,y=0}, 262 minMargin={top=0,bottom=0,left=0,right=0}, 263 margin={top=0,bottom=0,left=0,right=0}} of 264 NONE => (LRESINT 0, state) 265 | SOME {devMode, devNames, ...} => 266 (LRESINT 0, SOME{edit=edit, devMode=devMode, devNames=devNames, 267 fileName=fileName}) 268 ) 269 270 else if wId = menuPrint (* "Print" menu item. *) 271 then 272 let 273 (* Put up the dialogue box to get the settings. *) 274 val printSettings = 275 PrintDlg {owner=SOME hw, devMode=devMode, devNames=devNames, 276 context=NONE, 277 flags=PrintDlgFlags.flags[PrintDlgFlags.PD_RETURNDC], 278 fromPage=1, toPage= ~1, minPage=1, maxPage= ~1, copies=1}; 279 in 280 case printSettings of 281 SOME {devMode, devNames, context = SOME hdc, flags, fromPage, toPage, ...} => 282 (let 283 (* If the "Selection" button has been pressed we only print the 284 selection. *) 285 val printWhat = 286 if PrintDlgFlags.anySet(flags, PrintDlgFlags.PD_SELECTION) 287 then 288 let 289 val from = ref 0 and to = ref 0 290 val _ = SendMessage(edit, EM_GETSEL{startPos = from, endPos = to}) 291 val text = GetWindowText edit 292 in 293 if !from < 0 orelse !from > size text orelse 294 !to < 0 orelse !from > size text 295 then "" 296 else String.substring(text, !from, !to - !from) 297 end 298 else (* "All" button pressed or "Pages" pressed. *) 299 GetWindowText edit; 300 val textLength = size printWhat 301 302 (* Tell the spooler to start the document. *) 303 val jobID = StartDoc(hdc, {docName=fileName, output=NONE, dType=NONE}) 304 305 (* Find out how big a character is. From this we can work out 306 how many characters fit on a line and how many lines on a 307 page. Since we're using a fixed width font this is fairly 308 easy. *) 309 val _ = SetMapMode(hdc, MM_TEXT) 310 val white = RGB{red=255, blue=255, green=255} 311 val black = RGB{red=0, blue=0, green = 0} 312 val pageWidth = GetDeviceCaps(hdc, HORZRES) 313 and pageHeight = GetDeviceCaps(hdc, VERTRES) 314 315 (* Create the same font as we're using on the screen. Since this is 316 a fixed width font it makes calculating the number of characters 317 fairly easy. *) 318 val charHeight = ~10 * GetDeviceCaps(hdc, LOGPIXELSY) div 72; 319 val hFont = CreateFont{height=charHeight, width=0, escapement=0, orientation=0, 320 weight=FW_DONTCARE, italic=false, underline=false, strikeOut=false, 321 charSet=ANSI_CHARSET, outputPrecision=OUT_DEFAULT_PRECIS, 322 clipPrecision=CLIP_DEFAULT_PRECIS, quality=DEFAULT_QUALITY, 323 pitch=FIXED_PITCH, family=FF_MODERN, faceName="Courier"} 324 val oldFont = SelectObject(hdc, hFont); (* Use this font. *) 325 326 val textMetric = GetTextMetrics hdc; 327 328 fun printPage pno index = 329 let 330 (* If we are printing a range of pages we need to check whether 331 we are in the range. *) 332 val printThisPage = 333 if PrintDlgFlags.anySet(flags, PrintDlgFlags.PD_PAGENUMS) 334 then pno >= fromPage andalso (pno <= toPage orelse toPage < 0) 335 else true 336 val pageRect = {top=0, left=0, bottom=pageHeight, right=pageWidth} 337 (* Calculate the number of lines and columns. *) 338 val nLines = pageHeight div #height textMetric; 339 val nCols = pageWidth div #maxCharWidth textMetric 340 341 (* Output the lines to fill the page. *) 342 fun outputLines lineNo p = 343 if lineNo >= nLines 344 then p (* Return last pointer. *) 345 else 346 let 347 (* Find the point to split the line. We stop at the end of 348 the text, a line break, the last word break on the line 349 or the maximum number of characters. *) 350 fun findEnd lastBreak i = 351 if i >= textLength then (textLength, textLength) 352 else if i-p > nCols 353 then 354 ( 355 case lastBreak of 356 NONE => (* No breaks on the line - break just before here. *) 357 (i-1, i-1) 358 | SOME b => b (* Break at the last break. *) 359 ) 360 else if i < textLength - 1 andalso 361 String.sub(printWhat, i) = #"\r" andalso 362 String.sub(printWhat, i+1) = #"\n" 363 then (* End of line - stop here. *) 364 (i, i+2) 365 else if Char.isSpace(String.sub(printWhat, i)) 366 then (* Remember this. *) 367 findEnd (SOME(i, i+1)) (i+1) 368 (* Actually tabs need to be handled more carefully. *) 369 else findEnd lastBreak (i+1) 370 371 val (endLine, nextLine) = findEnd NONE p 372 val thisLine = 373 if p >= textLength 374 then "" 375 else String.substring(printWhat, p, endLine-p) 376 in 377 if printThisPage 378 then 379 ( 380 TabbedTextOut(hdc, {x=0, y= lineNo * #height textMetric}, 381 thisLine, [], 0); 382 () 383 ) 384 else (); 385 outputLines (lineNo+1) nextLine 386 end 387 val nextPage = 388 if printThisPage 389 then 390 let 391 val _ = StartPage hdc; 392 (* Fill the page with white. *) 393 val _ = SetBkColor(hdc, white); 394 val _ = SetTextColor(hdc, black); 395 val _ = ExtTextOut(hdc, {x=0, y=0}, [ETO_OPAQUE], SOME pageRect, "", []); 396 (* Print the text. *) 397 val next = outputLines 0 index 398 in 399 EndPage hdc; 400 next 401 end 402 else (* Format the page but don't print it. *) outputLines 0 index 403 in 404 if nextPage >= size printWhat 405 then () 406 else printPage (pno+1) nextPage 407 end 408 409 val _: unit = printPage 1 0 410 in 411 EndDoc hdc; 412 (* Restore the original font and delete the new one. *) 413 SelectObject(hdc, oldFont); 414 DeleteObject(hFont); 415 DeleteDC hdc; (* Now delete the device context. *) 416 (LRESINT 0, SOME{edit=edit, devMode=devMode, devNames=devNames, 417 fileName=fileName}) 418 end 419 (* If any of the functions failed simply delete the device 420 context and return the original state. *) 421 handle (exn as OS.SysErr _) => ( 422 print (exnName exn); AbortDoc hdc; DeleteDC hdc; (LRESINT 0, state))) 423 | _ => (LRESINT 0, state) 424 end 425 426 else if wId = menuAbout 427 then (aboutmlEdit hw; (LRESINT 0, state)) 428 429 else (DefWindowProc(hw, msg), state) 430 431 | FINDMSGSTRING{flags, findWhat, ...} => 432 if FindReplaceFlags.anySet(flags, FindReplaceFlags.FR_DIALOGTERM) 433 then (* The "find" box is going away. *) 434 ( 435 SetFocus(SOME edit); 436 (LRESINT 0, state) 437 ) 438 else if FindReplaceFlags.anySet(flags, FindReplaceFlags.FR_FINDNEXT) 439 then (* The Find Next button has been pressed. *) 440 let 441 (* Get the whole of the text - not very efficient. *) 442 val text = GetWindowText edit 443 val startPos = ref 0 and endPos = ref 0 444 (* Get the starting position. *) 445 val _ = SendMessage(edit, EM_GETSEL{startPos=startPos, endPos=endPos}) 446 447 val isDown = FindReplaceFlags.anySet(flags, FindReplaceFlags.FR_DOWN) 448 (* Get the starting position for the search. *) 449 val startPos = if isDown then !endPos else !startPos - 1 450 451 val findLen = size findWhat 452 (* Get the options. *) 453 local 454 val toLower = String.map Char.toLower 455 in 456 val doMatch: string * string -> bool = 457 if FindReplaceFlags.anySet(flags, FindReplaceFlags.FR_MATCHCASE) 458 then op = 459 else fn (s1, s2) => toLower s1 = toLower s2 460 end 461 462 fun doFind p = 463 let 464 val isMatch = 465 p >= 0 andalso size text - p >= size findWhat andalso 466 doMatch(String.substring(text, p, findLen), findWhat) 467 in 468 if isMatch then p 469 else if isDown 470 then if p = size text then p (* Finish *) else doFind(p+1) 471 else (* Find up *) if p = 0 then ~1 (* Finish *) else doFind(p-1) 472 end 473 val foundAt = doFind startPos 474 in 475 if foundAt >= 0 andalso foundAt + findLen < size text 476 then 477 ( 478 SendMessage(edit, EM_SETSEL{startPos=foundAt, endPos=foundAt + findLen}); 479 SendMessage(edit, EM_SCROLLCARET); 480 () 481 ) 482 else MessageBeep(MessageBoxStyle.fromWord 0wxFFFFFFFF); 483 (LRESINT 0, state) 484 end 485 else (DefWindowProc(hw, msg), state) 486 487 | _ => (DefWindowProc(hw, msg), state) 488 489 (* If this document has been modified we want to ask before quitting or 490 opening a new document. *) 491 and checkForSave(hw, edit, fileName) = 492 case SendMessage(edit, EM_GETMODIFY) of 493 LRESINT 0 => true (* Unmodified - continue. *) 494 | _ => 495 let 496 val res = 497 MessageBox(SOME hw, "Save document?", "Confirm", 498 MessageBoxStyle.MB_YESNOCANCEL) 499 in 500 if res = IDYES 501 then if fileName = "" 502 then saveAsDocument(hw, edit) <> NONE 503 else saveDocument(hw, fileName, edit) 504 else if res = IDNO 505 then true (* Continue anyway. *) 506 else false (* Cancel - don't exit or open. *) 507 end 508 509 and saveDocument(hw, fileName, edit) = 510 (* Write the document to the given file name. *) 511 let 512 (* Write the file as binary. That way we don't need to 513 convert CRNL to NL before writing. *) 514 val f = BinIO.openOut fileName 515 val s = GetWindowText edit 516 in 517 BinIO.output(f, Byte.stringToBytes s); 518 BinIO.closeOut f; 519 (* Document is now unmodified. *) 520 SendMessage(edit, EM_SETMODIFY{modified=false}); 521 true (* Succeeded. *) 522 end handle exn => 523 (MessageBox(SOME hw, 524 concat["Unable to save to - ", fileName, "\n"(*, exnMessage exn*)], 525 "Open failure", MessageBoxStyle.MB_OK); 526 false) 527 528 and saveAsDocument(hw, edit) = 529 (* Ask for the file name before trying to save. *) 530 let 531 val on = { 532 owner = SOME hw, 533 template = TemplateDefault, 534 filter = 535 [("Text Files (*.txt)", "*.txt"), 536 ("ML Files (*.sml)", "*.sml"), 537 ("All Files (*.*)", "*.*")], 538 customFilter = NONE, 539 filterIndex = 1, 540 file = "", 541 maxFile = 1000, 542 fileTitle = "", 543 initialDir = NONE, 544 title = NONE, 545 flags = OpenFileFlags.flags[], 546 defExt = NONE 547 } 548 in 549 case GetSaveFileName on of 550 NONE => NONE 551 | SOME {file, filterIndex, fileTitle, ...} => 552 let 553 (* If the user typed a file name without an extension use 554 the extension from the appropriate filter. *) 555 val suffix = 556 case filterIndex of 557 1 => ".txt" 558 | 2 => ".sml" 559 | _ => "" 560 val fileName = 561 if Char.contains fileTitle #"." 562 then file else file ^ suffix 563 in 564 if saveDocument(hw, fileName, edit) 565 then SOME file (* Return the selected name. *) 566 else NONE 567 end 568 end 569 570 and aboutmlEdit hw = 571 (* Called when the user selects "About..." from the help menu. *) 572 let 573 (* Dialogue template containing three items: an OK button, a static picture and 574 a piece of text. *) 575 val pictureId = 1000 (* Could use any number here. *) 576 open Static.Style 577 val template = 578 {x = 0, y = 0, cx = 210, cy = 94, font = SOME (8, "MS Sans Serif"), menu = NONE, 579 class = NONE,title = "About mlEdit", extendedStyle = 0, 580 style = flags[WS_POPUP, WS_CAPTION], 581 items = 582 [{x = 73, y = 62, cx = 50, cy = 14, id = 1, 583 class = DLG_BUTTON (flags[WS_CHILD, WS_VISIBLE, WS_TABSTOP]), 584 title = DLG_TITLESTRING "OK", creationData = NONE, extendedStyle = 0}, 585 {x = 7, y = 7, cx = 32, cy = 32, id = pictureId, 586 class = DLG_STATIC (flags[WS_CHILD, WS_VISIBLE, SS_ICON]), 587 title = DLG_TITLESTRING "", creationData = NONE, extendedStyle = 0}, 588 {x = 15, y = 39, cx = 180, cy = 21, id = 65535, 589 class = DLG_STATIC (flags[WS_CHILD, WS_VISIBLE, WS_GROUP]), 590 title = 591 DLG_TITLESTRING 592 "mlEdit - An example of Windows programming in Poly/ML\ 593 \\nCopyright David C.J. Matthews 2001-7", 594 creationData = NONE, extendedStyle = 0}] } 595 596 (* Dialogue procedure. *) 597 fun dlgProc(dial, WM_INITDIALOG _, ()) = 598 ( 599 (* Send a message to the picture control to set it to this icon. *) 600 SendMessage(GetDlgItem(dial, pictureId), STM_SETICON{icon=polyIcon}); 601 (LRESINT 1, ()) 602 ) 603 604 | dlgProc(dial, WM_COMMAND{notifyCode = 0, wId=1 (* OK button *), ...}, ()) = 605 (* When the OK button is pressed we end the dialogue. *) 606 (EndDialog(dial, 1); (LRESINT 1, ()) ) 607 608 | dlgProc _ = (LRESINT 0, ()) 609 610 in 611 DialogBoxIndirect(app, template, hw, dlgProc, ()); 612 () 613 end 614 615 val className = "mlEditWindowClass" 616 (* Register a class for the top-level window. Use the Poly icon from the application. *) 617 val myWindowClass = RegisterClassEx{style = Class.Style.flags[], 618 wndProc = wndProc, hInstance = app, 619 hIcon = SOME polyIcon, hCursor = NONE, hbrBackGround = NONE, menuName = NONE, 620 className = className, hIconSm = NONE}; 621 622 623 val w = CreateWindow{class = myWindowClass, name = "mlEdit", style = Window.Style.WS_OVERLAPPEDWINDOW, 624 x = CW_USEDEFAULT, y = CW_USEDEFAULT, height = CW_USEDEFAULT, width = CW_USEDEFAULT, 625 relation = PopupWindow menu, 626 instance = app, init = NONE}; 627in 628 ShowWindow(w, SW_SHOW); 629 SetForegroundWindow w; 630 631 RunApplication(); 632 (* Must unregister the class before returning otherwise RegisterClass will 633 fail if we call mlEdit again. *) 634 UnregisterClass(className, app) 635end; 636 </pre> 637</body> 638</html> 639