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