// Copyright (C) Microsoft Corporation 1996-1997, All Rights reserved. #include "header.h" #ifdef _DEBUG #undef THIS_FILE static const char THIS_FILE[] = __FILE__; #endif #include #include "strtable.h" #include "hha_strtable.h" #include "contain.h" #include "resource.h" #include "secwin.h" #include "state.h" #include "highlite.h" // CSizebar class for registration. #include "sizebar.h" // Custom NavPane for registration #include "custmtab.h" #include "unicode.h" #define COMPILE_MULTIMON_STUBS #include "multimon.h" #define DEFAULT_WINDOW_WIDTH 300 static const char txtNavWind[] = ">navwin"; #define WS_EX_LAYOUTRTL 0x00400000L // Right to left mirroring // Forward Reference void GetMonitorRect(HWND hwnd, LPRECT prc, BOOL fWork) ; void multiMonitorRectFromRect(/*in*/ RECT rcScreenCoords, /*out*/ LPRECT prc, /*in*/ BOOL fWork) ; void multiMonitorRectFromPoint(/*in*/ POINT ptScreenCoords, /*out*/ LPRECT prc, /*in*/ BOOL fWork) ; /*************************************************************************** FUNCTION: CreateHelpWindow PURPOSE: Create a help window PARAMETERS: pszType -- (optional) specifies a window type to create. Type must have been specified previously hwndCaller -- this will be the parent of the window RETURNS: HWND on success, NULL on failure COMMENTS: Reallocates pahwnd if more slots are necessary. MODIFICATION DATES: 26-Feb-1996 [ralphw] ***************************************************************************/ CHHWinType* CreateHelpWindow(PCSTR pszType, LPCTSTR pszFile, HWND hwndCaller, CHmData* phmData) { static BOOL fRegistered = FALSE; ASSERT(pahwnd != NULL); // Generate a default window type, if a name isn't given. char szName[20]; const char* pType = pszType ; if (IsEmptyString(pszType)) { static int iWindowNum = 1; // If the caller didn't specify a window type, then create a name // based off the current window number. wsprintf(szName, "win%u", iWindowNum++); pType = szName ; } // When we create a Window slot, we need the filename. However, if we are looking up a URL // we might not have a filename. So, pass NULL. This is a HOLE. CHHWinType* phh = FindOrCreateWindowSlot(pType, pszFile ? pszFile : phmData ? phmData->GetCompiledFile() : NULL); if (! phh ) return NULL; phh->m_phmData = phmData; if (phmData) { // Count references phmData->AddRef(); //--- Get the windows state. WINDOW_STATE wstate; ZERO_STRUCTURE(wstate); CState* pstate = phmData->m_pTitleCollection->GetState(); if (SUCCEEDED(pstate->Open(pType, STGM_READ))) { DWORD cbRead; pstate->Read(&wstate.cbStruct, sizeof(int), &cbRead); // // This looks funky until you understand that CState only supports atomic reads and writes from the beginning // of the stream. i.e. It does not maintain a file position pointer. // if ( wstate.cbStruct ) pstate->Read(&wstate, wstate.cbStruct, &cbRead); pstate->Close(); } if (wstate.cbStruct) { if (IsRectEmpty(phh->GetWinRect()) || phh->IsProperty(HHWIN_PROP_USER_POS)) { phh->fNotExpanded = wstate.fNotExpanded; CopyRect(&phh->rcWindowPos, &wstate.rcPos); phh->iNavWidth = wstate.iNavWidth; phh->rcNav.left = 0; phh->rcNav.right = wstate.iNavWidth; } if (phh->m_phmData->m_pTitleCollection->m_pSearchHighlight) phh->m_phmData->m_pTitleCollection->m_pSearchHighlight->EnableHighlight(wstate.fHighlight); phh->m_fLockSize = wstate.fLockSize; phh->m_fNoToolBarText = wstate.fNoToolBarText; phh->curNavType = wstate.curNavType; } } if (phh->idNotify) { HHN_NOTIFY hhcomp; hhcomp.hdr.hwndFrom = NULL; hhcomp.hdr.idFrom = phh->idNotify; hhcomp.hdr.code = HHN_WINDOW_CREATE; hhcomp.pszUrl = pType; if (IsWindow(hwndCaller)) { SendMessage(hwndCaller, WM_NOTIFY, phh->idNotify, (LPARAM) &hhcomp); } } // If this window type hasn't been defined, do so now if (!phh->GetTypeName()) { phh->SetTypeName(pType); phh->SetDisplayState(SW_SHOW); } if (!fRegistered) { RegisterOurWindow(); fRegistered = TRUE; } phh->hwndCaller = hwndCaller; if (IsRectEmpty(phh->GetWinRect())) { // Create a default window relative to the display size RECT rcScreen ; GetScreenResolution(hwndCaller, &rcScreen); phh->SetTop(rcScreen.top + 10); phh->SetBottom(phh->GetTop() + 450); if (phh->IsExpandedNavPane() && !phh->iNavWidth) phh->iNavWidth = DEFAULT_NAV_WIDTH; // If navwidth specified, balance navigation pane width and HTML pane width phh->SetLeft(rcScreen.right - DEFAULT_WINDOW_WIDTH - 5 - (phh->IsProperty(HHWIN_PROP_TRI_PANE) ? phh->iNavWidth : 0)); phh->SetRight(phh->GetLeft() + DEFAULT_WINDOW_WIDTH + (phh->IsProperty(HHWIN_PROP_TRI_PANE) ? phh->iNavWidth : 0)); } if (!(phh->dwStyles & WS_CHILD)) CheckWindowPosition(phh->GetWinRect(), TRUE); // Multimon support /* * The help author has the option of adding their own extended and * standard window styles. In addition, they can shut off all the * extended and normal styles that we would normally use, and just * use their own styles. In addition, they can specify all the * standard styles, but with no title bar. */ phh->hwndHelp = CreateWindowEx( phh->GetExStyles() | (phh->IsProperty(HHWIN_PROP_NODEF_EXSTYLES) ? 0 : WS_EX_APPWINDOW | ((phh->IsProperty(HHWIN_PROP_ONTOP) ? WS_EX_TOPMOST : 0))), txtHtmlHelpWindowClass, NULL, phh->GetStyles() | WS_CLIPCHILDREN, phh->GetLeft(), phh->GetTop(), phh->GetWidth(), phh->GetHeight(), hwndCaller, NULL, // REVIEW: Should we use the caller's hinstance instead? _Module.GetModuleInstance(), NULL); #ifdef _DEBUG ULONG err = GetLastError() ; #endif if (!IsValidWindow(*phh)) { OOM(); // BUGBUG: bogus error message if hwndCaller is NULL return NULL; } // This next section of code turns of the Win98/Win2K WS_EX_LAYOUTRTL (mirroring) // style in the event it is turned on (inherited from the parent window). // // Get the extended window styles // long lExStyles = GetWindowLongA(phh->hwndHelp, GWL_EXSTYLE); // Check if mirroring is turned on // if(lExStyles & WS_EX_LAYOUTRTL) { // turn off the mirroring bit // lExStyles ^= WS_EX_LAYOUTRTL; SetWindowLongA(phh->hwndHelp, GWL_EXSTYLE, lExStyles) ; // This is to update layout in the client area // InvalidateRect(hWnd, NULL, TRUE) ; } SendMessage(phh->hwndHelp, WM_SETFONT, (WPARAM)_Resource.GetAccessableUIFont(), 0); HMENU hmenu = GetSystemMenu(*phh, FALSE); AppendMenu(hmenu, MF_SEPARATOR, (UINT) -1, NULL); // before adding the jump runl to the system menu check if NoRun is set for this system Bug 7819 if (NoRun() == FALSE) HxAppendMenu(hmenu, MF_STRING, ID_JUMP_URL, GetStringResource(IDS_JUMP_URL)); if (IsHelpAuthor(hwndCaller)) { #if 0 // bug 5449 PCSTR psz = pGetDllStringResource(IDS_WINDOW_INFO); if (!IsEmptyString(psz)) HxAppendMenu(hmenu, MF_ENABLED | MF_STRING, IDM_WINDOW_INFO, pGetDllStringResource(IDS_WINDOW_INFO)); #endif HxAppendMenu(hmenu, MF_ENABLED | MF_STRING, IDM_VERSION, pGetDllStringResource(IDS_HHCTRL_VERSION)); } else HxAppendMenu(hmenu, MF_ENABLED | MF_STRING, IDM_VERSION, GetStringResource(IDS_ABOUT)); #ifdef _DEBUG HxAppendMenu(hmenu, MF_STRING, ID_VIEW_MEMORY, "Debug: memory usage..."); HxAppendMenu(hmenu, MF_STRING, ID_DEBUG_BREAK, "Debug: call DebugBreak()"); #endif // Load MSDN's Menu. if (phh->IsProperty(HHWIN_PROP_MENU)) { HMENU hMenu = LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(HH_MENU)) ; ASSERT(hMenu) ; BOOL b = SetMenu(phh->hwndHelp, hMenu) ; ASSERT(b) ; } if (phh->IsProperty(HHWIN_PROP_TRI_PANE) || phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) { if (phh->IsProperty(HHWIN_PROP_NOTB_TEXT)) phh->m_fNoToolBarText = TRUE; if (!phh->IsProperty(HHWIN_PROP_NO_TOOLBAR)) { TBBUTTON abtn[MAX_TB_BUTTONS]; ClearMemory(abtn, sizeof(abtn)); int cButtons = 0 ; cButtons = phh->CreateToolBar(abtn); if ( cButtons <= 0) { // No Toolbar buttons. Turn off this bit. phh->fsWinProperties &= ~HHWIN_PROP_NO_TOOLBAR ; } else { phh->hwndToolBar = CreateWindow("ToolbarWindow32", NULL, WS_CHILD | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_EX_DRAWDDARROWS | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_WRAPABLE | (phh->IsProperty(HHWIN_PROP_MENU) ? 0 : CCS_NODIVIDER) | (phh->m_fNoToolBarText ? 0 : TBSTYLE_WRAPABLE), 0, 0, 100, 30, *phh, (HMENU)ID_TOOLBAR, _Module.GetModuleInstance(), NULL); if (! phh->hwndToolBar ) return NULL; SendMessage(phh->hwndToolBar, TB_SETBITMAPSIZE, 0, (LPARAM)MAKELONG(TB_BMP_CX,TB_BMP_CY)); SendMessage(phh->hwndToolBar, TB_SETBITMAPSIZE, 0, (LPARAM)MAKELONG(TB_BTN_CX,TB_BTN_CY)); SendMessage(phh->hwndToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), (LPARAM)0); SendMessage(phh->hwndToolBar, TB_ADDBUTTONS, cButtons, (LPARAM)abtn); SendMessage(phh->hwndToolBar, WM_SETFONT, (WPARAM)_Resource.GetAccessableUIFont(), 0); phh->m_hImageListGray = ImageList_LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_TOOLBAR16G), TB_BMP_CX, 0, RGB(255,0,255), IMAGE_BITMAP, 0); SendMessage(phh->hwndToolBar, TB_SETIMAGELIST, 0, (LPARAM)(HIMAGELIST) phh->m_hImageListGray); phh->m_hImageList = ImageList_LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_TOOLBAR16), TB_BMP_CX, 0, RGB(255,0,255), IMAGE_BITMAP, 0); SendMessage(phh->hwndToolBar, TB_SETHOTIMAGELIST, 0, (LPARAM)(HIMAGELIST) phh->m_hImageList); if (!phh->m_fNoToolBarText) { for (int pos = 1; pos <= phh->m_ptblBtnStrings->CountStrings(); pos++) { char szBuf[256]; strcpy(szBuf, phh->m_ptblBtnStrings->GetPointer(pos)); szBuf[strlen(szBuf) + 1] = '\0'; // two terminating NULLs // Under W2K, send wide string to control (support for MUI) // if(g_bWinNT5) { WCHAR wszBuf[256]; memset(wszBuf,0,sizeof(wszBuf)); // get codepage of default UI // DWORD cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT)); MultiByteToWideChar(cp , 0, szBuf, -1, wszBuf, sizeof(wszBuf) / 2); SendMessageW(phh->hwndToolBar, TB_ADDSTRINGW, 0, (LPARAM) wszBuf); } else SendMessage(phh->hwndToolBar, TB_ADDSTRING, 0, (LPARAM) szBuf); } TCHAR szScratch[MAX_PATH]; LoadString(_Module.GetResourceInstance(), IDS_WEB_TB_TEXTROWS, szScratch, sizeof(szScratch)); int nRows = Atoi(szScratch); SendMessage(phh->hwndToolBar, TB_SETMAXTEXTROWS, nRows, 0); /* * Since we changed the window after we created it, we need to * force a recalculation which we do by changing the size of the * window ever so slightly. This causes the toolbar to * recalculate itself to be the exact size. */ phh->WrapTB(); } } } phh->CalcHtmlPaneRect(); if (phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) { phh->CreateOrShowNavPane(); ShowWindow(*phh, phh->GetShowState()); } else phh->CreateOrShowHTMLPane(); } if (IsValidWindow(*phh) ) { if (!phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) { phh->m_pCIExpContainer = new CContainer; HRESULT hr; BOOL bInstallEventSink = (BOOL)strcmp(phh->pszType, txtPrintWindow+1); if (IsValidWindow(phh->hwndHTML)) { hr = phh->m_pCIExpContainer->Create(phh->hwndHTML, &phh->rcHTML, bInstallEventSink); } else { RECT rc; phh->GetClientRect(&rc); hr = phh->m_pCIExpContainer->Create(*phh, &rc, bInstallEventSink); } if (!SUCCEEDED(hr)) { DEBUG_ReportOleError(hr); DestroyWindow(*phh); return NULL; } } if (phh->IsExpandedNavPane() && phh->AnyValidNavPane()) { phh->fNotExpanded = TRUE; BOOL fSaveLoack = phh->m_fLockSize; phh->m_fLockSize = TRUE; phh->ToggleExpansion(false); phh->m_fLockSize = fSaveLoack; } /* * 30-Sep-1996 [ralphw] For some reason, specifying the caption * when the window is created, doesn't work. So, we use * SetWindowText to specify the caption. */ // Set the window title (figure out which string is displayable) // // Rules: // // if (TitleLanguage = DefaultSystemLocale) // Display title string from CHM // // else // // if(Satellite DLL language == DefaultSystemLocale) // Display default title from Satellite DLL // // else // Display "HTML Help" // LANGID langidTitle = 0xFEFE; LANGID langidSystem = LANGIDFROMLCID(GetSystemDefaultLCID()); LANGID langidUI = _Module.m_Language.GetUiLanguage(); if(phh->m_phmData && phh->m_phmData->GetInfo()) langidTitle = LANGIDFROMLCID((phh->m_phmData->GetInfo())->GetLanguage()); if(langidTitle == langidSystem || PRIMARYLANGID(langidTitle) == LANG_ENGLISH ) { if (phh->GetCaption()) SetWindowText(*phh, phh->GetCaption()); else if (phh->m_phmData && phh->m_phmData->GetDefaultCaption()) SetWindowText(*phh, phh->m_phmData->GetDefaultCaption()); else SetWindowText(*phh, "HTML Help"); } else { if(langidUI == langidSystem) { CStr cszDefaultCaption = GetStringResource(IDS_HTML_HELP); SetWindowText(*phh, cszDefaultCaption); } else SetWindowText(*phh, "HTML Help"); } ShowWindow(*phh, phh->GetShowState()); if (IsValidWindow(phh->hwndToolBar)) ShowWindow(phh->hwndToolBar, phh->GetShowState()); if (IsValidWindow(phh->hwndHTML)) ShowWindow(phh->hwndHTML, phh->GetShowState()); if (phh->IsExpandedNavPane() && IsValidWindow(phh->hwndNavigation)) ShowWindow(phh->hwndNavigation, phh->GetShowState()); if ( phh->IsProperty(HHWIN_PROP_MENU) && phmData && phmData->m_sysflags.fDoSS ) { HMENU hMenuMain, hMenuSub; hMenuMain = GetMenu(phh->hwndHelp); hMenuSub = GetSubMenu(hMenuMain, 2); AppendMenu(hMenuSub, MF_SEPARATOR, 0, NULL); HxAppendMenu(hMenuSub, MF_STRING, HHM_DEFINE_SUBSET, GetStringResource(IDS_DEFINE_SUBSET)); } #ifdef _DEBUG if (phh->IsProperty(HHWIN_PROP_TRI_PANE) && phh->IsProperty(HHWIN_PROP_TAB_HISTORY)) phh->CreateHistoryTab(); // start tracking history immediately #endif #if 0 27-Sep-1996 [ralphw] Never returns the window... HWND hwndIE = (HWND) phh->m_pCIExpContainer->m_pWebBrowserApp->GetHwnd(); if (IsValidWindow(hwndIE)) { char szClass[256]; GetClassName(hwndIE, szClass, sizeof(szClass)); DWORD dwStyle = GetWindowLong(hwndIE, GWL_STYLE); DWORD dwexStyle = GetWindowLong(hwndIE, GWL_EXSTYLE); } #endif } return phh; } /*************************************************************************** FUNCTION: CheckWindowPosition PURPOSE: Make certain the window doesn't cover any portion of the tray, and that it has a certain minimum size. PARAMETERS: prc fAllowShrinkage RETURNS: COMMENTS: MODIFICATION DATES: 25-Feb-1996 [ralphw] ***************************************************************************/ // REVIEW: 25-Feb-1996 [ralphw] WinHelp did this, and set it to 200. I // dropped it down to 16 -- enough to see the window, but without forcing // it quite so large. const int HELP_WIDTH_MINIMUM = 16; const int HELP_HEIGHT_MINIMUM = 16; void CheckWindowPosition(RECT* prc, BOOL fAllowShrinkage) { GetWorkArea(); // Multimon support // Make certain we don't go off the edge of the screen if (prc->left < g_rcWorkArea.left) { int diff = g_rcWorkArea.left - prc->left; prc->left = g_rcWorkArea.left; prc->right += diff; } if (prc->top < g_rcWorkArea.top) { int diff = g_rcWorkArea.top - prc->top; prc->top = g_rcWorkArea.top; prc->bottom += diff; } /* * If the right side of the window is off the work area, move the * window to the left. If we don't have enough room for the window when * moved all the way to the left, then shrink the window (won't work for * dialogs). */ if (prc->right > g_rcWorkArea.right) { int diff = prc->right - g_rcWorkArea.right; if (diff < prc->left) { prc->left -= diff; prc->right = g_rcWorkArea.right; } else if (fAllowShrinkage) { diff -= prc->left; prc->left = g_rcWorkArea.left; prc->right -= diff; } else {// Can't shrink, so shove to the left side prc->left = g_rcWorkArea.left; } } // Same question about the bottom of the window being off the work area if (prc->bottom > g_rcWorkArea.bottom) { int diff = prc->bottom > g_rcWorkArea.bottom; if (diff < prc->top) { prc->top -= diff; prc->bottom = g_rcWorkArea.bottom; } else if (fAllowShrinkage) { diff -= prc->top; prc->top = g_rcWorkArea.top; prc->bottom -= diff; } else // Can't shrink, so shove to the top prc->top = g_rcWorkArea.top; } // Force minimum window size if (RECT_WIDTH(prc) < HELP_WIDTH_MINIMUM) { prc->right = prc->left + HELP_WIDTH_MINIMUM; // Width is now correct, but we could be off the work area. Start over CheckWindowPosition(prc, fAllowShrinkage); } if (RECT_HEIGHT(prc) < HELP_HEIGHT_MINIMUM) { prc->bottom = prc->top + HELP_HEIGHT_MINIMUM; // Height is now correct, but we could be off the work area. Start over CheckWindowPosition(prc, fAllowShrinkage); } } void GetScreenResolution(HWND hWnd, RECT* prc /*out*/) { ASSERT(prc) ; if (prc) { if (IsWindow(hWnd) ) { // Use the hWnd to get the monitor. GetMonitorRect(hWnd, prc, TRUE /*Get Work Area*/) ; } else { // hWnd isn't valid, use default monitor. POINT pt; pt.x=pt.y=0; multiMonitorRectFromPoint(pt, prc, TRUE) ; } } } void GetWorkArea() { // Get the size of the entire virtual screen. if (!g_cxScreen) { g_cxScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN) ; g_cyScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN) ; } // The tray must be handled externally. if (IsRectEmpty(&g_rcWorkArea)) { g_rcWorkArea.left = GetSystemMetrics(SM_XVIRTUALSCREEN) ; g_rcWorkArea.right = g_rcWorkArea.left + g_cxScreen ; g_rcWorkArea.top = GetSystemMetrics(SM_YVIRTUALSCREEN) ; g_rcWorkArea.bottom = g_rcWorkArea.top + g_cyScreen ; } } void RegisterOurWindow() { WNDCLASS wc; ZeroMemory(&wc, sizeof(WNDCLASS)); // clear all members wc.lpfnWndProc = HelpWndProc; wc.hInstance = _Module.GetModuleInstance(); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = txtHtmlHelpWindowClass; wc.hIcon = LoadIcon(_Module.GetResourceInstance(), "Icon!HTMLHelp"); wc.hbrBackground = (HBRUSH) COLOR_WINDOW; VERIFY(RegisterClass(&wc)); ASSERT(sizeof(WNDCLASSA)==sizeof(WNDCLASSW)); //lazy hack - just use the wcA wc.lpfnWndProc = ChildWndProc; wc.lpszClassName = (LPCSTR)L"HH Child"; //txtHtmlHelpChildWindowClass; wc.hbrBackground = (HBRUSH) COLOR_BTNSHADOW; if (NULL == RegisterClassW((CONST WNDCLASSW *)&wc)) { if (ERROR_CALL_NOT_IMPLEMENTED == GetLastError()) { wc.lpszClassName = txtHtmlHelpChildWindowClass; VERIFY(RegisterClass(&wc)); } } // Register the window class for the sizebar. CSizeBar::RegisterWindowClass() ; // Register the window class for the custom nav pane frame window. CCustomNavPane::RegisterWindowClass() ; } CHHWinType* FindHHWindowIndex(HWND hwnd) { static int iLastWindow = 0; static HWND hwndLastWindow = NULL; if (pahwnd && hwndLastWindow == hwnd && IsValidWindow(hwnd)) return pahwnd[iLastWindow]; hwndLastWindow = hwnd; while(IsValidWindow(hwnd)) { char szClassName[50]; GetClassName(hwnd, szClassName, sizeof(szClassName)); if (strcmp(szClassName, txtHtmlHelpWindowClass) == 0) break; hwnd = GetParent(hwnd); } if (pahwnd && pahwnd[iLastWindow] && pahwnd[iLastWindow]->hwndHelp == hwnd) return pahwnd[iLastWindow]; for (iLastWindow = 0; iLastWindow < g_cWindowSlots; iLastWindow++) { if (pahwnd && pahwnd[iLastWindow] && pahwnd[iLastWindow]->hwndHelp == hwnd) return pahwnd[iLastWindow]; } iLastWindow = 0; hwndLastWindow = NULL; return NULL; } void doHHWindowJump(PCSTR pszUrl, HWND hwndChild) { CHHWinType* phh = FindHHWindowIndex(hwndChild); if( !phh ) return; if (phh->IsProperty(HHWIN_PROP_NAV_ONLY_WIN)) { CStr cszUrl(pszUrl); cszUrl += txtNavWind; OnDisplayTopic(*phh, cszUrl, 0); return; } ASSERT(phh->m_pCIExpContainer); if (phh && phh->m_pCIExpContainer) { phh->m_pCIExpContainer->m_pWebBrowserApp->Navigate(pszUrl, NULL, NULL, NULL, NULL); } } /////////////////////////////////////////////////////////////////////////////// // // GetMonitorRect // // gets the "screen" or work area of the monitor that the passed // window is on. this is used for apps that want to clip or // center windows. // // the most common problem apps have with multimonitor systems is // when they use GetSystemMetrics(SM_C?SCREEN) to center or clip a // window to keep it on screen. If you do this on a multimonitor // system the window we be restricted to the primary monitor. // // this is a example of how you used the new Win32 multimonitor APIs // to do the same thing. // void GetMonitorRect(HWND hwnd, LPRECT prc, BOOL fWork) { // Preconditions ASSERT(hwnd != NULL) ; ASSERT(::IsWindow(hwnd)) ; // Core MONITORINFO mi; mi.cbSize = sizeof(mi); GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST), &mi); if (fWork) *prc = mi.rcWork; else *prc = mi.rcMonitor; } /////////////////////////////////////////////////////////////////////////////// // // Get the rectangle of the monitor containing the rectangle. // void multiMonitorRectFromRect(/*in*/ RECT rcScreenCoords, /*out*/ LPRECT prc, /*in*/ BOOL fWork) { //Preconditions ASSERT(prc != NULL) ; // ASSERT(AfxIsValidAddress(prc, sizeof(RECT))) ; // Get monitor which contains this rectangle. HMONITOR hMonitor = ::MonitorFromRect(&rcScreenCoords, MONITOR_DEFAULTTOPRIMARY) ; ASSERT(hMonitor != NULL) ; // Prepare to get the information for this monitor. MONITORINFO mi; mi.cbSize = sizeof(mi); // Get the rect of this monitor. VERIFY(GetMonitorInfo(hMonitor, &mi)); // Return the rectangle. if (fWork) *prc = mi.rcWork; else *prc = mi.rcMonitor; } /////////////////////////////////////////////////////////////////////////////// // // Get the rectangle of the monitor containing a point. // void multiMonitorRectFromPoint(/*in*/ POINT ptScreenCoords, /*out*/ LPRECT prc, /*in*/ BOOL fWork) { // precondition ASSERT(prc != NULL) ; // ASSERT(AfxIsValidAddress(prc, sizeof(RECT))) ; // Get the monitor which contains the point. HMONITOR hMonitor = MonitorFromPoint(ptScreenCoords, MONITOR_DEFAULTTOPRIMARY) ; ASSERT(hMonitor != NULL) ; // Prepare to get the information for this monitor. MONITORINFO mi; mi.cbSize = sizeof(mi); // Get the rect of this monitor. VERIFY(GetMonitorInfo(hMonitor, &mi)); // Return the rectangle. if (fWork) *prc = mi.rcWork; else *prc = mi.rcMonitor; }