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

817 lines
21 KiB
C

#include "acBrowser.h"
#include "resource.h"
#include <commctrl.h>
#include <commdlg.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
extern PDBENTRY g_pEntries;
#define SHOW_W_SHIMS 0x00000001
#define SHOW_W_FLAGS 0x00000002
#define SHOW_W_LAYERS 0x00000004
#define SHOW_W_PATCHES 0x00000008
#define SHOW_W_APPHELP 0x00000010
#define SHOW_WO_SHIMS 0x00000100
#define SHOW_WO_FLAGS 0x00000200
#define SHOW_WO_LAYERS 0x00000400
#define SHOW_WO_PATCHES 0x00000800
#define SHOW_WO_APPHELP 0x00001000
//
// These flags cannot occur simultaneously.
//
#define SHOW_MORETHAN5 0x00010000
#define SHOW_NOMATCHING 0x00020000
#define SHOW_DISABLED_ONLY 0x80000000
#define ID_SHOW_CONTENT 1234
//
// Global Variables
//
HINSTANCE g_hInstance;
HWND g_hDlg;
HWND g_hwndList;
HWND g_hwndEntryTree;
int g_nItems;
BOOL g_bSortAppAsc;
BOOL g_bSortExeAsc;
PDBENTRY g_pSelEntry;
char g_szBinary[MAX_PATH];
DWORD g_dwCrtShowFlags = 0xFFFFFFFF;
#define COLUMN_APP 0
#define COLUMN_EXE 1
char* g_szSeverity[] = { "NONE",
"NOBLOCK",
"HARDBLOCK",
"MINORPROBLEM",
"REINSTALL",
"VERSIONSUB",
"SHIM"};
#define IDQ_ALL 0
#define IDQ_MORETHAN5 1
#define IDQ_NOMATCHING 2
char* g_aszQueries[] = { "All entries",
"Entries with more than 5 extra matching files",
"Entries with no extra matching files",
""
};
void
LogMsg(
LPSTR pszFmt,
... )
{
CHAR gszT[1024];
va_list arglist;
va_start(arglist, pszFmt);
_vsnprintf(gszT, 1023, pszFmt, arglist);
gszT[1023] = 0;
va_end(arglist);
OutputDebugString(gszT);
}
/*******************************************************************************
* CenterWindow
*
* This function must be called at the WM_INIDIALOG in order to
* move the dialog window centered in the client area of the
* parent or owner window.
*******************************************************************************/
BOOL CenterWindow(
HWND hWnd)
{
RECT rectWindow, rectParent, rectScreen;
int nCX, nCY;
HWND hParent;
POINT ptPoint;
hParent = GetParent(hWnd);
if (hParent == NULL)
hParent = GetDesktopWindow();
GetWindowRect(hParent, (LPRECT)&rectParent);
GetWindowRect(hWnd, (LPRECT)&rectWindow);
GetWindowRect(GetDesktopWindow(), (LPRECT)&rectScreen);
nCX = rectWindow.right - rectWindow.left;
nCY = rectWindow.bottom - rectWindow.top;
ptPoint.x = ((rectParent.right + rectParent.left) / 2) - (nCX / 2);
ptPoint.y = ((rectParent.bottom + rectParent.top ) / 2) - (nCY / 2);
if (ptPoint.x < rectScreen.left)
ptPoint.x = rectScreen.left;
if (ptPoint.x > rectScreen.right - nCX)
ptPoint.x = rectScreen.right - nCX;
if (ptPoint.y < rectScreen.top)
ptPoint.y = rectScreen.top;
if (ptPoint.y > rectScreen.bottom - nCY)
ptPoint.y = rectScreen.bottom - nCY;
if (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD)
ScreenToClient(hParent, (LPPOINT)&ptPoint);
if (!MoveWindow(hWnd, ptPoint.x, ptPoint.y, nCX, nCY, TRUE))
return FALSE;
return TRUE;
}
void
AddEntryToList(
PDBENTRY pEntry
)
{
LVITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.pszText = pEntry->pszAppName;
lvi.iItem = g_nItems;
lvi.iSubItem = COLUMN_APP;
lvi.lParam = (LPARAM)pEntry;
ListView_InsertItem(g_hwndList, &lvi);
ListView_SetItemText(g_hwndList, g_nItems, COLUMN_EXE, pEntry->pszExeName);
g_nItems++;
}
void
InsertColumnIntoListView(
LPSTR lpszColumn,
DWORD dwSubItem,
DWORD widthPercent
)
{
LVCOLUMN lvc;
RECT rcClient;
DWORD width;
GetWindowRect(g_hwndList, &rcClient);
width = rcClient.right - rcClient.left -
4 * GetSystemMetrics(SM_CXBORDER) -
GetSystemMetrics(SM_CXVSCROLL);
width = width * widthPercent / 100;
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
lvc.fmt = LVCFMT_LEFT;
lvc.iSubItem = dwSubItem;
lvc.cx = width;
lvc.pszText = lpszColumn;
ListView_InsertColumn(g_hwndList, dwSubItem, &lvc);
}
void
UpdateEntryTreeView(
PDBENTRY pEntry
)
{
HTREEITEM hItemExe;
HTREEITEM hMatchItem;
HTREEITEM hItemMatchingFiles;
PMATCHINGFILE pMatch;
PFIXLIST pFixList;
TV_INSERTSTRUCT is;
char szText[256];
TreeView_DeleteAllItems(g_hwndEntryTree);
wsprintf(szText, "%s - %s", pEntry->pszExeName, pEntry->szGUID);
is.hParent = TVI_ROOT;
is.hInsertAfter = TVI_LAST;
is.item.mask = TVIF_TEXT | TVIF_PARAM;
is.item.lParam = 0;
is.item.pszText = szText;
hItemExe = TreeView_InsertItem(g_hwndEntryTree, &is);
if (pEntry->appHelp.bPresent) {
wsprintf(szText, "AppHelp - %s",
g_szSeverity[pEntry->appHelp.severity]);
is.hParent = hItemExe;
is.item.pszText = szText;
TreeView_InsertItem(g_hwndEntryTree, &is);
}
if (pEntry->pFirstShim) {
HTREEITEM hItemShims;
is.hParent = hItemExe;
is.hInsertAfter = TVI_SORT;
is.item.lParam = 0;
is.item.pszText = "Compatibility Fixes";
hItemShims = TreeView_InsertItem(g_hwndEntryTree, &is);
is.hParent = hItemShims;
pFixList = pEntry->pFirstShim;
while (pFixList) {
is.item.lParam = (LPARAM)pFixList->pFix->pszDescription;
is.item.pszText = pFixList->pFix->pszName;
TreeView_InsertItem(g_hwndEntryTree, &is);
pFixList = pFixList->pNext;
}
TreeView_Expand(g_hwndEntryTree, hItemShims, TVE_EXPAND);
}
if (pEntry->pFirstPatch) {
HTREEITEM hItemPatches;
is.hParent = hItemExe;
is.hInsertAfter = TVI_SORT;
is.item.lParam = 0;
is.item.pszText = "Compatibility Patches";
hItemPatches = TreeView_InsertItem(g_hwndEntryTree, &is);
is.hParent = hItemPatches;
pFixList = pEntry->pFirstPatch;
while (pFixList) {
is.item.lParam = (LPARAM)pFixList->pFix->pszDescription;
is.item.pszText = pFixList->pFix->pszName;
TreeView_InsertItem(g_hwndEntryTree, &is);
pFixList = pFixList->pNext;
}
TreeView_Expand(g_hwndEntryTree, hItemPatches, TVE_EXPAND);
}
if (pEntry->pFirstFlag) {
HTREEITEM hItemFlags;
is.hParent = hItemExe;
is.hInsertAfter = TVI_SORT;
is.item.lParam = 0;
is.item.pszText = "Compatibility Flags";
hItemFlags = TreeView_InsertItem(g_hwndEntryTree, &is);
is.hParent = hItemFlags;
pFixList = pEntry->pFirstFlag;
while (pFixList) {
is.item.lParam = (LPARAM)pFixList->pFix->pszDescription;
is.item.pszText = pFixList->pFix->pszName;
TreeView_InsertItem(g_hwndEntryTree, &is);
pFixList = pFixList->pNext;
}
TreeView_Expand(g_hwndEntryTree, hItemFlags, TVE_EXPAND);
}
if (pEntry->pFirstLayer) {
HTREEITEM hItemLayers;
is.hParent = hItemExe;
is.hInsertAfter = TVI_SORT;
is.item.lParam = 0;
is.item.pszText = "Compatibility Layers";
hItemLayers = TreeView_InsertItem(g_hwndEntryTree, &is);
is.hParent = hItemLayers;
pFixList = pEntry->pFirstLayer;
while (pFixList) {
is.item.lParam = (LPARAM)pFixList->pFix->pszDescription;
is.item.pszText = pFixList->pFix->pszName;
TreeView_InsertItem(g_hwndEntryTree, &is);
pFixList = pFixList->pNext;
}
TreeView_Expand(g_hwndEntryTree, hItemLayers, TVE_EXPAND);
}
pMatch = pEntry->pFirstMatchingFile;
is.hParent = hItemExe;
is.item.lParam = 0;
is.item.pszText = "Matching Files";
hItemMatchingFiles = TreeView_InsertItem(g_hwndEntryTree, &is);
while (pMatch) {
PATTRIBUTE pAttr;
is.hInsertAfter = TVI_SORT;
is.hParent = hItemMatchingFiles;
is.item.pszText = pMatch->pszName;
hMatchItem = TreeView_InsertItem(g_hwndEntryTree, &is);
pAttr = pMatch->pFirstAttribute;
while (pAttr) {
is.hParent = hMatchItem;
is.hInsertAfter = TVI_SORT;
is.item.pszText = pAttr->pszText;
TreeView_InsertItem(g_hwndEntryTree, &is);
pAttr = pAttr->pNext;
}
pMatch = pMatch->pNext;
}
TreeView_Expand(g_hwndEntryTree, hItemMatchingFiles, TVE_EXPAND);
TreeView_Expand(g_hwndEntryTree, hItemExe, TVE_EXPAND);
}
void
AppSelectedChanged(
HWND hdlg,
int nSel
)
{
LVITEM lvi;
PDBENTRY pEntry;
if (nSel == -1)
return;
lvi.iItem = nSel;
lvi.iSubItem = 0;
lvi.mask = LVIF_PARAM;
ListView_GetItem(g_hwndList, &lvi);
pEntry = (PDBENTRY)lvi.lParam;
g_pSelEntry = pEntry;
//
// Update the entry tree view
//
UpdateEntryTreeView(pEntry);
SendDlgItemMessage(hdlg, IDC_PER_USER, BM_SETCHECK,
(pEntry->bDisablePerUser ? BST_CHECKED : BST_UNCHECKED), 0);
SendDlgItemMessage(hdlg, IDC_PER_MACHINE, BM_SETCHECK,
(pEntry->bDisablePerMachine ? BST_CHECKED : BST_UNCHECKED), 0);
}
int CALLBACK
CompareItems(
LPARAM lParam1,
LPARAM lParam2,
LPARAM column)
{
PDBENTRY pItem1 = (PDBENTRY)lParam1;
PDBENTRY pItem2 = (PDBENTRY)lParam2;
int nVal = 0;
if (column == COLUMN_APP) {
if (g_bSortAppAsc) {
nVal = lstrcmpi(pItem1->pszAppName, pItem2->pszAppName);
} else {
nVal = lstrcmpi(pItem2->pszAppName, pItem1->pszAppName);
}
}
if (column == COLUMN_EXE) {
if (g_bSortExeAsc) {
nVal = lstrcmpi(pItem1->pszExeName, pItem2->pszExeName);
} else {
nVal = lstrcmpi(pItem2->pszExeName, pItem1->pszExeName);
}
}
return nVal;
}
void
ShowFixes(
HWND hdlg,
DWORD dwShowFlags
)
{
PDBENTRY pEntry;
char szEntries[128];
BOOL bDontShow;
if (dwShowFlags == g_dwCrtShowFlags) {
return;
}
g_nItems = 0;
SendMessage(g_hwndList, WM_SETREDRAW, FALSE, 0);
ListView_DeleteAllItems(g_hwndList);
pEntry = g_pEntries;
while (pEntry != NULL) {
bDontShow = (pEntry->pFirstShim == NULL && (dwShowFlags & SHOW_W_SHIMS) ||
pEntry->appHelp.bPresent == FALSE && (dwShowFlags & SHOW_W_APPHELP) ||
pEntry->pFirstFlag == NULL && (dwShowFlags & SHOW_W_FLAGS) ||
pEntry->pFirstPatch == NULL && (dwShowFlags & SHOW_W_PATCHES) ||
pEntry->pFirstLayer == NULL && (dwShowFlags & SHOW_W_LAYERS));
bDontShow = bDontShow ||
(pEntry->pFirstShim && (dwShowFlags & SHOW_WO_SHIMS) ||
pEntry->appHelp.bPresent && (dwShowFlags & SHOW_WO_APPHELP) ||
pEntry->pFirstFlag && (dwShowFlags & SHOW_WO_FLAGS) ||
pEntry->pFirstPatch && (dwShowFlags & SHOW_WO_PATCHES) ||
pEntry->pFirstLayer && (dwShowFlags & SHOW_WO_LAYERS));
if ((dwShowFlags & SHOW_DISABLED_ONLY) &&
!pEntry->bDisablePerMachine &&
!pEntry->bDisablePerUser) {
bDontShow = TRUE;
}
if (dwShowFlags & SHOW_MORETHAN5) {
if (pEntry->nMatchingFiles < 6) {
bDontShow = TRUE;
}
}
if (dwShowFlags & SHOW_NOMATCHING) {
if (pEntry->nMatchingFiles > 1) {
bDontShow = TRUE;
}
}
if (!bDontShow) {
AddEntryToList(pEntry);
}
pEntry = pEntry->pNext;
}
ListView_SortItems(g_hwndList, CompareItems, COLUMN_APP);
wsprintf(szEntries, "%d entries. Use the headers to sort them.", g_nItems);
SetDlgItemText(hdlg, IDC_ALL_ENTRIES, szEntries);
SendMessage(g_hwndList, WM_SETREDRAW, TRUE, 0);
g_dwCrtShowFlags = dwShowFlags;
}
void
DoInitDialog(
HWND hdlg
)
{
HICON hIcon;
int i;
g_hDlg = hdlg;
CenterWindow(hdlg);
g_hwndList = GetDlgItem(hdlg, IDC_LIST);
ListView_SetExtendedListViewStyle(g_hwndList, 0x20);
g_hwndEntryTree = GetDlgItem(hdlg, IDC_ENTRY);
g_nItems = 0;
InsertColumnIntoListView("Application", COLUMN_APP, 60);
InsertColumnIntoListView("Main Binary", COLUMN_EXE, 40);
g_bSortAppAsc = TRUE;
g_bSortExeAsc = FALSE;
//
// Show the app icon.
//
hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_APPICON));
SetClassLongPtr(hdlg, GCLP_HICON, (LONG_PTR)hIcon);
SendDlgItemMessage(hdlg, IDC_DC_APPHELP, BM_SETCHECK, BST_CHECKED, 0);
SendDlgItemMessage(hdlg, IDC_DC_SHIMS, BM_SETCHECK, BST_CHECKED, 0);
SendDlgItemMessage(hdlg, IDC_DC_FLAGS, BM_SETCHECK, BST_CHECKED, 0);
SendDlgItemMessage(hdlg, IDC_DC_PATCHES, BM_SETCHECK, BST_CHECKED, 0);
SendDlgItemMessage(hdlg, IDC_DC_LAYERS, BM_SETCHECK, BST_CHECKED, 0);
//
// Populate the statistics queries
//
for (i = 0; *g_aszQueries[i] != 0; i++) {
SendDlgItemMessage(hdlg, IDC_STATISTICS, CB_ADDSTRING, 0, (LPARAM)g_aszQueries[i]);
}
SetCursor(NULL);
SetTimer(hdlg, ID_SHOW_CONTENT, 100, NULL);
}
void
FilterAndShow(
HWND hdlg
)
{
DWORD dwShowFlags = 0;
if (SendDlgItemMessage(hdlg, IDC_W_APPHELP, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_W_APPHELP;
} else if (SendDlgItemMessage(hdlg, IDC_WO_APPHELP, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_WO_APPHELP;
}
if (SendDlgItemMessage(hdlg, IDC_W_SHIMS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_W_SHIMS;
} else if (SendDlgItemMessage(hdlg, IDC_WO_SHIMS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_WO_SHIMS;
}
if (SendDlgItemMessage(hdlg, IDC_W_PATCHES, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_W_PATCHES;
} else if (SendDlgItemMessage(hdlg, IDC_WO_PATCHES, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_WO_PATCHES;
}
if (SendDlgItemMessage(hdlg, IDC_W_FLAGS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_W_FLAGS;
} else if (SendDlgItemMessage(hdlg, IDC_WO_FLAGS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_WO_FLAGS;
}
if (SendDlgItemMessage(hdlg, IDC_W_LAYERS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_W_LAYERS;
} else if (SendDlgItemMessage(hdlg, IDC_WO_LAYERS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_WO_LAYERS;
}
if (SendDlgItemMessage(hdlg, IDC_DISABLED_ONLY, BM_GETCHECK, 0, 0) == BST_CHECKED) {
dwShowFlags |= SHOW_DISABLED_ONLY;
}
SendDlgItemMessage(hdlg, IDC_PER_USER, BM_SETCHECK, BST_UNCHECKED, 0);
SendDlgItemMessage(hdlg, IDC_PER_MACHINE, BM_SETCHECK, BST_UNCHECKED, 0);
ShowFixes(hdlg, dwShowFlags);
TreeView_DeleteAllItems(g_hwndEntryTree);
}
void
OnSubmitChanges(
HWND hdlg
)
{
BOOL bPerUser, bPerMachine;
if (g_pSelEntry == NULL) {
return;
}
bPerUser = (SendDlgItemMessage(hdlg, IDC_PER_USER, BM_GETCHECK, 0, 0) == BST_CHECKED);
bPerMachine = (SendDlgItemMessage(hdlg, IDC_PER_MACHINE, BM_GETCHECK, 0, 0) == BST_CHECKED);
UpdateFixStatus(g_pSelEntry->szGUID, bPerUser, bPerMachine);
g_pSelEntry->bDisablePerUser = bPerUser;
g_pSelEntry->bDisablePerMachine = bPerMachine;
}
INT_PTR CALLBACK
BrowseAppCompatDlgProc(
HWND hdlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
int wCode = LOWORD(wParam);
int wNotifyCode = HIWORD(wParam);
switch (uMsg) {
case WM_INITDIALOG:
DoInitDialog(hdlg);
break;
case WM_TIMER:
if (wParam == ID_SHOW_CONTENT) {
KillTimer(hdlg, ID_SHOW_CONTENT);
//
// Read the database
//
GetDatabaseEntries();
ShowFixes(hdlg, 0);
SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
}
break;
case WM_NOTIFY:
if (wParam == IDC_LIST) {
LPNMHDR pnm = (LPNMHDR)lParam;
switch (pnm->code) {
case LVN_COLUMNCLICK:
{
LPNMLISTVIEW pnmlv = (LPNMLISTVIEW)lParam;
if (pnmlv->iSubItem == COLUMN_APP) {
g_bSortAppAsc = !g_bSortAppAsc;
}
if (pnmlv->iSubItem == COLUMN_EXE) {
g_bSortExeAsc = !g_bSortExeAsc;
}
ListView_SortItems(g_hwndList, CompareItems, pnmlv->iSubItem);
break;
}
case LVN_ITEMCHANGED:
{
int nSel = ListView_GetSelectionMark(g_hwndList);
AppSelectedChanged(hdlg, nSel);
break;
}
case NM_CLICK:
{
LVHITTESTINFO ht;
int nSel;
GetCursorPos(&ht.pt);
ScreenToClient(g_hwndList, &ht.pt);
nSel = ListView_SubItemHitTest(g_hwndList, &ht);
if (nSel != -1) {
ListView_SetItemState(g_hwndList,
nSel,
LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED);
}
AppSelectedChanged(hdlg, nSel);
break;
}
default:
break;
}
} else if (wParam == IDC_ENTRY) {
LPNMHDR pnm = (LPNMHDR)lParam;
switch (pnm->code) {
case TVN_GETINFOTIP:
{
LPNMTVGETINFOTIP lpGetInfoTip = (LPNMTVGETINFOTIP)lParam;
if (lpGetInfoTip->lParam != 0) {
lstrcpy(lpGetInfoTip->pszText, (char*)lpGetInfoTip->lParam);
}
break;
}
}
}
break;
case WM_COMMAND:
if (wNotifyCode == CBN_SELCHANGE) {
int nSel;
nSel = (int)SendDlgItemMessage(hdlg, IDC_STATISTICS, CB_GETCURSEL, 0, 0);
switch (nSel) {
case IDQ_ALL:
ShowFixes(hdlg, (g_dwCrtShowFlags & ~(SHOW_MORETHAN5 | SHOW_NOMATCHING)));
break;
case IDQ_MORETHAN5:
ShowFixes(hdlg, ((g_dwCrtShowFlags | SHOW_MORETHAN5) & ~SHOW_NOMATCHING));
break;
case IDQ_NOMATCHING:
ShowFixes(hdlg, ((g_dwCrtShowFlags | SHOW_NOMATCHING) & ~SHOW_MORETHAN5));
break;
}
}
switch (wCode) {
case IDC_PER_USER:
case IDC_PER_MACHINE:
OnSubmitChanges(hdlg);
break;
case IDC_W_APPHELP:
case IDC_W_SHIMS:
case IDC_W_FLAGS:
case IDC_W_LAYERS:
case IDC_W_PATCHES:
case IDC_WO_APPHELP:
case IDC_WO_SHIMS:
case IDC_WO_FLAGS:
case IDC_WO_LAYERS:
case IDC_WO_PATCHES:
case IDC_DC_APPHELP:
case IDC_DC_SHIMS:
case IDC_DC_FLAGS:
case IDC_DC_LAYERS:
case IDC_DC_PATCHES:
case IDC_DISABLED_ONLY:
FilterAndShow(hdlg);
break;
case IDCANCEL:
EndDialog(hdlg, TRUE);
break;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
InitCommonControls();
g_hInstance = hInstance;
DialogBox(hInstance,
MAKEINTRESOURCE(IDD_DIALOG),
GetDesktopWindow(),
(DLGPROC)BrowseAppCompatDlgProc);
return 0;
}