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.

305 lines
8.6 KiB

  1. //
  2. // Copy Hook Handler for CDFView shell extension
  3. //
  4. // Description:
  5. // This object installs an ICopyHook handler that traps all
  6. // copies/movies/renames in the shell so that we can special
  7. // case links to channel objects and unsubscribe them when
  8. // the link is deleted. The implementation is in shdocvw for
  9. // speed.
  10. //
  11. // julianj 6/16/97
  12. //
  13. #include "priv.h"
  14. #include "sccls.h"
  15. #include "chanmgr.h"
  16. #include "channel.h"
  17. #include "../resource.h"
  18. #include <mluisupp.h>
  19. class CCDFCopyHook
  20. : public ICopyHookA
  21. , public ICopyHookW
  22. {
  23. public:
  24. // *** IUnknown ***
  25. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  26. STDMETHODIMP_(ULONG) AddRef(void);
  27. STDMETHODIMP_(ULONG) Release(void);
  28. // *** ICopyHookA method ***
  29. STDMETHODIMP_(UINT) CopyCallback(HWND hwnd,
  30. UINT wFunc, UINT wFlags, LPCSTR pszSrcFile, DWORD dwSrcAttribs, LPCSTR pszDestFile, DWORD dwDestAttribs);
  31. // *** ICopyHookW method ***
  32. STDMETHODIMP_(UINT) CopyCallback(HWND hwnd,
  33. UINT wFunc, UINT wFlags, LPCWSTR pwzSrcFile, DWORD dwSrcAttribs, LPCWSTR pwzDestFile, DWORD dwDestAttribs);
  34. private:
  35. CCDFCopyHook( HRESULT * pHr);
  36. ~CCDFCopyHook();
  37. BOOL IsSubscriptionFolder(LPCTSTR pszPath);
  38. LONG m_cRef;
  39. friend HRESULT CCDFCopyHook_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi); // for ctor
  40. };
  41. //The copyhook handler uses this function
  42. HRESULT Channel_GetFolder(LPTSTR pszPath, int cchPath)
  43. {
  44. TCHAR szChannel[MAX_PATH];
  45. TCHAR szFav[MAX_PATH];
  46. ULONG cbChannel = sizeof(szChannel);
  47. if (SHGetSpecialFolderPath(NULL, szFav, CSIDL_FAVORITES, TRUE))
  48. {
  49. //
  50. // Get the potentially localized name of the Channel folder from the
  51. // registry if it is there. Otherwise just read it from the resource.
  52. // Then tack this on the favorites path.
  53. //
  54. if (ERROR_SUCCESS != SHRegGetUSValue(L"Software\\Microsoft\\Windows\\CurrentVersion",
  55. L"ChannelFolderName", NULL, (void*)szChannel,
  56. &cbChannel, TRUE, NULL, 0))
  57. {
  58. MLLoadString(IDS_CHANNEL, szChannel, ARRAYSIZE(szChannel));
  59. }
  60. PathCombine(pszPath, szFav, szChannel);
  61. //
  62. // For IE5+ use the channels dir if it exists - else use favorites
  63. //
  64. if (!PathFileExists(pszPath))
  65. StrCpyN(pszPath, szFav, cchPath);
  66. return S_OK;
  67. }
  68. return E_FAIL;
  69. }
  70. //
  71. // Basic CreateInstance for this object
  72. //
  73. HRESULT CCDFCopyHook_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  74. {
  75. if ( pUnkOuter )
  76. return CLASS_E_NOAGGREGATION;
  77. HRESULT hr = NOERROR;
  78. CCDFCopyHook * pCDFCopyHook = new CCDFCopyHook( & hr );
  79. if ( !pCDFCopyHook )
  80. {
  81. return E_OUTOFMEMORY;
  82. }
  83. if ( FAILED( hr ))
  84. {
  85. delete pCDFCopyHook;
  86. return hr;
  87. }
  88. *ppunk = SAFECAST(pCDFCopyHook, ICopyHookA *);
  89. return NOERROR;
  90. }
  91. STDMETHODIMP CCDFCopyHook::QueryInterface( REFIID riid, LPVOID * ppvObj )
  92. {
  93. if (IsEqualIID(riid, IID_IUnknown) ||
  94. IsEqualIID(riid, IID_IShellCopyHookA))
  95. {
  96. *ppvObj = SAFECAST(this, ICopyHookA *);
  97. }
  98. else if (IsEqualIID(riid, IID_IShellCopyHookW))
  99. {
  100. *ppvObj = SAFECAST(this, ICopyHookW *);
  101. }
  102. else
  103. {
  104. *ppvObj = NULL;
  105. return E_NOINTERFACE;
  106. }
  107. AddRef();
  108. return NOERROR;
  109. }
  110. STDMETHODIMP_ (ULONG) CCDFCopyHook::AddRef()
  111. {
  112. return InterlockedIncrement(&m_cRef);
  113. }
  114. STDMETHODIMP_ (ULONG) CCDFCopyHook::Release()
  115. {
  116. if (InterlockedDecrement(&m_cRef))
  117. return m_cRef;
  118. delete this;
  119. return 0;
  120. }
  121. CCDFCopyHook::CCDFCopyHook( HRESULT * pHr) : m_cRef(1)
  122. {
  123. *pHr = S_OK;
  124. DllAddRef();
  125. }
  126. CCDFCopyHook::~CCDFCopyHook()
  127. {
  128. DllRelease();
  129. }
  130. ////////////////////////////////////////////////////////////////////////////////
  131. //
  132. // ICopyHookA::CopyCallback
  133. //
  134. // Either allows the shell to move, copy, delete, or rename a folder or printer
  135. // object, or disallows the shell from carrying out the operation. The shell
  136. // calls each copy hook handler registered for a folder or printer object until
  137. // either all the handlers have been called or one of them returns IDCANCEL.
  138. //
  139. // RETURNS:
  140. //
  141. // IDYES - Allows the operation.
  142. // IDNO - Prevents the operation on this file, but continues with any other
  143. // operations (for example, a batch copy operation).
  144. // IDCANCEL - Prevents the current operation and cancels any pending operations
  145. //
  146. ////////////////////////////////////////////////////////////////////////////////
  147. UINT CCDFCopyHook::CopyCallback(
  148. HWND hwnd, // Handle of the parent window for displaying UI objects
  149. UINT wFunc, // Operation to perform.
  150. UINT wFlags, // Flags that control the operation
  151. LPCSTR pszSrcFile, // Pointer to the source file
  152. DWORD dwSrcAttribs, // Source file attributes
  153. LPCSTR pszDestFile, // Pointer to the destination file
  154. DWORD dwDestAttribs // Destination file attributes
  155. )
  156. {
  157. WCHAR szSrcFile[MAX_PATH];
  158. WCHAR szDestFile[MAX_PATH];
  159. AnsiToUnicode(pszSrcFile, szSrcFile, ARRAYSIZE(szSrcFile));
  160. if (pszDestFile) // shell32.dll can call with NULL for pszDestFile
  161. AnsiToUnicode(pszDestFile, szDestFile, ARRAYSIZE(szDestFile));
  162. else
  163. szDestFile[0] = L'\0';
  164. return CopyCallback(hwnd, wFunc, wFlags, szSrcFile, dwSrcAttribs, szSrcFile, dwDestAttribs);
  165. }
  166. CCDFCopyHook::IsSubscriptionFolder(LPCTSTR pszPath)
  167. {
  168. TCHAR szSubsPath[MAX_PATH] = {0};
  169. DWORD dwSize = SIZEOF(szSubsPath);
  170. if (SHGetValueGoodBoot(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION,
  171. REGSTR_VAL_DIRECTORY, NULL, (LPBYTE)szSubsPath, &dwSize) != ERROR_SUCCESS)
  172. {
  173. TCHAR szWindows[MAX_PATH];
  174. GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
  175. PathCombine(szSubsPath, szWindows, TEXT("Offline Web Pages"));
  176. }
  177. return 0 == StrCmpI(pszPath, szSubsPath);
  178. }
  179. ////////////////////////////////////////////////////////////////////////////////
  180. //
  181. // ICopyHookW::CopyCallback
  182. //
  183. // Currently we just thunk to the ansi version.
  184. //
  185. ////////////////////////////////////////////////////////////////////////////////
  186. UINT CCDFCopyHook::CopyCallback(
  187. HWND hwnd, // Handle of the parent window for displaying UI objects
  188. UINT wFunc, // Operation to perform.
  189. UINT wFlags, // Flags that control the operation
  190. LPCWSTR pszSrcFile, // Pointer to the source file
  191. DWORD dwSrcAttribs, // Source file attributes
  192. LPCWSTR pszDestFile, // Pointer to the destination file
  193. DWORD dwDestAttribs // Destination file attributes
  194. )
  195. {
  196. HRESULT hr;
  197. ICopyHookA * pCDFViewCopyHookA;
  198. TCHAR szPath[MAX_PATH];
  199. //
  200. // Return immediately if this isn't a system folder or if isn't a delete or
  201. // rename operation
  202. //
  203. if (!(wFunc == FO_DELETE || wFunc == FO_RENAME))
  204. {
  205. return IDYES;
  206. }
  207. // no rename of channels folder allowed.
  208. if ((wFunc == FO_RENAME)
  209. && (Channel_GetFolder(szPath, ARRAYSIZE(szPath)) == S_OK)
  210. && (StrCmpI(szPath, pszSrcFile) == 0))
  211. {
  212. MessageBeep(MB_OK);
  213. return IDNO;
  214. }
  215. if (SHRestricted2W(REST_NoRemovingSubscriptions, NULL, 0) &&
  216. IsSubscriptionFolder(pszSrcFile))
  217. {
  218. MessageBeep(MB_OK);
  219. return IDNO;
  220. }
  221. if (!(dwSrcAttribs & FILE_ATTRIBUTE_SYSTEM))
  222. return IDYES;
  223. //
  224. // REVIEW could check for guid in desktop.ini matching CDFVIEW but its
  225. // cleaner to have the ChannelMgr know about that
  226. //
  227. //
  228. // Create the channel manager object and ask it for the copy hook iface
  229. //
  230. hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
  231. IID_IShellCopyHookA, (void**)&pCDFViewCopyHookA);
  232. if (SUCCEEDED(hr))
  233. {
  234. //
  235. // Delegate to the Copy hook handler in the channel mgr
  236. //
  237. CHAR szSrcFile[MAX_PATH];
  238. CHAR szDestFile[MAX_PATH] = {'\0'};
  239. SHUnicodeToAnsi(pszSrcFile, szSrcFile, ARRAYSIZE(szSrcFile));
  240. if (pszDestFile)
  241. SHUnicodeToAnsi(pszDestFile, szDestFile, ARRAYSIZE(szDestFile));
  242. UINT retValue = pCDFViewCopyHookA->CopyCallback(
  243. hwnd, wFunc, wFlags, szSrcFile,
  244. dwSrcAttribs, szDestFile, dwDestAttribs);
  245. pCDFViewCopyHookA->Release();
  246. return retValue;
  247. }
  248. else
  249. {
  250. // Couldn't create ChannelMgr object for some reason
  251. TraceMsg(TF_ERROR, "Could not CoCreateInstance CLSID_ChannelMgr");
  252. return IDYES;
  253. }
  254. }