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.

1536 lines
42 KiB

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