/****************************************************************************** Copyright (c) 2000 Microsoft Corporation Module Name: pfrscpl.cpp Abstract: Implements fault reporting for unhandled exceptions Revision History: created derekm 08/07/00 ******************************************************************************/ #include "sysdm.h" #include #include #include #include "pfrscpl.h" #include "pfrcfg.h" #include "help.h" #include "resource.h" #include "malloc.h" #include "windowsx.h" /////////////////////////////////////////////////////////////////////////////// // data structures #define KERNELLI 1 #define PROGLI 2 #define EXWINCOMP 0x80000000 #define EXALLMS 0x40000000 #define EXNOREM 0xc0000000 // EXWINCOMP | EXALLMS #define WM_SETEIELVSEL WM_APP const DWORD c_dxLVChkPixels = 30; struct SAddDlg { WCHAR wszApp[MAX_PATH]; }; struct SMainDlg { CPFFaultClientCfg *pcfg; EEnDis eedReport; EEnDis eedShowUI; EIncEx eieKernel; EIncEx eieApps; EIncEx eieShut; DWORD iLastSel; BOOL fRW; BOOL fForceQueue; }; struct SProgDlg { CPFFaultClientCfg *pcfg; EIncEx eieApps; EIncEx eieMS; EIncEx eieWinComp; DWORD iLastSelE; DWORD iLastSelI; DWORD cchMax; DWORD cxMaxE; DWORD cxMaxI; BOOL fRW; BOOL fShowIncRem; }; /////////////////////////////////////////////////////////////////////////////// // Global stuff // help IDs static DWORD g_rgPFER[] = { IDC_STATIC, NO_HELP, IDC_PFR_EXADD, (IDH_PFR), IDC_PFR_EXREM, (IDH_PFR + 1), IDC_PFR_INCADD, (IDH_PFR + 2), IDC_PFR_INCREM, (IDH_PFR + 3), IDC_PFR_DISABLE, (IDH_PFR + 4), IDC_PFR_ENABLE, (IDH_PFR + 5), IDC_PFR_ENABLEOS, (IDH_PFR + 6), IDC_PFR_ENABLEPROG, (IDH_PFR + 6), IDC_PFR_DETAILS, (IDH_PFR + 7), IDC_PFR_INCLIST, (IDH_PFR + 10), IDC_PFR_NEWPROG, (IDH_PFR + 11), IDC_PFR_BROWSE, (IDH_PFR + 13), IDC_PFR_EXLIST, (IDH_PFR + 14), IDC_PFR_SHOWUI, (IDH_PFR + 15), IDC_PFR_DEFALL, (IDH_PFR + 16), IDC_PFR_DEFNONE, (IDH_PFR + 16), IDC_PFR_ENABLESHUT, (IDH_PFR + 17), IDC_PFR_FORCEQ, (IDH_PFR + 18), 0, 0 }; // resource strings TCHAR g_szWinComp[256] = { TEXT('\0') }; TCHAR g_szOk[256] = { TEXT('\0') }; WCHAR g_wszTitle[256] = { L'\0' }; WCHAR g_wszFilter[256] = { L'\0' }; WCHAR g_wszMSProg[256] = { L'\0' }; /////////////////////////////////////////////////////////////////////////////// // utility functions // ************************************************************************** BOOL LoadPFRResourceStrings(void) { LoadString(hInstance, IDS_PFR_WINCOMP, g_szWinComp, ARRAYSIZE(g_szWinComp)); LoadString(hInstance, IDS_PFR_OK, g_szOk, ARRAYSIZE(g_szOk)); LoadStringW(hInstance, IDS_PFR_FILTER, g_wszFilter, ARRAYSIZE(g_wszFilter)); LoadStringW(hInstance, IDS_PFR_MSPROG, g_wszMSProg, ARRAYSIZE(g_wszMSProg)); LoadStringW(hInstance, IDS_PFR_TITLE, g_wszTitle, ARRAYSIZE(g_wszTitle)); return TRUE; } // ************************************************************************** static BOOL InitializePFLV(EPFListType epflt, HWND hlc, DWORD *pcchMax, DWORD *pcxMax, CPFFaultClientCfg *pcfg) { LVCOLUMN lvc; LVITEMW lvi; HRESULT hr; LPWSTR wszApp; DWORD dwExStyle, i, cchApps, cApps, dwChecked, cxMax; RECT rect; int iList; if (pcchMax == NULL || pcfg == NULL || hlc == NULL || pcxMax == NULL) return FALSE; // set up the list control SendMessage(hlc, LVM_SETUNICODEFORMAT, TRUE, 0); dwExStyle = (LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT); SendMessage(hlc, LVM_SETEXTENDEDLISTVIEWSTYLE, dwExStyle, dwExStyle); GetClientRect(hlc, &rect); *pcxMax = rect.right - GetSystemMetrics(SM_CYHSCROLL); ZeroMemory(&lvc, sizeof(lvc)); lvc.mask = LVCF_FMT; lvc.fmt = LVCFMT_LEFT; ListView_InsertColumn(hlc, 0, &lvc); hr = pcfg->InitList(epflt); if (FAILED(hr)) return FALSE; hr = pcfg->get_ListRegInfo(epflt, &cchApps, &cApps); if (FAILED(hr)) return FALSE; cchApps++; if (cchApps > *pcchMax) *pcchMax = cchApps; __try { wszApp = (LPWSTR)_alloca(cchApps * sizeof(WCHAR)); } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW) { wszApp = NULL; _resetstkoflw(); } if (wszApp == NULL) return FALSE; ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; lvi.stateMask = LVIS_STATEIMAGEMASK; lvi.state = 0; lvi.pszText = wszApp; for (i = 0; i < cApps; i++) { hr = pcfg->get_ListRegApp(epflt, i, wszApp, cchApps + 1, &dwChecked); if (FAILED(hr)) return FALSE; cxMax = (DWORD)SendMessageW(hlc, LVM_GETSTRINGWIDTHW, 0, (LPARAM)wszApp); cxMax += c_dxLVChkPixels; if (cxMax > *pcxMax) *pcxMax = cxMax; lvi.iItem = i; lvi.lParam = 1 + ((dwChecked == 1) ? 1 : 0); iList = (int)SendMessageW(hlc, LVM_INSERTITEMW, 0, (LPARAM)&lvi); if (iList >= 0) ListView_SetCheckState(hlc, iList, (dwChecked == 1)); } ListView_SetColumnWidth(hlc, 0, *pcxMax); if (cApps > 0) { ListView_SetItemState(hlc, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } return TRUE; } /////////////////////////////////////////////////////////////////////////////// // Add Program dialog proc // ************************************************************************** static UINT_PTR CALLBACK OFNHookProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { HWND hwndFile; switch(uMsg) { case WM_INITDIALOG: hwndFile = GetParent(hdlg); if (hwndFile != NULL) SendMessage(hwndFile, CDM_SETCONTROLTEXT, IDOK, (LPARAM)g_szOk); return TRUE; default: return FALSE; } return FALSE; } // ************************************************************************** #define LAUNCHOFN_OFFSET 10 static BOOL LaunchOFNDialog(HWND hdlg, LPWSTR wszFile, DWORD cchFile) { OPENFILENAMEW ofn; WCHAR wszFilePath[2 * MAX_PATH]; WCHAR wszInitalDir[] = L"\\"; WCHAR wszFilter[MAX_PATH], *pwsz; DWORD dw; if (wszFile == NULL || cchFile == 0) { return FALSE; } // the filter string needs to be of the form \0\0\0 ZeroMemory(wszFilter, sizeof(wszFilter)); COMPILETIME_ASSERT(sizeof(wszFilter) >= sizeof(g_wszFilter)); // should always be bigger StringCchCopy(wszFilter, ARRAYSIZE(wszFilter), g_wszFilter); dw = wcslen(g_wszFilter); if (dw < (ARRAYSIZE(wszFilter) - LAUNCHOFN_OFFSET)) { pwsz = wszFilter + dw + 1; } else { pwsz = wszFilter + ARRAYSIZE(wszFilter) - LAUNCHOFN_OFFSET; ZeroMemory(pwsz, LAUNCHOFN_OFFSET * sizeof(WCHAR)); pwsz++; } EVAL(SUCCEEDED(StringCchCopy(pwsz, LAUNCHOFN_OFFSET, L"*.exe"))); // should always be room wszFilePath[0] = L'\0'; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hdlg; ofn.lpstrFilter = wszFilter; ofn.lpstrFile = wszFilePath; ofn.nMaxFile = ARRAYSIZE(wszFilePath); ofn.lpstrFileTitle = wszFile; ofn.nMaxFileTitle = cchFile; ofn.lpstrInitialDir = wszInitalDir; ofn.lpstrTitle = g_wszTitle; ofn.Flags = OFN_DONTADDTORECENT | OFN_ENABLESIZING | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_SHAREAWARE; ofn.lpstrDefExt = NULL; ofn.lpfnHook = OFNHookProc; // get the filename & fill in the edit box with it return GetOpenFileNameW(&ofn); } // ************************************************************************** static INT_PTR APIENTRY PFRAddDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BOOL fShowErr = FALSE; switch (uMsg) { case WM_INITDIALOG: { HWND hbtn; SetWindowLongPtr(hdlg, DWLP_USER, lParam); // disable the ok button cuz we know that we don't have anything // in the 'filename' edit box hbtn = GetDlgItem(hdlg, IDOK); if (hbtn != NULL) EnableWindow(hbtn, FALSE); } break; // F1 help case WM_HELP: WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP, (DWORD_PTR)g_rgPFER); break; // right-click help case WM_CONTEXTMENU: WinHelp((HWND)wParam, HELP_FILE, HELP_CONTEXTMENU, (DWORD_PTR)g_rgPFER); break; case WM_COMMAND: switch (LOWORD(wParam)) { // browse button case IDC_PFR_BROWSE: { WCHAR wszFile[2 * MAX_PATH]; // get the filename & fill in the edit box with it if (LaunchOFNDialog(hdlg, wszFile, ARRAYSIZE(wszFile))) SetDlgItemTextW(hdlg, IDC_PFR_NEWPROG, wszFile); break; } // Ok button case IDOK: { SAddDlg *psad; psad = (SAddDlg *)GetWindowLongPtr(hdlg, DWLP_USER); if (psad != NULL) { WCHAR *wszText, *pwsz; DWORD cch; HWND hwndText; BOOL fReplaceWSpace = TRUE; hwndText = GetDlgItem(hdlg, IDC_PFR_NEWPROG); if (hwndText == NULL) { fShowErr = TRUE; goto done; } cch = GetWindowTextLength(hwndText); if (cch == 0) { fShowErr = TRUE; goto done; } cch++; __try { wszText = (LPWSTR)_alloca(cch * sizeof(WCHAR)); } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW) { wszText = NULL; _resetstkoflw(); } if (wszText == NULL) { fShowErr = TRUE; goto done; } *psad->wszApp = L'\0'; *wszText = L'\0'; GetDlgItemTextW(hdlg, IDC_PFR_NEWPROG, wszText, cch); // make sure that we only have the exe name- probably // should verify that it IS an exe, but it's possible // we'd want to trap on other file types as well, so // don't for now. // And while we're at it, rip off any trailing // whitespace (preceeding whitespace is apparently ok) cch = wcslen(wszText); if (cch > 0) { for(pwsz = wszText + cch - 1; pwsz > wszText; pwsz--) { if (fReplaceWSpace) { if (iswspace(*pwsz)) *pwsz = L'\0'; else fReplaceWSpace = FALSE; } if (*pwsz == L'\\') { pwsz++; break; } } if (*pwsz == L'\\') pwsz++; } cch = wcslen(pwsz); if (cch >= MAX_PATH || cch == 0) { fShowErr = TRUE; goto done; } if (FAILED(StringCchCopy(psad->wszApp, ARRAYSIZE(psad->wszApp), pwsz))) { psad->wszApp[0] = L'\0'; } } EndDialog(hdlg, IDOK); break; } // cancel button case IDCANCEL: EndDialog(hdlg, IDCANCEL); break; case IDC_PFR_NEWPROG: if (HIWORD(wParam) == EN_CHANGE) { HWND hbtn, hedt; hbtn = GetDlgItem(hdlg, IDOK); hedt = (HWND)(DWORD_PTR)lParam; if (hedt != NULL && hbtn != NULL) { if (GetWindowTextLength(hedt) != 0) EnableWindow(hbtn, TRUE); else EnableWindow(hbtn, FALSE); } } break; // return FALSE to indicate that we didn't handle the msg default: return FALSE; } break; // return FALSE to indicate that we didn't handle the msg default: return FALSE; } done: if (fShowErr) { TCHAR szMsg[256]; LoadString(hInstance, IDS_PFR_BADFILE, szMsg, ARRAYSIZE(szMsg)); MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // Programs dialog proc // ************************************************************************** static BOOL InitProgDlg(HWND hdlg, SProgDlg *pspd) { CPFFaultClientCfg *pcfg; LVITEMW lvi; DWORD cxMax; HWND hlc, hbtn; BOOL fRet = FALSE; int iList, cItems; if (pspd == NULL) goto done; pcfg = pspd->pcfg; // fill in the exclude list hlc = GetDlgItem(hdlg, IDC_PFR_EXLIST); if (hlc == NULL) goto done; if (InitializePFLV(epfltExclude, hlc, &pspd->cchMax, &pspd->cxMaxE, pcfg) == FALSE) goto done; // fill in the include list hlc = GetDlgItem(hdlg, IDC_PFR_INCLIST); if (hlc == NULL) goto done; if (InitializePFLV(epfltInclude, hlc, &pspd->cchMax, &pspd->cxMaxI, pcfg) == FALSE) goto done; pspd->fShowIncRem = TRUE; // add the item to the include list that lets users include all MS apps pspd->eieMS = pcfg->get_IncMSApps(); // Note that we set lParam to 1 or 2. This is because we need to ignore // the first notification message for the list item + the 2nd one if the // check state is set. Processing these two messages leads to corruption // in the configuration settings ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; lvi.stateMask = LVIS_STATEIMAGEMASK; lvi.state = 0; lvi.pszText = g_wszMSProg; lvi.iItem = 0; lvi.lParam = (1 + ((pspd->eieMS == eieInclude) ? 1 : 0)) | EXALLMS; iList = (int)SendMessageW(hlc, LVM_INSERTITEMW, 0, (LPARAM)&lvi); if (iList >= 0) ListView_SetCheckState(hlc, iList, (pspd->eieMS == eieInclude)); cxMax = (DWORD)SendMessageW(hlc, LVM_GETSTRINGWIDTHW, 0, (LPARAM)g_wszMSProg); cxMax += c_dxLVChkPixels; if (cxMax > pspd->cxMaxI) { pspd->cxMaxI = cxMax; ListView_SetColumnWidth(hlc, 0, cxMax); } // add the item to the include list that lets users exclude all windows // components pspd->eieWinComp = pcfg->get_IncWinComp(); // Note that we set lParam to 1 or 2. This is because we need to ignore // the first notification message for the list item + the 2nd one if the // check state is set. Processing these two messages leads to corruption // in the configuration settings ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; lvi.stateMask = LVIS_STATEIMAGEMASK; lvi.state = 0; lvi.pszText = g_szWinComp; lvi.iItem = 1; lvi.lParam = (1 + ((pspd->eieWinComp == eieInclude) ? 1 : 0)) | EXWINCOMP; iList = (int)SendMessageW(hlc, LVM_INSERTITEMW, 0, (LPARAM)&lvi); if (iList >= 0) ListView_SetCheckState(hlc, iList, (pspd->eieWinComp == eieInclude)); cxMax = (DWORD)SendMessageW(hlc, LVM_GETSTRINGWIDTHW, 0, (LPARAM)g_szWinComp); cxMax += c_dxLVChkPixels; if (cxMax > pspd->cxMaxI) { pspd->cxMaxI = cxMax; ListView_SetColumnWidth(hlc, 0, cxMax); } // do misc setup on the exclusion list (disabling the remove button, // setting the initial focus) hlc = GetDlgItem(hdlg, IDC_PFR_EXLIST); cItems = ListView_GetItemCount(hlc); if (cItems == 0) { hbtn = GetDlgItem(hdlg, IDC_PFR_EXREM); if (hbtn != NULL) EnableWindow(hbtn, FALSE); } else { ListView_SetItemState(hlc, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } // do misc setup on the inclusion list (disabling the remove button, // setting the initial focus) hlc = GetDlgItem(hdlg, IDC_PFR_INCLIST); ListView_SetItemState(hlc, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); cItems = ListView_GetItemCount(hlc); if (cItems < 3) { hbtn = GetDlgItem(hdlg, IDC_PFR_INCREM); if (hbtn != NULL) EnableWindow(hbtn, FALSE); pspd->fShowIncRem = FALSE; } // set up the radio buttons- if we are in 'include all' mode, then // we don't need the inclusion list. if (((DWORD)pspd->eieApps & eieIncMask) == eieInclude) { CheckDlgButton(hdlg, IDC_PFR_DEFALL, BST_CHECKED); CheckDlgButton(hdlg, IDC_PFR_DEFNONE, BST_UNCHECKED); hlc = GetDlgItem(hdlg, IDC_PFR_INCLIST); if (hlc != NULL) EnableWindow(hlc, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_INCREM); if (hbtn != NULL) EnableWindow(hbtn, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_INCADD); if (hbtn != NULL) EnableWindow(hbtn, FALSE); } else { CheckDlgButton(hdlg, IDC_PFR_DEFALL, BST_UNCHECKED); CheckDlgButton(hdlg, IDC_PFR_DEFNONE, BST_CHECKED); EnableWindow(hlc, TRUE); } fRet = TRUE; done: if (fRet == FALSE) { TCHAR szMsg[MAX_PATH]; LoadString(hInstance, IDS_PFR_CFGREADERR, szMsg, ARRAYSIZE(szMsg)); MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); } return fRet; } // ************************************************************************** static BOOL AddProgramToList(HWND hdlg, HWND hlc, SProgDlg *pspd, EPFListType epflt) { CPFFaultClientCfg *pcfg = NULL; HRESULT hr; SAddDlg sad; LVITEMW lvi; DWORD cch, cxMax, *pcxMax; TCHAR szMsg[256]; HWND hbtn; int nID, cItems; if (pspd == NULL) return FALSE; pcfg = pspd->pcfg; ZeroMemory(&sad, sizeof(sad)); nID = (int)DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PFR_ADDPROG), hdlg, PFRAddDlgProc, (LPARAM)&sad); if (nID == IDCANCEL || sad.wszApp[0] == L'\0') return FALSE; if (pcfg->IsOnList(epfltInclude, sad.wszApp)) { LoadString(hInstance, IDS_PFR_ISONLISTI, szMsg, ARRAYSIZE(szMsg)); if (epflt == epfltExclude) { TCHAR szTmp[256]; LoadString(hInstance, IDS_PFR_ADDTOEX, szTmp, ARRAYSIZE(szTmp)); StringCchCat(szMsg, ARRAYSIZE(szMsg), szTmp); // display string, truncation ok } MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); return FALSE; } else if (pcfg->IsOnList(epfltExclude, sad.wszApp)) { LoadString(hInstance, IDS_PFR_ISONLISTE, szMsg, ARRAYSIZE(szMsg)); if (epflt == epfltInclude) { TCHAR szTmp[256]; LoadString(hInstance, IDS_PFR_ADDTOINC, szTmp, ARRAYSIZE(szTmp)); StringCchCat(szMsg, ARRAYSIZE(szMsg), szTmp); // display string, truncation ok } MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); return FALSE; } cItems = ListView_GetItemCount(hlc); // update the max string size if necessary cch = wcslen(sad.wszApp); if (cch >= pspd->cchMax) pspd->cchMax = cch + 1; // yay! add it to the config class hr = pcfg->add_ListApp(epflt, sad.wszApp); if (FAILED(hr)) return FALSE; pcxMax = (epflt == epfltInclude) ? &pspd->cxMaxI : &pspd->cxMaxE; cxMax = (DWORD)SendMessageW(hlc, LVM_GETSTRINGWIDTHW, 0, (LPARAM)sad.wszApp); cxMax += c_dxLVChkPixels; if (cxMax > *pcxMax) { *pcxMax = cxMax; ListView_SetColumnWidth(hlc, 0, cxMax); } // add it to the UI // Note that we set lParam to 2. This is because we need to ignore the // first two notification messages per entry sent to the wndproc because // they are 'list initialization' messages and processing them leads to // corruption in the configuration settings ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE; lvi.stateMask = LVIS_STATEIMAGEMASK; lvi.state = 0; lvi.pszText = sad.wszApp; lvi.iItem = 0; lvi.lParam = 2; nID = (int)SendMessageW(hlc, LVM_INSERTITEMW, 0, (LPARAM)&lvi); if (nID >= 0) ListView_SetCheckState(hlc, nID, TRUE); // if there are no items, then there is no currently selected item, so // make sure this item gets selected. In our handler for this message // we will take care of setting the 'last selected item' field... if (cItems == 0) { ListView_SetItemState(hlc, nID, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); // Also, got to make sure we enable the 'Remove' button. The only // way we can get zero items in a list is in the exclude list cuz // the include list always has the 'include MS apps' item. hbtn = GetDlgItem(hdlg, IDC_PFR_EXREM); if (hbtn != NULL) EnableWindow(hbtn, TRUE); } return TRUE; } // ************************************************************************** static BOOL DelProgramFromList(HWND hdlg, HWND hlc, SProgDlg *pspd, EPFListType epflt) { LVITEMW lvi; HRESULT hr; LPWSTR wszApp; DWORD cItems, iSel; __try { wszApp = (LPWSTR)_alloca(pspd->cchMax * sizeof(WCHAR)); } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW) { wszApp = NULL; _resetstkoflw(); } if (wszApp == NULL) return FALSE; iSel = ((epflt == epfltInclude) ? pspd->iLastSelI : pspd->iLastSelE); // fetch the string for the item ZeroMemory(&lvi, sizeof(lvi)); lvi.iItem = iSel; lvi.mask = LVIF_TEXT; lvi.pszText = wszApp; lvi.cchTextMax = pspd->cchMax; if (SendMessageW(hlc, LVM_GETITEMW, 0, (LPARAM)&lvi)) { // delete it from the config class hr = pspd->pcfg->del_ListApp(epflt, lvi.pszText); if (FAILED(hr)) return FALSE; } // delete it from the UI if (ListView_DeleteItem(hlc, iSel) == FALSE) return FALSE; // reset the selection to be either the same index or one higher (if the // user deleted the last item) cItems = ListView_GetItemCount(hlc); if (cItems == 0) { HWND hbtn; // only time we can ever hit zero items is in the exclude list cuz the // include list always has the 'include MS apps' option. hbtn = GetDlgItem(hdlg, IDC_PFR_EXADD); if (hbtn != NULL) { SetFocus(hbtn); SendMessage(hdlg, DM_SETDEFID, IDC_PFR_EXADD, 0); } hbtn = GetDlgItem(hdlg, IDC_PFR_EXREM); if (hbtn != NULL) EnableWindow(hbtn, FALSE); pspd->iLastSelI = 0; return TRUE; } // if cItems <= iSel, then we just deleted the last index, so decrement the // select index down 1. else if (cItems <= iSel) { iSel--; } // this will convieniently take care of setting the appropriate iLastSel // field ListView_SetItemState(hlc, iSel, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); return TRUE; } // ************************************************************************** static INT_PTR APIENTRY PFRProgDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPFFaultClientCfg *pcfg = NULL; SProgDlg *pspd = (SProgDlg *)GetWindowLongPtr(hdlg, DWLP_USER); HRESULT hr; HWND hlc, hbtn; if (pspd != NULL) pcfg = pspd->pcfg; switch(uMsg) { case WM_INITDIALOG: SetWindowLongPtr(hdlg, DWLP_USER, lParam); if (InitProgDlg(hdlg, (SProgDlg *)lParam) == FALSE) EndDialog(hdlg, IDCANCEL); break; // F1 help case WM_HELP: WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP, (DWORD_PTR)g_rgPFER); break; // right-click help case WM_CONTEXTMENU: WinHelp((HWND)wParam, HELP_FILE, HELP_CONTEXTMENU, (DWORD_PTR)g_rgPFER); break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDOK: if (pspd->fRW) { hr = pcfg->CommitChanges(epfltExclude); if (SUCCEEDED(hr)) { hr = pcfg->CommitChanges(epfltInclude); if (SUCCEEDED(hr)) { pcfg->set_IncWinComp(pspd->eieWinComp); pcfg->set_IncMSApps(pspd->eieMS); pcfg->set_AllOrNone(pspd->eieApps); hr = pcfg->Write(); } } if (FAILED(hr)) { TCHAR szMsg[MAX_PATH]; if (hr != HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { LoadString(hInstance, IDS_PFR_CFGWRITEERR, szMsg, ARRAYSIZE(szMsg)); } else { LoadString(hInstance, IDS_PFR_NOTADMIN, szMsg, ARRAYSIZE(szMsg)); } MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); pcfg->ClearChanges(epfltExclude); pcfg->ClearChanges(epfltInclude); } } else { TCHAR szMsg[MAX_PATH]; LoadString(hInstance, IDS_PFR_NOTADMIN, szMsg, ARRAYSIZE(szMsg)); MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); } EndDialog(hdlg, IDOK); break; case IDCANCEL: EndDialog(hdlg, IDCANCEL); break; case IDC_PFR_DEFNONE: pspd->eieApps = (EIncEx)(((DWORD)pspd->eieApps & eieDisableMask) | eieExclude); // enable the include list. hlc = GetDlgItem(hdlg, IDC_PFR_INCLIST); if (hlc != NULL) EnableWindow(hlc, TRUE); hbtn = GetDlgItem(hdlg, IDC_PFR_INCADD); if (hbtn != NULL) EnableWindow(hbtn, TRUE); hbtn = GetDlgItem(hdlg, IDC_PFR_INCREM); if (hbtn != NULL) EnableWindow(hbtn, pspd->fShowIncRem); break; case IDC_PFR_DEFALL: pspd->eieApps = (EIncEx)(((DWORD)pspd->eieApps & eieDisableMask) | eieInclude); // disable the include list. hlc = GetDlgItem(hdlg, IDC_PFR_INCLIST); if (hlc != NULL) EnableWindow(hlc, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_INCADD); if (hbtn != NULL) EnableWindow(hbtn, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_INCREM); if (hbtn != NULL) EnableWindow(hbtn, FALSE); break; case IDC_PFR_INCADD: hlc = GetDlgItem(hdlg, IDC_PFR_INCLIST); if (hlc != NULL) return AddProgramToList(hdlg, hlc, pspd, epfltInclude); break; case IDC_PFR_EXADD: hlc = GetDlgItem(hdlg, IDC_PFR_EXLIST); if (hlc != NULL) return AddProgramToList(hdlg, hlc, pspd, epfltExclude); break; case IDC_PFR_INCREM: hlc = GetDlgItem(hdlg, IDC_PFR_INCLIST); if (hlc != NULL) return DelProgramFromList(hdlg, hlc, pspd, epfltInclude); break; case IDC_PFR_EXREM: hlc = GetDlgItem(hdlg, IDC_PFR_EXLIST); if (hlc != NULL) return DelProgramFromList(hdlg, hlc, pspd, epfltExclude); break; default: return FALSE; } break; } case WM_SETEIELVSEL: { hlc = GetDlgItem(hdlg, (int)wParam); if (ListView_GetItemCount(hlc) > 0) { int iSel; if (wParam == IDC_PFR_EXLIST) iSel = pspd->iLastSelE; else iSel = pspd->iLastSelI; ListView_SetItemState(hlc, iSel, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } break; } case WM_NOTIFY: { EPFListType epflt; NMLISTVIEW *pnmlv = (NMLISTVIEW *)lParam; LVITEMW lvi; NMHDR *pnmh = (NMHDR *)lParam; DWORD dw; UINT uiBtn; BOOL fCheck; int iSel; if ((pnmh->code != LVN_ITEMCHANGED && pnmh->code != NM_SETFOCUS) || (pnmh->idFrom != IDC_PFR_EXLIST && pnmh->idFrom != IDC_PFR_INCLIST)) return FALSE; hlc = pnmh->hwndFrom; uiBtn = (pnmh->idFrom == IDC_PFR_EXLIST) ? IDC_PFR_EXREM : IDC_PFR_INCREM; hbtn = GetDlgItem(hdlg, uiBtn); // check and see if there are any selected items iSel = (int)SendMessage(hlc, LVM_GETNEXTITEM, -1, LVNI_SELECTED); if (iSel < 0) { EnableWindow(hbtn, FALSE); if (pnmh->idFrom == IDC_PFR_INCLIST) pspd->fShowIncRem = FALSE; } else { if (pnmh->code == NM_SETFOCUS) { PostMessage(hdlg, WM_SETEIELVSEL, pnmh->idFrom, pnmh->code); return TRUE; } } // if it doesn't fit this condition, don't give a rat's patootie // about it if ((pnmlv->uChanged & LVIF_STATE) == 0 || (pnmlv->uNewState ^ pnmlv->uOldState) == 0) return FALSE; // hack cuz we get 1 or 2 messages when inserting items into the // list & initially setting their check state. Want to not // process those messages. The exception is the 'include // ms apps' item which we can process any number of times if ((pnmlv->lParam & ~EXNOREM) > 0) { ZeroMemory(&lvi, sizeof(lvi)); lvi.iItem = pnmlv->iItem; lvi.mask = LVIF_PARAM; lvi.lParam = (pnmlv->lParam - 1) | (pnmlv->lParam & EXNOREM); SendMessageW(hlc, LVM_SETITEM, 0, (LPARAM)&lvi); return TRUE; } // did the selection change? if ((pnmlv->uNewState & LVIS_SELECTED) != 0) { if (pnmh->idFrom == IDC_PFR_INCLIST) { pspd->iLastSelI = pnmlv->iItem; // we need to disable the exclude remove button if we hit // the 'exclude non ms apps' item if (hbtn != NULL) { if ((pnmlv->lParam & EXNOREM) != 0) { // disable the remove button- but if the remove // button had focus, we need to reset the focus // or nothing on the dialog will have focus. if (GetFocus() == hbtn) { HWND hbtnAdd; hbtnAdd = GetDlgItem(hdlg, IDC_PFR_INCADD); if (hbtnAdd != NULL) { SetFocus(hbtnAdd); SendMessage(hdlg, DM_SETDEFID, IDC_PFR_INCADD, 0); } } pspd->fShowIncRem = FALSE; EnableWindow(hbtn, FALSE); } else { pspd->fShowIncRem = TRUE; EnableWindow(hbtn, TRUE); } } } else { pspd->iLastSelE = pnmlv->iItem; if (hbtn != NULL) EnableWindow(hbtn, TRUE); } } // if we don't have a check-state change, can bail now. if (((pnmlv->uNewState ^ pnmlv->uOldState) & 0x3000) == 0) return TRUE; fCheck = ListView_GetCheckState(hlc, pnmlv->iItem); if (pnmh->idFrom == IDC_PFR_EXLIST) epflt = epfltExclude; else epflt = epfltInclude; // did we modify the 'exclude non ms apps' item? if ((pnmlv->lParam & EXNOREM) != 0) { if ((pnmlv->lParam & EXALLMS) != 0) pspd->eieMS = ((fCheck) ? eieInclude : eieExclude); else pspd->eieWinComp = ((fCheck) ? eieInclude : eieExclude); } // nope, modified a regular item else { LPWSTR wszApp; __try { wszApp = (LPWSTR)_alloca(pspd->cchMax * sizeof(WCHAR)); } __except(GetExceptionCode() == STATUS_STACK_OVERFLOW) { wszApp = NULL; _resetstkoflw(); } if (wszApp == NULL) return FALSE; // got to fetch it to make sure we have a unicode string ZeroMemory(&lvi, sizeof(lvi)); lvi.iItem = pnmlv->iItem; lvi.mask = LVIF_TEXT; lvi.pszText = wszApp; lvi.cchTextMax = pspd->cchMax; if (SendMessageW(hlc, LVM_GETITEMW, 0, (LPARAM)&lvi)) { hr = pcfg->mod_ListApp(epflt, lvi.pszText, fCheck); if (FAILED(hr)) return FALSE; } } break; } default: return FALSE; } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // Main PFR dialog proc // ************************************************************************** static BOOL InitMainDlg(HWND hdlg) { CPFFaultClientCfg *pcfg = NULL; SMainDlg *psmd = NULL; BOOL fRet = FALSE; UINT ui; HWND hbtn, hchk; LoadPFRResourceStrings(); hbtn = GetDlgItem(hdlg, IDC_PFR_DETAILS); if (hbtn == NULL) goto done; psmd = new SMainDlg; if (psmd == NULL) goto done; pcfg = new CPFFaultClientCfg; if (pcfg == NULL) goto done; // see if this user has write access to the appropriate registry // locations psmd->fRW = pcfg->HasWriteAccess(); if (FAILED(pcfg->Read((psmd->fRW) ? eroCPRW : eroCPRO))) goto done; psmd->eedReport = pcfg->get_DoReport(); psmd->eieKernel = pcfg->get_IncKernel(); psmd->eieApps = pcfg->get_AllOrNone(); psmd->eedShowUI = pcfg->get_ShowUI(); psmd->eieShut = pcfg->get_IncShutdown(); psmd->fForceQueue = pcfg->get_ForceQueueMode(); psmd->iLastSel = 0; // if ShowUI is completely disabled, then so should reporting- the control // panel does not support entering corporate mode. if (psmd->eedShowUI == eedDisabled) psmd->eedReport = eedDisabled; psmd->pcfg = pcfg; SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR)psmd); // set up the kernel checkbox ui = (psmd->eieKernel == eieInclude) ? BST_CHECKED : BST_UNCHECKED; CheckDlgButton(hdlg, IDC_PFR_ENABLEOS, ui); // set up the programs checkbox ui = ((psmd->eieApps & eieDisableMask) == 0) ? BST_CHECKED : BST_UNCHECKED; CheckDlgButton(hdlg, IDC_PFR_ENABLEPROG, ui); // set up the notification checkbox ui = (psmd->eedShowUI == eedEnabled) ? BST_CHECKED : BST_UNCHECKED; CheckDlgButton(hdlg, IDC_PFR_SHOWUI, ui); // set up the shutdown checkbox on server only if (pcfg->get_IsServer()) { ui = (psmd->eieShut == eieInclude) ? BST_CHECKED : BST_UNCHECKED; CheckDlgButton(hdlg, IDC_PFR_ENABLESHUT, ui); ui = (psmd->fForceQueue) ? BST_CHECKED : BST_UNCHECKED; CheckDlgButton(hdlg, IDC_PFR_FORCEQ, ui); } // set up the radio buttons if (psmd->eedReport == eedDisabled) { CheckRadioButton(hdlg, IDC_PFR_DISABLE, IDC_PFR_ENABLE, IDC_PFR_DISABLE); hchk = GetDlgItem(hdlg, IDC_PFR_SHOWUI); if (hchk != NULL) EnableWindow(hchk, TRUE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEOS); if (hchk != NULL) EnableWindow(hchk, FALSE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEPROG); if (hchk != NULL) EnableWindow(hchk, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_DETAILS); if (hbtn != NULL) EnableWindow(hbtn, FALSE); if (pcfg->get_IsServer()) { hbtn = GetDlgItem(hdlg, IDC_PFR_ENABLESHUT); if (hbtn != NULL) EnableWindow(hbtn, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_FORCEQ); if (hbtn != NULL) EnableWindow(hbtn, FALSE); } } else { CheckRadioButton(hdlg, IDC_PFR_DISABLE, IDC_PFR_ENABLE, IDC_PFR_ENABLE); hchk = GetDlgItem(hdlg, IDC_PFR_SHOWUI); if (hchk != NULL) EnableWindow(hchk, FALSE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEOS); if (hchk != NULL) EnableWindow(hchk, TRUE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEPROG); if (hchk != NULL) EnableWindow(hchk, TRUE); if (pcfg->get_IsServer()) { hbtn = GetDlgItem(hdlg, IDC_PFR_ENABLESHUT); if (hbtn != NULL) EnableWindow(hbtn, TRUE); } if ((psmd->eieApps & eieDisableMask) != 0) { hbtn = GetDlgItem(hdlg, IDC_PFR_DETAILS); if (hbtn != NULL) EnableWindow(hbtn, FALSE); if (pcfg->get_IsServer()) { hbtn = GetDlgItem(hdlg, IDC_PFR_FORCEQ); if (hbtn != NULL) EnableWindow(hbtn, FALSE); } } } fRet = TRUE; psmd = NULL; pcfg = NULL; done: if (fRet == FALSE) { TCHAR szMsg[MAX_PATH]; LoadString(hInstance, IDS_PFR_CFGREADERR, szMsg, ARRAYSIZE(szMsg)); MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); } if (psmd != NULL) delete psmd; if (pcfg != NULL) delete pcfg; return fRet; } // ************************************************************************** static inline INT_PTR LaunchSubDialog(HWND hdlgParent, DWORD dwDlgToLaunch, SMainDlg *psmd) { if (dwDlgToLaunch == PROGLI) { SProgDlg spd; ZeroMemory(&spd, sizeof(spd)); spd.pcfg = psmd->pcfg; spd.eieApps = psmd->eieApps; spd.eieMS = psmd->pcfg->get_IncMSApps(); spd.fRW = psmd->fRW; if (DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_PFR_PROG), hdlgParent, PFRProgDlgProc, (LPARAM)&spd) == IDOK) { psmd->eieApps = psmd->pcfg->get_AllOrNone(); } } else { return IDCANCEL; } return IDOK; } // ************************************************************************** INT_PTR APIENTRY PFRDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPFFaultClientCfg *pcfg = NULL; SMainDlg *psmd = (SMainDlg *)GetWindowLongPtr(hdlg, DWLP_USER); HWND hbtn, hchk; if (psmd != NULL) pcfg = psmd->pcfg; switch(uMsg) { case WM_INITDIALOG: if (InitMainDlg(hdlg) == FALSE) EndDialog(hdlg, IDCANCEL); break; case WM_DESTROY: if (psmd != NULL) { if (psmd->pcfg != NULL) delete psmd->pcfg; delete psmd; SetWindowLongPtr(hdlg, DWLP_USER, NULL); } break; // F1 help case WM_HELP: WinHelp((HWND)((LPHELPINFO)lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP, (DWORD_PTR)g_rgPFER); break; // right-click help case WM_CONTEXTMENU: WinHelp((HWND)wParam, HELP_FILE, HELP_CONTEXTMENU, (DWORD_PTR)g_rgPFER); break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDOK: if (psmd->fRW) { HRESULT hr; pcfg->set_AllOrNone(psmd->eieApps); pcfg->set_DoReport(psmd->eedReport); pcfg->set_IncKernel(psmd->eieKernel); pcfg->set_ShowUI(psmd->eedShowUI); if (pcfg->get_IsServer()) { pcfg->set_IncShutdown(psmd->eieShut); pcfg->set_ForceQueueMode(psmd->fForceQueue); } hr = pcfg->Write(); if (FAILED(hr)) { TCHAR szMsg[MAX_PATH]; if (hr != HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { LoadString(hInstance, IDS_PFR_CFGWRITEERR, szMsg, ARRAYSIZE(szMsg)); } else { LoadString(hInstance, IDS_PFR_NOTADMIN, szMsg, ARRAYSIZE(szMsg)); } MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); } } else { TCHAR szMsg[MAX_PATH]; LoadString(hInstance, IDS_PFR_NOTADMIN, szMsg, ARRAYSIZE(szMsg)); MessageBox(hdlg, szMsg, NULL, MB_OK | MB_ICONERROR); } EndDialog(hdlg, IDOK); break; case IDCANCEL: EndDialog(hdlg, IDCANCEL); break; case IDC_PFR_ENABLE: { LVITEM lvi; psmd->eedReport = eedEnabled; // if UI is disbaled, then implicitly enable it (but don't // change the check state of the 'show UI' checkbox) cuz // we only support headless uploading thru policy. if (psmd->eedShowUI == eedDisabled) psmd->eedShowUI = eedEnabledNoCheck; hchk = GetDlgItem(hdlg, IDC_PFR_SHOWUI); if (hchk != NULL) EnableWindow(hchk, FALSE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEOS); if (hchk != NULL) EnableWindow(hchk, TRUE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEPROG); if (hchk != NULL) EnableWindow(hchk, TRUE); if (pcfg->get_IsServer()) { hbtn = GetDlgItem(hdlg, IDC_PFR_ENABLESHUT); if (hbtn != NULL) EnableWindow(hbtn, TRUE); } if ((psmd->eieApps & eieDisableMask) == 0) { hbtn = GetDlgItem(hdlg, IDC_PFR_DETAILS); if (hbtn != NULL) EnableWindow(hbtn, TRUE); if (pcfg->get_IsServer()) { hbtn = GetDlgItem(hdlg, IDC_PFR_FORCEQ); if (hbtn != NULL) EnableWindow(hbtn, TRUE); } } break; } case IDC_PFR_DISABLE: { psmd->eedReport = eedDisabled; // if UI isn't explicitly enabled, disable it- it was // implicity enabled when the user previously enabled // reporting if (psmd->eedShowUI == eedEnabledNoCheck) psmd->eedShowUI = eedDisabled; hchk = GetDlgItem(hdlg, IDC_PFR_SHOWUI); if (hchk != NULL) EnableWindow(hchk, TRUE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEOS); if (hchk != NULL) EnableWindow(hchk, FALSE); hchk = GetDlgItem(hdlg, IDC_PFR_ENABLEPROG); if (hchk != NULL) EnableWindow(hchk, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_DETAILS); if (hbtn != NULL) EnableWindow(hbtn, FALSE); if (pcfg->get_IsServer()) { hbtn = GetDlgItem(hdlg, IDC_PFR_ENABLESHUT); if (hbtn != NULL) EnableWindow(hbtn, FALSE); hbtn = GetDlgItem(hdlg, IDC_PFR_FORCEQ); if (hbtn != NULL) EnableWindow(hbtn, FALSE); } break; } case IDC_PFR_DETAILS: { // don't need to check if this is a valid thing to bring up // a dialog for cuz the details button should not be // available if it isn't return LaunchSubDialog(hdlg, PROGLI, psmd); break; } case IDC_PFR_SHOWUI: { if (IsDlgButtonChecked(hdlg, IDC_PFR_SHOWUI) == BST_UNCHECKED) psmd->eedShowUI = eedDisabled; else if (psmd->eedReport == eedEnabled) psmd->eedShowUI = eedEnabledNoCheck; else psmd->eedShowUI = eedEnabled; break; } case IDC_PFR_ENABLEOS: { if (IsDlgButtonChecked(hdlg, IDC_PFR_ENABLEOS) == BST_UNCHECKED) psmd->eieKernel = eieExclude; else psmd->eieKernel = eieInclude; break; } case IDC_PFR_ENABLEPROG: { DWORD dw; hbtn = GetDlgItem(hdlg, IDC_PFR_DETAILS); if (pcfg->get_IsServer()) hchk = GetDlgItem(hdlg, IDC_PFR_FORCEQ); else hchk = NULL; if (IsDlgButtonChecked(hdlg, IDC_PFR_ENABLEPROG) == BST_UNCHECKED) { dw = (DWORD)psmd->eieApps | eieDisableMask; if (hbtn != NULL) EnableWindow(hbtn, FALSE); if (hchk != NULL) EnableWindow(hchk, FALSE); } else { dw = (DWORD)psmd->eieApps & eieIncMask; if (hbtn != NULL) EnableWindow(hbtn, TRUE); if (hchk != NULL) EnableWindow(hchk, TRUE); } psmd->eieApps = (EIncEx)dw; break; } case IDC_PFR_ENABLESHUT: if (pcfg->get_IsServer()) { if (IsDlgButtonChecked(hdlg, IDC_PFR_ENABLESHUT) == BST_UNCHECKED) psmd->eieShut = eieExclude; else psmd->eieShut = eieInclude; } case IDC_PFR_FORCEQ: if (pcfg->get_IsServer()) { if (IsDlgButtonChecked(hdlg, IDC_PFR_FORCEQ) == BST_UNCHECKED) psmd->fForceQueue = FALSE; else psmd->fForceQueue = TRUE; } default: return FALSE; } break; } default: return FALSE; } return TRUE; }