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.

838 lines
22 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 "strsafe.h"
  19. UINT g_DllRefCount = 0;
  20. BOOL g_bExtEnabled = FALSE;
  21. TCHAR g_szLayerStorage[MAX_PATH] = _T("");
  22. //////////////////////////////////////////////////////////////////////////
  23. // InitLayerStorage
  24. //
  25. // Get the name of the file that will be used to store
  26. // information about which EXEs/LNKs are layered.
  27. void
  28. InitLayerStorage(
  29. BOOL bDelete
  30. )
  31. {
  32. GetSystemWindowsDirectory(g_szLayerStorage, ARRAYSIZE(g_szLayerStorage));
  33. if (g_szLayerStorage[lstrlen(g_szLayerStorage) - 1] == _T('\\')) {
  34. g_szLayerStorage[lstrlen(g_szLayerStorage) - 1] = 0;
  35. }
  36. StringCchCat(g_szLayerStorage, ARRAYSIZE(g_szLayerStorage), _T("\\AppPatch\\LayerStorage.dat"));
  37. if (bDelete) {
  38. DeleteFile(g_szLayerStorage);
  39. }
  40. }
  41. //////////////////////////////////////////////////////////////////////////
  42. // CheckForRights
  43. //
  44. #define APPCOMPAT_KEY _T("System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility")
  45. #define APPCOMPAT_TEST_SUBKEY _T("12181969-7036745")
  46. void
  47. CheckForRights(
  48. void
  49. )
  50. {
  51. HKEY hkey = NULL, hkeyTest = NULL;
  52. LONG lRes;
  53. g_bExtEnabled = FALSE;
  54. lRes = RegOpenKey(HKEY_LOCAL_MACHINE, APPCOMPAT_KEY, &hkey);
  55. if (lRes != ERROR_SUCCESS) {
  56. LogMsg(_T("[CheckForRights] cannot open the appcompat key.\n")
  57. _T("The appcompat shell extension will be disabled\n"));
  58. return;
  59. }
  60. lRes = RegCreateKey(hkey, APPCOMPAT_TEST_SUBKEY, &hkeyTest);
  61. if (lRes != ERROR_SUCCESS) {
  62. LogMsg(_T("[CheckForRights] cannot create test registry key.\n")
  63. _T("The appcompat shell extension will be disabled\n"));
  64. goto cleanup;
  65. }
  66. RegCloseKey(hkeyTest);
  67. hkeyTest = NULL;
  68. lRes = RegDeleteKey(hkey, APPCOMPAT_TEST_SUBKEY);
  69. if (lRes != ERROR_SUCCESS) {
  70. LogMsg(_T("[CheckForRights] cannot delete test registry key.\n")
  71. _T("The appcompat shell extension will be disabled\n"));
  72. goto cleanup;
  73. }
  74. g_bExtEnabled = TRUE;
  75. cleanup:
  76. if (hkey != NULL) {
  77. RegCloseKey(hkey);
  78. }
  79. }
  80. //////////////////////////////////////////////////////////////////////////
  81. // CreateLayeredStorage
  82. //
  83. // Create the file for layer storage.
  84. void
  85. CreateLayeredStorage(
  86. LPWSTR pszItem,
  87. DWORD dwFlags
  88. )
  89. {
  90. HANDLE hFile;
  91. hFile = CreateFile(g_szLayerStorage,
  92. GENERIC_READ | GENERIC_WRITE,
  93. FILE_SHARE_READ | FILE_SHARE_WRITE,
  94. NULL,
  95. CREATE_NEW,
  96. 0,
  97. NULL);
  98. if (hFile == INVALID_HANDLE_VALUE) {
  99. LogMsg(_T("[CreateLayeredStorage] cannot create the storage file!\n"));
  100. return;
  101. }
  102. LayerStorageHeader Header;
  103. LayeredItem Item;
  104. Header.dwItemCount = 1;
  105. Header.dwMagic = LS_MAGIC;
  106. GetLocalTime(&Header.timeLast);
  107. ZeroMemory(&Item, sizeof(Item));
  108. Item.dwFlags = dwFlags;
  109. StringCchCopy(Item.szItemName, ARRAYSIZE(Item.szItemName), pszItem);
  110. DWORD dwBytesWritten = 0;
  111. WriteFile(hFile, &Header, sizeof(Header), &dwBytesWritten, NULL);
  112. WriteFile(hFile, &Item, sizeof(Item), &dwBytesWritten, NULL);
  113. LogMsg(_T("[CreateLayeredStorage] storage file \"%s\" initialized\n"),
  114. g_szLayerStorage);
  115. CloseHandle(hFile);
  116. }
  117. //////////////////////////////////////////////////////////////////////////
  118. // LayeredItemOperation
  119. //
  120. // Add/Delete/Query items in the layer storage
  121. void
  122. LayeredItemOperation(
  123. LPWSTR pszItem,
  124. DWORD dwOp,
  125. LPDWORD lpdwFlags
  126. )
  127. {
  128. LogMsg(_T("[LayeredItemOperation] op %d item \"%s\"\n"),
  129. dwOp, pszItem);
  130. HANDLE hFile = INVALID_HANDLE_VALUE;
  131. HANDLE hFileMapping = NULL;
  132. DWORD dwFileSize;
  133. PBYTE pData = NULL;
  134. PLayerStorageHeader pHeader = NULL;
  135. PLayeredItem pItems;
  136. PLayeredItem pCrtItem = NULL;
  137. int nLeft, nRight, nMid, nItem;
  138. BOOL bShrinkFile = FALSE;
  139. //
  140. // Make sure we don't corrupt the layer storage.
  141. //
  142. if (lstrlenW(pszItem) + 1 > MAX_PATH) {
  143. pszItem[MAX_PATH - 1] = 0;
  144. }
  145. hFile = CreateFile(g_szLayerStorage,
  146. GENERIC_READ | GENERIC_WRITE,
  147. FILE_SHARE_READ | FILE_SHARE_WRITE,
  148. NULL,
  149. OPEN_EXISTING,
  150. 0,
  151. NULL);
  152. if (hFile == INVALID_HANDLE_VALUE) {
  153. LogMsg(_T("[LayeredItemOperation] the layer storage doesn't exist\n"));
  154. if (dwOp == LIO_READITEM) {
  155. *lpdwFlags = 0;
  156. return;
  157. }
  158. if (dwOp == LIO_DELETEITEM) {
  159. LogMsg(_T("[LayeredItemOperation] cannot delete item\n"));
  160. return;
  161. }
  162. //
  163. // The file doesn't exist and the operation is LIO_ADDITEM.
  164. // Create the file, write the item and get out.
  165. //
  166. CreateLayeredStorage(pszItem, *lpdwFlags);
  167. return;
  168. }
  169. //
  170. // The file already exists. Create a file mapping that will allow
  171. // for adding/deleting/querying the item.
  172. //
  173. dwFileSize = GetFileSize(hFile, NULL);
  174. hFileMapping = CreateFileMapping(hFile,
  175. NULL,
  176. PAGE_READWRITE,
  177. 0,
  178. dwFileSize + (dwOp == LIO_ADDITEM ? sizeof(LayeredItem) : 0),
  179. NULL);
  180. if (hFileMapping == NULL) {
  181. LogMsg(_T("[LayeredItemOperation] CreateFileMapping failed 0x%X\n"),
  182. GetLastError());
  183. goto done;
  184. }
  185. pData = (PBYTE)MapViewOfFile(hFileMapping,
  186. FILE_MAP_READ | FILE_MAP_WRITE,
  187. 0,
  188. 0,
  189. 0);
  190. if (pData == NULL) {
  191. LogMsg(_T("[LayeredItemOperation] MapViewOfFile failed 0x%X\n"),
  192. GetLastError());
  193. goto done;
  194. }
  195. pHeader = (PLayerStorageHeader)pData;
  196. pItems = (PLayeredItem)(pData + sizeof(LayerStorageHeader));
  197. //
  198. // Make sure it's our file.
  199. //
  200. if (dwFileSize < sizeof(LayerStorageHeader) || pHeader->dwMagic != LS_MAGIC) {
  201. LogMsg(_T("[LayeredItemOperation] invalid file magic 0x%0X\n"),
  202. pHeader->dwMagic);
  203. goto done;
  204. }
  205. //
  206. // Get the last access time.
  207. //
  208. GetLocalTime(&pHeader->timeLast);
  209. //
  210. // First search for the item. The array is sorted so we do binary search.
  211. //
  212. nItem = -1, nLeft = 0, nRight = (int)pHeader->dwItemCount - 1;
  213. while (nLeft <= nRight) {
  214. int nVal;
  215. nMid = (nLeft + nRight) / 2;
  216. pCrtItem = pItems + nMid;
  217. nVal = lstrcmpi(pszItem, pCrtItem->szItemName);
  218. if (nVal == 0) {
  219. nItem = nMid;
  220. break;
  221. } else if (nVal < 0) {
  222. nRight = nMid - 1;
  223. } else {
  224. nLeft = nMid + 1;
  225. }
  226. }
  227. if (nItem == -1) {
  228. LogMsg(_T("[LayeredItemOperation] the item was not found in the file.\n"));
  229. if (dwOp == LIO_DELETEITEM) {
  230. goto done;
  231. }
  232. if (dwOp == LIO_READITEM) {
  233. *lpdwFlags = 0;
  234. goto done;
  235. }
  236. if (pHeader->dwItemCount == 0) {
  237. pCrtItem = pItems;
  238. } else {
  239. MoveMemory(pItems + nLeft + 1,
  240. pItems + nLeft,
  241. ((int)pHeader->dwItemCount - nLeft) * sizeof(LayeredItem));
  242. pCrtItem = pItems + nLeft;
  243. }
  244. ZeroMemory(pCrtItem, sizeof(LayeredItem));
  245. pCrtItem->dwFlags = *lpdwFlags;
  246. StringCchCopy(pCrtItem->szItemName, ARRAYSIZE(pCrtItem->szItemName), pszItem);
  247. (pHeader->dwItemCount)++;
  248. } else {
  249. //
  250. // The item is already in the file.
  251. //
  252. LogMsg(_T("[LayeredItemOperation] the item is in the file\n"));
  253. if (dwOp == LIO_READITEM) {
  254. *lpdwFlags = pCrtItem->dwFlags;
  255. goto done;
  256. }
  257. if (dwOp == LIO_DELETEITEM) {
  258. MoveMemory(pItems + nItem,
  259. pItems + nItem + 1,
  260. ((int)pHeader->dwItemCount - nItem - 1) * sizeof(LayeredItem));
  261. (pHeader->dwItemCount)--;
  262. } else {
  263. //
  264. // Update the item's flags.
  265. //
  266. pCrtItem->dwFlags = *lpdwFlags;
  267. }
  268. //
  269. // We've found the item so shrink the file by one item.
  270. //
  271. bShrinkFile = TRUE;
  272. }
  273. done:
  274. if (pData != NULL) {
  275. UnmapViewOfFile(pData);
  276. }
  277. if (hFileMapping != NULL) {
  278. CloseHandle(hFileMapping);
  279. }
  280. if (bShrinkFile) {
  281. SetFilePointer(hFile, - (int)sizeof(LayeredItem), NULL, FILE_END);
  282. SetEndOfFile(hFile);
  283. }
  284. if (hFile != INVALID_HANDLE_VALUE) {
  285. CloseHandle(hFile);
  286. }
  287. }
  288. //////////////////////////////////////////////////////////////////////////
  289. // LayerSelection
  290. //
  291. // The user changed the selection in the combo-box with the layers.
  292. // Persist the user's selection to the layer storage.
  293. void
  294. LayerSelection(
  295. HWND hdlg,
  296. LPWSTR pszItem
  297. )
  298. {
  299. //
  300. // See which layer is selected.
  301. //
  302. LPARAM lSel = SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_GETCURSEL, 0, 0);
  303. if (lSel == CB_ERR) {
  304. LogMsg(_T("[LayerSelection] couldn't get the current selection\n"));
  305. } else {
  306. DWORD dwFlags;
  307. switch (lSel) {
  308. case 0:
  309. dwFlags = LI_WIN95;
  310. break;
  311. case 1:
  312. dwFlags = LI_WIN98;
  313. break;
  314. case 2:
  315. dwFlags = LI_NT4;
  316. break;
  317. default:
  318. LogMsg(_T("[LayerSelection] bad selection. default to Win9x\n"));
  319. dwFlags = LI_WIN95;
  320. break;
  321. }
  322. LayeredItemOperation(pszItem, LIO_ADDITEM, &dwFlags);
  323. }
  324. }
  325. //////////////////////////////////////////////////////////////////////////
  326. // LayerPageDlgProc
  327. //
  328. // The dialog proc for the layer property page.
  329. INT_PTR CALLBACK
  330. LayerPageDlgProc(
  331. HWND hdlg,
  332. UINT uMsg,
  333. WPARAM wParam,
  334. LPARAM lParam)
  335. {
  336. int wCode = LOWORD(wParam);
  337. int wNotifyCode = HIWORD(wParam);
  338. switch (uMsg) {
  339. case WM_INITDIALOG:
  340. {
  341. PROPSHEETPAGE* ppsp = (PROPSHEETPAGE*)lParam;
  342. DWORD dwFlags = 0;
  343. CLayerUIPropPage* pPropPage = (CLayerUIPropPage*)ppsp->lParam;
  344. LogMsg(_T("[LayerPageDlgProc] WM_INITDIALOG - item \"%s\"\n"),
  345. pPropPage->m_szFile);
  346. //
  347. // Store the name of the EXE/LNK in the dialog.
  348. //
  349. SetWindowLong(hdlg, GWL_USERDATA, (LPARAM)pPropPage->m_szFile);
  350. //
  351. // Add the names of the layers.
  352. //
  353. SendDlgItemMessage(hdlg,
  354. IDC_LAYER_NAME,
  355. CB_ADDSTRING,
  356. 0,
  357. (LPARAM)_T("Windows 95 Compatibility Layer"));
  358. SendDlgItemMessage(hdlg,
  359. IDC_LAYER_NAME,
  360. CB_ADDSTRING,
  361. 0,
  362. (LPARAM)_T("Windows 98 Compatibility Layer"));
  363. SendDlgItemMessage(hdlg,
  364. IDC_LAYER_NAME,
  365. CB_ADDSTRING,
  366. 0,
  367. (LPARAM)_T("Windows NT4 SP5 Compatibility Layer"));
  368. //
  369. // Read the layer storage for info on this item.
  370. //
  371. LayeredItemOperation(pPropPage->m_szFile, LIO_READITEM, &dwFlags);
  372. //
  373. // Select the appropriate layer for this item. If no info
  374. // is available in the layer store, default to the Win9x layer.
  375. //
  376. BOOL bEnable;
  377. switch (dwFlags) {
  378. case LI_WIN95:
  379. SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 0, 0);
  380. bEnable = TRUE;
  381. break;
  382. case LI_WIN98:
  383. SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 1, 0);
  384. bEnable = TRUE;
  385. break;
  386. case LI_NT4:
  387. SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 2, 0);
  388. bEnable = TRUE;
  389. break;
  390. default:
  391. SendDlgItemMessage(hdlg, IDC_LAYER_NAME, CB_SETCURSEL, 0, 0);
  392. bEnable = FALSE;
  393. }
  394. if (bEnable) {
  395. EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), TRUE);
  396. SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_SETCHECK, BST_CHECKED, 0);
  397. }
  398. break;
  399. }
  400. case WM_COMMAND:
  401. {
  402. LPWSTR pszItem;
  403. pszItem = (LPTSTR)GetWindowLong(hdlg, GWL_USERDATA);
  404. switch (wNotifyCode) {
  405. case CBN_SELCHANGE:
  406. LayerSelection(hdlg, pszItem);
  407. return TRUE;
  408. }
  409. switch (wCode) {
  410. case IDC_USE_LAYER:
  411. if (SendDlgItemMessage(hdlg, IDC_USE_LAYER, BM_GETCHECK, 0, 0) == BST_CHECKED) {
  412. EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), TRUE);
  413. LayerSelection(hdlg, pszItem);
  414. } else {
  415. EnableWindow(GetDlgItem(hdlg, IDC_LAYER_NAME), FALSE);
  416. LayeredItemOperation(pszItem, LIO_DELETEITEM, NULL);
  417. }
  418. break;
  419. default:
  420. return FALSE;
  421. }
  422. break;
  423. }
  424. default:
  425. return FALSE;
  426. }
  427. return TRUE;
  428. }
  429. //////////////////////////////////////////////////////////////////////////
  430. // LayerPageCallbackProc
  431. //
  432. // The callback for the property page.
  433. UINT CALLBACK
  434. LayerPageCallbackProc(
  435. HWND hwnd,
  436. UINT uMsg,
  437. LPPROPSHEETPAGE ppsp
  438. )
  439. {
  440. switch (uMsg) {
  441. case PSPCB_RELEASE:
  442. if (ppsp->lParam != 0) {
  443. CLayerUIPropPage* pPropPage = (CLayerUIPropPage*)(ppsp->lParam);
  444. LogMsg(_T("[LayerPageCallbackProc] releasing CLayerUIPropPage\n"));
  445. pPropPage->Release();
  446. }
  447. break;
  448. }
  449. return 1;
  450. }
  451. BOOL
  452. GetExeFromLnk(
  453. TCHAR* pszLnk,
  454. TCHAR* pszExe,
  455. int cchSize
  456. )
  457. {
  458. HRESULT hres;
  459. IShellLink* psl = NULL;
  460. IPersistFile* pPf = NULL;
  461. WIN32_FIND_DATA wfd;
  462. TCHAR szArg[MAX_PATH];
  463. BOOL bSuccess = FALSE;
  464. IShellLinkDataList* psldl = NULL;
  465. EXP_DARWIN_LINK* pexpDarwin = NULL;
  466. hres = CoCreateInstance(CLSID_ShellLink,
  467. NULL,
  468. CLSCTX_INPROC_SERVER,
  469. IID_IShellLink,
  470. (LPVOID*)&psl);
  471. if (FAILED(hres)) {
  472. LogMsg(_T("[GetExeFromLnk] CoCreateInstance failed\n"));
  473. return FALSE;
  474. }
  475. hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&pPf);
  476. if (FAILED(hres)) {
  477. LogMsg(_T("[GetExeFromLnk] QueryInterface for IPersistFile failed\n"));
  478. goto cleanup;
  479. }
  480. //
  481. // Load the link file.
  482. //
  483. hres = pPf->Load(pszLnk, STGM_READ);
  484. if (FAILED(hres)) {
  485. LogMsg(_T("[GetExeFromLnk] failed to load link \"%s\"\n"),
  486. pszLnk);
  487. goto cleanup;
  488. }
  489. //
  490. // See if this is a DARWIN link.
  491. //
  492. hres = psl->QueryInterface(IID_IShellLinkDataList, (LPVOID*)&psldl);
  493. if (FAILED(hres)) {
  494. LogMsg(_T("[GetExeFromLnk] failed to get IShellLinkDataList.\n"));
  495. } else {
  496. hres = psldl->CopyDataBlock(EXP_DARWIN_ID_SIG, (void**)&pexpDarwin);
  497. if (SUCCEEDED(hres)) {
  498. LogMsg(_T("[GetExeFromLnk] this is a DARWIN link \"%s\".\n"),
  499. pszLnk);
  500. goto cleanup;
  501. }
  502. }
  503. //
  504. // Resolve the link.
  505. //
  506. hres = psl->Resolve(NULL,
  507. SLR_NOTRACK | SLR_NOSEARCH | SLR_NO_UI | SLR_NOUPDATE);
  508. if (FAILED(hres)) {
  509. LogMsg(_T("[GetExeFromLnk] failed to resolve the link \"%s\"\n"),
  510. pszLnk);
  511. goto cleanup;
  512. }
  513. pszExe[0] = _T('\"');
  514. //
  515. // Get the path to the link target.
  516. //
  517. hres = psl->GetPath(pszExe + 1,
  518. cchSize,
  519. &wfd,
  520. SLGP_UNCPRIORITY);
  521. if (FAILED(hres)) {
  522. LogMsg(_T("[GetExeFromLnk] failed to get the path for link \"%s\"\n"),
  523. pszLnk);
  524. goto cleanup;
  525. }
  526. szArg[0] = 0;
  527. hres = psl->GetArguments(szArg, MAX_PATH);
  528. if (SUCCEEDED(hres) && szArg[0] != 0) {
  529. StringCchCat(pszExe, cchSize, _T("\" "));
  530. StringCchCat(pszExe, cchSize, szArg);
  531. } else {
  532. StringCchCat(pszExe, cchSize, _T("\""));
  533. }
  534. bSuccess = TRUE;
  535. cleanup:
  536. if (pPf != NULL) {
  537. pPf->Release();
  538. }
  539. if (psl) {
  540. psl->Release();
  541. }
  542. if (psldl) {
  543. psldl->Release();
  544. }
  545. if (pexpDarwin) {
  546. LocalFree(pexpDarwin);
  547. }
  548. return bSuccess;
  549. }
  550. //////////////////////////////////////////////////////////////////////////
  551. // CLayerUIPropPage
  552. CLayerUIPropPage::CLayerUIPropPage()
  553. {
  554. LogMsg(_T("[CLayerUIPropPage::CLayerUIPropPage]\n"));
  555. }
  556. CLayerUIPropPage::~CLayerUIPropPage()
  557. {
  558. LogMsg(_T("[CLayerUIPropPage::~CLayerUIPropPage]\n"));
  559. }
  560. //////////////////////////////////////////////////////////////////////////
  561. // IShellExtInit methods
  562. STDMETHODIMP
  563. CLayerUIPropPage::Initialize(
  564. LPCITEMIDLIST pIDFolder,
  565. LPDATAOBJECT pDataObj,
  566. HKEY hKeyID
  567. )
  568. {
  569. LogMsg(_T("[CLayerUIPropPage::Initialize]\n"));
  570. if (!g_bExtEnabled) {
  571. return NOERROR;
  572. }
  573. if (pDataObj == NULL) {
  574. LogMsg(_T("\t failed. bad argument.\n"));
  575. return E_INVALIDARG;
  576. }
  577. //
  578. // Store a pointer to the data object
  579. //
  580. m_spDataObj = pDataObj;
  581. //
  582. // If a data object pointer was passed in, save it and
  583. // extract the file name.
  584. //
  585. STGMEDIUM medium;
  586. UINT uCount;
  587. FORMATETC fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1,
  588. TYMED_HGLOBAL};
  589. if (SUCCEEDED(m_spDataObj->GetData(&fe, &medium))) {
  590. //
  591. // Get the file name from the CF_HDROP.
  592. //
  593. uCount = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1,
  594. NULL, 0);
  595. if (uCount > 0) {
  596. TCHAR szExe[MAX_PATH];
  597. DragQueryFile((HDROP)medium.hGlobal, 0, szExe,
  598. ARRAYSIZE(szExe));
  599. LogMsg(_T("\tlink \"%s\".\n"), szExe);
  600. if (!GetExeFromLnk(szExe, m_szFile, ARRAYSIZE(m_szFile))) {
  601. m_szFile[0] = 0;
  602. }
  603. LogMsg(_T("\tfile \"%s\".\n"), m_szFile);
  604. }
  605. ReleaseStgMedium(&medium);
  606. } else {
  607. LogMsg(_T("\t failed to get the data.\n"));
  608. }
  609. return NOERROR;
  610. }
  611. //////////////////////////////////////////////////////////////////////////
  612. // IShellPropSheetExt methods
  613. STDMETHODIMP
  614. CLayerUIPropPage::AddPages(
  615. LPFNADDPROPSHEETPAGE lpfnAddPage,
  616. LPARAM lParam
  617. )
  618. {
  619. PROPSHEETPAGE psp;
  620. HPROPSHEETPAGE hPage;
  621. LogMsg(_T("[CLayerUIPropPage::AddPages]\n"));
  622. if (!g_bExtEnabled || m_szFile[0] == 0) {
  623. return S_OK;
  624. }
  625. psp.dwSize = sizeof(psp);
  626. psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
  627. psp.hInstance = _Module.m_hInst;
  628. psp.pszTemplate = MAKEINTRESOURCE(IDD_LAYER_PROPPAGE);
  629. psp.hIcon = 0;
  630. psp.pszTitle = _T("Compatibility");
  631. psp.pfnDlgProc = LayerPageDlgProc;
  632. psp.pcRefParent = &g_DllRefCount;
  633. psp.pfnCallback = LayerPageCallbackProc;
  634. psp.lParam = (LPARAM)this;
  635. LogMsg(_T("\titem \"%s\".\n"), m_szFile);
  636. LogMsg(_T("\tg_DllRefCount %d.\n"), g_DllRefCount);
  637. AddRef();
  638. hPage = CreatePropertySheetPage(&psp);
  639. if (hPage != NULL) {
  640. if (lpfnAddPage(hPage, lParam)) {
  641. return S_OK;
  642. } else {
  643. DestroyPropertySheetPage(hPage);
  644. Release();
  645. return S_OK;
  646. }
  647. } else {
  648. return E_OUTOFMEMORY;
  649. }
  650. return E_FAIL;
  651. }
  652. STDMETHODIMP
  653. CLayerUIPropPage::ReplacePage(
  654. UINT uPageID,
  655. LPFNADDPROPSHEETPAGE lpfnReplacePage,
  656. LPARAM lParam
  657. )
  658. {
  659. LogMsg(_T("[CLayerUIPropPage::ReplacePage]\n"));
  660. return S_OK;
  661. }