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.

368 lines
12 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "copy.h"
  4. UINT DefView_CopyHook(const COPYHOOKINFO *pchi);
  5. int PathCopyHookCallback(HWND hwnd, UINT wFunc, LPCTSTR pszSrc, LPCTSTR pszDest);
  6. void _CopyHookTerminate(HDSA hdsaCopyHooks, BOOL fProcessDetach);
  7. typedef struct {
  8. ICopyHook * pcphk; // Either ICopyHookA *or LPCOPYHOOK
  9. BOOL fAnsiCrossOver; // TRUE for ICopyHookA *on UNICODE build
  10. } CALLABLECOPYHOOK;
  11. typedef struct
  12. {
  13. ICopyHook cphk;
  14. ICopyHookA cphkA;
  15. LONG cRef;
  16. } CCopyHook;
  17. STDMETHODIMP_(ULONG) CCopyHook_AddRef(ICopyHook *pcphk); // forward
  18. STDMETHODIMP CCopyHook_QueryInterface(ICopyHook *pcphk, REFIID riid, void **ppvObj)
  19. {
  20. CCopyHook *this = IToClass(CCopyHook, cphk, pcphk);
  21. if (IsEqualIID(riid, &IID_IShellCopyHook) ||
  22. IsEqualIID(riid, &IID_IUnknown))
  23. {
  24. *ppvObj = pcphk;
  25. }
  26. else if (IsEqualIID(riid, &IID_IShellCopyHookA))
  27. {
  28. *ppvObj = &this->cphkA;
  29. }
  30. else
  31. {
  32. *ppvObj = NULL;
  33. return E_NOINTERFACE;
  34. }
  35. CCopyHook_AddRef(&this->cphk);
  36. return NOERROR;
  37. }
  38. STDMETHODIMP_(ULONG) CCopyHook_AddRef(ICopyHook *pcphk)
  39. {
  40. CCopyHook *this = IToClass(CCopyHook, cphk, pcphk);
  41. return InterlockedIncrement(&this->cRef);
  42. }
  43. STDMETHODIMP_(ULONG) CCopyHook_Release(ICopyHook *pcphk)
  44. {
  45. CCopyHook *this = IToClass(CCopyHook, cphk, pcphk);
  46. ULONG cRef;
  47. ASSERT( 0 != this->cRef );
  48. cRef = InterlockedDecrement(&this->cRef);
  49. if ( 0 == cRef )
  50. {
  51. LocalFree((HLOCAL)this);
  52. }
  53. return cRef;
  54. }
  55. STDMETHODIMP_(UINT) CCopyHook_CopyCallback(ICopyHook *pcphk, HWND hwnd, UINT wFunc, UINT wFlags,
  56. LPCTSTR pszSrcFile, DWORD dwSrcAttribs, LPCTSTR pszDestFile, DWORD dwDestAttribs)
  57. {
  58. COPYHOOKINFO chi = { hwnd, wFunc, wFlags, pszSrcFile, dwSrcAttribs, pszDestFile, dwDestAttribs };
  59. DebugMsg(DM_TRACE, TEXT("Event = %d, File = %s , %s"), wFunc, pszSrcFile,
  60. Dbg_SafeStr(pszDestFile));
  61. // check Special Folders first...
  62. if (PathCopyHookCallback(hwnd, wFunc, pszSrcFile, pszDestFile) == IDNO)
  63. {
  64. return IDNO;
  65. }
  66. if (wFunc != FO_COPY && !(wFlags & FOF_NOCONFIRMATION))
  67. {
  68. TCHAR szShortName[MAX_PATH];
  69. BOOL fInReg = (RLIsPathInList(pszSrcFile) != -1);
  70. BOOL fInBitBucket = IsFileInBitBucket(pszSrcFile);
  71. UINT iLength = GetShortPathName(pszSrcFile, szShortName, ARRAYSIZE(szShortName));
  72. // Don't double search for names that are the same (or already found)
  73. if (iLength != 0 && lstrcmpi(pszSrcFile, szShortName) != 0)
  74. {
  75. if (!fInReg)
  76. fInReg = (RLIsPathInList(szShortName) != -1);
  77. if (!fInBitBucket)
  78. fInBitBucket = IsFileInBitBucket(szShortName);
  79. }
  80. if (fInReg && !fInBitBucket)
  81. {
  82. LPCTSTR pszSpec = PathFindFileName(pszSrcFile);
  83. return ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_RENAMEFILESINREG),
  84. pszSpec, MB_YESNO | MB_ICONEXCLAMATION, pszSpec);
  85. }
  86. }
  87. return DefView_CopyHook(&chi);
  88. }
  89. ICopyHookVtbl c_CCopyHookVtbl = {
  90. CCopyHook_QueryInterface, CCopyHook_AddRef, CCopyHook_Release,
  91. CCopyHook_CopyCallback,
  92. };
  93. STDMETHODIMP CCopyHookA_QueryInterface(ICopyHookA *pcphkA, REFIID riid, void **ppvObj)
  94. {
  95. CCopyHook *this = IToClass(CCopyHook, cphkA, pcphkA);
  96. return CCopyHook_QueryInterface(&this->cphk,riid,ppvObj);
  97. }
  98. STDMETHODIMP_(ULONG) CCopyHookA_AddRef(ICopyHookA *pcphkA)
  99. {
  100. CCopyHook *this = IToClass(CCopyHook, cphkA, pcphkA);
  101. return CCopyHook_AddRef(&this->cphk);
  102. }
  103. STDMETHODIMP_(ULONG) CCopyHookA_Release(ICopyHookA *pcphkA)
  104. {
  105. CCopyHook *this = IToClass(CCopyHook, cphkA, pcphkA);
  106. return CCopyHook_Release(&this->cphk);
  107. }
  108. STDMETHODIMP_(UINT) CCopyHookA_CopyCallback(ICopyHookA *pcphkA, HWND hwnd, UINT wFunc, UINT wFlags,
  109. LPCSTR pszSrcFile, DWORD dwSrcAttribs, LPCSTR pszDestFile, DWORD dwDestAttribs)
  110. {
  111. WCHAR szSrcFileW[MAX_PATH];
  112. WCHAR szDestFileW[MAX_PATH];
  113. LPWSTR pszSrcFileW = NULL;
  114. LPWSTR pszDestFileW = NULL;
  115. CCopyHook *this = IToClass(CCopyHook, cphkA, pcphkA);
  116. if (pszSrcFile)
  117. {
  118. SHAnsiToUnicode(pszSrcFile, szSrcFileW, ARRAYSIZE(szSrcFileW));
  119. pszSrcFileW = szSrcFileW;
  120. }
  121. if (pszDestFile)
  122. {
  123. SHAnsiToUnicode(pszDestFile, szDestFileW, ARRAYSIZE(szDestFileW));
  124. pszDestFileW = szDestFileW;
  125. }
  126. return CCopyHook_CopyCallback(&this->cphk, hwnd, wFunc, wFlags,
  127. pszSrcFileW, dwSrcAttribs,
  128. pszDestFileW, dwDestAttribs);
  129. }
  130. ICopyHookAVtbl c_CCopyHookAVtbl = {
  131. CCopyHookA_QueryInterface, CCopyHookA_AddRef, CCopyHookA_Release,
  132. CCopyHookA_CopyCallback,
  133. };
  134. STDAPI SHCreateShellCopyHook(ICopyHook **pcphkOut, REFIID riid)
  135. {
  136. HRESULT hres = E_OUTOFMEMORY; // assume error;
  137. CCopyHook *pcphk = (void*)LocalAlloc(LPTR, SIZEOF(CCopyHook));
  138. if (pcphk)
  139. {
  140. pcphk->cphk.lpVtbl = &c_CCopyHookVtbl;
  141. pcphk->cphkA.lpVtbl = &c_CCopyHookAVtbl;
  142. pcphk->cRef = 1;
  143. hres = CCopyHook_QueryInterface(&pcphk->cphk, riid, pcphkOut);
  144. CCopyHook_Release(&pcphk->cphk);
  145. }
  146. return hres;
  147. }
  148. HRESULT CCopyHook_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  149. {
  150. return SHCreateShellCopyHook((ICopyHook **)ppv, riid);
  151. }
  152. // create the HDSA of copyhook objects
  153. HDSA CreateCopyHooks(LPCTSTR pszKey)
  154. {
  155. HDSA hdsaCopyHooks = DSA_Create(SIZEOF(CALLABLECOPYHOOK), 4);
  156. if (hdsaCopyHooks)
  157. {
  158. HKEY hk;
  159. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, pszKey, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hk))
  160. {
  161. int i;
  162. TCHAR szKey[128];
  163. // iterate through the subkeys
  164. for (i = 0; RegEnumKey(hk, i, szKey, ARRAYSIZE(szKey)) == ERROR_SUCCESS; ++i)
  165. {
  166. TCHAR szCLSID[128];
  167. DWORD cb = sizeof(szCLSID);
  168. // for each subkey, get the class id and do a cocreateinstance
  169. if (SHRegGetValue(hk, szKey, NULL, SRRF_RT_REG_SZ, NULL, szCLSID, &cb) == ERROR_SUCCESS)
  170. {
  171. IUnknown *punk;
  172. HRESULT hres = SHExtCoCreateInstance(szCLSID, NULL, NULL, &IID_IUnknown, &punk);
  173. if (SUCCEEDED(hres))
  174. {
  175. CALLABLECOPYHOOK cc;
  176. SHPinDllOfCLSIDStr(szCLSID);
  177. cc.pcphk = NULL;
  178. cc.fAnsiCrossOver = FALSE;
  179. hres = punk->lpVtbl->QueryInterface(punk, &IID_IShellCopyHook, &cc.pcphk);
  180. if (SUCCEEDED(hres))
  181. {
  182. DSA_AppendItem(hdsaCopyHooks, &cc);
  183. }
  184. else
  185. {
  186. hres = punk->lpVtbl->QueryInterface(punk, &IID_IShellCopyHookA, &cc.pcphk);
  187. if (SUCCEEDED(hres))
  188. {
  189. cc.fAnsiCrossOver = TRUE;
  190. DSA_AppendItem(hdsaCopyHooks, &cc);
  191. }
  192. }
  193. punk->lpVtbl->Release(punk);
  194. }
  195. }
  196. }
  197. RegCloseKey(hk);
  198. }
  199. }
  200. return hdsaCopyHooks;
  201. }
  202. int CallCopyHooks(HDSA *phdsaHooks, LPCTSTR pszKey, HWND hwnd, UINT wFunc, FILEOP_FLAGS fFlags,
  203. LPCTSTR pszSrcFile, DWORD dwSrcAttribs, LPCTSTR pszDestFile, DWORD dwDestAttribs)
  204. {
  205. int i;
  206. if (!*phdsaHooks)
  207. {
  208. HDSA hdsaTemp = CreateCopyHooks(pszKey);
  209. if (hdsaTemp == NULL)
  210. return IDYES;
  211. // we don't hold a CritSection when doing the above to avoid deadlocks,
  212. // now we need to atomicaly store our results. if someone beat us to this
  213. // we free the hdsa we created. SHInterlockedCompareExchange does this for us
  214. // letting us know where there is a race condition so we can free the dup copy
  215. if (SHInterlockedCompareExchange((void **)phdsaHooks, hdsaTemp, 0))
  216. {
  217. // some other thread raced with us, blow this away now
  218. _CopyHookTerminate(hdsaTemp, FALSE);
  219. }
  220. }
  221. for (i = DSA_GetItemCount(*phdsaHooks) - 1; i >= 0; i--)
  222. {
  223. int iReturn;
  224. CALLABLECOPYHOOK *pcc = (CALLABLECOPYHOOK *)DSA_GetItemPtr(*phdsaHooks, i);
  225. if (!pcc->fAnsiCrossOver)
  226. {
  227. iReturn = pcc->pcphk->lpVtbl->CopyCallback(pcc->pcphk,
  228. hwnd, wFunc, fFlags, pszSrcFile, dwSrcAttribs, pszDestFile, dwDestAttribs);
  229. }
  230. else
  231. {
  232. CHAR szSrcFileA[MAX_PATH];
  233. CHAR szDestFileA[MAX_PATH];
  234. LPSTR pszSrcFileA = NULL;
  235. LPSTR pszDestFileA = NULL;
  236. ICopyHookA *pcphkA = (LPCOPYHOOKA)pcc->pcphk;
  237. if (pszSrcFile)
  238. {
  239. SHUnicodeToAnsi(pszSrcFile, szSrcFileA, ARRAYSIZE(szSrcFileA));
  240. pszSrcFileA = szSrcFileA;
  241. }
  242. if (pszDestFile)
  243. {
  244. SHUnicodeToAnsi(pszDestFile, szDestFileA, ARRAYSIZE(szDestFileA));
  245. pszDestFileA = szDestFileA;
  246. }
  247. iReturn = pcphkA->lpVtbl->CopyCallback(pcphkA,
  248. hwnd, wFunc, fFlags,
  249. pszSrcFileA, dwSrcAttribs,
  250. pszDestFileA, dwDestAttribs);
  251. }
  252. if (iReturn != IDYES)
  253. return iReturn;
  254. }
  255. return IDYES;
  256. }
  257. // These need to be per-instance since we are storing interfaces pointers
  258. HDSA g_hdsaFileCopyHooks = NULL;
  259. HDSA g_hdsaPrinterCopyHooks = NULL;
  260. int CallFileCopyHooks(HWND hwnd, UINT wFunc, FILEOP_FLAGS fFlags,
  261. LPCTSTR pszSrcFile, DWORD dwSrcAttribs, LPCTSTR pszDestFile, DWORD dwDestAttribs)
  262. {
  263. return CallCopyHooks(&g_hdsaFileCopyHooks, STRREG_SHEX_COPYHOOK, hwnd,
  264. wFunc, fFlags, pszSrcFile, dwSrcAttribs, pszDestFile, dwDestAttribs);
  265. }
  266. int CallPrinterCopyHooks(HWND hwnd, UINT wFunc, PRINTEROP_FLAGS fFlags,
  267. LPCTSTR pszSrcPrinter, DWORD dwSrcAttribs, LPCTSTR pszDestPrinter, DWORD dwDestAttribs)
  268. {
  269. return CallCopyHooks(&g_hdsaPrinterCopyHooks, STRREG_SHEX_PRNCOPYHOOK, hwnd,
  270. wFunc, fFlags, pszSrcPrinter, dwSrcAttribs, pszDestPrinter, dwDestAttribs);
  271. }
  272. //
  273. // We will only call this on process detach, and these are per-process
  274. // globals, so we do not need a critical section here
  275. //
  276. // This function is also called from CreateCopyHooks when the second
  277. // thread is cleaning up its local hdsaCopyHoos, which does not require
  278. // a critical section either.
  279. //
  280. void _CopyHookTerminate(HDSA hdsaCopyHooks, BOOL fProcessDetach)
  281. {
  282. // Note that we must no call any of virtual functions when we are
  283. // processing PROCESS_DETACH signal, because the DLL might have been
  284. // already unloaded before shell32. We just hope that they don't
  285. // allocate any global thing to be cleaned. USER does the same thing
  286. // with undestroyed window. It does not send call its window procedure
  287. // when it is destroying an undestroyed window within its PROCESS_DETACH
  288. // code. (SatoNa/DavidDS)
  289. //
  290. if (!fProcessDetach)
  291. {
  292. int i;
  293. for (i = DSA_GetItemCount(hdsaCopyHooks) - 1; i >= 0; i--)
  294. {
  295. CALLABLECOPYHOOK *pcc = (CALLABLECOPYHOOK *)DSA_GetItemPtr(hdsaCopyHooks, i);
  296. pcc->pcphk->lpVtbl->Release(pcc->pcphk);
  297. }
  298. }
  299. DSA_Destroy(hdsaCopyHooks);
  300. }
  301. // called from ProcessDetatch
  302. // NOTE: we are seralized at this point, don't need critical sections
  303. void CopyHooksTerminate(void)
  304. {
  305. ASSERTDLLENTRY; // does not require a critical section
  306. if (g_hdsaFileCopyHooks)
  307. {
  308. _CopyHookTerminate(g_hdsaFileCopyHooks, TRUE);
  309. g_hdsaFileCopyHooks = NULL;
  310. }
  311. if (g_hdsaPrinterCopyHooks)
  312. {
  313. _CopyHookTerminate(g_hdsaPrinterCopyHooks, TRUE);
  314. g_hdsaPrinterCopyHooks = NULL;
  315. }
  316. }