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