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