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.

494 lines
15 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "copy.h"
  4. #include "filetbl.h"
  5. #include "ovrlaymn.h"
  6. #include "drives.h"
  7. #include "mixctnt.h"
  8. #include "unicpp\admovr2.h"
  9. void FreeExtractIconInfo(int);
  10. void DAD_ThreadDetach(void);
  11. void DAD_ProcessDetach(void);
  12. void TaskMem_MakeInvalid(void);
  13. void UltRoot_Term(void);
  14. void FlushRunDlgMRU(void);
  15. STDAPI_(BOOL) ATL_DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/);
  16. // from mtpt.cpp
  17. STDAPI_(void) CMtPt_FinalCleanUp();
  18. STDAPI_(void) CMtPt_Initialize();
  19. STDAPI_(void) CMtPt_FakeVolatileKeys();
  20. // from rgsprtc.cpp
  21. STDAPI_(void) CRegSupportCached_RSEnableKeyCaching(BOOL fEnable);
  22. // Global data
  23. BOOL g_bMirroredOS = FALSE; // Is Mirroring enabled
  24. BOOL g_bBiDiPlatform = FALSE; // Is DATE_LTRREADING flag supported by GetDateFormat() API?
  25. HINSTANCE g_hinst = NULL;
  26. extern HANDLE g_hCounter; // Global count of mods to Special Folder cache.
  27. extern HANDLE g_hRestrictions ; // Global count of mods to restriction cache.
  28. extern HANDLE g_hSettings; // global count of mods to shellsettings cache
  29. DWORD g_dwThreadBindCtx = (DWORD) -1;
  30. #ifdef DEBUG
  31. BOOL g_bInDllEntry = FALSE;
  32. #endif
  33. CRITICAL_SECTION g_csDll = {0};
  34. extern CRITICAL_SECTION g_csSCN;
  35. extern CRITICAL_SECTION g_csTNGEN;
  36. extern CRITICAL_SECTION g_csDarwinAds;
  37. // these will always be zero
  38. const LARGE_INTEGER g_li0 = {0};
  39. const ULARGE_INTEGER g_uli0 = {0};
  40. #ifdef DEBUG
  41. // Undefine what shlwapi.h defined so our ordinal asserts map correctly
  42. #undef PathAddBackslash
  43. WINSHELLAPI LPTSTR WINAPI PathAddBackslash(LPTSTR lpszPath);
  44. #undef PathMatchSpec
  45. WINSHELLAPI BOOL WINAPI PathMatchSpec(LPCTSTR pszFile, LPCTSTR pszSpec);
  46. #endif
  47. void LoadCCv5()
  48. {
  49. HANDLE hComctl32;
  50. ULONG_PTR ul = 0;
  51. // Rundll does not have a manifest. However, it will activate a context for a
  52. // dll, if it has an embedded manifest at 123. This will cause Shell32.dll
  53. // to be loaded inside of a v6 context. This means this comctl32 load would be v6.
  54. // In order to work in the Rundll cases, we need to activate NULL. This verifies that
  55. // we load v5 and not v6 in this case.
  56. // other cases are not affected.
  57. ActivateActCtx(NULL, &ul);
  58. hComctl32 = LoadLibrary(TEXT("comctl32.dll")); // Needs to add ref the DLL.
  59. if (hComctl32)
  60. {
  61. typedef BOOL (*PFNICOMCTL32)(LPINITCOMMONCONTROLSEX);
  62. PFNICOMCTL32 pfn = (PFNICOMCTL32)GetProcAddress(hComctl32, "InitCommonControlsEx");
  63. if (pfn)
  64. {
  65. INITCOMMONCONTROLSEX icce;
  66. icce.dwICC = 0x00003FFF;
  67. icce.dwSize = sizeof(icce);
  68. pfn(&icce);
  69. }
  70. }
  71. if (ul != 0)
  72. DeactivateActCtx(0, ul);
  73. }
  74. #ifdef DEBUG
  75. void _ValidateExport(FARPROC fp, LPCSTR pszExport, MEMORY_BASIC_INFORMATION *pmbi)
  76. {
  77. FARPROC fpExport;
  78. // If not yet computed, calculate the size of our code segment.
  79. if (pmbi->BaseAddress == NULL)
  80. {
  81. VirtualQuery(_ValidateExport, pmbi, sizeof(*pmbi));
  82. }
  83. fpExport = GetProcAddress(g_hinst, pszExport);
  84. // Sometimes our import table is patched. So if fpExport does not
  85. // reside inside our DLL, then ignore it.
  86. // (But complain if fpExport==NULL.)
  87. if (fpExport == NULL ||
  88. ((SIZE_T)fpExport - (SIZE_T)pmbi->BaseAddress) < pmbi->RegionSize)
  89. {
  90. ASSERT(fp == fpExport);
  91. }
  92. }
  93. #endif
  94. STDAPI_(BOOL) IsProcessWinlogon()
  95. {
  96. return BOOLFROMPTR(GetModuleHandle(TEXT("winlogon.EXE")));
  97. }
  98. BOOL _ProcessAttach(HINSTANCE hDll)
  99. {
  100. BOOL fIgnoreFusionCall = FALSE;
  101. ASSERTMSG(g_hinst < ((HINSTANCE)1), "Shell32.dll DLL_POCESS_ATTACH is being called for the second time.");
  102. g_hinst = hDll;
  103. g_uCodePage = GetACP();
  104. // Got Fusion?
  105. //
  106. // not get fusion if (1) the current exe is winlogon.exe; (2) in GUI mode setup ; xiaoyuw@03/12/2001
  107. //
  108. #if 0
  109. if (IsGuimodeSetupRunning())
  110. {
  111. WCHAR winlogon_fullpath[MAX_PATH];
  112. PWSTR pszImagePath = NULL, p = NULL;
  113. if (SHGetSystemWindowsDirectory(winlogon_fullpath, ARRAYSIZE(winlogon_fullpath)))
  114. {
  115. PathAppend(winlogon_fullpath, TEXT("\\system32\\winlogon.exe"));
  116. if (NtCurrentPeb()->ProcessParameters != NULL)
  117. pszImagePath = NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer;
  118. p = pszImagePath;
  119. if (_wcsicmp(p, TEXT("\\??\\"))) // convert nt path to win32 path
  120. p += 4;
  121. if (_wcsicmp(p, winlogon_fullpath) == 0)
  122. fIgnoreFusionCall = TRUE;
  123. }
  124. }
  125. #else
  126. if ((IsGuimodeSetupRunning()) && (IsProcessWinlogon()))
  127. fIgnoreFusionCall = TRUE;
  128. #endif
  129. if ( ! fIgnoreFusionCall)
  130. SHFusionInitializeFromModuleID(hDll, 124);
  131. // For app Compat Reasons we need to have the old window classes in memory as well
  132. // as the new fusionized ones. This is because bad applications such as WinAmp don't
  133. // follow instructions can call into ComCtl32 by themselves. They expect that shell32
  134. // will do it for them.
  135. LoadCCv5();
  136. InitializeCriticalSection(&g_csDll);
  137. InitializeCriticalSection(&g_csSCN);
  138. InitializeCriticalSection(&g_csTNGEN);
  139. InitializeCriticalSection(&g_csDarwinAds);
  140. // Initialize the MountPoint stuff
  141. CMtPt_Initialize();
  142. // Initialize a Crit Sect for the Autoplay prompts
  143. InitializeCriticalSection(&g_csAutoplayPrompt);
  144. // perthread BindCtx
  145. g_dwThreadBindCtx = TlsAlloc();
  146. // We need to disable HKEY caching for classes using CRegSupportCached in
  147. // winlogon since it does not get unloaded. This must also apply to the other
  148. // services loading shell32.dllNot being unloaded the _ProcessDetach
  149. // never gets called for shell32, and we never release the cached HKEYs. This
  150. // prevents the user hives from being unloaded. SO we'll enable caching only
  151. // for Explorer.exe. (stephstm, 08/20/99)
  152. //
  153. CRegSupportCached_RSEnableKeyCaching(IsProcessAnExplorer());
  154. // Check if the mirroring APIs exist on the current platform.
  155. g_bMirroredOS = IS_MIRRORING_ENABLED();
  156. g_bBiDiPlatform = BOOLFROMPTR(GetModuleHandle(TEXT("LPK.DLL")));
  157. #ifdef DEBUG
  158. {
  159. MEMORY_BASIC_INFORMATION mbi = {0};
  160. #define DEREFMACRO(x) x
  161. #define ValidateORD(_name) _ValidateExport((FARPROC)_name, (LPSTR)MAKEINTRESOURCE(DEREFMACRO(_name##ORD)), &mbi)
  162. ValidateORD(SHValidateUNC);
  163. ValidateORD(SHChangeNotifyRegister);
  164. ValidateORD(SHChangeNotifyDeregister);
  165. ValidateORD(OleStrToStrN);
  166. ValidateORD(SHCloneSpecialIDList);
  167. _ValidateExport((FARPROC)DllGetClassObject, (LPSTR)MAKEINTRESOURCE(SHDllGetClassObjectORD), &mbi);
  168. ValidateORD(SHLogILFromFSIL);
  169. ValidateORD(SHMapPIDLToSystemImageListIndex);
  170. ValidateORD(SHShellFolderView_Message);
  171. ValidateORD(Shell_GetImageLists);
  172. ValidateORD(SHGetSpecialFolderPath);
  173. ValidateORD(StrToOleStrN);
  174. ValidateORD(ILClone);
  175. ValidateORD(ILCloneFirst);
  176. ValidateORD(ILCombine);
  177. ValidateORD(ILFindChild);
  178. ValidateORD(ILFree);
  179. ValidateORD(ILGetNext);
  180. ValidateORD(ILGetSize);
  181. ValidateORD(ILIsEqual);
  182. ValidateORD(ILRemoveLastID);
  183. ValidateORD(PathAddBackslash);
  184. ValidateORD(PathIsExe);
  185. ValidateORD(PathMatchSpec);
  186. ValidateORD(SHGetSetSettings);
  187. ValidateORD(SHILCreateFromPath);
  188. ValidateORD(SHFree);
  189. ValidateORD(SHAddFromPropSheetExtArray);
  190. ValidateORD(SHCreatePropSheetExtArray);
  191. ValidateORD(SHDestroyPropSheetExtArray);
  192. ValidateORD(SHReplaceFromPropSheetExtArray);
  193. ValidateORD(SHCreateDefClassObject);
  194. ValidateORD(SHGetNetResource);
  195. }
  196. #endif // DEBUG
  197. #ifdef DEBUG
  198. {
  199. extern LPMALLOC g_pmemTask;
  200. AssertMsg(g_pmemTask == NULL, TEXT("Somebody called SHAlloc in DllEntry!"));
  201. }
  202. // Make sure ShellDispatch has the right flags for shell settings
  203. {
  204. STDAPI_(void) _VerifyDispatchGetSetting();
  205. _VerifyDispatchGetSetting();
  206. }
  207. #endif
  208. return TRUE;
  209. }
  210. // Table of all window classes we register so we can unregister them
  211. // at DLL unload.
  212. //
  213. extern const TCHAR c_szBackgroundPreview2[];
  214. extern const TCHAR c_szComponentPreview[];
  215. extern const TCHAR c_szUserEventWindow[];
  216. const LPCTSTR c_rgszClasses[] = {
  217. TEXT("SHELLDLL_DefView"), // defview.cpp
  218. TEXT("WOACnslWinPreview"), // lnkcon.c
  219. TEXT("WOACnslFontPreview"), // lnkcon.c
  220. TEXT("cpColor"), // lnkcon.c
  221. TEXT("cpShowColor"), // lnkcon.c
  222. c_szStubWindowClass, // rundll32.c
  223. c_szBackgroundPreview2, // unicpp\dbackp.cpp
  224. c_szComponentPreview, // unicpp\dcompp.cpp
  225. TEXT(STR_DESKTOPCLASS), // unicpp\desktop.cpp
  226. TEXT("MSGlobalFolderOptionsStub"), // unicpp\options.cpp
  227. TEXT("DivWindow"), // fsrchdlg.h
  228. TEXT("ATL Shell Embedding"), // unicpp\dvoc.h
  229. TEXT("ShellFileSearchControl"), // fsearch.h
  230. TEXT("GroupButton"), // fsearch
  231. TEXT("ATL:STATIC"), // unicpp\deskmovr.cpp
  232. TEXT("DeskMover"), // unicpp\deskmovr.cpp
  233. TEXT("SysFader"), // menuband\fadetsk.cpp
  234. c_szUserEventWindow, // uevttmr.cpp
  235. LINKWINDOW_CLASS, // linkwnd.cpp
  236. TEXT("DUIViewWndClassName"), // duiview.cpp
  237. TEXT("DUIMiniPreviewer"), // duiinfo.cpp
  238. };
  239. void _ProcessDetach(BOOL bProcessShutdown)
  240. {
  241. #ifdef DEBUG
  242. if (bProcessShutdown)
  243. {
  244. // to catch bugs where people use the task allocator at process
  245. // detatch time (this is a problem becuase OLE32.DLL could be unloaded)
  246. TaskMem_MakeInvalid();
  247. }
  248. g_hinst = (HINSTANCE)1;
  249. #endif
  250. FlushRunDlgMRU();
  251. FlushFileClass();
  252. if (!bProcessShutdown)
  253. {
  254. // some of these may use the task allocator. we can only do
  255. // this when we our DLL is being unloaded in a process, not
  256. // at process term since OLE32 might not be around to be called
  257. // at process shutdown time this memory will be freed as a result
  258. // of the process address space going away.
  259. SpecialFolderIDTerminate();
  260. BitBucket_Terminate();
  261. UltRoot_Term();
  262. RLTerminate(); // close our use of the Registry list...
  263. DAD_ProcessDetach();
  264. CopyHooksTerminate();
  265. IconOverlayManagerTerminate();
  266. // being unloaded via FreeLibrary, then do some more stuff.
  267. // Don't need to do this on process terminate.
  268. SHUnregisterClasses(HINST_THISDLL, c_rgszClasses, ARRAYSIZE(c_rgszClasses));
  269. FreeExtractIconInfo(-1);
  270. FreeUndoList();
  271. DestroyHashItemTable(NULL);
  272. FileIconTerm();
  273. }
  274. SHChangeNotifyTerminate(TRUE, bProcessShutdown);
  275. if (!bProcessShutdown)
  276. {
  277. // this line was moved from the above !bProcessShutdown block because
  278. // it needs to happen after SHChangeNotifyTerminate b/c the SCHNE code has
  279. // a thread running that uses the CDrivesFolder global psf.
  280. // NOTE: this needs to be in a !bProcessShutdown block since it calls the
  281. // task allocator and we blow this off at shutdown since OLE might already
  282. // be gone.
  283. CDrives_Terminate();
  284. }
  285. // global resources that we need to free in all cases
  286. CMtPt_FinalCleanUp();
  287. // Delete the Crit Sect for the Autoplay prompts
  288. DeleteCriticalSection(&g_csAutoplayPrompt);
  289. if ((DWORD) -1 != g_dwThreadBindCtx)
  290. TlsFree(g_dwThreadBindCtx);
  291. SHDestroyCachedGlobalCounter(&g_hCounter);
  292. SHDestroyCachedGlobalCounter(&g_hRestrictions);
  293. SHDestroyCachedGlobalCounter(&g_hSettings);
  294. if (g_hklmApprovedExt && g_hklmApprovedExt != INVALID_HANDLE_VALUE)
  295. RegCloseKey(g_hklmApprovedExt);
  296. UnInitializeDirectUI();
  297. DeleteCriticalSection(&g_csDll);
  298. DeleteCriticalSection(&g_csSCN);
  299. DeleteCriticalSection(&g_csTNGEN);
  300. DeleteCriticalSection(&g_csDarwinAds);
  301. SHFusionUninitialize();
  302. }
  303. BOOL _ThreadDetach()
  304. {
  305. ASSERTNONCRITICAL // Thread shouldn't term while holding CS
  306. DAD_ThreadDetach();
  307. return TRUE;
  308. }
  309. STDAPI_(BOOL) DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
  310. {
  311. BOOL fRet = TRUE;
  312. #ifdef DEBUG
  313. g_bInDllEntry = TRUE;
  314. #endif
  315. switch(dwReason)
  316. {
  317. case DLL_PROCESS_ATTACH:
  318. if (fRet)
  319. {
  320. CcshellGetDebugFlags(); // Don't put this line under #ifdef
  321. fRet = _ProcessAttach(hDll);
  322. }
  323. break;
  324. case DLL_PROCESS_DETACH:
  325. _ProcessDetach(lpReserved != NULL);
  326. break;
  327. case DLL_THREAD_DETACH:
  328. _ThreadDetach();
  329. break;
  330. default:
  331. break;
  332. }
  333. if (fRet)
  334. ATL_DllMain(hDll, dwReason, lpReserved);
  335. #ifdef DEBUG
  336. g_bInDllEntry = FALSE;
  337. #endif
  338. return fRet;
  339. }
  340. #ifdef DEBUG
  341. LRESULT WINAPI SendMessageD( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  342. {
  343. ASSERTNONCRITICAL;
  344. #ifdef UNICODE
  345. return SendMessageW(hWnd, Msg, wParam, lParam);
  346. #else
  347. return SendMessageA(hWnd, Msg, wParam, lParam);
  348. #endif
  349. }
  350. //
  351. // In DEBUG, make sure every class we register lives in the c_rgszClasses
  352. // table so we can clean up properly at DLL unload. NT does not automatically
  353. // unregister classes when a DLL unloads, so we have to do it manually.
  354. //
  355. ATOM WINAPI RegisterClassD(CONST WNDCLASS *pwc)
  356. {
  357. int i;
  358. for (i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
  359. {
  360. if (lstrcmpi(c_rgszClasses[i], pwc->lpszClassName) == 0)
  361. {
  362. return RealRegisterClass(pwc);
  363. }
  364. }
  365. AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
  366. return 0;
  367. }
  368. ATOM WINAPI RegisterClassExD(CONST WNDCLASSEX *pwc)
  369. {
  370. int i;
  371. for (i = 0; i < ARRAYSIZE(c_rgszClasses); i++)
  372. {
  373. if (lstrcmpi(c_rgszClasses[i], pwc->lpszClassName) == 0)
  374. {
  375. return RealRegisterClassEx(pwc);
  376. }
  377. }
  378. AssertMsg(0, TEXT("Class %s needs to be added to the c_rgszClasses list"), pwc->lpszClassName);
  379. return 0;
  380. }
  381. //
  382. // In DEBUG, send FindWindow through a wrapper that ensures that the
  383. // critical section is not taken. FindWindow'ing for a window title
  384. // sends inter-thread WM_GETTEXT messages, which is not obvious.
  385. //
  386. STDAPI_(HWND) FindWindowD(LPCTSTR lpClassName, LPCTSTR lpWindowName)
  387. {
  388. return FindWindowExD(NULL, NULL, lpClassName, lpWindowName);
  389. }
  390. STDAPI_(HWND) FindWindowExD(HWND hwndParent, HWND hwndChildAfter, LPCTSTR lpClassName, LPCTSTR lpWindowName)
  391. {
  392. if (lpWindowName)
  393. {
  394. ASSERTNONCRITICAL;
  395. }
  396. return RealFindWindowEx(hwndParent, hwndChildAfter, lpClassName, lpWindowName);
  397. }
  398. #endif // DEBUG
  399. STDAPI DllCanUnloadNow()
  400. {
  401. // shell32 won't be able to be unloaded since there are lots of APIs and
  402. // other non COM things that will need to keep it loaded
  403. return S_FALSE;
  404. }