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