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