Source code of Windows XP (NT5)
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.

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