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