Leaked source code of windows server 2003
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

/*++
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;
}