Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

807 lines
26 KiB

  1. // Copyright (C) Microsoft Corporation 1996-1997, All Rights reserved.
  2. #include "header.h"
  3. #ifdef _DEBUG
  4. #undef THIS_FILE
  5. static const char THIS_FILE[] = __FILE__;
  6. #endif
  7. #include <commctrl.h>
  8. #include "strtable.h"
  9. #include "hha_strtable.h"
  10. #include "contain.h"
  11. #include "resource.h"
  12. #include "secwin.h"
  13. #include "state.h"
  14. #include "highlite.h"
  15. // CSizebar class for registration.
  16. #include "sizebar.h"
  17. // Custom NavPane for registration
  18. #include "custmtab.h"
  19. #include "unicode.h"
  20. #define COMPILE_MULTIMON_STUBS
  21. #include "multimon.h"
  22. #define DEFAULT_WINDOW_WIDTH 300
  23. static const char txtNavWind[] = ">navwin";
  24. #define WS_EX_LAYOUTRTL 0x00400000L // Right to left mirroring
  25. // Forward Reference
  26. void GetMonitorRect(HWND hwnd, LPRECT prc, BOOL fWork) ;
  27. void multiMonitorRectFromRect(/*in*/ RECT rcScreenCoords, /*out*/ LPRECT prc, /*in*/ BOOL fWork) ;
  28. void multiMonitorRectFromPoint(/*in*/ POINT ptScreenCoords, /*out*/ LPRECT prc, /*in*/ BOOL fWork) ;
  29. /***************************************************************************
  30. FUNCTION: CreateHelpWindow
  31. PURPOSE: Create a help window
  32. PARAMETERS:
  33. pszType -- (optional) specifies a window type to create. Type must
  34. have been specified previously
  35. hwndCaller -- this will be the parent of the window
  36. RETURNS: HWND on success, NULL on failure
  37. COMMENTS:
  38. Reallocates pahwnd if more slots are necessary.
  39. MODIFICATION DATES:
  40. 26-Feb-1996 [ralphw]
  41. ***************************************************************************/
  42. CHHWinType* CreateHelpWindow(PCSTR pszType, LPCTSTR pszFile, HWND hwndCaller, CHmData* phmData)
  43. {
  44. static BOOL fRegistered = FALSE;
  45. ASSERT(pahwnd != NULL);
  46. // Generate a default window type, if a name isn't given.
  47. char szName[20];
  48. const char* pType = pszType ;
  49. if (IsEmptyString(pszType))
  50. {
  51. static int iWindowNum = 1;
  52. // If the caller didn't specify a window type, then create a name
  53. // based off the current window number.
  54. wsprintf(szName, "win%u", iWindowNum++);
  55. pType = szName ;
  56. }
  57. // When we create a Window slot, we need the filename. However, if we are looking up a URL
  58. // we might not have a filename. So, pass NULL. This is a HOLE.
  59. CHHWinType* phh = FindOrCreateWindowSlot(pType, pszFile ? pszFile
  60. : phmData ? phmData->GetCompiledFile()
  61. : NULL);
  62. if (! phh )
  63. return NULL;
  64. phh->m_phmData = phmData;
  65. if (phmData)
  66. {
  67. // Count references
  68. phmData->AddRef();
  69. //--- Get the windows state.
  70. WINDOW_STATE wstate;
  71. ZERO_STRUCTURE(wstate);
  72. CState* pstate = phmData->m_pTitleCollection->GetState();
  73. if (SUCCEEDED(pstate->Open(pType, STGM_READ)))
  74. {
  75. DWORD cbRead;
  76. pstate->Read(&wstate.cbStruct, sizeof(int), &cbRead);
  77. //
  78. // This looks funky until you understand that CState only supports atomic reads and writes from the beginning
  79. // of the stream. i.e. It does not maintain a file position pointer. <mc>
  80. //
  81. if ( wstate.cbStruct )
  82. pstate->Read(&wstate, wstate.cbStruct, &cbRead);
  83. pstate->Close();
  84. }
  85. if (wstate.cbStruct)
  86. {
  87. if (IsRectEmpty(phh->GetWinRect()) || phh->IsProperty(HHWIN_PROP_USER_POS))
  88. {
  89. phh->fNotExpanded = wstate.fNotExpanded;
  90. CopyRect(&phh->rcWindowPos, &wstate.rcPos);
  91. phh->iNavWidth = wstate.iNavWidth;
  92. phh->rcNav.left = 0;
  93. phh->rcNav.right = wstate.iNavWidth;
  94. }
  95. if (phh->m_phmData->m_pTitleCollection->m_pSearchHighlight)
  96. phh->m_phmData->m_pTitleCollection->m_pSearchHighlight->EnableHighlight(wstate.fHighlight);
  97. phh->m_fLockSize = wstate.fLockSize;
  98. phh->m_fNoToolBarText = wstate.fNoToolBarText;
  99. phh->curNavType = wstate.curNavType;
  100. }
  101. }
  102. if (phh->idNotify) {
  103. HHN_NOTIFY hhcomp;
  104. hhcomp.hdr.hwndFrom = NULL;
  105. hhcomp.hdr.idFrom = phh->idNotify;
  106. hhcomp.hdr.code = HHN_WINDOW_CREATE;
  107. hhcomp.pszUrl = pType;
  108. if (IsWindow(hwndCaller))
  109. {
  110. SendMessage(hwndCaller, WM_NOTIFY, phh->idNotify, (LPARAM) &hhcomp);
  111. }
  112. }
  113. // If this window type hasn't been defined, do so now
  114. if (!phh->GetTypeName())
  115. {
  116. phh->SetTypeName(pType);
  117. phh->SetDisplayState(SW_SHOW);
  118. }
  119. if (!fRegistered) {
  120. RegisterOurWindow();
  121. fRegistered = TRUE;
  122. }
  123. phh->hwndCaller = hwndCaller;
  124. if (IsRectEmpty(phh->GetWinRect()))
  125. {
  126. // Create a default window relative to the display size
  127. RECT rcScreen ;
  128. GetScreenResolution(hwndCaller, &rcScreen);
  129. phh->SetTop(rcScreen.top + 10);
  130. phh->SetBottom(phh->GetTop() + 450);
  131. if (phh->IsExpandedNavPane() && !phh->iNavWidth)
  132. phh->iNavWidth = DEFAULT_NAV_WIDTH;
  133. // If navwidth specified, balance navigation pane width and HTML pane width
  134. phh->SetLeft(rcScreen.right - DEFAULT_WINDOW_WIDTH - 5 -
  135. (phh->IsProperty(HHWIN_PROP_TRI_PANE) ? phh->iNavWidth : 0));
  136. phh->SetRight(phh->GetLeft() + DEFAULT_WINDOW_WIDTH +
  137. (phh->IsProperty(HHWIN_PROP_TRI_PANE) ? phh->iNavWidth : 0));
  138. }
  139. if (!(phh->dwStyles & WS_CHILD))
  140. CheckWindowPosition(phh->GetWinRect(), TRUE); // Multimon support
  141. /*
  142. * The help author has the option of adding their own extended and
  143. * standard window styles. In addition, they can shut off all the
  144. * extended and normal styles that we would normally use, and just
  145. * use their own styles. In addition, they can specify all the
  146. * standard styles, but with no title bar.
  147. */
  148. phh->hwndHelp =
  149. CreateWindowEx(
  150. phh->GetExStyles() | (phh->IsProperty(HHWIN_PROP_NODEF_EXSTYLES) ?
  151. 0 : WS_EX_APPWINDOW | ((phh->IsProperty(HHWIN_PROP_ONTOP) ?
  152. WS_EX_TOPMOST : 0))),
  153. txtHtmlHelpWindowClass, NULL,
  154. phh->GetStyles() | WS_CLIPCHILDREN,
  155. phh->GetLeft(), phh->GetTop(), phh->GetWidth(), phh->GetHeight(),
  156. hwndCaller, NULL,
  157. // REVIEW: Should we use the caller's hinstance instead?
  158. _Module.GetModuleInstance(), NULL);
  159. #ifdef _DEBUG
  160. ULONG err = GetLastError() ;
  161. #endif
  162. if (!IsValidWindow(*phh)) {
  163. OOM(); // BUGBUG: bogus error message if hwndCaller is NULL
  164. return NULL;
  165. }
  166. // This next section of code turns of the Win98/Win2K WS_EX_LAYOUTRTL (mirroring)
  167. // style in the event it is turned on (inherited from the parent window).
  168. //
  169. // Get the extended window styles
  170. //
  171. long lExStyles = GetWindowLongA(phh->hwndHelp, GWL_EXSTYLE);
  172. // Check if mirroring is turned on
  173. //
  174. if(lExStyles & WS_EX_LAYOUTRTL)
  175. {
  176. // turn off the mirroring bit
  177. //
  178. lExStyles ^= WS_EX_LAYOUTRTL;
  179. SetWindowLongA(phh->hwndHelp, GWL_EXSTYLE, lExStyles) ;
  180. // This is to update layout in the client area
  181. // InvalidateRect(hWnd, NULL, TRUE) ;
  182. }
  183. SendMessage(phh->hwndHelp, WM_SETFONT, (WPARAM)_Resource.GetAccessableUIFont(), 0);
  184. HMENU hmenu = GetSystemMenu(*phh, FALSE);
  185. AppendMenu(hmenu, MF_SEPARATOR, (UINT) -1, NULL);
  186. // before adding the jump runl to the system menu check if NoRun is set for this system Bug 7819
  187. if (NoRun() == FALSE)
  188. HxAppendMenu(hmenu, MF_STRING, ID_JUMP_URL, GetStringResource(IDS_JUMP_URL));
  189. if (IsHelpAuthor(hwndCaller)) {
  190. #if 0 // bug 5449
  191. PCSTR psz = pGetDllStringResource(IDS_WINDOW_INFO);
  192. if (!IsEmptyString(psz))
  193. HxAppendMenu(hmenu, MF_ENABLED | MF_STRING, IDM_WINDOW_INFO,
  194. pGetDllStringResource(IDS_WINDOW_INFO));
  195. #endif
  196. HxAppendMenu(hmenu, MF_ENABLED | MF_STRING, IDM_VERSION,
  197. pGetDllStringResource(IDS_HHCTRL_VERSION));
  198. }
  199. else
  200. HxAppendMenu(hmenu, MF_ENABLED | MF_STRING, IDM_VERSION, GetStringResource(IDS_ABOUT));
  201. #ifdef _DEBUG
  202. HxAppendMenu(hmenu, MF_STRING, ID_VIEW_MEMORY, "Debug: memory usage...");
  203. HxAppendMenu(hmenu, MF_STRING, ID_DEBUG_BREAK, "Debug: call DebugBreak()");
  204. #endif
  205. // Load MSDN's Menu.
  206. if (phh->IsProperty(HHWIN_PROP_MENU))
  207. {
  208. HMENU hMenu = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(HH_MENU)) ;
  209. ASSERT(hMenu) ;
  210. BOOL b = SetMenu(phh->hwndHelp, hMenu) ;
  211. ASSERT(b) ;
  212. }
  213. if (phh->IsProperty(HHWIN_PROP_TRI_PANE) ||
  214. phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) {
  215. if (phh->IsProperty(HHWIN_PROP_NOTB_TEXT))
  216. phh->m_fNoToolBarText = TRUE;
  217. if (!phh->IsProperty(HHWIN_PROP_NO_TOOLBAR))
  218. {
  219. TBBUTTON abtn[MAX_TB_BUTTONS];
  220. ClearMemory(abtn, sizeof(abtn));
  221. int cButtons = 0 ;
  222. cButtons = phh->CreateToolBar(abtn);
  223. if ( cButtons <= 0)
  224. {
  225. // No Toolbar buttons. Turn off this bit.
  226. phh->fsWinProperties &= ~HHWIN_PROP_NO_TOOLBAR ;
  227. }
  228. else
  229. {
  230. phh->hwndToolBar = CreateWindow("ToolbarWindow32", NULL, WS_CHILD | TBSTYLE_FLAT |
  231. TBSTYLE_TOOLTIPS | TBSTYLE_EX_DRAWDDARROWS | CCS_NORESIZE |
  232. CCS_NOPARENTALIGN | TBSTYLE_WRAPABLE |
  233. (phh->IsProperty(HHWIN_PROP_MENU) ? 0 : CCS_NODIVIDER) |
  234. (phh->m_fNoToolBarText ? 0 : TBSTYLE_WRAPABLE),
  235. 0, 0, 100, 30, *phh, (HMENU)ID_TOOLBAR,
  236. _Module.GetModuleInstance(), NULL);
  237. if (! phh->hwndToolBar )
  238. return NULL;
  239. SendMessage(phh->hwndToolBar, TB_SETBITMAPSIZE, 0, (LPARAM)MAKELONG(TB_BMP_CX,TB_BMP_CY));
  240. SendMessage(phh->hwndToolBar, TB_SETBITMAPSIZE, 0, (LPARAM)MAKELONG(TB_BTN_CX,TB_BTN_CY));
  241. SendMessage(phh->hwndToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), (LPARAM)0);
  242. SendMessage(phh->hwndToolBar, TB_ADDBUTTONS, cButtons, (LPARAM)abtn);
  243. SendMessage(phh->hwndToolBar, WM_SETFONT, (WPARAM)_Resource.GetAccessableUIFont(), 0);
  244. phh->m_hImageListGray = ImageList_LoadImage(_Module.GetResourceInstance(),
  245. MAKEINTRESOURCE(IDB_TOOLBAR16G),
  246. TB_BMP_CX, 0, RGB(255,0,255), IMAGE_BITMAP, 0);
  247. SendMessage(phh->hwndToolBar, TB_SETIMAGELIST, 0, (LPARAM)(HIMAGELIST) phh->m_hImageListGray);
  248. phh->m_hImageList = ImageList_LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_TOOLBAR16),
  249. TB_BMP_CX, 0, RGB(255,0,255), IMAGE_BITMAP, 0);
  250. SendMessage(phh->hwndToolBar, TB_SETHOTIMAGELIST, 0, (LPARAM)(HIMAGELIST) phh->m_hImageList);
  251. if (!phh->m_fNoToolBarText)
  252. {
  253. for (int pos = 1; pos <= phh->m_ptblBtnStrings->CountStrings(); pos++)
  254. {
  255. char szBuf[256];
  256. strcpy(szBuf, phh->m_ptblBtnStrings->GetPointer(pos));
  257. szBuf[strlen(szBuf) + 1] = '\0'; // two terminating NULLs
  258. // Under W2K, send wide string to control (support for MUI)
  259. //
  260. if(g_bWinNT5)
  261. {
  262. WCHAR wszBuf[256];
  263. memset(wszBuf,0,sizeof(wszBuf));
  264. // get codepage of default UI
  265. //
  266. DWORD cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT));
  267. MultiByteToWideChar(cp , 0, szBuf, -1, wszBuf, sizeof(wszBuf) / 2);
  268. SendMessageW(phh->hwndToolBar, TB_ADDSTRINGW, 0, (LPARAM) wszBuf);
  269. }
  270. else
  271. SendMessage(phh->hwndToolBar, TB_ADDSTRING, 0, (LPARAM) szBuf);
  272. }
  273. TCHAR szScratch[MAX_PATH];
  274. LoadString(_Module.GetResourceInstance(), IDS_WEB_TB_TEXTROWS, szScratch, sizeof(szScratch));
  275. int nRows = Atoi(szScratch);
  276. SendMessage(phh->hwndToolBar, TB_SETMAXTEXTROWS, nRows, 0);
  277. /*
  278. * Since we changed the window after we created it, we need to
  279. * force a recalculation which we do by changing the size of the
  280. * window ever so slightly. This causes the toolbar to
  281. * recalculate itself to be the exact size.
  282. */
  283. phh->WrapTB();
  284. }
  285. }
  286. }
  287. phh->CalcHtmlPaneRect();
  288. if (phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) {
  289. phh->CreateOrShowNavPane();
  290. ShowWindow(*phh, phh->GetShowState());
  291. }
  292. else
  293. phh->CreateOrShowHTMLPane();
  294. }
  295. if (IsValidWindow(*phh) ) {
  296. if (!phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN))
  297. {
  298. phh->m_pCIExpContainer = new CContainer;
  299. HRESULT hr;
  300. BOOL bInstallEventSink = (BOOL)strcmp(phh->pszType, txtPrintWindow+1);
  301. if (IsValidWindow(phh->hwndHTML)) {
  302. hr = phh->m_pCIExpContainer->Create(phh->hwndHTML, &phh->rcHTML, bInstallEventSink);
  303. }
  304. else {
  305. RECT rc;
  306. phh->GetClientRect(&rc);
  307. hr = phh->m_pCIExpContainer->Create(*phh, &rc, bInstallEventSink);
  308. }
  309. if (!SUCCEEDED(hr)) {
  310. DEBUG_ReportOleError(hr);
  311. DestroyWindow(*phh);
  312. return NULL;
  313. }
  314. }
  315. if (phh->IsExpandedNavPane() && phh->AnyValidNavPane()) {
  316. phh->fNotExpanded = TRUE;
  317. BOOL fSaveLoack = phh->m_fLockSize;
  318. phh->m_fLockSize = TRUE;
  319. phh->ToggleExpansion(false);
  320. phh->m_fLockSize = fSaveLoack;
  321. }
  322. /*
  323. * 30-Sep-1996 [ralphw] For some reason, specifying the caption
  324. * when the window is created, doesn't work. So, we use
  325. * SetWindowText to specify the caption.
  326. */
  327. // Set the window title (figure out which string is displayable)
  328. //
  329. // Rules:
  330. //
  331. // if (TitleLanguage = DefaultSystemLocale)
  332. // Display title string from CHM
  333. //
  334. // else
  335. //
  336. // if(Satellite DLL language == DefaultSystemLocale)
  337. // Display default title from Satellite DLL
  338. //
  339. // else
  340. // Display "HTML Help"
  341. //
  342. LANGID langidTitle = 0xFEFE;
  343. LANGID langidSystem = LANGIDFROMLCID(GetSystemDefaultLCID());
  344. LANGID langidUI = _Module.m_Language.GetUiLanguage();
  345. if(phh->m_phmData && phh->m_phmData->GetInfo())
  346. langidTitle = LANGIDFROMLCID((phh->m_phmData->GetInfo())->GetLanguage());
  347. if(langidTitle == langidSystem || PRIMARYLANGID(langidTitle) == LANG_ENGLISH )
  348. {
  349. if (phh->GetCaption())
  350. SetWindowText(*phh, phh->GetCaption());
  351. else
  352. if (phh->m_phmData && phh->m_phmData->GetDefaultCaption())
  353. SetWindowText(*phh, phh->m_phmData->GetDefaultCaption());
  354. else
  355. SetWindowText(*phh, "HTML Help");
  356. }
  357. else
  358. {
  359. if(langidUI == langidSystem)
  360. {
  361. CStr cszDefaultCaption = GetStringResource(IDS_HTML_HELP);
  362. SetWindowText(*phh, cszDefaultCaption);
  363. }
  364. else
  365. SetWindowText(*phh, "HTML Help");
  366. }
  367. ShowWindow(*phh, phh->GetShowState());
  368. if (IsValidWindow(phh->hwndToolBar))
  369. ShowWindow(phh->hwndToolBar, phh->GetShowState());
  370. if (IsValidWindow(phh->hwndHTML))
  371. ShowWindow(phh->hwndHTML, phh->GetShowState());
  372. if (phh->IsExpandedNavPane() && IsValidWindow(phh->hwndNavigation))
  373. ShowWindow(phh->hwndNavigation, phh->GetShowState());
  374. if ( phh->IsProperty(HHWIN_PROP_MENU) && phmData && phmData->m_sysflags.fDoSS )
  375. {
  376. HMENU hMenuMain, hMenuSub;
  377. hMenuMain = GetMenu(phh->hwndHelp);
  378. hMenuSub = GetSubMenu(hMenuMain, 2);
  379. AppendMenu(hMenuSub, MF_SEPARATOR, 0, NULL);
  380. HxAppendMenu(hMenuSub, MF_STRING, HHM_DEFINE_SUBSET, GetStringResource(IDS_DEFINE_SUBSET));
  381. }
  382. #ifdef _DEBUG
  383. if (phh->IsProperty(HHWIN_PROP_TRI_PANE) && phh->IsProperty(HHWIN_PROP_TAB_HISTORY))
  384. phh->CreateHistoryTab(); // start tracking history immediately
  385. #endif
  386. #if 0
  387. 27-Sep-1996 [ralphw] Never returns the window...
  388. HWND hwndIE = (HWND) phh->m_pCIExpContainer->m_pWebBrowserApp->GetHwnd();
  389. if (IsValidWindow(hwndIE)) {
  390. char szClass[256];
  391. GetClassName(hwndIE, szClass, sizeof(szClass));
  392. DWORD dwStyle = GetWindowLong(hwndIE, GWL_STYLE);
  393. DWORD dwexStyle = GetWindowLong(hwndIE, GWL_EXSTYLE);
  394. }
  395. #endif
  396. }
  397. return phh;
  398. }
  399. /***************************************************************************
  400. FUNCTION: CheckWindowPosition
  401. PURPOSE: Make certain the window doesn't cover any portion of the tray,
  402. and that it has a certain minimum size.
  403. PARAMETERS:
  404. prc
  405. fAllowShrinkage
  406. RETURNS:
  407. COMMENTS:
  408. MODIFICATION DATES:
  409. 25-Feb-1996 [ralphw]
  410. ***************************************************************************/
  411. // REVIEW: 25-Feb-1996 [ralphw] WinHelp did this, and set it to 200. I
  412. // dropped it down to 16 -- enough to see the window, but without forcing
  413. // it quite so large.
  414. const int HELP_WIDTH_MINIMUM = 16;
  415. const int HELP_HEIGHT_MINIMUM = 16;
  416. void CheckWindowPosition(RECT* prc, BOOL fAllowShrinkage)
  417. {
  418. GetWorkArea(); // Multimon support
  419. // Make certain we don't go off the edge of the screen
  420. if (prc->left < g_rcWorkArea.left) {
  421. int diff = g_rcWorkArea.left - prc->left;
  422. prc->left = g_rcWorkArea.left;
  423. prc->right += diff;
  424. }
  425. if (prc->top < g_rcWorkArea.top) {
  426. int diff = g_rcWorkArea.top - prc->top;
  427. prc->top = g_rcWorkArea.top;
  428. prc->bottom += diff;
  429. }
  430. /*
  431. * If the right side of the window is off the work area, move the
  432. * window to the left. If we don't have enough room for the window when
  433. * moved all the way to the left, then shrink the window (won't work for
  434. * dialogs).
  435. */
  436. if (prc->right > g_rcWorkArea.right) {
  437. int diff = prc->right - g_rcWorkArea.right;
  438. if (diff < prc->left) {
  439. prc->left -= diff;
  440. prc->right = g_rcWorkArea.right;
  441. }
  442. else if (fAllowShrinkage) {
  443. diff -= prc->left;
  444. prc->left = g_rcWorkArea.left;
  445. prc->right -= diff;
  446. }
  447. else {// Can't shrink, so shove to the left side
  448. prc->left = g_rcWorkArea.left;
  449. }
  450. }
  451. // Same question about the bottom of the window being off the work area
  452. if (prc->bottom > g_rcWorkArea.bottom) {
  453. int diff = prc->bottom > g_rcWorkArea.bottom;
  454. if (diff < prc->top) {
  455. prc->top -= diff;
  456. prc->bottom = g_rcWorkArea.bottom;
  457. }
  458. else if (fAllowShrinkage) {
  459. diff -= prc->top;
  460. prc->top = g_rcWorkArea.top;
  461. prc->bottom -= diff;
  462. }
  463. else // Can't shrink, so shove to the top
  464. prc->top = g_rcWorkArea.top;
  465. }
  466. // Force minimum window size
  467. if (RECT_WIDTH(prc) < HELP_WIDTH_MINIMUM) {
  468. prc->right = prc->left + HELP_WIDTH_MINIMUM;
  469. // Width is now correct, but we could be off the work area. Start over
  470. CheckWindowPosition(prc, fAllowShrinkage);
  471. }
  472. if (RECT_HEIGHT(prc) < HELP_HEIGHT_MINIMUM) {
  473. prc->bottom = prc->top + HELP_HEIGHT_MINIMUM;
  474. // Height is now correct, but we could be off the work area. Start over
  475. CheckWindowPosition(prc, fAllowShrinkage);
  476. }
  477. }
  478. void GetScreenResolution(HWND hWnd, RECT* prc /*out*/)
  479. {
  480. ASSERT(prc) ;
  481. if (prc)
  482. {
  483. if (IsWindow(hWnd) )
  484. {
  485. // Use the hWnd to get the monitor.
  486. GetMonitorRect(hWnd, prc, TRUE /*Get Work Area*/) ;
  487. }
  488. else
  489. {
  490. // hWnd isn't valid, use default monitor.
  491. POINT pt;
  492. pt.x=pt.y=0;
  493. multiMonitorRectFromPoint(pt, prc, TRUE) ;
  494. }
  495. }
  496. }
  497. void GetWorkArea()
  498. {
  499. // Get the size of the entire virtual screen.
  500. if (!g_cxScreen)
  501. {
  502. g_cxScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN) ;
  503. g_cyScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN) ;
  504. }
  505. // The tray must be handled externally.
  506. if (IsRectEmpty(&g_rcWorkArea))
  507. {
  508. g_rcWorkArea.left = GetSystemMetrics(SM_XVIRTUALSCREEN) ;
  509. g_rcWorkArea.right = g_rcWorkArea.left + g_cxScreen ;
  510. g_rcWorkArea.top = GetSystemMetrics(SM_YVIRTUALSCREEN) ;
  511. g_rcWorkArea.bottom = g_rcWorkArea.top + g_cyScreen ;
  512. }
  513. }
  514. void RegisterOurWindow()
  515. {
  516. WNDCLASS wc;
  517. ZeroMemory(&wc, sizeof(WNDCLASS)); // clear all members
  518. wc.lpfnWndProc = HelpWndProc;
  519. wc.hInstance = _Module.GetModuleInstance();
  520. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  521. wc.lpszClassName = txtHtmlHelpWindowClass;
  522. wc.hIcon = LoadIcon(_Module.GetResourceInstance(), "Icon!HTMLHelp");
  523. wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
  524. VERIFY(RegisterClass(&wc));
  525. ASSERT(sizeof(WNDCLASSA)==sizeof(WNDCLASSW)); //lazy hack - just use the wcA
  526. wc.lpfnWndProc = ChildWndProc;
  527. wc.lpszClassName = (LPCSTR)L"HH Child"; //txtHtmlHelpChildWindowClass;
  528. wc.hbrBackground = (HBRUSH) COLOR_BTNSHADOW;
  529. if (NULL == RegisterClassW((CONST WNDCLASSW *)&wc))
  530. {
  531. if (ERROR_CALL_NOT_IMPLEMENTED == GetLastError())
  532. {
  533. wc.lpszClassName = txtHtmlHelpChildWindowClass;
  534. VERIFY(RegisterClass(&wc));
  535. }
  536. }
  537. // Register the window class for the sizebar.
  538. CSizeBar::RegisterWindowClass() ;
  539. // Register the window class for the custom nav pane frame window.
  540. CCustomNavPane::RegisterWindowClass() ;
  541. }
  542. CHHWinType* FindHHWindowIndex(HWND hwnd)
  543. {
  544. static int iLastWindow = 0;
  545. static HWND hwndLastWindow = NULL;
  546. if (pahwnd && hwndLastWindow == hwnd && IsValidWindow(hwnd))
  547. return pahwnd[iLastWindow];
  548. hwndLastWindow = hwnd;
  549. while(IsValidWindow(hwnd)) {
  550. char szClassName[50];
  551. GetClassName(hwnd, szClassName, sizeof(szClassName));
  552. if (strcmp(szClassName, txtHtmlHelpWindowClass) == 0)
  553. break;
  554. hwnd = GetParent(hwnd);
  555. }
  556. if (pahwnd && pahwnd[iLastWindow] && pahwnd[iLastWindow]->hwndHelp == hwnd)
  557. return pahwnd[iLastWindow];
  558. for (iLastWindow = 0; iLastWindow < g_cWindowSlots; iLastWindow++) {
  559. if (pahwnd && pahwnd[iLastWindow] && pahwnd[iLastWindow]->hwndHelp == hwnd)
  560. return pahwnd[iLastWindow];
  561. }
  562. iLastWindow = 0;
  563. hwndLastWindow = NULL;
  564. return NULL;
  565. }
  566. void doHHWindowJump(PCSTR pszUrl, HWND hwndChild)
  567. {
  568. CHHWinType* phh = FindHHWindowIndex(hwndChild);
  569. if( !phh )
  570. return;
  571. if (phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) {
  572. CStr cszUrl(pszUrl);
  573. cszUrl += txtNavWind;
  574. OnDisplayTopic(*phh, cszUrl, 0);
  575. return;
  576. }
  577. ASSERT(phh->m_pCIExpContainer);
  578. if (phh && phh->m_pCIExpContainer)
  579. {
  580. phh->m_pCIExpContainer->m_pWebBrowserApp->Navigate(pszUrl, NULL, NULL, NULL, NULL);
  581. }
  582. }
  583. ///////////////////////////////////////////////////////////////////////////////
  584. //
  585. // GetMonitorRect
  586. //
  587. // gets the "screen" or work area of the monitor that the passed
  588. // window is on. this is used for apps that want to clip or
  589. // center windows.
  590. //
  591. // the most common problem apps have with multimonitor systems is
  592. // when they use GetSystemMetrics(SM_C?SCREEN) to center or clip a
  593. // window to keep it on screen. If you do this on a multimonitor
  594. // system the window we be restricted to the primary monitor.
  595. //
  596. // this is a example of how you used the new Win32 multimonitor APIs
  597. // to do the same thing.
  598. //
  599. void GetMonitorRect(HWND hwnd, LPRECT prc, BOOL fWork)
  600. {
  601. // Preconditions
  602. ASSERT(hwnd != NULL) ;
  603. ASSERT(::IsWindow(hwnd)) ;
  604. // Core
  605. MONITORINFO mi;
  606. mi.cbSize = sizeof(mi);
  607. GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi);
  608. if (fWork)
  609. *prc = mi.rcWork;
  610. else
  611. *prc = mi.rcMonitor;
  612. }
  613. ///////////////////////////////////////////////////////////////////////////////
  614. //
  615. // Get the rectangle of the monitor containing the rectangle.
  616. //
  617. void multiMonitorRectFromRect(/*in*/ RECT rcScreenCoords,
  618. /*out*/ LPRECT prc,
  619. /*in*/ BOOL fWork)
  620. {
  621. //Preconditions
  622. ASSERT(prc != NULL) ;
  623. // ASSERT(AfxIsValidAddress(prc, sizeof(RECT))) ;
  624. // Get monitor which contains this rectangle.
  625. HMONITOR hMonitor = ::MonitorFromRect(&rcScreenCoords, MONITOR_DEFAULTTOPRIMARY) ;
  626. ASSERT(hMonitor != NULL) ;
  627. // Prepare to get the information for this monitor.
  628. MONITORINFO mi;
  629. mi.cbSize = sizeof(mi);
  630. // Get the rect of this monitor.
  631. VERIFY(GetMonitorInfo(hMonitor, &mi));
  632. // Return the rectangle.
  633. if (fWork)
  634. *prc = mi.rcWork;
  635. else
  636. *prc = mi.rcMonitor;
  637. }
  638. ///////////////////////////////////////////////////////////////////////////////
  639. //
  640. // Get the rectangle of the monitor containing a point.
  641. //
  642. void multiMonitorRectFromPoint(/*in*/ POINT ptScreenCoords,
  643. /*out*/ LPRECT prc,
  644. /*in*/ BOOL fWork)
  645. {
  646. // precondition
  647. ASSERT(prc != NULL) ;
  648. // ASSERT(AfxIsValidAddress(prc, sizeof(RECT))) ;
  649. // Get the monitor which contains the point.
  650. HMONITOR hMonitor = MonitorFromPoint(ptScreenCoords, MONITOR_DEFAULTTOPRIMARY) ;
  651. ASSERT(hMonitor != NULL) ;
  652. // Prepare to get the information for this monitor.
  653. MONITORINFO mi;
  654. mi.cbSize = sizeof(mi);
  655. // Get the rect of this monitor.
  656. VERIFY(GetMonitorInfo(hMonitor, &mi));
  657. // Return the rectangle.
  658. if (fWork)
  659. *prc = mi.rcWork;
  660. else
  661. *prc = mi.rcMonitor;
  662. }