2 * Wordpad implementation - Printing and print preview functions
4 * Copyright 2007-2008 by Alexander N. Sørnes <alex@thehandofagony.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 typedef struct _previewinfo
31 int saved_pages_shown
;
32 int *pageEnds
, pageCapacity
;
46 } previewinfo
, *ppreviewinfo
;
48 static HGLOBAL devMode
;
49 static HGLOBAL devNames
;
52 static previewinfo preview
;
54 extern const WCHAR wszPreviewWndClass
[];
56 static const WCHAR var_pagemargin
[] = {'P','a','g','e','M','a','r','g','i','n',0};
57 static const WCHAR var_previewpages
[] = {'P','r','e','v','i','e','w','P','a','g','e','s',0};
59 static LPWSTR
get_print_file_filter(HWND hMainWnd
)
61 static WCHAR wszPrintFilter
[MAX_STRING_LEN
*2+6+4+1];
62 const WCHAR files_prn
[] = {'*','.','P','R','N',0};
63 const WCHAR files_all
[] = {'*','.','*','\0'};
65 HINSTANCE hInstance
= GetModuleHandleW(0);
68 LoadStringW(hInstance
, STRING_PRINTER_FILES_PRN
, p
, MAX_STRING_LEN
);
70 lstrcpyW(p
, files_prn
);
72 LoadStringW(hInstance
, STRING_ALL_FILES
, p
, MAX_STRING_LEN
);
74 lstrcpyW(p
, files_all
);
78 return wszPrintFilter
;
81 void registry_set_pagemargins(HKEY hKey
)
83 RegSetValueExW(hKey
, var_pagemargin
, 0, REG_BINARY
, (LPBYTE
)&margins
, sizeof(RECT
));
86 void registry_read_pagemargins(HKEY hKey
)
88 DWORD size
= sizeof(RECT
);
90 if(!hKey
|| RegQueryValueExW(hKey
, var_pagemargin
, 0, NULL
, (LPBYTE
)&margins
,
91 &size
) != ERROR_SUCCESS
|| size
!= sizeof(RECT
))
94 margins
.bottom
= 1417;
100 void registry_set_previewpages(HKEY hKey
)
102 RegSetValueExW(hKey
, var_previewpages
, 0, REG_DWORD
,
103 (LPBYTE
)&preview
.pages_shown
, sizeof(DWORD
));
106 void registry_read_previewpages(HKEY hKey
)
108 DWORD size
= sizeof(DWORD
);
110 RegQueryValueExW(hKey
, var_previewpages
, 0, NULL
,
111 (LPBYTE
)&preview
.pages_shown
, &size
) != ERROR_SUCCESS
||
112 size
!= sizeof(DWORD
))
114 preview
.pages_shown
= 1;
116 if (preview
.pages_shown
< 1) preview
.pages_shown
= 1;
117 else if (preview
.pages_shown
> 2) preview
.pages_shown
= 2;
122 static void AddTextButton(HWND hRebarWnd
, UINT string
, UINT command
, UINT id
)
125 HINSTANCE hInstance
= GetModuleHandleW(0);
126 WCHAR text
[MAX_STRING_LEN
];
129 LoadStringW(hInstance
, string
, text
, MAX_STRING_LEN
);
130 hButton
= CreateWindowW(WC_BUTTONW
, text
,
131 WS_VISIBLE
| WS_CHILD
, 5, 5, 100, 15,
132 hRebarWnd
, ULongToHandle(command
), hInstance
, NULL
);
134 rb
.cbSize
= REBARBANDINFOW_V6_SIZE
;
135 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
136 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
137 rb
.hwndChild
= hButton
;
138 rb
.cyChild
= rb
.cyMinChild
= 22;
139 rb
.cx
= rb
.cxMinChild
= 90;
143 SendMessageW(hRebarWnd
, RB_INSERTBAND
, -1, (LPARAM
)&rb
);
146 static HDC
make_dc(void)
148 if(devNames
&& devMode
)
150 LPDEVNAMES dn
= GlobalLock(devNames
);
151 LPDEVMODEW dm
= GlobalLock(devMode
);
154 ret
= CreateDCW((LPWSTR
)dn
+ dn
->wDriverOffset
,
155 (LPWSTR
)dn
+ dn
->wDeviceOffset
, 0, dm
);
167 static LONG
twips_to_centmm(int twips
)
169 return MulDiv(twips
, CENTMM_PER_INCH
, TWIPS_PER_INCH
);
172 static LONG
centmm_to_twips(int mm
)
174 return MulDiv(mm
, TWIPS_PER_INCH
, CENTMM_PER_INCH
);
177 static LONG
twips_to_pixels(int twips
, int dpi
)
179 return MulDiv(twips
, dpi
, TWIPS_PER_INCH
);
182 static LONG
devunits_to_twips(int units
, int dpi
)
184 return MulDiv(units
, TWIPS_PER_INCH
, dpi
);
188 static RECT
get_print_rect(HDC hdc
)
195 int dpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
196 int dpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
197 width
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALWIDTH
), dpiX
);
198 height
= devunits_to_twips(GetDeviceCaps(hdc
, PHYSICALHEIGHT
), dpiY
);
201 width
= centmm_to_twips(18500);
202 height
= centmm_to_twips(27000);
205 rc
.left
= margins
.left
;
206 rc
.right
= width
- margins
.right
;
207 rc
.top
= margins
.top
;
208 rc
.bottom
= height
- margins
.bottom
;
213 void target_device(HWND hMainWnd
, DWORD wordWrap
)
215 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
217 if(wordWrap
== ID_WORDWRAP_MARGIN
)
222 RECT rc
= get_print_rect(hdc
);
224 width
= rc
.right
- rc
.left
;
227 HDC hMaindc
= GetDC(hMainWnd
);
228 hdc
= CreateCompatibleDC(hMaindc
);
229 ReleaseDC(hMainWnd
, hMaindc
);
231 result
= SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, (WPARAM
)hdc
, width
);
235 /* otherwise EM_SETTARGETDEVICE failed, so fall back on wrapping
236 * to window using the NULL DC. */
239 if (wordWrap
!= ID_WORDWRAP_NONE
) {
240 SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, 0, 0);
242 SendMessageW(hEditorWnd
, EM_SETTARGETDEVICE
, 0, 1);
247 static LPWSTR
dialog_print_to_file(HWND hMainWnd
)
250 static WCHAR file
[MAX_PATH
] = {'O','U','T','P','U','T','.','P','R','N',0};
251 static const WCHAR defExt
[] = {'P','R','N',0};
252 static LPWSTR file_filter
;
255 file_filter
= get_print_file_filter(hMainWnd
);
257 ZeroMemory(&ofn
, sizeof(ofn
));
259 ofn
.lStructSize
= sizeof(ofn
);
260 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
| OFN_OVERWRITEPROMPT
;
261 ofn
.hwndOwner
= hMainWnd
;
262 ofn
.lpstrFilter
= file_filter
;
263 ofn
.lpstrFile
= file
;
264 ofn
.nMaxFile
= MAX_PATH
;
265 ofn
.lpstrDefExt
= defExt
;
267 if(GetSaveFileNameW(&ofn
))
273 static void char_from_pagenum(HWND hEditorWnd
, FORMATRANGE
*fr
, int page
)
279 for(i
= 1; i
< page
; i
++)
281 int bottom
= fr
->rc
.bottom
;
282 fr
->chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, (LPARAM
)fr
);
283 fr
->rc
.bottom
= bottom
;
287 static HWND
get_ruler_wnd(HWND hMainWnd
)
289 return GetDlgItem(GetDlgItem(hMainWnd
, IDC_REBAR
), IDC_RULER
);
292 void redraw_ruler(HWND hRulerWnd
)
296 GetClientRect(hRulerWnd
, &rc
);
297 InvalidateRect(hRulerWnd
, &rc
, TRUE
);
300 static void update_ruler(HWND hRulerWnd
)
302 SendMessageW(hRulerWnd
, WM_USER
, 0, 0);
303 redraw_ruler(hRulerWnd
);
306 static void add_ruler_units(HDC hdcRuler
, RECT
* drawRect
, BOOL NewMetrics
, LONG EditLeftmost
)
312 static HBITMAP hBitmap
;
313 int i
, x
, y
, RulerTextEnd
;
317 WCHAR FontName
[] = {'M','S',' ','S','a','n','s',' ','S','e','r','i','f',0};
322 DeleteObject(hBitmap
);
325 hdc
= CreateCompatibleDC(0);
327 CmPixels
= twips_to_pixels(centmm_to_twips(1000), GetDeviceCaps(hdc
, LOGPIXELSX
));
328 QuarterCmPixels
= (int)((float)CmPixels
/ 4.0);
330 hBitmap
= CreateCompatibleBitmap(hdc
, drawRect
->right
, drawRect
->bottom
);
331 SelectObject(hdc
, hBitmap
);
332 FillRect(hdc
, drawRect
, GetStockObject(WHITE_BRUSH
));
334 hFont
= CreateFontW(10, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FontName
);
336 SelectObject(hdc
, hFont
);
337 SetBkMode(hdc
, TRANSPARENT
);
338 SetTextAlign(hdc
, TA_CENTER
);
339 y
= (int)(((float)drawRect
->bottom
- (float)drawRect
->top
) / 2.0) + 1;
340 RulerTextEnd
= drawRect
->right
- EditLeftmost
+ 1;
341 for(i
= 1, x
= EditLeftmost
; x
< (drawRect
->right
- EditLeftmost
+ 1); i
++)
344 WCHAR format
[] = {'%','d',0};
347 x2
+= QuarterCmPixels
;
348 if(x2
> RulerTextEnd
)
351 MoveToEx(hdc
, x2
, y
, NULL
);
352 LineTo(hdc
, x2
, y
+2);
354 x2
+= QuarterCmPixels
;
355 if(x2
> RulerTextEnd
)
358 MoveToEx(hdc
, x2
, y
- 3, NULL
);
359 LineTo(hdc
, x2
, y
+ 3);
361 x2
+= QuarterCmPixels
;
362 if(x2
> RulerTextEnd
)
365 MoveToEx(hdc
, x2
, y
, NULL
);
366 LineTo(hdc
, x2
, y
+2);
372 wsprintfW(str
, format
, i
);
373 TextOutW(hdc
, x
, 5, str
, lstrlenW(str
));
378 BitBlt(hdcRuler
, 0, 0, drawRect
->right
, drawRect
->bottom
, hdc
, 0, 0, SRCAND
);
381 static void paint_ruler(HWND hWnd
, LONG EditLeftmost
, BOOL NewMetrics
)
384 HDC hdc
= BeginPaint(hWnd
, &ps
);
385 HDC hdcPrint
= make_dc();
386 RECT printRect
= get_print_rect(hdcPrint
);
388 HBRUSH hBrush
= CreateSolidBrush(GetSysColor(COLOR_MENU
));
390 GetClientRect(hWnd
, &drawRect
);
391 FillRect(hdc
, &drawRect
, hBrush
);
394 drawRect
.bottom
-= 3;
395 drawRect
.left
= EditLeftmost
;
396 drawRect
.right
= twips_to_pixels(printRect
.right
- margins
.left
, GetDeviceCaps(hdc
, LOGPIXELSX
));
397 FillRect(hdc
, &drawRect
, GetStockObject(WHITE_BRUSH
));
401 DrawEdge(hdc
, &drawRect
, EDGE_SUNKEN
, BF_RECT
);
403 drawRect
.left
= drawRect
.right
- 1;
404 drawRect
.right
= twips_to_pixels(printRect
.right
+ margins
.right
- margins
.left
, GetDeviceCaps(hdc
, LOGPIXELSX
));
405 DrawEdge(hdc
, &drawRect
, EDGE_ETCHED
, BF_RECT
);
409 add_ruler_units(hdc
, &drawRect
, NewMetrics
, EditLeftmost
);
411 SelectObject(hdc
, GetStockObject(BLACK_BRUSH
));
412 DeleteObject(hBrush
);
417 LRESULT CALLBACK
ruler_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
419 static WNDPROC pPrevRulerProc
;
420 static LONG EditLeftmost
;
421 static BOOL NewMetrics
;
428 EditLeftmost
= ((POINTL
*)wParam
)->x
;
429 pPrevRulerProc
= (WNDPROC
)lParam
;
435 paint_ruler(hWnd
, EditLeftmost
, NewMetrics
);
439 return CallWindowProcW(pPrevRulerProc
, hWnd
, msg
, wParam
, lParam
);
445 static void print(LPPRINTDLGW pd
, LPWSTR wszFileName
)
449 HWND hEditorWnd
= GetDlgItem(pd
->hwndOwner
, IDC_EDITOR
);
450 int printedPages
= 0;
453 fr
.hdcTarget
= pd
->hDC
;
455 fr
.rc
= get_print_rect(fr
.hdc
);
457 fr
.rcPage
.right
= fr
.rc
.right
+ margins
.right
;
459 fr
.rcPage
.bottom
= fr
.rc
.bottom
+ margins
.bottom
;
461 ZeroMemory(&di
, sizeof(di
));
462 di
.cbSize
= sizeof(di
);
463 di
.lpszDocName
= wszFileName
;
465 if(pd
->Flags
& PD_PRINTTOFILE
)
467 di
.lpszOutput
= dialog_print_to_file(pd
->hwndOwner
);
472 if(pd
->Flags
& PD_SELECTION
)
474 SendMessageW(hEditorWnd
, EM_EXGETSEL
, 0, (LPARAM
)&fr
.chrg
);
478 gt
.flags
= GTL_DEFAULT
;
481 fr
.chrg
.cpMax
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
483 if(pd
->Flags
& PD_PAGENUMS
)
484 char_from_pagenum(hEditorWnd
, &fr
, pd
->nToPage
);
487 StartDocW(fr
.hdc
, &di
);
490 int bottom
= fr
.rc
.bottom
;
491 if(StartPage(fr
.hdc
) <= 0)
494 fr
.chrg
.cpMin
= SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)&fr
);
496 if(EndPage(fr
.hdc
) <= 0)
498 bottom
= fr
.rc
.bottom
;
501 if((pd
->Flags
& PD_PAGENUMS
) && (printedPages
> (pd
->nToPage
- pd
->nFromPage
)))
504 while(fr
.chrg
.cpMin
&& fr
.chrg
.cpMin
< fr
.chrg
.cpMax
);
507 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
510 void dialog_printsetup(HWND hMainWnd
)
514 ZeroMemory(&ps
, sizeof(ps
));
515 ps
.lStructSize
= sizeof(ps
);
516 ps
.hwndOwner
= hMainWnd
;
517 ps
.Flags
= PSD_INHUNDREDTHSOFMILLIMETERS
| PSD_MARGINS
;
518 ps
.rtMargin
.left
= twips_to_centmm(margins
.left
);
519 ps
.rtMargin
.right
= twips_to_centmm(margins
.right
);
520 ps
.rtMargin
.top
= twips_to_centmm(margins
.top
);
521 ps
.rtMargin
.bottom
= twips_to_centmm(margins
.bottom
);
522 ps
.hDevMode
= devMode
;
523 ps
.hDevNames
= devNames
;
525 if(PageSetupDlgW(&ps
))
527 margins
.left
= centmm_to_twips(ps
.rtMargin
.left
);
528 margins
.right
= centmm_to_twips(ps
.rtMargin
.right
);
529 margins
.top
= centmm_to_twips(ps
.rtMargin
.top
);
530 margins
.bottom
= centmm_to_twips(ps
.rtMargin
.bottom
);
531 devMode
= ps
.hDevMode
;
532 devNames
= ps
.hDevNames
;
533 update_ruler(get_ruler_wnd(hMainWnd
));
537 void get_default_printer_opts(void)
540 ZeroMemory(&pd
, sizeof(pd
));
542 ZeroMemory(&pd
, sizeof(pd
));
543 pd
.lStructSize
= sizeof(pd
);
544 pd
.Flags
= PD_RETURNDC
| PD_RETURNDEFAULT
;
545 pd
.hDevMode
= devMode
;
549 devMode
= pd
.hDevMode
;
550 devNames
= pd
.hDevNames
;
553 void print_quick(HWND hMainWnd
, LPWSTR wszFileName
)
557 ZeroMemory(&pd
, sizeof(pd
));
558 pd
.hwndOwner
= hMainWnd
;
561 print(&pd
, wszFileName
);
565 void dialog_print(HWND hMainWnd
, LPWSTR wszFileName
)
568 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
572 ZeroMemory(&pd
, sizeof(pd
));
573 pd
.lStructSize
= sizeof(pd
);
574 pd
.hwndOwner
= hMainWnd
;
575 pd
.Flags
= PD_RETURNDC
| PD_USEDEVMODECOPIESANDCOLLATE
;
578 pd
.hDevMode
= devMode
;
579 pd
.hDevNames
= devNames
;
581 SendMessageW(hEditorWnd
, EM_GETSEL
, (WPARAM
)&from
, (LPARAM
)&to
);
583 pd
.Flags
|= PD_NOSELECTION
;
587 devMode
= pd
.hDevMode
;
588 devNames
= pd
.hDevNames
;
589 print(&pd
, wszFileName
);
590 update_ruler(get_ruler_wnd(hMainWnd
));
594 static void preview_bar_show(HWND hMainWnd
, BOOL show
)
596 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
603 UINT num_pages_string
= preview
.pages_shown
> 1 ? STRING_PREVIEW_ONEPAGE
:
604 STRING_PREVIEW_TWOPAGES
;
606 AddTextButton(hReBar
, STRING_PREVIEW_PRINT
, ID_PRINT
, BANDID_PREVIEW_BTN1
);
607 AddTextButton(hReBar
, STRING_PREVIEW_NEXTPAGE
, ID_PREVIEW_NEXTPAGE
, BANDID_PREVIEW_BTN2
);
608 AddTextButton(hReBar
, STRING_PREVIEW_PREVPAGE
, ID_PREVIEW_PREVPAGE
, BANDID_PREVIEW_BTN3
);
609 AddTextButton(hReBar
, num_pages_string
, ID_PREVIEW_NUMPAGES
, BANDID_PREVIEW_BTN4
);
610 AddTextButton(hReBar
, STRING_PREVIEW_ZOOMIN
, ID_PREVIEW_ZOOMIN
, BANDID_PREVIEW_BTN5
);
611 AddTextButton(hReBar
, STRING_PREVIEW_ZOOMOUT
, ID_PREVIEW_ZOOMOUT
, BANDID_PREVIEW_BTN6
);
612 AddTextButton(hReBar
, STRING_PREVIEW_CLOSE
, ID_FILE_EXIT
, BANDID_PREVIEW_BTN7
);
614 hStatic
= CreateWindowW(WC_STATICW
, NULL
,
615 WS_VISIBLE
| WS_CHILD
, 0, 0, 0, 0,
616 hReBar
, NULL
, NULL
, NULL
);
618 rb
.cbSize
= REBARBANDINFOW_V6_SIZE
;
619 rb
.fMask
= RBBIM_SIZE
| RBBIM_CHILDSIZE
| RBBIM_STYLE
| RBBIM_CHILD
| RBBIM_IDEALSIZE
| RBBIM_ID
;
620 rb
.fStyle
= RBBS_NOGRIPPER
| RBBS_VARIABLEHEIGHT
;
621 rb
.hwndChild
= hStatic
;
622 rb
.cyChild
= rb
.cyMinChild
= 22;
623 rb
.cx
= rb
.cxMinChild
= 90;
625 rb
.wID
= BANDID_PREVIEW_BUFFER
;
627 SendMessageW(hReBar
, RB_INSERTBAND
, -1, (LPARAM
)&rb
);
630 for(i
= 0; i
<= PREVIEW_BUTTONS
; i
++)
631 SendMessageW(hReBar
, RB_DELETEBAND
, SendMessageW(hReBar
, RB_IDTOINDEX
, BANDID_PREVIEW_BTN1
+i
, 0), 0);
635 static const int min_spacing
= 10;
637 static void update_preview_scrollbars(HWND hwndPreview
, RECT
*window
)
640 sbi
.cbSize
= sizeof(sbi
);
641 sbi
.fMask
= SIF_PAGE
|SIF_RANGE
;
643 if (preview
.zoomlevel
== 0)
645 /* Hide scrollbars when zoomed out. */
647 sbi
.nPage
= window
->right
;
648 SetScrollInfo(hwndPreview
, SB_HORZ
, &sbi
, TRUE
);
649 sbi
.nPage
= window
->bottom
;
650 SetScrollInfo(hwndPreview
, SB_VERT
, &sbi
, TRUE
);
652 sbi
.nMax
= preview
.bmScaledSize
.cx
* preview
.pages_shown
+
653 min_spacing
* (preview
.pages_shown
+ 1);
654 sbi
.nPage
= window
->right
;
655 SetScrollInfo(hwndPreview
, SB_HORZ
, &sbi
, TRUE
);
656 /* Change in the horizontal scrollbar visibility affects the
657 * client rect, so update the client rect. */
658 GetClientRect(hwndPreview
, window
);
659 sbi
.nMax
= preview
.bmScaledSize
.cy
+ min_spacing
* 2;
660 sbi
.nPage
= window
->bottom
;
661 SetScrollInfo(hwndPreview
, SB_VERT
, &sbi
, TRUE
);
665 static void update_preview_sizes(HWND hwndPreview
, BOOL zoomLevelUpdated
)
669 GetClientRect(hwndPreview
, &window
);
671 /* The zoom ratio isn't updated for partial zoom because of resizing the window. */
672 if (zoomLevelUpdated
|| preview
.zoomlevel
!= 1)
674 float ratio
, ratioHeight
, ratioWidth
;
675 if (preview
.zoomlevel
== 2)
679 ratioHeight
= (window
.bottom
- min_spacing
* 2) / (float)preview
.bmSize
.cy
;
681 ratioWidth
= (float)(window
.right
-
682 min_spacing
* (preview
.pages_shown
+ 1)) /
683 (preview
.pages_shown
* preview
.bmSize
.cx
);
685 if(ratioWidth
> ratioHeight
)
690 if (preview
.zoomlevel
== 1)
691 ratio
+= (1.0 - ratio
) / 2;
693 preview
.zoomratio
= ratio
;
696 preview
.bmScaledSize
.cx
= preview
.bmSize
.cx
* preview
.zoomratio
;
697 preview
.bmScaledSize
.cy
= preview
.bmSize
.cy
* preview
.zoomratio
;
699 preview
.spacing
.cy
= max(min_spacing
, (window
.bottom
- preview
.bmScaledSize
.cy
) / 2);
701 preview
.spacing
.cx
= (window
.right
-
702 preview
.bmScaledSize
.cx
* preview
.pages_shown
) /
703 (preview
.pages_shown
+ 1);
704 if (preview
.spacing
.cx
< min_spacing
)
705 preview
.spacing
.cx
= min_spacing
;
707 update_preview_scrollbars(hwndPreview
, &window
);
710 static void draw_preview_page(HDC hdc
, HDC
* hdcSized
, FORMATRANGE
* lpFr
, float ratio
, int bmNewWidth
, int bmNewHeight
, int bmWidth
, int bmHeight
, BOOL draw_margins
)
712 HBITMAP hBitmapScaled
= CreateCompatibleBitmap(hdc
, bmNewWidth
, bmNewHeight
);
715 int TopMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.top
, GetDeviceCaps(hdc
, LOGPIXELSX
)) * ratio
);
716 int BottomMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.bottom
, GetDeviceCaps(hdc
, LOGPIXELSX
)) * ratio
);
717 int LeftMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.left
, GetDeviceCaps(hdc
, LOGPIXELSY
)) * ratio
);
718 int RightMargin
= (int)((float)twips_to_pixels(lpFr
->rc
.right
, GetDeviceCaps(hdc
, LOGPIXELSY
)) * ratio
);
721 oldbm
= SelectObject(*hdcSized
, hBitmapScaled
);
724 *hdcSized
= CreateCompatibleDC(hdc
);
725 SelectObject(*hdcSized
, hBitmapScaled
);
728 StretchBlt(*hdcSized
, 0, 0, bmNewWidth
, bmNewHeight
, hdc
, 0, 0, bmWidth
, bmHeight
, SRCCOPY
);
730 if (!draw_margins
) return;
732 /* Draw margin lines */
733 hPen
= CreatePen(PS_DOT
, 1, RGB(0,0,0));
734 oldPen
= SelectObject(*hdcSized
, hPen
);
736 MoveToEx(*hdcSized
, 0, TopMargin
, NULL
);
737 LineTo(*hdcSized
, bmNewWidth
, TopMargin
);
738 MoveToEx(*hdcSized
, 0, BottomMargin
, NULL
);
739 LineTo(*hdcSized
, bmNewWidth
, BottomMargin
);
741 MoveToEx(*hdcSized
, LeftMargin
, 0, NULL
);
742 LineTo(*hdcSized
, LeftMargin
, bmNewHeight
);
743 MoveToEx(*hdcSized
, RightMargin
, 0, NULL
);
744 LineTo(*hdcSized
, RightMargin
, bmNewHeight
);
746 SelectObject(*hdcSized
, oldPen
);
750 static BOOL
is_last_preview_page(int page
)
752 return preview
.pageEnds
[page
- 1] >= preview
.textlength
;
755 /* Update for zoom ratio changes with same page. */
756 static void update_scaled_preview(HWND hMainWnd
)
761 /* This may occur on WM_CREATE before update_preview is called
762 * because a WM_SIZE message is generated from updating the
764 if (!preview
.hdc
) return;
766 hwndPreview
= GetDlgItem(hMainWnd
, IDC_PREVIEW
);
767 fr
.hdcTarget
= make_dc();
768 fr
.rc
= fr
.rcPage
= preview
.rcPage
;
769 fr
.rc
.left
+= margins
.left
;
770 fr
.rc
.top
+= margins
.top
;
771 fr
.rc
.bottom
-= margins
.bottom
;
772 fr
.rc
.right
-= margins
.right
;
774 draw_preview_page(preview
.hdc
, &preview
.hdcSized
, &fr
, preview
.zoomratio
,
775 preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
776 preview
.bmSize
.cx
, preview
.bmSize
.cy
, TRUE
);
778 if(preview
.pages_shown
> 1)
780 draw_preview_page(preview
.hdc2
, &preview
.hdcSized2
, &fr
, preview
.zoomratio
,
781 preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
782 preview
.bmSize
.cx
, preview
.bmSize
.cy
,
783 !is_last_preview_page(preview
.page
));
786 InvalidateRect(hwndPreview
, NULL
, TRUE
);
787 DeleteDC(fr
.hdcTarget
);
790 void init_preview(HWND hMainWnd
, LPWSTR wszFileName
)
793 HINSTANCE hInstance
= GetModuleHandleW(0);
797 preview
.wszFileName
= wszFileName
;
798 preview
.zoomratio
= 0;
799 preview
.zoomlevel
= 0;
800 preview_bar_show(hMainWnd
, TRUE
);
802 hwndPreview
= CreateWindowExW(0, wszPreviewWndClass
, NULL
,
803 WS_VISIBLE
| WS_CHILD
| WS_VSCROLL
| WS_HSCROLL
,
804 0, 0, 200, 10, hMainWnd
, (HMENU
)IDC_PREVIEW
, hInstance
, NULL
);
807 void close_preview(HWND hMainWnd
)
809 HWND hwndPreview
= GetDlgItem(hMainWnd
, IDC_PREVIEW
);
810 preview
.window
.right
= 0;
811 preview
.window
.bottom
= 0;
813 HeapFree(GetProcessHeap(), 0, preview
.pageEnds
);
814 preview
.pageEnds
= NULL
;
815 preview
.pageCapacity
= 0;
816 if (preview
.zoomlevel
> 0)
817 preview
.pages_shown
= preview
.saved_pages_shown
;
819 HBITMAP oldbm
= GetCurrentObject(preview
.hdc
, OBJ_BITMAP
);
820 DeleteDC(preview
.hdc
);
825 HBITMAP oldbm
= GetCurrentObject(preview
.hdc2
, OBJ_BITMAP
);
826 DeleteDC(preview
.hdc2
);
830 if(preview
.hdcSized
) {
831 HBITMAP oldbm
= GetCurrentObject(preview
.hdcSized
, OBJ_BITMAP
);
832 DeleteDC(preview
.hdcSized
);
834 preview
.hdcSized
= NULL
;
836 if(preview
.hdcSized2
) {
837 HBITMAP oldbm
= GetCurrentObject(preview
.hdcSized2
, OBJ_BITMAP
);
838 DeleteDC(preview
.hdcSized2
);
840 preview
.hdcSized2
= NULL
;
843 preview_bar_show(hMainWnd
, FALSE
);
844 DestroyWindow(hwndPreview
);
847 BOOL
preview_isactive(void)
849 return preview
.page
!= 0;
852 static void draw_preview(HWND hEditorWnd
, FORMATRANGE
* lpFr
, RECT
* paper
, int page
)
856 if (!preview
.pageEnds
)
858 preview
.pageCapacity
= 32;
859 preview
.pageEnds
= HeapAlloc(GetProcessHeap(), 0,
860 sizeof(int) * preview
.pageCapacity
);
861 if (!preview
.pageEnds
) return;
862 } else if (page
>= preview
.pageCapacity
) {
864 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, preview
.pageEnds
,
865 sizeof(int) * preview
.pageCapacity
* 2);
866 if (!new_buffer
) return;
867 preview
.pageCapacity
*= 2;
868 preview
.pageEnds
= new_buffer
;
871 FillRect(lpFr
->hdc
, paper
, GetStockObject(WHITE_BRUSH
));
872 if (page
> 1 && is_last_preview_page(page
- 1)) return;
873 lpFr
->chrg
.cpMin
= page
<= 1 ? 0 : preview
.pageEnds
[page
-2];
874 bottom
= lpFr
->rc
.bottom
;
875 preview
.pageEnds
[page
-1] = SendMessageW(hEditorWnd
, EM_FORMATRANGE
, TRUE
, (LPARAM
)lpFr
);
877 /* EM_FORMATRANGE sets fr.rc.bottom to indicate the area printed in,
878 * but we want to keep the original for drawing margins */
879 lpFr
->rc
.bottom
= bottom
;
880 SendMessageW(hEditorWnd
, EM_FORMATRANGE
, FALSE
, 0);
883 static void update_preview_buttons(HWND hMainWnd
)
885 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
886 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_PREVPAGE
), preview
.page
> 1);
887 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_NEXTPAGE
),
888 !is_last_preview_page(preview
.page
) &&
889 !is_last_preview_page(preview
.page
+ preview
.pages_shown
- 1));
890 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_NUMPAGES
),
891 preview
.pages_shown
> 1 ||
892 (!is_last_preview_page(1) && preview
.zoomlevel
== 0));
893 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_ZOOMIN
), preview
.zoomlevel
< 2);
894 EnableWindow(GetDlgItem(hReBar
, ID_PREVIEW_ZOOMOUT
), preview
.zoomlevel
> 0);
897 LRESULT
print_preview(HWND hwndPreview
)
900 RECT window
, background
;
904 hdc
= BeginPaint(hwndPreview
, &ps
);
905 GetClientRect(hwndPreview
, &window
);
907 FillRect(hdc
, &window
, GetStockObject(GRAY_BRUSH
));
909 scrollpos
.x
= GetScrollPos(hwndPreview
, SB_HORZ
);
910 scrollpos
.y
= GetScrollPos(hwndPreview
, SB_VERT
);
912 background
.left
= preview
.spacing
.cx
- 2 - scrollpos
.x
;
913 background
.right
= background
.left
+ preview
.bmScaledSize
.cx
+ 4;
914 background
.top
= preview
.spacing
.cy
- 2 - scrollpos
.y
;
915 background
.bottom
= background
.top
+ preview
.bmScaledSize
.cy
+ 4;
917 FillRect(hdc
, &background
, GetStockObject(BLACK_BRUSH
));
919 if(preview
.pages_shown
> 1)
921 background
.left
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
922 background
.right
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
924 FillRect(hdc
, &background
, GetStockObject(BLACK_BRUSH
));
927 BitBlt(hdc
, preview
.spacing
.cx
- scrollpos
.x
, preview
.spacing
.cy
- scrollpos
.y
,
928 preview
.bmScaledSize
.cx
, preview
.bmScaledSize
.cy
,
929 preview
.hdcSized
, 0, 0, SRCCOPY
);
931 if(preview
.pages_shown
> 1)
933 BitBlt(hdc
, preview
.spacing
.cx
* 2 + preview
.bmScaledSize
.cx
- scrollpos
.x
,
934 preview
.spacing
.cy
- scrollpos
.y
, preview
.bmScaledSize
.cx
,
935 preview
.bmScaledSize
.cy
, preview
.hdcSized2
, 0, 0, SRCCOPY
);
938 preview
.window
= window
;
940 EndPaint(hwndPreview
, &ps
);
945 static void update_preview_statusbar(HWND hMainWnd
)
947 HWND hStatusbar
= GetDlgItem(hMainWnd
, IDC_STATUSBAR
);
948 HINSTANCE hInst
= GetModuleHandleW(0);
950 WCHAR wstr
[MAX_STRING_LEN
];
953 if (preview
.pages_shown
< 2 || is_last_preview_page(preview
.page
))
955 static const WCHAR fmt
[] = {' ','%','d','\0'};
956 p
+= LoadStringW(hInst
, STRING_PREVIEW_PAGE
, wstr
, MAX_STRING_LEN
);
957 wsprintfW(p
, fmt
, preview
.page
);
959 static const WCHAR fmt
[] = {' ','%','d','-','%','d','\0'};
960 p
+= LoadStringW(hInst
, STRING_PREVIEW_PAGES
, wstr
, MAX_STRING_LEN
);
961 wsprintfW(p
, fmt
, preview
.page
, preview
.page
+ 1);
963 SetWindowTextW(hStatusbar
, wstr
);
966 /* Update for page changes. */
967 static void update_preview(HWND hMainWnd
)
970 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
971 HWND hwndPreview
= GetDlgItem(hMainWnd
, IDC_PREVIEW
);
972 HBITMAP hBitmapCapture
;
974 HDC hdc
= GetDC(hwndPreview
);
976 fr
.hdcTarget
= make_dc();
977 fr
.rc
= fr
.rcPage
= preview
.rcPage
;
978 fr
.rc
.left
+= margins
.left
;
979 fr
.rc
.top
+= margins
.top
;
980 fr
.rc
.bottom
-= margins
.bottom
;
981 fr
.rc
.right
-= margins
.right
;
984 fr
.chrg
.cpMax
= preview
.textlength
;
987 paper
.right
= preview
.bmSize
.cx
;
989 paper
.bottom
= preview
.bmSize
.cy
;
992 preview
.hdc
= CreateCompatibleDC(hdc
);
993 hBitmapCapture
= CreateCompatibleBitmap(hdc
, preview
.bmSize
.cx
, preview
.bmSize
.cy
);
994 SelectObject(preview
.hdc
, hBitmapCapture
);
997 fr
.hdc
= preview
.hdc
;
998 draw_preview(hEditorWnd
, &fr
, &paper
, preview
.page
);
1000 if(preview
.pages_shown
> 1)
1004 preview
.hdc2
= CreateCompatibleDC(hdc
);
1005 hBitmapCapture
= CreateCompatibleBitmap(hdc
,
1008 SelectObject(preview
.hdc2
, hBitmapCapture
);
1011 fr
.hdc
= preview
.hdc2
;
1012 draw_preview(hEditorWnd
, &fr
, &fr
.rcPage
, preview
.page
+ 1);
1014 DeleteDC(fr
.hdcTarget
);
1015 ReleaseDC(hwndPreview
, hdc
);
1017 update_scaled_preview(hMainWnd
);
1018 update_preview_buttons(hMainWnd
);
1019 update_preview_statusbar(hMainWnd
);
1022 static void toggle_num_pages(HWND hMainWnd
)
1024 HWND hReBar
= GetDlgItem(hMainWnd
, IDC_REBAR
);
1025 WCHAR name
[MAX_STRING_LEN
];
1026 HINSTANCE hInst
= GetModuleHandleW(0);
1029 preview
.pages_shown
= preview
.pages_shown
> 1 ? 1 : 2;
1031 nPreviewPages
= preview
.zoomlevel
> 0 ? preview
.saved_pages_shown
:
1032 preview
.pages_shown
;
1034 LoadStringW(hInst
, nPreviewPages
> 1 ? STRING_PREVIEW_ONEPAGE
:
1035 STRING_PREVIEW_TWOPAGES
,
1036 name
, MAX_STRING_LEN
);
1038 SetWindowTextW(GetDlgItem(hReBar
, ID_PREVIEW_NUMPAGES
), name
);
1039 update_preview_sizes(GetDlgItem(hMainWnd
, IDC_PREVIEW
), TRUE
);
1040 update_preview(hMainWnd
);
1043 /* Returns the page shown that the point is in (1 or 2) or 0 if the point
1044 * isn't inside either page */
1045 int preview_page_hittest(POINT pt
)
1048 rc
.left
= preview
.spacing
.cx
;
1049 rc
.right
= rc
.left
+ preview
.bmScaledSize
.cx
;
1050 rc
.top
= preview
.spacing
.cy
;
1051 rc
.bottom
= rc
.top
+ preview
.bmScaledSize
.cy
;
1052 if (PtInRect(&rc
, pt
))
1055 if (preview
.pages_shown
<= 1)
1058 rc
.left
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
1059 rc
.right
+= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
1060 if (PtInRect(&rc
, pt
))
1061 return is_last_preview_page(preview
.page
) ? 1 : 2;
1066 LRESULT CALLBACK
preview_proc(HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
1072 HWND hMainWnd
= GetParent(hWnd
);
1073 HWND hEditorWnd
= GetDlgItem(hMainWnd
, IDC_EDITOR
);
1075 GETTEXTLENGTHEX gt
= {GTL_DEFAULT
, 1200};
1076 HDC hdc
= GetDC(hWnd
);
1077 HDC hdcTarget
= make_dc();
1079 fr
.rc
= preview
.rcPage
= get_print_rect(hdcTarget
);
1080 preview
.rcPage
.bottom
+= margins
.bottom
;
1081 preview
.rcPage
.right
+= margins
.right
;
1082 preview
.rcPage
.top
= preview
.rcPage
.left
= 0;
1083 fr
.rcPage
= preview
.rcPage
;
1085 preview
.bmSize
.cx
= twips_to_pixels(preview
.rcPage
.right
, GetDeviceCaps(hdc
, LOGPIXELSX
));
1086 preview
.bmSize
.cy
= twips_to_pixels(preview
.rcPage
.bottom
, GetDeviceCaps(hdc
, LOGPIXELSY
));
1088 preview
.textlength
= SendMessageW(hEditorWnd
, EM_GETTEXTLENGTHEX
, (WPARAM
)>
, 0);
1090 fr
.hdc
= CreateCompatibleDC(hdc
);
1091 fr
.hdcTarget
= hdcTarget
;
1093 fr
.chrg
.cpMax
= preview
.textlength
;
1095 DeleteDC(hdcTarget
);
1096 ReleaseDC(hWnd
, hdc
);
1098 update_preview_sizes(hWnd
, TRUE
);
1099 update_preview(hMainWnd
);
1104 return print_preview(hWnd
);
1108 update_preview_sizes(hWnd
, FALSE
);
1109 update_scaled_preview(hWnd
);
1118 int nBar
= (msg
== WM_VSCROLL
) ? SB_VERT
: SB_HORZ
;
1121 GetClientRect(hWnd
, &rc
);
1122 si
.cbSize
= sizeof(si
);
1124 GetScrollInfo(hWnd
, nBar
, &si
);
1126 switch(LOWORD(wParam
))
1128 case SB_TOP
: /* == SB_LEFT */
1131 case SB_BOTTOM
: /* == SB_RIGHT */
1134 case SB_LINEUP
: /* == SB_LINELEFT */
1135 si
.nPos
-= si
.nPage
/ 10;
1137 case SB_LINEDOWN
: /* == SB_LINERIGHT */
1138 si
.nPos
+= si
.nPage
/ 10;
1140 case SB_PAGEUP
: /* == SB_PAGELEFT */
1141 si
.nPos
-= si
.nPage
;
1143 case SB_PAGEDOWN
: /* SB_PAGERIGHT */
1144 si
.nPos
+= si
.nPage
;
1147 si
.nPos
= si
.nTrackPos
;
1151 SetScrollInfo(hWnd
, nBar
, &si
, TRUE
);
1152 GetScrollInfo(hWnd
, nBar
, &si
);
1153 if (si
.nPos
!= origPos
)
1155 int amount
= origPos
- si
.nPos
;
1156 if (msg
== WM_VSCROLL
)
1157 ScrollWindow(hWnd
, 0, amount
, NULL
, NULL
);
1159 ScrollWindow(hWnd
, amount
, 0, NULL
, NULL
);
1168 int bHittest
= FALSE
;
1169 DWORD messagePos
= GetMessagePos();
1170 pt
.x
= (short)LOWORD(messagePos
);
1171 pt
.y
= (short)HIWORD(messagePos
);
1172 ScreenToClient(hWnd
, &pt
);
1174 GetClientRect(hWnd
, &rc
);
1175 if (PtInRect(&rc
, pt
))
1177 pt
.x
+= GetScrollPos(hWnd
, SB_HORZ
);
1178 pt
.y
+= GetScrollPos(hWnd
, SB_VERT
);
1179 bHittest
= preview_page_hittest(pt
);
1183 SetCursor(LoadCursorW(GetModuleHandleW(0),
1184 MAKEINTRESOURCEW(IDC_ZOOM
)));
1186 SetCursor(LoadCursorW(NULL
, (WCHAR
*)IDC_ARROW
));
1191 case WM_LBUTTONDOWN
:
1195 pt
.x
= (short)LOWORD(lParam
) + GetScrollPos(hWnd
, SB_HORZ
);
1196 pt
.y
= (short)HIWORD(lParam
) + GetScrollPos(hWnd
, SB_VERT
);
1197 if ((page
= preview_page_hittest(pt
)) > 0)
1199 HWND hMainWnd
= GetParent(hWnd
);
1201 /* Convert point from client coordinate to unzoomed page
1203 pt
.x
-= preview
.spacing
.cx
;
1205 pt
.x
-= preview
.bmScaledSize
.cx
+ preview
.spacing
.cx
;
1206 pt
.y
-= preview
.spacing
.cy
;
1207 pt
.x
/= preview
.zoomratio
;
1208 pt
.y
/= preview
.zoomratio
;
1210 if (preview
.zoomlevel
== 0)
1211 preview
.saved_pages_shown
= preview
.pages_shown
;
1212 preview
.zoomlevel
= (preview
.zoomlevel
+ 1) % 3;
1213 preview
.zoomratio
= 0;
1214 if (preview
.zoomlevel
== 0 && preview
.saved_pages_shown
> 1)
1216 toggle_num_pages(hMainWnd
);
1217 } else if (preview
.pages_shown
> 1) {
1218 if (page
>= 2) preview
.page
++;
1219 toggle_num_pages(hMainWnd
);
1221 update_preview_sizes(hWnd
, TRUE
);
1222 update_scaled_preview(hMainWnd
);
1223 update_preview_buttons(hMainWnd
);
1226 if (preview
.zoomlevel
> 0) {
1228 /* Convert the coordinate back to client coordinate. */
1229 pt
.x
*= preview
.zoomratio
;
1230 pt
.y
*= preview
.zoomratio
;
1231 pt
.x
+= preview
.spacing
.cx
;
1232 pt
.y
+= preview
.spacing
.cy
;
1233 /* Scroll to center view at that point on the page */
1234 si
.cbSize
= sizeof(si
);
1235 si
.fMask
= SIF_PAGE
;
1236 GetScrollInfo(hWnd
, SB_HORZ
, &si
);
1237 pt
.x
-= si
.nPage
/ 2;
1238 SetScrollPos(hWnd
, SB_HORZ
, pt
.x
, TRUE
);
1239 GetScrollInfo(hWnd
, SB_VERT
, &si
);
1240 pt
.y
-= si
.nPage
/ 2;
1241 SetScrollPos(hWnd
, SB_VERT
, pt
.y
, TRUE
);
1247 return DefWindowProcW(hWnd
, msg
, wParam
, lParam
);
1253 LRESULT
preview_command(HWND hWnd
, WPARAM wParam
)
1255 switch(LOWORD(wParam
))
1258 PostMessageW(hWnd
, WM_CLOSE
, 0, 0);
1261 case ID_PREVIEW_NEXTPAGE
:
1262 case ID_PREVIEW_PREVPAGE
:
1264 if(LOWORD(wParam
) == ID_PREVIEW_NEXTPAGE
)
1269 update_preview(hWnd
);
1273 case ID_PREVIEW_NUMPAGES
:
1274 toggle_num_pages(hWnd
);
1277 case ID_PREVIEW_ZOOMIN
:
1278 if (preview
.zoomlevel
< 2)
1280 if (preview
.zoomlevel
== 0)
1281 preview
.saved_pages_shown
= preview
.pages_shown
;
1282 preview
.zoomlevel
++;
1283 preview
.zoomratio
= 0;
1284 if (preview
.pages_shown
> 1)
1286 /* Forced switch to one page when zooming in. */
1287 toggle_num_pages(hWnd
);
1289 HWND hwndPreview
= GetDlgItem(hWnd
, IDC_PREVIEW
);
1290 update_preview_sizes(hwndPreview
, TRUE
);
1291 update_scaled_preview(hWnd
);
1292 update_preview_buttons(hWnd
);
1297 case ID_PREVIEW_ZOOMOUT
:
1298 if (preview
.zoomlevel
> 0)
1300 HWND hwndPreview
= GetDlgItem(hWnd
, IDC_PREVIEW
);
1301 preview
.zoomlevel
--;
1302 preview
.zoomratio
= 0;
1303 if (preview
.zoomlevel
== 0 && preview
.saved_pages_shown
> 1) {
1304 toggle_num_pages(hWnd
);
1306 update_preview_sizes(hwndPreview
, TRUE
);
1307 update_scaled_preview(hWnd
);
1308 update_preview_buttons(hWnd
);
1314 dialog_print(hWnd
, preview
.wszFileName
);
1315 SendMessageW(hWnd
, WM_CLOSE
, 0, 0);