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