EnumThemeColors() and EnumThemeSizes() actually do not return a single
[wine] / dlls / hhctrl.ocx / help.c
1 /*
2  * Help Viewer Implementation
3  *
4  * Copyright 2005 James Hawkins
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winuser.h"
27 #include "winnls.h"
28 #include "commctrl.h"
29 #include "htmlhelp.h"
30 #include "ole2.h"
31 #include "wine/unicode.h"
32
33 #include "resource.h"
34
35 /* Window type defaults */
36
37 #define WINTYPE_DEFAULT_X           280
38 #define WINTYPE_DEFAULT_Y           100
39 #define WINTYPE_DEFAULT_WIDTH       740
40 #define WINTYPE_DEFAULT_HEIGHT      640
41 #define WINTYPE_DEFAULT_NAVWIDTH    251
42
43 typedef struct tagHHInfo
44 {
45     HH_WINTYPEW *pHHWinType;
46     HINSTANCE hInstance;
47     LPWSTR szCmdLine;
48     HWND hwndTabCtrl;
49     HFONT hFont;
50 } HHInfo;
51
52 extern HINSTANCE hhctrl_hinstance;
53
54 static LPWSTR HH_ANSIToUnicode(LPCSTR ansi)
55 {
56     LPWSTR unicode;
57     int count;
58
59     count = MultiByteToWideChar(CP_ACP, 0, ansi, -1, NULL, 0);
60     unicode = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
61     MultiByteToWideChar(CP_ACP, 0, ansi, -1, unicode, count);
62
63     return unicode;
64 }
65
66 /* Loads a string from the resource file */
67 static LPWSTR HH_LoadString(DWORD dwID)
68 {
69     LPWSTR string = NULL;
70     int iSize;
71
72     iSize = LoadStringW(hhctrl_hinstance, dwID, NULL, 0);
73     iSize += 2; /* some strings (tab text) needs double-null termination */
74
75     string = HeapAlloc(GetProcessHeap(), 0, iSize * sizeof(WCHAR));
76     LoadStringW(hhctrl_hinstance, dwID, string, iSize);
77
78     return string;
79 }
80
81 /* Child Window */
82
83 static const WCHAR szChildClass[] = {
84     'H','H',' ','C','h','i','l','d',0
85 };
86
87 static const WCHAR szEmpty[] = {0};
88
89 static void Child_OnPaint(HWND hWnd)
90 {
91     PAINTSTRUCT ps;
92     HDC hdc;
93     RECT rc;
94
95     hdc = BeginPaint(hWnd, &ps);
96
97     /* Only paint the Navigation pane, identified by the fact
98      * that it has a child window
99      */
100     if (GetWindow(hWnd, GW_CHILD))
101     {
102         GetClientRect(hWnd, &rc);
103
104         /* set the border color */
105         SelectObject(hdc, GetStockObject(DC_PEN));
106         SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
107
108         /* Draw the top and right borders */
109         MoveToEx(hdc, 0, 0, NULL);
110         LineTo(hdc, rc.right - 1, 0);
111         LineTo(hdc, rc.right - 1, rc.bottom);
112
113         /* Fill in the background, taking the border lines into account */
114         rc.top += 2;
115         rc.right -= 1;
116         FillRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
117     }
118
119     EndPaint(hWnd, &ps);
120 }
121
122 LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
123 {
124     switch (message)
125     {
126         case WM_PAINT:
127             Child_OnPaint(hWnd);
128             break;
129         default:
130             return DefWindowProcW(hWnd, message, wParam, lParam);
131     }
132
133     return 0;
134 }
135
136 static void HH_RegisterChildWndClass(HHInfo *pHHInfo)
137 {
138     WNDCLASSEXW wcex;
139
140     wcex.cbSize         = sizeof(WNDCLASSEXW);
141     wcex.style          = 0;
142     wcex.lpfnWndProc    = (WNDPROC)Child_WndProc;
143     wcex.cbClsExtra     = 0;
144     wcex.cbWndExtra     = 0;
145     wcex.hInstance      = pHHInfo->hInstance;
146     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
147     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
148     wcex.hbrBackground  = (HBRUSH)(COLOR_3DFACE);
149     wcex.lpszMenuName   = NULL;
150     wcex.lpszClassName  = szChildClass;
151     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
152
153     RegisterClassExW(&wcex);
154 }
155
156 /* Toolbar */
157
158 #define ICON_SIZE   20
159
160 static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID)
161 {
162     /* FIXME: Load the correct button bitmaps */
163     pButtons[dwIndex].iBitmap = STD_PRINT;
164     pButtons[dwIndex].idCommand = dwID;
165     pButtons[dwIndex].fsState = TBSTATE_ENABLED;
166     pButtons[dwIndex].fsStyle = BTNS_BUTTON;
167     pButtons[dwIndex].dwData = 0;
168     pButtons[dwIndex].iString = 0;
169 }
170
171 static void TB_AddButtonsFromFlags(TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons)
172 {
173     *pdwNumButtons = 0;
174
175     if (dwButtonFlags & HHWIN_BUTTON_EXPAND)
176         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND);
177
178     if (dwButtonFlags & HHWIN_BUTTON_BACK)
179         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK);
180
181     if (dwButtonFlags & HHWIN_BUTTON_FORWARD)
182         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD);
183
184     if (dwButtonFlags & HHWIN_BUTTON_STOP)
185         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP);
186
187     if (dwButtonFlags & HHWIN_BUTTON_REFRESH)
188         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH);
189
190     if (dwButtonFlags & HHWIN_BUTTON_HOME)
191         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME);
192
193     if (dwButtonFlags & HHWIN_BUTTON_SYNC)
194         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC);
195
196     if (dwButtonFlags & HHWIN_BUTTON_OPTIONS)
197         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS);
198
199     if (dwButtonFlags & HHWIN_BUTTON_PRINT)
200         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT);
201
202     if (dwButtonFlags & HHWIN_BUTTON_JUMP1)
203         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_JUMP1);
204
205     if (dwButtonFlags & HHWIN_BUTTON_JUMP2)
206         TB_AddButton(pButtons,(*pdwNumButtons)++, IDTB_JUMP2);
207
208     if (dwButtonFlags & HHWIN_BUTTON_ZOOM)
209         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_ZOOM);
210
211     if (dwButtonFlags & HHWIN_BUTTON_TOC_NEXT)
212         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_NEXT);
213
214     if (dwButtonFlags & HHWIN_BUTTON_TOC_PREV)
215         TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_TOC_PREV);
216 }
217
218 static BOOL HH_AddToolbar(HHInfo *pHHInfo)
219 {
220     HWND hToolbar;
221     HWND hwndParent = pHHInfo->pHHWinType->hwndHelp;
222     DWORD toolbarFlags = pHHInfo->pHHWinType->fsToolBarFlags;
223     TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND];
224     TBADDBITMAP tbAB;
225     DWORD dwStyles, dwExStyles;
226     DWORD dwNumButtons, dwIndex;
227
228     /* FIXME: Remove the following line once we read the CHM file */
229     toolbarFlags = HHWIN_BUTTON_EXPAND | HHWIN_BUTTON_BACK | HHWIN_BUTTON_STOP |
230                    HHWIN_BUTTON_REFRESH | HHWIN_BUTTON_HOME | HHWIN_BUTTON_PRINT;
231     TB_AddButtonsFromFlags(buttons, toolbarFlags, &dwNumButtons);
232
233     dwStyles = WS_CHILDWINDOW | WS_VISIBLE | TBSTYLE_FLAT |
234                TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER;
235     dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
236
237     hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles,
238                                0, 0, 0, 0, hwndParent, NULL,
239                                pHHInfo->hInstance, NULL);
240     if (!hToolbar)
241         return FALSE;
242
243     SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE));
244     SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
245     SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
246
247     /* FIXME: Load correct icons for all buttons */
248     tbAB.hInst = HINST_COMMCTRL;
249     tbAB.nID = IDB_STD_LARGE_COLOR;
250     SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB);
251
252     for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++)
253     {
254         LPWSTR szBuf = HH_LoadString(buttons[dwIndex].idCommand);
255         DWORD dwLen = strlenW(szBuf);
256         szBuf[dwLen + 2] = 0; /* Double-null terminate */
257
258         buttons[dwIndex].iString = (DWORD)SendMessageW(hToolbar, TB_ADDSTRINGW, 0, (LPARAM)szBuf);
259         HeapFree(GetProcessHeap(), 0, szBuf);
260     }
261
262     SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)&buttons);
263     SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0);
264     ShowWindow(hToolbar, SW_SHOW);
265
266     pHHInfo->pHHWinType->hwndToolBar = hToolbar;
267     return TRUE;
268 }
269
270 /* Navigation Pane */
271
272 #define TAB_PADDING         2
273 #define TAB_TOP_PADDING     8
274 #define TAB_RIGHT_PADDING   4
275
276 static void NP_GetNavigationRect(HHInfo *pHHInfo, RECT *rc)
277 {
278     HWND hwndParent = pHHInfo->pHHWinType->hwndHelp;
279     HWND hwndToolbar = pHHInfo->pHHWinType->hwndToolBar;
280     RECT rectWND, rectTB;
281
282     GetClientRect(hwndParent, &rectWND);
283     GetClientRect(hwndToolbar, &rectTB);
284
285     rc->left = 0;
286     rc->top = rectTB.bottom;
287     rc->bottom = rectWND.bottom - rectTB.bottom;
288
289     if (pHHInfo->pHHWinType->fsValidMembers & HHWIN_PARAM_NAV_WIDTH)
290         rc->right = pHHInfo->pHHWinType->iNavWidth;
291     else
292         rc->right = WINTYPE_DEFAULT_NAVWIDTH;
293 }
294
295 static void NP_CreateTab(HINSTANCE hInstance, HWND hwndTabCtrl, DWORD dwStrID, DWORD dwIndex)
296 {
297     TCITEMW tie;
298     LPWSTR tabText = HH_LoadString(dwStrID);
299
300     tie.mask = TCIF_TEXT;
301     tie.pszText = tabText;
302
303     TabCtrl_InsertItemW(hwndTabCtrl, dwIndex, &tie);
304     HeapFree(GetProcessHeap(), 0, tabText);
305 }
306
307 static BOOL HH_AddNavigationPane(HHInfo *pHHInfo)
308 {
309     HWND hWnd, hwndTabCtrl;
310     HWND hwndParent = pHHInfo->pHHWinType->hwndHelp;
311     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE;
312     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
313     DWORD dwIndex = 0;
314     RECT rc;
315
316     NP_GetNavigationRect(pHHInfo, &rc);
317
318     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
319                            rc.left, rc.top, rc.right, rc.bottom,
320                            hwndParent, NULL, pHHInfo->hInstance, NULL);
321     if (!hWnd)
322         return FALSE;
323
324     hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles,
325                                   TAB_PADDING, TAB_TOP_PADDING,
326                                   rc.right - TAB_PADDING - TAB_RIGHT_PADDING,
327                                   rc.bottom - TAB_PADDING - TAB_TOP_PADDING,
328                                   hWnd, NULL, pHHInfo->hInstance, NULL);
329     if (!hwndTabCtrl)
330         return FALSE;
331
332     /* FIXME: Check which tabs to include when we read the CHM file */
333     NP_CreateTab(pHHInfo->hInstance, hwndTabCtrl, IDS_CONTENTS, dwIndex++);
334     NP_CreateTab(pHHInfo->hInstance, hwndTabCtrl, IDS_INDEX, dwIndex++);
335     NP_CreateTab(pHHInfo->hInstance, hwndTabCtrl, IDS_SEARCH, dwIndex++);
336     NP_CreateTab(pHHInfo->hInstance, hwndTabCtrl, IDS_FAVORITES, dwIndex++);
337
338     SendMessageW(hwndTabCtrl, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE);
339
340     pHHInfo->hwndTabCtrl = hwndTabCtrl;
341     pHHInfo->pHHWinType->hwndNavigation = hWnd;
342     return TRUE;
343 }
344
345 /* HTML Pane */
346
347 static void HP_GetHTMLRect(HHInfo *pHHInfo, RECT *rc)
348 {
349     HWND hwndParent = pHHInfo->pHHWinType->hwndHelp;
350     HWND hwndToolbar = pHHInfo->pHHWinType->hwndToolBar;
351     HWND hwndNavigation = pHHInfo->pHHWinType->hwndNavigation;
352     RECT rectTB, rectWND, rectNP;
353
354     GetClientRect(hwndParent, &rectWND);
355     GetClientRect(hwndToolbar, &rectTB);
356     GetClientRect(hwndNavigation, &rectNP);
357
358     rc->left = rectNP.right;
359     rc->top = rectTB.bottom;
360     rc->right = rectWND.right - rectNP.right;
361     rc->bottom = rectWND.bottom - rectTB.bottom;
362 }
363
364 static BOOL HH_AddHTMLPane(HHInfo *pHHInfo)
365 {
366     HWND hWnd;
367     HWND hwndParent = pHHInfo->pHHWinType->hwndHelp;
368     DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN;
369     DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_CLIENTEDGE;
370     RECT rc;
371
372     HP_GetHTMLRect(pHHInfo, &rc);
373
374     hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles,
375                            rc.left, rc.top, rc.right, rc.bottom,
376                            hwndParent, NULL, pHHInfo->hInstance, NULL);
377     if (!hWnd)
378         return FALSE;
379
380     /* store the pointer to the HH info struct */
381     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
382
383     ShowWindow(hWnd, SW_SHOW);
384     UpdateWindow(hWnd);
385
386     pHHInfo->pHHWinType->hwndHTML = hWnd;
387     return TRUE;
388 }
389
390 /* Viewer Window */
391
392 static void Help_OnSize(HWND hWnd, LPARAM lParam)
393 {
394     HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
395     RECT rc;
396
397     if (!pHHInfo)
398         return;
399
400     /* Only resize the Navigation pane vertically */
401     if (HIWORD(lParam))
402     {
403         NP_GetNavigationRect(pHHInfo, &rc);
404         SetWindowPos(pHHInfo->pHHWinType->hwndNavigation, HWND_TOP, 0, 0,
405                      rc.right, rc.bottom, SWP_NOMOVE);
406
407         GetClientRect(pHHInfo->pHHWinType->hwndNavigation, &rc);
408         SetWindowPos(pHHInfo->hwndTabCtrl, HWND_TOP, 0, 0,
409                      rc.right - TAB_PADDING - TAB_RIGHT_PADDING,
410                      rc.bottom - TAB_PADDING - TAB_TOP_PADDING, SWP_NOMOVE);
411     }
412
413     HP_GetHTMLRect(pHHInfo, &rc);
414     SetWindowPos(pHHInfo->pHHWinType->hwndHTML, HWND_TOP, 0, 0,
415                  LOWORD(lParam), HIWORD(lParam), SWP_NOMOVE);
416 }
417
418 LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
419 {
420     PAINTSTRUCT ps;
421     HDC hdc;
422
423     switch (message)
424     {
425         case WM_SIZE:
426             Help_OnSize(hWnd, lParam);
427             break;
428         case WM_PAINT:
429             hdc = BeginPaint(hWnd, &ps);
430             EndPaint(hWnd, &ps);
431             break;
432         case WM_DESTROY:
433             PostQuitMessage(0);
434             break;
435
436         default:
437             return DefWindowProcW(hWnd, message, wParam, lParam);
438     }
439
440     return 0;
441 }
442
443 static BOOL HH_CreateHelpWindow(HHInfo *pHHInfo)
444 {
445     HWND hWnd;
446     HINSTANCE hInstance = pHHInfo->hInstance;
447     WNDCLASSEXW wcex;
448     DWORD dwStyles, dwExStyles;
449     DWORD x, y, width, height;
450
451     static const WCHAR windowClassW[] = {
452         'H','H',' ', 'P','a','r','e','n','t',0
453     };
454
455     static const WCHAR windowTitleW[] = {
456         'H','T','M','L',' ','H','e','l','p',0
457     };
458
459     wcex.cbSize         = sizeof(WNDCLASSEXW);
460     wcex.style          = CS_HREDRAW | CS_VREDRAW;
461     wcex.lpfnWndProc    = (WNDPROC)Help_WndProc;
462     wcex.cbClsExtra     = 0;
463     wcex.cbWndExtra     = 0;
464     wcex.hInstance      = hInstance;
465     wcex.hIcon          = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
466     wcex.hCursor        = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
467     wcex.hbrBackground  = (HBRUSH)(COLOR_MENU + 1);
468     wcex.lpszMenuName   = NULL;
469     wcex.lpszClassName  = windowClassW;
470     wcex.hIconSm        = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
471
472     RegisterClassExW(&wcex);
473
474     dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
475     dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR |
476                  WS_EX_WINDOWEDGE | WS_EX_APPWINDOW;
477
478     /* these will be loaded from the CHM file in the future if they're provided */
479     x = WINTYPE_DEFAULT_X;
480     y = WINTYPE_DEFAULT_Y;
481     width = WINTYPE_DEFAULT_WIDTH;
482     height = WINTYPE_DEFAULT_HEIGHT;
483
484     hWnd = CreateWindowExW(dwExStyles, windowClassW, windowTitleW, dwStyles,
485                            x, y, width, height, NULL, NULL, hInstance, NULL);
486     if (!hWnd)
487         return FALSE;
488
489     ShowWindow(hWnd, SW_SHOW);
490     UpdateWindow(hWnd);
491
492     /* store the pointer to the HH info struct */
493     SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pHHInfo);
494
495     pHHInfo->pHHWinType->hwndHelp = hWnd;
496     return TRUE;
497 }
498
499 static void HH_CreateFont(HHInfo *pHHInfo)
500 {
501     LOGFONTW lf;
502
503     GetObjectW(GetStockObject(ANSI_VAR_FONT), sizeof(LOGFONTW), &lf);
504     lf.lfWeight = FW_NORMAL;
505     lf.lfItalic = FALSE;
506     lf.lfUnderline = FALSE;
507
508     pHHInfo->hFont = CreateFontIndirectW(&lf);
509 }
510
511 static void HH_InitRequiredControls(DWORD dwControls)
512 {
513     INITCOMMONCONTROLSEX icex;
514
515     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
516     icex.dwICC = dwControls;
517     InitCommonControlsEx(&icex);
518 }
519
520 /* Creates the whole package */
521 static BOOL HH_CreateViewer(HHInfo *pHHInfo)
522 {
523     HH_CreateFont(pHHInfo);
524
525     if (!HH_CreateHelpWindow(pHHInfo))
526         return FALSE;
527
528     HH_InitRequiredControls(ICC_BAR_CLASSES);
529
530     if (!HH_AddToolbar(pHHInfo))
531         return FALSE;
532
533     HH_RegisterChildWndClass(pHHInfo);
534
535     if (!HH_AddNavigationPane(pHHInfo))
536         return FALSE;
537
538     if (!HH_AddHTMLPane(pHHInfo))
539         return FALSE;
540
541     return TRUE;
542 }
543
544 static HHInfo *HH_OpenHH(HINSTANCE hInstance, LPWSTR szCmdLine)
545 {
546     HHInfo *pHHInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HHInfo));
547
548     pHHInfo->pHHWinType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HH_WINTYPEW));
549     pHHInfo->hInstance = hInstance;
550     pHHInfo->szCmdLine = szCmdLine;
551
552     return pHHInfo;
553 }
554
555 static void HH_Close(HHInfo *pHHInfo)
556 {
557     if (!pHHInfo)
558         return;
559
560     HeapFree(GetProcessHeap(), 0, pHHInfo->pHHWinType);
561     HeapFree(GetProcessHeap(), 0, pHHInfo->szCmdLine);
562 }
563
564 /* FIXME: Check szCmdLine for bad arguments */
565 int WINAPI doWinMain(HINSTANCE hInstance, LPSTR szCmdLine)
566 {
567     MSG msg;
568     HHInfo *pHHInfo;
569
570     if (OleInitialize(NULL) != S_OK)
571         return -1;
572
573     pHHInfo = HH_OpenHH(hInstance, HH_ANSIToUnicode(szCmdLine));
574     if (!pHHInfo || !HH_CreateViewer(pHHInfo))
575     {
576         OleUninitialize();
577         return -1;
578     }
579
580     while (GetMessageW(&msg, 0, 0, 0))
581     {
582         TranslateMessage(&msg);
583         DispatchMessageW(&msg);
584     }
585
586     HH_Close(pHHInfo);
587     HeapFree(GetProcessHeap(), 0, pHHInfo);
588     OleUninitialize();
589
590     return 0;
591 }