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.

1447 lines
42 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "control.h"
  4. HDSA g_hacplmLoaded = NULL;
  5. void ConvertCplInfo(void * lpv)
  6. {
  7. NEWCPLINFOA CplInfoA;
  8. LPNEWCPLINFOW lpCplInfoW = (LPNEWCPLINFOW)lpv;
  9. memcpy(&CplInfoA, lpv, sizeof(CplInfoA));
  10. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  11. CplInfoA.szName, ARRAYSIZE(CplInfoA.szName),
  12. lpCplInfoW->szName, ARRAYSIZE(lpCplInfoW->szName));
  13. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  14. CplInfoA.szInfo, ARRAYSIZE(CplInfoA.szInfo),
  15. lpCplInfoW->szInfo, ARRAYSIZE(lpCplInfoW->szInfo));
  16. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  17. CplInfoA.szHelpFile, ARRAYSIZE(CplInfoA.szHelpFile),
  18. lpCplInfoW->szHelpFile, ARRAYSIZE(lpCplInfoW->szHelpFile));
  19. lpCplInfoW->dwSize = sizeof(NEWCPLINFOW);
  20. }
  21. // See if pszShort is a truncated version of the string referred to by
  22. // hinst/id. If so, then use the long string. This is to work around
  23. // a "bad design feature" of CPL_NEWINQUIRE where the app returns a buffer
  24. // (which is only 32 or 64 chars long) rather than a resource id
  25. // like CPL_INQUIRE. So if the app responds to both messages, and the
  26. // NEWINQUIRE string is a truncated version of the INQUIRE string, then
  27. // switch to the INQUIRE string.
  28. LPTSTR _RestoreTruncatedCplString(
  29. HINSTANCE hinst,
  30. int id,
  31. LPTSTR pszShort,
  32. LPTSTR pszBuf,
  33. int cchBufMax)
  34. {
  35. int cchLenShort, cchLen;
  36. cchLenShort = lstrlen(pszShort);
  37. cchLen = LoadString(hinst, id, pszBuf, cchBufMax);
  38. // Don't use SHTruncateString since KERNEL32 doesn't either
  39. if (StrCmpNC(pszShort, pszBuf, cchLenShort) == 0)
  40. {
  41. pszShort = pszBuf;
  42. }
  43. return pszShort;
  44. }
  45. //
  46. // Initializes *pcpli.
  47. //
  48. // Requires:
  49. // *pcpli is filled with 0 & NULL's.
  50. //
  51. BOOL _InitializeControl(LPCPLMODULE pcplm, LPCPLITEM pcpli)
  52. {
  53. BOOL fSucceed = TRUE;
  54. union {
  55. NEWCPLINFO Native;
  56. NEWCPLINFOA NewCplInfoA;
  57. NEWCPLINFOW NewCplInfoW;
  58. } Newcpl;
  59. CPLINFO cpl;
  60. TCHAR szName[MAX_CCH_CPLNAME];
  61. TCHAR szInfo[MAX_CCH_CPLINFO];
  62. LPTSTR pszName = Newcpl.Native.szName, pszInfo = Newcpl.Native.szInfo;
  63. HICON hIconTemp = NULL;
  64. //
  65. // always do the old method to get the icon ID
  66. //
  67. cpl.idIcon = 0;
  68. CPL_CallEntry(pcplm, NULL, CPL_INQUIRE, (LONG)pcpli->idControl, (LONG_PTR)(LPCPLINFO)&cpl);
  69. //
  70. // if this is a 32bit CPL and it gave us an ID then validate it
  71. // this fixes ODBC32 which gives back a bogus ID but a correct HICON
  72. // note that the next load of the same icon should be very fast
  73. //
  74. if (cpl.idIcon)
  75. {
  76. hIconTemp = LoadImage(pcplm->minst.hinst, MAKEINTRESOURCE(cpl.idIcon),
  77. IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
  78. if (!hIconTemp)
  79. {
  80. // the id was bogus, make it a negative number (invalid resource)...
  81. cpl.idIcon = -1;
  82. TraceMsg(TF_GENERAL, "_InitializaControl: %s returned an invalid icon id, ignoring", pcplm->szModule);
  83. }
  84. }
  85. pcpli->idIcon = cpl.idIcon;
  86. //
  87. // Try the new method first and call it with the largest structure
  88. // so it doesn't overwrite anything on the stack. If you put a
  89. // Unicode applet on Windows '95 it will kill the Explorer because
  90. // it trashes memory by overwriting the stack.
  91. //
  92. memset(&Newcpl,0,sizeof(Newcpl));
  93. CPL_CallEntry(pcplm, NULL, CPL_NEWINQUIRE, (LONG)pcpli->idControl,
  94. (LONG_PTR)(LPCPLINFO)&Newcpl);
  95. //
  96. // If the call is to an ANSI applet, convert strings to Unicode
  97. //
  98. // I'm leaving this ANSI-only code as it helps explain
  99. // the way some of the subsequent code works - or why it was
  100. // written the way it was. [brianau - 03/07/02]
  101. //
  102. #ifdef UNICODE
  103. #define UNNATIVE_SIZE sizeof(NEWCPLINFOA)
  104. #else
  105. #define UNNATIVE_SIZE sizeof(NEWCPLINFOW)
  106. #endif
  107. if (Newcpl.Native.dwSize == UNNATIVE_SIZE)
  108. {
  109. ConvertCplInfo(&Newcpl); // This will set Newcpl.Native.dwSize
  110. }
  111. if (Newcpl.Native.dwSize == sizeof(NEWCPLINFO))
  112. {
  113. pszName = _RestoreTruncatedCplString(pcplm->minst.hinst, cpl.idName, pszName, szName, ARRAYSIZE(szName));
  114. pszInfo = _RestoreTruncatedCplString(pcplm->minst.hinst, cpl.idInfo, pszInfo, szInfo, ARRAYSIZE(szInfo));
  115. }
  116. else
  117. {
  118. Newcpl.Native.hIcon = LoadImage(pcplm->minst.hinst, MAKEINTRESOURCE(cpl.idIcon), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
  119. pszName = szName;
  120. LoadString(pcplm->minst.hinst, cpl.idName, szName, ARRAYSIZE(szName));
  121. pszInfo = szInfo;
  122. LoadString(pcplm->minst.hinst, cpl.idInfo, szInfo, ARRAYSIZE(szInfo));
  123. Newcpl.Native.szHelpFile[0] = 0;
  124. Newcpl.Native.lData = cpl.lData;
  125. Newcpl.Native.dwHelpContext = 0;
  126. }
  127. pcpli->hIcon = Newcpl.Native.hIcon;
  128. if (hIconTemp)
  129. DestroyIcon(hIconTemp);
  130. fSucceed = Str_SetPtr(&pcpli->pszName, pszName)
  131. && Str_SetPtr(&pcpli->pszInfo, pszInfo)
  132. && Str_SetPtr(&pcpli->pszHelpFile, Newcpl.Native.szHelpFile);
  133. pcpli->lData = Newcpl.Native.lData;
  134. pcpli->dwContext = Newcpl.Native.dwHelpContext;
  135. #ifdef DEBUG
  136. if (!pcpli->idIcon)
  137. TraceMsg(TF_GENERAL, "PERFORMANCE: cannot cache %s because no icon ID for <%s>", pcplm->szModule, pcpli->pszName);
  138. #endif
  139. return fSucceed;
  140. }
  141. //
  142. // Terminate the control
  143. //
  144. void _TerminateControl(LPCPLMODULE pcplm, LPCPLITEM pcpli)
  145. {
  146. if (pcpli->hIcon)
  147. {
  148. DestroyIcon(pcpli->hIcon);
  149. pcpli->hIcon = NULL;
  150. }
  151. Str_SetPtr(&pcpli->pszName, NULL);
  152. Str_SetPtr(&pcpli->pszInfo, NULL);
  153. Str_SetPtr(&pcpli->pszHelpFile, NULL);
  154. CPL_CallEntry(pcplm, NULL, CPL_STOP, pcpli->idControl, pcpli->lData);
  155. }
  156. void _FreeLibraryForControlPanel(MINST *pminst)
  157. {
  158. FreeLibrary(pminst->hinst);
  159. }
  160. //
  161. // For each control of the specified CPL module, call the control entry
  162. // with CPL_STOP. Then, call it with CPL_EXIT.
  163. //
  164. void _TerminateCPLModule(LPCPLMODULE pcplm)
  165. {
  166. if (pcplm->minst.hinst)
  167. {
  168. ULONG_PTR dwCookie = 0;
  169. if (pcplm->lpfnCPL)
  170. {
  171. if (pcplm->hacpli)
  172. {
  173. int cControls, i;
  174. for (i = 0, cControls = DSA_GetItemCount(pcplm->hacpli); i < cControls; ++i)
  175. {
  176. LPCPLITEM pcpli = DSA_GetItemPtr(pcplm->hacpli, i);
  177. _TerminateControl(pcplm, pcpli);
  178. }
  179. DSA_DeleteAllItems(pcplm->hacpli);
  180. DSA_Destroy(pcplm->hacpli);
  181. pcplm->hacpli=NULL;
  182. }
  183. CPL_CallEntry(pcplm, NULL, CPL_EXIT, 0, 0);
  184. pcplm->lpfnCPL=NULL;
  185. }
  186. ActivateActCtx(pcplm->hActCtx, &dwCookie);
  187. _FreeLibraryForControlPanel(&pcplm->minst);
  188. if (dwCookie != 0)
  189. DeactivateActCtx(0, dwCookie);
  190. pcplm->minst.hinst = NULL;
  191. }
  192. pcplm->minst.idOwner = (DWORD)-1;
  193. if (pcplm->hActCtx != NULL)
  194. {
  195. ReleaseActCtx(pcplm->hActCtx);
  196. pcplm->hActCtx = NULL;
  197. }
  198. if (pcplm->minst.hOwner)
  199. {
  200. CloseHandle(pcplm->minst.hOwner);
  201. pcplm->minst.hOwner = NULL;
  202. }
  203. }
  204. //
  205. // Initializes the CPL Module.
  206. //
  207. // Requires:
  208. // *pcplm should be initialized appropriately.
  209. //
  210. //
  211. BOOL _InitializeCPLModule(LPCPLMODULE pcplm)
  212. {
  213. BOOL fSuccess = FALSE;
  214. pcplm->lpfnCPL32 = (APPLET_PROC)GetProcAddress(pcplm->minst.hinst, "CPlApplet");
  215. //
  216. // Initialize the CPL
  217. if (pcplm->lpfnCPL &&
  218. CPL_CallEntry(pcplm, NULL, CPL_INIT, 0, 0))
  219. {
  220. int cControls = (int)CPL_CallEntry(pcplm, NULL, CPL_GETCOUNT, 0, 0);
  221. if (cControls>0)
  222. {
  223. //
  224. // By passing in the number of applets, we should speed up allocation
  225. // of this array.
  226. //
  227. pcplm->hacpli = DSA_Create(sizeof(CPLITEM), cControls);
  228. if (pcplm->hacpli)
  229. {
  230. int i;
  231. fSuccess = TRUE; // succeded, so far.
  232. // Go through the applets and load the information about them
  233. for (i = 0; i < cControls; ++i)
  234. {
  235. CPLITEM control = {i, 0};
  236. if (_InitializeControl(pcplm, &control))
  237. {
  238. // removing this now saves us from doing it later
  239. CPL_StripAmpersand(control.pszName);
  240. if (DSA_AppendItem(pcplm->hacpli, &control) >= 0)
  241. {
  242. continue;
  243. }
  244. }
  245. _TerminateControl(pcplm, &control);
  246. fSuccess=FALSE;
  247. break;
  248. }
  249. }
  250. }
  251. }
  252. else
  253. {
  254. // don't ever call it again if we couldn't CPL_INIT
  255. pcplm->lpfnCPL = NULL;
  256. }
  257. return fSuccess;
  258. }
  259. //
  260. // Returns:
  261. // The index to the g_hacplmLoaded, if the specified DLL is already
  262. // loaded; -1 otherwise.
  263. //
  264. int _FindCPLModule(const MINST * pminst)
  265. {
  266. int i = -1; // Assumes error
  267. ENTERCRITICAL;
  268. if (g_hacplmLoaded)
  269. {
  270. for (i=DSA_GetItemCount(g_hacplmLoaded)-1; i>=0; --i)
  271. {
  272. LPCPLMODULE pcplm = DSA_GetItemPtr(g_hacplmLoaded, i);
  273. //
  274. // owner id tested last since hinst is more varied
  275. //
  276. if ((pcplm->minst.hinst == pminst->hinst) &&
  277. (pcplm->minst.idOwner == pminst->idOwner))
  278. {
  279. break;
  280. }
  281. }
  282. }
  283. LEAVECRITICAL;
  284. return i;
  285. }
  286. LPCPLMODULE FindCPLModule(const MINST * pminst)
  287. {
  288. return (LPCPLMODULE) DSA_GetItemPtr(g_hacplmLoaded, _FindCPLModule(pminst));
  289. }
  290. //
  291. // Adds the specified CPL module to g_hacplmLoaded.
  292. //
  293. // Requires:
  294. // The specified CPL module is not in g_hacplmLoaded yet.
  295. //
  296. // Returns:
  297. // The index to the CPL module if succeeded; -1 otherwise.
  298. //
  299. int _AddModule(LPCPLMODULE pcplm)
  300. {
  301. int result;
  302. //
  303. // Create the Loaded Modules guy if necessary
  304. //
  305. ENTERCRITICAL;
  306. if (g_hacplmLoaded == NULL)
  307. g_hacplmLoaded = DSA_Create(sizeof(CPLMODULE), 4);
  308. //
  309. // Add this CPL to our list
  310. //
  311. if (g_hacplmLoaded == NULL)
  312. result = -1;
  313. else
  314. result = DSA_AppendItem(g_hacplmLoaded, pcplm);
  315. LEAVECRITICAL;
  316. return(result);
  317. }
  318. #define SZ_RUNDLL32_NOEXCEPT_ARGS TEXT("/d ")
  319. BOOL CatchCPLExceptions(UINT msg)
  320. {
  321. LPCTSTR pszCmdLine = GetCommandLine();
  322. BOOL fCatch = TRUE;
  323. // Some callers don't want to run and have exceptions caught.
  324. // This will allow crashes to be uploaded to PCHealth.
  325. if (((CPL_STARTWPARMSA == msg) || (CPL_STARTWPARMS == msg) || (CPL_DBLCLK == msg)) &&
  326. StrCmpNI(pszCmdLine, SZ_RUNDLL32_NOEXCEPT_ARGS, (ARRAYSIZE(SZ_RUNDLL32_NOEXCEPT_ARGS) - 1)))
  327. {
  328. fCatch = FALSE;
  329. }
  330. return fCatch;
  331. }
  332. LRESULT CPL_CallEntry(LPCPLMODULE pcplm, HWND hwnd, UINT msg, LPARAM lParam1, LPARAM lParam2)
  333. {
  334. LRESULT lres;
  335. ULONG_PTR dwCookie = 0;
  336. ActivateActCtx(pcplm->hActCtx, &dwCookie);
  337. if (!CatchCPLExceptions(msg))
  338. {
  339. lres = pcplm->lpfnCPL32(hwnd, msg, lParam1, lParam2);
  340. }
  341. else
  342. {
  343. __try
  344. {
  345. lres = pcplm->lpfnCPL32(hwnd, msg, lParam1, lParam2);
  346. }
  347. __except(SetErrorMode(SEM_NOGPFAULTERRORBOX),UnhandledExceptionFilter(GetExceptionInformation()))
  348. {
  349. TraceMsg(TF_ERROR, "CPL: Exception calling CPL module: %s", pcplm->szModule);
  350. ShellMessageBox(HINST_THISDLL, NULL, MAKEINTRESOURCE(IDS_CPL_EXCEPTION),
  351. MAKEINTRESOURCE(IDS_CONTROLPANEL),
  352. MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL,
  353. (LPTSTR)pcplm->szModule);
  354. lres = 0;
  355. }
  356. }
  357. if (dwCookie != 0)
  358. DeactivateActCtx(0, dwCookie);
  359. return lres;
  360. }
  361. EXTERN_C DECLSPEC_IMPORT BOOL STDAPICALLTYPE
  362. ApphelpCheckExe(
  363. LPCWSTR lpApplicationName,
  364. BOOL bApphelp,
  365. BOOL bShim,
  366. BOOL bUseModuleName
  367. );
  368. //
  369. // Loads the specified CPL module and returns the index to g_hacplmLoaded.
  370. //
  371. int _LoadCPLModule(LPCTSTR pszModule)
  372. {
  373. TCHAR szManifest[MAX_PATH];
  374. HANDLE hActCtx = NULL;
  375. MINST minst;
  376. int iModule;
  377. ULONG_PTR dwCookie;
  378. ACTCTX act = {0};
  379. #ifndef UNICODE
  380. WCHAR wszModuleName[MAX_PATH];
  381. #endif
  382. LPWSTR pwszModuleName = NULL;
  383. if (FAILED(StringCchPrintf(szManifest, ARRAYSIZE(szManifest), TEXT("%s.manifest"), pszModule)))
  384. {
  385. return -1;
  386. }
  387. minst.idOwner = GetCurrentProcessId();
  388. minst.hOwner = OpenProcess(SYNCHRONIZE,FALSE,minst.idOwner);
  389. if (NULL == minst.hOwner)
  390. {
  391. return -1;
  392. }
  393. // See if this application has a context
  394. if (PathFileExists(szManifest))
  395. {
  396. act.cbSize = sizeof(act);
  397. act.dwFlags = 0;
  398. act.lpSource = szManifest;
  399. hActCtx = CreateActCtx(&act);
  400. }
  401. else
  402. {
  403. act.cbSize = sizeof(act);
  404. act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
  405. act.lpSource = pszModule;
  406. act.lpResourceName = MAKEINTRESOURCE(123);
  407. hActCtx = CreateActCtx(&act);
  408. }
  409. if (hActCtx == INVALID_HANDLE_VALUE)
  410. hActCtx = NULL;
  411. ActivateActCtx(hActCtx, &dwCookie);
  412. //
  413. // check and [possibly] fix this module
  414. //
  415. #ifdef UNICODE
  416. pwszModuleName = (LPWSTR)pszModule;
  417. #else // if !defined(UNICODE)
  418. if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  419. pszModule, -1,
  420. wszModuleName, ARRAYSIZE(wszModuleName)) != 0) {
  421. pwszModuleName = wszModuleName;
  422. }
  423. #endif // UNICODE
  424. if (!ApphelpCheckExe(pwszModuleName, TRUE, TRUE, TRUE)) {
  425. minst.hinst = NULL;
  426. } else {
  427. minst.hinst = LoadLibrary(pszModule);
  428. }
  429. if (dwCookie != 0)
  430. DeactivateActCtx(0, dwCookie);
  431. if (!ISVALIDHINSTANCE(minst.hinst))
  432. {
  433. if (hActCtx != NULL) {
  434. ReleaseActCtx(hActCtx);
  435. }
  436. CloseHandle(minst.hOwner);
  437. return -1;
  438. }
  439. //
  440. // Check if this module is already in the list.
  441. //
  442. iModule = _FindCPLModule(&minst);
  443. if (iModule >= 0)
  444. {
  445. //
  446. // Yes. Increment the reference count and return the ID.
  447. //
  448. LPCPLMODULE pcplm;
  449. ENTERCRITICAL;
  450. pcplm = DSA_GetItemPtr(g_hacplmLoaded, iModule);
  451. ++pcplm->cRef;
  452. LEAVECRITICAL;
  453. ActivateActCtx(hActCtx, &dwCookie);
  454. //
  455. // Decrement KERNELs reference count
  456. //
  457. _FreeLibraryForControlPanel(&minst);
  458. if (dwCookie != 0)
  459. DeactivateActCtx(0, dwCookie);
  460. if (hActCtx != NULL)
  461. ReleaseActCtx(hActCtx);
  462. CloseHandle(minst.hOwner);
  463. }
  464. else
  465. {
  466. CPLMODULE sModule = {0};
  467. //
  468. // No. Append it.
  469. //
  470. sModule.cRef = 1;
  471. sModule.minst = minst;
  472. sModule.hActCtx = hActCtx;
  473. GetModuleFileName(minst.hinst, sModule.szModule, ARRAYSIZE(sModule.szModule));
  474. if (_InitializeCPLModule(&sModule))
  475. {
  476. iModule = _AddModule(&sModule);
  477. }
  478. if (iModule < 0)
  479. {
  480. _TerminateCPLModule(&sModule);
  481. }
  482. }
  483. return iModule;
  484. }
  485. int _FreeCPLModuleIndex(int iModule)
  486. {
  487. LPCPLMODULE pcplm;
  488. ENTERCRITICAL;
  489. pcplm = DSA_GetItemPtr(g_hacplmLoaded, iModule);
  490. if (!pcplm)
  491. {
  492. LEAVECRITICAL;
  493. return(-1);
  494. }
  495. //
  496. // Dec the ref count; return if not 0
  497. //
  498. --pcplm->cRef;
  499. if (pcplm->cRef)
  500. {
  501. LEAVECRITICAL;
  502. return(pcplm->cRef);
  503. }
  504. //
  505. // Free up the whole thing and return 0
  506. //
  507. _TerminateCPLModule(pcplm);
  508. DSA_DeleteItem(g_hacplmLoaded, iModule);
  509. //
  510. // Destroy this when all CPLs have been removed
  511. //
  512. if (DSA_GetItemCount(g_hacplmLoaded) == 0)
  513. {
  514. DSA_Destroy(g_hacplmLoaded);
  515. g_hacplmLoaded = NULL;
  516. }
  517. LEAVECRITICAL;
  518. return(0);
  519. }
  520. int _FreeCPLModuleHandle(const MINST * pminst)
  521. {
  522. int iModule;
  523. //
  524. // Check if the module is actually loaded (major error if not)
  525. //
  526. iModule = _FindCPLModule(pminst);
  527. if (iModule < 0)
  528. {
  529. return(-1);
  530. }
  531. return _FreeCPLModuleIndex(iModule);
  532. }
  533. int CPL_FreeCPLModule(LPCPLMODULE pcplm)
  534. {
  535. return _FreeCPLModuleHandle(&pcplm->minst);
  536. }
  537. void CPL_StripAmpersand(LPTSTR szBuffer)
  538. {
  539. LPTSTR pIn, pOut;
  540. //
  541. // copy the name sans '&' chars
  542. //
  543. pIn = pOut = szBuffer;
  544. do
  545. {
  546. //
  547. // strip FE accelerators with parentheses. e.g. "foo(&F)" -> "foo"
  548. //
  549. if (*pIn == TEXT('(') && *(pIn+1) == TEXT('&') &&
  550. *(pIn+2) && *(pIn+3) == TEXT(')')) {
  551. pIn += 4;
  552. }
  553. #ifdef DBCS
  554. // Also strip FE accelerators in old win31 cpl, i.e, 01EH/01FH.
  555. if (*pIn == 0x1e && *++pIn) {
  556. // Assumes a character right before the mnemonic
  557. // is a parenthesis or something to be removed as well.
  558. //
  559. pOut=CharPrev(szBuffer, pOut);
  560. // Skip Alphabet accelerator.
  561. pIn = CharNext(pIn);
  562. if (*pIn) {
  563. if (*pIn == 0x1f && *++pIn) {
  564. // Skip FE accelelator
  565. //
  566. pIn = CharNext(pIn);
  567. }
  568. // Skip second parenthesis.
  569. //
  570. pIn = CharNext(pIn);
  571. }
  572. }
  573. #endif
  574. if (*pIn != TEXT('&')) {
  575. *pOut++ = *pIn;
  576. }
  577. if (IsDBCSLeadByte(*pIn)) {
  578. *pOut++ = *++pIn;
  579. }
  580. } while (*pIn++) ;
  581. }
  582. //
  583. // filter out bogus old ini keys... we may be able to blow this off
  584. BOOL IsValidCplKey(LPCTSTR pszKey)
  585. {
  586. return lstrcmpi(pszKey, TEXT("NumApps")) &&
  587. !((*(pszKey+1) == 0) &&
  588. ((*pszKey == TEXT('X')) || (*pszKey == TEXT('Y')) || (*pszKey == TEXT('W')) || (*pszKey == TEXT('H'))));
  589. }
  590. LPCPLMODULE CPL_LoadCPLModule(LPCTSTR szModule)
  591. {
  592. LPCPLMODULE result;
  593. int iModule = _LoadCPLModule(szModule);
  594. if (iModule < 0)
  595. result = NULL;
  596. else
  597. {
  598. ENTERCRITICAL;
  599. result = DSA_GetItemPtr(g_hacplmLoaded, iModule);
  600. LEAVECRITICAL;
  601. }
  602. return result;
  603. }
  604. BOOL DontLoadCPL(LPCTSTR pszName)
  605. {
  606. // the first reg location is the old alias for control.ini [don't load]
  607. // entries that map into the registry on NT. the next is for per
  608. // machine support to hide cpls, new for whistler
  609. return (SHGetValue(HKEY_CURRENT_USER, TEXT("Control Panel\\don't load"), pszName, NULL, NULL, NULL) == ERROR_SUCCESS) ||
  610. (SHGetValue(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\don't load"), pszName, NULL, NULL, NULL) == ERROR_SUCCESS);
  611. }
  612. // Called for each CPL module file which we may want to load
  613. void _InsertModuleName(ControlData *lpData, LPCTSTR szPath, PMODULEINFO pmi)
  614. {
  615. pmi->pszModule = NULL;
  616. Str_SetPtr(&pmi->pszModule, szPath);
  617. if (pmi->pszModule)
  618. {
  619. int i;
  620. pmi->pszModuleName = PathFindFileName(pmi->pszModule);
  621. if (DontLoadCPL(pmi->pszModuleName))
  622. {
  623. Str_SetPtr(&pmi->pszModule, NULL);
  624. goto skip;
  625. }
  626. // don't insert the module if it's already in the list!
  627. for (i = DSA_GetItemCount(lpData->hamiModule)-1 ; i >= 0 ; i--)
  628. {
  629. PMODULEINFO pmi1 = DSA_GetItemPtr(lpData->hamiModule, i);
  630. if (!lstrcmpi(pmi1->pszModuleName, pmi->pszModuleName))
  631. {
  632. Str_SetPtr(&pmi->pszModule, NULL);
  633. goto skip;
  634. }
  635. }
  636. DSA_AppendItem(lpData->hamiModule, pmi);
  637. skip:
  638. ;
  639. }
  640. }
  641. #define GETMODULE(haminst,i) ((MINST *)DSA_GetItemPtr(haminst, i))
  642. #define ADDMODULE(haminst,pminst) DSA_AppendItem(haminst, (void *)pminst)
  643. int _LoadCPLModuleAndAdd(ControlData *lpData, LPCTSTR szModule)
  644. {
  645. int iModule, i;
  646. LPCPLMODULE pcplm;
  647. //
  648. // Load the module and controls (or get the previous one if already
  649. // loaded).
  650. //
  651. iModule = _LoadCPLModule(szModule);
  652. if (iModule < 0)
  653. {
  654. TraceMsg(TF_WARNING, "_LoadCPLModuleAndAdd: _LoadControls refused %s", szModule);
  655. return -1;
  656. }
  657. pcplm = DSA_GetItemPtr(g_hacplmLoaded, iModule);
  658. if (pcplm == NULL)
  659. {
  660. TraceMsg(TF_WARNING, "_LoadCPLModuleAndAdd: DSA returned NULL structure");
  661. return -1;
  662. }
  663. //
  664. // Check if this guy has already loaded this module
  665. //
  666. for (i = DSA_GetItemCount(lpData->haminst) - 1; i >= 0; --i)
  667. {
  668. const MINST * pminst = GETMODULE(lpData->haminst,i);
  669. //
  670. // note: owner id tested last since hinst is more varied
  671. //
  672. if ((pminst->hinst == pcplm->minst.hinst) &&
  673. (pminst->idOwner == pcplm->minst.idOwner))
  674. {
  675. FreeThisModule:
  676. //
  677. // This guy already loaded this module, so dec
  678. // the reference and return failure
  679. //
  680. _FreeCPLModuleIndex(iModule);
  681. return(-1);
  682. }
  683. }
  684. //
  685. // this is a new module, so add it to the list
  686. //
  687. if (ADDMODULE(lpData->haminst, &pcplm->minst) < 0)
  688. {
  689. goto FreeThisModule;
  690. }
  691. return iModule;
  692. }
  693. void _AddItemsFromKey(ControlData *pcd, HKEY hkRoot)
  694. {
  695. HKEY hkey;
  696. MODULEINFO mi = {0};
  697. mi.flags = MI_FIND_FILE;
  698. if (ERROR_SUCCESS == RegOpenKeyEx(hkRoot,
  699. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\CPLs"),
  700. 0,
  701. KEY_QUERY_VALUE,
  702. &hkey))
  703. {
  704. TCHAR szData[MAX_PATH], szValue[128];
  705. DWORD dwSizeData, dwValue, dwIndex;
  706. for (dwIndex = 0;
  707. ERROR_SUCCESS == (dwValue = ARRAYSIZE(szValue), dwSizeData = sizeof(szData),
  708. RegEnumValue(hkey, dwIndex, szValue, &dwValue, NULL, NULL, (BYTE *)szData, &dwSizeData));
  709. dwIndex++)
  710. {
  711. TCHAR szPath[MAX_PATH];
  712. if (SHExpandEnvironmentStrings(szData, szPath, ARRAYSIZE(szPath)))
  713. {
  714. WIN32_FIND_DATA fd;
  715. HANDLE hfind = FindFirstFile(szPath, &fd);
  716. if (hfind != INVALID_HANDLE_VALUE)
  717. {
  718. mi.ftCreationTime = fd.ftCreationTime;
  719. mi.nFileSizeHigh = fd.nFileSizeHigh;
  720. mi.nFileSizeLow = fd.nFileSizeLow;
  721. FindClose(hfind);
  722. _InsertModuleName(pcd, szPath, &mi);
  723. }
  724. }
  725. }
  726. RegCloseKey(hkey);
  727. }
  728. }
  729. /* Get the keynames under [MMCPL] in CONTROL.INI and cycle
  730. through all such keys to load their applets into our
  731. list box. Also allocate the array of CPLMODULE structs.
  732. Returns early if can't load old WIN3 applets.
  733. */
  734. BOOL CPLD_GetModules(ControlData *lpData)
  735. {
  736. LPTSTR pStr;
  737. HANDLE hFindFile;
  738. WIN32_FIND_DATA findData;
  739. MODULEINFO mi;
  740. TCHAR szPath[MAX_PATH], szSysDir[MAX_PATH], szName[MAX_PATH];
  741. ASSERT(lpData->hamiModule == NULL);
  742. lpData->hamiModule = DSA_Create(sizeof(mi), 4);
  743. if (!lpData->hamiModule)
  744. {
  745. return FALSE;
  746. }
  747. lpData->haminst = DSA_Create(sizeof(MINST), 4);
  748. if (!lpData->haminst)
  749. {
  750. DSA_Destroy(lpData->hamiModule);
  751. lpData->hamiModule = NULL; // no one is freeing hamiModule in the caller if this fails, but just to make sure ...
  752. return FALSE;
  753. }
  754. //
  755. // So here's the deal:
  756. // We have this global list of all modules that have been loaded, along
  757. // with a reference count for each. This is so that we don't need to
  758. // load a CPL file again when the user double clicks on it.
  759. // We still need to keep a list for each window that is open, so that
  760. // we will not load the same CPL twice in a single window. Therefore,
  761. // we need to keep a list of all modules that are loaded (note that
  762. // we cannot just keep indexes, since the global list can move around).
  763. //
  764. // hamiModule contains the module name, the instance info if loaded,
  765. // and some other information for comparing with cached information
  766. //
  767. ZeroMemory(&mi, sizeof(mi));
  768. //
  769. // don't special case main, instead sort the data by title
  770. //
  771. GetSystemDirectory(szSysDir, ARRAYSIZE(szSysDir));
  772. // load the modules specified in CONTROL.INI under [MMCPL]
  773. {
  774. TCHAR szKeys[512]; // from section of extra cpls to load
  775. GetPrivateProfileString(TEXT("MMCPL"), NULL, c_szNULL, szKeys, ARRAYSIZE(szKeys), TEXT("control.ini"));
  776. for (pStr = szKeys; *pStr; pStr += lstrlen(pStr) + 1)
  777. {
  778. GetPrivateProfileString(TEXT("MMCPL"), pStr, c_szNULL, szName, ARRAYSIZE(szName), TEXT("control.ini"));
  779. if (IsValidCplKey(pStr))
  780. {
  781. _InsertModuleName(lpData, szName, &mi);
  782. }
  783. }
  784. }
  785. // load applets from the system directory
  786. if (PathCombine(szPath, szSysDir, TEXT("*.CPL")))
  787. {
  788. mi.flags |= MI_FIND_FILE;
  789. hFindFile = FindFirstFile(szPath, &findData);
  790. if (hFindFile != INVALID_HANDLE_VALUE)
  791. {
  792. do
  793. {
  794. if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  795. {
  796. BOOL fOkToUse = TRUE;
  797. if (IsOS(OS_WOW6432))
  798. {
  799. GetWindowsDirectory(szPath,ARRAYSIZE(szPath));
  800. if (PathCombine(szPath, szPath, TEXT("system32")) &&
  801. PathCombine(szPath, szPath, findData.cFileName))
  802. {
  803. //
  804. // Don't use any CPLs which exist in the real system32
  805. // directory, since we only have them in the fake system
  806. // directory for compatibility reasons.
  807. //
  808. if (PathFileExists(szPath))
  809. {
  810. fOkToUse = FALSE;
  811. }
  812. }
  813. }
  814. if (fOkToUse)
  815. {
  816. if (PathCombine(szPath, szSysDir, findData.cFileName))
  817. {
  818. mi.ftCreationTime = findData.ftCreationTime;
  819. mi.nFileSizeHigh = findData.nFileSizeHigh;
  820. mi.nFileSizeLow = findData.nFileSizeLow;
  821. _InsertModuleName(lpData, szPath, &mi);
  822. }
  823. }
  824. }
  825. } while (FindNextFile(hFindFile, &findData));
  826. FindClose(hFindFile);
  827. }
  828. }
  829. _AddItemsFromKey(lpData, HKEY_CURRENT_USER);
  830. _AddItemsFromKey(lpData, HKEY_LOCAL_MACHINE);
  831. lpData->cModules = DPA_GetPtrCount(lpData->hamiModule);
  832. return TRUE;
  833. }
  834. //
  835. // A bug has existed in Control Panel for as long as I can tell that,
  836. // under the right conditions involving roaming user profiles, could
  837. // prevent a control panel item from appearing in the folder. The
  838. // problem description is too long for a comment but the MI_REG_INVALID
  839. // flag was added to solve it. See it's use in CControlPanelEnum::Next.
  840. // However, presentation caches created prior to this fix under the
  841. // problem scenario may still result in affected CPL items not appearing.
  842. // In those cases, refreshing the presentation cache using the new code
  843. // corrects the problem. Therefore, any cache created prior to the date
  844. // of this new code's introduction must be discarded and refreshed.
  845. // The presence of the REGCPL_POST_102001 (oct 2001) flag in a cache entry
  846. // indicates the cache was created after this new code was introduced and may
  847. // be safely used. This function reports the presence/absence of this
  848. // flag in the cache buffer. [brianau - 10/03/01]
  849. //
  850. BOOL _IsPresentationCachePostOctober2001(LPBYTE pbData, DWORD cbData)
  851. {
  852. BOOL bPostOct2001 = FALSE;
  853. if (cbData >= sizeof(REG_CPL_INFO))
  854. {
  855. if (REGCPL_POST_102001 & ((REG_CPL_INFO *)pbData)->flags)
  856. {
  857. bPostOct2001 = TRUE;
  858. }
  859. }
  860. return bPostOct2001;
  861. }
  862. // Read the registry for cached CPL info.
  863. // If this info is up-to-date with current modules (from CPLD_GetModules),
  864. // then we can enumerate these without loading the CPLs.
  865. void CPLD_GetRegModules(ControlData *lpData)
  866. {
  867. HKEY hkey;
  868. LPCTSTR lpszRegKey;
  869. // dont cache any-thing in clean boot.
  870. if (GetSystemMetrics(SM_CLEANBOOT))
  871. return;
  872. if (IsOS(OS_WOW6432))
  873. {
  874. lpszRegKey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Controls Folder (Wow64)");
  875. }
  876. else
  877. {
  878. lpszRegKey = REGSTR_PATH_CONTROLSFOLDER;
  879. }
  880. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
  881. lpszRegKey,
  882. 0,
  883. KEY_READ,
  884. &hkey))
  885. {
  886. DWORD cbSize;
  887. DWORD dwLCID = 0;
  888. cbSize = sizeof(dwLCID);
  889. // fail if this cache is not tagged with the UI language ID, or we are not in
  890. // the language ID that the cache was saved in.
  891. if (ERROR_SUCCESS != SHQueryValueEx(hkey, TEXT("Presentation LCID"),
  892. NULL, NULL, (LPBYTE) &dwLCID, &cbSize) || dwLCID != GetUserDefaultUILanguage())
  893. {
  894. RegCloseKey(hkey);
  895. return;
  896. }
  897. if (ERROR_SUCCESS == SHQueryValueEx(hkey, TEXT("Presentation Cache"),
  898. NULL, NULL, NULL, &cbSize))
  899. {
  900. lpData->pRegCPLBuffer = LocalAlloc(LPTR, cbSize);
  901. if (lpData->pRegCPLBuffer)
  902. {
  903. if (ERROR_SUCCESS == SHQueryValueEx(hkey, TEXT("Presentation Cache"),
  904. NULL, NULL, lpData->pRegCPLBuffer, &cbSize))
  905. {
  906. if (!_IsPresentationCachePostOctober2001(lpData->pRegCPLBuffer, cbSize))
  907. {
  908. TraceMsg(TF_WARNING, "CPLD_GetRegModules: Presentation cache pre Oct 2001.");
  909. LocalFree(lpData->pRegCPLBuffer);
  910. lpData->pRegCPLBuffer = NULL;
  911. }
  912. else
  913. {
  914. lpData->hRegCPLs = DPA_Create(4);
  915. if (lpData->hRegCPLs)
  916. {
  917. REG_CPL_INFO * p;
  918. DWORD cbOffset;
  919. for (cbOffset = 0 ;
  920. cbOffset < cbSize ;
  921. cbOffset += p->cbSize)
  922. {
  923. p = (REG_CPL_INFO *)&(lpData->pRegCPLBuffer[cbOffset]);
  924. p->flags |= REGCPL_FROMREG;
  925. DPA_AppendPtr(lpData->hRegCPLs, p);
  926. //DebugMsg(DM_TRACE,"sh CPLD_GetRegModules: %s (%s)", REGCPL_FILENAME(p), REGCPL_CPLNAME(p));
  927. }
  928. lpData->cRegCPLs = DPA_GetPtrCount(lpData->hRegCPLs);
  929. }
  930. }
  931. }
  932. else
  933. {
  934. TraceMsg(TF_WARNING, "CPLD_GetRegModules: failed read!");
  935. }
  936. } // Alloc
  937. } // SHQueryValueEx for size
  938. RegCloseKey(hkey);
  939. } // RegOpenKey
  940. }
  941. //
  942. // On a typical system, we will successfully cache all the CPLs. So this
  943. // function will write out the data only once.
  944. //
  945. void CPLD_FlushRegModules(ControlData *lpData)
  946. {
  947. if (lpData->fRegCPLChanged)
  948. {
  949. int num = DPA_GetPtrCount(lpData->hRegCPLs);
  950. DWORD cbSize = num * sizeof(REG_CPL_INFO);
  951. REG_CPL_INFO * prcpli = LocalAlloc(LPTR, cbSize);
  952. LPCTSTR lpszRegKey;
  953. if (IsOS(OS_WOW6432))
  954. {
  955. lpszRegKey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Controls Folder (Wow64)");
  956. }
  957. else
  958. {
  959. lpszRegKey = REGSTR_PATH_CONTROLSFOLDER;
  960. }
  961. if (prcpli)
  962. {
  963. REG_CPL_INFO * pDest;
  964. HKEY hkey;
  965. int i;
  966. //
  967. // 0<=i<=num && CPLs 0..i-1 have been copied to prcpli or skipped
  968. //
  969. for (i = 0, pDest = prcpli; i < num ;)
  970. {
  971. REG_CPL_INFO * p = DPA_GetPtr(lpData->hRegCPLs, i);
  972. int j;
  973. //
  974. // if any CPL in this module has a dynamic icon, we cannot cache
  975. // any of this module's CPLs.
  976. //
  977. // i<=j<=num && CPLs i..j-1 are in same module
  978. //
  979. for (j = i; j < num; j++)
  980. {
  981. REG_CPL_INFO * q = DPA_GetPtr(lpData->hRegCPLs, j);
  982. if (lstrcmp(REGCPL_FILENAME(p), REGCPL_FILENAME(q)))
  983. {
  984. // all CPLs in this module are okay, save 'em
  985. break;
  986. }
  987. if (q->idIcon == 0)
  988. {
  989. TraceMsg(TF_GENERAL, "CPLD_FlushRegModules: SKIPPING %s (%s) [dynamic icon]",REGCPL_FILENAME(p),REGCPL_CPLNAME(p));
  990. // this module has a dynamic icon, skip it
  991. for (j++ ; j < num ; j++)
  992. {
  993. q = DPA_GetPtr(lpData->hRegCPLs, j);
  994. if (lstrcmp(REGCPL_FILENAME(p), REGCPL_FILENAME(q)))
  995. break;
  996. }
  997. i = j;
  998. break;
  999. }
  1000. }
  1001. // CPLs i..j-1 are in the same module and need to be saved
  1002. // (if j<num, CPL j is in the next module)
  1003. for (; i < j ; i++)
  1004. {
  1005. p = DPA_GetPtr(lpData->hRegCPLs, i);
  1006. hmemcpy(pDest, p, p->cbSize);
  1007. //
  1008. // Set the post-Oct 2001 flag.
  1009. //
  1010. pDest->flags |= REGCPL_POST_102001;
  1011. pDest = (REG_CPL_INFO *)(((LPBYTE)pDest) + pDest->cbSize);
  1012. //DebugMsg(DM_TRACE,"CPLD_FlushRegModules: %s (%s)",REGCPL_FILENAME(p),REGCPL_CPLNAME(p));
  1013. }
  1014. } // for (i=0,pDest=prcpli
  1015. // prcpli contains packed REG_CPL_INFO structures to save to the registry
  1016. if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER,
  1017. lpszRegKey,
  1018. 0,
  1019. NULL,
  1020. REG_OPTION_NON_VOLATILE,
  1021. KEY_WRITE,
  1022. NULL, // default security
  1023. &hkey,
  1024. NULL))
  1025. {
  1026. DWORD dwLCID;
  1027. DWORD dwSize = sizeof(dwLCID);
  1028. dwLCID = GetUserDefaultUILanguage();
  1029. if (ERROR_SUCCESS != RegSetValueEx(hkey, TEXT("Presentation LCID"), 0, REG_DWORD, (LPBYTE) &dwLCID, dwSize))
  1030. {
  1031. TraceMsg(TF_WARNING, "CPLD_FLushRegModules: failed to write the LCID!");
  1032. }
  1033. if (ERROR_SUCCESS != RegSetValueEx(hkey, TEXT("Presentation Cache"), 0, REG_BINARY, (LPBYTE)prcpli, (DWORD) ((LPBYTE)pDest-(LPBYTE)prcpli)))
  1034. {
  1035. TraceMsg(TF_WARNING, "CPLD_FLushRegModules: failed write!");
  1036. }
  1037. RegCloseKey(hkey);
  1038. }
  1039. LocalFree((HLOCAL)prcpli);
  1040. lpData->fRegCPLChanged = FALSE; // no longer dirty
  1041. } // if (prcpli)
  1042. } // if dirty
  1043. }
  1044. //---------------------------------------------------------------------------
  1045. void CPLD_Destroy(ControlData *lpData)
  1046. {
  1047. int i;
  1048. if (lpData->haminst)
  1049. {
  1050. for (i=DSA_GetItemCount(lpData->haminst)-1 ; i>=0 ; --i)
  1051. _FreeCPLModuleHandle(DSA_GetItemPtr(lpData->haminst, i));
  1052. DSA_Destroy(lpData->haminst);
  1053. }
  1054. if (lpData->hamiModule)
  1055. {
  1056. for (i=DSA_GetItemCount(lpData->hamiModule)-1 ; i>=0 ; --i)
  1057. {
  1058. PMODULEINFO pmi = DSA_GetItemPtr(lpData->hamiModule, i);
  1059. Str_SetPtr(&pmi->pszModule, NULL);
  1060. }
  1061. DSA_Destroy(lpData->hamiModule);
  1062. }
  1063. if (lpData->hRegCPLs)
  1064. {
  1065. CPLD_FlushRegModules(lpData);
  1066. for (i = DPA_GetPtrCount(lpData->hRegCPLs)-1 ; i >= 0 ; i--)
  1067. {
  1068. REG_CPL_INFO * p = DPA_GetPtr(lpData->hRegCPLs, i);
  1069. if (!(p->flags & REGCPL_FROMREG))
  1070. LocalFree((HLOCAL)p);
  1071. }
  1072. DPA_Destroy(lpData->hRegCPLs);
  1073. }
  1074. if (lpData->pRegCPLBuffer)
  1075. LocalFree((HLOCAL)lpData->pRegCPLBuffer);
  1076. }
  1077. //
  1078. // Loads module lpData->hamiModule[nModule] and returns # cpls in module
  1079. int CPLD_InitModule(ControlData *lpData, int nModule, MINST *pminst)
  1080. {
  1081. PMODULEINFO pmi;
  1082. LPCPLMODULE pcplm;
  1083. int iModule;
  1084. pmi = DSA_GetItemPtr(lpData->hamiModule, nModule);
  1085. if (pmi == NULL)
  1086. {
  1087. TraceMsg(TF_WARNING, "CPLD_InitModule: DSA returned NULL structure");
  1088. return 0;
  1089. }
  1090. iModule = _LoadCPLModuleAndAdd(lpData, pmi->pszModule);
  1091. if (iModule < 0)
  1092. {
  1093. return(0);
  1094. }
  1095. pcplm = DSA_GetItemPtr(g_hacplmLoaded, iModule);
  1096. *pminst = pcplm->minst;
  1097. return DSA_GetItemCount(pcplm->hacpli);
  1098. }
  1099. BOOL CPLD_AddControlToReg(ControlData *lpData, const MINST * pminst, int nControl)
  1100. {
  1101. int iModule;
  1102. LPCPLMODULE pcplm;
  1103. LPCPLITEM pcpli = NULL;
  1104. TCHAR buf[MAX_PATH];
  1105. HANDLE hFindFile;
  1106. WIN32_FIND_DATA findData;
  1107. iModule = _FindCPLModule(pminst);
  1108. if (iModule >= 0)
  1109. {
  1110. pcplm = DSA_GetItemPtr(g_hacplmLoaded, iModule);
  1111. if (pcplm != NULL)
  1112. pcpli = DSA_GetItemPtr(pcplm->hacpli, nControl);
  1113. }
  1114. if (pcpli == NULL)
  1115. return FALSE;
  1116. //
  1117. // PERF: Why are we using GetModuleFileName instead of the name
  1118. // of the file we used to load this module? (We have the name both
  1119. // in the calling function and in lpData.)
  1120. //
  1121. GetModuleFileName(pcplm->minst.hinst, buf, MAX_PATH);
  1122. if (*buf != 0)
  1123. hFindFile = FindFirstFile(buf, &findData);
  1124. else
  1125. hFindFile = INVALID_HANDLE_VALUE;
  1126. if (hFindFile != INVALID_HANDLE_VALUE)
  1127. {
  1128. REG_CPL_INFO * prcpli = LocalAlloc(LPTR, sizeof(REG_CPL_INFO));
  1129. FindClose(hFindFile);
  1130. if (prcpli)
  1131. {
  1132. if (SUCCEEDED(StringCchCopy(REGCPL_FILENAME(prcpli), MAX_PATH, buf)))
  1133. {
  1134. prcpli->flags = FALSE;
  1135. prcpli->ftCreationTime = findData.ftCreationTime;
  1136. prcpli->nFileSizeHigh = findData.nFileSizeHigh;
  1137. prcpli->nFileSizeLow = findData.nFileSizeLow;
  1138. prcpli->idIcon = pcpli->idIcon;
  1139. prcpli->oName = lstrlen(REGCPL_FILENAME(prcpli)) + 1;
  1140. //
  1141. // We don't check return values from StringCchCopy because we
  1142. // don't care if the CPL display name or info text are truncated.
  1143. // We do care that the file name is complete (above).
  1144. //
  1145. StringCchCopy(REGCPL_CPLNAME(prcpli), MAX_CCH_CPLNAME, pcpli->pszName);
  1146. prcpli->oInfo = prcpli->oName + lstrlen(REGCPL_CPLNAME(prcpli)) + 1;
  1147. StringCchCopy(REGCPL_CPLINFO(prcpli), MAX_CCH_CPLINFO, pcpli->pszInfo);
  1148. prcpli->cbSize = FIELD_OFFSET(REG_CPL_INFO, buf) + (prcpli->oInfo
  1149. + lstrlen(REGCPL_CPLINFO(prcpli))
  1150. + 1) * sizeof(TCHAR);
  1151. //
  1152. // Force struct size to be DWORD aligned since these are packed
  1153. // together in registry, then read and accessed after reading
  1154. // cache from registry.
  1155. //
  1156. if (prcpli->cbSize & 3)
  1157. prcpli->cbSize += sizeof(DWORD) - (prcpli->cbSize & 3);
  1158. if (!lpData->hRegCPLs)
  1159. {
  1160. lpData->hRegCPLs = DPA_Create(4);
  1161. }
  1162. if (lpData->hRegCPLs)
  1163. {
  1164. DPA_AppendPtr(lpData->hRegCPLs, prcpli);
  1165. //
  1166. // don't update cRegCPLs. We don't need it any more, and
  1167. // it is also the upper-end counter for ESF_Next registry enum.
  1168. //lpData->cRegCPLs++;
  1169. //
  1170. lpData->fRegCPLChanged = TRUE;
  1171. }
  1172. else
  1173. LocalFree((HLOCAL)prcpli);
  1174. }
  1175. }
  1176. }
  1177. return TRUE;
  1178. }