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.

1251 lines
34 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000
  5. //
  6. // File: ShellExtensions.cpp
  7. //
  8. // Contents: object to implement propertypage extensions
  9. // for Win2k shim layer
  10. //
  11. // History: 23-september-00 clupu Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "stdafx.h"
  16. #include "resource.h"
  17. #include "ShellExtensions.h"
  18. #include <sfc.h>
  19. #include "Aclapi.h"
  20. #include "strsafe.h"
  21. UINT g_DllRefCount = 0;
  22. extern HINSTANCE g_hInstance;
  23. typedef struct _LAYER_INFO {
  24. WCHAR wszInternalName[32];
  25. UINT nstrFriendlyName;
  26. } LAYER_INFO, *PLAYER_INFO;
  27. //
  28. // internal definitions of layer names
  29. //
  30. #define STR_LAYER_WIN95 L"WIN95"
  31. #define STR_LAYER_WIN98 L"WIN98"
  32. #define STR_LAYER_WINNT L"NT4SP5"
  33. #define STR_LAYER_WIN2K L"WIN2000"
  34. #define STR_LAYER_WINXP L"WINXP"
  35. #define STR_LAYER_256COLOR L"256COLOR"
  36. #define STR_LAYER_LORES L"640X480"
  37. #define STR_LAYER_DISABLETHEMES L"DISABLETHEMES"
  38. #define STR_LAYER_ENABLELUA L"LUA"
  39. //
  40. // Layer flags
  41. //
  42. #define FLAG_256 0x00000001
  43. #define FLAG_640x480 0x00000002
  44. #define FLAG_DISABLE_THEMES 0x00000004
  45. #define FLAG_ENABLE_LUA 0x00000010
  46. const LAYER_INFO g_LayerInfo[] =
  47. {
  48. {
  49. STR_LAYER_WIN95,
  50. IDS_LAYER_WIN95_EXT
  51. },
  52. {
  53. STR_LAYER_WIN98,
  54. IDS_LAYER_WIN98_EXT
  55. },
  56. {
  57. STR_LAYER_WINNT,
  58. IDS_LAYER_NT4_EXT
  59. },
  60. {
  61. STR_LAYER_WIN2K,
  62. IDS_LAYER_WIN2K_EXT
  63. },
  64. {
  65. STR_LAYER_WINXP,
  66. IDS_LAYER_WINXP_EXT
  67. }
  68. };
  69. #define NUM_LAYERS (sizeof(g_LayerInfo)/sizeof(g_LayerInfo[0]))
  70. typedef BOOL (STDAPICALLTYPE *_pfn_AllowPermLayer)(WCHAR* pwszPath);
  71. typedef BOOL (STDAPICALLTYPE *_pfn_GetPermLayers)(WCHAR* pwszPath, WCHAR *pwszLayers, DWORD *pdwBytes, DWORD dwFlags);
  72. typedef BOOL (STDAPICALLTYPE *_pfn_SetPermLayers)(WCHAR* pwszPath, WCHAR *pwszLayers, BOOL bMachine);
  73. HINSTANCE g_hAppHelp = NULL;
  74. BOOL g_bAdmin = FALSE;
  75. BOOL g_bServer = FALSE;
  76. _pfn_AllowPermLayer g_pfnAllowPermLayer = NULL;
  77. _pfn_GetPermLayers g_pfnGetPermLayers = NULL;
  78. _pfn_SetPermLayers g_pfnSetPermLayers = NULL;
  79. void
  80. IsDotNetServer(
  81. void
  82. )
  83. {
  84. OSVERSIONINFOEX osvi;
  85. osvi.dwOSVersionInfoSize = sizeof(osvi);
  86. if (!GetVersionEx((OSVERSIONINFO*)&osvi)) {
  87. return;
  88. }
  89. if (osvi.wProductType != VER_NT_WORKSTATION) {
  90. g_bServer = TRUE;
  91. }
  92. }
  93. BOOL
  94. CheckGroupPolicy(
  95. void
  96. )
  97. {
  98. HKEY hKey;
  99. LONG lResult;
  100. DWORD dwValue, dwSize = sizeof(dwValue);
  101. DWORD dwType;
  102. //
  103. // First, check for the whole engine being disabled.
  104. //
  105. lResult = RegOpenKeyExW (HKEY_LOCAL_MACHINE, POLICY_KEY_APPCOMPAT_W, 0,
  106. KEY_READ, &hKey);
  107. if (lResult == ERROR_SUCCESS) {
  108. dwValue = 0;
  109. lResult = RegQueryValueExW (hKey, POLICY_VALUE_DISABLE_ENGINE_W, 0, &dwType,
  110. (LPBYTE) &dwValue, &dwSize);
  111. RegCloseKey (hKey);
  112. }
  113. //
  114. // The default is enabled, so if we didn't find a value, treat it like the value is 0.
  115. //
  116. if (lResult != ERROR_SUCCESS || dwValue == 0) {
  117. //
  118. // Check for the proppage being disabled.
  119. //
  120. lResult = RegOpenKeyExW (HKEY_LOCAL_MACHINE, POLICY_KEY_APPCOMPAT_W, 0,
  121. KEY_READ, &hKey);
  122. if (lResult == ERROR_SUCCESS) {
  123. dwValue = 0;
  124. lResult = RegQueryValueExW (hKey, POLICY_VALUE_DISABLE_PROPPAGE_W, 0, &dwType,
  125. (LPBYTE) &dwValue, &dwSize);
  126. RegCloseKey (hKey);
  127. }
  128. //
  129. // 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.
  130. //
  131. if (lResult != ERROR_SUCCESS || dwValue == 0) {
  132. return TRUE;
  133. }
  134. }
  135. return FALSE;
  136. }
  137. BOOL
  138. InitAppHelpCalls(
  139. void
  140. )
  141. {
  142. HINSTANCE hAppHelp;
  143. if (g_hAppHelp) {
  144. //
  145. // we're already inited
  146. //
  147. return TRUE;
  148. }
  149. hAppHelp = LoadLibrary(TEXT("apphelp.dll"));
  150. if (!hAppHelp) {
  151. LogMsg(_T("[InitAppHelpCalls] Can't get handle to apphelp.dll.\n"));
  152. return FALSE;
  153. }
  154. g_pfnAllowPermLayer = (_pfn_AllowPermLayer)GetProcAddress(hAppHelp, "AllowPermLayer");
  155. g_pfnGetPermLayers = (_pfn_GetPermLayers)GetProcAddress(hAppHelp, "GetPermLayers");
  156. g_pfnSetPermLayers = (_pfn_SetPermLayers)GetProcAddress(hAppHelp, "SetPermLayers");
  157. if (!g_pfnAllowPermLayer || !g_pfnGetPermLayers || !g_pfnSetPermLayers) {
  158. LogMsg(_T("[InitAppHelpCalls] Can't get function pointers.\n"));
  159. return FALSE;
  160. }
  161. //
  162. // this needs to be here at the end to avoid a race condition
  163. //
  164. g_hAppHelp = hAppHelp;
  165. return TRUE;
  166. }
  167. BOOL
  168. GiveUsersWriteAccess(
  169. void
  170. )
  171. {
  172. DWORD dwRes;
  173. EXPLICIT_ACCESS ea;
  174. PACL pOldDACL;
  175. PACL pNewDACL = NULL;
  176. PSECURITY_DESCRIPTOR pSD = NULL;
  177. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  178. PSID pUsersSID = NULL;
  179. TCHAR szDir[MAX_PATH];
  180. ExpandEnvironmentStrings(LUA_REDIR_W, szDir, MAX_PATH);
  181. if (!CreateDirectory(szDir, NULL)) {
  182. DWORD err = GetLastError();
  183. if (GetLastError() != ERROR_ALREADY_EXISTS) {
  184. LogMsg(_T("[GiveUsersWriteAccess] Failed to create the directory.\n"));
  185. return FALSE;
  186. }
  187. }
  188. dwRes = GetNamedSecurityInfo(szDir,
  189. SE_FILE_OBJECT,
  190. DACL_SECURITY_INFORMATION,
  191. NULL,
  192. NULL,
  193. &pOldDACL,
  194. NULL,
  195. &pSD);
  196. if (ERROR_SUCCESS != dwRes) {
  197. LogMsg(_T("[GiveUsersWriteAccess] GetNamedSecurityInfo error %u\n"), dwRes);
  198. goto Cleanup;
  199. }
  200. if (!AllocateAndInitializeSid(&SIDAuth,
  201. 2,
  202. SECURITY_BUILTIN_DOMAIN_RID,
  203. DOMAIN_ALIAS_RID_USERS,
  204. 0,
  205. 0,
  206. 0,
  207. 0,
  208. 0,
  209. 0,
  210. &pUsersSID) ) {
  211. LogMsg(_T("[GiveUsersWriteAccess] AllocateAndInitializeSid error %u\n"), GetLastError());
  212. goto Cleanup;
  213. }
  214. //
  215. // Initialize an EXPLICIT_ACCESS structure for the new ACE.
  216. //
  217. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
  218. ea.grfAccessPermissions = FILE_GENERIC_WRITE | FILE_GENERIC_READ | DELETE;
  219. ea.grfAccessMode = GRANT_ACCESS;
  220. ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  221. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  222. ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  223. ea.Trustee.ptstrName = (LPTSTR)pUsersSID;
  224. //
  225. // Create a new ACL that merges the new ACE
  226. // into the existing DACL.
  227. //
  228. dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
  229. if (ERROR_SUCCESS != dwRes) {
  230. LogMsg(_T("[GiveUsersWriteAccess] SetEntriesInAcl error %u\n"), dwRes);
  231. goto Cleanup;
  232. }
  233. dwRes = SetNamedSecurityInfo(szDir,
  234. SE_FILE_OBJECT,
  235. DACL_SECURITY_INFORMATION,
  236. NULL,
  237. NULL,
  238. pNewDACL,
  239. NULL);
  240. if (ERROR_SUCCESS != dwRes) {
  241. LogMsg(_T("[GiveUsersWriteAccess] SetNamedSecurityInfo error %u\n"), dwRes);
  242. goto Cleanup;
  243. }
  244. Cleanup:
  245. if (pSD) {
  246. LocalFree(pSD);
  247. }
  248. if (pUsersSID) {
  249. FreeSid(pUsersSID);
  250. }
  251. if (pNewDACL) {
  252. LocalFree(pNewDACL);
  253. }
  254. return (dwRes == ERROR_SUCCESS);
  255. }
  256. //////////////////////////////////////////////////////////////////////////
  257. // GetLayerInfo
  258. //
  259. BOOL
  260. GetLayerInfo(
  261. TCHAR* szPath,
  262. DWORD dwFrom,
  263. int* pnMainLayer,
  264. DWORD* pdwFlags
  265. )
  266. {
  267. WCHAR wszLayers[256];
  268. DWORD dwBytes = sizeof(wszLayers);
  269. int i;
  270. if (!pnMainLayer || pdwFlags == NULL) {
  271. LogMsg(_T("[GetLayerInfo] invalid parameters\n"));
  272. return FALSE;
  273. }
  274. *pdwFlags = 0;
  275. //
  276. // get layer string
  277. //
  278. if (!g_pfnGetPermLayers(szPath, wszLayers, &dwBytes, dwFrom)) {
  279. *pnMainLayer = -1;
  280. return TRUE;
  281. }
  282. LogMsg(_T("[GetLayerInfo] Layers \"%s\"\n"), wszLayers);
  283. //
  284. // Make the layer string upper case, so we'll match case-insensitive
  285. //
  286. _wcsupr(wszLayers);
  287. //
  288. // find the first layer that matches
  289. //
  290. *pnMainLayer = -1;
  291. for (i = 0; i < NUM_LAYERS; ++i) {
  292. if (wcsstr(wszLayers, g_LayerInfo[i].wszInternalName) != NULL) {
  293. *pnMainLayer = i;
  294. }
  295. }
  296. if (wcsstr(wszLayers, STR_LAYER_256COLOR) != NULL) {
  297. *pdwFlags |= FLAG_256;
  298. }
  299. if (wcsstr(wszLayers, STR_LAYER_LORES) != NULL) {
  300. *pdwFlags |= FLAG_640x480;
  301. }
  302. if (wcsstr(wszLayers, STR_LAYER_DISABLETHEMES) != NULL) {
  303. *pdwFlags |= FLAG_DISABLE_THEMES;
  304. }
  305. if (wcsstr(wszLayers, STR_LAYER_ENABLELUA) != NULL) {
  306. *pdwFlags |= FLAG_ENABLE_LUA;
  307. }
  308. LogMsg(_T("[GetLayerInfo] Layers 0x%x\n"), *pdwFlags);
  309. return TRUE;
  310. }
  311. void
  312. BuildLayerString(
  313. WCHAR* pwszLayers,
  314. DWORD cchBufSize,
  315. int nMainLayer,
  316. DWORD dwFlags,
  317. BOOL bMachine
  318. )
  319. {
  320. pwszLayers[0] = 0;
  321. if (nMainLayer >= 0 && nMainLayer < NUM_LAYERS) {
  322. StringCchCatW(pwszLayers, cchBufSize, g_LayerInfo[nMainLayer].wszInternalName);
  323. }
  324. if (dwFlags & FLAG_256) {
  325. if (pwszLayers[0]) {
  326. StringCchCatW(pwszLayers, cchBufSize, L" ");
  327. }
  328. StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_256COLOR);
  329. }
  330. if (dwFlags & FLAG_640x480) {
  331. if (pwszLayers[0]) {
  332. StringCchCatW(pwszLayers, cchBufSize, L" ");
  333. }
  334. StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_LORES);
  335. }
  336. if (dwFlags & FLAG_DISABLE_THEMES) {
  337. if (pwszLayers[0]) {
  338. StringCchCatW(pwszLayers, cchBufSize, L" ");
  339. }
  340. StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_DISABLETHEMES);
  341. }
  342. if (bMachine) {
  343. if (dwFlags & FLAG_ENABLE_LUA) {
  344. if (pwszLayers[0]) {
  345. StringCchCatW(pwszLayers, cchBufSize, L" ");
  346. }
  347. StringCchCatW(pwszLayers, cchBufSize, STR_LAYER_ENABLELUA);
  348. }
  349. }
  350. }
  351. //////////////////////////////////////////////////////////////////////////
  352. // SetLayerInfo
  353. //
  354. BOOL
  355. SetLayerInfo(
  356. TCHAR* szPath,
  357. int nMainLayer,
  358. DWORD dwFlags
  359. )
  360. {
  361. WCHAR wszLayers[256];
  362. //
  363. // build layer string
  364. //
  365. BuildLayerString(wszLayers, ARRAYSIZE(wszLayers), nMainLayer, dwFlags, FALSE);
  366. if (g_bAdmin) {
  367. WCHAR wszMachineLayers[256];
  368. DWORD dwMachineFlags;
  369. int nMainLayer;
  370. //
  371. // Get the layers first.
  372. //
  373. GetLayerInfo(szPath, GPLK_MACHINE, &nMainLayer, &dwMachineFlags);
  374. if (dwFlags & FLAG_ENABLE_LUA) {
  375. if (!GiveUsersWriteAccess()) {
  376. LogMsg(_T("[SetLayerInfo] Failed to change directory ACLs.\n"));
  377. }
  378. dwMachineFlags |= FLAG_ENABLE_LUA;
  379. } else {
  380. dwMachineFlags &= ~FLAG_ENABLE_LUA;
  381. }
  382. BuildLayerString(wszMachineLayers, ARRAYSIZE(wszMachineLayers), nMainLayer, dwMachineFlags, TRUE);
  383. if (!g_pfnSetPermLayers(szPath, wszMachineLayers, TRUE)) {
  384. return FALSE;
  385. }
  386. }
  387. //
  388. // set it
  389. //
  390. return g_pfnSetPermLayers(szPath, wszLayers, FALSE);
  391. }
  392. void
  393. NotifyDataChanged(
  394. HWND hDlg
  395. )
  396. {
  397. HWND hParent;
  398. if (!hDlg) {
  399. LogMsg(_T("[NotifyDataChanged] NULL handle passed in\n"));
  400. return;
  401. }
  402. hParent = GetParent(hDlg);
  403. if (!hParent) {
  404. LogMsg(_T("[NotifyDataChanged] Can't get get prop sheet parent\n"));
  405. return;
  406. }
  407. PropSheet_Changed(hParent, hDlg);
  408. }
  409. BOOL
  410. SearchGroupForSID(
  411. DWORD dwGroup,
  412. BOOL* pfIsMember
  413. )
  414. {
  415. PSID pSID = NULL;
  416. SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  417. BOOL fRes = FALSE;
  418. if (!AllocateAndInitializeSid(&SIDAuth,
  419. 2,
  420. SECURITY_BUILTIN_DOMAIN_RID,
  421. dwGroup,
  422. 0,
  423. 0,
  424. 0,
  425. 0,
  426. 0,
  427. 0,
  428. &pSID)) {
  429. LogMsg(_T("[SearchGroupForSID] AllocateAndInitializeSid failed 0x%X\n"), GetLastError());
  430. goto out;
  431. }
  432. if (!CheckTokenMembership(NULL, pSID, pfIsMember)) {
  433. LogMsg(_T("[SearchGroupForSID] CheckTokenMembership failed 0x%X\n"), GetLastError());
  434. goto out;
  435. }
  436. fRes = TRUE;
  437. out:
  438. if (pSID) {
  439. FreeSid(pSID);
  440. }
  441. if (!fRes && pfIsMember) {
  442. *pfIsMember = FALSE;
  443. }
  444. return fRes;
  445. }
  446. void
  447. CheckForRestrictedUser(
  448. void
  449. )
  450. {
  451. BOOL fIsAdmin = FALSE;
  452. if (!SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &fIsAdmin)) {
  453. return;
  454. }
  455. g_bAdmin = fIsAdmin;
  456. return;
  457. }
  458. //////////////////////////////////////////////////////////////////////////
  459. // LayerPageDlgProc
  460. //
  461. // The dialog proc for the layer property page.
  462. INT_PTR CALLBACK
  463. LayerPageDlgProc(
  464. HWND hdlg,
  465. UINT uMsg,
  466. WPARAM wParam,
  467. LPARAM lParam)
  468. {
  469. int wCode = LOWORD(wParam);
  470. int wNotifyCode = HIWORD(wParam);
  471. int nLayer = -1;
  472. DWORD dwFlags = 0;
  473. switch (uMsg) {
  474. case WM_INITDIALOG:
  475. {
  476. PROPSHEETPAGE* ppsp = (PROPSHEETPAGE*)lParam;
  477. DWORD dwFlags = 0;
  478. CLayerUIPropPage* pPropPage = (CLayerUIPropPage*)ppsp->lParam;
  479. HINSTANCE hSlayerXPInst = NULL;
  480. BOOL bSystemBinary;
  481. int i;
  482. LogMsg(_T("[LayerPageDlgProc] WM_INITDIALOG - item \"%s\"\n"),
  483. pPropPage->m_szFile);
  484. //
  485. // Store the name of the EXE/LNK in the dialog.
  486. //
  487. SetWindowLongPtr(hdlg, GWLP_USERDATA, (LONG_PTR)pPropPage->m_szFile);
  488. //
  489. // Check for restricted users.
  490. //
  491. CheckForRestrictedUser();
  492. //
  493. // Check for .NET Server which uses a different URL for help center.
  494. //
  495. IsDotNetServer();
  496. if (!g_bAdmin) {
  497. EnableWindow(GetDlgItem(hdlg, IDC_ENABLELUA), FALSE);
  498. }
  499. //
  500. // Add the names of the layers.
  501. //
  502. for (i = 0; i < NUM_LAYERS; ++i) {
  503. TCHAR szFriendlyName[100];
  504. if (LoadString(g_hInstance, g_LayerInfo[i].nstrFriendlyName, szFriendlyName, ARRAYSIZE(szFriendlyName))) {
  505. SendDlgItemMessage(hdlg,
  506. IDC_LAYER_NAME,
  507. CB_ADDSTRING,
  508. 0,
  509. (LPARAM)szFriendlyName);
  510. }
  511. }
  512. //
  513. // Check if the EXE is SFPed.
  514. //
  515. bSystemBinary = SfcIsFileProtected(0, pPropPage->m_szFile);
  516. //
  517. // Check to see if we can change layers on this file
  518. //
  519. if (!g_pfnAllowPermLayer(pPropPage->m_szFile) || bSystemBinary) {
  520. TCHAR szTemp[256] = _T("");
  521. SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 0, 0);
  522. EnableWindow(GetDlgItem(hdlg, IDC_USE_LAYER), FALSE);
  523. EnableWindow(GetDlgItem(hdlg, IDC_256COLORS), FALSE);
  524. EnableWindow(GetDlgItem(hdlg, IDC_640X480), FALSE);
  525. EnableWindow(GetDlgItem(hdlg, IDC_ENABLE_THEMES), FALSE);
  526. EnableWindow(GetDlgItem(hdlg, IDC_ENABLELUA), FALSE);
  527. //
  528. // Change the text on the static object
  529. //
  530. if (bSystemBinary) {
  531. LoadString(g_hInstance, IDS_COMPAT_UNAVAILABLE_SYSTEM, szTemp, ARRAYSIZE(szTemp));
  532. } else {
  533. LoadString(g_hInstance, IDS_COMPAT_UNAVAILABLE, szTemp, ARRAYSIZE(szTemp));
  534. }
  535. SendDlgItemMessage(hdlg, IDC_TEXT_INSTRUCTIONS, WM_SETTEXT, 0, (LPARAM)szTemp);
  536. } else {
  537. //
  538. // Read the layer storage for info on this item.
  539. //
  540. GetLayerInfo(pPropPage->m_szFile, GPLK_ALL, &nLayer, &dwFlags);
  541. //
  542. // Select the appropriate layer for this item. If no info
  543. // is available in the layer store, default to the Win9x layer.
  544. //
  545. if (nLayer != -1) {
  546. SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, nLayer, 0);
  547. EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), TRUE);
  548. SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_SETCHECK, BST_CHECKED, 0);
  549. } else {
  550. SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 0, 0);
  551. EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), FALSE);
  552. SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_SETCHECK, BST_UNCHECKED, 0);
  553. }
  554. if (dwFlags & FLAG_256) {
  555. SendDlgItemMessage(hdlg, IDC_256COLORS, BM_SETCHECK, BST_CHECKED, 0);
  556. }
  557. if (dwFlags & FLAG_640x480) {
  558. SendDlgItemMessage(hdlg, IDC_640X480, BM_SETCHECK, BST_CHECKED, 0);
  559. }
  560. if (dwFlags & FLAG_DISABLE_THEMES) {
  561. SendDlgItemMessage(hdlg, IDC_ENABLE_THEMES, BM_SETCHECK, BST_CHECKED, 0);
  562. }
  563. if (dwFlags & FLAG_ENABLE_LUA) {
  564. SendDlgItemMessage(hdlg, IDC_ENABLELUA, BM_SETCHECK, BST_CHECKED, 0);
  565. }
  566. }
  567. break;
  568. }
  569. case WM_HELP:
  570. {
  571. LPHELPINFO lphi;
  572. lphi = (LPHELPINFO)lParam;
  573. if (lphi->iContextType == HELPINFO_WINDOW) {
  574. WinHelp((HWND)lphi->hItemHandle,
  575. L"Windows.hlp",
  576. HELP_CONTEXTPOPUP,
  577. (DWORD)lphi->iCtrlId);
  578. }
  579. break;
  580. }
  581. case WM_COMMAND:
  582. {
  583. switch (wNotifyCode) {
  584. case CBN_SELCHANGE:
  585. NotifyDataChanged(hdlg);
  586. return TRUE;
  587. }
  588. switch (wCode) {
  589. case IDC_256COLORS:
  590. case IDC_640X480:
  591. case IDC_ENABLE_THEMES:
  592. case IDC_ENABLELUA:
  593. NotifyDataChanged(hdlg);
  594. break;
  595. case IDC_USE_LAYER:
  596. if (SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_GETCHECK, 0, 0) == BST_CHECKED) {
  597. EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), TRUE);
  598. } else {
  599. EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), FALSE);
  600. }
  601. NotifyDataChanged(hdlg);
  602. break;
  603. default:
  604. return FALSE;
  605. }
  606. break;
  607. }
  608. case WM_NOTIFY:
  609. {
  610. NMHDR *pHdr = (NMHDR*)lParam;
  611. switch (pHdr->code) {
  612. case NM_CLICK:
  613. case NM_RETURN:
  614. {
  615. if ((int)wParam != IDC_LEARN) {
  616. break;
  617. }
  618. SHELLEXECUTEINFO sei = { 0 };
  619. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  620. sei.fMask = SEE_MASK_DOENVSUBST;
  621. sei.hwnd = hdlg;
  622. sei.nShow = SW_SHOWNORMAL;
  623. if (g_bServer) {
  624. sei.lpFile = _T("hcp://services/subsite?node=Troubleshooting_Strategies&")
  625. _T("topic=MS-ITS%3A%25HELP_LOCATION%25%5Cmisc.chm%3A%3A/")
  626. _T("compatibility_tab_and_wizard.htm");
  627. } else {
  628. sei.lpFile = _T("hcp://services/subsite?node=TopLevelBucket_4/")
  629. _T("Fixing_a_problem&topic=MS-ITS%3A%25HELP_LOCATION")
  630. _T("%25%5Cmisc.chm%3A%3A/compatibility_tab_and_wizard.htm")
  631. _T("&select=TopLevelBucket_4/Fixing_a_problem/")
  632. _T("Application_and_software_problems");
  633. }
  634. ShellExecuteEx(&sei);
  635. break;
  636. }
  637. case PSN_APPLY:
  638. {
  639. TCHAR *szFile;
  640. szFile = (TCHAR*)GetWindowLongPtr(hdlg, GWLP_USERDATA);
  641. if (szFile) {
  642. if (SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_GETCHECK, 0, 0) == BST_CHECKED) {
  643. LRESULT retval;
  644. retval = SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_GETCURSEL, 0, 0);
  645. if (retval == CB_ERR) {
  646. LogMsg(_T("[LayerPageDlgProc] Can't get combobox selection\n"));
  647. nLayer = -1;
  648. } else {
  649. nLayer = (int)retval;
  650. }
  651. } else {
  652. nLayer = -1;
  653. }
  654. dwFlags = 0;
  655. if (SendDlgItemMessage(hdlg, IDC_256COLORS, BM_GETCHECK, 0, 0) == BST_CHECKED) {
  656. dwFlags |= FLAG_256;
  657. }
  658. if (SendDlgItemMessage(hdlg, IDC_640X480, BM_GETCHECK, 0, 0) == BST_CHECKED) {
  659. dwFlags |= FLAG_640x480;
  660. }
  661. if (SendDlgItemMessage(hdlg, IDC_ENABLE_THEMES, BM_GETCHECK, 0, 0) == BST_CHECKED) {
  662. dwFlags |= FLAG_DISABLE_THEMES;
  663. }
  664. if (SendDlgItemMessage(hdlg, IDC_ENABLELUA, BM_GETCHECK, 0, 0) == BST_CHECKED) {
  665. dwFlags |= FLAG_ENABLE_LUA;
  666. }
  667. SetLayerInfo(szFile, nLayer, dwFlags);
  668. } else {
  669. LogMsg(_T("[LayerPageDlgProc] Can't get file name from WindowLong\n"));
  670. }
  671. SetWindowLongPtr(hdlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  672. break;
  673. }
  674. }
  675. return TRUE;
  676. }
  677. default:
  678. return FALSE;
  679. }
  680. return TRUE;
  681. }
  682. //////////////////////////////////////////////////////////////////////////
  683. // LayerPageCallbackProc
  684. //
  685. // The callback for the property page.
  686. UINT CALLBACK
  687. LayerPageCallbackProc(
  688. HWND hwnd,
  689. UINT uMsg,
  690. LPPROPSHEETPAGE ppsp
  691. )
  692. {
  693. switch (uMsg) {
  694. case PSPCB_RELEASE:
  695. if (ppsp->lParam != 0) {
  696. CLayerUIPropPage* pPropPage = (CLayerUIPropPage*)(ppsp->lParam);
  697. LogMsg(_T("[LayerPageCallbackProc] releasing CLayerUIPropPage\n"));
  698. pPropPage->Release();
  699. }
  700. break;
  701. }
  702. return 1;
  703. }
  704. BOOL
  705. GetExeFromLnk(
  706. TCHAR* pszLnk,
  707. TCHAR* pszExe,
  708. int cchSize
  709. )
  710. {
  711. HRESULT hres;
  712. IShellLink* psl = NULL;
  713. IPersistFile* pPf = NULL;
  714. TCHAR szArg[MAX_PATH];
  715. BOOL bSuccess = FALSE;
  716. IShellLinkDataList* psldl = NULL;
  717. EXP_DARWIN_LINK* pexpDarwin = NULL;
  718. hres = CoCreateInstance(CLSID_ShellLink,
  719. NULL,
  720. CLSCTX_INPROC_SERVER,
  721. IID_IShellLink,
  722. (LPVOID*)&psl);
  723. if (FAILED(hres)) {
  724. LogMsg(_T("[GetExeFromLnk] CoCreateInstance failed\n"));
  725. return FALSE;
  726. }
  727. hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&pPf);
  728. if (FAILED(hres)) {
  729. LogMsg(_T("[GetExeFromLnk] QueryInterface for IPersistFile failed\n"));
  730. goto cleanup;
  731. }
  732. //
  733. // Load the link file.
  734. //
  735. hres = pPf->Load(pszLnk, STGM_READ);
  736. if (FAILED(hres)) {
  737. LogMsg(_T("[GetExeFromLnk] failed to load link \"%s\"\n"),
  738. pszLnk);
  739. goto cleanup;
  740. }
  741. //
  742. // See if this is a DARWIN link.
  743. //
  744. hres = psl->QueryInterface(IID_IShellLinkDataList, (LPVOID*)&psldl);
  745. if (FAILED(hres)) {
  746. LogMsg(_T("[GetExeFromLnk] failed to get IShellLinkDataList.\n"));
  747. } else {
  748. hres = psldl->CopyDataBlock(EXP_DARWIN_ID_SIG, (void**)&pexpDarwin);
  749. if (SUCCEEDED(hres)) {
  750. LogMsg(_T("[GetExeFromLnk] this is a DARWIN link \"%s\".\n"),
  751. pszLnk);
  752. goto cleanup;
  753. }
  754. }
  755. //
  756. // Resolve the link.
  757. //
  758. hres = psl->Resolve(NULL,
  759. SLR_NOTRACK | SLR_NOSEARCH | SLR_NO_UI | SLR_NOUPDATE);
  760. if (FAILED(hres)) {
  761. LogMsg(_T("[GetExeFromLnk] failed to resolve the link \"%s\"\n"),
  762. pszLnk);
  763. goto cleanup;
  764. }
  765. pszExe[0] = 0;
  766. //
  767. // Get the path to the link target.
  768. //
  769. hres = psl->GetPath(pszExe,
  770. cchSize,
  771. NULL,
  772. SLGP_UNCPRIORITY);
  773. if (FAILED(hres)) {
  774. LogMsg(_T("[GetExeFromLnk] failed to get the path for link \"%s\"\n"),
  775. pszLnk);
  776. goto cleanup;
  777. }
  778. bSuccess = TRUE;
  779. cleanup:
  780. if (pPf) {
  781. pPf->Release();
  782. }
  783. if (psl) {
  784. psl->Release();
  785. }
  786. if (psldl) {
  787. psldl->Release();
  788. }
  789. if (pexpDarwin) {
  790. LocalFree(pexpDarwin);
  791. }
  792. return bSuccess;
  793. }
  794. //////////////////////////////////////////////////////////////////////////
  795. // CLayerUIPropPage
  796. CLayerUIPropPage::CLayerUIPropPage()
  797. {
  798. LogMsg(_T("[CLayerUIPropPage::CLayerUIPropPage]\n"));
  799. }
  800. CLayerUIPropPage::~CLayerUIPropPage()
  801. {
  802. LogMsg(_T("[CLayerUIPropPage::~CLayerUIPropPage]\n"));
  803. }
  804. //////////////////////////////////////////////////////////////////////////
  805. //
  806. // Function: ValidateExecutableFile
  807. //
  808. // This function exists also in compatUI.dll for the purpose of validating
  809. // the file as being acceptable for compatibility handling. It looks at the
  810. // file extension to determine whether a given file is "acceptable"
  811. //
  812. BOOL
  813. ValidateExecutableFile(
  814. LPCTSTR pszPath,
  815. BOOL bValidateFileExists,
  816. BOOL* pbIsLink
  817. )
  818. {
  819. LPTSTR rgExt[] = { // this list should be sorted
  820. _T("BAT"),
  821. _T("CMD"),
  822. _T("COM"),
  823. _T("EXE"),
  824. _T("LNK"),
  825. _T("PIF")
  826. };
  827. LPTSTR pExt;
  828. TCHAR szLnk[] = _T("LNK");
  829. int i;
  830. int iCmp = 1;
  831. pExt = PathFindExtension(pszPath);
  832. if (pExt == NULL || *pExt == TEXT('\0')) {
  833. return FALSE;
  834. }
  835. ++pExt; // move past '.'
  836. for (i = 0; i < sizeof(rgExt)/sizeof(rgExt[0]) && iCmp > 0; ++i) {
  837. iCmp = _tcsicmp(pExt, rgExt[i]);
  838. }
  839. if (iCmp) {
  840. return FALSE;
  841. }
  842. if (pbIsLink) {
  843. *pbIsLink = !_tcsicmp(pExt, szLnk);
  844. }
  845. return bValidateFileExists ? PathFileExists(pszPath) : TRUE;
  846. }
  847. //////////////////////////////////////////////////////////////////////////
  848. // IShellExtInit methods
  849. STDMETHODIMP
  850. CLayerUIPropPage::Initialize(
  851. LPCITEMIDLIST pIDFolder,
  852. LPDATAOBJECT pDataObj,
  853. HKEY hKeyID
  854. )
  855. {
  856. LogMsg(_T("[CLayerUIPropPage::Initialize]\n"));
  857. if (pDataObj == NULL) {
  858. LogMsg(_T("\t failed. bad argument.\n"));
  859. return E_INVALIDARG;
  860. }
  861. //
  862. // check the policy settings
  863. //
  864. if (!CheckGroupPolicy()) {
  865. LogMsg(_T("\t failed. Group policy set to disable compat UI.\n"));
  866. return E_ACCESSDENIED;
  867. }
  868. //
  869. // init the apphelp calls
  870. //
  871. if (!InitAppHelpCalls()) {
  872. LogMsg(_T("\t failed. couldn't init apphelp calls.\n"));
  873. return E_FAIL;
  874. }
  875. //
  876. // Store a pointer to the data object
  877. //
  878. m_spDataObj = pDataObj;
  879. //
  880. // If a data object pointer was passed in, save it and
  881. // extract the file name.
  882. //
  883. STGMEDIUM medium;
  884. UINT uCount;
  885. FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1,
  886. TYMED_HGLOBAL};
  887. m_szFile[0] = 0;
  888. if (SUCCEEDED(m_spDataObj->GetData(&fe, &medium))) {
  889. //
  890. // Get the file name from the CF_HDROP.
  891. //
  892. uCount = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1,
  893. NULL, 0);
  894. if (uCount == 1) {
  895. TCHAR szExe[MAX_PATH];
  896. BOOL bIsLink = FALSE;
  897. DragQueryFile((HDROP)medium.hGlobal, 0, szExe,
  898. sizeof(szExe) / sizeof(TCHAR));
  899. LogMsg(_T("\tProp page for: \"%s\".\n"), szExe);
  900. if (ValidateExecutableFile(szExe, TRUE, &bIsLink)) {
  901. if (bIsLink) {
  902. //
  903. // the file is a link indeed, get the contents
  904. //
  905. if (!GetExeFromLnk(szExe, m_szFile, ARRAYSIZE(m_szFile))) {
  906. //
  907. // can't get exe from the link
  908. //
  909. LogMsg(_T("Couldn't convert \"%s\" to EXE.\n"), m_szFile);
  910. m_szFile[0] = 0;
  911. } else {
  912. LogMsg(_T("\tLNK points to: \"%s\".\n"), m_szFile);
  913. //
  914. // check to see if it's a shortcut to an EXE file
  915. //
  916. if (!ValidateExecutableFile(m_szFile, FALSE, NULL)) {
  917. //
  918. // shortcut points to a file of the unsupported type, reset the name
  919. //
  920. LogMsg(_T("\tNot an EXE file. Won't init prop page.\n"), m_szFile);
  921. m_szFile[0] = 0;
  922. }
  923. }
  924. } else {
  925. //
  926. // not a link, just copy the filename
  927. //
  928. StringCchCopy(m_szFile, ARRAYSIZE(m_szFile), szExe);
  929. }
  930. } else {
  931. //
  932. // this is the case when the file is not .lnk, exe or other recognizable type.
  933. //
  934. LogMsg(_T("\tNot an EXE or LNK file. Won't init prop page.\n"));
  935. m_szFile[0] = 0;
  936. }
  937. }
  938. ReleaseStgMedium(&medium);
  939. } else {
  940. LogMsg(_T("\t failed to get the data.\n"));
  941. }
  942. return NOERROR;
  943. }
  944. //////////////////////////////////////////////////////////////////////////
  945. // IShellPropSheetExt methods
  946. STDMETHODIMP
  947. CLayerUIPropPage::AddPages(
  948. LPFNADDPROPSHEETPAGE lpfnAddPage,
  949. LPARAM lParam
  950. )
  951. {
  952. PROPSHEETPAGE psp;
  953. HPROPSHEETPAGE hPage;
  954. TCHAR szCompatibility[128] = _T("");
  955. BOOL fIsGuest = FALSE;
  956. DWORD dwBinaryType = SCS_32BIT_BINARY;
  957. LogMsg(_T("[CLayerUIPropPage::AddPages]\n"));
  958. if (m_szFile[0] == 0) {
  959. return S_OK;
  960. }
  961. if (GetBinaryTypeW(m_szFile, &dwBinaryType)) {
  962. if (dwBinaryType == SCS_64BIT_BINARY) {
  963. //
  964. // If this is a 64-bit binary, don't show the page.
  965. //
  966. //
  967. LogMsg(_T("\tDisable the compatibility page for 64-bit binary\n"));
  968. return S_OK;
  969. }
  970. }
  971. //
  972. // Disable the property page for guests
  973. //
  974. if (!SearchGroupForSID(DOMAIN_ALIAS_RID_GUESTS, &fIsGuest)) {
  975. LogMsg(_T("\tFailed to lookup the GUEST account\n"));
  976. return S_OK;
  977. }
  978. if (fIsGuest) {
  979. LogMsg(_T("\tDisable the compatibility page for the GUEST account\n"));
  980. return S_OK;
  981. }
  982. if (!LoadString(g_hInstance, IDS_COMPATIBILITY, szCompatibility, ARRAYSIZE(szCompatibility))) {
  983. LogMsg(_T("\tFailed to load \"Compatibility\" resource string\n"));
  984. return S_OK;
  985. }
  986. psp.dwSize = sizeof(psp);
  987. psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
  988. psp.hInstance = _Module.m_hInst;
  989. psp.pszTemplate = MAKEINTRESOURCE(IDD_LAYER_PROPPAGE);
  990. psp.hIcon = 0;
  991. psp.pszTitle = szCompatibility;
  992. psp.pfnDlgProc = LayerPageDlgProc;
  993. psp.pcRefParent = &g_DllRefCount;
  994. psp.pfnCallback = LayerPageCallbackProc;
  995. psp.lParam = (LPARAM)this;
  996. LogMsg(_T("\titem \"%s\".\n"), m_szFile);
  997. LogMsg(_T("\tg_DllRefCount %d.\n"), g_DllRefCount);
  998. AddRef();
  999. hPage = CreatePropertySheetPage(&psp);
  1000. if (hPage != NULL) {
  1001. if (lpfnAddPage(hPage, lParam)) {
  1002. return S_OK;
  1003. } else {
  1004. DestroyPropertySheetPage(hPage);
  1005. Release();
  1006. return S_OK;
  1007. }
  1008. } else {
  1009. return E_OUTOFMEMORY;
  1010. }
  1011. return E_FAIL;
  1012. }
  1013. STDMETHODIMP
  1014. CLayerUIPropPage::ReplacePage(
  1015. UINT uPageID,
  1016. LPFNADDPROPSHEETPAGE lpfnReplacePage,
  1017. LPARAM lParam
  1018. )
  1019. {
  1020. LogMsg(_T("[CLayerUIPropPage::ReplacePage]\n"));
  1021. return S_OK;
  1022. }