/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: QFixApp.cpp Abstract: Contains the application entry point, user interface code, and some supporting functions. Notes: ANSI & Unicode via TCHAR - runs on NT/2K/XP etc. History: 02/16/00 clupu Created 11/10/00 rparsons Minor common dialog change 11/23/00 rparsons Added save XML file capability 11/25/00 rparsons Matching file on a different drive can be selected 05/19/01 rparsons Added context menu for file tree. Added URL for WU package/helpcenter. Added Remove Matching File button. Converted shim list to list view. 07/06/01 rparsons Static tab control -> child dialogs 09/24/01 rparsons Spawn a separate VDM when running apps 10/09/01 rparsons Flags have a command-line 10/26/01 rparsons No change - 476903. 01/26/02 rparsons Fix bug # 491301 02/20/02 rparsons Implemented strsafe functions 03/22/02 rparsons Fix bug # 583475 --*/ #include "afxwin.h" #include "commctrl.h" #include "commdlg.h" #include "shlwapi.h" #include "shellapi.h" #include "shlobj.h" #include "shlobjp.h" // needed for Link Window support #include "uxtheme.h" // needed for tab control theme support #include "resource.h" #include #include #include #include "QFixApp.h" #include "dbSupport.h" extern "C" { #include "shimdb.h" } CWinApp theApp; /* * Global Variables */ HINSTANCE g_hInstance; HWND g_hDlg; HWND g_hLayersDlg; HWND g_hFixesDlg; HWND g_hwndTab; HWND g_hwndListLayers; TCHAR g_szAppTitle[64]; TCHAR g_szWinDir[MAX_PATH]; // %windir% TCHAR g_szSysDir[MAX_PATH]; // %windir%\System32 TCHAR g_szBinary[MAX_PATH]; // the full path of the main binary being shimmed TCHAR g_szShortName[128]; // the short name of the main EXE TCHAR g_szParentExeName[MAX_PATH]; // the short name of the parent EXE TCHAR g_szParentExeFullPath[MAX_PATH]; // the full path of the parent EXE TCHAR g_szSDBToDelete[MAX_PATH]; // the SDB file to delete from a previous 'Run' int g_nCrtTab; HWND g_hwndShimList; // the handle to the list view control // containing all the shims available HWND g_hwndFilesTree; // the handle to the tree view control // containing the matching files selected HWND g_hwndModuleList; // the handle to the list view control // containing module information BOOL g_bSimpleEdition; // simple or dev edition BOOL g_fW2K; // Win2K or XP BOOL g_fNETServer; // indicates if we're running on .NET Server RECT g_rcDlgBig, g_rcDlgSmall; // rectangle of the simple and the dev edition // of the dialog BOOL g_bAllShims; // indicates if all shims should be displayed BOOL g_bShowXML; // indicates if we should hide the 'Show XML' button BOOL g_bSelectedParentExe; // flag to indicate if a parent EXE has been // selected BOOL g_bSDBInstalled; // flag to indicate if the user installed the SDB // associated with the current EXE PFIX g_pFixHead; TCHAR g_szXPUrl[] = _T("hcp://services/subsite?node=TopLevelBucket_4/") _T("Fixing_a_problem&topic=MS-ITS%3A%25HELP_LOCATION") _T("%25%5Cmisc.chm%3A%3A/compatibility_tab_and_wizard.htm") _T("&select=TopLevelBucket_4/Fixing_a_problem/") _T("Application_and_software_problems"); TCHAR g_szNETUrl[] = _T("hcp://services/subsite?node=Troubleshooting_Strategies&") _T("topic=MS-ITS%3A%25HELP_LOCATION%25%5Cmisc.chm%3A%3A/") _T("compatibility_tab_and_wizard.htm"); TCHAR g_szW2KUrl[] = _T("http://www.microsoft.com/windows2000/") _T("downloads/tools/appcompat/"); #define ID_COUNT_SHIMS 1234 typedef HRESULT (*PFNEnableThemeDialogTexture)(HWND hwnd, DWORD dwFlags); /*++ Routine Description: Prints a formatted string to the debugger. Arguments: dwDetail - Specifies the level of the information provided. pszFmt - The string to be displayed. ... - A va_list of insertion strings. Return Value: None. --*/ void __cdecl DebugPrintfEx( IN LPSTR pszFmt, ... ) { char szT[1024]; va_list arglist; int len; va_start(arglist, pszFmt); // // Reserve one character for the potential '\n' that we may be adding. // StringCchVPrintfA(szT, sizeof(szT) - 1, pszFmt, arglist); va_end(arglist); // // Make sure we have a '\n' at the end of the string // len = strlen(szT); if (len > 0 && szT[len - 1] != '\n') { szT[len] = '\n'; szT[len + 1] = 0; } OutputDebugStringA(szT); } BOOL SearchGroupForSID( IN DWORD dwGroup, OUT BOOL* pfIsMember ) { PSID pSID; SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY; BOOL fRes = TRUE; if (!AllocateAndInitializeSid(&SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, dwGroup, 0, 0, 0, 0, 0, 0, &pSID)) { fRes = FALSE; } if (!CheckTokenMembership(NULL, pSID, pfIsMember)) { fRes = FALSE; } FreeSid(pSID); return fRes; } BOOL IsUserAnAdministrator( void ) /*++ IsUserAnAdministrator Description: Determine if the currently logged on user is an admin. --*/ { BOOL fIsAdmin; if (!SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &fIsAdmin)) { return FALSE; } return fIsAdmin; } BOOL CheckForSDB( void ) /*++ CheckForSDB Description: Attempts to locate sysmain.sdb in the apppatch directory. --*/ { TCHAR szSDBPath[MAX_PATH]; BOOL fResult = FALSE; HRESULT hr; hr = StringCchPrintf(szSDBPath, ARRAYSIZE(szSDBPath), _T("%s\\AppPatch\\sysmain.sdb"), g_szWinDir); if (FAILED(hr)) { DPF("[CheckForSDB] 0x%08X Buffer too small", HRESULT_CODE(hr)); return FALSE; } if (GetFileAttributes(szSDBPath) != -1) { fResult = TRUE; } return fResult; } void AddModuleToListView( TCHAR* pModuleName, UINT uOption ) /*++ AddModuleToListView Description: Adds the specified module to the list view. --*/ { LVITEM lvi; int nIndex; TCHAR szInclude[MAX_PATH]; TCHAR szExclude[MAX_PATH]; LoadString(g_hInstance, IDS_INCLUDE_HDR, szInclude, ARRAYSIZE(szInclude)); LoadString(g_hInstance, IDS_EXCLUDE_HDR, szExclude, ARRAYSIZE(szExclude)); lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.lParam = uOption == BST_CHECKED ? 1 : 0; lvi.pszText = uOption == BST_CHECKED ? szInclude : szExclude; lvi.iItem = ListView_GetItemCount(g_hwndModuleList); lvi.iSubItem = 0; nIndex = ListView_InsertItem(g_hwndModuleList, &lvi); ListView_SetItemText(g_hwndModuleList, nIndex, 1, pModuleName); } void BuildModuleListForShim( PFIX pFix, DWORD dwFlags ) /*++ BuildModuleListForShim Description: Based on the flag, adds modules to the list view for the specified shim or retrieves them and adds them to the linked list. --*/ { PMODULE pModule, pModuleTmp, pModuleNew; int cItems, nIndex, nLen; LVITEM lvi; TCHAR szBuffer[MAX_PATH]; if (dwFlags & BML_ADDTOLISTVIEW) { // // Walk the linked list and add the modules to the list view. // pModule = pFix->pModule; while (pModule) { AddModuleToListView(pModule->pszName, pModule->fInclude ? BST_CHECKED : 0); pModule = pModule->pNext; } } if (dwFlags & BML_DELFRLISTVIEW) { pModule = pFix->pModule; while (NULL != pModule) { pModuleTmp = pModule->pNext; HeapFree(GetProcessHeap(), 0, pModule->pszName); HeapFree(GetProcessHeap(), 0, pModule); pModule = pModuleTmp; } pFix->pModule = NULL; } if (dwFlags & BML_GETFRLISTVIEW) { pModule = pFix->pModule; while (NULL != pModule) { pModuleTmp = pModule->pNext; HeapFree(GetProcessHeap(), 0, pModule->pszName); HeapFree(GetProcessHeap(), 0, pModule); pModule = pModuleTmp; } pFix->pModule = NULL; // // Get each module from the list view and add it to the linked list. // cItems = ListView_GetItemCount(g_hwndModuleList); if (cItems == 0) { return; } for (nIndex = cItems - 1; nIndex >= 0; nIndex--) { lvi.mask = LVIF_PARAM; lvi.iItem = nIndex; lvi.iSubItem = 0; ListView_GetItem(g_hwndModuleList, &lvi); ListView_GetItemText(g_hwndModuleList, nIndex, 1, szBuffer, ARRAYSIZE(szBuffer)); pModuleNew = (PMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MODULE)); if (!pModuleNew) { DPF("[BuildModuleListForShim] Couldn't allocate memory for node"); return; } nLen = _tcslen(szBuffer) + 1; pModuleNew->pszName = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLen * sizeof(TCHAR)); if (!pModuleNew->pszName) { DPF("[BuildModuleListForShim] Couldn't allocate memory to store module info"); HeapFree(GetProcessHeap(), 0, pModuleNew); return; } StringCchCopy(pModuleNew->pszName, nLen, szBuffer); pModuleNew->fInclude = (BOOL)lvi.lParam; pModuleNew->pNext = pFix->pModule; pFix->pModule = pModuleNew; } } } int CountShims( BOOL fCountSelected ) /*++ CountShims Description: Counts the number of selected shims in the list and updates the text on the dialog. --*/ { int cShims = 0, nTotalShims, nShims = 0; BOOL fReturn; TCHAR szShims[MAX_PATH]; TCHAR szTemp[MAX_PATH]; HRESULT hr; cShims = ListView_GetItemCount(g_hwndShimList); if (fCountSelected) { for (nTotalShims = 0; nTotalShims < cShims; nTotalShims++) { fReturn = ListView_GetCheckState(g_hwndShimList, nTotalShims); if (fReturn) { nShims++; } } } LoadString(g_hInstance, IDS_SEL_CAPTION, szTemp, ARRAYSIZE(szTemp)); hr = StringCchPrintf(szShims, ARRAYSIZE(szShims), szTemp, nShims, cShims); if (FAILED(hr)) { DPF("[CountShims] 0x%08X Buffer too small", HRESULT_CODE(hr)); return 0; } SetDlgItemText(g_hFixesDlg, IDC_SELECTED_SHIMS, szShims); return cShims; } void DisplayAttrContextMenu( POINT* pt ) /*++ DisplayAttrContextMenu Description: Displays a popup menu for the attributes tree. --*/ { HMENU hPopupMenu, hTrackPopup; // // Load the popup menu and display it. // hPopupMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_ATTR_POPUP)); if (hPopupMenu == NULL) { return; } hTrackPopup = GetSubMenu(hPopupMenu, 0); TrackPopupMenu(hTrackPopup, TPM_LEFTBUTTON | TPM_NOANIMATION | TPM_LEFTALIGN, pt->x, pt->y, 0, g_hDlg, NULL); DestroyMenu(hPopupMenu); } void InsertListViewColumn( HWND hWndListView, LPTSTR lpColumnName, BOOL fCenter, int nColumnID, int nSize ) /*++ InsertListViewColumn Description: Wrapper for ListView_InsertColumn. --*/ { LV_COLUMN lvColumn; if (fCenter) { lvColumn.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT; } else { lvColumn.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; } // // Fill in the structure and add the column. // lvColumn.fmt = LVCFMT_CENTER; lvColumn.cx = nSize; lvColumn.iSubItem = 0; lvColumn.pszText = lpColumnName; ListView_InsertColumn(hWndListView, nColumnID, &lvColumn); } void EnableTabBackground( HWND hDlg ) { PFNEnableThemeDialogTexture pFnEnableThemeDialogTexture; HMODULE hUxTheme; hUxTheme = (HMODULE)LoadLibrary(_T("uxtheme.dll")); if (hUxTheme) { pFnEnableThemeDialogTexture = (PFNEnableThemeDialogTexture) GetProcAddress(hUxTheme, "EnableThemeDialogTexture"); if (pFnEnableThemeDialogTexture) { pFnEnableThemeDialogTexture(hDlg, ETDT_USETABTEXTURE); } FreeLibrary(hUxTheme); } } void HandleLayersDialogInit( HWND hDlg ) { HWND hParent; DLGHDR* pHdr; g_hLayersDlg = hDlg; hParent = GetParent(hDlg); pHdr = (DLGHDR*)GetWindowLongPtr(hParent, DWLP_USER); // // Position the dialog within the tab. // SetWindowPos(hDlg, HWND_TOP, pHdr->rcDisplay.left, pHdr->rcDisplay.top, pHdr->rcDisplay.right - pHdr->rcDisplay.left, pHdr->rcDisplay.bottom - pHdr->rcDisplay.top, 0); g_hwndListLayers = GetDlgItem(hDlg, IDC_LAYERS); EnableTabBackground(hDlg); } BOOL HandleFixesDialogInit( HWND hDlg ) { HWND hParent; DLGHDR* pHdr; int nCount = 0; TCHAR szColumn[MAX_PATH]; g_hFixesDlg = hDlg; hParent = GetParent(hDlg); pHdr = (DLGHDR*)GetWindowLongPtr(hParent, DWLP_USER); // // Position the dialog within the tab. // SetWindowPos(hDlg, HWND_TOP, pHdr->rcDisplay.left, pHdr->rcDisplay.top, pHdr->rcDisplay.right - pHdr->rcDisplay.left, pHdr->rcDisplay.bottom - pHdr->rcDisplay.top, 0); g_hwndShimList = GetDlgItem(hDlg, IDC_SHIMS); // // Set up the shim list. // LoadString(g_hInstance, IDS_FIXNAME_COLUMN, szColumn, ARRAYSIZE(szColumn)); InsertListViewColumn(g_hwndShimList, szColumn, FALSE, 0, 200); LoadString(g_hInstance, IDS_CMDLINE_COLUMN, szColumn, ARRAYSIZE(szColumn)); InsertListViewColumn(g_hwndShimList, szColumn, TRUE, 1, 59); LoadString(g_hInstance, IDS_MODULE_COLUMN, szColumn, ARRAYSIZE(szColumn)); InsertListViewColumn(g_hwndShimList, szColumn, TRUE, 2, 52); ListView_SetExtendedListViewStyle(g_hwndShimList, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT); // // Query the database and show the available general purpose fixes. // ShowAvailableFixes(g_hwndShimList); nCount = CountShims(FALSE); if (!nCount) { return FALSE; } ListView_SetItemCount(g_hwndShimList, nCount); EnableTabBackground(hDlg); return TRUE; } DLGTEMPLATE* LockDlgRes( LPCTSTR lpResName ) { HRSRC hrsrc = FindResource(NULL, lpResName, RT_DIALOG); if (NULL == hrsrc) { return NULL; } HGLOBAL hglb = LoadResource(g_hInstance, hrsrc); if (NULL == hglb) { return NULL; } return (DLGTEMPLATE*)LockResource(hglb); } void InitTabs( HWND hMainDlg, HWND hTab ) { DLGHDR* pHdr; TCITEM tcitem; RECT rcTab; int nCount; TCHAR szTabText[MAX_PATH]; TCHAR szError[MAX_PATH]; pHdr = (DLGHDR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DLGHDR)); if (NULL == pHdr) { LoadString(g_hInstance, IDS_TAB_SETUP_FAIL, szError, ARRAYSIZE(szError)); MessageBox(hMainDlg, szError, g_szAppTitle, MB_ICONERROR); return; } // // Save away a pointer to the structure. // SetWindowLongPtr(hMainDlg, DWLP_USER, (LONG_PTR)pHdr); // // Save away the handle to the tab control. // pHdr->hTab = hTab; // // Add the tabs. // LoadString(g_hInstance, IDS_TAB_FIRST_TEXT, szTabText, ARRAYSIZE(szTabText)); tcitem.mask = TCIF_TEXT | TCIF_PARAM; tcitem.pszText = szTabText; tcitem.lParam = 0; TabCtrl_InsertItem(pHdr->hTab, 0, &tcitem); LoadString(g_hInstance, IDS_TAB_SECOND_TEXT, szTabText, ARRAYSIZE(szTabText)); tcitem.pszText = szTabText; tcitem.lParam = 1; TabCtrl_InsertItem(pHdr->hTab, 1, &tcitem); // // Lock the resources for two child dialog boxes. // pHdr->pRes[0] = LockDlgRes(MAKEINTRESOURCE(IDD_LAYERS_TAB)); pHdr->pDlgProc[0] = LayersTabDlgProc; pHdr->pRes[1] = LockDlgRes(MAKEINTRESOURCE(IDD_FIXES_TAB)); pHdr->pDlgProc[1] = FixesTabDlgProc; // // Determine the bounding rectangle for all child dialog boxes. // GetWindowRect(pHdr->hTab, &rcTab); TabCtrl_AdjustRect(pHdr->hTab, FALSE, &rcTab); InflateRect(&rcTab, 1, 1); rcTab.left -= 2; MapWindowPoints(NULL, hMainDlg, (LPPOINT)&rcTab, 2); pHdr->rcDisplay = rcTab; // // Create both dialog boxes. // for (nCount = 0; nCount < NUM_TABS; nCount++) { pHdr->hDisplay[nCount] = CreateDialogIndirect(g_hInstance, pHdr->pRes[nCount], hMainDlg, pHdr->pDlgProc[nCount]); } } TCHAR* GetRelativePath( TCHAR* pExeFile, TCHAR* pMatchFile ) /*++ GetRelativePath Description: Returns a relative path based on an EXE and a matching file. The caller must free the memory using HeapFree. --*/ { int nLenExe = 0; int nLenMatch = 0; TCHAR* pExe = NULL; TCHAR* pMatch = NULL; TCHAR* pReturn = NULL; TCHAR result[MAX_PATH] = { _T('\0') }; TCHAR* resultIdx = result; BOOL bCommonBegin = FALSE; // Indicates if the paths have a common beginning pExe = _tcschr(pExeFile, _T('\\')); pMatch = _tcschr(pMatchFile, _T('\\')); while (pExe && pMatch) { nLenExe = (int)(pExe - pExeFile); nLenMatch = (int)(pMatch - pMatchFile); if (nLenExe != nLenMatch) { break; } if (!(_tcsnicmp(pExeFile, pMatchFile, nLenExe) == 0)) { break; } bCommonBegin = TRUE; pExeFile = pExe + 1; pMatchFile = pMatch + 1; pExe = _tcschr(pExeFile, _T('\\')); pMatch = _tcschr(pMatchFile, _T('\\')); } // // Walk the path and put '..\' where necessary // if (bCommonBegin) { while (pExe) { StringCchCopy(resultIdx, ARRAYSIZE(result), _T("..\\")); resultIdx = resultIdx + 3; pExeFile = pExe + 1; pExe = _tcschr(pExeFile, _T('\\')); } StringCchCopy(resultIdx, ARRAYSIZE(result), pMatchFile); nLenExe = _tcslen(result) + 1; pReturn = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLenExe * sizeof(TCHAR)); if (!pReturn) { return NULL; } StringCchCopy(pReturn, nLenExe, result); return pReturn; } return NULL; } void SaveEntryToFile( HWND hDlg, HWND hEdit, LPCTSTR lpFileName ) /*++ SaveEntryToFile Description: Writes the XML out to a file. --*/ { int cchSize = 0; DWORD cbBytesWritten; HANDLE hFile = NULL; LPTSTR lpData = NULL; TCHAR szError[MAX_PATH]; // // Determine how much space we need for the buffer, then allocate it. // cchSize = GetWindowTextLength(hEdit); if (cchSize) { // // Account for the additional byte & the NULL that we're storing // in the file. // cchSize += 2; lpData = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cchSize * sizeof(TCHAR)); if (!lpData) { LoadString(g_hInstance, IDS_BUFFER_ALLOC_FAIL, szError, ARRAYSIZE(szError)); MessageBox(hDlg, szError, g_szAppTitle, MB_ICONERROR); return; } // // Ensure that the file is saved as Unicode. // lpData[0] = 0xFEFF; // // Get the text out of the text box and write it out to our file. // if (!GetWindowText(hEdit, lpData + 1, cchSize - 1)) { goto Cleanup; } hFile = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { LoadString(g_hInstance, IDS_FILE_CREATE_FAIL, szError, ARRAYSIZE(szError)); MessageBox(hDlg, szError, g_szAppTitle, MB_ICONERROR); goto Cleanup; } WriteFile(hFile, lpData, cchSize * sizeof(TCHAR), &cbBytesWritten, NULL); CloseHandle(hFile); } Cleanup: HeapFree(GetProcessHeap(), 0, lpData); } void DoFileSave( HWND hDlg ) /*++ DoFileSave Description: Displays the common dialog allowing for file save. --*/ { TCHAR szFilter[MAX_PATH] = _T(""); TCHAR szTemp[MAX_PATH] = _T(""); OPENFILENAME ofn = {0}; *szTemp = 0; LoadString(g_hInstance, IDS_SAVE_FILTER, szFilter, ARRAYSIZE(szFilter)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hDlg; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = (LPTSTR)NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 1; ofn.lpstrFile = szTemp; ofn.nMaxFile = sizeof(szTemp); ofn.lpstrTitle = NULL; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = _T("xml"); ofn.lCustData = 0; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if (GetSaveFileName(&ofn)) { SaveEntryToFile(hDlg, GetDlgItem(hDlg, IDC_XML), szTemp); } } void GetTopLevelWindowIntoView( HWND hwnd ) { RECT rectWindow, rectScreen; int nCx, nCy, nCxScreen, nCyScreen; int dx = 0, dy = 0; HWND hwndDesktop; if (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD) { return; } hwndDesktop = GetDesktopWindow(); GetWindowRect(hwnd, &rectWindow); GetWindowRect(hwndDesktop, &rectScreen); nCx = rectWindow.right - rectWindow.left; nCy = rectWindow.bottom - rectWindow.top; nCxScreen = rectScreen.right - rectScreen.left; nCyScreen = rectScreen.bottom - rectScreen.top; // // Make it fix on the x coord. // if (rectWindow.left < rectScreen.left) { dx = rectScreen.left - rectWindow.left; rectWindow.left += dx; rectWindow.right += dx; } if (rectWindow.right > rectScreen.right) { if (nCx < nCxScreen) { dx = rectScreen.right - rectWindow.right; rectWindow.left += dx; rectWindow.right += dx; } } // // Make it fix on the y coord. // if (rectWindow.top < rectScreen.top) { dy = rectScreen.top - rectWindow.top; rectWindow.top += dy; rectWindow.bottom += dy; } if (rectWindow.bottom > rectScreen.bottom) { if (nCy < nCyScreen) { dy = rectScreen.bottom - rectWindow.bottom; rectWindow.top += dy; rectWindow.bottom += dy; } } if (dx != 0 || dy != 0) { MoveWindow(hwnd, rectWindow.left, rectWindow.top, nCx, nCy, TRUE); } } void ReplaceCmdLine( PFIX pFix, TCHAR* pszNewCmdLine ) /*++ ReplaceCmdLine Description: Replaces the command line for a shim DLL. --*/ { TCHAR szError[MAX_PATH]; int nLen; if (pFix->pszCmdLine != NULL) { HeapFree(GetProcessHeap(), 0, pFix->pszCmdLine); pFix->pszCmdLine = NULL; } if (pszNewCmdLine == NULL) { return; } else if ((*pszNewCmdLine == '"') && (_tcslen(pszNewCmdLine) == 1)) { LoadString(g_hInstance, IDS_INVALID_CMD_LINE, szError, ARRAYSIZE(szError)); MessageBox(g_hDlg, szError, g_szAppTitle, MB_ICONEXCLAMATION); return; } nLen = _tcslen(pszNewCmdLine) + 1; pFix->pszCmdLine = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLen * sizeof(TCHAR)); if (pFix->pszCmdLine != NULL) { StringCchCopy(pFix->pszCmdLine, nLen, pszNewCmdLine); } else { DPF("[ReplaceCmdLine] Failed to replace the cmd line for '%S'", pFix->pszName); } } void DeselectAllShims( HWND hdlg ) /*++ DeselectAllShims Description: Removes selections for all shims listed. --*/ { int cShims, nIndex; LVITEM lvi; // // Walk all the shims in the list view and deselect them. // ZeroMemory(&lvi, sizeof(lvi)); cShims = ListView_GetItemCount(g_hwndShimList); for (nIndex = 0; nIndex < cShims; nIndex++) { PFIX pFix; lvi.iItem = nIndex; lvi.mask = LVIF_STATE | LVIF_PARAM; lvi.stateMask = LVIS_STATEIMAGEMASK; ListView_GetItem(g_hwndShimList, &lvi); pFix = (PFIX)lvi.lParam; // // Clear the check box, removes the 'X', clear the command line, // and clear the modules. // ListView_SetItemText(g_hwndShimList, nIndex, 1, _T("")); ListView_SetItemText(g_hwndShimList, nIndex, 2, _T("")); ListView_SetCheckState(g_hwndShimList, nIndex, FALSE); ReplaceCmdLine(pFix, NULL); BuildModuleListForShim(pFix, BML_DELFRLISTVIEW); } // // Update the count of selected shims. // SetTimer(hdlg, ID_COUNT_SHIMS, 100, NULL); } void AddMatchingFile( HWND hdlg, LPCTSTR pszFullPath, LPCTSTR pszRelativePath, BOOL bMainEXE ) /*++ AddMatchingFile Description: Adds a matching file and it's attributes to the tree. --*/ { TVINSERTSTRUCT is; HTREEITEM hParent; DWORD dwCount; DWORD dwAttrCount; TCHAR szItem[MAX_PATH]; PATTRINFO pAttrInfo = NULL; // // Call the attribute manager to get all the attributes for this file. // if (!SdbGetFileAttributes(pszFullPath, &pAttrInfo, &dwAttrCount)) { DPF("[AddMatchingFile] Failed to get attributes for %S", pszFullPath); return; } is.hParent = TVI_ROOT; is.hInsertAfter = TVI_LAST; is.item.lParam = (LPARAM)pAttrInfo; is.item.mask = TVIF_TEXT | TVIF_PARAM; is.item.pszText = (LPTSTR)pszRelativePath; hParent = TreeView_InsertItem(g_hwndFilesTree, &is); is.hParent = hParent; is.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; is.item.pszText = szItem; is.item.iImage = 0; is.item.iSelectedImage = 1; // // By default the attributes are not selected. To have them selected // by default you need to replace the following 1 with 2. // is.item.state = INDEXTOSTATEIMAGEMASK(1); is.item.stateMask = TVIS_STATEIMAGEMASK; // // Loop through all the attributes and show the ones that are available. // for (dwCount = 0; dwCount < dwAttrCount; dwCount++) { if (!SdbFormatAttribute(&pAttrInfo[dwCount], szItem, ARRAYSIZE(szItem))) { continue; } // // EXETYPE is a bogus attribute. Don't show it! // is.item.lParam = dwCount; TreeView_InsertItem(g_hwndFilesTree, &is); } TreeView_Expand(g_hwndFilesTree, hParent, TVE_EXPAND); } void BrowseForApp( HWND hdlg ) /*++ BrowseForApp Description: Browse for the main executable for which a shim will be applied. --*/ { TCHAR szFilter[MAX_PATH] = _T(""); TCHAR szTitle[MAX_PATH] = _T(""); TCHAR szExe[MAX_PATH] = _T(""); TCHAR szShortName[MAX_PATH] = _T(""); OPENFILENAME ofn = {0}; HRESULT hr; LoadString(g_hInstance, IDS_BROWSE_FILTER, szFilter, ARRAYSIZE(szFilter)); LoadString(g_hInstance, IDS_BROWSE_TITLE, szTitle, ARRAYSIZE(szTitle)); // // Use locals instead of globals because if the user cancels // the dialog without selecting, we'll ruin whatever app is // already selected. // rparsons - 14 Jan 02 // ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hdlg; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = szExe; ofn.nMaxFile = ARRAYSIZE(szExe); ofn.lpstrFileTitle = szShortName; ofn.nMaxFileTitle = ARRAYSIZE(szShortName); ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = szTitle; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = _T("exe"); if (GetOpenFileName(&ofn)) { TCHAR szMainEXE[128]; g_bSDBInstalled = FALSE; StringCchCopy(g_szBinary, ARRAYSIZE(g_szBinary), szExe); StringCchCopy(g_szShortName, ARRAYSIZE(g_szShortName), szShortName); // // The parent exe defaults to the same as the EXE. // StringCchCopy(g_szParentExeName, ARRAYSIZE(g_szParentExeName), g_szShortName); StringCchCopy(g_szParentExeFullPath, ARRAYSIZE(g_szParentExeFullPath), g_szBinary); g_bSelectedParentExe = FALSE; SetDlgItemText(hdlg, IDC_BINARY, g_szBinary); EnableWindow(GetDlgItem(hdlg, IDC_ADD_MATCHING), TRUE); EnableWindow(GetDlgItem(hdlg, IDC_RUN), TRUE); EnableWindow(GetDlgItem(hdlg, IDC_CREATEFILE), TRUE); EnableWindow(GetDlgItem(hdlg, IDC_SHOWXML), TRUE); TreeView_DeleteAllItems(g_hwndFilesTree); hr = StringCchPrintf(szMainEXE, ARRAYSIZE(szMainEXE), _T("Main executable (%s)"), g_szShortName); if (FAILED(hr)) { DPF("[BrowseForApp] 0x%08X Buffer too small", HRESULT_CODE(hr)); return; } AddMatchingFile(hdlg, g_szBinary, szMainEXE, TRUE); } } void PromptAddMatchingFile( HWND hdlg ) /*++ PromptAddMatchingFile Description: Show the open file dialog to allow the user to add a matching file. --*/ { TCHAR szFullPath[MAX_PATH] = _T(""); TCHAR szShortName[MAX_PATH] = _T(""); TCHAR szFilter[MAX_PATH] = _T(""); TCHAR szTitle[MAX_PATH] = _T(""); TCHAR szParentTitle[MAX_PATH] = _T(""); TCHAR szInitialPath[MAX_PATH] = _T(""); TCHAR szDrive[_MAX_DRIVE] = _T(""); TCHAR szDir[_MAX_DIR] = _T(""); TCHAR* pMatch = NULL; TCHAR szError[MAX_PATH]; OPENFILENAME ofn = {0}; *szInitialPath = 0; LoadString(g_hInstance, IDS_MATCH_FILTER, szFilter, ARRAYSIZE(szFilter)); LoadString(g_hInstance, IDS_MATCH_TITLE, szTitle, ARRAYSIZE(szTitle)); if (*g_szParentExeFullPath) { _tsplitpath(g_szParentExeFullPath, szDrive, szDir, NULL, NULL); StringCchCopy(szInitialPath, ARRAYSIZE(szInitialPath), szDrive); StringCchCat(szInitialPath, ARRAYSIZE(szInitialPath), szDir); } ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hdlg; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = szFullPath; ofn.nMaxFile = ARRAYSIZE(szFullPath); ofn.lpstrFileTitle = szShortName; ofn.nMaxFileTitle = ARRAYSIZE(szShortName); ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = szTitle; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = _T("exe"); if (GetOpenFileName(&ofn)) { // // Determine if the matching file is on the same drive // as the EXE that was selected. // if (!PathIsSameRoot(szFullPath, g_szParentExeFullPath) && !g_bSelectedParentExe) { TCHAR szParentFile[MAX_PATH]; // // Prompt the user for the parent EXE. // *szParentFile = 0; *szInitialPath = 0; if (*szFullPath) { _tsplitpath(szFullPath, szDrive, szDir, NULL, NULL); StringCchCopy(szInitialPath, ARRAYSIZE(szInitialPath), szDrive); StringCchCat(szInitialPath, ARRAYSIZE(szInitialPath), szDir); } LoadString(g_hInstance, IDS_PARENT_TITLE, szParentTitle, ARRAYSIZE(szParentTitle)); ofn.lpstrTitle = szParentTitle; ofn.lpstrFile = szParentFile; ofn.nMaxFile = sizeof(szParentFile); if (GetOpenFileName(&ofn) == TRUE) { StringCchCopy(g_szParentExeName, ARRAYSIZE(g_szParentExeName), szShortName); StringCchCopy(g_szParentExeFullPath, ARRAYSIZE(g_szParentExeFullPath), szParentFile); g_bSelectedParentExe = TRUE; } } // // Check the drive letters to see which drive the match file is on // then calculate a relative path to the matching file. // if (PathIsSameRoot(szFullPath, g_szParentExeFullPath)) { pMatch = GetRelativePath(g_szParentExeFullPath, szFullPath); } else if (PathIsSameRoot(szFullPath, g_szBinary)) { pMatch = GetRelativePath(g_szBinary, szFullPath); } else { LoadString(g_hInstance, IDS_MATCH_PATH_NOT_RELATIVE, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION); return; } if (pMatch) { // // Finally add the maching file and free the memory // AddMatchingFile(hdlg, szFullPath, pMatch, FALSE); HeapFree(GetProcessHeap(), 0, pMatch); } } } void ShowAvailableFixes( HWND hList ) /*++ ShowAvailableFixes Description: Query the shim database and populate the shim list with all the available shims. --*/ { LVITEM lvitem; PFIX pFix; TCHAR szError[MAX_PATH]; UINT uCount = 0; g_pFixHead = ReadFixesFromSdb(_T("sysmain.sdb"), g_bAllShims); if (g_pFixHead == NULL) { LoadString(g_hInstance, IDS_SDB_READ_FAIL, szError, ARRAYSIZE(szError)); MessageBox(NULL, szError, g_szAppTitle, MB_ICONERROR); return; } // // Walk the list and add all the fixes to the list view. // pFix = g_pFixHead; while (pFix != NULL) { if (pFix->dwFlags & FIX_TYPE_LAYER) { LPARAM lInd; lInd = SendMessage(g_hwndListLayers, LB_ADDSTRING, 0, (LPARAM)pFix->pszName); SendMessage(g_hwndListLayers, LB_SETITEMDATA, lInd, (LPARAM)pFix); } else { lvitem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE; lvitem.lParam = (LPARAM)pFix; lvitem.pszText = pFix->pszName; lvitem.iItem = ListView_GetItemCount(g_hwndShimList); lvitem.iSubItem = 0; lvitem.state = INDEXTOSTATEIMAGEMASK(1); lvitem.stateMask = LVIS_STATEIMAGEMASK; ListView_InsertItem(hList, &lvitem); } pFix = pFix->pNext; } } BOOL InstallSDB( TCHAR* pszFileName, BOOL fInstall ) /*++ InstallSDB Description: Launch sdbinst.exe to install or uninstall the specified SDB. --*/ { HRESULT hr; TCHAR szAppName[MAX_PATH]; TCHAR szCmdLine[MAX_PATH]; STARTUPINFO si; PROCESS_INFORMATION pi; // // Build a path to our application name and command-line. // hr = StringCchPrintf(szAppName, ARRAYSIZE(szAppName), _T("%s\\sdbinst.exe"), g_szSysDir); if (FAILED(hr)) { DPF("[InstallSDB] 0x%08X Buffer too small (1)", HRESULT_CODE(hr)); return FALSE; } hr = StringCchPrintf(szCmdLine, ARRAYSIZE(szCmdLine), fInstall ? _T("\"%s\" -q \"%s\"") : _T("\"%s\" -q -u \"%s\""), szAppName, pszFileName); if (FAILED(hr)) { DPF("[InstallSDB] 0x%08X Buffer too small (2)", HRESULT_CODE(hr)); return FALSE; } ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(si); DPF("[InstallSDB] AppName: %S CmdLine: %S\n", szAppName, szCmdLine); if (!CreateProcess(szAppName, szCmdLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { DPF("[InstallSDB] 0x%08X CreateProcess '%S %S' failed", szAppName, szCmdLine, GetLastError()); return FALSE; } // // Wait for SDBInst to complete it's work. // WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return TRUE; } void CreateSupportForApp( HWND hdlg ) /*++ CreateSupportForApp Description: Build an SDB for the application and offer the user the chance to install it. --*/ { BOOL bok; TCHAR szFileCreated[MAX_PATH]; TCHAR szError[MAX_PATH]; TCHAR szTemp[MAX_PATH]; HRESULT hr; int nAnswer; CleanupSupportForApp(g_szShortName); bok = CollectFix(g_hwndListLayers, g_hwndShimList, g_hwndFilesTree, g_szShortName, g_szBinary, (g_nCrtTab == 0 ? CFF_USELAYERTAB : 0) | (g_fW2K ? CFF_ADDW2KSUPPORT : 0), szFileCreated); if (!bok) { LoadString(g_hInstance, IDS_FIX_CREATE_FAIL, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONERROR); } else { LoadString(g_hInstance, IDS_CREATE_FIX, szTemp, ARRAYSIZE(szTemp)); hr = StringCchPrintf(szError, ARRAYSIZE(szError), szTemp, szFileCreated); if (FAILED(hr)) { DPF("[CreateSupportForApp] 0x%08X Buffer too small", HRESULT_CODE(hr)); return; } nAnswer = MessageBox(hdlg, szError, g_szAppTitle, MB_YESNO | MB_ICONQUESTION); if (IDYES == nAnswer) { bok = InstallSDB(szFileCreated, TRUE); if (!bok) { LoadString(g_hInstance, IDS_INSTALL_FIX_FAIL, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONERROR); } else { LoadString(g_hInstance, IDS_INSTALL_FIX_OK, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONINFORMATION); g_bSDBInstalled = TRUE; } } else { // // NTRAID#583475-rparsons The user decided not to install the database. // Ensure that we do not remove the file that we created upon exit. // *g_szSDBToDelete = 0; } } } BOOL ShowXML( HWND hdlg ) /*++ ShowXML Description: Show the XML for the current selections. --*/ { BOOL bok; TCHAR szError[MAX_PATH]; bok = CollectFix(g_hwndListLayers, g_hwndShimList, g_hwndFilesTree, g_szShortName, g_szBinary, CFF_SHOWXML | (g_nCrtTab == 0 ? CFF_USELAYERTAB : 0) | (g_fW2K ? CFF_ADDW2KSUPPORT : 0), NULL); if (!bok) { LoadString(g_hInstance, IDS_TOO_MANY_FILES, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION); } return bok; } void RunTheApp( HWND hdlg ) /*++ RunTheApp Description: Run the selected app. --*/ { STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR szFileCreated[MAX_PATH]; TCHAR szCmdLine[MAX_PATH]; TCHAR szFullCmdLine[MAX_PATH]; TCHAR szError[MAX_PATH]; TCHAR szRun[MAX_PATH]; TCHAR* pszCmd; TCHAR* pszDir; TCHAR* psz; BOOL bok; HRESULT hr; // // Cleanup for the previous app. // CleanupSupportForApp(g_szShortName); bok = CollectFix(g_hwndListLayers, g_hwndShimList, g_hwndFilesTree, g_szShortName, g_szBinary, CFF_SHIMLOG | CFF_APPENDLAYER | (g_nCrtTab == 0 ? CFF_USELAYERTAB : 0) | (g_fW2K ? CFF_ADDW2KSUPPORT : 0), szFileCreated); if (!bok) { LoadString(g_hInstance, IDS_ADD_SUPPORT_FAIL, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONERROR); return; } // // We need to install the fix for them. // if (!(InstallSDB(szFileCreated, TRUE))) { LoadString(g_hInstance, IDS_INSTALL_FIX_FAIL, szError, ARRAYSIZE(szError)); MessageBox(g_hDlg, szError, g_szAppTitle, MB_ICONERROR); return; } ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); // // Get the command line, if there is one. // *szCmdLine = 0; *szFullCmdLine = 0; GetDlgItemText(hdlg, IDC_CMD_LINE, szCmdLine, ARRAYSIZE(szCmdLine)); // // To have a proper command-line, we need to the module name. // if (*szCmdLine) { hr = StringCchPrintf(szFullCmdLine, ARRAYSIZE(szFullCmdLine), _T("%s %s"), g_szBinary, szCmdLine); if (FAILED(hr)) { DPF("[RunTheApp] 0x%08X Buffer too small", HRESULT_CODE(hr)); LoadString(g_hInstance, IDS_RUNAPP_FAILED, szError, ARRAYSIZE(szError)); MessageBox(g_hDlg, szError, g_szAppTitle, MB_ICONERROR); return; } } StringCchCopy(szRun, ARRAYSIZE(szRun), g_szBinary); pszCmd = szRun; pszDir = g_szBinary; // // We need to change the current directory or some apps won't run. // psz = pszDir + _tcslen(pszDir) - 1; while (psz > pszDir && *psz != _T('\\')) { psz--; } if (psz > pszDir) { *psz = 0; SetCurrentDirectory(pszDir); *psz = _T('\\'); } DPF("[RunTheApp] AppName: %S CmdLine: %S", szRun, szCmdLine); if (!CreateProcess(szRun, *szFullCmdLine ? szFullCmdLine : NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_SEPARATE_WOW_VDM, NULL, NULL, &si, &pi)) { LoadString(g_hInstance, IDS_RUNAPP_FAILED, szError, ARRAYSIZE(szError)); MessageBox(g_hDlg, szError, g_szAppTitle, MB_ICONERROR); DPF("[RunTheApp] CreateProcess failed 0x%08X", GetLastError()); } else { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } // // Save this SDB for later so we can remove it. // StringCchCopy(g_szSDBToDelete, ARRAYSIZE(g_szSDBToDelete), szFileCreated); } void ExpandCollapseDialog( HWND hdlg, BOOL bHide ) /*++ ExpandCollapseDialog Description: Change the current view of the dialog. --*/ { TCHAR szSimple[64]; TCHAR szAdvanced[64]; int i, nShow; DWORD arrId[] = {IDC_ADD_MATCHING, IDC_FILE_ATTRIBUTES_STATIC, IDC_ATTRIBUTES, IDC_CREATEFILE, 0}; if (!bHide) { SetWindowPos(hdlg, NULL, 0, 0, g_rcDlgBig.right - g_rcDlgBig.left, g_rcDlgBig.bottom - g_rcDlgBig.top, SWP_NOMOVE | SWP_NOZORDER); nShow = SW_SHOW; g_bSimpleEdition = FALSE; LoadString(g_hInstance, IDS_SIMPLE_TEXT, szSimple, ARRAYSIZE(szSimple)); SetDlgItemText(hdlg, IDC_DETAILS, szSimple); SendDlgItemMessage(hdlg, IDC_CREATEFILE, BM_SETCHECK, BST_CHECKED, 0); // // Make sure the dialog is in view. // GetTopLevelWindowIntoView(hdlg); } else { nShow = SW_HIDE; g_bSimpleEdition = TRUE; LoadString(g_hInstance, IDS_ADVANCED_TEXT, szAdvanced, ARRAYSIZE(szAdvanced)); SetDlgItemText(hdlg, IDC_DETAILS, szAdvanced); SendDlgItemMessage(hdlg, IDC_CREATEFILE, BM_SETCHECK, BST_UNCHECKED, 0); } for (i = 0; arrId[i] != 0; i++) { ShowWindow(GetDlgItem(hdlg, arrId[i]), nShow); } if (bHide) { SetWindowPos(hdlg, NULL, 0, 0, g_rcDlgSmall.right - g_rcDlgSmall.left, g_rcDlgSmall.bottom - g_rcDlgSmall.top, SWP_NOMOVE | SWP_NOZORDER); } } void LayerChanged( HWND hdlg ) /*++ LayerChanged Description: Changing the layer has the effect of selecting the shims that the layer consists of. --*/ { LRESULT lSel; PFIX pFix; LVITEM lvi; int nIndex, cShims = 0; lSel = SendMessage(g_hwndListLayers, LB_GETCURSEL, 0, 0); if (lSel == LB_ERR) { DPF("[LayerChanged] No layer selected"); return; } pFix = (PFIX)SendMessage(g_hwndListLayers, LB_GETITEMDATA, lSel, 0); if (pFix->parrShim == NULL) { DPF("[LayerChanged] No array of DLLs"); return; } // Remove any prior selections. DeselectAllShims(g_hFixesDlg); // // Loop through all the items in the shim list and make the // appropriate selections. // cShims = ListView_GetItemCount(g_hwndShimList); for (nIndex = 0; nIndex < cShims; nIndex++) { PFIX pFixItem; int nInd = 0; lvi.mask = LVIF_PARAM; lvi.iItem = nIndex; lvi.iSubItem = 0; ListView_GetItem(g_hwndShimList, &lvi); pFixItem = (PFIX)lvi.lParam; // // See if this shim DLL is in the array for the selected layer. // while (pFix->parrShim[nInd] != NULL) { if (pFix->parrShim[nInd] == pFixItem) { break; } nInd++; } // // Put a check next to this shim DLL. If he has a command line, // put an 'X' in the CmdLine subitem. // if (pFix->parrShim[nInd] != NULL) { ListView_SetCheckState(g_hwndShimList, nIndex, TRUE); } else { ListView_SetCheckState(g_hwndShimList, nIndex, FALSE); } if (pFix->parrCmdLine[nInd] != NULL) { ReplaceCmdLine(pFixItem, pFix->parrCmdLine[nInd]); ListView_SetItemText(g_hwndShimList, nIndex, 1, _T("X")); } ListView_SetItem(g_hwndShimList, &lvi); } // // Update the count of selected shims. // SetTimer(g_hFixesDlg, ID_COUNT_SHIMS, 100, NULL); } BOOL InitMainDialog( HWND hdlg ) /*++ InitMainDialog Description: Init routine called during WM_INITDIALOG for the main dialog of QFixApp. --*/ { HICON hIcon; RECT rcList, rcTree; HIMAGELIST hImage; TCHAR szText[MAX_PATH]; // // Initialize globals. // g_bSDBInstalled = FALSE; g_szParentExeFullPath[0] = 0; g_szBinary[0] = 0; g_hDlg = hdlg; // // If we didn't get the proper command-line, disable the 'Show XML' // button. // if (!g_bShowXML) { ShowWindow(GetDlgItem(hdlg, IDC_SHOWXML), SW_HIDE); } // // The dialog has two views. Calculate the size of the smaller // view and show the simpler view by default. // GetWindowRect(hdlg, &g_rcDlgBig); GetWindowRect(GetDlgItem(hdlg, IDC_ATTRIBUTES), &rcList); GetWindowRect(GetDlgItem(hdlg, IDC_TAB_FIXES), &rcTree); g_rcDlgSmall.left = g_rcDlgBig.left; g_rcDlgSmall.top = g_rcDlgBig.top; g_rcDlgSmall.bottom = g_rcDlgBig.bottom; g_rcDlgSmall.right = g_rcDlgBig.right - (rcList.right - rcList.left) - (rcList.left - rcTree.right); ExpandCollapseDialog(hdlg, TRUE); // // Disable a bunch of controls. // EnableWindow(GetDlgItem(hdlg, IDC_ADD_MATCHING), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_REMOVE_MATCHING), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_RUN), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_CREATEFILE), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_SHOWXML), FALSE); // // Show the app icon. // hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON)); SetClassLongPtr(hdlg, GCLP_HICON, (LONG_PTR)hIcon); g_hwndTab = GetDlgItem(hdlg, IDC_TAB_FIXES); g_hwndFilesTree = GetDlgItem(hdlg, IDC_ATTRIBUTES); // // Set up the tab control. // InitTabs(hdlg, g_hwndTab); hImage = ImageList_LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_BMP_CHECK), 16, 0, CLR_DEFAULT, IMAGE_BITMAP, LR_LOADTRANSPARENT); if (hImage != NULL) { TreeView_SetImageList(g_hwndFilesTree, hImage, TVSIL_STATE); } else { DPF("[InitMainDialog] Failed to load imagelist"); } // // Set the text for the link window. // LoadString(g_hInstance, g_fW2K ? IDS_W2K_LINK : IDS_XP_LINK, szText, ARRAYSIZE(szText)); SetDlgItemText(g_hDlg, IDC_DOWNLOAD_WU, szText); // // Limit the amount of text that can be typed into the command-line // edit box for safety. // SendDlgItemMessage(hdlg, IDC_CMD_LINE, EM_LIMITTEXT, (WPARAM)MAX_COMMAND_LINE, 0); // // Try selecting the Win95 layer. // SendMessage(g_hwndListLayers, LB_SELECTSTRING, (WPARAM)(-1), (LPARAM)_T("Win95")); LayerChanged(hdlg); TabCtrl_SetCurFocus(g_hwndTab, 0); ShowWindow(g_hLayersDlg, SW_SHOWNORMAL); return TRUE; } void FileTreeToggleSelection( HTREEITEM hItem, int uMode ) /*++ FileTreeToggleSelection Description: Changes the selection on the attributes tree. --*/ { UINT State; TVITEM item; switch (uMode) { case uSelect: State = INDEXTOSTATEIMAGEMASK(2); break; case uDeselect: State = INDEXTOSTATEIMAGEMASK(1); break; case uReverse: { item.mask = TVIF_HANDLE | TVIF_STATE; item.hItem = hItem; item.stateMask = TVIS_STATEIMAGEMASK; TreeView_GetItem(g_hwndFilesTree, &item); State = item.state & TVIS_STATEIMAGEMASK; if (State) { if (((State >> 12) & 0x03) == 2) { State = INDEXTOSTATEIMAGEMASK(1); } else { State = INDEXTOSTATEIMAGEMASK(2); } } break; } default: DPF("[FileTreeToggleSelection] Invalid mode %u", uMode); return; } item.mask = TVIF_HANDLE | TVIF_STATE; item.hItem = hItem; item.state = State; item.stateMask = TVIS_STATEIMAGEMASK; TreeView_SetItem(g_hwndFilesTree, &item); } void SelectAttrsInTree( BOOL fSelect ) /*++ SelectAttrsInTree Description: Walks each attribute in tree and reverses it's selection. --*/ { HTREEITEM hItem, hChildItem; hItem = TreeView_GetSelection(g_hwndFilesTree); hChildItem = TreeView_GetChild(g_hwndFilesTree, hItem); FileTreeToggleSelection(hChildItem, fSelect ? uSelect : uDeselect); while (hChildItem) { hChildItem = TreeView_GetNextSibling(g_hwndFilesTree, hChildItem); FileTreeToggleSelection(hChildItem, fSelect ? uSelect : uDeselect); } } void ShimListToggleSelection( int nItem, int uMode ) /*++ ShimListToggleSelection Description: Changes the selection on the shim list. --*/ { UINT uState; switch (uMode) { case uSelect: ListView_SetCheckState(g_hwndShimList, nItem, TRUE); break; case uDeselect: ListView_SetCheckState(g_hwndShimList, nItem, FALSE); break; case uReverse: uState = ListView_GetItemState(g_hwndShimList, nItem, LVIS_STATEIMAGEMASK); if (uState) { if (((uState >> 12) & 0x03) == 2) { uState = INDEXTOSTATEIMAGEMASK(2); } else { uState = INDEXTOSTATEIMAGEMASK(1); } } ListView_SetItemState(g_hwndShimList, nItem, uState, LVIS_STATEIMAGEMASK); break; } } void HandleTabNotification( HWND hdlg, LPARAM lParam ) /*++ HandleTabNotification Description: Handle all the notifications we care about for the tab. --*/ { LPNMHDR pnm = (LPNMHDR)lParam; int ind = 0; switch (pnm->code) { case TCN_SELCHANGE: { int nSel; DLGHDR *pHdr = (DLGHDR*)GetWindowLongPtr(hdlg, DWLP_USER); nSel = TabCtrl_GetCurSel(pHdr->hTab); if (-1 == nSel) { break; } g_nCrtTab = nSel; if (nSel == 0) { ShowWindow(pHdr->hDisplay[1], SW_HIDE); ShowWindow(pHdr->hDisplay[0], SW_SHOW); } else { ShowWindow(pHdr->hDisplay[0], SW_HIDE); ShowWindow(pHdr->hDisplay[1], SW_SHOW); } break; } default: break; } } INT_PTR CALLBACK OptionsDlgProc( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) /*++ OptionsDlgProc Description: Handles messages for the options dialog. --*/ { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); switch (uMsg) { case WM_INITDIALOG: { PFIX pFix; TCHAR szTitle[MAX_PATH]; TCHAR szTemp[MAX_PATH]; TCHAR szType[64]; TCHAR szModuleName[128]; HRESULT hr; pFix = (PFIX)lParam; // // Limit the amount of text that can be typed into the command-line // and module name edit boxes for safety. // SendDlgItemMessage(hdlg, IDC_SHIM_CMD_LINE, EM_LIMITTEXT, (WPARAM)SHIM_COMMAND_LINE_MAX_BUFFER, 0); SendDlgItemMessage(hdlg, IDC_MOD_NAME, EM_LIMITTEXT, (WPARAM)MAX_PATH, 0); LoadString(g_hInstance, IDS_MOD_TYPE, szType, ARRAYSIZE(szType)); LoadString(g_hInstance, IDS_MOD_NAME, szModuleName, ARRAYSIZE(szModuleName)); LoadString(g_hInstance, IDS_OPTIONS_TITLE, szTemp, ARRAYSIZE(szTemp)); SetWindowLongPtr(hdlg, DWLP_USER, lParam); EnableWindow(GetDlgItem(hdlg, IDC_REMOVE), FALSE); g_hwndModuleList = GetDlgItem(hdlg, IDC_MOD_LIST); InsertListViewColumn(g_hwndModuleList, szType, FALSE, 0, 75); InsertListViewColumn(g_hwndModuleList, szModuleName, FALSE, 1, 115); ListView_SetExtendedListViewStyle(g_hwndModuleList, LVS_EX_FULLROWSELECT); hr = StringCchPrintf(szTitle, ARRAYSIZE(szTitle), szTemp, pFix->pszName); if (FAILED(hr)) { DPF("[OptionsDlgProc] 0x%08X Buffer too small", HRESULT_CODE(hr)); return 0; } SetWindowText(hdlg, szTitle); if (NULL != pFix->pszCmdLine) { SetDlgItemText(hdlg, IDC_SHIM_CMD_LINE, pFix->pszCmdLine); } // // If this is a flag, disable the module include/exclude controls. // if (pFix->dwFlags & FIX_TYPE_FLAGVDM) { EnableWindow(g_hwndModuleList, FALSE); EnableWindow(GetDlgItem(hdlg, IDC_ADD), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_REMOVE), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_INCLUDE), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_EXCLUDE), FALSE); EnableWindow(GetDlgItem(hdlg, IDC_MOD_NAME), FALSE); } else { CheckDlgButton(hdlg, IDC_INCLUDE, BST_CHECKED); // Add any modules to the list view. BuildModuleListForShim(pFix, BML_ADDTOLISTVIEW); } break; } case WM_NOTIFY: HandleModuleListNotification(hdlg, lParam); break; case WM_COMMAND: switch (wCode) { case IDC_ADD: { TCHAR szModName[MAX_PATH]; TCHAR szError[MAX_PATH]; UINT uInclude, uExclude; GetDlgItemText(hdlg, IDC_MOD_NAME, szModName, ARRAYSIZE(szModName)); if (*szModName == 0) { LoadString(g_hInstance, IDS_NO_MOD, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION); SetFocus(GetDlgItem(hdlg, IDC_MOD_NAME)); break; } uInclude = IsDlgButtonChecked(hdlg, IDC_INCLUDE); uExclude = IsDlgButtonChecked(hdlg, IDC_EXCLUDE); if ((BST_CHECKED == uInclude) || (BST_CHECKED == uExclude)) { AddModuleToListView(szModName, uInclude); SetDlgItemText(hdlg, IDC_MOD_NAME, _T("")); SetFocus(GetDlgItem(hdlg, IDC_MOD_NAME)); } else { LoadString(g_hInstance, IDS_NO_INCEXC, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION); SetFocus(GetDlgItem(hdlg, IDC_INCLUDE)); break; } break; } case IDC_REMOVE: { int nIndex; nIndex = ListView_GetSelectionMark(g_hwndModuleList); ListView_DeleteItem(g_hwndModuleList, nIndex); EnableWindow(GetDlgItem(hdlg, IDC_REMOVE), FALSE); SetFocus(GetDlgItem(hdlg, IDC_MOD_NAME)); break; } case IDOK: { PFIX pFix; TCHAR szCmdLine[1024] = _T(""); pFix = (PFIX)GetWindowLongPtr(hdlg, DWLP_USER); GetDlgItemText(hdlg, IDC_SHIM_CMD_LINE, szCmdLine, 1023); if (*szCmdLine != 0) { ReplaceCmdLine(pFix, szCmdLine); } else { ReplaceCmdLine(pFix, NULL); } // Retrieve any modules from the list view. BuildModuleListForShim(pFix, BML_GETFRLISTVIEW); EndDialog(hdlg, TRUE); break; } case IDCANCEL: EndDialog(hdlg, FALSE); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } INT_PTR CALLBACK MsgBoxDlgProc( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) /*++ MsgBoxDlgProc Description: Displays a message box dialog so we can use the hyperlink. --*/ { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); switch (uMsg) { case WM_INITDIALOG: { TCHAR szLink[MAX_PATH]; UINT uNoSDB; uNoSDB = (UINT)lParam; // // Use the parameter to determine what text to display. // if (uNoSDB) { LoadString(g_hInstance, IDS_W2K_NO_SDB, szLink, ARRAYSIZE(szLink)); SetDlgItemText(hdlg, IDC_MESSAGE, szLink); } else { LoadString(g_hInstance, IDS_SP2_SDB, szLink, ARRAYSIZE(szLink)); SetDlgItemText(hdlg, IDC_MESSAGE, szLink); } LoadString(g_hInstance, IDS_MSG_LINK, szLink, ARRAYSIZE(szLink)); SetDlgItemText(hdlg, IDC_MSG_LINK, szLink); break; } case WM_NOTIFY: if (wParam == IDC_MSG_LINK) { NMHDR* pHdr = (NMHDR*)lParam; if (pHdr->code == NM_CLICK || pHdr->code == NM_RETURN) { SHELLEXECUTEINFO sei = { 0 }; sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.fMask = SEE_MASK_DOENVSUBST; sei.hwnd = hdlg; sei.nShow = SW_SHOWNORMAL; sei.lpFile = g_szW2KUrl; ShellExecuteEx(&sei); break; } } break; case WM_COMMAND: switch (wCode) { case IDCANCEL: EndDialog(hdlg, TRUE); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } INT_PTR CALLBACK LayersTabDlgProc( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) /*++ LayersTabDlgProc Description: Handle messages for the layers tab. --*/ { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); switch (uMsg) { case WM_INITDIALOG: HandleLayersDialogInit(hdlg); break; case WM_COMMAND: if (wNotifyCode == LBN_SELCHANGE && wCode == IDC_LAYERS) { LayerChanged(hdlg); break; } switch (wCode) { case IDCANCEL: EndDialog(hdlg, TRUE); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } INT_PTR CALLBACK FixesTabDlgProc( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) /*++ LayersDlgProc Description: Handle messages for the fixes tab. --*/ { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); switch (uMsg) { case WM_INITDIALOG: if (!HandleFixesDialogInit(hdlg)) { EndDialog(g_hDlg, 0); } break; case WM_NOTIFY: if (wParam == IDC_SHIMS) { HandleShimListNotification(hdlg, lParam); } break; case WM_TIMER: if (wParam == ID_COUNT_SHIMS) { KillTimer(hdlg, ID_COUNT_SHIMS); CountShims(TRUE); } break; case WM_COMMAND: switch (wCode) { case IDCANCEL: EndDialog(hdlg, TRUE); break; case IDC_CLEAR_SHIMS: DeselectAllShims(hdlg); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } void HandleModuleListNotification( HWND hdlg, LPARAM lParam ) /*++ HandleModuleListNotification Description: Handle all the notifications we care about for the shim list. --*/ { LPNMHDR pnm = (LPNMHDR)lParam; switch (pnm->code) { case NM_CLICK: { LVHITTESTINFO lvhti; GetCursorPos(&lvhti.pt); ScreenToClient(g_hwndShimList, &lvhti.pt); ListView_HitTest(g_hwndShimList, &lvhti); // // If the user clicked on a list view item, // enable the Remove button. // if (lvhti.flags & LVHT_ONITEMLABEL) { EnableWindow(GetDlgItem(hdlg, IDC_REMOVE), TRUE); } break; } default: break; } } void HandleShimListNotification( HWND hdlg, LPARAM lParam ) /*++ HandleShimListNotification Description: Handle all the notifications we care about for the shim list. --*/ { LPNMHDR pnm = (LPNMHDR)lParam; switch (pnm->code) { case NM_CLICK: { LVHITTESTINFO lvhti; GetCursorPos(&lvhti.pt); ScreenToClient(g_hwndShimList, &lvhti.pt); ListView_HitTest(g_hwndShimList, &lvhti); // // If the check box state has changed, // toggle the selection. Either way, // maintain selection as we go. // if (lvhti.flags & LVHT_ONITEMSTATEICON) { ShimListToggleSelection(lvhti.iItem, uReverse); } ListView_SetItemState(g_hwndShimList, lvhti.iItem, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); SetTimer(hdlg, ID_COUNT_SHIMS, 100, NULL); break; } case NM_DBLCLK: { LVITEM lvi; int nItem; PFIX pFix; nItem = ListView_GetSelectionMark(g_hwndShimList); if (-1 == nItem) { break; } lvi.mask = LVIF_PARAM; lvi.iItem = nItem; ListView_GetItem(g_hwndShimList, &lvi); pFix = (PFIX)lvi.lParam; if ((pFix->dwFlags & FIX_TYPE_SHIM) || (pFix->dwFlags & FIX_TYPE_FLAGVDM)) { if (DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_OPTIONS), hdlg, OptionsDlgProc, (LPARAM)pFix)) { if (NULL != pFix->pszCmdLine) { ListView_SetItemText(g_hwndShimList, nItem, 1, _T("X")); } else { ListView_SetItemText(g_hwndShimList, nItem, 1, _T("")); } if (NULL != pFix->pModule) { ListView_SetItemText(g_hwndShimList, nItem, 2, _T("X")); } else { ListView_SetItemText(g_hwndShimList, nItem, 2, _T("")); } } } break; } case LVN_ITEMCHANGED: { LPNMLISTVIEW lpnmlv; PFIX pFix; lpnmlv = (LPNMLISTVIEW)lParam; pFix = (PFIX)lpnmlv->lParam; // // Only change the text if our selection has changed. // If we don't do this, the text goes bye-bye when // the user clicks the Clear button. // if ((lpnmlv->uChanged & LVIF_STATE) && (lpnmlv->uNewState & LVIS_SELECTED)) { SetDlgItemText(hdlg, IDC_SHIM_DESCRIPTION, pFix->pszDesc); ListView_SetSelectionMark(g_hwndShimList, lpnmlv->iItem); } break; } default: break; } } void HandleAttributeTreeNotification( HWND hdlg, LPARAM lParam ) /*++ HandleAttributeTreeNotification Description: Handle all the notifications we care about for the file attributes tree. --*/ { LPNMHDR pnm = (LPNMHDR)lParam; switch (pnm->code) { case NM_CLICK: { TVHITTESTINFO HitTest; GetCursorPos(&HitTest.pt); ScreenToClient(g_hwndFilesTree, &HitTest.pt); TreeView_HitTest(g_hwndFilesTree, &HitTest); if (HitTest.flags & TVHT_ONITEMSTATEICON) { FileTreeToggleSelection(HitTest.hItem, uReverse); } else if (HitTest.flags & TVHT_ONITEMLABEL) { HWND hwndButton; HTREEITEM hItem, hRoot; hwndButton = GetDlgItem(hdlg, IDC_REMOVE_MATCHING); hItem = TreeView_GetParent(g_hwndFilesTree, HitTest.hItem); hRoot = TreeView_GetRoot(g_hwndFilesTree); // // If the selected item has no parent and it's not // the root, enable the remove matching button. // if ((NULL == hItem) && (hRoot != HitTest.hItem)) { EnableWindow(hwndButton, TRUE); } else { EnableWindow(hwndButton, FALSE); } } break; } case NM_RCLICK: { TVHITTESTINFO HitTest; POINT pt; GetCursorPos(&HitTest.pt); pt.x = HitTest.pt.x; pt.y = HitTest.pt.y; ScreenToClient(g_hwndFilesTree, &HitTest.pt); TreeView_HitTest(g_hwndFilesTree, &HitTest); if (HitTest.flags & TVHT_ONITEMLABEL) { HTREEITEM hParentItem; TreeView_SelectItem(g_hwndFilesTree, HitTest.hItem); // // If the selected item has no parent, we assume that a // matching file was right-clicked. // hParentItem = TreeView_GetParent(g_hwndFilesTree, HitTest.hItem); if (NULL == hParentItem) { DisplayAttrContextMenu(&pt); } } break; } case TVN_KEYDOWN: { LPNMTVKEYDOWN lpKeyDown = (LPNMTVKEYDOWN)lParam; HTREEITEM hItem; if (lpKeyDown->wVKey == VK_SPACE) { hItem = TreeView_GetSelection(g_hwndFilesTree); if (hItem != NULL) { FileTreeToggleSelection(hItem, uReverse); } } else if (lpKeyDown->wVKey == VK_DELETE) { HTREEITEM hParentItem; hItem = TreeView_GetSelection(g_hwndFilesTree); hParentItem = TreeView_GetParent(g_hwndFilesTree, hItem); if (hParentItem == NULL) { if (TreeView_GetPrevSibling(g_hwndFilesTree, hItem) != NULL) { TreeView_DeleteItem(g_hwndFilesTree, hItem); } } } break; } default: break; } } INT_PTR CALLBACK QFixAppDlgProc( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) /*++ QFixAppDlgProc Description: The dialog proc of QFixApp. --*/ { int wCode = LOWORD(wParam); int wNotifyCode = HIWORD(wParam); switch (uMsg) { case WM_INITDIALOG: if (!InitMainDialog(hdlg)) { EndDialog(hdlg, TRUE); } break; case WM_NOTIFY: if (wParam == IDC_SHIMS) { HandleShimListNotification(hdlg, lParam); } else if (wParam == IDC_ATTRIBUTES) { HandleAttributeTreeNotification(hdlg, lParam); } else if (wParam == IDC_TAB_FIXES) { HandleTabNotification(hdlg, lParam); } else if (wParam == IDC_DOWNLOAD_WU) { NMHDR* pHdr = (NMHDR*)lParam; if (pHdr->code == NM_CLICK || pHdr->code == NM_RETURN) { SHELLEXECUTEINFO sei = { 0 }; sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.fMask = SEE_MASK_DOENVSUBST; sei.hwnd = hdlg; sei.nShow = SW_SHOWNORMAL; if (g_fW2K) { sei.lpFile = g_szW2KUrl; } else if (g_fNETServer) { sei.lpFile = g_szNETUrl; } else { sei.lpFile = g_szXPUrl; } ShellExecuteEx(&sei); break; } } break; case WM_DESTROY: { DLGHDR* pHdr; // // Destory the dialogs and remove any misc files. // pHdr = (DLGHDR*)GetWindowLongPtr(hdlg, DWLP_USER); DestroyWindow(pHdr->hDisplay[0]); DestroyWindow(pHdr->hDisplay[1]); CleanupSupportForApp(g_szShortName); break; } case WM_COMMAND: if (wNotifyCode == LBN_SELCHANGE && wCode == IDC_LAYERS) { LayerChanged(hdlg); break; } switch (wCode) { case IDC_RUN: RunTheApp(hdlg); break; case IDC_BROWSE: BrowseForApp(hdlg); break; case IDC_DETAILS: ExpandCollapseDialog(hdlg, !g_bSimpleEdition); break; case IDC_CREATEFILE: CreateSupportForApp(hdlg); break; case IDC_SHOWXML: ShowXML(hdlg); break; case IDC_ADD_MATCHING: PromptAddMatchingFile(hdlg); break; case IDC_VIEW_LOG: ShowShimLog(); break; case IDCANCEL: EndDialog(hdlg, TRUE); break; case IDM_SELECT_ALL: SelectAttrsInTree(TRUE); break; case IDM_CLEAR_ALL: SelectAttrsInTree(FALSE); break; case IDC_REMOVE_MATCHING: { HTREEITEM hParentItem, hItem; TCHAR szError[MAX_PATH]; hItem = TreeView_GetSelection(g_hwndFilesTree); if (NULL == hItem) { LoadString(g_hInstance, IDS_NO_SELECTION, szError, ARRAYSIZE(szError)); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION); return TRUE; } hParentItem = TreeView_GetParent(g_hwndFilesTree, hItem); if (hParentItem == NULL) { if (TreeView_GetPrevSibling(g_hwndFilesTree, hItem) != NULL) { TreeView_DeleteItem(g_hwndFilesTree, hItem); EnableWindow(GetDlgItem(hdlg, IDC_REMOVE_MATCHING), FALSE); } } break; } default: return FALSE; } break; default: return FALSE; } return TRUE; } BOOL QFixAppInitialize( void ) /*++ QFixAppInitialize Description: Initializes common paths, etc. --*/ { UINT cchSize; INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_TAB_CLASSES; // // Initialize the common controls. // if (!InitCommonControlsEx(&icex)) { InitCommonControls(); } // // Set up our hyperlink control. // LinkWindow_RegisterClass(); // // Save away common paths for later use. // cchSize = GetSystemDirectory(g_szSysDir, ARRAYSIZE(g_szSysDir)); if (cchSize > ARRAYSIZE(g_szSysDir) || cchSize == 0) { DPF("[QFixAppInitialize] 0x%08X Failed to get system directory", GetLastError()); return FALSE; } cchSize = GetSystemWindowsDirectory(g_szWinDir, ARRAYSIZE(g_szWinDir)); if (cchSize > ARRAYSIZE(g_szWinDir) || cchSize == 0) { DPF("[QFixAppInitialize] 0x%08X Failed to get windows directory", GetLastError()); return FALSE; } return TRUE; } int WINAPI wWinMain( HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR lpszCmd, int swShow ) /*++ WinMain Description: Application entry point. --*/ { BOOL fSP2 = FALSE; TCHAR szError[MAX_PATH]; OSVERSIONINFOEX osviex; LoadString(g_hInstance, IDS_APP_TITLE, g_szAppTitle, ARRAYSIZE(g_szAppTitle)); g_hInstance = hInst; osviex.dwOSVersionInfoSize = sizeof(osviex); GetVersionEx((OSVERSIONINFO*)&osviex); // // See if they're an administrator - bail if not. // if (!(IsUserAnAdministrator())) { LoadString(g_hInstance, IDS_NOT_ADMIN, szError, ARRAYSIZE(szError)); MessageBox(NULL, szError, g_szAppTitle, MB_ICONERROR); return 0; } // // See if we're running on Windows 2000, then check for SP2, then // check for .NET Server. // if ((osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 0)) { g_fW2K = TRUE; } if (g_fW2K && (!_tcscmp(osviex.szCSDVersion, _T("Service Pack 2")))) { fSP2 = TRUE; } if (!(osviex.wProductType == VER_NT_WORKSTATION)) { g_fNETServer = TRUE; } // // Perform some necessary initialization. // if (!QFixAppInitialize()) { LoadString(g_hInstance, IDS_INIT_FAILED, szError, ARRAYSIZE(szError)); MessageBox(GetDesktopWindow(), szError, g_szAppTitle, MB_ICONERROR); return 0; } // // Attempt to locate the SDB in the AppPatch directory. // if (!CheckForSDB()) { if (g_fW2K) { DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MSGBOX_SDB), GetDesktopWindow(), MsgBoxDlgProc, (LPARAM)1); return 0; } else { LoadString(g_hInstance, IDS_XP_NO_SDB, szError, ARRAYSIZE(szError)); MessageBox(GetDesktopWindow(), szError, g_szAppTitle, MB_ICONEXCLAMATION); return 0; } } // // If this is SP2, and the SDB is older, bail out. // if (fSP2) { if (IsSDBFromSP2()) { DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MSGBOX_SP2), GetDesktopWindow(), MsgBoxDlgProc, (LPARAM)0); return 0; } } // // Check for command line options. // if (lpszCmd) { DPF("[WinMain] Command line '%S'", lpszCmd); while (*lpszCmd) { if (*lpszCmd == _T('a') || *lpszCmd == _T('A')) { g_bAllShims = TRUE; } else if (*lpszCmd == _T('x') || *lpszCmd == _T('X')) { g_bShowXML = TRUE; } lpszCmd++; } } DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG), GetDesktopWindow(), QFixAppDlgProc); return 1; }