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.
1251 lines
34 KiB
1251 lines
34 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000
|
|
//
|
|
// File: ShellExtensions.cpp
|
|
//
|
|
// Contents: object to implement propertypage extensions
|
|
// for Win2k shim layer
|
|
//
|
|
// History: 23-september-00 clupu Created
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "resource.h"
|
|
#include "ShellExtensions.h"
|
|
#include <sfc.h>
|
|
#include "Aclapi.h"
|
|
#include "strsafe.h"
|
|
|
|
UINT g_DllRefCount = 0;
|
|
|
|
extern HINSTANCE g_hInstance;
|
|
|
|
typedef struct _LAYER_INFO {
|
|
WCHAR wszInternalName[32];
|
|
UINT nstrFriendlyName;
|
|
} LAYER_INFO, *PLAYER_INFO;
|
|
|
|
//
|
|
// internal definitions of layer names
|
|
//
|
|
#define STR_LAYER_WIN95 L"WIN95"
|
|
#define STR_LAYER_WIN98 L"WIN98"
|
|
#define STR_LAYER_WINNT L"NT4SP5"
|
|
#define STR_LAYER_WIN2K L"WIN2000"
|
|
#define STR_LAYER_WINXP L"WINXP"
|
|
#define STR_LAYER_256COLOR L"256COLOR"
|
|
#define STR_LAYER_LORES L"640X480"
|
|
#define STR_LAYER_DISABLETHEMES L"DISABLETHEMES"
|
|
#define STR_LAYER_ENABLELUA L"LUA"
|
|
|
|
//
|
|
// Layer flags
|
|
//
|
|
#define FLAG_256 0x00000001
|
|
#define FLAG_640x480 0x00000002
|
|
#define FLAG_DISABLE_THEMES 0x00000004
|
|
#define FLAG_ENABLE_LUA 0x00000010
|
|
|
|
const LAYER_INFO g_LayerInfo[] =
|
|
{
|
|
{
|
|
STR_LAYER_WIN95,
|
|
IDS_LAYER_WIN95_EXT
|
|
},
|
|
{
|
|
STR_LAYER_WIN98,
|
|
IDS_LAYER_WIN98_EXT
|
|
},
|
|
{
|
|
STR_LAYER_WINNT,
|
|
IDS_LAYER_NT4_EXT
|
|
},
|
|
{
|
|
STR_LAYER_WIN2K,
|
|
IDS_LAYER_WIN2K_EXT
|
|
},
|
|
{
|
|
STR_LAYER_WINXP,
|
|
IDS_LAYER_WINXP_EXT
|
|
}
|
|
};
|
|
|
|
|
|
#define NUM_LAYERS (sizeof(g_LayerInfo)/sizeof(g_LayerInfo[0]))
|
|
|
|
typedef BOOL (STDAPICALLTYPE *_pfn_AllowPermLayer)(WCHAR* pwszPath);
|
|
typedef BOOL (STDAPICALLTYPE *_pfn_GetPermLayers)(WCHAR* pwszPath, WCHAR *pwszLayers, DWORD *pdwBytes, DWORD dwFlags);
|
|
typedef BOOL (STDAPICALLTYPE *_pfn_SetPermLayers)(WCHAR* pwszPath, WCHAR *pwszLayers, BOOL bMachine);
|
|
|
|
HINSTANCE g_hAppHelp = NULL;
|
|
BOOL g_bAdmin = FALSE;
|
|
BOOL g_bServer = FALSE;
|
|
|
|
_pfn_AllowPermLayer g_pfnAllowPermLayer = NULL;
|
|
_pfn_GetPermLayers g_pfnGetPermLayers = NULL;
|
|
_pfn_SetPermLayers g_pfnSetPermLayers = NULL;
|
|
|
|
void
|
|
IsDotNetServer(
|
|
void
|
|
)
|
|
{
|
|
OSVERSIONINFOEX osvi;
|
|
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
|
|
|
if (!GetVersionEx((OSVERSIONINFO*)&osvi)) {
|
|
return;
|
|
}
|
|
|
|
if (osvi.wProductType != VER_NT_WORKSTATION) {
|
|
g_bServer = TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CheckGroupPolicy(
|
|
void
|
|
)
|
|
{
|
|
HKEY hKey;
|
|
LONG lResult;
|
|
DWORD dwValue, dwSize = sizeof(dwValue);
|
|
DWORD dwType;
|
|
|
|
//
|
|
// First, check for the whole engine being disabled.
|
|
//
|
|
lResult = RegOpenKeyExW (HKEY_LOCAL_MACHINE, POLICY_KEY_APPCOMPAT_W, 0,
|
|
KEY_READ, &hKey);
|
|
if (lResult == ERROR_SUCCESS) {
|
|
dwValue = 0;
|
|
lResult = RegQueryValueExW (hKey, POLICY_VALUE_DISABLE_ENGINE_W, 0, &dwType,
|
|
(LPBYTE) &dwValue, &dwSize);
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
//
|
|
// The default is enabled, so if we didn't find a value, treat it like the value is 0.
|
|
//
|
|
if (lResult != ERROR_SUCCESS || dwValue == 0) {
|
|
//
|
|
// Check for the proppage being disabled.
|
|
//
|
|
lResult = RegOpenKeyExW (HKEY_LOCAL_MACHINE, POLICY_KEY_APPCOMPAT_W, 0,
|
|
KEY_READ, &hKey);
|
|
if (lResult == ERROR_SUCCESS) {
|
|
dwValue = 0;
|
|
lResult = RegQueryValueExW (hKey, POLICY_VALUE_DISABLE_PROPPAGE_W, 0, &dwType,
|
|
(LPBYTE) &dwValue, &dwSize);
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
//
|
|
// The default is to be enabled, so if we didn't find a value, or the value is 0, then we're good to go.
|
|
//
|
|
if (lResult != ERROR_SUCCESS || dwValue == 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
InitAppHelpCalls(
|
|
void
|
|
)
|
|
{
|
|
HINSTANCE hAppHelp;
|
|
|
|
if (g_hAppHelp) {
|
|
//
|
|
// we're already inited
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
hAppHelp = LoadLibrary(TEXT("apphelp.dll"));
|
|
if (!hAppHelp) {
|
|
LogMsg(_T("[InitAppHelpCalls] Can't get handle to apphelp.dll.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
g_pfnAllowPermLayer = (_pfn_AllowPermLayer)GetProcAddress(hAppHelp, "AllowPermLayer");
|
|
g_pfnGetPermLayers = (_pfn_GetPermLayers)GetProcAddress(hAppHelp, "GetPermLayers");
|
|
g_pfnSetPermLayers = (_pfn_SetPermLayers)GetProcAddress(hAppHelp, "SetPermLayers");
|
|
|
|
if (!g_pfnAllowPermLayer || !g_pfnGetPermLayers || !g_pfnSetPermLayers) {
|
|
LogMsg(_T("[InitAppHelpCalls] Can't get function pointers.\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// this needs to be here at the end to avoid a race condition
|
|
//
|
|
g_hAppHelp = hAppHelp;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GiveUsersWriteAccess(
|
|
void
|
|
)
|
|
{
|
|
DWORD dwRes;
|
|
EXPLICIT_ACCESS ea;
|
|
PACL pOldDACL;
|
|
PACL pNewDACL = NULL;
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
|
|
PSID pUsersSID = NULL;
|
|
TCHAR szDir[MAX_PATH];
|
|
|
|
ExpandEnvironmentStrings(LUA_REDIR_W, szDir, MAX_PATH);
|
|
|
|
if (!CreateDirectory(szDir, NULL)) {
|
|
DWORD err = GetLastError();
|
|
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
LogMsg(_T("[GiveUsersWriteAccess] Failed to create the directory.\n"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
dwRes = GetNamedSecurityInfo(szDir,
|
|
SE_FILE_OBJECT,
|
|
DACL_SECURITY_INFORMATION,
|
|
NULL,
|
|
NULL,
|
|
&pOldDACL,
|
|
NULL,
|
|
&pSD);
|
|
|
|
if (ERROR_SUCCESS != dwRes) {
|
|
LogMsg(_T("[GiveUsersWriteAccess] GetNamedSecurityInfo error %u\n"), dwRes);
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!AllocateAndInitializeSid(&SIDAuth,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_USERS,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&pUsersSID) ) {
|
|
LogMsg(_T("[GiveUsersWriteAccess] AllocateAndInitializeSid error %u\n"), GetLastError());
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
|
|
//
|
|
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
|
|
|
|
ea.grfAccessPermissions = FILE_GENERIC_WRITE | FILE_GENERIC_READ | DELETE;
|
|
ea.grfAccessMode = GRANT_ACCESS;
|
|
ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
|
|
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
|
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
|
|
ea.Trustee.ptstrName = (LPTSTR)pUsersSID;
|
|
|
|
//
|
|
// Create a new ACL that merges the new ACE
|
|
// into the existing DACL.
|
|
//
|
|
dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
|
|
|
|
if (ERROR_SUCCESS != dwRes) {
|
|
LogMsg(_T("[GiveUsersWriteAccess] SetEntriesInAcl error %u\n"), dwRes);
|
|
goto Cleanup;
|
|
}
|
|
|
|
dwRes = SetNamedSecurityInfo(szDir,
|
|
SE_FILE_OBJECT,
|
|
DACL_SECURITY_INFORMATION,
|
|
NULL,
|
|
NULL,
|
|
pNewDACL,
|
|
NULL);
|
|
|
|
if (ERROR_SUCCESS != dwRes) {
|
|
LogMsg(_T("[GiveUsersWriteAccess] SetNamedSecurityInfo error %u\n"), dwRes);
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (pSD) {
|
|
LocalFree(pSD);
|
|
}
|
|
|
|
if (pUsersSID) {
|
|
FreeSid(pUsersSID);
|
|
}
|
|
|
|
if (pNewDACL) {
|
|
LocalFree(pNewDACL);
|
|
}
|
|
|
|
return (dwRes == ERROR_SUCCESS);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// GetLayerInfo
|
|
//
|
|
BOOL
|
|
GetLayerInfo(
|
|
TCHAR* szPath,
|
|
DWORD dwFrom,
|
|
int* pnMainLayer,
|
|
DWORD* pdwFlags
|
|
)
|
|
{
|
|
WCHAR wszLayers[256];
|
|
DWORD dwBytes = sizeof(wszLayers);
|
|
int i;
|
|
|
|
if (!pnMainLayer || pdwFlags == NULL) {
|
|
LogMsg(_T("[GetLayerInfo] invalid parameters\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
*pdwFlags = 0;
|
|
|
|
//
|
|
// get layer string
|
|
//
|
|
if (!g_pfnGetPermLayers(szPath, wszLayers, &dwBytes, dwFrom)) {
|
|
*pnMainLayer = -1;
|
|
return TRUE;
|
|
}
|
|
|
|
LogMsg(_T("[GetLayerInfo] Layers \"%s\"\n"), wszLayers);
|
|
|
|
//
|
|
// Make the layer string upper case, so we'll match case-insensitive
|
|
//
|
|
_wcsupr(wszLayers);
|
|
|
|
//
|
|
// find the first layer that matches
|
|
//
|
|
*pnMainLayer = -1;
|
|
for (i = 0; i < NUM_LAYERS; ++i) {
|
|
if (wcsstr(wszLayers, g_LayerInfo[i].wszInternalName) != NULL) {
|
|
*pnMainLayer = i;
|
|
}
|
|
}
|
|
|
|
if (wcsstr(wszLayers, STR_LAYER_256COLOR) != NULL) {
|
|
*pdwFlags |= FLAG_256;
|
|
}
|
|
|
|
if (wcsstr(wszLayers, STR_LAYER_LORES) != NULL) {
|
|
*pdwFlags |= FLAG_640x480;
|
|
}
|
|
|
|
if (wcsstr(wszLayers, STR_LAYER_DISABLETHEMES) != NULL) {
|
|
*pdwFlags |= FLAG_DISABLE_THEMES;
|
|
}
|
|
|
|
if (wcsstr(wszLayers, STR_LAYER_ENABLELUA) != NULL) {
|
|
*pdwFlags |= FLAG_ENABLE_LUA;
|
|
}
|
|
|
|
LogMsg(_T("[GetLayerInfo] Layers 0x%x\n"), *pdwFlags);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
BuildLayerString(
|
|
WCHAR* pwszLayers,
|
|
DWORD cchBufSize,
|
|
int nMainLayer,
|
|
DWORD dwFlags,
|
|
BOOL bMachine
|
|
)
|
|
{
|
|
pwszLayers[0] = 0;
|
|
|
|
if (nMainLayer >= 0 && nMainLayer < NUM_LAYERS) {
|
|
StringCchCatW(pwszLayers, cchBufSize, g_LayerInfo[nMainLayer].wszInternalName);
|
|
}
|
|
|
|
if (dwFlags & FLAG_256) {
|
|
if (pwszLayers[0]) {
|
|
StringCchCatW(pwszLayers, cchBufSize, L" ");
|
|
}
|
|
StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_256COLOR);
|
|
}
|
|
|
|
if (dwFlags & FLAG_640x480) {
|
|
if (pwszLayers[0]) {
|
|
StringCchCatW(pwszLayers, cchBufSize, L" ");
|
|
}
|
|
StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_LORES);
|
|
}
|
|
|
|
if (dwFlags & FLAG_DISABLE_THEMES) {
|
|
if (pwszLayers[0]) {
|
|
StringCchCatW(pwszLayers, cchBufSize, L" ");
|
|
}
|
|
StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_DISABLETHEMES);
|
|
}
|
|
|
|
if (bMachine) {
|
|
if (dwFlags & FLAG_ENABLE_LUA) {
|
|
if (pwszLayers[0]) {
|
|
StringCchCatW(pwszLayers, cchBufSize, L" ");
|
|
}
|
|
StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_ENABLELUA);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// SetLayerInfo
|
|
//
|
|
BOOL
|
|
SetLayerInfo(
|
|
TCHAR* szPath,
|
|
int nMainLayer,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
WCHAR wszLayers[256];
|
|
|
|
//
|
|
// build layer string
|
|
//
|
|
BuildLayerString(wszLayers, ARRAYSIZE(wszLayers), nMainLayer, dwFlags, FALSE);
|
|
|
|
if (g_bAdmin) {
|
|
|
|
WCHAR wszMachineLayers[256];
|
|
DWORD dwMachineFlags;
|
|
int nMainLayer;
|
|
//
|
|
// Get the layers first.
|
|
//
|
|
GetLayerInfo(szPath, GPLK_MACHINE, &nMainLayer, &dwMachineFlags);
|
|
|
|
if (dwFlags & FLAG_ENABLE_LUA) {
|
|
if (!GiveUsersWriteAccess()) {
|
|
LogMsg(_T("[SetLayerInfo] Failed to change directory ACLs.\n"));
|
|
}
|
|
|
|
dwMachineFlags |= FLAG_ENABLE_LUA;
|
|
|
|
} else {
|
|
dwMachineFlags &= ~FLAG_ENABLE_LUA;
|
|
}
|
|
|
|
BuildLayerString(wszMachineLayers, ARRAYSIZE(wszMachineLayers), nMainLayer, dwMachineFlags, TRUE);
|
|
|
|
if (!g_pfnSetPermLayers(szPath, wszMachineLayers, TRUE)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// set it
|
|
//
|
|
return g_pfnSetPermLayers(szPath, wszLayers, FALSE);
|
|
}
|
|
|
|
void
|
|
NotifyDataChanged(
|
|
HWND hDlg
|
|
)
|
|
{
|
|
HWND hParent;
|
|
|
|
if (!hDlg) {
|
|
LogMsg(_T("[NotifyDataChanged] NULL handle passed in\n"));
|
|
return;
|
|
}
|
|
|
|
hParent = GetParent(hDlg);
|
|
|
|
if (!hParent) {
|
|
LogMsg(_T("[NotifyDataChanged] Can't get get prop sheet parent\n"));
|
|
return;
|
|
}
|
|
|
|
PropSheet_Changed(hParent, hDlg);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SearchGroupForSID(
|
|
DWORD dwGroup,
|
|
BOOL* pfIsMember
|
|
)
|
|
{
|
|
PSID pSID = NULL;
|
|
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
|
|
BOOL fRes = FALSE;
|
|
|
|
if (!AllocateAndInitializeSid(&SIDAuth,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
dwGroup,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
&pSID)) {
|
|
LogMsg(_T("[SearchGroupForSID] AllocateAndInitializeSid failed 0x%X\n"), GetLastError());
|
|
goto out;
|
|
}
|
|
|
|
if (!CheckTokenMembership(NULL, pSID, pfIsMember)) {
|
|
LogMsg(_T("[SearchGroupForSID] CheckTokenMembership failed 0x%X\n"), GetLastError());
|
|
goto out;
|
|
}
|
|
|
|
fRes = TRUE;
|
|
|
|
out:
|
|
|
|
if (pSID) {
|
|
FreeSid(pSID);
|
|
}
|
|
|
|
if (!fRes && pfIsMember) {
|
|
*pfIsMember = FALSE;
|
|
}
|
|
|
|
return fRes;
|
|
}
|
|
|
|
void
|
|
CheckForRestrictedUser(
|
|
void
|
|
)
|
|
{
|
|
BOOL fIsAdmin = FALSE;
|
|
|
|
if (!SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &fIsAdmin)) {
|
|
return;
|
|
}
|
|
|
|
g_bAdmin = fIsAdmin;
|
|
|
|
return;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LayerPageDlgProc
|
|
//
|
|
// The dialog proc for the layer property page.
|
|
|
|
INT_PTR CALLBACK
|
|
LayerPageDlgProc(
|
|
HWND hdlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
int wCode = LOWORD(wParam);
|
|
int wNotifyCode = HIWORD(wParam);
|
|
int nLayer = -1;
|
|
DWORD dwFlags = 0;
|
|
|
|
switch (uMsg) {
|
|
case WM_INITDIALOG:
|
|
{
|
|
PROPSHEETPAGE* ppsp = (PROPSHEETPAGE*)lParam;
|
|
DWORD dwFlags = 0;
|
|
CLayerUIPropPage* pPropPage = (CLayerUIPropPage*)ppsp->lParam;
|
|
HINSTANCE hSlayerXPInst = NULL;
|
|
BOOL bSystemBinary;
|
|
int i;
|
|
|
|
LogMsg(_T("[LayerPageDlgProc] WM_INITDIALOG - item \"%s\"\n"),
|
|
pPropPage->m_szFile);
|
|
|
|
//
|
|
// Store the name of the EXE/LNK in the dialog.
|
|
//
|
|
SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pPropPage->m_szFile);
|
|
|
|
//
|
|
// Check for restricted users.
|
|
//
|
|
CheckForRestrictedUser();
|
|
|
|
//
|
|
// Check for .NET Server which uses a different URL for help center.
|
|
//
|
|
IsDotNetServer();
|
|
|
|
if (!g_bAdmin) {
|
|
EnableWindow(GetDlgItem(hdlg, IDC_ENABLELUA), FALSE);
|
|
}
|
|
|
|
//
|
|
// Add the names of the layers.
|
|
//
|
|
for (i = 0; i < NUM_LAYERS; ++i) {
|
|
TCHAR szFriendlyName[100];
|
|
|
|
if (LoadString(g_hInstance, g_LayerInfo[i].nstrFriendlyName, szFriendlyName, ARRAYSIZE(szFriendlyName))) {
|
|
SendDlgItemMessage(hdlg,
|
|
IDC_LAYER_NAME,
|
|
CB_ADDSTRING,
|
|
0,
|
|
(LPARAM)szFriendlyName);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if the EXE is SFPed.
|
|
//
|
|
bSystemBinary = SfcIsFileProtected(0, pPropPage->m_szFile);
|
|
|
|
//
|
|
// Check to see if we can change layers on this file
|
|
//
|
|
if (!g_pfnAllowPermLayer(pPropPage->m_szFile) || bSystemBinary) {
|
|
|
|
TCHAR szTemp[256] = _T("");
|
|
|
|
SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 0, 0);
|
|
EnableWindow(GetDlgItem(hdlg, IDC_USE_LAYER), FALSE);
|
|
EnableWindow(GetDlgItem(hdlg, IDC_256COLORS), FALSE);
|
|
EnableWindow(GetDlgItem(hdlg, IDC_640X480), FALSE);
|
|
EnableWindow(GetDlgItem(hdlg, IDC_ENABLE_THEMES), FALSE);
|
|
EnableWindow(GetDlgItem(hdlg, IDC_ENABLELUA), FALSE);
|
|
|
|
//
|
|
// Change the text on the static object
|
|
//
|
|
if (bSystemBinary) {
|
|
LoadString(g_hInstance, IDS_COMPAT_UNAVAILABLE_SYSTEM, szTemp, ARRAYSIZE(szTemp));
|
|
} else {
|
|
LoadString(g_hInstance, IDS_COMPAT_UNAVAILABLE, szTemp, ARRAYSIZE(szTemp));
|
|
}
|
|
|
|
SendDlgItemMessage(hdlg, IDC_TEXT_INSTRUCTIONS, WM_SETTEXT, 0, (LPARAM)szTemp);
|
|
|
|
} else {
|
|
//
|
|
// Read the layer storage for info on this item.
|
|
//
|
|
GetLayerInfo(pPropPage->m_szFile, GPLK_ALL, &nLayer, &dwFlags);
|
|
|
|
//
|
|
// Select the appropriate layer for this item. If no info
|
|
// is available in the layer store, default to the Win9x layer.
|
|
//
|
|
if (nLayer != -1) {
|
|
SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, nLayer, 0);
|
|
EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), TRUE);
|
|
SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_SETCHECK, BST_CHECKED, 0);
|
|
|
|
} else {
|
|
SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 0, 0);
|
|
EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), FALSE);
|
|
SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_SETCHECK, BST_UNCHECKED, 0);
|
|
}
|
|
|
|
if (dwFlags & FLAG_256) {
|
|
SendDlgItemMessage(hdlg, IDC_256COLORS, BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
|
|
if (dwFlags & FLAG_640x480) {
|
|
SendDlgItemMessage(hdlg, IDC_640X480, BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
|
|
if (dwFlags & FLAG_DISABLE_THEMES) {
|
|
SendDlgItemMessage(hdlg, IDC_ENABLE_THEMES, BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
|
|
if (dwFlags & FLAG_ENABLE_LUA) {
|
|
SendDlgItemMessage(hdlg, IDC_ENABLELUA, BM_SETCHECK, BST_CHECKED, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_HELP:
|
|
{
|
|
LPHELPINFO lphi;
|
|
|
|
lphi = (LPHELPINFO)lParam;
|
|
if (lphi->iContextType == HELPINFO_WINDOW) {
|
|
WinHelp((HWND)lphi->hItemHandle,
|
|
L"Windows.hlp",
|
|
HELP_CONTEXTPOPUP,
|
|
(DWORD)lphi->iCtrlId);
|
|
|
|
}
|
|
break;
|
|
}
|
|
case WM_COMMAND:
|
|
{
|
|
|
|
switch (wNotifyCode) {
|
|
|
|
case CBN_SELCHANGE:
|
|
NotifyDataChanged(hdlg);
|
|
return TRUE;
|
|
}
|
|
|
|
switch (wCode) {
|
|
|
|
case IDC_256COLORS:
|
|
case IDC_640X480:
|
|
case IDC_ENABLE_THEMES:
|
|
case IDC_ENABLELUA:
|
|
NotifyDataChanged(hdlg);
|
|
break;
|
|
|
|
|
|
case IDC_USE_LAYER:
|
|
if (SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
|
EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), TRUE);
|
|
|
|
} else {
|
|
EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), FALSE);
|
|
}
|
|
NotifyDataChanged(hdlg);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_NOTIFY:
|
|
{
|
|
NMHDR *pHdr = (NMHDR*)lParam;
|
|
|
|
switch (pHdr->code) {
|
|
case NM_CLICK:
|
|
case NM_RETURN:
|
|
{
|
|
if ((int)wParam != IDC_LEARN) {
|
|
break;
|
|
}
|
|
|
|
SHELLEXECUTEINFO sei = { 0 };
|
|
|
|
sei.cbSize = sizeof(SHELLEXECUTEINFO);
|
|
sei.fMask = SEE_MASK_DOENVSUBST;
|
|
sei.hwnd = hdlg;
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
|
|
if (g_bServer) {
|
|
sei.lpFile = _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");
|
|
} else {
|
|
sei.lpFile = _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");
|
|
}
|
|
|
|
ShellExecuteEx(&sei);
|
|
break;
|
|
}
|
|
case PSN_APPLY:
|
|
{
|
|
TCHAR *szFile;
|
|
|
|
szFile = (TCHAR*)GetWindowLongPtr(hdlg, GWLP_USERDATA);
|
|
|
|
if (szFile) {
|
|
if (SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
|
LRESULT retval;
|
|
|
|
retval = SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_GETCURSEL, 0, 0);
|
|
if (retval == CB_ERR) {
|
|
LogMsg(_T("[LayerPageDlgProc] Can't get combobox selection\n"));
|
|
nLayer = -1;
|
|
} else {
|
|
nLayer = (int)retval;
|
|
}
|
|
} else {
|
|
nLayer = -1;
|
|
}
|
|
|
|
dwFlags = 0;
|
|
|
|
if (SendDlgItemMessage(hdlg, IDC_256COLORS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
|
dwFlags |= FLAG_256;
|
|
}
|
|
|
|
if (SendDlgItemMessage(hdlg, IDC_640X480, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
|
dwFlags |= FLAG_640x480;
|
|
}
|
|
|
|
if (SendDlgItemMessage(hdlg, IDC_ENABLE_THEMES, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
|
dwFlags |= FLAG_DISABLE_THEMES;
|
|
}
|
|
|
|
if (SendDlgItemMessage(hdlg, IDC_ENABLELUA, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
|
dwFlags |= FLAG_ENABLE_LUA;
|
|
}
|
|
|
|
SetLayerInfo(szFile, nLayer, dwFlags);
|
|
} else {
|
|
LogMsg(_T("[LayerPageDlgProc] Can't get file name from WindowLong\n"));
|
|
}
|
|
|
|
SetWindowLongPtr(hdlg, DWLP_MSGRESULT, PSNRET_NOERROR);
|
|
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// LayerPageCallbackProc
|
|
//
|
|
// The callback for the property page.
|
|
|
|
UINT CALLBACK
|
|
LayerPageCallbackProc(
|
|
HWND hwnd,
|
|
UINT uMsg,
|
|
LPPROPSHEETPAGE ppsp
|
|
)
|
|
{
|
|
switch (uMsg) {
|
|
case PSPCB_RELEASE:
|
|
if (ppsp->lParam != 0) {
|
|
CLayerUIPropPage* pPropPage = (CLayerUIPropPage*)(ppsp->lParam);
|
|
|
|
LogMsg(_T("[LayerPageCallbackProc] releasing CLayerUIPropPage\n"));
|
|
|
|
pPropPage->Release();
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetExeFromLnk(
|
|
TCHAR* pszLnk,
|
|
TCHAR* pszExe,
|
|
int cchSize
|
|
)
|
|
{
|
|
HRESULT hres;
|
|
IShellLink* psl = NULL;
|
|
IPersistFile* pPf = NULL;
|
|
TCHAR szArg[MAX_PATH];
|
|
BOOL bSuccess = FALSE;
|
|
|
|
IShellLinkDataList* psldl = NULL;
|
|
EXP_DARWIN_LINK* pexpDarwin = NULL;
|
|
|
|
hres = CoCreateInstance(CLSID_ShellLink,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink,
|
|
(LPVOID*)&psl);
|
|
if (FAILED(hres)) {
|
|
LogMsg(_T("[GetExeFromLnk] CoCreateInstance failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&pPf);
|
|
|
|
if (FAILED(hres)) {
|
|
LogMsg(_T("[GetExeFromLnk] QueryInterface for IPersistFile failed\n"));
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Load the link file.
|
|
//
|
|
hres = pPf->Load(pszLnk, STGM_READ);
|
|
|
|
if (FAILED(hres)) {
|
|
LogMsg(_T("[GetExeFromLnk] failed to load link \"%s\"\n"),
|
|
pszLnk);
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// See if this is a DARWIN link.
|
|
//
|
|
|
|
hres = psl->QueryInterface(IID_IShellLinkDataList, (LPVOID*)&psldl);
|
|
|
|
if (FAILED(hres)) {
|
|
LogMsg(_T("[GetExeFromLnk] failed to get IShellLinkDataList.\n"));
|
|
} else {
|
|
hres = psldl->CopyDataBlock(EXP_DARWIN_ID_SIG, (void**)&pexpDarwin);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
LogMsg(_T("[GetExeFromLnk] this is a DARWIN link \"%s\".\n"),
|
|
pszLnk);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resolve the link.
|
|
//
|
|
hres = psl->Resolve(NULL,
|
|
SLR_NOTRACK | SLR_NOSEARCH | SLR_NO_UI | SLR_NOUPDATE);
|
|
|
|
if (FAILED(hres)) {
|
|
LogMsg(_T("[GetExeFromLnk] failed to resolve the link \"%s\"\n"),
|
|
pszLnk);
|
|
goto cleanup;
|
|
}
|
|
|
|
pszExe[0] = 0;
|
|
|
|
//
|
|
// Get the path to the link target.
|
|
//
|
|
hres = psl->GetPath(pszExe,
|
|
cchSize,
|
|
NULL,
|
|
SLGP_UNCPRIORITY);
|
|
|
|
if (FAILED(hres)) {
|
|
LogMsg(_T("[GetExeFromLnk] failed to get the path for link \"%s\"\n"),
|
|
pszLnk);
|
|
goto cleanup;
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
cleanup:
|
|
|
|
if (pPf) {
|
|
pPf->Release();
|
|
}
|
|
|
|
if (psl) {
|
|
psl->Release();
|
|
}
|
|
|
|
if (psldl) {
|
|
psldl->Release();
|
|
}
|
|
|
|
if (pexpDarwin) {
|
|
LocalFree(pexpDarwin);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CLayerUIPropPage
|
|
|
|
CLayerUIPropPage::CLayerUIPropPage()
|
|
{
|
|
LogMsg(_T("[CLayerUIPropPage::CLayerUIPropPage]\n"));
|
|
}
|
|
|
|
CLayerUIPropPage::~CLayerUIPropPage()
|
|
{
|
|
LogMsg(_T("[CLayerUIPropPage::~CLayerUIPropPage]\n"));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: ValidateExecutableFile
|
|
//
|
|
// This function exists also in compatUI.dll for the purpose of validating
|
|
// the file as being acceptable for compatibility handling. It looks at the
|
|
// file extension to determine whether a given file is "acceptable"
|
|
//
|
|
|
|
BOOL
|
|
ValidateExecutableFile(
|
|
LPCTSTR pszPath,
|
|
BOOL bValidateFileExists,
|
|
BOOL* pbIsLink
|
|
)
|
|
{
|
|
LPTSTR rgExt[] = { // this list should be sorted
|
|
_T("BAT"),
|
|
_T("CMD"),
|
|
_T("COM"),
|
|
_T("EXE"),
|
|
_T("LNK"),
|
|
_T("PIF")
|
|
};
|
|
LPTSTR pExt;
|
|
TCHAR szLnk[] = _T("LNK");
|
|
int i;
|
|
int iCmp = 1;
|
|
|
|
pExt = PathFindExtension(pszPath);
|
|
if (pExt == NULL || *pExt == TEXT('\0')) {
|
|
return FALSE;
|
|
}
|
|
++pExt; // move past '.'
|
|
|
|
for (i = 0; i < sizeof(rgExt)/sizeof(rgExt[0]) && iCmp > 0; ++i) {
|
|
iCmp = _tcsicmp(pExt, rgExt[i]);
|
|
}
|
|
|
|
if (iCmp) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pbIsLink) {
|
|
*pbIsLink = !_tcsicmp(pExt, szLnk);
|
|
}
|
|
|
|
return bValidateFileExists ? PathFileExists(pszPath) : TRUE;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// IShellExtInit methods
|
|
|
|
STDMETHODIMP
|
|
CLayerUIPropPage::Initialize(
|
|
LPCITEMIDLIST pIDFolder,
|
|
LPDATAOBJECT pDataObj,
|
|
HKEY hKeyID
|
|
)
|
|
{
|
|
LogMsg(_T("[CLayerUIPropPage::Initialize]\n"));
|
|
|
|
if (pDataObj == NULL) {
|
|
LogMsg(_T("\t failed. bad argument.\n"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// check the policy settings
|
|
//
|
|
if (!CheckGroupPolicy()) {
|
|
LogMsg(_T("\t failed. Group policy set to disable compat UI.\n"));
|
|
return E_ACCESSDENIED;
|
|
}
|
|
|
|
//
|
|
// init the apphelp calls
|
|
//
|
|
if (!InitAppHelpCalls()) {
|
|
LogMsg(_T("\t failed. couldn't init apphelp calls.\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Store a pointer to the data object
|
|
//
|
|
m_spDataObj = pDataObj;
|
|
|
|
//
|
|
// If a data object pointer was passed in, save it and
|
|
// extract the file name.
|
|
//
|
|
STGMEDIUM medium;
|
|
UINT uCount;
|
|
FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1,
|
|
TYMED_HGLOBAL};
|
|
|
|
m_szFile[0] = 0;
|
|
|
|
if (SUCCEEDED(m_spDataObj->GetData(&fe, &medium))) {
|
|
|
|
//
|
|
// Get the file name from the CF_HDROP.
|
|
//
|
|
uCount = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1,
|
|
NULL, 0);
|
|
if (uCount == 1) {
|
|
|
|
TCHAR szExe[MAX_PATH];
|
|
BOOL bIsLink = FALSE;
|
|
|
|
DragQueryFile((HDROP)medium.hGlobal, 0, szExe,
|
|
sizeof(szExe) / sizeof(TCHAR));
|
|
|
|
LogMsg(_T("\tProp page for: \"%s\".\n"), szExe);
|
|
|
|
if (ValidateExecutableFile(szExe, TRUE, &bIsLink)) {
|
|
|
|
|
|
if (bIsLink) {
|
|
//
|
|
// the file is a link indeed, get the contents
|
|
//
|
|
if (!GetExeFromLnk(szExe, m_szFile, ARRAYSIZE(m_szFile))) {
|
|
|
|
//
|
|
// can't get exe from the link
|
|
//
|
|
LogMsg(_T("Couldn't convert \"%s\" to EXE.\n"), m_szFile);
|
|
m_szFile[0] = 0;
|
|
|
|
} else {
|
|
|
|
LogMsg(_T("\tLNK points to: \"%s\".\n"), m_szFile);
|
|
//
|
|
// check to see if it's a shortcut to an EXE file
|
|
//
|
|
if (!ValidateExecutableFile(m_szFile, FALSE, NULL)) {
|
|
//
|
|
// shortcut points to a file of the unsupported type, reset the name
|
|
//
|
|
LogMsg(_T("\tNot an EXE file. Won't init prop page.\n"), m_szFile);
|
|
m_szFile[0] = 0;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// not a link, just copy the filename
|
|
//
|
|
|
|
StringCchCopy(m_szFile, ARRAYSIZE(m_szFile), szExe);
|
|
|
|
}
|
|
} else {
|
|
//
|
|
// this is the case when the file is not .lnk, exe or other recognizable type.
|
|
//
|
|
LogMsg(_T("\tNot an EXE or LNK file. Won't init prop page.\n"));
|
|
m_szFile[0] = 0;
|
|
}
|
|
}
|
|
|
|
ReleaseStgMedium(&medium);
|
|
} else {
|
|
LogMsg(_T("\t failed to get the data.\n"));
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// IShellPropSheetExt methods
|
|
|
|
|
|
STDMETHODIMP
|
|
CLayerUIPropPage::AddPages(
|
|
LPFNADDPROPSHEETPAGE lpfnAddPage,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PROPSHEETPAGE psp;
|
|
HPROPSHEETPAGE hPage;
|
|
TCHAR szCompatibility[128] = _T("");
|
|
BOOL fIsGuest = FALSE;
|
|
DWORD dwBinaryType = SCS_32BIT_BINARY;
|
|
|
|
LogMsg(_T("[CLayerUIPropPage::AddPages]\n"));
|
|
|
|
if (m_szFile[0] == 0) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (GetBinaryTypeW(m_szFile, &dwBinaryType)) {
|
|
if (dwBinaryType == SCS_64BIT_BINARY) {
|
|
//
|
|
// If this is a 64-bit binary, don't show the page.
|
|
//
|
|
//
|
|
LogMsg(_T("\tDisable the compatibility page for 64-bit binary\n"));
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Disable the property page for guests
|
|
//
|
|
if (!SearchGroupForSID(DOMAIN_ALIAS_RID_GUESTS, &fIsGuest)) {
|
|
LogMsg(_T("\tFailed to lookup the GUEST account\n"));
|
|
return S_OK;
|
|
}
|
|
|
|
if (fIsGuest) {
|
|
LogMsg(_T("\tDisable the compatibility page for the GUEST account\n"));
|
|
return S_OK;
|
|
}
|
|
|
|
if (!LoadString(g_hInstance, IDS_COMPATIBILITY, szCompatibility, ARRAYSIZE(szCompatibility))) {
|
|
LogMsg(_T("\tFailed to load \"Compatibility\" resource string\n"));
|
|
return S_OK;
|
|
}
|
|
|
|
psp.dwSize = sizeof(psp);
|
|
psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
|
|
psp.hInstance = _Module.m_hInst;
|
|
psp.pszTemplate = MAKEINTRESOURCE(IDD_LAYER_PROPPAGE);
|
|
psp.hIcon = 0;
|
|
psp.pszTitle = szCompatibility;
|
|
psp.pfnDlgProc = LayerPageDlgProc;
|
|
psp.pcRefParent = &g_DllRefCount;
|
|
psp.pfnCallback = LayerPageCallbackProc;
|
|
psp.lParam = (LPARAM)this;
|
|
|
|
LogMsg(_T("\titem \"%s\".\n"), m_szFile);
|
|
LogMsg(_T("\tg_DllRefCount %d.\n"), g_DllRefCount);
|
|
|
|
AddRef();
|
|
|
|
hPage = CreatePropertySheetPage(&psp);
|
|
|
|
if (hPage != NULL) {
|
|
|
|
if (lpfnAddPage(hPage, lParam)) {
|
|
return S_OK;
|
|
} else {
|
|
DestroyPropertySheetPage(hPage);
|
|
Release();
|
|
return S_OK;
|
|
}
|
|
} else {
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CLayerUIPropPage::ReplacePage(
|
|
UINT uPageID,
|
|
LPFNADDPROPSHEETPAGE lpfnReplacePage,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
LogMsg(_T("[CLayerUIPropPage::ReplacePage]\n"));
|
|
return S_OK;
|
|
}
|
|
|