1 /*
2  * PROJECT:     ReactOS VGA Font Editor
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Implements the main window of the application
5  * COPYRIGHT:   Copyright 2008 Colin Finck (colin@reactos.org)
6  *              Copyright 2018 Katayama Hirofui MZ (katayama.hirofumi.mz@gmail.com)
7  */
8 
9 #include "precomp.h"
10 
11 static const WCHAR szMainWndClass[] = L"VGAFontEditMainWndClass";
12 
13 static VOID
InitResources(IN PMAIN_WND_INFO Info)14 InitResources(IN PMAIN_WND_INFO Info)
15 {
16     HDC hMemDC;
17     HDC hMainDC;
18     HPEN hPen, hPenOld;
19     RECT rect;
20     HBITMAP hBitmapOld;
21 
22     hMemDC = CreateCompatibleDC(NULL);
23     hMainDC = GetDC(Info->hMainWnd);
24 
25     // Create the "Box" bitmap
26     Info->hBoxBmp = CreateCompatibleBitmap(hMainDC, CHARACTER_BOX_WIDTH, CHARACTER_BOX_HEIGHT);
27     hBitmapOld = SelectObject(hMemDC, Info->hBoxBmp);
28 
29     rect.left = 0;
30     rect.top = 0;
31     rect.right = CHARACTER_INFO_BOX_WIDTH;
32     rect.bottom = CHARACTER_INFO_BOX_HEIGHT;
33     FillRect( hMemDC, &rect, (HBRUSH)(COLOR_BTNFACE + 1) );
34 
35     hPenOld = SelectObject( hMemDC, GetStockObject(WHITE_PEN) );
36     Rectangle(hMemDC, 0, 0, CHARACTER_INFO_BOX_WIDTH - 1, 2);
37     Rectangle(hMemDC, 0, 2, 2, CHARACTER_INFO_BOX_HEIGHT - 1);
38     hPen = SelectObject(hMemDC, hPenOld);
39 
40     hPen = CreatePen( PS_SOLID, 1, RGB(128, 128, 128) );
41     hPenOld = SelectObject(hMemDC, hPen);
42     Rectangle(hMemDC, 1, CHARACTER_INFO_BOX_HEIGHT - 2, CHARACTER_INFO_BOX_WIDTH, CHARACTER_INFO_BOX_HEIGHT);
43     Rectangle(hMemDC, CHARACTER_INFO_BOX_WIDTH - 2, 1, CHARACTER_INFO_BOX_WIDTH, CHARACTER_INFO_BOX_HEIGHT - 2);
44 
45     SetPixel( hMemDC, CHARACTER_INFO_BOX_WIDTH - 1, 0, RGB(128, 128, 128) );
46     SetPixel( hMemDC, 0, CHARACTER_INFO_BOX_HEIGHT - 1, RGB(128, 128, 128) );
47     SelectObject(hMemDC, hBitmapOld);
48 
49     hPen = SelectObject(hMemDC, hPenOld);
50     DeleteObject(hPen);
51     DeleteDC(hMemDC);
52     ReleaseDC(Info->hMainWnd, hMainDC);
53 }
54 
55 static VOID
UnInitResources(IN PMAIN_WND_INFO Info)56 UnInitResources(IN PMAIN_WND_INFO Info)
57 {
58     DeleteObject(Info->hBoxBmp);
59 }
60 
61 static VOID
AddToolbarButton(IN PMAIN_WND_INFO Info,IN INT iBitmap,IN INT idCommand,IN UINT uID)62 AddToolbarButton(IN PMAIN_WND_INFO Info, IN INT iBitmap, IN INT idCommand, IN UINT uID)
63 {
64     PWSTR pszTooltip;
65     TBBUTTON tbb = {0,};
66 
67     if( AllocAndLoadString(&pszTooltip, uID) )
68     {
69         tbb.fsState = TBSTATE_ENABLED;
70         tbb.iBitmap = iBitmap;
71         tbb.idCommand = idCommand;
72         tbb.iString = (INT_PTR)pszTooltip;
73 
74         SendMessageW( Info->hToolbar, TB_ADDBUTTONSW, 1, (LPARAM)&tbb );
75         HeapFree(hProcessHeap, 0, pszTooltip);
76     }
77 }
78 
79 static VOID
SetToolbarButtonState(IN PMAIN_WND_INFO Info,INT idCommand,BOOL bEnabled)80 SetToolbarButtonState(IN PMAIN_WND_INFO Info, INT idCommand, BOOL bEnabled)
81 {
82     TBBUTTONINFOW tbbi = {0,};
83 
84     tbbi.cbSize = sizeof(tbbi);
85     tbbi.dwMask = TBIF_STATE;
86     tbbi.fsState = (bEnabled ? TBSTATE_ENABLED : 0);
87 
88     SendMessageW(Info->hToolbar, TB_SETBUTTONINFOW, idCommand, (LPARAM)&tbbi);
89 }
90 
91 VOID
SetToolbarFileButtonState(IN PMAIN_WND_INFO Info,BOOL bEnabled)92 SetToolbarFileButtonState(IN PMAIN_WND_INFO Info, BOOL bEnabled)
93 {
94     SetToolbarButtonState(Info, ID_FILE_SAVE, bEnabled);
95     SetToolbarButtonState(Info, ID_EDIT_GLYPH, bEnabled);
96     SetToolbarButtonState(Info, ID_EDIT_COPY, bEnabled);
97 }
98 
99 static VOID
AddToolbarSeparator(IN PMAIN_WND_INFO Info)100 AddToolbarSeparator(IN PMAIN_WND_INFO Info)
101 {
102     TBBUTTON tbb = {0,};
103 
104     tbb.fsStyle = BTNS_SEP;
105 
106     SendMessageW( Info->hToolbar, TB_ADDBUTTONSW, 1, (LPARAM)&tbb );
107 }
108 
109 static VOID
InitMainWnd(IN PMAIN_WND_INFO Info)110 InitMainWnd(IN PMAIN_WND_INFO Info)
111 {
112     CLIENTCREATESTRUCT ccs;
113     INT iCustomBitmaps;
114     INT iStandardBitmaps;
115     TBADDBITMAP tbab;
116 
117     // Add the toolbar
118     Info->hToolbar = CreateWindowExW(0,
119                                      TOOLBARCLASSNAMEW,
120                                      NULL,
121                                      WS_VISIBLE | WS_CHILD | TBSTYLE_TOOLTIPS,
122                                      0,
123                                      0,
124                                      0,
125                                      0,
126                                      Info->hMainWnd,
127                                      NULL,
128                                      hInstance,
129                                      NULL);
130 
131     // Identify the used Common Controls version
132     SendMessageW(Info->hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
133 
134     // Enable Tooltips
135     SendMessageW(Info->hToolbar, TB_SETMAXTEXTROWS, 0, 0);
136 
137     // Add the toolbar bitmaps
138     tbab.hInst = HINST_COMMCTRL;
139     tbab.nID = IDB_STD_SMALL_COLOR;
140     iStandardBitmaps = (INT)SendMessageW(Info->hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
141 
142     tbab.hInst = hInstance;
143     tbab.nID = IDB_MAIN_TOOLBAR;
144     iCustomBitmaps = (INT)SendMessageW(Info->hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
145 
146     // Add the toolbar buttons
147     AddToolbarButton(Info, iStandardBitmaps + STD_FILENEW, ID_FILE_NEW, IDS_TOOLTIP_NEW);
148     AddToolbarButton(Info, iStandardBitmaps + STD_FILEOPEN, ID_FILE_OPEN, IDS_TOOLTIP_OPEN);
149     AddToolbarButton(Info, iStandardBitmaps + STD_FILESAVE, ID_FILE_SAVE, IDS_TOOLTIP_SAVE);
150     AddToolbarSeparator(Info);
151     AddToolbarButton(Info, iCustomBitmaps + TOOLBAR_EDIT_GLYPH, ID_EDIT_GLYPH, IDS_TOOLTIP_EDIT_GLYPH);
152     AddToolbarSeparator(Info);
153     AddToolbarButton(Info, iStandardBitmaps + STD_COPY, ID_EDIT_COPY, IDS_TOOLTIP_COPY);
154     AddToolbarButton(Info, iStandardBitmaps + STD_PASTE, ID_EDIT_PASTE, IDS_TOOLTIP_PASTE);
155 
156     SetToolbarFileButtonState(Info, FALSE);
157     SetPasteButtonState(Info);
158 
159     // Add the MDI client area
160     ccs.hWindowMenu = GetSubMenu(Info->hMenu, 2);
161     ccs.idFirstChild = ID_MDI_FIRSTCHILD;
162 
163     Info->hMdiClient = CreateWindowExW(WS_EX_CLIENTEDGE,
164                                        L"MDICLIENT",
165                                        NULL,
166                                        WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL,
167                                        0,
168                                        0,
169                                        0,
170                                        0,
171                                        Info->hMainWnd,
172                                        NULL,
173                                        hInstance,
174                                        &ccs);
175 
176     // Initialize the file handling
177     FileInitialize(Info->hMainWnd);
178 }
179 
180 static VOID
InitMenuPopup(IN PMAIN_WND_INFO Info)181 InitMenuPopup(IN PMAIN_WND_INFO Info)
182 {
183     UINT uState;
184 
185     uState = MF_BYCOMMAND | !(Info->CurrentFontWnd);
186 
187     EnableMenuItem(Info->hMenu, ID_FILE_CLOSE, uState);
188     EnableMenuItem(Info->hMenu, ID_FILE_SAVE, uState);
189     EnableMenuItem(Info->hMenu, ID_FILE_SAVE_AS, uState);
190 
191     EnableMenuItem(Info->hMenu, ID_EDIT_COPY, uState);
192     EnableMenuItem(Info->hMenu, ID_EDIT_GLYPH, uState);
193 
194     uState = MF_BYCOMMAND | !(Info->CurrentFontWnd && IsClipboardFormatAvailable(uCharacterClipboardFormat));
195     EnableMenuItem(Info->hMenu, ID_EDIT_PASTE, uState);
196 }
197 
198 static VOID
OutOfMemory(IN PMAIN_WND_INFO Info)199 OutOfMemory(IN PMAIN_WND_INFO Info)
200 {
201     MessageBoxW(Info->hMainWnd, L"Out of memory!", NULL, MB_ICONERROR);
202 }
203 
204 static PFONT_OPEN_INFO
CreateOpenInfo(IN PMAIN_WND_INFO Info,BOOL bCreateNew,LPCWSTR File)205 CreateOpenInfo(IN PMAIN_WND_INFO Info, BOOL bCreateNew, LPCWSTR File)
206 {
207     PFONT_OPEN_INFO OpenInfo;
208 
209     OpenInfo = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(FONT_OPEN_INFO));
210     if (!OpenInfo)
211     {
212         OutOfMemory(Info);
213         return NULL;
214     }
215 
216     OpenInfo->bCreateNew = bCreateNew;
217     OpenInfo->pszFileName = HeapAlloc(hProcessHeap, 0, MAX_PATH);
218     if (!OpenInfo->pszFileName)
219     {
220         OutOfMemory(Info);
221         HeapFree(hProcessHeap, 0, OpenInfo);
222         return NULL;
223     }
224 
225     if (StringCchCopyW(OpenInfo->pszFileName, MAX_PATH, File) != S_OK)
226     {
227         MessageBoxW(Info->hMainWnd, L"Pathname is too long!", NULL, MB_ICONERROR);
228         HeapFree(hProcessHeap, 0, OpenInfo->pszFileName);
229         HeapFree(hProcessHeap, 0, OpenInfo);
230         return NULL;
231     }
232 
233     return OpenInfo;
234 }
235 
236 static VOID
DoFileNew(IN PMAIN_WND_INFO Info)237 DoFileNew(IN PMAIN_WND_INFO Info)
238 {
239     PFONT_OPEN_INFO OpenInfo = CreateOpenInfo(Info, TRUE, L"");
240     if (!OpenInfo)
241         return;
242 
243     CreateFontWindow(Info, OpenInfo);
244 }
245 
246 static VOID
DoFileOpen(IN PMAIN_WND_INFO Info)247 DoFileOpen(IN PMAIN_WND_INFO Info)
248 {
249     PFONT_OPEN_INFO OpenInfo = CreateOpenInfo(Info, FALSE, L"");
250     if (!OpenInfo)
251         return;
252 
253     if (DoOpenFile(OpenInfo->pszFileName))
254     {
255         CreateFontWindow(Info, OpenInfo);
256         return;
257     }
258 
259     HeapFree(hProcessHeap, 0, OpenInfo->pszFileName);
260     HeapFree(hProcessHeap, 0, OpenInfo);
261 }
262 
263 static VOID
MainWndOpenFile(IN PMAIN_WND_INFO Info,LPCWSTR File)264 MainWndOpenFile(IN PMAIN_WND_INFO Info, LPCWSTR File)
265 {
266     PFONT_OPEN_INFO OpenInfo = CreateOpenInfo(Info, FALSE, File);
267     if (!OpenInfo)
268         return;
269 
270     CreateFontWindow(Info, OpenInfo);
271 }
272 
273 static VOID
MainWndDropFiles(IN PMAIN_WND_INFO Info,HDROP hDrop)274 MainWndDropFiles(IN PMAIN_WND_INFO Info, HDROP hDrop)
275 {
276     WCHAR Path[MAX_PATH];
277     INT i, Count = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
278 
279     for (i = 0; i < Count; ++i)
280     {
281         DragQueryFileW(hDrop, i, Path, MAX_PATH);
282         MainWndOpenFile(Info, Path);
283     }
284 
285     DragFinish(hDrop);
286 }
287 
288 VOID
DoFileSave(IN PMAIN_WND_INFO Info,IN BOOL bSaveAs)289 DoFileSave(IN PMAIN_WND_INFO Info, IN BOOL bSaveAs)
290 {
291     DWORD dwBytesWritten;
292     HANDLE hFile;
293 
294     // Show the "Save" dialog
295     //   - if "Save As" was clicked
296     //   - if the file was not yet saved
297     //   - if another format than the binary format was opened
298     if(bSaveAs || !Info->CurrentFontWnd->OpenInfo->bBinaryFileOpened)
299     {
300         if(!Info->CurrentFontWnd->OpenInfo->pszFileName)
301         {
302             Info->CurrentFontWnd->OpenInfo->pszFileName = (PWSTR) HeapAlloc(hProcessHeap, 0, MAX_PATH);
303             Info->CurrentFontWnd->OpenInfo->pszFileName[0] = 0;
304         }
305         else if(!Info->CurrentFontWnd->OpenInfo->bBinaryFileOpened)
306         {
307             // For a file in another format, the user has to enter a new file name as well
308             Info->CurrentFontWnd->OpenInfo->pszFileName[0] = 0;
309         }
310 
311         if( !DoSaveFile(Info->CurrentFontWnd->OpenInfo->pszFileName) )
312             return;
313     }
314 
315     // Save the binary font
316     hFile = CreateFileW(Info->CurrentFontWnd->OpenInfo->pszFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
317 
318     if(hFile == INVALID_HANDLE_VALUE)
319     {
320         LocalizedError( IDS_OPENERROR, GetLastError() );
321         return;
322     }
323 
324     if( !WriteFile(hFile, Info->CurrentFontWnd->Font, sizeof(BITMAP_FONT), &dwBytesWritten, NULL) )
325         LocalizedError( IDS_WRITEERROR, GetLastError() );
326 
327     CloseHandle(hFile);
328 }
329 
330 static VOID
CopyCurrentGlyph(IN PFONT_WND_INFO FontWndInfo)331 CopyCurrentGlyph(IN PFONT_WND_INFO FontWndInfo)
332 {
333     HGLOBAL hMem;
334     PUCHAR pCharacterBits;
335 
336     if(!OpenClipboard(NULL))
337         return;
338 
339     EmptyClipboard();
340 
341     hMem = GlobalAlloc(GMEM_MOVEABLE, 8);
342     pCharacterBits = GlobalLock(hMem);
343     RtlCopyMemory(pCharacterBits, FontWndInfo->Font->Bits + FontWndInfo->uSelectedCharacter * 8, 8);
344     GlobalUnlock(hMem);
345 
346     SetClipboardData(uCharacterClipboardFormat, hMem);
347 
348     CloseClipboard();
349 }
350 
351 static VOID
PasteIntoCurrentGlyph(IN PFONT_WND_INFO FontWndInfo)352 PasteIntoCurrentGlyph(IN PFONT_WND_INFO FontWndInfo)
353 {
354     HGLOBAL hMem;
355 
356     if(!IsClipboardFormatAvailable(uCharacterClipboardFormat))
357         return;
358 
359     if(!OpenClipboard(NULL))
360         return;
361 
362     hMem = GetClipboardData(uCharacterClipboardFormat);
363     if(hMem)
364     {
365         PUCHAR pCharacterBits;
366 
367         pCharacterBits = GlobalLock(hMem);
368         if(pCharacterBits)
369         {
370             RECT CharacterRect;
371             UINT uFontRow;
372             UINT uFontColumn;
373 
374             RtlCopyMemory(FontWndInfo->Font->Bits + FontWndInfo->uSelectedCharacter * 8, pCharacterBits, 8);
375             GlobalUnlock(hMem);
376 
377             FontWndInfo->OpenInfo->bModified = TRUE;
378 
379             GetCharacterPosition(FontWndInfo->uSelectedCharacter, &uFontRow, &uFontColumn);
380             GetCharacterRect(uFontRow, uFontColumn, &CharacterRect);
381             InvalidateRect(FontWndInfo->hFontBoxesWnd, &CharacterRect, FALSE);
382         }
383     }
384 
385     CloseClipboard();
386 }
387 
388 VOID
SetPasteButtonState(IN PMAIN_WND_INFO Info)389 SetPasteButtonState(IN PMAIN_WND_INFO Info)
390 {
391     SetToolbarButtonState(Info,
392                           ID_EDIT_PASTE,
393                           (Info->CurrentFontWnd && IsClipboardFormatAvailable(uCharacterClipboardFormat)));
394 }
395 
396 static BOOL
MenuCommand(IN INT nMenuItemID,IN PMAIN_WND_INFO Info)397 MenuCommand(IN INT nMenuItemID, IN PMAIN_WND_INFO Info)
398 {
399     switch(nMenuItemID)
400     {
401         // File Menu
402         case ID_FILE_NEW:
403             DoFileNew(Info);
404             return TRUE;
405 
406         case ID_FILE_OPEN:
407             DoFileOpen(Info);
408             return TRUE;
409 
410         case ID_FILE_CLOSE:
411             SendMessageW(Info->CurrentFontWnd->hSelf, WM_CLOSE, 0, 0);
412             return TRUE;
413 
414         case ID_FILE_SAVE:
415             DoFileSave(Info, FALSE);
416             return TRUE;
417 
418         case ID_FILE_SAVE_AS:
419             DoFileSave(Info, TRUE);
420             return TRUE;
421 
422         case ID_FILE_EXIT:
423             PostMessage(Info->hMainWnd, WM_CLOSE, 0, 0);
424             return TRUE;
425 
426         // Edit Menu
427         case ID_EDIT_GLYPH:
428             EditCurrentGlyph(Info->CurrentFontWnd);
429             return TRUE;
430 
431         case ID_EDIT_COPY:
432             CopyCurrentGlyph(Info->CurrentFontWnd);
433             return TRUE;
434 
435         case ID_EDIT_PASTE:
436             PasteIntoCurrentGlyph(Info->CurrentFontWnd);
437             return TRUE;
438 
439         // Window Menu
440         case ID_WINDOW_TILE_HORZ:
441             SendMessageW(Info->hMdiClient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
442             return TRUE;
443 
444         case ID_WINDOW_TILE_VERT:
445             SendMessageW(Info->hMdiClient, WM_MDITILE, MDITILE_VERTICAL, 0);
446             return TRUE;
447 
448         case ID_WINDOW_CASCADE:
449             SendMessageW(Info->hMdiClient, WM_MDICASCADE, 0, 0);
450             return TRUE;
451 
452         case ID_WINDOW_ARRANGE:
453             SendMessageW(Info->hMdiClient, WM_MDIICONARRANGE, 0, 0);
454             return TRUE;
455 
456         case ID_WINDOW_NEXT:
457             SendMessageW(Info->hMdiClient, WM_MDINEXT, 0, 0);
458             return TRUE;
459 
460         // Help Menu
461         case ID_HELP_ABOUT:
462             DialogBoxW( hInstance, MAKEINTRESOURCEW(IDD_ABOUT), Info->hMainWnd, AboutDlgProc );
463             return TRUE;
464     }
465 
466     return FALSE;
467 }
468 
469 static VOID
MainWndSize(PMAIN_WND_INFO Info,INT cx,INT cy)470 MainWndSize(PMAIN_WND_INFO Info, INT cx, INT cy)
471 {
472     HDWP dwp;
473     INT iMdiTop;
474     RECT ToolbarRect;
475 
476     iMdiTop = 0;
477 
478     dwp = BeginDeferWindowPos(2);
479     if(!dwp)
480         return;
481 
482     if(Info->hToolbar)
483     {
484         GetWindowRect(Info->hToolbar, &ToolbarRect);
485         iMdiTop += ToolbarRect.bottom - ToolbarRect.top;
486 
487         dwp = DeferWindowPos(dwp, Info->hToolbar, NULL, 0, 0, cx, ToolbarRect.bottom - ToolbarRect.top, SWP_NOZORDER);
488         if(!dwp)
489             return;
490     }
491 
492     if(Info->hMdiClient)
493     {
494         dwp = DeferWindowPos(dwp, Info->hMdiClient, NULL, 0, iMdiTop, cx, cy - iMdiTop, SWP_NOZORDER);
495         if(!dwp)
496             return;
497     }
498 
499     EndDeferWindowPos(dwp);
500 }
501 
502 static LRESULT CALLBACK
MainWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)503 MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
504 {
505     static HWND hNextClipboardViewer;
506     INT i;
507     PMAIN_WND_INFO Info;
508 
509     Info = (PMAIN_WND_INFO) GetWindowLongPtrW(hwnd, GWLP_USERDATA);
510 
511     if(Info || uMsg == WM_CREATE)
512     {
513         switch(uMsg)
514         {
515             case WM_COMMAND:
516                 if( MenuCommand( LOWORD(wParam), Info ) )
517                     return 0;
518 
519                 break;
520 
521             case WM_CHANGECBCHAIN:
522                 if((HWND)wParam == hNextClipboardViewer)
523                     hNextClipboardViewer = (HWND)lParam;
524                 else
525                     SendMessage(hNextClipboardViewer, uMsg, wParam, lParam);
526 
527                 return 0;
528 
529             case WM_CLOSE:
530                 if(Info->FirstFontWnd)
531                 {
532                     // Send WM_CLOSE to all subwindows, so they can prompt for saving unsaved files
533                     PFONT_WND_INFO pNextWnd;
534                     PFONT_WND_INFO pWnd;
535 
536                     pWnd = Info->FirstFontWnd;
537 
538                     do
539                     {
540                         // The pWnd structure might already be destroyed after the WM_CLOSE, so we have to preserve the address of the next window here
541                         pNextWnd = pWnd->NextFontWnd;
542 
543                         // Send WM_USER_APPCLOSE, so we can check for a custom return value
544                         // In this case, we check if the user clicked the "Cancel" button in one of the prompts and if so, we don't close the app
545                         if( !SendMessage(pWnd->hSelf, WM_USER_APPCLOSE, 0, 0) )
546                             return 0;
547                     }
548                     while( (pWnd = pNextWnd) );
549                 }
550                 break;
551 
552             case WM_CREATE:
553                 Info = (PMAIN_WND_INFO)( ( (LPCREATESTRUCT)lParam )->lpCreateParams );
554                 Info->hMainWnd = hwnd;
555                 Info->hMenu = GetMenu(hwnd);
556                 SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)Info);
557 
558                 hNextClipboardViewer = SetClipboardViewer(hwnd);
559 
560                 InitMainWnd(Info);
561                 InitResources(Info);
562 
563                 ShowWindow(hwnd, Info->nCmdShow);
564 
565                 for (i = 1; i < __argc; ++i)
566                 {
567                     MainWndOpenFile(Info, __wargv[i]);
568                 }
569                 DragAcceptFiles(hwnd, TRUE);
570                 return 0;
571 
572             case WM_DESTROY:
573                 UnInitResources(Info);
574 
575                 HeapFree(hProcessHeap, 0, Info);
576                 SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0);
577                 PostQuitMessage(0);
578                 return 0;
579 
580             case WM_DRAWCLIPBOARD:
581                 SetPasteButtonState(Info);
582 
583                 // Pass the message to the next clipboard window in the chain
584                 SendMessage(hNextClipboardViewer, uMsg, wParam, lParam);
585                 return 0;
586 
587             case WM_INITMENUPOPUP:
588                 InitMenuPopup(Info);
589                 break;
590 
591             case WM_SIZE:
592                 MainWndSize( Info, LOWORD(lParam), HIWORD(lParam) );
593                 return 0;
594 
595             case WM_DROPFILES:
596                 MainWndDropFiles(Info, (HDROP)wParam);
597                 return 0;
598         }
599     }
600 
601     if(Info && Info->hMdiClient)
602         return DefFrameProcW(hwnd, Info->hMdiClient, uMsg, wParam, lParam);
603     else
604         return DefWindowProcW(hwnd, uMsg, wParam, lParam);
605 }
606 
607 BOOL
CreateMainWindow(IN INT nCmdShow,OUT PMAIN_WND_INFO * Info)608 CreateMainWindow(IN INT nCmdShow, OUT PMAIN_WND_INFO* Info)
609 {
610     HWND hMainWnd;
611 
612     *Info = (PMAIN_WND_INFO) HeapAlloc( hProcessHeap, HEAP_ZERO_MEMORY, sizeof(MAIN_WND_INFO) );
613 
614     if(*Info)
615     {
616         (*Info)->nCmdShow = nCmdShow;
617 
618         hMainWnd = CreateWindowExW(0,
619                                    szMainWndClass,
620                                    szAppName,
621                                    WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
622                                    CW_USEDEFAULT,
623                                    CW_USEDEFAULT,
624                                    CW_USEDEFAULT,
625                                    CW_USEDEFAULT,
626                                    NULL,
627                                    LoadMenuW(hInstance, MAKEINTRESOURCEW(IDM_MAINMENU)),
628                                    hInstance,
629                                    *Info);
630 
631         if(hMainWnd)
632             return TRUE;
633         else
634             HeapFree(hProcessHeap, 0, *Info);
635     }
636 
637     return FALSE;
638 }
639 
640 BOOL
InitMainWndClass(VOID)641 InitMainWndClass(VOID)
642 {
643     WNDCLASSW wc = {0,};
644 
645     wc.lpfnWndProc    = MainWndProc;
646     wc.hInstance      = hInstance;
647     wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
648     wc.hIcon          = LoadIconW( hInstance, MAKEINTRESOURCEW(IDI_MAIN) );
649     wc.hbrBackground  = (HBRUSH)( COLOR_BTNFACE + 1 );
650     wc.lpszClassName  = szMainWndClass;
651 
652     return RegisterClassW(&wc) != 0;
653 }
654 
655 VOID
UnInitMainWndClass(VOID)656 UnInitMainWndClass(VOID)
657 {
658     UnregisterClassW(szMainWndClass, hInstance);
659 }
660