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