1 /* 2 * Help Viewer Implementation 3 * 4 * Copyright 2005 James Hawkins 5 * Copyright 2007 Jacek Caban for CodeWeavers 6 * Copyright 2011 Owen Rudge for CodeWeavers 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include "hhctrl.h" 24 25 #include "wingdi.h" 26 #include "commctrl.h" 27 #include "wininet.h" 28 29 #include "wine/debug.h" 30 31 #include "resource.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(htmlhelp); 34 35 static LRESULT Help_OnSize(HWND hWnd); 36 static void ExpandContract(HHInfo *pHHInfo); 37 38 /* Window type defaults */ 39 40 #define WINTYPE_DEFAULT_X 280 41 #define WINTYPE_DEFAULT_Y 100 42 #define WINTYPE_DEFAULT_WIDTH 740 43 #define WINTYPE_DEFAULT_HEIGHT 640 44 #define WINTYPE_DEFAULT_NAVWIDTH 250 45 46 #define TAB_TOP_PADDING 8 47 #define TAB_RIGHT_PADDING 4 48 #define TAB_MARGIN 8 49 #define EDIT_HEIGHT 20 50 51 struct list window_list = LIST_INIT(window_list); 52 53 static const WCHAR szEmpty[] = {0}; 54 55 struct html_encoded_symbol { 56 const char *html_code; 57 char ansi_symbol; 58 }; 59 60 /* 61 * Table mapping the conversion between HTML encoded symbols and their ANSI code page equivalent. 62 * Note: Add additional entries in proper alphabetical order (a binary search is used on this table). 63 */ 64 static struct html_encoded_symbol html_encoded_symbols[] = 65 { 66 {"AElig", 0xC6}, 67 {"Aacute", 0xC1}, 68 {"Acirc", 0xC2}, 69 {"Agrave", 0xC0}, 70 {"Aring", 0xC5}, 71 {"Atilde", 0xC3}, 72 {"Auml", 0xC4}, 73 {"Ccedil", 0xC7}, 74 {"ETH", 0xD0}, 75 {"Eacute", 0xC9}, 76 {"Ecirc", 0xCA}, 77 {"Egrave", 0xC8}, 78 {"Euml", 0xCB}, 79 {"Iacute", 0xCD}, 80 {"Icirc", 0xCE}, 81 {"Igrave", 0xCC}, 82 {"Iuml", 0xCF}, 83 {"Ntilde", 0xD1}, 84 {"Oacute", 0xD3}, 85 {"Ocirc", 0xD4}, 86 {"Ograve", 0xD2}, 87 {"Oslash", 0xD8}, 88 {"Otilde", 0xD5}, 89 {"Ouml", 0xD6}, 90 {"THORN", 0xDE}, 91 {"Uacute", 0xDA}, 92 {"Ucirc", 0xDB}, 93 {"Ugrave", 0xD9}, 94 {"Uuml", 0xDC}, 95 {"Yacute", 0xDD}, 96 {"aacute", 0xE1}, 97 {"acirc", 0xE2}, 98 {"acute", 0xB4}, 99 {"aelig", 0xE6}, 100 {"agrave", 0xE0}, 101 {"amp", '&'}, 102 {"aring", 0xE5}, 103 {"atilde", 0xE3}, 104 {"auml", 0xE4}, 105 {"brvbar", 0xA6}, 106 {"ccedil", 0xE7}, 107 {"cedil", 0xB8}, 108 {"cent", 0xA2}, 109 {"copy", 0xA9}, 110 {"curren", 0xA4}, 111 {"deg", 0xB0}, 112 {"divide", 0xF7}, 113 {"eacute", 0xE9}, 114 {"ecirc", 0xEA}, 115 {"egrave", 0xE8}, 116 {"eth", 0xF0}, 117 {"euml", 0xEB}, 118 {"frac12", 0xBD}, 119 {"frac14", 0xBC}, 120 {"frac34", 0xBE}, 121 {"gt", '>'}, 122 {"iacute", 0xED}, 123 {"icirc", 0xEE}, 124 {"iexcl", 0xA1}, 125 {"igrave", 0xEC}, 126 {"iquest", 0xBF}, 127 {"iuml", 0xEF}, 128 {"laquo", 0xAB}, 129 {"lt", '<'}, 130 {"macr", 0xAF}, 131 {"micro", 0xB5}, 132 {"middot", 0xB7}, 133 {"nbsp", ' '}, 134 {"not", 0xAC}, 135 {"ntilde", 0xF1}, 136 {"oacute", 0xF3}, 137 {"ocirc", 0xF4}, 138 {"ograve", 0xF2}, 139 {"ordf", 0xAA}, 140 {"ordm", 0xBA}, 141 {"oslash", 0xF8}, 142 {"otilde", 0xF5}, 143 {"ouml", 0xF6}, 144 {"para", 0xB6}, 145 {"plusmn", 0xB1}, 146 {"pound", 0xA3}, 147 {"quot", '"'}, 148 {"raquo", 0xBB}, 149 {"reg", 0xAE}, 150 {"sect", 0xA7}, 151 {"shy", 0xAD}, 152 {"sup1", 0xB9}, 153 {"sup2", 0xB2}, 154 {"sup3", 0xB3}, 155 {"szlig", 0xDF}, 156 {"thorn", 0xFE}, 157 {"times", 0xD7}, 158 {"uacute", 0xFA}, 159 {"ucirc", 0xFB}, 160 {"ugrave", 0xF9}, 161 {"uml", 0xA8}, 162 {"uuml", 0xFC}, 163 {"yacute", 0xFD}, 164 {"yen", 0xA5}, 165 {"yuml", 0xFF} 166 }; 167 168 static inline BOOL navigation_visible(HHInfo *info) 169 { 170 return ((info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) && !info->WinType.fNotExpanded); 171 } 172 173 /* Loads a string from the resource file */ 174 #ifdef __REACTOS__ 175 LPWSTR HH_LoadString(DWORD dwID) 176 #else 177 static LPWSTR HH_LoadString(DWORD dwID) 178 #endif 179 { 180 LPWSTR string = NULL; 181 LPCWSTR stringresource; 182 int iSize; 183 184 iSize = LoadStringW(hhctrl_hinstance, dwID, (LPWSTR)&stringresource, 0); 185 186 string = heap_alloc((iSize + 2) * sizeof(WCHAR)); /* some strings (tab text) needs double-null termination */ 187 memcpy(string, stringresource, iSize*sizeof(WCHAR)); 188 string[iSize] = 0; 189 190 return string; 191 } 192 193 static HRESULT navigate_url(HHInfo *info, LPCWSTR surl) 194 { 195 VARIANT url; 196 HRESULT hres; 197 198 TRACE("%s\n", debugstr_w(surl)); 199 200 V_VT(&url) = VT_BSTR; 201 V_BSTR(&url) = SysAllocString(surl); 202 203 hres = IWebBrowser2_Navigate2(info->web_browser->web_browser, &url, 0, 0, 0, 0); 204 205 VariantClear(&url); 206 207 if(FAILED(hres)) 208 TRACE("Navigation failed: %08x\n", hres); 209 210 return hres; 211 } 212 213 BOOL NavigateToUrl(HHInfo *info, LPCWSTR surl) 214 { 215 ChmPath chm_path; 216 BOOL ret; 217 HRESULT hres; 218 219 static const WCHAR url_indicator[] = {':', '/', '/', 0}; 220 221 TRACE("%s\n", debugstr_w(surl)); 222 223 if (wcsstr(surl, url_indicator)) { 224 hres = navigate_url(info, surl); 225 if(SUCCEEDED(hres)) 226 return TRUE; 227 } /* look up in chm if it doesn't look like a full url */ 228 229 SetChmPath(&chm_path, info->pCHMInfo->szFile, surl); 230 ret = NavigateToChm(info, chm_path.chm_file, chm_path.chm_index); 231 232 heap_free(chm_path.chm_file); 233 heap_free(chm_path.chm_index); 234 235 return ret; 236 } 237 238 static BOOL AppendFullPathURL(LPCWSTR file, LPWSTR buf, LPCWSTR index) 239 { 240 static const WCHAR url_format[] = 241 {'m','k',':','@','M','S','I','T','S','t','o','r','e',':','%','s',':',':','%','s','%','s',0}; 242 static const WCHAR slash[] = {'/',0}; 243 static const WCHAR empty[] = {0}; 244 WCHAR full_path[MAX_PATH]; 245 246 TRACE("%s %p %s\n", debugstr_w(file), buf, debugstr_w(index)); 247 248 if (!GetFullPathNameW(file, ARRAY_SIZE(full_path), full_path, NULL)) { 249 WARN("GetFullPathName failed: %u\n", GetLastError()); 250 return FALSE; 251 } 252 253 wsprintfW(buf, url_format, full_path, (!index || index[0] == '/') ? empty : slash, index); 254 return TRUE; 255 } 256 257 BOOL NavigateToChm(HHInfo *info, LPCWSTR file, LPCWSTR index) 258 { 259 WCHAR buf[INTERNET_MAX_URL_LENGTH]; 260 261 TRACE("%p %s %s\n", info, debugstr_w(file), debugstr_w(index)); 262 263 if ((!info->web_browser) || !AppendFullPathURL(file, buf, index)) 264 return FALSE; 265 266 return SUCCEEDED(navigate_url(info, buf)); 267 } 268 269 static void DoSync(HHInfo *info) 270 { 271 WCHAR buf[INTERNET_MAX_URL_LENGTH]; 272 HRESULT hres; 273 BSTR url; 274 275 hres = IWebBrowser2_get_LocationURL(info->web_browser->web_browser, &url); 276 277 if (FAILED(hres)) 278 { 279 WARN("get_LocationURL failed: %08x\n", hres); 280 return; 281 } 282 283 /* If we're not currently viewing a page in the active .chm file, abort */ 284 if ((!AppendFullPathURL(info->WinType.pszFile, buf, NULL)) || (lstrlenW(buf) > lstrlenW(url))) 285 { 286 SysFreeString(url); 287 return; 288 } 289 290 if (lstrcmpiW(buf, url) > 0) 291 { 292 static const WCHAR delimW[] = {':',':','/',0}; 293 const WCHAR *index; 294 295 index = wcsstr(url, delimW); 296 297 if (index) 298 ActivateContentTopic(info->tabs[TAB_CONTENTS].hwnd, index + 3, info->content); /* skip over ::/ */ 299 } 300 301 SysFreeString(url); 302 } 303 304 /* Size Bar */ 305 306 #define SIZEBAR_WIDTH 4 307 308 static const WCHAR szSizeBarClass[] = { 309 'H','H',' ','S','i','z','e','B','a','r',0 310 }; 311 312 /* Draw the SizeBar */ 313 static void SB_OnPaint(HWND hWnd) 314 { 315 PAINTSTRUCT ps; 316 HDC hdc; 317 RECT rc; 318 319 hdc = BeginPaint(hWnd, &ps); 320 321 GetClientRect(hWnd, &rc); 322 323 /* dark frame */ 324 rc.right += 1; 325 rc.bottom -= 1; 326 FrameRect(hdc, &rc, GetStockObject(GRAY_BRUSH)); 327 328 /* white highlight */ 329 SelectObject(hdc, GetStockObject(WHITE_PEN)); 330 MoveToEx(hdc, rc.right, 1, NULL); 331 LineTo(hdc, 1, 1); 332 LineTo(hdc, 1, rc.bottom - 1); 333 334 335 MoveToEx(hdc, 0, rc.bottom, NULL); 336 LineTo(hdc, rc.right, rc.bottom); 337 338 EndPaint(hWnd, &ps); 339 } 340 341 static void SB_OnLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam) 342 { 343 SetCapture(hWnd); 344 } 345 346 static void SB_OnLButtonUp(HWND hWnd, WPARAM wParam, LPARAM lParam) 347 { 348 HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, 0); 349 POINT pt; 350 351 pt.x = (short)LOWORD(lParam); 352 pt.y = (short)HIWORD(lParam); 353 354 /* update the window sizes */ 355 pHHInfo->WinType.iNavWidth += pt.x; 356 Help_OnSize(hWnd); 357 358 ReleaseCapture(); 359 } 360 361 static void SB_OnMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam) 362 { 363 /* ignore WM_MOUSEMOVE if not dragging the SizeBar */ 364 if (!(wParam & MK_LBUTTON)) 365 return; 366 } 367 368 static LRESULT CALLBACK SizeBar_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 369 { 370 switch (message) 371 { 372 case WM_LBUTTONDOWN: 373 SB_OnLButtonDown(hWnd, wParam, lParam); 374 break; 375 case WM_LBUTTONUP: 376 SB_OnLButtonUp(hWnd, wParam, lParam); 377 break; 378 case WM_MOUSEMOVE: 379 SB_OnMouseMove(hWnd, wParam, lParam); 380 break; 381 case WM_PAINT: 382 SB_OnPaint(hWnd); 383 break; 384 default: 385 return DefWindowProcW(hWnd, message, wParam, lParam); 386 } 387 388 return 0; 389 } 390 391 static void HH_RegisterSizeBarClass(HHInfo *pHHInfo) 392 { 393 WNDCLASSEXW wcex; 394 395 wcex.cbSize = sizeof(WNDCLASSEXW); 396 wcex.style = 0; 397 wcex.lpfnWndProc = SizeBar_WndProc; 398 wcex.cbClsExtra = 0; 399 wcex.cbWndExtra = sizeof(LONG_PTR); 400 wcex.hInstance = hhctrl_hinstance; 401 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 402 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEWE); 403 wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1); 404 wcex.lpszMenuName = NULL; 405 wcex.lpszClassName = szSizeBarClass; 406 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 407 408 RegisterClassExW(&wcex); 409 } 410 411 static void SB_GetSizeBarRect(HHInfo *info, RECT *rc) 412 { 413 RECT rectWND, rectTB, rectNP; 414 415 GetClientRect(info->WinType.hwndHelp, &rectWND); 416 GetClientRect(info->WinType.hwndToolBar, &rectTB); 417 GetClientRect(info->WinType.hwndNavigation, &rectNP); 418 419 SetRect(rc, rectNP.right, rectTB.bottom, SIZEBAR_WIDTH, rectWND.bottom - rectTB.bottom); 420 } 421 422 static BOOL HH_AddSizeBar(HHInfo *pHHInfo) 423 { 424 HWND hWnd; 425 HWND hwndParent = pHHInfo->WinType.hwndHelp; 426 DWORD dwStyles = WS_CHILDWINDOW | WS_OVERLAPPED; 427 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR; 428 RECT rc; 429 430 if (navigation_visible(pHHInfo)) 431 dwStyles |= WS_VISIBLE; 432 433 SB_GetSizeBarRect(pHHInfo, &rc); 434 435 hWnd = CreateWindowExW(dwExStyles, szSizeBarClass, szEmpty, dwStyles, 436 rc.left, rc.top, rc.right, rc.bottom, 437 hwndParent, NULL, hhctrl_hinstance, NULL); 438 if (!hWnd) 439 return FALSE; 440 441 /* store the pointer to the HH info struct */ 442 SetWindowLongPtrW(hWnd, 0, (LONG_PTR)pHHInfo); 443 444 pHHInfo->hwndSizeBar = hWnd; 445 return TRUE; 446 } 447 448 /* Child Window */ 449 450 static const WCHAR szChildClass[] = { 451 'H','H',' ','C','h','i','l','d',0 452 }; 453 454 static LRESULT Child_OnPaint(HWND hWnd) 455 { 456 PAINTSTRUCT ps; 457 HDC hdc; 458 RECT rc; 459 460 hdc = BeginPaint(hWnd, &ps); 461 462 /* Only paint the Navigation pane, identified by the fact 463 * that it has a child window 464 */ 465 if (GetWindow(hWnd, GW_CHILD)) 466 { 467 GetClientRect(hWnd, &rc); 468 469 /* set the border color */ 470 SelectObject(hdc, GetStockObject(DC_PEN)); 471 SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW)); 472 473 /* Draw the top border */ 474 LineTo(hdc, rc.right, 0); 475 476 SelectObject(hdc, GetStockObject(WHITE_PEN)); 477 MoveToEx(hdc, 0, 1, NULL); 478 LineTo(hdc, rc.right, 1); 479 } 480 481 EndPaint(hWnd, &ps); 482 483 return 0; 484 } 485 486 static void ResizeTabChild(HHInfo *info, int tab) 487 { 488 HWND hwnd = info->tabs[tab].hwnd; 489 INT width, height; 490 RECT rect, tabrc; 491 DWORD cnt; 492 493 GetClientRect(info->WinType.hwndNavigation, &rect); 494 SendMessageW(info->hwndTabCtrl, TCM_GETITEMRECT, 0, (LPARAM)&tabrc); 495 cnt = SendMessageW(info->hwndTabCtrl, TCM_GETROWCOUNT, 0, 0); 496 497 rect.left = TAB_MARGIN; 498 rect.top = TAB_TOP_PADDING + cnt*(tabrc.bottom-tabrc.top) + TAB_MARGIN; 499 rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN; 500 rect.bottom -= TAB_MARGIN; 501 width = rect.right-rect.left; 502 height = rect.bottom-rect.top; 503 504 SetWindowPos(hwnd, NULL, rect.left, rect.top, width, height, 505 SWP_NOZORDER | SWP_NOACTIVATE); 506 507 switch (tab) 508 { 509 case TAB_INDEX: { 510 int scroll_width = GetSystemMetrics(SM_CXVSCROLL); 511 int border_width = GetSystemMetrics(SM_CXBORDER); 512 int edge_width = GetSystemMetrics(SM_CXEDGE); 513 514 /* Resize the tab widget column to perfectly fit the tab window and 515 * leave sufficient space for the scroll widget. 516 */ 517 SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_SETCOLUMNWIDTH, 0, 518 width-scroll_width-2*border_width-2*edge_width); 519 520 break; 521 } 522 case TAB_SEARCH: { 523 int scroll_width = GetSystemMetrics(SM_CXVSCROLL); 524 int border_width = GetSystemMetrics(SM_CXBORDER); 525 int edge_width = GetSystemMetrics(SM_CXEDGE); 526 int top_pos = 0; 527 528 SetWindowPos(info->search.hwndEdit, NULL, 0, top_pos, width, 529 EDIT_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE); 530 top_pos += EDIT_HEIGHT + TAB_MARGIN; 531 SetWindowPos(info->search.hwndList, NULL, 0, top_pos, width, 532 height-top_pos, SWP_NOZORDER | SWP_NOACTIVATE); 533 /* Resize the tab widget column to perfectly fit the tab window and 534 * leave sufficient space for the scroll widget. 535 */ 536 SendMessageW(info->search.hwndList, LVM_SETCOLUMNWIDTH, 0, 537 width-scroll_width-2*border_width-2*edge_width); 538 539 break; 540 } 541 } 542 } 543 544 static LRESULT Child_OnSize(HWND hwnd) 545 { 546 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, 0); 547 RECT rect; 548 549 if(!info || hwnd != info->WinType.hwndNavigation) 550 return 0; 551 552 GetClientRect(hwnd, &rect); 553 SetWindowPos(info->hwndTabCtrl, HWND_TOP, 0, 0, 554 rect.right - TAB_RIGHT_PADDING, 555 rect.bottom - TAB_TOP_PADDING, SWP_NOMOVE); 556 557 ResizeTabChild(info, TAB_CONTENTS); 558 ResizeTabChild(info, TAB_INDEX); 559 ResizeTabChild(info, TAB_SEARCH); 560 return 0; 561 } 562 563 static LRESULT OnTabChange(HWND hwnd) 564 { 565 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hwnd, 0); 566 int tab_id, tab_index, i; 567 568 TRACE("%p\n", hwnd); 569 570 if (!info) 571 return 0; 572 573 if(info->tabs[info->current_tab].hwnd) 574 ShowWindow(info->tabs[info->current_tab].hwnd, SW_HIDE); 575 576 tab_id = (int) SendMessageW(info->hwndTabCtrl, TCM_GETCURSEL, 0, 0); 577 /* convert the ID of the tab to an index in our tab list */ 578 tab_index = -1; 579 for (i=0; i<TAB_NUMTABS; i++) 580 { 581 if (info->tabs[i].id == tab_id) 582 { 583 tab_index = i; 584 break; 585 } 586 } 587 if (tab_index == -1) 588 { 589 FIXME("Tab ID %d does not correspond to a valid index in the tab list.\n", tab_id); 590 return 0; 591 } 592 info->current_tab = tab_index; 593 594 if(info->tabs[info->current_tab].hwnd) 595 ShowWindow(info->tabs[info->current_tab].hwnd, SW_SHOW); 596 597 return 0; 598 } 599 600 static LRESULT OnTopicChange(HHInfo *info, void *user_data) 601 { 602 LPCWSTR chmfile = NULL, name = NULL, local = NULL; 603 ContentItem *citer; 604 SearchItem *siter; 605 IndexItem *iiter; 606 607 if(!user_data || !info) 608 return 0; 609 610 switch (info->current_tab) 611 { 612 case TAB_CONTENTS: 613 citer = (ContentItem *) user_data; 614 name = citer->name; 615 local = citer->local; 616 while(citer) { 617 if(citer->merge.chm_file) { 618 chmfile = citer->merge.chm_file; 619 break; 620 } 621 citer = citer->parent; 622 } 623 break; 624 case TAB_INDEX: 625 iiter = (IndexItem *) user_data; 626 if(iiter->nItems == 0) { 627 FIXME("No entries for this item!\n"); 628 return 0; 629 } 630 if(iiter->nItems > 1) { 631 int i = 0; 632 LVITEMW lvi; 633 634 SendMessageW(info->popup.hwndList, LVM_DELETEALLITEMS, 0, 0); 635 for(i=0;i<iiter->nItems;i++) { 636 IndexSubItem *item = &iiter->items[i]; 637 WCHAR *name = iiter->keyword; 638 639 if(!item->name) 640 item->name = GetDocumentTitle(info->pCHMInfo, item->local); 641 if(item->name) 642 name = item->name; 643 memset(&lvi, 0, sizeof(lvi)); 644 lvi.iItem = i; 645 lvi.mask = LVIF_TEXT|LVIF_PARAM; 646 lvi.cchTextMax = lstrlenW(name)+1; 647 lvi.pszText = name; 648 lvi.lParam = (LPARAM) item; 649 SendMessageW(info->popup.hwndList, LVM_INSERTITEMW, 0, (LPARAM)&lvi); 650 } 651 ShowWindow(info->popup.hwndPopup, SW_SHOW); 652 return 0; 653 } 654 name = iiter->items[0].name; 655 local = iiter->items[0].local; 656 chmfile = iiter->merge.chm_file; 657 break; 658 case TAB_SEARCH: 659 siter = (SearchItem *) user_data; 660 name = siter->filename; 661 local = siter->filename; 662 chmfile = info->pCHMInfo->szFile; 663 break; 664 default: 665 FIXME("Unhandled operation for this tab!\n"); 666 return 0; 667 } 668 669 if(!chmfile) 670 { 671 FIXME("No help file found for this item!\n"); 672 return 0; 673 } 674 675 TRACE("name %s loal %s\n", debugstr_w(name), debugstr_w(local)); 676 677 NavigateToChm(info, chmfile, local); 678 return 0; 679 } 680 681 /* Capture the Enter/Return key and send it up to Child_WndProc as an NM_RETURN message */ 682 static LRESULT CALLBACK EditChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 683 { 684 WNDPROC editWndProc = (WNDPROC)GetWindowLongPtrW(hWnd, GWLP_USERDATA); 685 686 if(message == WM_KEYUP && wParam == VK_RETURN) 687 { 688 NMHDR nmhdr; 689 690 nmhdr.hwndFrom = hWnd; 691 nmhdr.code = NM_RETURN; 692 SendMessageW(GetParent(GetParent(hWnd)), WM_NOTIFY, wParam, (LPARAM)&nmhdr); 693 } 694 return editWndProc(hWnd, message, wParam, lParam); 695 } 696 697 static LRESULT CALLBACK Child_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 698 { 699 switch (message) 700 { 701 case WM_PAINT: 702 return Child_OnPaint(hWnd); 703 case WM_SIZE: 704 return Child_OnSize(hWnd); 705 case WM_NOTIFY: { 706 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0); 707 NMHDR *nmhdr = (NMHDR*)lParam; 708 709 switch(nmhdr->code) { 710 case TCN_SELCHANGE: 711 return OnTabChange(hWnd); 712 case TVN_SELCHANGEDW: 713 return OnTopicChange(info, (void*)((NMTREEVIEWW *)lParam)->itemNew.lParam); 714 case TVN_ITEMEXPANDINGW: { 715 TVITEMW *item = &((NMTREEVIEWW *)lParam)->itemNew; 716 HWND hwndTreeView = info->tabs[TAB_CONTENTS].hwnd; 717 718 item->mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE; 719 if (item->state & TVIS_EXPANDED) 720 { 721 item->iImage = HHTV_FOLDER; 722 item->iSelectedImage = HHTV_FOLDER; 723 } 724 else 725 { 726 item->iImage = HHTV_OPENFOLDER; 727 item->iSelectedImage = HHTV_OPENFOLDER; 728 } 729 SendMessageW(hwndTreeView, TVM_SETITEMW, 0, (LPARAM)item); 730 return 0; 731 } 732 case NM_DBLCLK: 733 if(!info) 734 return 0; 735 switch(info->current_tab) 736 { 737 case TAB_INDEX: 738 return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam); 739 case TAB_SEARCH: 740 return OnTopicChange(info, (void*)((NMITEMACTIVATE *)lParam)->lParam); 741 } 742 break; 743 case NM_RETURN: 744 if(!info) 745 return 0; 746 switch(info->current_tab) { 747 case TAB_INDEX: { 748 HWND hwndList = info->tabs[TAB_INDEX].hwnd; 749 LVITEMW lvItem; 750 751 lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0); 752 lvItem.mask = TVIF_PARAM; 753 SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem); 754 OnTopicChange(info, (void*) lvItem.lParam); 755 return 0; 756 } 757 case TAB_SEARCH: { 758 if(nmhdr->hwndFrom == info->search.hwndEdit) { 759 char needle[100]; 760 DWORD i, len; 761 762 len = GetWindowTextA(info->search.hwndEdit, needle, sizeof(needle)); 763 if(!len) 764 { 765 FIXME("Unable to get search text.\n"); 766 return 0; 767 } 768 /* Convert the requested text for comparison later against the 769 * lower case version of HTML file contents. 770 */ 771 for(i=0;i<len;i++) 772 needle[i] = tolower(needle[i]); 773 InitSearch(info, needle); 774 return 0; 775 }else if(nmhdr->hwndFrom == info->search.hwndList) { 776 HWND hwndList = info->search.hwndList; 777 LVITEMW lvItem; 778 779 lvItem.iItem = (int) SendMessageW(hwndList, LVM_GETSELECTIONMARK, 0, 0); 780 lvItem.mask = TVIF_PARAM; 781 SendMessageW(hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem); 782 OnTopicChange(info, (void*) lvItem.lParam); 783 return 0; 784 } 785 break; 786 } 787 } 788 break; 789 } 790 break; 791 } 792 default: 793 return DefWindowProcW(hWnd, message, wParam, lParam); 794 } 795 796 return 0; 797 } 798 799 static void HH_RegisterChildWndClass(HHInfo *pHHInfo) 800 { 801 WNDCLASSEXW wcex; 802 803 wcex.cbSize = sizeof(WNDCLASSEXW); 804 wcex.style = 0; 805 wcex.lpfnWndProc = Child_WndProc; 806 wcex.cbClsExtra = 0; 807 wcex.cbWndExtra = sizeof(LONG_PTR); 808 wcex.hInstance = hhctrl_hinstance; 809 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 810 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); 811 wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 812 wcex.lpszMenuName = NULL; 813 wcex.lpszClassName = szChildClass; 814 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 815 816 RegisterClassExW(&wcex); 817 } 818 819 /* Toolbar */ 820 821 #define ICON_SIZE 20 822 823 static void DisplayPopupMenu(HHInfo *info) 824 { 825 HMENU menu, submenu; 826 TBBUTTONINFOW button; 827 MENUITEMINFOW item; 828 POINT coords; 829 RECT rect; 830 DWORD index; 831 832 menu = LoadMenuW(hhctrl_hinstance, MAKEINTRESOURCEW(MENU_POPUP)); 833 834 if (!menu) 835 return; 836 837 submenu = GetSubMenu(menu, 0); 838 839 /* Update the Show/Hide menu item */ 840 item.cbSize = sizeof(MENUITEMINFOW); 841 item.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_STRING; 842 item.fType = MFT_STRING; 843 item.fState = MF_ENABLED; 844 845 if (info->WinType.fNotExpanded) 846 item.dwTypeData = HH_LoadString(IDS_SHOWTABS); 847 else 848 item.dwTypeData = HH_LoadString(IDS_HIDETABS); 849 850 SetMenuItemInfoW(submenu, IDTB_EXPAND, FALSE, &item); 851 heap_free(item.dwTypeData); 852 853 /* Find the index toolbar button */ 854 button.cbSize = sizeof(TBBUTTONINFOW); 855 button.dwMask = TBIF_COMMAND; 856 index = SendMessageW(info->WinType.hwndToolBar, TB_GETBUTTONINFOW, IDTB_OPTIONS, (LPARAM) &button); 857 858 if (index == -1) 859 return; 860 861 /* Get position */ 862 SendMessageW(info->WinType.hwndToolBar, TB_GETITEMRECT, index, (LPARAM) &rect); 863 864 coords.x = rect.left; 865 coords.y = rect.bottom; 866 867 ClientToScreen(info->WinType.hwndToolBar, &coords); 868 TrackPopupMenu(submenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_NOANIMATION, coords.x, coords.y, 0, info->WinType.hwndHelp, NULL); 869 } 870 871 static void TB_OnClick(HWND hWnd, DWORD dwID) 872 { 873 HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, 0); 874 875 switch (dwID) 876 { 877 case IDTB_STOP: 878 DoPageAction(info->web_browser, WB_STOP); 879 break; 880 case IDTB_REFRESH: 881 DoPageAction(info->web_browser, WB_REFRESH); 882 break; 883 case IDTB_BACK: 884 DoPageAction(info->web_browser, WB_GOBACK); 885 break; 886 case IDTB_HOME: 887 NavigateToChm(info, info->pCHMInfo->szFile, info->WinType.pszHome); 888 break; 889 case IDTB_FORWARD: 890 DoPageAction(info->web_browser, WB_GOFORWARD); 891 break; 892 case IDTB_PRINT: 893 DoPageAction(info->web_browser, WB_PRINT); 894 break; 895 case IDTB_EXPAND: 896 case IDTB_CONTRACT: 897 ExpandContract(info); 898 break; 899 case IDTB_SYNC: 900 DoSync(info); 901 break; 902 case IDTB_OPTIONS: 903 DisplayPopupMenu(info); 904 break; 905 case IDTB_NOTES: 906 case IDTB_CONTENTS: 907 case IDTB_INDEX: 908 case IDTB_SEARCH: 909 case IDTB_HISTORY: 910 case IDTB_FAVORITES: 911 /* These are officially unimplemented as of the Windows 7 SDK */ 912 break; 913 case IDTB_BROWSE_FWD: 914 case IDTB_BROWSE_BACK: 915 case IDTB_JUMP1: 916 case IDTB_JUMP2: 917 case IDTB_CUSTOMIZE: 918 case IDTB_ZOOM: 919 case IDTB_TOC_NEXT: 920 case IDTB_TOC_PREV: 921 break; 922 } 923 } 924 925 static void TB_AddButton(TBBUTTON *pButtons, DWORD dwIndex, DWORD dwID, DWORD dwBitmap) 926 { 927 pButtons[dwIndex].iBitmap = dwBitmap; 928 pButtons[dwIndex].idCommand = dwID; 929 pButtons[dwIndex].fsState = TBSTATE_ENABLED; 930 pButtons[dwIndex].fsStyle = BTNS_BUTTON; 931 pButtons[dwIndex].dwData = 0; 932 pButtons[dwIndex].iString = 0; 933 } 934 935 static void TB_AddButtonsFromFlags(HHInfo *pHHInfo, TBBUTTON *pButtons, DWORD dwButtonFlags, LPDWORD pdwNumButtons) 936 { 937 int nHistBitmaps = 0, nStdBitmaps = 0, nHHBitmaps = 0; 938 HWND hToolbar = pHHInfo->WinType.hwndToolBar; 939 TBADDBITMAP tbAB; 940 DWORD unsupported; 941 942 /* Common bitmaps */ 943 tbAB.hInst = HINST_COMMCTRL; 944 tbAB.nID = IDB_HIST_LARGE_COLOR; 945 nHistBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB); 946 tbAB.nID = IDB_STD_LARGE_COLOR; 947 nStdBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, 0, (LPARAM)&tbAB); 948 /* hhctrl.ocx bitmaps */ 949 tbAB.hInst = hhctrl_hinstance; 950 tbAB.nID = IDB_HHTOOLBAR; 951 nHHBitmaps = SendMessageW(hToolbar, TB_ADDBITMAP, HHTB_NUMBITMAPS, (LPARAM)&tbAB); 952 953 *pdwNumButtons = 0; 954 955 unsupported = dwButtonFlags & (HHWIN_BUTTON_BROWSE_FWD | 956 HHWIN_BUTTON_BROWSE_BCK | HHWIN_BUTTON_NOTES | HHWIN_BUTTON_CONTENTS | 957 HHWIN_BUTTON_INDEX | HHWIN_BUTTON_SEARCH | HHWIN_BUTTON_HISTORY | 958 HHWIN_BUTTON_FAVORITES | HHWIN_BUTTON_JUMP1 | HHWIN_BUTTON_JUMP2 | 959 HHWIN_BUTTON_ZOOM | HHWIN_BUTTON_TOC_NEXT | HHWIN_BUTTON_TOC_PREV); 960 if (unsupported) 961 FIXME("got asked for unsupported buttons: %06x\n", unsupported); 962 963 if (dwButtonFlags & HHWIN_BUTTON_EXPAND) 964 { 965 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_EXPAND, nHHBitmaps + HHTB_EXPAND); 966 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_CONTRACT, nHHBitmaps + HHTB_CONTRACT); 967 968 if (pHHInfo->WinType.fNotExpanded) 969 pButtons[1].fsState |= TBSTATE_HIDDEN; 970 else 971 pButtons[0].fsState |= TBSTATE_HIDDEN; 972 } 973 974 if (dwButtonFlags & HHWIN_BUTTON_BACK) 975 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_BACK, nHistBitmaps + HIST_BACK); 976 977 if (dwButtonFlags & HHWIN_BUTTON_FORWARD) 978 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_FORWARD, nHistBitmaps + HIST_FORWARD); 979 980 if (dwButtonFlags & HHWIN_BUTTON_STOP) 981 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_STOP, nHHBitmaps + HHTB_STOP); 982 983 if (dwButtonFlags & HHWIN_BUTTON_REFRESH) 984 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_REFRESH, nHHBitmaps + HHTB_REFRESH); 985 986 if (dwButtonFlags & HHWIN_BUTTON_HOME) 987 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_HOME, nHHBitmaps + HHTB_HOME); 988 989 if (dwButtonFlags & HHWIN_BUTTON_SYNC) 990 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_SYNC, nHHBitmaps + HHTB_SYNC); 991 992 if (dwButtonFlags & HHWIN_BUTTON_OPTIONS) 993 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_OPTIONS, nStdBitmaps + STD_PROPERTIES); 994 995 if (dwButtonFlags & HHWIN_BUTTON_PRINT) 996 TB_AddButton(pButtons, (*pdwNumButtons)++, IDTB_PRINT, nStdBitmaps + STD_PRINT); 997 } 998 999 static BOOL HH_AddToolbar(HHInfo *pHHInfo) 1000 { 1001 HWND hToolbar; 1002 HWND hwndParent = pHHInfo->WinType.hwndHelp; 1003 DWORD toolbarFlags; 1004 TBBUTTON buttons[IDTB_TOC_PREV - IDTB_EXPAND]; 1005 DWORD dwStyles, dwExStyles; 1006 DWORD dwNumButtons, dwIndex; 1007 1008 if (pHHInfo->WinType.fsWinProperties & HHWIN_PARAM_TB_FLAGS) 1009 toolbarFlags = pHHInfo->WinType.fsToolBarFlags; 1010 else 1011 toolbarFlags = HHWIN_DEF_BUTTONS; 1012 1013 dwStyles = WS_CHILDWINDOW | TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TOOLTIPS | CCS_NODIVIDER; 1014 dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR; 1015 1016 hToolbar = CreateWindowExW(dwExStyles, TOOLBARCLASSNAMEW, NULL, dwStyles, 1017 0, 0, 0, 0, hwndParent, NULL, 1018 hhctrl_hinstance, NULL); 1019 if (!hToolbar) 1020 return FALSE; 1021 pHHInfo->WinType.hwndToolBar = hToolbar; 1022 1023 SendMessageW(hToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(ICON_SIZE, ICON_SIZE)); 1024 SendMessageW(hToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); 1025 SendMessageW(hToolbar, WM_SETFONT, (WPARAM)pHHInfo->hFont, TRUE); 1026 1027 TB_AddButtonsFromFlags(pHHInfo, buttons, toolbarFlags, &dwNumButtons); 1028 1029 for (dwIndex = 0; dwIndex < dwNumButtons; dwIndex++) 1030 { 1031 LPWSTR szBuf = HH_LoadString(buttons[dwIndex].idCommand); 1032 DWORD dwLen = lstrlenW(szBuf); 1033 szBuf[dwLen + 1] = 0; /* Double-null terminate */ 1034 1035 buttons[dwIndex].iString = (DWORD)SendMessageW(hToolbar, TB_ADDSTRINGW, 0, (LPARAM)szBuf); 1036 heap_free(szBuf); 1037 } 1038 1039 SendMessageW(hToolbar, TB_ADDBUTTONSW, dwNumButtons, (LPARAM)buttons); 1040 SendMessageW(hToolbar, TB_AUTOSIZE, 0, 0); 1041 if (pHHInfo->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) 1042 ShowWindow(hToolbar, SW_SHOW); 1043 1044 return TRUE; 1045 } 1046 1047 /* Navigation Pane */ 1048 1049 static void NP_GetNavigationRect(HHInfo *pHHInfo, RECT *rc) 1050 { 1051 HWND hwndParent = pHHInfo->WinType.hwndHelp; 1052 HWND hwndToolbar = pHHInfo->WinType.hwndToolBar; 1053 RECT rectWND, rectTB; 1054 1055 GetClientRect(hwndParent, &rectWND); 1056 GetClientRect(hwndToolbar, &rectTB); 1057 1058 rc->left = 0; 1059 rc->top = rectTB.bottom; 1060 rc->bottom = rectWND.bottom - rectTB.bottom; 1061 1062 if (!(pHHInfo->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) && 1063 pHHInfo->WinType.iNavWidth == 0) 1064 { 1065 pHHInfo->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH; 1066 } 1067 1068 rc->right = pHHInfo->WinType.iNavWidth; 1069 } 1070 1071 static DWORD NP_CreateTab(HINSTANCE hInstance, HWND hwndTabCtrl, DWORD index) 1072 { 1073 TCITEMW tie; 1074 LPWSTR tabText = HH_LoadString(index); 1075 DWORD ret; 1076 1077 tie.mask = TCIF_TEXT; 1078 tie.pszText = tabText; 1079 1080 ret = SendMessageW( hwndTabCtrl, TCM_INSERTITEMW, index, (LPARAM)&tie ); 1081 1082 heap_free(tabText); 1083 return ret; 1084 } 1085 1086 static BOOL HH_AddNavigationPane(HHInfo *info) 1087 { 1088 HWND hWnd, hwndTabCtrl; 1089 HWND hwndParent = info->WinType.hwndHelp; 1090 DWORD dwStyles = WS_CHILDWINDOW; 1091 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR; 1092 RECT rc; 1093 1094 if (navigation_visible(info)) 1095 dwStyles |= WS_VISIBLE; 1096 1097 NP_GetNavigationRect(info, &rc); 1098 1099 hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles, 1100 rc.left, rc.top, rc.right, rc.bottom, 1101 hwndParent, NULL, hhctrl_hinstance, NULL); 1102 if (!hWnd) 1103 return FALSE; 1104 1105 SetWindowLongPtrW(hWnd, 0, (LONG_PTR)info); 1106 1107 hwndTabCtrl = CreateWindowExW(dwExStyles, WC_TABCONTROLW, szEmpty, dwStyles | WS_VISIBLE, 1108 0, TAB_TOP_PADDING, 1109 rc.right - TAB_RIGHT_PADDING, 1110 rc.bottom - TAB_TOP_PADDING, 1111 hWnd, NULL, hhctrl_hinstance, NULL); 1112 if (!hwndTabCtrl) 1113 return FALSE; 1114 1115 if (*info->WinType.pszToc) 1116 info->tabs[TAB_CONTENTS].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_CONTENTS); 1117 1118 if (*info->WinType.pszIndex) 1119 info->tabs[TAB_INDEX].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_INDEX); 1120 1121 if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_SEARCH) 1122 info->tabs[TAB_SEARCH].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_SEARCH); 1123 1124 if (info->WinType.fsWinProperties & HHWIN_PROP_TAB_FAVORITES) 1125 info->tabs[TAB_FAVORITES].id = NP_CreateTab(hhctrl_hinstance, hwndTabCtrl, IDS_FAVORITES); 1126 1127 SendMessageW(hwndTabCtrl, WM_SETFONT, (WPARAM)info->hFont, TRUE); 1128 1129 info->hwndTabCtrl = hwndTabCtrl; 1130 info->WinType.hwndNavigation = hWnd; 1131 return TRUE; 1132 } 1133 1134 /* HTML Pane */ 1135 1136 static void HP_GetHTMLRect(HHInfo *info, RECT *rc) 1137 { 1138 RECT rectTB, rectWND, rectNP, rectSB; 1139 1140 GetClientRect(info->WinType.hwndHelp, &rectWND); 1141 GetClientRect(info->hwndSizeBar, &rectSB); 1142 1143 rc->left = 0; 1144 rc->top = 0; 1145 if (navigation_visible(info)) 1146 { 1147 GetClientRect(info->WinType.hwndNavigation, &rectNP); 1148 rc->left += rectNP.right + rectSB.right; 1149 } 1150 if (info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) 1151 { 1152 GetClientRect(info->WinType.hwndToolBar, &rectTB); 1153 rc->top += rectTB.bottom; 1154 } 1155 rc->right = rectWND.right - rc->left; 1156 rc->bottom = rectWND.bottom - rc->top; 1157 } 1158 1159 static BOOL HH_AddHTMLPane(HHInfo *pHHInfo) 1160 { 1161 HWND hWnd; 1162 HWND hwndParent = pHHInfo->WinType.hwndHelp; 1163 DWORD dwStyles = WS_CHILDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN; 1164 DWORD dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_CLIENTEDGE; 1165 RECT rc; 1166 1167 HP_GetHTMLRect(pHHInfo, &rc); 1168 1169 hWnd = CreateWindowExW(dwExStyles, szChildClass, szEmpty, dwStyles, 1170 rc.left, rc.top, rc.right, rc.bottom, 1171 hwndParent, NULL, hhctrl_hinstance, NULL); 1172 if (!hWnd) 1173 return FALSE; 1174 1175 if (!InitWebBrowser(pHHInfo, hWnd)) 1176 return FALSE; 1177 1178 /* store the pointer to the HH info struct */ 1179 SetWindowLongPtrW(hWnd, 0, (LONG_PTR)pHHInfo); 1180 1181 ShowWindow(hWnd, SW_SHOW); 1182 UpdateWindow(hWnd); 1183 1184 pHHInfo->WinType.hwndHTML = hWnd; 1185 return TRUE; 1186 } 1187 1188 static BOOL AddContentTab(HHInfo *info) 1189 { 1190 HIMAGELIST hImageList; 1191 HBITMAP hBitmap; 1192 HWND hWnd; 1193 1194 if(info->tabs[TAB_CONTENTS].id == -1) 1195 return TRUE; /* No "Contents" tab */ 1196 hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW, szEmpty, WS_CHILD | WS_BORDER | TVS_LINESATROOT 1197 | TVS_SHOWSELALWAYS | TVS_HASBUTTONS, 50, 50, 100, 100, 1198 info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL); 1199 if(!hWnd) { 1200 ERR("Could not create treeview control\n"); 1201 return FALSE; 1202 } 1203 1204 hImageList = ImageList_Create(16, 16, ILC_COLOR32, 0, HHTV_NUMBITMAPS); 1205 hBitmap = LoadBitmapW(hhctrl_hinstance, MAKEINTRESOURCEW(IDB_HHTREEVIEW)); 1206 ImageList_Add(hImageList, hBitmap, NULL); 1207 SendMessageW(hWnd, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM)hImageList); 1208 1209 info->contents.hImageList = hImageList; 1210 info->tabs[TAB_CONTENTS].hwnd = hWnd; 1211 ResizeTabChild(info, TAB_CONTENTS); 1212 ShowWindow(hWnd, SW_SHOW); 1213 1214 return TRUE; 1215 } 1216 1217 static BOOL AddIndexTab(HHInfo *info) 1218 { 1219 char hidden_column[] = "Column"; 1220 LVCOLUMNA lvc; 1221 1222 if(info->tabs[TAB_INDEX].id == -1) 1223 return TRUE; /* No "Index" tab */ 1224 info->tabs[TAB_INDEX].hwnd = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, 1225 szEmpty, WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT | LVS_NOCOLUMNHEADER, 50, 50, 100, 100, 1226 info->WinType.hwndNavigation, NULL, hhctrl_hinstance, NULL); 1227 if(!info->tabs[TAB_INDEX].hwnd) { 1228 ERR("Could not create ListView control\n"); 1229 return FALSE; 1230 } 1231 memset(&lvc, 0, sizeof(lvc)); 1232 lvc.mask = LVCF_TEXT; 1233 lvc.pszText = hidden_column; 1234 if(SendMessageW(info->tabs[TAB_INDEX].hwnd, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1) 1235 { 1236 ERR("Could not create ListView column\n"); 1237 return FALSE; 1238 } 1239 1240 ResizeTabChild(info, TAB_INDEX); 1241 ShowWindow(info->tabs[TAB_INDEX].hwnd, SW_HIDE); 1242 1243 return TRUE; 1244 } 1245 1246 static BOOL AddSearchTab(HHInfo *info) 1247 { 1248 HWND hwndList, hwndEdit, hwndContainer; 1249 char hidden_column[] = "Column"; 1250 WNDPROC editWndProc; 1251 LVCOLUMNA lvc; 1252 1253 if(info->tabs[TAB_SEARCH].id == -1) 1254 return TRUE; /* No "Search" tab */ 1255 hwndContainer = CreateWindowExW(WS_EX_CONTROLPARENT, szChildClass, szEmpty, 1256 WS_CHILD, 0, 0, 0, 0, info->WinType.hwndNavigation, 1257 NULL, hhctrl_hinstance, NULL); 1258 if(!hwndContainer) { 1259 ERR("Could not create search window container control.\n"); 1260 return FALSE; 1261 } 1262 hwndEdit = CreateWindowExW(WS_EX_CLIENTEDGE, WC_EDITW, szEmpty, WS_CHILD 1263 | WS_VISIBLE | ES_LEFT | SS_NOTIFY, 0, 0, 0, 0, 1264 hwndContainer, NULL, hhctrl_hinstance, NULL); 1265 if(!hwndEdit) { 1266 ERR("Could not create search ListView control.\n"); 1267 return FALSE; 1268 } 1269 if(SendMessageW(hwndEdit, WM_SETFONT, (WPARAM) info->hFont, (LPARAM) FALSE) == -1) 1270 { 1271 ERR("Could not set font for edit control.\n"); 1272 return FALSE; 1273 } 1274 editWndProc = (WNDPROC) SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR)EditChild_WndProc); 1275 if(!editWndProc) { 1276 ERR("Could not redirect messages for edit control.\n"); 1277 return FALSE; 1278 } 1279 SetWindowLongPtrW(hwndEdit, GWLP_USERDATA, (LONG_PTR)editWndProc); 1280 hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty, 1281 WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_SINGLESEL 1282 | LVS_REPORT | LVS_NOCOLUMNHEADER, 0, 0, 0, 0, 1283 hwndContainer, NULL, hhctrl_hinstance, NULL); 1284 if(!hwndList) { 1285 ERR("Could not create search ListView control.\n"); 1286 return FALSE; 1287 } 1288 memset(&lvc, 0, sizeof(lvc)); 1289 lvc.mask = LVCF_TEXT; 1290 lvc.pszText = hidden_column; 1291 if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1) 1292 { 1293 ERR("Could not create ListView column\n"); 1294 return FALSE; 1295 } 1296 1297 info->search.hwndEdit = hwndEdit; 1298 info->search.hwndList = hwndList; 1299 info->search.hwndContainer = hwndContainer; 1300 info->tabs[TAB_SEARCH].hwnd = hwndContainer; 1301 1302 SetWindowLongPtrW(hwndContainer, 0, (LONG_PTR)info); 1303 1304 ResizeTabChild(info, TAB_SEARCH); 1305 1306 return TRUE; 1307 } 1308 1309 /* The Index tab's sub-topic popup */ 1310 1311 static void ResizePopupChild(HHInfo *info) 1312 { 1313 int scroll_width = GetSystemMetrics(SM_CXVSCROLL); 1314 int border_width = GetSystemMetrics(SM_CXBORDER); 1315 int edge_width = GetSystemMetrics(SM_CXEDGE); 1316 INT width, height; 1317 RECT rect; 1318 1319 if(!info) 1320 return; 1321 1322 GetClientRect(info->popup.hwndPopup, &rect); 1323 SetWindowPos(info->popup.hwndCallback, HWND_TOP, 0, 0, 1324 rect.right, rect.bottom, SWP_NOMOVE); 1325 1326 rect.left = TAB_MARGIN; 1327 rect.top = TAB_TOP_PADDING + TAB_MARGIN; 1328 rect.right -= TAB_RIGHT_PADDING + TAB_MARGIN; 1329 rect.bottom -= TAB_MARGIN; 1330 width = rect.right-rect.left; 1331 height = rect.bottom-rect.top; 1332 1333 SetWindowPos(info->popup.hwndList, NULL, rect.left, rect.top, width, height, 1334 SWP_NOZORDER | SWP_NOACTIVATE); 1335 1336 SendMessageW(info->popup.hwndList, LVM_SETCOLUMNWIDTH, 0, 1337 width-scroll_width-2*border_width-2*edge_width); 1338 } 1339 1340 static LRESULT CALLBACK HelpPopup_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 1341 { 1342 HHInfo *info = (HHInfo *)GetWindowLongPtrW(hWnd, 0); 1343 1344 switch (message) 1345 { 1346 case WM_SIZE: 1347 ResizePopupChild(info); 1348 return 0; 1349 case WM_DESTROY: 1350 DestroyWindow(hWnd); 1351 return 0; 1352 case WM_CLOSE: 1353 ShowWindow(hWnd, SW_HIDE); 1354 return 0; 1355 1356 default: 1357 return DefWindowProcW(hWnd, message, wParam, lParam); 1358 } 1359 1360 return 0; 1361 } 1362 1363 static LRESULT CALLBACK PopupChild_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 1364 { 1365 switch (message) 1366 { 1367 case WM_NOTIFY: { 1368 NMHDR *nmhdr = (NMHDR*)lParam; 1369 switch(nmhdr->code) 1370 { 1371 case NM_DBLCLK: { 1372 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0); 1373 IndexSubItem *iter; 1374 1375 if(info == 0 || lParam == 0) 1376 return 0; 1377 iter = (IndexSubItem*) ((NMITEMACTIVATE *)lParam)->lParam; 1378 if(iter == 0) 1379 return 0; 1380 NavigateToChm(info, info->index->merge.chm_file, iter->local); 1381 ShowWindow(info->popup.hwndPopup, SW_HIDE); 1382 return 0; 1383 } 1384 case NM_RETURN: { 1385 HHInfo *info = (HHInfo*)GetWindowLongPtrW(hWnd, 0); 1386 IndexSubItem *iter; 1387 LVITEMW lvItem; 1388 1389 if(info == 0) 1390 return 0; 1391 1392 lvItem.iItem = (int) SendMessageW(info->popup.hwndList, LVM_GETSELECTIONMARK, 0, 0); 1393 lvItem.mask = TVIF_PARAM; 1394 SendMessageW(info->popup.hwndList, LVM_GETITEMW, 0, (LPARAM)&lvItem); 1395 iter = (IndexSubItem*) lvItem.lParam; 1396 NavigateToChm(info, info->index->merge.chm_file, iter->local); 1397 ShowWindow(info->popup.hwndPopup, SW_HIDE); 1398 return 0; 1399 } 1400 } 1401 break; 1402 } 1403 default: 1404 return DefWindowProcW(hWnd, message, wParam, lParam); 1405 } 1406 1407 return 0; 1408 } 1409 1410 static BOOL AddIndexPopup(HHInfo *info) 1411 { 1412 static const WCHAR szPopupChildClass[] = {'H','H',' ','P','o','p','u','p',' ','C','h','i','l','d',0}; 1413 static const WCHAR windowCaptionW[] = {'S','e','l','e','c','t',' ','T','o','p','i','c',':',0}; 1414 static const WCHAR windowClassW[] = {'H','H',' ','P','o','p','u','p',0}; 1415 HWND hwndList, hwndPopup, hwndCallback; 1416 char hidden_column[] = "Column"; 1417 WNDCLASSEXW wcex; 1418 LVCOLUMNA lvc; 1419 1420 if(info->tabs[TAB_INDEX].id == -1) 1421 return TRUE; /* No "Index" tab */ 1422 1423 wcex.cbSize = sizeof(WNDCLASSEXW); 1424 wcex.style = CS_HREDRAW | CS_VREDRAW; 1425 wcex.lpfnWndProc = HelpPopup_WndProc; 1426 wcex.cbClsExtra = 0; 1427 wcex.cbWndExtra = sizeof(LONG_PTR); 1428 wcex.hInstance = hhctrl_hinstance; 1429 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 1430 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); 1431 wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1); 1432 wcex.lpszMenuName = NULL; 1433 wcex.lpszClassName = windowClassW; 1434 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 1435 RegisterClassExW(&wcex); 1436 1437 wcex.cbSize = sizeof(WNDCLASSEXW); 1438 wcex.style = 0; 1439 wcex.lpfnWndProc = PopupChild_WndProc; 1440 wcex.cbClsExtra = 0; 1441 wcex.cbWndExtra = sizeof(LONG_PTR); 1442 wcex.hInstance = hhctrl_hinstance; 1443 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 1444 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); 1445 wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 1446 wcex.lpszMenuName = NULL; 1447 wcex.lpszClassName = szPopupChildClass; 1448 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 1449 RegisterClassExW(&wcex); 1450 1451 hwndPopup = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW 1452 | WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR, 1453 windowClassW, windowCaptionW, WS_POPUPWINDOW 1454 | WS_OVERLAPPEDWINDOW | WS_VISIBLE 1455 | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, 1456 CW_USEDEFAULT, 300, 200, info->WinType.hwndHelp, 1457 NULL, hhctrl_hinstance, NULL); 1458 if (!hwndPopup) 1459 return FALSE; 1460 1461 hwndCallback = CreateWindowExW(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, 1462 szPopupChildClass, szEmpty, WS_CHILDWINDOW | WS_VISIBLE, 1463 0, 0, 0, 0, 1464 hwndPopup, NULL, hhctrl_hinstance, NULL); 1465 if (!hwndCallback) 1466 return FALSE; 1467 1468 ShowWindow(hwndPopup, SW_HIDE); 1469 hwndList = CreateWindowExW(WS_EX_CLIENTEDGE, WC_LISTVIEWW, szEmpty, 1470 WS_CHILD | WS_BORDER | LVS_SINGLESEL | LVS_REPORT 1471 | LVS_NOCOLUMNHEADER, 50, 50, 100, 100, 1472 hwndCallback, NULL, hhctrl_hinstance, NULL); 1473 if(!hwndList) { 1474 ERR("Could not create popup ListView control\n"); 1475 return FALSE; 1476 } 1477 memset(&lvc, 0, sizeof(lvc)); 1478 lvc.mask = LVCF_TEXT; 1479 lvc.pszText = hidden_column; 1480 if(SendMessageW(hwndList, LVM_INSERTCOLUMNA, 0, (LPARAM) &lvc) == -1) 1481 { 1482 ERR("Could not create popup ListView column\n"); 1483 return FALSE; 1484 } 1485 1486 info->popup.hwndCallback = hwndCallback; 1487 info->popup.hwndPopup = hwndPopup; 1488 info->popup.hwndList = hwndList; 1489 SetWindowLongPtrW(hwndPopup, 0, (LONG_PTR)info); 1490 SetWindowLongPtrW(hwndCallback, 0, (LONG_PTR)info); 1491 1492 ResizePopupChild(info); 1493 ShowWindow(hwndList, SW_SHOW); 1494 1495 return TRUE; 1496 } 1497 1498 /* Viewer Window */ 1499 1500 static void ExpandContract(HHInfo *pHHInfo) 1501 { 1502 RECT r, nav; 1503 1504 pHHInfo->WinType.fNotExpanded = !pHHInfo->WinType.fNotExpanded; 1505 GetWindowRect(pHHInfo->WinType.hwndHelp, &r); 1506 NP_GetNavigationRect(pHHInfo, &nav); 1507 1508 /* hide/show both the nav bar and the size bar */ 1509 if (pHHInfo->WinType.fNotExpanded) 1510 { 1511 ShowWindow(pHHInfo->WinType.hwndNavigation, SW_HIDE); 1512 ShowWindow(pHHInfo->hwndSizeBar, SW_HIDE); 1513 r.left = r.left + nav.right; 1514 1515 SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_EXPAND, MAKELPARAM(FALSE, 0)); 1516 SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_CONTRACT, MAKELPARAM(TRUE, 0)); 1517 } 1518 else 1519 { 1520 ShowWindow(pHHInfo->WinType.hwndNavigation, SW_SHOW); 1521 ShowWindow(pHHInfo->hwndSizeBar, SW_SHOW); 1522 r.left = r.left - nav.right; 1523 1524 SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_EXPAND, MAKELPARAM(TRUE, 0)); 1525 SendMessageW(pHHInfo->WinType.hwndToolBar, TB_HIDEBUTTON, IDTB_CONTRACT, MAKELPARAM(FALSE, 0)); 1526 } 1527 1528 MoveWindow(pHHInfo->WinType.hwndHelp, r.left, r.top, r.right-r.left, r.bottom-r.top, TRUE); 1529 } 1530 1531 static LRESULT Help_OnSize(HWND hWnd) 1532 { 1533 HHInfo *pHHInfo = (HHInfo *)GetWindowLongPtrW(hWnd, 0); 1534 DWORD dwSize; 1535 RECT rc; 1536 1537 if (!pHHInfo) 1538 return 0; 1539 1540 if (navigation_visible(pHHInfo)) 1541 { 1542 NP_GetNavigationRect(pHHInfo, &rc); 1543 SetWindowPos(pHHInfo->WinType.hwndNavigation, HWND_TOP, 0, 0, 1544 rc.right, rc.bottom, SWP_NOMOVE); 1545 1546 SB_GetSizeBarRect(pHHInfo, &rc); 1547 SetWindowPos(pHHInfo->hwndSizeBar, HWND_TOP, rc.left, rc.top, 1548 rc.right, rc.bottom, SWP_SHOWWINDOW); 1549 1550 } 1551 1552 HP_GetHTMLRect(pHHInfo, &rc); 1553 SetWindowPos(pHHInfo->WinType.hwndHTML, HWND_TOP, rc.left, rc.top, 1554 rc.right, rc.bottom, SWP_SHOWWINDOW); 1555 1556 /* Resize browser window taking the frame size into account */ 1557 dwSize = GetSystemMetrics(SM_CXFRAME); 1558 ResizeWebBrowser(pHHInfo, rc.right - dwSize, rc.bottom - dwSize); 1559 1560 return 0; 1561 } 1562 1563 void UpdateHelpWindow(HHInfo *info) 1564 { 1565 if (!info->WinType.hwndHelp) 1566 return; 1567 1568 WARN("Only the size of the window is currently updated.\n"); 1569 if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT) 1570 { 1571 RECT *rect = &info->WinType.rcWindowPos; 1572 INT x, y, width, height; 1573 1574 x = rect->left; 1575 y = rect->top; 1576 width = rect->right - x; 1577 height = rect->bottom - y; 1578 SetWindowPos(info->WinType.hwndHelp, NULL, rect->left, rect->top, width, height, 1579 SWP_NOZORDER | SWP_NOACTIVATE); 1580 } 1581 } 1582 1583 static LRESULT CALLBACK Help_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 1584 { 1585 switch (message) 1586 { 1587 case WM_COMMAND: 1588 if (HIWORD(wParam) == BN_CLICKED) 1589 TB_OnClick(hWnd, LOWORD(wParam)); 1590 break; 1591 case WM_SIZE: 1592 return Help_OnSize(hWnd); 1593 case WM_CLOSE: 1594 ReleaseHelpViewer((HHInfo *)GetWindowLongPtrW(hWnd, 0)); 1595 return 0; 1596 case WM_DESTROY: 1597 if(hh_process) 1598 PostQuitMessage(0); 1599 break; 1600 1601 default: 1602 return DefWindowProcW(hWnd, message, wParam, lParam); 1603 } 1604 1605 return 0; 1606 } 1607 1608 static BOOL HH_CreateHelpWindow(HHInfo *info) 1609 { 1610 HWND hWnd; 1611 RECT winPos = info->WinType.rcWindowPos; 1612 WNDCLASSEXW wcex; 1613 DWORD dwStyles, dwExStyles; 1614 DWORD x, y, width = 0, height = 0; 1615 LPCWSTR caption; 1616 1617 static const WCHAR windowClassW[] = { 1618 'H','H',' ', 'P','a','r','e','n','t',0 1619 }; 1620 1621 wcex.cbSize = sizeof(WNDCLASSEXW); 1622 wcex.style = CS_HREDRAW | CS_VREDRAW; 1623 wcex.lpfnWndProc = Help_WndProc; 1624 wcex.cbClsExtra = 0; 1625 wcex.cbWndExtra = sizeof(LONG_PTR); 1626 wcex.hInstance = hhctrl_hinstance; 1627 #ifdef __REACTOS__ 1628 wcex.hIcon = LoadIconW(hhctrl_hinstance, MAKEINTRESOURCEW(IDI_HHICON)); 1629 #else 1630 wcex.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 1631 #endif 1632 wcex.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); 1633 wcex.hbrBackground = (HBRUSH)(COLOR_MENU + 1); 1634 wcex.lpszMenuName = NULL; 1635 wcex.lpszClassName = windowClassW; 1636 #ifdef __REACTOS__ 1637 wcex.hIconSm = NULL; 1638 #else 1639 wcex.hIconSm = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); 1640 #endif 1641 1642 RegisterClassExW(&wcex); 1643 1644 /* Read in window parameters if available */ 1645 if (info->WinType.fsValidMembers & HHWIN_PARAM_STYLES) 1646 { 1647 dwStyles = info->WinType.dwStyles; 1648 if (!(info->WinType.dwStyles & WS_CHILD)) 1649 dwStyles |= WS_OVERLAPPEDWINDOW; 1650 } 1651 else 1652 dwStyles = WS_OVERLAPPEDWINDOW | WS_VISIBLE | 1653 WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 1654 1655 if (info->WinType.fsValidMembers & HHWIN_PARAM_EXSTYLES) 1656 dwExStyles = info->WinType.dwExStyles; 1657 else 1658 dwExStyles = WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_APPWINDOW | 1659 WS_EX_WINDOWEDGE | WS_EX_RIGHTSCROLLBAR; 1660 1661 if (info->WinType.fsValidMembers & HHWIN_PARAM_RECT) 1662 { 1663 x = winPos.left; 1664 y = winPos.top; 1665 width = winPos.right - x; 1666 height = winPos.bottom - y; 1667 } 1668 if (!width || !height) 1669 { 1670 x = WINTYPE_DEFAULT_X; 1671 y = WINTYPE_DEFAULT_Y; 1672 width = WINTYPE_DEFAULT_WIDTH; 1673 height = WINTYPE_DEFAULT_HEIGHT; 1674 } 1675 1676 if (!(info->WinType.fsWinProperties & HHWIN_PROP_TRI_PANE) && info->WinType.fNotExpanded) 1677 { 1678 if (!(info->WinType.fsValidMembers & HHWIN_PARAM_NAV_WIDTH) && 1679 info->WinType.iNavWidth == 0) 1680 { 1681 info->WinType.iNavWidth = WINTYPE_DEFAULT_NAVWIDTH; 1682 } 1683 1684 x += info->WinType.iNavWidth; 1685 width -= info->WinType.iNavWidth; 1686 } 1687 1688 1689 caption = info->WinType.pszCaption; 1690 if (!*caption) caption = info->pCHMInfo->defTitle; 1691 1692 hWnd = CreateWindowExW(dwExStyles, windowClassW, caption, dwStyles, x, y, width, height, 1693 info->WinType.hwndCaller, NULL, hhctrl_hinstance, NULL); 1694 if (!hWnd) 1695 return FALSE; 1696 1697 ShowWindow(hWnd, SW_SHOW); 1698 UpdateWindow(hWnd); 1699 1700 /* store the pointer to the HH info struct */ 1701 SetWindowLongPtrW(hWnd, 0, (LONG_PTR)info); 1702 1703 info->WinType.hwndHelp = hWnd; 1704 return TRUE; 1705 } 1706 1707 static void HH_CreateFont(HHInfo *pHHInfo) 1708 { 1709 LOGFONTW lf; 1710 1711 GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONTW), &lf); 1712 lf.lfWeight = FW_NORMAL; 1713 lf.lfItalic = FALSE; 1714 lf.lfUnderline = FALSE; 1715 1716 pHHInfo->hFont = CreateFontIndirectW(&lf); 1717 } 1718 1719 static void HH_InitRequiredControls(DWORD dwControls) 1720 { 1721 INITCOMMONCONTROLSEX icex; 1722 1723 icex.dwSize = sizeof(INITCOMMONCONTROLSEX); 1724 icex.dwICC = dwControls; 1725 InitCommonControlsEx(&icex); 1726 } 1727 1728 /* Creates the whole package */ 1729 static BOOL CreateViewer(HHInfo *pHHInfo) 1730 { 1731 HH_CreateFont(pHHInfo); 1732 1733 if (!HH_CreateHelpWindow(pHHInfo)) 1734 return FALSE; 1735 1736 HH_InitRequiredControls(ICC_BAR_CLASSES); 1737 1738 if (!HH_AddToolbar(pHHInfo)) 1739 return FALSE; 1740 1741 HH_RegisterChildWndClass(pHHInfo); 1742 1743 if (!HH_AddNavigationPane(pHHInfo)) 1744 return FALSE; 1745 1746 HH_RegisterSizeBarClass(pHHInfo); 1747 1748 if (!HH_AddSizeBar(pHHInfo)) 1749 return FALSE; 1750 1751 if (!HH_AddHTMLPane(pHHInfo)) 1752 return FALSE; 1753 1754 if (!AddContentTab(pHHInfo)) 1755 return FALSE; 1756 1757 if (!AddIndexTab(pHHInfo)) 1758 return FALSE; 1759 1760 if (!AddIndexPopup(pHHInfo)) 1761 return FALSE; 1762 1763 if (!AddSearchTab(pHHInfo)) 1764 return FALSE; 1765 1766 InitContent(pHHInfo); 1767 InitIndex(pHHInfo); 1768 1769 pHHInfo->viewer_initialized = TRUE; 1770 return TRUE; 1771 } 1772 1773 void wintype_stringsW_free(struct wintype_stringsW *stringsW) 1774 { 1775 heap_free(stringsW->pszType); 1776 heap_free(stringsW->pszCaption); 1777 heap_free(stringsW->pszToc); 1778 heap_free(stringsW->pszIndex); 1779 heap_free(stringsW->pszFile); 1780 heap_free(stringsW->pszHome); 1781 heap_free(stringsW->pszJump1); 1782 heap_free(stringsW->pszJump2); 1783 heap_free(stringsW->pszUrlJump1); 1784 heap_free(stringsW->pszUrlJump2); 1785 } 1786 1787 void wintype_stringsA_free(struct wintype_stringsA *stringsA) 1788 { 1789 heap_free(stringsA->pszType); 1790 heap_free(stringsA->pszCaption); 1791 heap_free(stringsA->pszToc); 1792 heap_free(stringsA->pszIndex); 1793 heap_free(stringsA->pszFile); 1794 heap_free(stringsA->pszHome); 1795 heap_free(stringsA->pszJump1); 1796 heap_free(stringsA->pszJump2); 1797 heap_free(stringsA->pszUrlJump1); 1798 heap_free(stringsA->pszUrlJump2); 1799 heap_free(stringsA->pszCustomTabs); 1800 } 1801 1802 void ReleaseHelpViewer(HHInfo *info) 1803 { 1804 TRACE("(%p)\n", info); 1805 1806 if (!info) 1807 return; 1808 1809 list_remove(&info->entry); 1810 1811 wintype_stringsA_free(&info->stringsA); 1812 wintype_stringsW_free(&info->stringsW); 1813 1814 if (info->pCHMInfo) 1815 CloseCHM(info->pCHMInfo); 1816 1817 ReleaseWebBrowser(info); 1818 ReleaseContent(info); 1819 ReleaseIndex(info); 1820 ReleaseSearch(info); 1821 1822 if(info->contents.hImageList) 1823 ImageList_Destroy(info->contents.hImageList); 1824 if(info->WinType.hwndHelp) 1825 DestroyWindow(info->WinType.hwndHelp); 1826 1827 heap_free(info); 1828 OleUninitialize(); 1829 } 1830 1831 HHInfo *CreateHelpViewer(HHInfo *info, LPCWSTR filename, HWND caller) 1832 { 1833 HHInfo *tmp_info; 1834 unsigned int i; 1835 1836 if(!info) 1837 { 1838 info = heap_alloc_zero(sizeof(HHInfo)); 1839 list_add_tail(&window_list, &info->entry); 1840 } 1841 1842 /* Set the invalid tab ID (-1) as the default value for all 1843 * of the tabs, this matches a failed TCM_INSERTITEM call. 1844 */ 1845 for (i = 0; i < ARRAY_SIZE(info->tabs); i++) 1846 info->tabs[i].id = -1; 1847 1848 OleInitialize(NULL); 1849 1850 info->pCHMInfo = OpenCHM(filename); 1851 if(!info->pCHMInfo) { 1852 ReleaseHelpViewer(info); 1853 return NULL; 1854 } 1855 1856 if (!LoadWinTypeFromCHM(info)) { 1857 ReleaseHelpViewer(info); 1858 return NULL; 1859 } 1860 info->WinType.hwndCaller = caller; 1861 1862 /* If the window is already open then load the file in that existing window */ 1863 if ((tmp_info = find_window(info->WinType.pszType)) && tmp_info != info) 1864 { 1865 ReleaseHelpViewer(info); 1866 return CreateHelpViewer(tmp_info, filename, caller); 1867 } 1868 1869 if(!info->viewer_initialized && !CreateViewer(info)) { 1870 ReleaseHelpViewer(info); 1871 return NULL; 1872 } 1873 1874 return info; 1875 } 1876 1877 /* 1878 * Search the table of HTML entities and return the corresponding ANSI symbol. 1879 */ 1880 static char find_html_symbol(const char *entity, int entity_len) 1881 { 1882 int max = ARRAY_SIZE(html_encoded_symbols)-1; 1883 int min = 0, dir; 1884 1885 while(min <= max) 1886 { 1887 int pos = (min+max)/2; 1888 const char *encoded_symbol = html_encoded_symbols[pos].html_code; 1889 dir = strncmp(encoded_symbol, entity, entity_len); 1890 if(dir == 0 && !encoded_symbol[entity_len]) return html_encoded_symbols[pos].ansi_symbol; 1891 if(dir < 0) 1892 min = pos+1; 1893 else 1894 max = pos-1; 1895 } 1896 return 0; 1897 } 1898 1899 /* 1900 * Decode a string containing HTML encoded characters into a unicode string. 1901 */ 1902 WCHAR *decode_html(const char *html_fragment, int html_fragment_len, UINT code_page) 1903 { 1904 const char *h = html_fragment, *amp, *sem; 1905 char symbol, *tmp; 1906 int len, tmp_len = 0; 1907 WCHAR *unicode_text; 1908 1909 tmp = heap_alloc(html_fragment_len+1); 1910 while(1) 1911 { 1912 symbol = 0; 1913 amp = strchr(h, '&'); 1914 if(!amp) break; 1915 len = amp-h; 1916 /* Copy the characters prior to the HTML encoded character */ 1917 memcpy(&tmp[tmp_len], h, len); 1918 tmp_len += len; 1919 amp++; /* skip ampersand */ 1920 sem = strchr(amp, ';'); 1921 /* Require a semicolon after the ampersand */ 1922 if(!sem) 1923 { 1924 h = amp; 1925 tmp[tmp_len++] = '&'; 1926 continue; 1927 } 1928 /* Find the symbol either by using the ANSI character number (prefixed by the pound symbol) 1929 * or by searching the HTML entity table */ 1930 len = sem-amp; 1931 if(amp[0] == '#') 1932 { 1933 char *endnum = NULL; 1934 int tmp; 1935 1936 tmp = (char) strtol(amp, &endnum, 10); 1937 if(endnum == sem) 1938 symbol = tmp; 1939 } 1940 else 1941 symbol = find_html_symbol(amp, len); 1942 if(!symbol) 1943 { 1944 FIXME("Failed to translate HTML encoded character '&%.*s;'.\n", len, amp); 1945 h = amp; 1946 tmp[tmp_len++] = '&'; 1947 continue; 1948 } 1949 /* Insert the new symbol */ 1950 h = sem+1; 1951 tmp[tmp_len++] = symbol; 1952 } 1953 /* Convert any remaining characters */ 1954 len = html_fragment_len-(h-html_fragment); 1955 memcpy(&tmp[tmp_len], h, len); 1956 tmp_len += len; 1957 tmp[tmp_len++] = 0; /* NULL-terminate the string */ 1958 1959 len = MultiByteToWideChar(code_page, 0, tmp, tmp_len, NULL, 0); 1960 unicode_text = heap_alloc(len*sizeof(WCHAR)); 1961 MultiByteToWideChar(code_page, 0, tmp, tmp_len, unicode_text, len); 1962 heap_free(tmp); 1963 return unicode_text; 1964 } 1965 1966 /* Find the HTMLHelp structure for an existing window title */ 1967 HHInfo *find_window(const WCHAR *window) 1968 { 1969 HHInfo *info; 1970 1971 LIST_FOR_EACH_ENTRY(info, &window_list, HHInfo, entry) 1972 { 1973 if (lstrcmpW(info->WinType.pszType, window) == 0) 1974 return info; 1975 } 1976 return NULL; 1977 } 1978