/*++ Copyright (c) 1999-2001 Microsoft Corporation Module Name: util.cpp --*/ #include "precomp.hxx" #pragma hdrstop //Current Help Id for Open, Merge, Save and Open project dialog box WORD g_CurHelpId; // Number of dialog/message boxes currently open int g_nBoxCount; BOOL g_fNoPopups; HWND MDIGetActive( HWND hwndParent, BOOL *lpbMaximized ) /*++ Routine Description: Create the command window. Arguments: hwndParent - The parent window to the command window. In an MDI document, this is usually the handle to the MDI client window: g_hwndMDIClient Return Value: The return value is the handle to the active MDI child window. NULL if no MDI window has been created. --*/ { Assert(IsWindow(hwndParent)); return (HWND)SendMessage(hwndParent, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized ); } /*** hGetBoxParent ** ** Synopsis: ** hwnd = hGetBoxParent() ** ** Entry: ** none ** ** Returns: ** ** Description: ** Gets a suitable parent window handle for an ** invocation of a message or dialog box. ** Helper function to util.c functions so declared ** near. ** */ HWND hGetBoxParent() { HWND hCurWnd; int i = 0; hCurWnd = GetFocus(); if (hCurWnd) { while (GetWindowLong(hCurWnd, GWL_STYLE) & WS_CHILD) { hCurWnd = GetParent(hCurWnd); Dbg((++i < 100)); } } else { hCurWnd = g_hwndFrame; } return hCurWnd; } /**************************************************************************** FUNCTION: MsgBox PURPOSE: General purpose message box routine which takes a pointer to the message text. Provides program title as caption. ****************************************************************************/ int MsgBox( HWND hwndParent, PTSTR szText, UINT wType ) /*++ Routine Description: Generial purpose message box routine which takes a pointer to a message text and prvoides the program title for the caption of the message box. Arguments: hwndParament - Supplies the parent window handle for the message box szText - Supplies a pointer to the message box text. wType - Supplies the message box type (to specify buttons) Return Value: Returns the message box return code --*/ { int MsgBoxRet = IDOK; if (g_fNoPopups) { // // log the string to the command win in case testing // or when the remote server is running // CmdLogFmt (_T("%s\r\n"), szText); } else { g_nBoxCount++; MsgBoxRet = MessageBox(hwndParent, szText, g_MainTitleText, wType); g_nBoxCount--; } return MsgBoxRet; } /* MsgBox() */ /*** ErrorBox ** ** Returns: ** FALSE ** ** Description: ** Display an error message box with an "Error" title, an OK ** button and a Exclamation Icon. First parameter is a ** reference string in the ressource file. The string ** can contain printf formatting chars, the arguments ** follow from the second parameter onwards. ** */ BOOL ErrorBox( HWND hwnd, UINT type, int wErrorFormat, ... ) { TCHAR szErrorFormat[MAX_MSG_TXT]; TCHAR szErrorText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary va_list vargs; // load format string from resource file Dbg(LoadString(g_hInst, wErrorFormat, (PTSTR)szErrorFormat, MAX_MSG_TXT)); va_start(vargs, wErrorFormat); _vstprintf(szErrorText, szErrorFormat, vargs); va_end(vargs); if (hwnd == NULL) { hwnd = g_hwndFrame; } if (type == 0) { type = MB_TASKMODAL; } MsgBox(g_hwndFrame, (PTSTR)szErrorText, type | MB_OK | MB_ICONINFORMATION); return FALSE; //Keep it always FALSE please } /*** InformationBox ** ** Description: ** Display an information message box with an "Information" ** title, an OK button and an Information Icon. ** */ void InformationBox( WORD wDescript ... ) { TCHAR szFormat[MAX_MSG_TXT]; TCHAR szText[MAX_VAR_MSG_TXT]; // size is as big as considered necessary va_list vargs; // load format string from resource file Dbg(LoadString(g_hInst, wDescript, (PTSTR)szFormat, MAX_MSG_TXT)); // set up szText from passed parameters va_start(vargs, wDescript); _vstprintf(szText, szFormat, vargs); va_end(vargs); MsgBox(g_hwndFrame, (PTSTR)szText, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); return; } /*** QuestionBox ** ** Synopsis: ** int = QuestionBox(wCaptionId, wMsgFormat, wType, ...) ** ** Entry: ** ** Returns: ** The result of the message box call ** ** Description: ** Display an query box with combination of YES, NO and ** CANCEL buttons and a question mark Icon. ** See ErrorBox for discussion. ** */ int CDECL QuestionBox( WORD wMsgFormat, UINT wType, ... ) { TCHAR szMsgFormat[MAX_MSG_TXT]; TCHAR szMsgText[MAX_VAR_MSG_TXT]; va_list vargs; //Load format string from resource file Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT)); //Set up szMsgText from passed parameters va_start(vargs, wType); _vstprintf(szMsgText, szMsgFormat, vargs); va_end(vargs); return MsgBox(g_hwndFrame, szMsgText, wType | MB_ICONEXCLAMATION | MB_TASKMODAL); } /* QuestionBox() */ /**************************************************************************** FUNCTION: QuestionBox2 PURPOSE: Display an query box with combination of YES, NO and CANCEL buttons and a question mark Icon. The type and the parent window are adjustable. RETURNS: MessageBox result ****************************************************************************/ int CDECL QuestionBox2( HWND hwnd, WORD wMsgFormat, UINT wType, ... ) { TCHAR szMsgFormat[MAX_MSG_TXT]; TCHAR szMsgText[MAX_VAR_MSG_TXT]; va_list vargs; //Load format string from resource file Dbg(LoadString(g_hInst, wMsgFormat, (PTSTR)szMsgFormat, MAX_MSG_TXT)); //Set up szMsgText from passed parameters va_start(vargs, wType); _vstprintf(szMsgText, szMsgFormat, vargs); va_end(vargs); return MsgBox(hwnd, szMsgText, wType | MB_ICONEXCLAMATION); } /* QuestionBox2() */ /*** ShowAssert ** ** Synopsis: ** void = ShowAssert(szCond, iLine, szFile) ** ** Entry: ** szCond - tokenized form of the failed condition ** iLine - Line number for the assertion ** szFile - File for the assertion ** ** Returns: ** void ** ** Description: ** Prepare and display a Message Box with szCondition, iLine and ** szFile as fields. ** */ void ShowAssert( PTSTR condition, UINT line, PTSTR file ) { TCHAR text[MAX_VAR_MSG_TXT]; //Build line, show assertion and exit program _stprintf(text, _T("- Line:%u, File:%Fs, Condition:%Fs"), (WPARAM) line, file, condition); TCHAR szBuffer[_MAX_PATH]; PTSTR pszBuffer; PTSTR szAssertFile = _T("assert.wbg"); HANDLE hFile = NULL; hFile = CreateFile(szAssertFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (INVALID_HANDLE_VALUE != hFile) { // Write the text out to the file DWORD dwBytesWritten = 0; Assert(WriteFile(hFile, text, _tcslen(text), &dwBytesWritten, NULL)); Assert(_tcslen(text) == dwBytesWritten); CloseHandle(hFile); } int Action = MessageBox(GetDesktopWindow(), text, "Assertion Failure", MB_ABORTRETRYIGNORE); if (Action == IDABORT) { exit(3); } else if (Action == IDRETRY) { DebugBreak(); } } // ShowAssert() /*** StartDialog ** ** Synopsis: ** int = StartDialog(rcDlgNb, dlgProc, lParam) ** ** Entry: ** rcDlgNb - Resource number of dialog to be openned ** dlgProc - Filter procedure for the dialog ** lParam - Data passed into the dlg proc via LPARAM ** ** Returns: ** Result of the dialog box call ** ** Description: ** Loads and execute the dialog box 'rcDlgNb' (resource ** file string number) associated with the dialog ** function 'dlgProc' ** */ int StartDialog( int rcDlgNb, DLGPROC dlgProc, LPARAM lParam ) { LRESULT result; // //Execute Dialog Box // g_nBoxCount++; result = DialogBoxParam(g_hInst, MAKEINTRESOURCE(rcDlgNb), hGetBoxParent(), dlgProc, lParam ); Assert(result != (LRESULT)-1); g_nBoxCount--; return (int)result; } void ProcessNonDlgMessage(LPMSG Msg) { #if 0 { DebugPrint("NonDlg msg %X for %p, args %X %X\n", Msg->message, Msg->hwnd, Msg->wParam, Msg->lParam); } #endif // If a keyboard message is for the MDI , let the MDI client // take care of it. Otherwise, check to see if it's a normal // accelerator key (like F3 = find next). Otherwise, just handle // the message as usual. if (!TranslateMDISysAccel(g_hwndMDIClient, Msg) && !TranslateAccelerator(g_hwndFrame, g_hMainAccTable, Msg)) { // // If this is a right-button-down over a child window, // automatically activate the window's contex menu. // if (Msg->message == WM_RBUTTONDOWN && IsChild(g_hwndMDIClient, Msg->hwnd)) { HMENU Menu; PCOMMONWIN_DATA CmnWin; POINT ScreenPt; POINT Pt = {LOWORD(Msg->lParam), HIWORD(Msg->lParam)}; ClientToScreen(Msg->hwnd, &Pt); ScreenPt = Pt; ScreenToClient(g_hwndMDIClient, &Pt); HWND Win = ChildWindowFromPointEx(g_hwndMDIClient, Pt, CWP_SKIPINVISIBLE); if (Win != NULL && (CmnWin = GetCommonWinData(Win)) != NULL && (Menu = CmnWin->GetContextMenu()) != NULL) { UINT Item = TrackPopupMenu(Menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_RIGHTBUTTON, ScreenPt.x, ScreenPt.y, 0, Msg->hwnd, NULL); if (Item) { CmnWin->OnContextMenuSelection(Item); } return; } } TranslateMessage(Msg); DispatchMessage(Msg); } } void ProcessPendingMessages(void) { MSG Msg; // Process all available messages. while (PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE)) { if (!GetMessage(&Msg, NULL, 0, 0)) { g_Exit = TRUE; break; } if (g_FindDialog == NULL || !IsDialogMessage(g_FindDialog, &Msg)) { ProcessNonDlgMessage(&Msg); } } } /**************************************************************************** FUNCTION: InfoBox PURPOSE: Opens a Dialog box with a title and accepting a printf style for text. It's for DEBUGGING USE ONLY ****************************************************************************/ int InfoBox( PTSTR text, ... ) { TCHAR buffer[MAX_MSG_TXT]; va_list vargs; va_start(vargs, text); _vstprintf(buffer, text, vargs); va_end(vargs); return MsgBox(GetActiveWindow(), buffer, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); } void ExitDebugger(PDEBUG_CLIENT Client, ULONG Code) { if (Client != NULL && !g_RemoteClient) { Client->EndSession(DEBUG_END_PASSIVE); // Force servers to get cleaned up. Client->EndSession(DEBUG_END_REENTRANT); } ExitProcess(Code); } // XXX drewb - Is this functionality present in other utilities? // FatalErrorBox is close. Probably can combine something here. void ErrorExit(PDEBUG_CLIENT Client, PCSTR Format, ...) { char Message[1024]; va_list Args; va_start(Args, Format); _vsnprintf(Message, sizeof(Message), Format, Args); va_end(Args); // XXX drewb - Could put up message box. OutputDebugString(Message); ExitDebugger(Client, E_FAIL); } #define MAX_FORMAT_STRINGS 8 LPSTR FormatAddr64( ULONG64 addr ) /*++ Routine Description: Format a 64 bit address, showing the high bits or not according to various flags. An array of static string buffers is used, returning a different buffer for each successive call so that it may be used multiple times in the same printf. Arguments: addr - Supplies the value to format Return Value: A pointer to the string buffer containing the formatted number --*/ { static CHAR strings[MAX_FORMAT_STRINGS][18]; static int next = 0; LPSTR string; string = strings[next]; ++next; if (next >= MAX_FORMAT_STRINGS) { next = 0; } if (g_Ptr64) { sprintf(string, "%08x`%08x", (ULONG)(addr>>32), (ULONG)addr); } else { sprintf(string, "%08x", (ULONG)addr); } return string; } static BOOL FAddToSearchPath = FALSE; static BOOL FAddToRootMap = FALSE; /* ** AppendFilter ** ** Description: ** Append a filter to an existing filters string. ** */ BOOL AppendFilter( WORD filterTextId, int filterExtId, PTSTR filterString, int *len, int maxLen ) { int size; TCHAR Tmp[MAX_MSG_TXT]; // // Append filter text // Dbg(LoadString(g_hInst, filterTextId, Tmp, MAX_MSG_TXT)); size = _tcslen(Tmp) + 1; if (*len + size > maxLen) { return FALSE; } memmove(filterString + *len, Tmp, size); *len += size; // // Append filter extension // Dbg(LoadString(g_hInst, filterExtId, Tmp, MAX_MSG_TXT)); size = _tcslen(Tmp) + 1; if (*len + size > maxLen) { return FALSE; } memmove(filterString + *len, Tmp, size); *len += size; return TRUE; } /* ** InitFilterString ** ** Description: ** Initialize file filters for file dialog boxes. */ void InitFilterString( WORD titleId, PTSTR filter, int maxLen ) { int len = 0; switch (titleId) { case DLG_Browse_CrashDump_Title: AppendFilter(TYP_File_DUMP, DEF_Ext_DUMP, filter, &len, maxLen); break; case DLG_Browse_Executable_Title: AppendFilter(TYP_File_EXE, DEF_Ext_EXE, filter, &len, maxLen); break; case DLG_Browse_LogFile_Title: AppendFilter(TYP_File_LOG, DEF_Ext_LOG, filter, &len, maxLen); break; case DLG_Open_Filebox_Title: case DLG_Browse_Filebox_Title: AppendFilter(TYP_File_SOURCE, DEF_Ext_SOURCE, filter, &len, maxLen); AppendFilter(TYP_File_INCLUDE, DEF_Ext_INCLUDE, filter, &len, maxLen); AppendFilter(TYP_File_ASMSRC, DEF_Ext_ASMSRC, filter, &len, maxLen); AppendFilter(TYP_File_INC, DEF_Ext_INC, filter, &len, maxLen); AppendFilter(TYP_File_RC, DEF_Ext_RC, filter, &len, maxLen); AppendFilter(TYP_File_DLG, DEF_Ext_DLG, filter, &len, maxLen); AppendFilter(TYP_File_DEF, DEF_Ext_DEF, filter, &len, maxLen); AppendFilter(TYP_File_MAK, DEF_Ext_MAK, filter, &len, maxLen); break ; case DLG_Browse_DbugDll_Title: AppendFilter(TYP_File_DLL, DEF_Ext_DLL, filter, &len, maxLen); break; default: Assert(FALSE); break; } AppendFilter(TYP_File_ALL, DEF_Ext_ALL, filter, &len, maxLen); filter[len] = _T('\0'); } BOOL StartFileDlg( HWND hwnd, int titleId, int defExtId, int helpId, int templateId, PTSTR InitialDir, PTSTR fileName, DWORD* pFlags, LPOFNHOOKPROC lpfnHook ) /*++ Routine Description: This function is used by windbg to open the set of common file handling dialog boxes. Arguments: hwnd - Supplies the wnd to hook the dialog box to titleId - Supplies the string resource of the title defExtId - Supplies The default extension resource string helpId - Supplies the help number for the dialog box templateId - Supplies the dialog resource number if non-zero fileName - Supplies the default file name pFiles - Supplies a pointer to flags lpfnHook - Supplies the address of a hook procedure for the dialog Return Value: The result of the dialog box call (usually TRUE for OK and FALSE for cancel) --*/ { #define filtersMaxSize 350 OPENFILENAME_NT4 OpenFileName = {0}; TCHAR title[MAX_MSG_TXT]; TCHAR defExt[MAX_MSG_TXT]; BOOL result; TCHAR filters[filtersMaxSize]; LPOFNHOOKPROC lpDlgHook = NULL; HCURSOR hSaveCursor; TCHAR files[_MAX_PATH + 8]; TCHAR szExt[_MAX_EXT + 8]; TCHAR szBase[_MAX_PATH + 8]; int indx; TCHAR ch; TCHAR fname[_MAX_FNAME]; TCHAR ext[_MAX_EXT]; PTSTR LocalInitialDir = NULL; *pFlags |= (OFN_EXPLORER | OFN_NOCHANGEDIR); if (InitialDir == NULL || !InitialDir[0]) { DWORD retval = GetCurrentDirectory(NULL, NULL); InitialDir = (PTSTR)calloc(retval, sizeof(TCHAR) ); if (InitialDir == NULL) { return FALSE; } GetCurrentDirectory(retval, InitialDir); LocalInitialDir = InitialDir; } if (DLG_Browse_Filebox_Title == titleId) { _tsplitpath( fileName, NULL, NULL, fname, ext ); _tmakepath( files, NULL, NULL, fname, ext ); } else { _tcscpy(files, fileName); } // // Set the Hour glass cursor // hSaveCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); InitFilterString((WORD)titleId, (PTSTR)filters, (int)filtersMaxSize); Dbg(LoadString(g_hInst, titleId, (PTSTR)title, MAX_MSG_TXT)); Dbg(LoadString(g_hInst, defExtId, (PTSTR)defExt, MAX_MSG_TXT)); if (templateId) { // // Build dialog box Name // *pFlags |= OFN_ENABLETEMPLATE; OpenFileName.lpTemplateName = MAKEINTRESOURCE(templateId); } else { *pFlags |= OFN_EXPLORER; } // // Make instance for _T('dlgProc') // if (lpfnHook) { lpDlgHook = lpfnHook; *pFlags |= OFN_ENABLEHOOK; } g_CurHelpId = (WORD) helpId; OpenFileName.lStructSize = sizeof(OpenFileName); OpenFileName.hwndOwner = hwnd; OpenFileName.hInstance = g_hInst; OpenFileName.lpstrFilter = (PTSTR)filters; OpenFileName.lpstrCustomFilter = NULL; OpenFileName.nMaxCustFilter = 0; OpenFileName.nFilterIndex = 1; OpenFileName.lpstrFile = files; OpenFileName.nMaxFile = _MAX_PATH; OpenFileName.lpstrFileTitle = NULL; OpenFileName.lpstrInitialDir = InitialDir; OpenFileName.lpstrTitle = (PTSTR)title; OpenFileName.Flags = *pFlags; OpenFileName.lpstrDefExt = (PTSTR)NULL; OpenFileName.lCustData = 0L; OpenFileName.lpfnHook = lpDlgHook; g_nBoxCount++; switch (titleId) { case DLG_Open_Filebox_Title: _tcscat(OpenFileName.lpstrFile, defExt); // fall thru case DLG_Browse_Executable_Title: case DLG_Browse_CrashDump_Title: result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ; break ; case DLG_Browse_LogFile_Title: if (fileName) { _tcscpy(OpenFileName.lpstrFile, fileName); } else { *OpenFileName.lpstrFile = 0; } result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ; break; case DLG_Browse_DbugDll_Title: *(OpenFileName.lpstrFile) = _T('\0'); result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ; break ; case DLG_Browse_Filebox_Title: _tsplitpath (files, (PTSTR)NULL, (PTSTR)NULL, (PTSTR)szBase, szExt); indx = matchExt (szExt, filters); if (indx != -1) { OpenFileName.nFilterIndex = indx; } _tcscat(title, szBase); if (*szExt) { _tcscat(title, szExt); } FAddToSearchPath = FALSE; FAddToRootMap = FALSE; result = GetOpenFileName((LPOPENFILENAME)&OpenFileName) ; // // Check to see if the use said to add a file to the browse path. // If so then add it to the front of the path // /*if (FAddToSearchPath) { AddToSearchPath(OpenFileName.lpstrFile); } else if (FAddToRootMap) { RootSetMapped(fileName, OpenFileName.lpstrFile); }*/ break; default: Assert(FALSE); free(LocalInitialDir); return FALSE; } g_nBoxCount--; if (result) { _tcscpy(fileName, OpenFileName.lpstrFile); if (titleId == DLG_Open_Filebox_Title) { AddFileToMru(FILE_USE_SOURCE, fileName); } // // Get the output of flags // *pFlags = OpenFileName.Flags ; } // //Restore cursor // SetCursor(hSaveCursor); free(LocalInitialDir); return result; } /* StartFileDlg() */ /*** matchExt ** ** Synopsis: ** int = matchExt (queryExtension, sourceList) ** ** Entry: ** ** Returns: 1-based index of pairwise substring for which the second ** element (i.e., the extension list), contains the target ** extension. If there is no match, we return -1. ** ** Description: ** Searches extension lists for the Open/Save/Browse common ** dialogs to try to match a filter to the input filename's ** extension. ** (Open File, Save File, Merge File and Open Project) ** ** Implementation note: Our thinking looks like this: ** ** We are given a sequence of null-terminated strings which ** are text/extension pairs. We return the pairwise 1-based ** index of the first pair for which the second element has an ** exact match for the target extension. (Everything, by the ** way, is compared without case sensitivity.) We picture the ** source sequence, then, to be an array whose elements are pairs ** of strings (we will call the pairs 'left' and 'right'). ** ** Just to complicate things, we allow the '.right' pair elements to ** be strings like "*.c;*.cpp;*.cxx", where we our query might be ** any one of the three (minus the leading asterisk). Fortunately, ** _tcstok() will break things apart for us (see the 'delims[]' array ** in the code for the delimiters we have chosen). ** ** Assuming there is a match in there somewhere, our invariant ** for locating the first one will be: ** ** Exists(k): ** ForAll(i) : 0 <= i < k ** : queryExtension \not IS_IN source[i].right ** \and ** queryExtension IS_IN source[k].right ** ** where we define IS_IN to be a membership predicate (using _tcstok() ** and _tcsicmp() in the implementation, eh?): ** ** x IS_IN y ** <=> ** Exists (t:token) : (t \in y) \and (x == t). ** ** The guard for our main loop, then, comes from the search for the ** queryExtension within the tokens inside successive '.right' elements. ** We choose to continue as long as there is no current token in the ** pair's right side that contains the query. ** ** (We have the pragmatic concern that the value may not be there, so we ** augment the loop guard with the condition that we have not yet ** exhausted the source. This is straightforward to add to the ** invariant, but it causes a lot of clutter that does help our ** comprehension at all, so we just stick it in the guard without ** formal justification.) */ int matchExt( PTSTR queryExtension, PTSTR sourceList ) { int answer; int idxPair = 1; // a 1-based index! PTSTR tokenMatch = 0; TCHAR delims[] = _T("*,; ") ; // Given a typical string: "*.c;*.cpp;*.cxx", // _tcstok() would produce three tokens: // ".c", ".cpp", and ".cxx". while (*sourceList != 0 && tokenMatch == 0) { while (*sourceList != _T('\0')) { sourceList++; } // skip first string of pair sourceList++; // and increment beyond NULL if (*sourceList != _T('\0')) { PTSTR work = _tcsdup (sourceList); // copy to poke holes in tokenMatch = _tcstok (work, delims); while (tokenMatch && _tcsicmp (tokenMatch, queryExtension)) { tokenMatch = _tcstok (0, delims); } free (work); } if (tokenMatch == 0) // no match: need to move to next pair { while (*sourceList != _T('\0')) { sourceList++; } // skip second string of pair sourceList++; // and increment beyond NULL idxPair++; } } answer = (tokenMatch != 0) ? idxPair : (-1); return (answer); } /*** DlgFile ** ** Synopsis: ** bool = DlgFile(hDlg, message, wParam, lParam) ** ** Entry: ** ** Returns: ** ** Description: ** Processes messages for file dialog boxes ** Those dialogs are not called directly but are called ** by the DlgFile function which contains all basic ** elements for Dialogs Files Operations Handling. ** (Open File, Save File, Merge File and Open Project) ** ** See OFNHookProc */ UINT_PTR APIENTRY DlgFile( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) { case WM_NOTIFY: { LPOFNOTIFY lpon = (LPOFNOTIFY) lParam; // // Determine what happened/why we are being notified // switch (lpon->hdr.code) { case CDN_HELP: // Help button pushed Dbg(HtmlHelp(hDlg,g_HelpFileName, HH_HELP_CONTEXT, g_CurHelpId)); break; } } break; } return FALSE; } /* DlgFile() */ UINT_PTR APIENTRY GetOpenFileNameHookProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) /*++ Routine Description: This routine is handle the Add Directory To radio buttons in the browser source file dialog box. Arguments: hDlg - Supplies the handle to current dialog msg - Supplies the message to be processed wParam - Supplies info about the message lParam - Supplies info about the message Return Value: TRUE if we replaced default processing of the message, FALSE otherwise --*/ { /* switch( msg ) { case WM_INITDIALOG: return TRUE; case WM_NOTIFY: { LPOFNOTIFY lpon = (LPOFNOTIFY) lParam; switch(lpon->hdr.code) { case CDN_FILEOK: FAddToSearchPath = (IsDlgButtonChecked( hDlg, IDC_CHECK_ADD_SRC_ROOT_MAPPING) == BST_CHECKED); return 0; } } } return DlgFile(hDlg, msg, wParam, lParam); */ return 0; } /* GetOpenFileNameHookProc() */ void Internal_Activate( HWND hwndCur, HWND hwndNew, int nPosition ) /*++ Routine Description: Places a window in the specified Z order position. Arguments: hwndCur - Currently active window, topmost in Z order. Can be NULL. hwndNew - The window to be placed in the new Z order. nPosition - Where the window is to be place in the Z order. 1 - topmost 2 - 2nd place (behind topmost) 3 - 3rd place, etc.... Return Value: None --*/ { // Sanity check. Make sure the programmer // specified a 1, 2, or 3. We are strict in order to // keep it readable. Assert(1 <= nPosition && nPosition <= 3); Assert(hwndNew); switch (nPosition) { case 1: // Make it topmost SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0); break; case 2: // Try to place it 2nd in Z order if (NULL == hwndCur) { // We don't have a topmost window, so make this one the topmost window SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0); } else { // Place it in 2nd SetWindowPos(hwndNew, hwndCur, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); // Give the topmost most focus again and activate UI visual clues. SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0); } break; case 3: // Try to place it 3rd in Z order if (NULL == hwndCur) { // We don't have a topmost window, so make this one the topmost window SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndNew, 0); } else { // Is there a window 2nd in the Z order? HWND hwndPlaceAfter = GetNextWindow(hwndCur, GW_HWNDNEXT); if (NULL == hwndPlaceAfter) { // No window 2nd in Z order. Then simply place it after the // topmost window. hwndPlaceAfter = hwndCur; } // Place it SetWindowPos(hwndNew, hwndPlaceAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); // Give the topmost most focus again and activate UI visual clues. SendMessage(g_hwndMDIClient, WM_MDIACTIVATE, (WPARAM) hwndCur, 0); } break; default: // Sanity check, the programmer missed a case Assert(0); } } void ActivateMDIChild( HWND hwndNew, BOOL bUserActivated ) /*++ Routine Description: Used to activate a specified window. Automatically uses the hwndActive variable to determine the currently active window. Arguments: hwndNew - The window to be placed in the new Z order. bUserActivated - Indicates whether this action was initiated by the user or by windbg. The value is to determine the Z order of any windows that are opened. --*/ { if (hwndNew == NULL) { Assert(hwndNew); return; } HWND hwndPrev = NULL; PCOMMONWIN_DATA pCur_WinData = NULL; PCOMMONWIN_DATA pNew_WinData = NULL; PCOMMONWIN_DATA pPrev_WinData = NULL; HWND hwndCur = MDIGetActive(g_hwndMDIClient, NULL); if (!hwndCur || bUserActivated || hwndCur == hwndNew) { // Nothing else was open. So we make this one the // topmost window. // // Or the user requested that this window be made // the topmost window, and we obey. // // Or we are re-activating the current window. Internal_Activate(hwndCur, hwndNew, 1); return; } // See is we have 3 or more windows open hwndPrev = GetNextWindow(hwndCur, GW_HWNDNEXT); if (hwndCur) { pCur_WinData = GetCommonWinData(hwndCur); } pNew_WinData = GetCommonWinData(hwndNew); Assert(pNew_WinData); if (!pNew_WinData) { return; } if (hwndPrev) { pPrev_WinData = GetCommonWinData(hwndPrev); } // // Handle the case where the window activation // was requested by the debugger itself and not the // user. // switch (pNew_WinData->m_enumType) { default: Internal_Activate(hwndCur, hwndNew, bUserActivated ? 2 : 1); break; case DISASM_WINDOW: case DOC_WINDOW: if (GetSrcMode_StatusBar()) { // Src mode if (pCur_WinData != NULL && (DISASM_WINDOW == pCur_WinData->m_enumType || DOC_WINDOW == pCur_WinData->m_enumType)) { // We can take the place of another doc/asm wind // Place 1st in z-order Internal_Activate(hwndCur, hwndNew, 1); } else { if (pPrev_WinData != NULL && (DOC_WINDOW == pPrev_WinData->m_enumType || DISASM_WINDOW == pPrev_WinData->m_enumType)) { // Don't have a window in 2nd place, or if we do it // is a src or asm window, and we can hide it. // Place 2nd in Z-order Internal_Activate(hwndCur, hwndNew, 2); } else { // Place 3rd in Z-order Internal_Activate(hwndCur, hwndNew, 3); } } } else { WIN_TYPES Type = pCur_WinData != NULL ? pCur_WinData->m_enumType : MINVAL_WINDOW; // Asm mode // Which is currently the topmost window. switch (Type) { case DOC_WINDOW: // Place 1st in z-order Internal_Activate(hwndCur, hwndNew, 1); break; case DISASM_WINDOW: if (DOC_WINDOW == pNew_WinData->m_enumType) { if (pPrev_WinData == NULL || DOC_WINDOW != pPrev_WinData->m_enumType) { // We have a window in second place that isn't a doc // window (locals, watch, ...). Internal_Activate(hwndCur, hwndNew, 3); } else { // Either don't have any windows in second place, or // we have a window in second place that is a doc // window. We can take its place. // // Place 2nd in z-order Internal_Activate(hwndCur, hwndNew, 2); } } else { // Should never happen. The case of disasm being activated // when it is currently active should ahve already been // taken care of. Dbg(0); } break; default: if ((pPrev_WinData != NULL && DISASM_WINDOW == pPrev_WinData->m_enumType) && DOC_WINDOW == pNew_WinData->m_enumType) { // window (locals, watch, ...). Internal_Activate(hwndCur, hwndNew, 3); } else { // Place 2nd in z-order Internal_Activate(hwndCur, hwndNew, 2); } break; } } break; } } void AppendTextToAnEditControl( HWND hwnd, PTSTR pszNewText ) { Assert(hwnd); Assert(pszNewText); CHARRANGE chrrgCurrent = {0}; CHARRANGE chrrgAppend = {0}; // Get the current selection SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) &chrrgCurrent); // Set the selection to the very end of the edit control chrrgAppend.cpMin = chrrgAppend.cpMax = GetWindowTextLength(hwnd); SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent); // Append the text SendMessage(hwnd, EM_REPLACESEL, FALSE, (LPARAM) pszNewText); // Restore previous selection SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM) &chrrgCurrent); } VOID CopyToClipboard( PSTR str ) { if (!str) { return; } ULONG Len = strlen(str)+1; HANDLE Mem = GlobalAlloc(GMEM_MOVEABLE, Len); if (Mem == NULL) { return; } PSTR Text = (PSTR)GlobalLock(Mem); if (Text == NULL) { GlobalFree(Mem); return; } strcpy(Text, str); GlobalUnlock(Mem); if (OpenClipboard(NULL)) { EmptyClipboard(); if (SetClipboardData(CF_TEXT, Mem) == NULL) { GlobalFree(Mem); } CloseClipboard(); } } void SetAllocString(PSTR* Str, PSTR New) { if (*Str != NULL) { free(*Str); } *Str = New; } BOOL DupAllocString(PSTR* Str, PSTR New) { PSTR NewStr = (PSTR)malloc(strlen(New) + 1); if (NewStr == NULL) { return FALSE; } strcpy(NewStr, New); SetAllocString(Str, NewStr); return TRUE; } BOOL PrintAllocString(PSTR* Str, int Len, PCSTR Format, ...) { PSTR NewStr = (PSTR)malloc(Len); if (NewStr == NULL) { return FALSE; } va_list Args; va_start(Args, Format); _vsnprintf(NewStr, Len, Format, Args); va_end(Args); SetAllocString(Str, NewStr); return TRUE; } HMENU CreateContextMenuFromToolbarButtons(ULONG NumButtons, TBBUTTON* Buttons, ULONG IdBias) { ULONG i; HMENU Menu; Menu = CreatePopupMenu(); if (Menu == NULL) { return Menu; } for (i = 0; i < NumButtons; i++) { MENUITEMINFO Item; ZeroMemory(&Item, sizeof(Item)); Item.cbSize = sizeof(Item); Item.fMask = MIIM_TYPE; if (Buttons->fsStyle & BTNS_SEP) { Item.fType = MFT_SEPARATOR; } else { Item.fMask |= MIIM_ID; Item.fType = MFT_STRING; Item.wID = (WORD)(Buttons->idCommand + IdBias); Item.dwTypeData = (LPSTR)Buttons->iString; } if (!InsertMenuItem(Menu, i, TRUE, &Item)) { DestroyMenu(Menu); return NULL; } Buttons++; } DrawMenuBar(g_hwndFrame); return Menu; } HWND AddButtonBand(HWND Bar, PTSTR Text, PTSTR SizingText, UINT Id) { HWND Button; HDC Dc; RECT Rect; Button = CreateWindowEx(0, "BUTTON", Text, WS_VISIBLE | WS_CHILD, 0, 0, 0, 0, Bar, (HMENU)(UINT_PTR)Id, g_hInst, NULL); if (Button == NULL) { return NULL; } Rect.left = 0; Rect.top = 0; SendMessage(Button, WM_SETFONT, (WPARAM)g_Fonts[FONT_VARIABLE].Font, 0); Dc = GetDC(Button); if (Dc != NULL) { SIZE Size; GetTextExtentPoint32(Dc, SizingText, strlen(SizingText), &Size); Rect.right = Size.cx; Rect.bottom = Size.cy; ReleaseDC(Button, Dc); } else { Rect.right = strlen(Text) * g_Fonts[FONT_FIXED].Metrics.tmAveCharWidth; Rect.bottom = g_Fonts[FONT_FIXED].Metrics.tmHeight; } REBARBANDINFO BandInfo; BandInfo.cbSize = sizeof(BandInfo); BandInfo.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE; BandInfo.fStyle = RBBS_FIXEDSIZE; BandInfo.hwndChild = Button; BandInfo.cxMinChild = Rect.right - Rect.left + 4 * GetSystemMetrics(SM_CXEDGE); BandInfo.cyMinChild = Rect.bottom - Rect.top + 2 * GetSystemMetrics(SM_CYEDGE); SendMessage(Bar, RB_INSERTBAND, -1, (LPARAM)&BandInfo); return Button; }