/*****************************************************************************\ * * Module: dialogs.c * * Contains dialog procs for the Windows debugging Spy SDK applet. * * History: * \*****************************************************************************/ #include "spy.h" #include #define DINV 3 PRIVATE HWND ghwndSpyingOnTemp; // Temp when selecting hwnd to spy on. PRIVATE HWND ghwndDlgBeingFilled = NULL; PRIVATE BOOL bBorderOn = FALSE; PRIVATE INT gcItemsSave; PRIVATE BOOL SelectWindowCommand(HWND hwnd, INT nCmd, INT nNotifyCode); PRIVATE VOID FillListBox(HWND hDlg, HWND hwndList, HWND hwnd); BOOL CALLBACK AddOneWindow(HWND hwnd, LPARAM hwndListLP); PRIVATE VOID MakeWindowName(HWND hwnd, LPSTR lpString, INT nStringLen); PRIVATE INT FindHwndInListBox(HWND hwndList, HWND hSpyWnd); PRIVATE VOID HighlightWindow(HWND hwnd, BOOL fDraw); PRIVATE VOID SelectWindowUpdateInfo(HWND hDlg, HWND hwnd); PRIVATE VOID SelectWindowEnableFields(HWND hwnd, BOOL fEnable); PRIVATE BOOL OutputCommand(HWND hwnd, INT nCmd, INT nNotifyCode); PRIVATE VOID MessagesInit(HWND hwnd); PRIVATE BOOL MessagesCommand(HWND hwnd, INT nCmd, INT nNotifyCode); PRIVATE VOID MessagesUpdateCheckBoxes(HWND hwnd); // BUGBUG - If the console window class name ever changes, we must update // this string as well! CHAR szConsoleWindowClass[] = "ConsoleWindowClass"; /*****************************************************************************\ * MyDialogBox * * Puts up the specified dialog. * * Arguments: * INT idDlg - The resource id of the dialog to display. * DLGPROC pfnDlgProc - The dialog proc to use. * * Returns: * The return value from DialogBox (whatever the dialog proc passes * to EndDialog). * \*****************************************************************************/ BOOL MyDialogBox( INT idDlg, DLGPROC pfnDlgProc ) { return DialogBox(ghInst, MAKEINTRESOURCE(idDlg), ghwndSpyApp, pfnDlgProc); } /*****************************************************************************\ * AboutDlgProc * * Dialog proc for the About box. * \*****************************************************************************/ BOOL CALLBACK AboutDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch (msg) { case WM_INITDIALOG: return TRUE; case WM_COMMAND: EndDialog(hwnd, IDOK); break; } return FALSE; } /*****************************************************************************\ * SelectWindowDlgProc * * Dialog proc for the Select Window dialog. This dialog allows the user * to select which window they want to spy on. * \*****************************************************************************/ BOOL CALLBACK SelectWindowDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { HWND hwndList; INT nIndex; UNREFERENCED_PARAMETER(lParam); switch (msg) { case WM_INITDIALOG: hwndList = GetDlgItem(hwnd, DID_SELWINLIST); ghwndSpyingOnTemp = ghwndSpyingOn == HWND_ALL ? NULL : (ghwndSpyingOn == NULL ? NULL : GetParent(ghwndSpyingOn)); FillListBox(hwnd, hwndList, ghwndSpyingOnTemp); nIndex = FindHwndInListBox(hwndList, ghwndSpyingOn == HWND_ALL ? NULL : ghwndSpyingOn); SendMessage(hwndList, LB_SETCURSEL, nIndex, 0); ghwndSpyingOnTemp = (HWND)SendMessage(hwndList, LB_GETITEMDATA, nIndex, 0); SelectWindowUpdateInfo(hwnd, ghwndSpyingOnTemp); CheckDlgButton(hwnd, DID_SELWINALLWINDOWS, gfSpyAll); SelectWindowEnableFields(hwnd, !gfSpyAll); SetFocus(hwnd); HighlightWindow(ghwndSpyingOnTemp, TRUE); return TRUE; case WM_NCLBUTTONDOWN: if (wParam == HTCAPTION) { // // The mouse is down for a move of the dialog, so clean up the // border stuff. // if (bBorderOn) HighlightWindow(ghwndSpyingOnTemp, FALSE); } return FALSE; case WM_KEYDOWN: case WM_LBUTTONUP: case WM_NCLBUTTONUP: // // The mouse is up from a move of the dialog, so put up the // border stuff again. // if (!bBorderOn) HighlightWindow(ghwndSpyingOnTemp, TRUE); return FALSE; case WM_CANCELMODE: return FALSE; case WM_COMMAND: return SelectWindowCommand(hwnd, LOWORD(wParam), HIWORD(wParam)); } return FALSE; } /*****************************************************************************\ * SelectWindowCommand * * Handles thw WM_COMMAND messages for the Select Window dialog. * * Arguments: * HWND hwnd - Window handle of the dialog. * INT nCmd - Command value. * INT nNotifyCode - The notify code. * * Returns: * The value that the dialog proc should return, based on the processing * of the specific WM_COMMAND message received. * \*****************************************************************************/ PRIVATE BOOL SelectWindowCommand( HWND hwnd, INT nCmd, INT nNotifyCode ) { INT nIndex; HWND hwndList; CHAR rgString[32]; switch (nCmd) { case IDOK: SetWindowToSpyOn(IsDlgButtonChecked(hwnd, DID_SELWINALLWINDOWS) ? HWND_ALL : ghwndSpyingOnTemp); if (bBorderOn) HighlightWindow(ghwndSpyingOnTemp, FALSE); EndDialog(hwnd, IDOK); return TRUE; case IDCANCEL: if (bBorderOn) HighlightWindow(ghwndSpyingOnTemp, FALSE); EndDialog(hwnd, IDCANCEL); return TRUE; case DID_SELWINLIST: // // User single clicked or doubled clicked in listbox - // Single click means select a window to spy on // Double click means enumerate all the children of that window. // hwndList = GetDlgItem(hwnd, DID_SELWINLIST); switch (nNotifyCode) { case LBN_SELCHANGE: // // Single click case. Select a window to spy upon. // // Get the window handle, set it as the window to spy on. // if (bBorderOn) HighlightWindow(ghwndSpyingOnTemp, FALSE); nIndex = (INT)SendMessage(hwndList, LB_GETCURSEL, 0, 0); ghwndSpyingOnTemp = (HWND)SendMessage(hwndList, LB_GETITEMDATA, nIndex, 0); SelectWindowUpdateInfo(hwnd, ghwndSpyingOnTemp); HighlightWindow(ghwndSpyingOnTemp, TRUE); break; case LBN_DBLCLK: // // Double click case - first click has already been // processed as single click. In this case, the user has // requested to look at all the children of a given // selection. // // Get the current selection, and check to see if it is the // " [ parent.. ]" entry. If so, go up one level first. // SetCursor(LoadCursor(NULL, IDC_WAIT)); if (bBorderOn) HighlightWindow(ghwndSpyingOnTemp, FALSE); nIndex = (INT)SendMessage(hwndList, LB_GETCURSEL, 0, 0); ghwndSpyingOnTemp = (HWND)SendMessage(hwndList, LB_GETITEMDATA, nIndex, 0); SendMessage(hwndList, LB_GETTEXT, nIndex, (LPARAM)rgString); if (rgString[0] == ' ') { // At top? If so, we are done. if (ghwndSpyingOnTemp == NULL) { SetCursor(LoadCursor(NULL, IDC_ARROW)); break; } ghwndSpyingOnTemp = GetParent(ghwndSpyingOnTemp); } SendMessage(hwndList, LB_RESETCONTENT, 0, 0); FillListBox(hwnd, hwndList, ghwndSpyingOnTemp); nIndex = FindHwndInListBox(hwndList, ghwndSpyingOnTemp); SendMessage(hwndList, LB_SETCURSEL, nIndex, 0); ghwndSpyingOnTemp = (HWND)SendMessage(hwndList, LB_GETITEMDATA, nIndex, 0); HighlightWindow(ghwndSpyingOnTemp,TRUE); SelectWindowUpdateInfo(hwnd, ghwndSpyingOnTemp); SetCursor(LoadCursor(NULL, IDC_ARROW)); break; } break; case DID_SELWINALLWINDOWS: SelectWindowEnableFields(hwnd, !IsDlgButtonChecked(hwnd, DID_SELWINALLWINDOWS)); break; } return FALSE; } /*****************************************************************************\ * FillListBox * * Fills the listbox in the Select Window dialog with the names of * the child windows of the given window. * * Arguments: * hDlg - Window handle of the dialog window * hwndList - Handle to the listbox within the dialog. * hwnd - Parent whose children to enumerate. * * Returns: * VOID * \*****************************************************************************/ PRIVATE VOID FillListBox( HWND hDlg, HWND hwndList, HWND hwnd ) { INT nIndex; // // First fill the list box with child windows // // Make sure we display the list box after things are added. // SendMessage(hwndList, WM_SETREDRAW, 0, 0); // // remember which dialog we are processing // ghwndDlgBeingFilled = hDlg; if (hwnd == NULL) { // // Enumerate the top level separately... gross unsymmetry, but // hey. // EnumWindows(AddOneWindow, (LPARAM)hwndList); } else { EnumChildWindows(hwnd, AddOneWindow, (LPARAM)hwndList); } // // Now give the user a method of getting back to the parent. The space at // the beginning of the " [parent]" string identifies the entry as the // parent entry and makes it different from all the other entries since // the others start with a handle number of some sort. // nIndex = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR)LoadResourceString(IDS_PARENT)); SendMessage(hwndList, LB_SETITEMDATA, nIndex, (LONG)hwnd); // // Now do the redraw... // SendMessage(hwndList, WM_SETREDRAW, 1, 0); } /*****************************************************************************\ * AddOneWindow * * * * Arguments: * * * * Returns: * * \*****************************************************************************/ #define CCH_RGBUF 32 BOOL CALLBACK AddOneWindow( HWND hwnd, LPARAM hwndListLP ) { CHAR rgBuf[CCH_RGBUF]; INT nIndex; HWND htemp; HWND hwndList = (HWND)hwndListLP; // // Make sure we don't add any window that has anything to do with // the dialog or any other spy window // htemp = GetParent(hwnd); // Don't put console windows in the list since they can not be hooked if (GetClassName(hwnd, rgBuf, CCH_RGBUF) != 0 && strcmp(rgBuf, szConsoleWindowClass) == 0 ) { return 1; } // Don't put windows that belong to spy in the list if (hwnd == ghwndDlgBeingFilled || htemp == ghwndDlgBeingFilled || hwnd == ghwndSpyApp || htemp == ghwndSpyApp || hwnd == ghwndPrintf || htemp == ghwndPrintf || hwnd == ghwndSpyHook || htemp == ghwndSpyHook) { return 1; } MakeWindowName(hwnd, rgBuf, CCH_RGBUF); nIndex = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)rgBuf); if (nIndex == LB_ERR || nIndex == LB_ERRSPACE) return 0; if (SendMessage(hwndList, LB_SETITEMDATA, nIndex, (LPARAM)hwnd) == LB_ERR) return 0; return 1; } /*****************************************************************************\ * MakeWindowName * * * * Arguments: * * * * Returns: * * \*****************************************************************************/ PRIVATE VOID MakeWindowName( HWND hwnd, LPSTR lpString, INT nStringLen ) { wsprintf(lpString, "%8.8lX:", hwnd); if (hwnd == NULL || !IsWindow(hwnd)) { lstrcat(lpString, "!!!"); } else { GetWindowText(hwnd, lpString + 9, nStringLen - 9); } } /*****************************************************************************\ * FindHwndInListBox * * * * Arguments: * * * * Returns: * * \*****************************************************************************/ PRIVATE INT FindHwndInListBox( HWND hwndList, HWND hSpyWnd ) { CHAR rgBuf[9]; INT nIndex; wsprintf(rgBuf, "%08lX", (LONG)hSpyWnd); nIndex = SendMessage(hwndList, LB_FINDSTRING, (WPARAM)-1, (LPARAM)rgBuf); if (nIndex == LB_ERR) nIndex = 0; return nIndex; } /*****************************************************************************\ * HighlightWindow * * Used to temporarily highlight the window that the user has selected from * the Select Window dialog. It does this by inverting a border around the * window. * * Arguments: * * * * Returns: * * \*****************************************************************************/ PRIVATE VOID HighlightWindow( HWND hwnd, BOOL fDraw ) { HDC hdc; RECT rc; bBorderOn = fDraw; if (hwnd == NULL || !IsWindow(hwnd)) return; hdc = GetWindowDC(hwnd); GetWindowRect(hwnd, &rc); OffsetRect(&rc, -rc.left, -rc.top); if (!IsRectEmpty(&rc)) { PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, DINV, DSTINVERT); PatBlt(hdc, rc.left, rc.bottom - DINV, DINV, -(rc.bottom - rc.top - 2 * DINV), DSTINVERT); PatBlt(hdc, rc.right - DINV, rc.top + DINV, DINV, rc.bottom - rc.top - 2 * DINV, DSTINVERT); PatBlt(hdc, rc.right, rc.bottom - DINV, -(rc.right - rc.left), DINV, DSTINVERT); } ReleaseDC(hwnd, hdc); } /*****************************************************************************\ * SelectWindowUpdateInfo * * Updates the informational fields in the Select Window dialog when * a new window is selected from the hwnd listbox. * * Arguments: * * * * Returns: * * \*****************************************************************************/ PRIVATE VOID SelectWindowUpdateInfo( HWND hDlg, HWND hwnd ) { HWND hParent; DWORD dwStyle; RECT rc; CHAR szTemp[MAXSTRING]; if (hwnd) { hParent = GetParent(hwnd); dwStyle = GetWindowLong(hwnd, GWL_STYLE); MakeWindowName(hwnd, szTemp, MAXSTRING); SetDlgItemText(hDlg, DID_SELWINWINDOW, szTemp); GetClassName(hwnd, szTemp, MAXSTRING); SetDlgItemText(hDlg, DID_SELWINCLASS, szTemp); if (hParent) { MakeWindowName(hParent, szTemp, MAXSTRING); SetDlgItemText(hDlg, DID_SELWINPARENT, szTemp); } else { SetDlgItemText(hDlg, DID_SELWINPARENT, LoadResourceString(IDS_NOPARENT)); } GetWindowRect(hwnd, &rc); wsprintf(szTemp, "(%d,%d)-(%d,%d) %dx%d", rc, rc.right-rc.left, rc.bottom-rc.top); SetDlgItemText(hDlg, DID_SELWINRECT, szTemp); if (dwStyle & WS_POPUP) wsprintf (szTemp, "%08lX: WS_POPUP", dwStyle); else if (dwStyle & WS_CHILD) wsprintf (szTemp, "%08lX: WS_CHILD, ID: %lX", dwStyle, GetWindowLong(hwnd, GWL_ID)); else if (dwStyle & WS_ICONIC) wsprintf (szTemp, "%08lX: WS_ICONIC", dwStyle); else wsprintf (szTemp, "%08lX: WS_OVERLAPPED", dwStyle); SetDlgItemText(hDlg, DID_SELWINSTYLE, szTemp); } else { TCHAR lpBuf[256]; LoadString(GetModuleHandle(NULL), IDS_UNDEFINED, lpBuf, sizeof(lpBuf)); SetDlgItemText(hDlg, DID_SELWINWINDOW, lpBuf); SetDlgItemText(hDlg, DID_SELWINCLASS, lpBuf); SetDlgItemText(hDlg, DID_SELWINPARENT, lpBuf); SetDlgItemText(hDlg, DID_SELWINRECT, lpBuf); SetDlgItemText(hDlg, DID_SELWINSTYLE, lpBuf); } } /*****************************************************************************\ * SelectWindowEnableFields * * Enables/disables the different fields in the Select Window dialog * based on whether the user wants to spy on all windows or individually * select one. * * Arguments: * HWND hwnd - Dialog window handle. * BOOL fEnable - TRUE to enable the fields, FALSE to disable them. * \*****************************************************************************/ PRIVATE VOID SelectWindowEnableFields( HWND hwnd, BOOL fEnable ) { EnableWindow(GetDlgItem(hwnd, DID_SELWINLIST), fEnable); EnableWindow(GetDlgItem(hwnd, DID_SELWINWINDOW), fEnable); EnableWindow(GetDlgItem(hwnd, DID_SELWINCLASS), fEnable); EnableWindow(GetDlgItem(hwnd, DID_SELWINPARENT), fEnable); EnableWindow(GetDlgItem(hwnd, DID_SELWINRECT), fEnable); EnableWindow(GetDlgItem(hwnd, DID_SELWINSTYLE), fEnable); } /*****************************************************************************\ * OutputDlgProc * * Dialog proc for the Output dialog. * \*****************************************************************************/ BOOL CALLBACK OutputDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch (msg) { case WM_INITDIALOG: CheckDlgButton(hwnd, DID_OUTPUTWINDOW, gfOutputWin); CheckDlgButton(hwnd, DID_OUTPUTCOM1, gfOutputCom1); CheckDlgButton(hwnd, DID_OUTPUTFILE, gfOutputFile); SetDlgItemText(hwnd, DID_OUTPUTFILENAME, gszFile); SetDlgItemInt(hwnd, DID_OUTPUTLINES, gnLines, FALSE); return TRUE; case WM_COMMAND: return OutputCommand(hwnd, LOWORD(wParam), HIWORD(wParam)); } return FALSE; } /*****************************************************************************\ * OutputCommand * * Handles the WM_COMMAND messages for the Output dialog. * * Arguments: * HWND hwnd - Window handle of the dialog. * INT nCmd - Command value. * INT nNotifyCode - The notify code. * * Returns: * The value that the dialog proc should return, based on the processing * of the specific WM_COMMAND message received. * \*****************************************************************************/ PRIVATE BOOL OutputCommand( HWND hwnd, INT nCmd, INT nNotifyCode ) { HFILE fh; INT i; CHAR szTemp[MAXSTRING]; switch (nCmd) { case IDOK: i = GetDlgItemInt(hwnd, DID_OUTPUTLINES, &i, FALSE); if (i != gnLines) { if ( i > 0 && i <= LINES_MAX) { gnLines = i; MyCreatePrintfWin(ghwndSpyApp); } else { Message(MB_OK | MB_ICONEXCLAMATION, LoadResourceString(IDS_ERROR_WND_LINE), LINES_MAX); SetFocus(GetDlgItem(hwnd, DID_OUTPUTLINES)); break; } } gfOutputWin = IsDlgButtonChecked(hwnd, DID_OUTPUTWINDOW); gfOutputCom1 = IsDlgButtonChecked(hwnd, DID_OUTPUTCOM1); gfOutputFile = IsDlgButtonChecked(hwnd, DID_OUTPUTFILE); if (gfOutputFile) { GetDlgItemText(hwnd, DID_OUTPUTFILENAME, szTemp, MAXSTRING); /* * If they changed the filename, or the file is not open * then open it. */ if (lstrcmp(gszFile, szTemp) != 0 || gfhFile == 0) { fh = _lcreat(szTemp, 0); if (fh == (HFILE)(-1)) { if (Message(MB_OKCANCEL | MB_ICONEXCLAMATION, LoadResourceString(IDS_ERROR_CANT_OPEN_FILE), szTemp) == IDCANCEL) { EndDialog(hwnd, FALSE); } return TRUE; } lstrcpy(gszFile, szTemp); if (gfhFile) _lclose(gfhFile); gfhFile = fh; } } else { if (gfhFile) { _lclose(gfhFile); gfhFile = 0; } } #ifdef JAPAN // DBCS_FIX if (gfOutputCom1) { if (gfhCom1 != INVALID_HANDLE_VALUE) CloseHandle(gfhCom1); gfhCom1 = CreateFile( "com1", GENERIC_WRITE, 0, // exclusive access NULL, // no security attrs OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (gfhCom1 == INVALID_HANDLE_VALUE) { if (Message(MB_OKCANCEL | MB_ICONEXCLAMATION, LoadResourceString(IDS_ERROR_CANT_OPEN_COM1)) == IDCANCEL) { EndDialog(hwnd, FALSE); } return TRUE; } } else { if (gfhCom1 != INVALID_HANDLE_VALUE) { CloseHandle(gfhCom1); } } #endif // JAPAN --- DBCS_FIX EndDialog(hwnd, TRUE); return TRUE; case IDCANCEL: EndDialog(hwnd, FALSE); return TRUE; } return FALSE; } /*****************************************************************************\ * SelectFont * * Allows the user to select a new font for the display. * \*****************************************************************************/ VOID SelectFont( VOID ) { CHOOSEFONT cf; LOGFONT lf; HFONT hfontNew; GetObject(ghfontPrintf, sizeof(LOGFONT), (LPVOID)&lf); cf.lStructSize = sizeof(cf); cf.hwndOwner = ghwndSpyApp; cf.hDC = NULL; cf.lpLogFont = &lf; cf.iPointSize = 0; cf.Flags = CF_ANSIONLY | CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS; cf.rgbColors = 0; cf.lCustData = 0; cf.lpfnHook = NULL; cf.lpTemplateName = NULL; cf.hInstance = NULL; cf.lpszStyle = NULL; cf.nFontType = 0; cf.nSizeMin = 0; cf.nSizeMax = 0; if (ChooseFont(&cf)) { if (hfontNew = CreateFontIndirect(&lf)) { SetPrintfFont(ghwndPrintf, hfontNew); ghfontPrintf = hfontNew; } } } /*****************************************************************************\ * MessagesDlgProc * * Dialog proc for the Messages dialog. This dialog allows the user * to select which messages they want to spy on. * \*****************************************************************************/ BOOL CALLBACK MessagesDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch (msg) { case WM_INITDIALOG: MessagesInit(hwnd); return TRUE; case WM_COMMAND: return MessagesCommand(hwnd, LOWORD(wParam), HIWORD(wParam)); } return FALSE; } /*****************************************************************************\ * MessagesInit * * * * Arguments: * HWND hwnd - Dialog window handle. * \*****************************************************************************/ PRIVATE VOID MessagesInit( HWND hwnd ) { HWND hwndList; INT i; INT j; INT iSel; PMSGDESC pmd; for (j = 0; j < gcMsgGroups; j++) gaMsgGroup[j].cUseCount = 0; hwndList = GetDlgItem(hwnd, DID_MSGSLIST); for (i = 0, pmd = gaMsgs; i < gcMessages; i++, pmd++) { iSel = (INT)SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)pmd->pszMsg); SendMessage(hwndList, LB_SETITEMDATA, iSel, (LPARAM)pmd); if (pmd->Flags & MTF_SELECTED) { SendMessage(hwndList, LB_SETSEL, TRUE, iSel); for (j = 0; j < gcMsgGroups; j++) { if (gaMsgGroup[j].flMask & pmd->Flags) gaMsgGroup[j].cUseCount++; } } } // // Set the selection rectangle to the first item in the listbox. // SendMessage(hwndList, LB_SETCARETINDEX, 0, FALSE); // // Loop through all the message groups. // for (j = 0; j < gcMsgGroups; j++) { // // Is at least one message in the group selected? // if (gaMsgGroup[j].cUseCount) { // // Check the corresponding checkbox. If all messages // in the group are selected, the checkbox is checked. // If only some are selected, the checkbox is set to // grayed (3-state). // CheckDlgButton(hwnd, gaMsgGroup[j].idCheckBox, (gaMsgGroup[j].cUseCount == gaMsgGroup[j].cMsgs) ? 1 : 2); } } if (gfMsgsUser) CheckDlgButton(hwnd, DID_MSGSUSER, 1); if (gfMsgsUnknown) CheckDlgButton(hwnd, DID_MSGSUNKNOWN, 1); gcItemsSave = SendMessage(hwndList, LB_GETSELITEMS, gcMessages, (LPARAM)gaiSelected); } /*****************************************************************************\ * MessagesCommand * * Handles the WM_COMMAND messages for the Messages dialog. * * Arguments: * HWND hwnd - Window handle of the dialog. * INT nCmd - Command value. * INT nNotifyCode - The notify code. * * Returns: * The value that the dialog proc should return, based on the processing * of the specific WM_COMMAND message received. * \*****************************************************************************/ PRIVATE BOOL MessagesCommand( HWND hwnd, INT nCmd, INT nNotifyCode ) { INT i; INT j; PMSGGROUP pmg; PMSGDESC pmd; BOOL fChecked; HWND hwndList; INT cItems; BOOL fSel; INT iSel; INT cSelItemsMax; INT iTopIndex; switch (nCmd) { case DID_MSGSLIST: if (nNotifyCode == LBN_SELCHANGE) { hwndList = GetDlgItem(hwnd, DID_MSGSLIST); cItems = SendMessage(hwndList, LB_GETSELITEMS, gcMessages, (LPARAM)gaiSelected2); if (cItems == gcItemsSave) { // // Nothing changed except for the selection // rectangle moving. We are done. // break; } if (cItems > gcItemsSave) { // // A message was selected. Look for it. // for (i = 0; i < gcItemsSave && gaiSelected[i] == gaiSelected2[i]; i++) ; iSel = gaiSelected2[i]; fSel = TRUE; } else { // // A message was unselected. Look for it. // for (i = 0; i < cItems && gaiSelected[i] == gaiSelected2[i]; i++) ; iSel = gaiSelected[i]; fSel = FALSE; } // // Get the currently selected item. It was either // just turned on or off. // pmd = (PMSGDESC)SendMessage(hwndList, LB_GETITEMDATA, iSel, 0); // // Loop through the message groups and update the use // counts for all groups that contain this message. // for (i = 0; i < gcMsgGroups; i++) { if (pmd->Flags & gaMsgGroup[i].flMask) { gaMsgGroup[i].cUseCount += fSel ? 1 : -1; } } // // Be sure that the checkboxes reflect the updated // status of the message group use counts. // MessagesUpdateCheckBoxes(hwnd); // // Save away the new selected item array. // cSelItemsMax = max(cItems, gcItemsSave); for (i = 0; i < cSelItemsMax; i++) { gaiSelected[i] = gaiSelected2[i]; } gcItemsSave = cItems; } break; case DID_MSGSALL: hwndList = GetDlgItem(hwnd, DID_MSGSLIST); SendMessage(hwndList, LB_SETSEL, TRUE, (LPARAM)-1); for (i = 0; i < gcMsgGroups; i++) { gaMsgGroup[i].cUseCount = gaMsgGroup[i].cMsgs; CheckDlgButton(hwnd, gaMsgGroup[i].idCheckBox, 1); } gcItemsSave = SendMessage(hwndList, LB_GETSELITEMS, gcMessages, (LPARAM)gaiSelected); CheckDlgButton(hwnd, DID_MSGSUSER, 1); CheckDlgButton(hwnd, DID_MSGSUNKNOWN, 1); break; case DID_MSGSNONE: hwndList = GetDlgItem(hwnd, DID_MSGSLIST); SendMessage(hwndList, LB_SETSEL, FALSE, (LPARAM)-1); for (i = 0; i < gcMsgGroups; i++) { gaMsgGroup[i].cUseCount = 0; CheckDlgButton(hwnd, gaMsgGroup[i].idCheckBox, 0); } gcItemsSave = 0; CheckDlgButton(hwnd, DID_MSGSUSER, 0); CheckDlgButton(hwnd, DID_MSGSUNKNOWN, 0); break; case DID_MSGSDDE: case DID_MSGSCLIP: case DID_MSGSMOUSE: case DID_MSGSNC: case DID_MSGSKEYBD: #ifdef FE_IME case DID_MSGSIME: #endif case DID_MSGSBM: case DID_MSGSCB: case DID_MSGSEM: case DID_MSGSLB: case DID_MSGSSTM: for (i = 0; i < gcMsgGroups; i++) { if (gaMsgGroup[i].idCheckBox == nCmd) { pmg = &gaMsgGroup[i]; break; } } fChecked = IsDlgButtonChecked(hwnd, pmg->idCheckBox); if (fChecked == 1) fChecked = FALSE; else fChecked = TRUE; hwndList = GetDlgItem(hwnd, DID_MSGSLIST); if (fChecked) { SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); iTopIndex = SendMessage(hwndList, LB_GETTOPINDEX, 0, 0); } // // Get the list of currently selected items. // cItems = SendMessage(hwndList, LB_GETSELITEMS, gcMessages, (LPARAM)gaiSelected); // // Look for all the messages in this group. // for (i = 0, iSel = 0; i < gcMessages; i++) { pmd = (PMSGDESC)SendMessage(hwndList, LB_GETITEMDATA, i, 0); if (pmd->Flags & pmg->flMask) { // // Bump up through the list of selected items, looking // to see if this item is currently selected. // for (fSel = FALSE; iSel < cItems && gaiSelected[iSel] <= i; iSel++) { // // A match was found. The item is selected. // if(gaiSelected[iSel] == i) { fSel = TRUE; break; } } // // Is the current selection state of the item // different from the desired selection state? // if (fSel != fChecked) { // // Update the use counts of all groups that contain // this message. // for (j = 0; j < gcMsgGroups; j++) { if (pmd->Flags & gaMsgGroup[j].flMask) { gaMsgGroup[j].cUseCount += fChecked ? 1 : -1; } } // // Select/deselect the message in the list box. // SendMessage(hwndList, LB_SETSEL, fChecked, i); } } } // // Be sure that the checkboxes reflect the updated // status of the message group use counts. // MessagesUpdateCheckBoxes(hwnd); if (fChecked) { SendMessage(hwndList, LB_SETTOPINDEX, iTopIndex, 0); SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); InvalidateRect(hwndList, NULL, FALSE); } gcItemsSave = SendMessage(hwndList, LB_GETSELITEMS, gcMessages, (LPARAM)gaiSelected); break; case IDOK: hwndList = GetDlgItem(hwnd, DID_MSGSLIST); cItems = SendMessage(hwndList, LB_GETSELITEMS, gcMessages, (LPARAM)gaiSelected); // // Unselect all messages. // for (i = 0; i < gcMessages; i++) gaMsgs[i].Flags &= ~MTF_SELECTED; // // Mark all the messages that are selected. // for (i = 0; i < cItems; i++) { pmd = (PMSGDESC)SendMessage(hwndList, LB_GETITEMDATA, gaiSelected[i], 0); pmd->Flags |= MTF_SELECTED; } if (IsDlgButtonChecked(hwnd, DID_MSGSUSER)) gfMsgsUser = TRUE; else gfMsgsUser = FALSE; if (IsDlgButtonChecked(hwnd, DID_MSGSUNKNOWN)) gfMsgsUnknown = TRUE; else gfMsgsUnknown = FALSE; #if 0 //Debug code! for (i = 0; i < gcMsgGroups; i++) { iSel = 0; for (j = 0; j < cItems; j++) { pmd = (PMSGDESC)SendMessage(hwndList, LB_GETITEMDATA, gaiSelected[j], 0); if (pmd->Flags & gaMsgGroup[i].flMask) iSel++; } if (iSel != gaMsgGroup[i].cUseCount) { DbgPrintf("Use counts are wrong!!!"); for (j = 0; j < gcMsgGroups; j++) { DbgPrintf("cMsgs:%d Use:%d", gaMsgGroup[j].cMsgs, gaMsgGroup[j].cUseCount); } } } #endif //BUGBUG end debug code EndDialog(hwnd, IDOK); return TRUE; case IDCANCEL: EndDialog(hwnd, IDCANCEL); return TRUE; } return FALSE; } /*****************************************************************************\ * MessagesUpdateCheckBoxes * * Updates the message group checkboxes in the Messages dialog. * This routine should be called when the use counts in the * message group table are changed, so that the state of the * checkboxes will get updated also. * * Arguments: * HWND hwnd - Dialog window handle. * \*****************************************************************************/ PRIVATE VOID MessagesUpdateCheckBoxes( HWND hwnd ) { INT i; INT fState; for (i = 0; i < gcMsgGroups; i++) { if (gaMsgGroup[i].cUseCount == gaMsgGroup[i].cMsgs) fState = 1; else if (gaMsgGroup[i].cUseCount == 0) fState = 0; else fState = 2; CheckDlgButton(hwnd, gaMsgGroup[i].idCheckBox, fState); } }