windows-nt/Source/XPSP1/NT/windows/appcompat/tools/qfixapp/qfixapp.cpp
2020-09-26 16:20:57 +08:00

3043 lines
75 KiB
C++

/***************************************************************************
* 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 <tchar.h>
#include <aclapi.h>
#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;
}