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.

501 lines
14 KiB

  1. /*
  2. * isbase.cpp - IUnknown implementation for Intshcut class.
  3. */
  4. #include "priv.h"
  5. #include "sccls.h"
  6. #include "ishcut.h"
  7. HRESULT IsProtocolRegistered(LPCTSTR pcszProtocol)
  8. {
  9. HRESULT hres = S_OK;
  10. ASSERT(IS_VALID_STRING_PTR(pcszProtocol, -1));
  11. if (NO_ERROR != SHGetValue(HKEY_CLASSES_ROOT, pcszProtocol, TEXT("URL Protocol"),
  12. NULL, NULL, NULL))
  13. {
  14. TraceMsg(TF_ERROR, "IsProtocolRegistered(): Protocol \"%s\" is not registered.",
  15. pcszProtocol);
  16. hres = URL_E_UNREGISTERED_PROTOCOL;
  17. }
  18. return hres;
  19. }
  20. /*----------------------------------------------------------
  21. Purpose: Takes the given URL and returns an allocated string
  22. containing the protocol. Also optionally returns the
  23. parsed-url structure.
  24. Returns: S_OK if the URL was parsed
  25. Cond: --
  26. */
  27. STDAPI
  28. CopyURLProtocol(
  29. IN LPCTSTR pcszURL,
  30. OUT LPTSTR * ppszProtocol,
  31. OUT PARSEDURL * ppu) OPTIONAL
  32. {
  33. HRESULT hr;
  34. PARSEDURL pu;
  35. ASSERT(IS_VALID_STRING_PTR(pcszURL, -1));
  36. ASSERT(IS_VALID_WRITE_PTR(ppszProtocol, PTSTR));
  37. if (NULL == ppu)
  38. ppu = &pu;
  39. *ppszProtocol = NULL;
  40. ppu->cbSize = SIZEOF(*ppu);
  41. hr = ParseURL(pcszURL, ppu);
  42. if (hr == S_OK)
  43. {
  44. *ppszProtocol = (LPTSTR)LocalAlloc(LPTR, CbFromCch(ppu->cchProtocol + 1));
  45. if (*ppszProtocol)
  46. {
  47. // Just copy the protocol portion of string
  48. StrCpyN(*ppszProtocol, ppu->pszProtocol, ppu->cchProtocol + 1);
  49. }
  50. else
  51. {
  52. hr = E_OUTOFMEMORY;
  53. }
  54. }
  55. ASSERT(FAILED(hr) ||
  56. (hr == S_OK &&
  57. IS_VALID_STRING_PTR(*ppszProtocol, -1)));
  58. return(hr);
  59. }
  60. HRESULT ValidateURL(LPCTSTR pcszURL)
  61. {
  62. HRESULT hr;
  63. LPTSTR pszProtocol;
  64. ASSERT(IS_VALID_STRING_PTR(pcszURL, -1));
  65. hr = CopyURLProtocol(pcszURL, &pszProtocol, NULL);
  66. if (hr == S_OK)
  67. {
  68. hr = IsProtocolRegistered(pszProtocol);
  69. LocalFree(pszProtocol);
  70. pszProtocol = NULL;
  71. }
  72. return(hr);
  73. }
  74. #define SUBS_DEL_TIMEOUT 3000
  75. void DeleteSubsOnShortcutDelete(void *pData, BOOLEAN)
  76. {
  77. IS_SUBS_DEL_DATA *pSubsDelData = (IS_SUBS_DEL_DATA *)pData;
  78. ASSERT(NULL != pData);
  79. ASSERT(0 != pSubsDelData->m_szFile[0]);
  80. ASSERT(0 != pSubsDelData->m_pwszURL[0]);
  81. if ((((DWORD)-1) == GetFileAttributes(pSubsDelData->m_szFile)) &&
  82. (ERROR_FILE_NOT_FOUND == GetLastError()))
  83. {
  84. if (SUCCEEDED(CoInitialize(NULL)))
  85. {
  86. ISubscriptionMgr2 *pSubsMgr2;
  87. if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr,
  88. NULL,
  89. CLSCTX_INPROC_SERVER,
  90. IID_ISubscriptionMgr2,
  91. (void **)&pSubsMgr2)))
  92. {
  93. pSubsMgr2->DeleteSubscription(pSubsDelData->m_pwszURL, NULL);
  94. pSubsMgr2->Release();
  95. }
  96. CoUninitialize();
  97. }
  98. }
  99. delete pSubsDelData;
  100. }
  101. #ifdef DEBUG
  102. BOOL IsValidPCIntshcut(PCIntshcut pcintshcut)
  103. {
  104. return(IS_VALID_READ_PTR(pcintshcut, CIntshcut) &&
  105. FLAGS_ARE_VALID(pcintshcut->m_dwFlags, ISF_ALL) &&
  106. (! pcintshcut->m_pszFile ||
  107. IS_VALID_STRING_PTR(pcintshcut->m_pszFile, -1)) &&
  108. EVAL(! pcintshcut->m_pszFolder ||
  109. IsValidPath(pcintshcut->m_pszFolder)) &&
  110. EVAL(! pcintshcut->m_pprop ||
  111. IS_VALID_STRUCT_PTR(pcintshcut->m_pprop, CIntshcutProp)) &&
  112. EVAL(! pcintshcut->m_psiteprop ||
  113. IS_VALID_STRUCT_PTR(pcintshcut->m_psiteprop, CIntsiteProp)));
  114. }
  115. #endif
  116. Intshcut::Intshcut(void) : m_cRef(1)
  117. {
  118. DllAddRef();
  119. // Intshcut objects should always be allocated
  120. ASSERT(ISF_DEFAULT == m_dwFlags);
  121. ASSERT(NULL == m_pszFile);
  122. ASSERT(NULL == m_pszFolder);
  123. ASSERT(NULL == m_pprop);
  124. ASSERT(NULL == m_psiteprop);
  125. ASSERT(NULL == _punkSite);
  126. ASSERT(NULL == m_pszTempFileName);
  127. ASSERT(NULL == m_pszDescription);
  128. ASSERT(NULL == m_pszFileToLoad);
  129. ASSERT(!m_fMustLoadSync);
  130. ASSERT(!m_bCheckForDelete);
  131. // Init our registered data formats
  132. InitClipboardFormats();
  133. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  134. return;
  135. }
  136. Intshcut::~Intshcut(void)
  137. {
  138. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  139. if (m_bCheckForDelete)
  140. {
  141. if (NULL != m_pszFile)
  142. {
  143. IS_SUBS_DEL_DATA *pSubsDelData = new IS_SUBS_DEL_DATA;
  144. if (NULL != pSubsDelData)
  145. {
  146. HRESULT hr = GetURL(&pSubsDelData->m_pwszURL);
  147. if (SUCCEEDED(hr))
  148. {
  149. hr = StringCchCopy(pSubsDelData->m_szFile, ARRAYSIZE(pSubsDelData->m_szFile), m_pszFile);
  150. if (SUCCEEDED(hr))
  151. {
  152. HANDLE hTimer = SHSetTimerQueueTimer(NULL,
  153. DeleteSubsOnShortcutDelete,
  154. pSubsDelData,
  155. SUBS_DEL_TIMEOUT,
  156. 0,
  157. NULL,
  158. FALSE);
  159. if (NULL == hTimer)
  160. {
  161. hr = E_FAIL;
  162. }
  163. }
  164. }
  165. if (FAILED(hr))
  166. {
  167. delete pSubsDelData;
  168. }
  169. }
  170. }
  171. else
  172. {
  173. ASSERT(FALSE); // m_bCheckForDelete only gets set to TRUE in the context menu code
  174. }
  175. }
  176. Str_SetPtr(&m_pszFile, NULL);
  177. Str_SetPtr(&m_pszFileToLoad, NULL);
  178. if (m_pprop)
  179. {
  180. delete m_pprop;
  181. m_pprop = NULL;
  182. }
  183. if (m_psiteprop)
  184. {
  185. delete m_psiteprop;
  186. m_psiteprop = NULL;
  187. }
  188. if (m_pInitDataObject)
  189. {
  190. m_pInitDataObject->Release();
  191. m_pInitDataObject = NULL;
  192. }
  193. SetSite(NULL);
  194. if(m_pszTempFileName)
  195. {
  196. DeleteFile(m_pszTempFileName);
  197. Str_SetPtr(&m_pszTempFileName, NULL);
  198. }
  199. Str_SetPtr(&m_pszFolder, NULL);
  200. Str_SetPtr(&m_pszDescription, NULL);
  201. ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut));
  202. ATOMICRELEASE(_punkLink);
  203. DllRelease();
  204. return;
  205. }
  206. /*----------------------------------------------------------
  207. Purpose: IUnknown::QueryInterface handler for Intshcut
  208. Returns:
  209. Cond: --
  210. */
  211. STDMETHODIMP Intshcut::QueryInterface(REFIID riid, PVOID *ppvObj)
  212. {
  213. // We try and delay when we load the file specified by IPersistFile::Load
  214. // until someone asks for an interface that actually needs that file.
  215. // So put the "safe" interfaces that don't require this in this first
  216. // table here, and all the "must load" interfaces in the second table:
  217. //
  218. static const QITAB qitDontLoad[] = {
  219. QITABENT(Intshcut, IExtractIconW), // IID_IExtractIconW
  220. QITABENT(Intshcut, IExtractIconA), // IID_IExtractIconA
  221. QITABENT(Intshcut, IPersistFile), // IID_IPersistFile
  222. QITABENTMULTI(Intshcut, IPersist, IPersistFile), // IID_IPersist
  223. { 0 },
  224. };
  225. static const QITAB qitMustLoad[] = {
  226. QITABENT(Intshcut, IContextMenu2), // IID_IContextMenu2
  227. QITABENTMULTI(Intshcut, IContextMenu, IContextMenu2), // IID_IContextMenu
  228. QITABENT(Intshcut, IDataObject), // IID_IDataObject
  229. QITABENT(Intshcut, INewShortcutHookW), // IID_INewShortcutHookW
  230. QITABENT(Intshcut, INewShortcutHookA), // IID_INewShortcutHookA
  231. QITABENT(Intshcut, IPersistStream), // IID_IPersistStream
  232. QITABENT(Intshcut, IPropertySetStorage),// IID_IPropertySetStorage
  233. QITABENT(Intshcut, IShellExtInit), // IID_IShellExtInit
  234. QITABENT(Intshcut, IShellLinkA), // IID_IShellLinkA
  235. QITABENT(Intshcut, IShellLinkW), // IID_IShellLinkW
  236. QITABENT(Intshcut, IShellPropSheetExt), // IID_IShellPropSheetExt
  237. QITABENT(Intshcut, IUniformResourceLocatorA), // IID_IUniformResourceLocatorA
  238. QITABENT(Intshcut, IUniformResourceLocatorW), // IID_IUniformResourceLocatorW
  239. QITABENT(Intshcut, IQueryInfo), // IID_IQueryInfo
  240. QITABENT(Intshcut, IQueryCodePage), // IID_IQueryCodePage
  241. QITABENT(Intshcut, INamedPropertyBag), // IID_INamedPropertyBag
  242. QITABENT(Intshcut, IObjectWithSite), // IID_IObjectWithSite
  243. QITABENT(Intshcut, IOleCommandTarget), // IID_IOleCommandTarget
  244. { 0 },
  245. };
  246. HRESULT hres = QISearch(this, qitDontLoad, riid, ppvObj);
  247. if (FAILED(hres))
  248. {
  249. hres = QISearch(this, qitMustLoad, riid, ppvObj);
  250. if (SUCCEEDED(hres))
  251. {
  252. m_fMustLoadSync = TRUE;
  253. if (m_pszFileToLoad)
  254. {
  255. LoadFromAsyncFileNow();
  256. }
  257. }
  258. }
  259. return hres;
  260. }
  261. STDMETHODIMP_(ULONG) Intshcut::AddRef()
  262. {
  263. return InterlockedIncrement(&m_cRef);
  264. }
  265. STDMETHODIMP_(ULONG) Intshcut::Release()
  266. {
  267. ASSERT( 0 != m_cRef );
  268. ULONG cRef = InterlockedDecrement(&m_cRef);
  269. if ( 0 == cRef )
  270. {
  271. delete this;
  272. }
  273. return cRef;
  274. }
  275. STDMETHODIMP Intshcut::InitProp()
  276. {
  277. HRESULT hres;
  278. if (m_pprop)
  279. hres = S_OK;
  280. else
  281. {
  282. m_pprop = new IntshcutProp;
  283. if (m_pprop)
  284. {
  285. // m_pszFile may be NULL here
  286. hres = m_pprop->InitFromFile(m_pszFile);
  287. if (FAILED(hres))
  288. {
  289. delete m_pprop;
  290. m_pprop = NULL;
  291. }
  292. }
  293. else
  294. hres = E_OUTOFMEMORY;
  295. }
  296. return hres;
  297. }
  298. STDMETHODIMP Intshcut::InitSiteProp(void)
  299. {
  300. HRESULT hres = InitProp();
  301. if (SUCCEEDED(hres))
  302. {
  303. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  304. hres = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
  305. if (NULL == m_psiteprop && SUCCEEDED( hres ))
  306. {
  307. m_psiteprop = new IntsiteProp;
  308. if (m_psiteprop)
  309. {
  310. hres = m_psiteprop->InitFromDB(szURL, this, TRUE);
  311. if (FAILED(hres))
  312. {
  313. delete m_psiteprop;
  314. m_psiteprop = NULL;
  315. }
  316. }
  317. else
  318. hres = E_OUTOFMEMORY;
  319. }
  320. }
  321. return hres;
  322. }
  323. /*----------------------------------------------------------
  324. Purpose: Only copy the property if it is different. Return
  325. TRUE if it was.
  326. */
  327. BOOL CopyChangedProperty(IntshcutProp * pprop, PROPID pid,
  328. IntsiteProp * psiteprop, PROPID pidSite,
  329. BOOL bCopyToDB)
  330. {
  331. BOOL bRet = FALSE;
  332. TCHAR szBuf[1024];
  333. TCHAR szBufSite[1024];
  334. pprop->GetProp(pid, szBuf, SIZECHARS(szBuf));
  335. psiteprop->GetProp(pidSite, szBufSite, SIZECHARS(szBufSite));
  336. StrTrim(szBuf, TEXT(" "));
  337. StrTrim(szBufSite, TEXT(" "));
  338. if (StrCmp(szBuf, szBufSite))
  339. {
  340. if (bCopyToDB)
  341. psiteprop->SetProp(pidSite, szBuf);
  342. else
  343. pprop->SetProp(pid, szBufSite);
  344. bRet = TRUE;
  345. }
  346. return bRet;
  347. }
  348. /*----------------------------------------------------------
  349. Purpose: Mirror the following properties between FMTID_INTSHCUT
  350. and FMTID_INTSITE:
  351. PID_IS_WHATSNEW <----> PID_INTSITE_WHATSNEW
  352. PID_IS_DESCRIPTION <----> PID_INTSITE_DESCRIPTION
  353. PID_IS_AUTHOR <----> PID_INTSITE_AUTHOR
  354. PID_IS_COMMENT <----> PID_INTSITE_COMMENT
  355. Returns:
  356. Cond: --
  357. */
  358. STDMETHODIMP Intshcut::MirrorProperties(void)
  359. {
  360. HRESULT hres = InitSiteProp();
  361. if (SUCCEEDED(hres))
  362. {
  363. STATPROPSETSTG statSite;
  364. STATPROPSETSTG stat;
  365. LONG lRet;
  366. // Get the times that the properties were set. The later
  367. // time becomes the source.
  368. m_psiteprop->Stat(&statSite);
  369. m_pprop->Stat(&stat);
  370. // Don't do anything if the times are equal
  371. lRet = CompareFileTime(&stat.mtime, &statSite.mtime);
  372. if (0 != lRet)
  373. {
  374. BOOL bChanged = FALSE;
  375. BOOL bCopyToDB = (0 < lRet);
  376. bChanged |= CopyChangedProperty(m_pprop, PID_IS_WHATSNEW, m_psiteprop, PID_INTSITE_WHATSNEW, bCopyToDB);
  377. bChanged |= CopyChangedProperty(m_pprop, PID_IS_DESCRIPTION, m_psiteprop, PID_INTSITE_DESCRIPTION, bCopyToDB);
  378. bChanged |= CopyChangedProperty(m_pprop, PID_IS_AUTHOR, m_psiteprop, PID_INTSITE_AUTHOR, bCopyToDB);
  379. bChanged |= CopyChangedProperty(m_pprop, PID_IS_COMMENT, m_psiteprop, PID_INTSITE_COMMENT, bCopyToDB);
  380. if (bChanged)
  381. {
  382. if (bCopyToDB)
  383. {
  384. m_psiteprop->SetTimes(&stat.mtime, NULL, NULL);
  385. m_psiteprop->Commit(STGC_DEFAULT);
  386. TraceMsg(TF_INTSHCUT, "Mirroring properties of %s to the central database", Dbg_SafeStr(m_pszFile));
  387. }
  388. else
  389. {
  390. m_pprop->SetTimes(&statSite.mtime, NULL, NULL);
  391. m_pprop->Commit(STGC_DEFAULT);
  392. TraceMsg(TF_INTSHCUT, "Mirroring properties of %s to the .url file", Dbg_SafeStr(m_pszFile));
  393. }
  394. }
  395. }
  396. hres = S_OK;
  397. }
  398. return hres;
  399. }
  400. STDMETHODIMP_(void) Intshcut::ChangeNotify(LONG wEventId, UINT uFlags)
  401. {
  402. if (m_pszFile)
  403. SHChangeNotify(wEventId, uFlags | SHCNF_PATH, m_pszFile, 0);
  404. }
  405. STDAPI
  406. CIntShcut_CreateInstance(
  407. IUnknown * punkOuter,
  408. IUnknown ** ppunk,
  409. LPCOBJECTINFO poi)
  410. {
  411. // aggregation checking is handled in class factory
  412. HRESULT hres = E_OUTOFMEMORY;
  413. Intshcut *pis = new Intshcut;
  414. if (pis)
  415. {
  416. *ppunk = SAFECAST(pis, IDataObject *);
  417. hres = S_OK;
  418. }
  419. return hres;
  420. }