/*************************************************************************** * Quick fix application tools * * Author: clupu (Feb 16, 2000) * * History: * * rparsons - 11/10/2000 - Modified titles on common dialogs * * rparsons - 11/23/2000 - Added ability to save XML to file * * rparsons - 11/25/2000 - Modified to allow matching file on a * different drive to be selected * * rparsons - 05/19/2001 - Added context menu on file tree. * Added URL for WU package. * Added Remove Matching button. * Converted shim list to list view. * * rparsons - 07/06/2001 - Converted static tab control to use * child dialogs. * \**************************************************************************/ #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 "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_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 RECT g_rcDlgBig, g_rcDlgSmall; // rectangle of the simple and the dev edition // of the dialog BOOL g_bAllShims; BOOL g_bSelectedParentExe; // flag to indicate if a parent EXE has been // selected 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_szW2KUrl[] = _T("http://www.microsoft.com/windows2000/") _T("downloads/tools/appcompat/"); #define ID_COUNT_SHIMS 1234 typedef HRESULT (*PFNEnableThemeDialogTexture)(HWND hwnd, DWORD dwFlags); #if DBG void LogMsgDbg( LPTSTR pszFmt, ... ) /*++ LogMsgDbg Description: DbgPrint. --*/ { TCHAR gszT[1024]; va_list arglist; va_start(arglist, pszFmt); _vsntprintf(gszT, 1023, pszFmt, arglist); gszT[1023] = 0; va_end(arglist); OutputDebugString(gszT); } #endif // DBG BOOL IsUserAnAdministrator( void ) /*++ IsUserAnAdministrator Description: Determine if the currently logged on user is an admin. --*/ { HANDLE hToken; DWORD dwStatus = 0, dwAccessMask = 0; DWORD dwAccessDesired = 0, dwACLSize = 0; DWORD dwStructureSize = sizeof(PRIVILEGE_SET); PACL pACL = NULL; PSID psidAdmin = NULL; BOOL fReturn = FALSE; PRIVILEGE_SET ps; GENERIC_MAPPING GenericMapping; PSECURITY_DESCRIPTOR psdAdmin = NULL; SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; // AccessCheck() requires an impersonation token if (!ImpersonateSelf(SecurityImpersonation)) { goto cleanup; } // Attempt to access the token for the current thread if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken)) { if (GetLastError() != ERROR_NO_TOKEN) { goto cleanup; } // If the thread does not have an access token, we'll // examine the access token associated with the process. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { goto cleanup; } } // Build a SID for administrators group if (!AllocateAndInitializeSid(&SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin)) { goto cleanup; } // Allocate memory for the security descriptor psdAdmin = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SECURITY_DESCRIPTOR_MIN_LENGTH); if (psdAdmin == NULL) { goto cleanup; } // Initialize the new security descriptor if (!InitializeSecurityDescriptor(psdAdmin, SECURITY_DESCRIPTOR_REVISION)) { goto cleanup; } // Compute size needed for the ACL dwACLSize = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidAdmin) - sizeof(DWORD); // Allocate memory for ACL pACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwACLSize); if (pACL == NULL) { goto cleanup; } // Initialize the new ACL if (!InitializeAcl(pACL, dwACLSize, ACL_REVISION2)) { goto cleanup; } dwAccessMask = ACCESS_READ | ACCESS_WRITE; // Add the access-allowed ACE to the DACL if (!AddAccessAllowedAce(pACL, ACL_REVISION2, dwAccessMask, psidAdmin)) { goto cleanup; } // Set our DACL to the security descriptor if (!SetSecurityDescriptorDacl(psdAdmin, TRUE, pACL, FALSE)) { goto cleanup; } // AccessCheck is sensitive about the format of the // security descriptor; set the group & owner SetSecurityDescriptorGroup(psdAdmin, psidAdmin, FALSE); SetSecurityDescriptorOwner(psdAdmin, psidAdmin, FALSE); // Ensure that the SD is valid if (!IsValidSecurityDescriptor(psdAdmin)) { goto cleanup; } dwAccessDesired = ACCESS_READ; // Initialize GenericMapping structure even though we // won't be using generic rights. GenericMapping.GenericRead = ACCESS_READ; GenericMapping.GenericWrite = ACCESS_WRITE; GenericMapping.GenericExecute = 0; GenericMapping.GenericAll = ACCESS_READ | ACCESS_WRITE; // After all that work, it boils down to this call if (!AccessCheck(psdAdmin, hToken, dwAccessDesired, &GenericMapping, &ps, &dwStructureSize, &dwStatus, &fReturn)) { goto cleanup; } RevertToSelf(); cleanup: if (pACL) { HeapFree(GetProcessHeap(), 0, pACL); } if (psdAdmin){ HeapFree(GetProcessHeap(), 0, psdAdmin); } if (psidAdmin){ FreeSid(psidAdmin); } return (fReturn); } BOOL CheckForSDB( void ) /*++ CheckForSDB Description: Attempts to locate sysmain.sdb in the apppatch directory. --*/ { HANDLE hFile; TCHAR szSDBPath[MAX_PATH]; BOOL fResult = FALSE; if (!GetSystemWindowsDirectory(szSDBPath, MAX_PATH)) { return FALSE; } _tcscat(szSDBPath, _T("\\apppatch\\sysmain.sdb")); hFile = CreateFile(szSDBPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { CloseHandle(hFile); 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, MAX_PATH); LoadString(g_hInstance, IDS_EXCLUDE_HDR, szExclude, MAX_PATH); 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 nItemCount = 0, nIndex; 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 shim from the list view and add it to the list. // nItemCount = ListView_GetItemCount(g_hwndModuleList); if (nItemCount == 0) { return; } for (nIndex = nItemCount - 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, MAX_PATH); pModuleNew = (PMODULE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MODULE)); pModuleNew->pszName = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR) * (lstrlen(szBuffer) + 1)); if (pModuleNew == NULL || pModuleNew->pszName == NULL) { LogMsg(_T("[BuildModuleListForShim] Couldn't allocate memory to store module info.")); return; } lstrcpy(pModuleNew->pszName, 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]; 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, MAX_PATH); wsprintf(szShims, szTemp, nShims, cShims); 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, MAX_PATH); InsertListViewColumn(g_hwndShimList, szColumn, FALSE, 0, 200); LoadString(g_hInstance, IDS_CMDLINE_COLUMN, szColumn, MAX_PATH); InsertListViewColumn(g_hwndShimList, szColumn, TRUE, 1, 59); LoadString(g_hInstance, IDS_MODULE_COLUMN, szColumn, MAX_PATH); 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, MAX_PATH); MessageBox(hMainDlg, szError, g_szAppTitle, MB_OK | 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, MAX_PATH); 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, MAX_PATH); 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 free. --*/ { 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 // // Ensure that the beginning of the path matches between the two files // 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) { lstrcpy(resultIdx, _T("..\\")); resultIdx = resultIdx + 3; pExeFile = pExe + 1; pExe = _tcschr(pExeFile, _T('\\')); } lstrcpy(resultIdx, pMatchFile); pReturn = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR) * (lstrlen(result) + 1)); if (NULL == pReturn) { return NULL; } lstrcpy(pReturn, result); return pReturn; } // the two paths don't have a common beginning, // and there is no relative path return NULL; } void SaveEntryToFile( HWND hDlg, HWND hEdit, LPCTSTR lpFileName ) /*++ SaveEntryToFile Description: Writes the XML out to a file. --*/ { int nLen = 0; DWORD dwBytesWritten = 0; HANDLE hFile = NULL; LPTSTR lpData = NULL; TCHAR szError[MAX_PATH]; // // Determine how much space we need for the buffer, then allocate it. // nLen = GetWindowTextLength(hEdit); if (nLen) { lpData = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLen * 2 * sizeof(TCHAR)); if (lpData == NULL) { LoadString(g_hInstance, IDS_BUFFER_ALLOC_FAIL, szError, MAX_PATH); MessageBox(hDlg, szError, g_szAppTitle, MB_OK | MB_ICONERROR); return; } // // Get the text out of the text box and write it out to our file. // GetWindowText(hEdit, lpData, nLen * 2); 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, MAX_PATH); MessageBox(hDlg, szError, g_szAppTitle, MB_OK | MB_ICONERROR); goto Cleanup; } WriteFile(hFile, lpData, nLen * 2, &dwBytesWritten, NULL); CloseHandle(hFile); } Cleanup: HeapFree(GetProcessHeap(), 0, lpData); } void DoFileSave( HWND hDlg ) /*++ DoFileSave Description: Displays the common dialog allowing for file save. --*/ { int nAnswer; TCHAR szError[MAX_PATH]; TCHAR szFilter[MAX_PATH] = _T(""); TCHAR szTemp[MAX_PATH+1] = _T(""); OPENFILENAME ofn = {0}; szTemp[0] = 0; LoadString(g_hInstance, IDS_SAVE_FILTER, szFilter, MAX_PATH); 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); } } BOOL CenterWindow( HWND hWnd ) /*++ CenterWindow Description: Centers the window specified in hWnd. --*/ { RECT rectWindow, rectParent, rectScreen; int nCX, nCY; HWND hParent; POINT ptPoint; hParent = GetParent(hWnd); if (hParent == NULL) { hParent = GetDesktopWindow(); } GetWindowRect(hParent, &rectParent); GetWindowRect(hWnd, &rectWindow); GetWindowRect(GetDesktopWindow(), &rectScreen); nCX = rectWindow.right - rectWindow.left; nCY = rectWindow.bottom - rectWindow.top; ptPoint.x = ((rectParent.right + rectParent.left) / 2) - (nCX / 2); ptPoint.y = ((rectParent.bottom + rectParent.top ) / 2) - (nCY / 2); if (ptPoint.x < rectScreen.left) { ptPoint.x = rectScreen.left; } if (ptPoint.x > rectScreen.right - nCX) { ptPoint.x = rectScreen.right - nCX; } if (ptPoint.y < rectScreen.top) { ptPoint.y = rectScreen.top; } if (ptPoint.y > rectScreen.bottom - nCY) { ptPoint.y = rectScreen.bottom - nCY; } if (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD) { ScreenToClient(hParent, (LPPOINT)&ptPoint); } if (!MoveWindow(hWnd, ptPoint.x, ptPoint.y, nCX, nCY, TRUE)) { return FALSE; } return TRUE; } void ReplaceCmdLine( PFIX pFix, TCHAR* pszNewCmdLine ) /*++ ReplaceCmdLine Description: Replaces the command line for a shim DLL. --*/ { TCHAR szError[MAX_PATH]; 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, MAX_PATH); MessageBox(g_hDlg, szError, g_szAppTitle, MB_OK | MB_ICONEXCLAMATION); return; } pFix->pszCmdLine = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR) * (lstrlen(pszNewCmdLine) + 1)); if (pFix->pszCmdLine != NULL) { lstrcpy(pFix->pszCmdLine, pszNewCmdLine); } else { LogMsg(_T("[ReplaceCmdLine] failed to replace the cmd line for \"%s\"\n"), pFix->pszName); } } void DeselectAllShims( HWND hdlg ) /*++ DeselectAllShims Description: Removes selections for all shims listed. --*/ { int cShims, nIndex; LVITEM lvi; UINT uState; // // 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. --*/ { PATTRINFO pAttrInfo; TVINSERTSTRUCT is; HTREEITEM hParent; DWORD i; DWORD dwAttrCount; TCHAR szItem[MAX_PATH]; // // Call the attribute manager to get all the attributes for this file. // SdbGetFileAttributes(pszFullPath, &pAttrInfo, &dwAttrCount); 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 (i = 0; i < dwAttrCount; i++) { if (!SdbFormatAttribute(&pAttrInfo[i], szItem, MAX_PATH)) { continue; } // // EXETYPE is a bogus attribute. Don't show it! // is.item.lParam = i; 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(""); OPENFILENAME ofn = {0}; g_szBinary[0] = 0; LoadString(g_hInstance, IDS_BROWSE_FILTER, szFilter, MAX_PATH); LoadString(g_hInstance, IDS_BROWSE_TITLE, szTitle, MAX_PATH); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hdlg; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = g_szBinary; ofn.nMaxFile = MAX_PATH; ofn.lpstrFileTitle = g_szShortName; ofn.nMaxFileTitle = 128; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = szTitle; ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = _T("exe"); if (GetOpenFileName(&ofn)) { TCHAR szMainEXE[128]; // the parent exe defaults to the same as the EXE lstrcpy(g_szParentExeName, g_szShortName); lstrcpy(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); wsprintf(szMainEXE, _T("Main executable (%s)"), g_szShortName); 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+1] = _T(""); TCHAR szShortName[128] = _T(""); TCHAR szRelativePath[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] = 0; LoadString(g_hInstance, IDS_MATCH_FILTER, szFilter, MAX_PATH); LoadString(g_hInstance, IDS_MATCH_TITLE, szTitle, MAX_PATH); if (g_szParentExeFullPath[0]) { _tsplitpath(g_szParentExeFullPath, szDrive, szDir, NULL, NULL); lstrcpy(szInitialPath, szDrive); lstrcat(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 = MAX_PATH; ofn.lpstrFileTitle = szShortName; ofn.nMaxFileTitle = 128; 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] = 0; szInitialPath[0] = 0; if (szFullPath[0]) { _tsplitpath(szFullPath, szDrive, szDir, NULL, NULL); lstrcpy(szInitialPath, szDrive); lstrcat(szInitialPath, szDir); } LoadString(g_hInstance, IDS_PARENT_TITLE, szParentTitle, MAX_PATH); ofn.lpstrTitle = szParentTitle; ofn.lpstrFile = szParentFile; ofn.nMaxFile = sizeof(szParentFile); if (GetOpenFileName(&ofn) == TRUE) { lstrcpy(g_szParentExeName, szShortName); lstrcpy(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, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_OK | 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, MAX_PATH); MessageBox(NULL, szError, g_szAppTitle, MB_OK | MB_ICONERROR); return; } // // Walk the list and add all the fixes to the list view. // pFix = g_pFixHead; while (pFix != NULL) { if (pFix->bLayer) { 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 to install or uninstall the specified SDB. --*/ { TCHAR szCmd[MAX_PATH]; TCHAR szExePath[MAX_PATH]; TCHAR* pExt = NULL; STARTUPINFO si; PROCESS_INFORMATION pi; GetSystemDirectory(szExePath, MAX_PATH); _tcscat(szExePath, _T("\\sdbinst.exe")); if (GetFileAttributes(szExePath) == -1) { return FALSE; } wsprintf(szCmd, fInstall ? _T("%s -q %s") : _T("%s -q -u %s"), szExePath, pszFileName); ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); if (!CreateProcess(NULL, szCmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { LogMsg(_T("[InstallSDB] CreateProcess \"%s\" failed 0x%X\n"), szCmd, 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]; int nAnswer; 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, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_OK | MB_ICONERROR); } else { LoadString(g_hInstance, IDS_CREATE_FIX, szTemp, MAX_PATH); wsprintf(szError, szTemp, szFileCreated); 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, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_OK | MB_ICONERROR); } else { LoadString(g_hInstance, IDS_INSTALL_FIX_OK, szError, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_OK | MB_ICONINFORMATION); } } } } 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, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_OK | 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 szError[MAX_PATH]; TCHAR szRun[MAX_PATH]; TCHAR* pszCmd; TCHAR* pszDir; TCHAR* psz; BOOL bok; // // 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, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_OK | MB_ICONERROR); return; } // // We need to install the fix for them. // if (!(InstallSDB(szFileCreated, TRUE))) { LoadString(g_hInstance, IDS_INSTALL_FIX_FAIL, szError, MAX_PATH); MessageBox(g_hDlg, szError, g_szAppTitle, MB_OK | MB_ICONERROR); return; } ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); // // Try to run the app. // GetDlgItemText(hdlg, IDC_CMD_LINE, szCmdLine, MAX_PATH); if (szCmdLine[0] == 0) { wsprintf(szRun, _T("\"%s\""), g_szBinary); } else { wsprintf(szRun, _T("\"%s\" %s"), g_szBinary, szCmdLine); } pszCmd = szRun; pszDir = g_szBinary; // // We need to change the current directory or some // apps won't run. // psz = pszDir + lstrlen(pszDir) - 1; while (psz > pszDir && *psz != _T('\\')) { psz--; } if (psz > pszDir) { *psz = 0; SetCurrentDirectory(pszDir); *psz = _T('\\'); } LogMsg(_T("[RunTheApp] : %s\n"), pszCmd); if (!CreateProcess(NULL, pszCmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { LogMsg(_T("[RunTheApp] CreateProcess failed 0x%X\n"), GetLastError()); return; } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); // // Save this SDB for later so we can remove it. // lstrcpy(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, 64); 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, 64); 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) { LogMsg(_T("[LayerChanged] No layer selected.\n")); return; } pFix = (PFIX)SendMessage(g_hwndListLayers, LB_GETITEMDATA, lSel, 0); if (pFix->parrShim == NULL) { LogMsg(_T("[LayerChanged] No array of DLLs.\n")); 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; TCHAR szText[1024]; 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_szParentExeFullPath[0] = 0; g_szBinary[0] = 0; g_hDlg = hdlg; // // 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); CenterWindow(hdlg); // // 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 { LogMsg(_T("[InitMainDialog] Failed to load imagelist\n")); } // // Set the text for the link window. // LoadString(g_hInstance, g_fW2K ? IDS_W2K_LINK : IDS_XP_LINK, szText, MAX_PATH); SetDlgItemText(g_hDlg, IDC_DOWNLOAD_WU, szText); // // 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; } } 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]; pFix = (PFIX)lParam; LoadString(g_hInstance, IDS_MOD_TYPE, szType, 64); LoadString(g_hInstance, IDS_MOD_NAME, szModuleName, 128); LoadString(g_hInstance, IDS_OPTIONS_TITLE, szTemp, MAX_PATH); CenterWindow(hdlg); 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); wsprintf(szTitle, szTemp, pFix->pszName); SetWindowText(hdlg, szTitle); if (NULL != pFix->pszCmdLine) { SetDlgItemText(hdlg, IDC_SHIM_CMD_LINE, pFix->pszCmdLine); } 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]; LVITEM lvi; UINT uInclude, uExclude; GetDlgItemText(hdlg, IDC_MOD_NAME, szModName, MAX_PATH); if (*szModName == 0) { LoadString(g_hInstance, IDS_NO_MOD, szError, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION | MB_OK); 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, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION | MB_OK); 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; CenterWindow(hdlg); // // Use the parameter to determine what text to display. // if (uNoSDB) { LoadString(g_hInstance, IDS_W2K_NO_SDB, szLink, MAX_PATH); SetDlgItemText(hdlg, IDC_MESSAGE, szLink); } else { LoadString(g_hInstance, IDS_SP2_SDB, szLink, MAX_PATH); SetDlgItemText(hdlg, IDC_MESSAGE, szLink); } LoadString(g_hInstance, IDS_MSG_LINK, szLink, MAX_PATH); 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; LVITEM lvi; 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; LVITEM lvi; 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; TCHAR szShimName[MAX_PATH]; 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 this is a shim, display the options dialog. if (!pFix->bFlag) { 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("")); } } } else { MessageBeep(MB_ICONEXCLAMATION); } 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; HTREEITEM hParentItem; 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 hItem, 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; sei.lpFile = g_fW2K ? g_szW2KUrl : 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, MAX_PATH); MessageBox(hdlg, szError, g_szAppTitle, MB_ICONEXCLAMATION | MB_OK); 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; } int WINAPI wWinMain( HINSTANCE hInst, HINSTANCE hInstPrev, LPTSTR lpszCmd, int swShow ) /*++ WinMain Description: Application entry point. --*/ { BOOL fSP2 = FALSE; TCHAR szError[MAX_PATH]; OSVERSIONINFO osvi; INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_TAB_CLASSES; if (!InitCommonControlsEx(&icex)) { InitCommonControls(); } LoadString(g_hInstance, IDS_APP_TITLE, g_szAppTitle, 64); LinkWindow_RegisterClass(); g_hInstance = hInst; osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi); // // See if they're an administrator - bail if not. // if (!(IsUserAnAdministrator())) { LoadString(g_hInstance, IDS_NOT_ADMIN, szError, MAX_PATH); MessageBox(NULL, szError, g_szAppTitle, MB_ICONERROR | MB_OK); return 0; } // // See if we're running on Windows 2000. // if ((osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)) { g_fW2K = TRUE; } // See if we're running on SP2 if (!(_tcscmp(osvi.szCSDVersion, _T("Service Pack 2")))) { fSP2 = TRUE; } // // 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, MAX_PATH); MessageBox(GetDesktopWindow(), szError, g_szAppTitle, MB_OK | 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; } } LogMsg(_T("[WinMain] Command line \"%s\"\n"), lpszCmd); // // Check for command line options. // if (*lpszCmd == _T('a') || *lpszCmd == _T('A')) { g_bAllShims = TRUE; } DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG), GetDesktopWindow(), QFixAppDlgProc); return 1; }