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.

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