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.

388 lines
13 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. /*-----------------------------------------------------------------------------
  4. / Misc data
  5. /----------------------------------------------------------------------------*/
  6. static UINT g_cfDsPropPageInfo = 0;
  7. #define PATH_IS TEXT("?path=")
  8. #define PROPERTY_PAGES_ROOT TEXT("PropertyPagesRoot")
  9. class CDsPropPageDataObject : public IDataObject
  10. {
  11. private:
  12. LONG _cRef;
  13. IDataObject* _pDataObject;
  14. LPWSTR _pParameters;
  15. public:
  16. CDsPropPageDataObject(IDataObject* pDataObject, LPWSTR pParameters);
  17. ~CDsPropPageDataObject();
  18. // IUnknown
  19. STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject);
  20. STDMETHOD_(ULONG, AddRef)();
  21. STDMETHOD_(ULONG, Release)();
  22. // IDataObject
  23. STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
  24. STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
  25. { return _pDataObject->GetDataHere(pformatetc, pmedium); }
  26. STDMETHODIMP QueryGetData(FORMATETC *pformatetc)
  27. { return _pDataObject->QueryGetData(pformatetc); }
  28. STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
  29. { return _pDataObject->GetCanonicalFormatEtc(pformatectIn, pformatetcOut); }
  30. STDMETHODIMP SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
  31. { return _pDataObject->SetData(pformatetc, pmedium, fRelease); }
  32. STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
  33. { return _pDataObject->EnumFormatEtc(dwDirection, ppenumFormatEtc); }
  34. STDMETHODIMP DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
  35. { return _pDataObject->DAdvise(pformatetc, advf, pAdvSink, pdwConnection); }
  36. STDMETHODIMP DUnadvise(DWORD dwConnection)
  37. { return _pDataObject->DUnadvise(dwConnection); }
  38. STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
  39. { return _pDataObject->EnumDAdvise(ppenumAdvise); }
  40. };
  41. /*-----------------------------------------------------------------------------
  42. / Tab Collector bits
  43. /----------------------------------------------------------------------------*/
  44. /*-----------------------------------------------------------------------------
  45. / TabCollector_AddPages
  46. / ---------------------
  47. / Given a string that represents a page reference add the pages required
  48. / to support that reference
  49. /
  50. / In:
  51. / pPageReference -> string reperesenting the page
  52. / pDsObjectName -> ADs path of object
  53. / pDataObject -> data object interface for the Win32 extensions
  54. / lpfnAddPage, lParam => parameters used for adding each page
  55. /
  56. / Out:
  57. / HRESULT
  58. /----------------------------------------------------------------------------*/
  59. HRESULT TabCollector_AddPages(LPWSTR pPageReference, LPWSTR pDsObjectName,
  60. IUnknown* punkSite, IDataObject* pDataObject,
  61. LPFNADDPROPSHEETPAGE pAddPageProc, LPARAM lParam)
  62. {
  63. HRESULT hres;
  64. HPROPSHEETPAGE hPage;
  65. IUnknown* pUnknown = NULL;
  66. IShellExtInit* pShellExtInit = NULL;
  67. IShellPropSheetExt* pShellPropSheetExt = NULL;
  68. IObjectWithSite *pows = NULL;
  69. WCHAR szBuffer[MAX_PATH];
  70. WCHAR szGUID[MAX_PATH];
  71. WCHAR szURL[INTERNET_MAX_URL_LENGTH];
  72. LPTSTR pAbsoluteURL = NULL;
  73. USES_CONVERSION;
  74. GUID guid;
  75. TraceEnter(TRACE_TABS, "TabCollector_AddPages");
  76. Trace(TEXT("Page reference is %s"), W2T(pPageReference));
  77. // The name is either a CLSID, or a URL description. Therefore lets try and
  78. // parse it as a GUID, if that fails then we can just attempt to break out the
  79. // other components.
  80. if ( SUCCEEDED(GetStringElementW(pPageReference, 0, szGUID, ARRAYSIZE(szGUID))) &&
  81. GetGUIDFromStringW(pPageReference, &guid) )
  82. {
  83. if ( SUCCEEDED(CoCreateInstance(guid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (LPVOID*)&pUnknown)) )
  84. {
  85. // We have found the object, lets try and initialize it passing it the data
  86. // object we have, if that fails then we ignore this entry.
  87. if ( punkSite && SUCCEEDED(pUnknown->QueryInterface(IID_IObjectWithSite, (void **)&pows)) )
  88. {
  89. hres = pows->SetSite(punkSite);
  90. FailGracefully(hres, "Failed when setting site on the object");
  91. }
  92. if ( SUCCEEDED(pUnknown->QueryInterface(IID_IShellExtInit, (LPVOID*)&pShellExtInit)) )
  93. {
  94. if ( SUCCEEDED(GetStringElementW(pPageReference, 1, szBuffer, ARRAYSIZE(szBuffer))) && szBuffer[0] )
  95. {
  96. CDsPropPageDataObject* pDsPropPageDataObject = new CDsPropPageDataObject(pDataObject, szBuffer);
  97. TraceAssert(pDsPropPageDataObject);
  98. if ( !pDsPropPageDataObject )
  99. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate IDataObject wrapper");
  100. Trace(TEXT("IDsPropPageDataObject constructed with: %s"), szBuffer);
  101. hres = pShellExtInit->Initialize(NULL, pDsPropPageDataObject, NULL);
  102. pDsPropPageDataObject->Release();
  103. }
  104. else
  105. {
  106. TraceMsg("No extra parameters for property page, invoking with original IDataObject");
  107. hres = pShellExtInit->Initialize(NULL, pDataObject, NULL);
  108. }
  109. DoRelease(pShellExtInit);
  110. if ( FAILED(hres) )
  111. ExitGracefully(hres, S_OK, "Failed to Initialize the Win32 extension - PAGE IGNORED");
  112. }
  113. // We have tried to Initialize the object, so lets get it to add the pages if it
  114. // supports the IShellPropSheetExt interface.
  115. if ( SUCCEEDED(pUnknown->QueryInterface(IID_IShellPropSheetExt, (LPVOID*)&pShellPropSheetExt)) )
  116. {
  117. hres = pShellPropSheetExt->AddPages(pAddPageProc, lParam);
  118. DoRelease(pShellPropSheetExt);
  119. if (hres == HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP))
  120. FailGracefully(hres, "Cannot talk to the DC");
  121. }
  122. }
  123. else
  124. {
  125. TraceGUID("Failed to CoCreateInstance ", guid);
  126. }
  127. }
  128. else
  129. {
  130. ExitGracefully(hres, E_NOTIMPL, "HTML property pages are not supported");
  131. }
  132. hres = S_OK; // success
  133. exit_gracefully:
  134. LocalFreeString(&pAbsoluteURL);
  135. DoRelease(pUnknown);
  136. DoRelease(pows);
  137. DoRelease(pShellExtInit);
  138. DoRelease(pShellPropSheetExt);
  139. TraceLeaveResult(hres);
  140. }
  141. /*-----------------------------------------------------------------------------
  142. / TabCollector_Collect
  143. / --------------------
  144. / Given the IDataObject interface and a callback function add the
  145. / pages that represent that object class.
  146. /
  147. / In:
  148. / pDataObject -> data object interface that we can query for the object names
  149. / lpfnAddPage, lParam => parameters used for adding each page
  150. /
  151. / Out:
  152. / HRESULT
  153. /----------------------------------------------------------------------------*/
  154. HRESULT TabCollector_Collect(IUnknown *punkSite, IDataObject* pDataObject, LPFNADDPROPSHEETPAGE pAddPageProc, LPARAM lParam)
  155. {
  156. HRESULT hres;
  157. STGMEDIUM medium = { TYMED_NULL };
  158. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  159. LPDSOBJECTNAMES pDsObjectNames;
  160. LPWSTR pPath;
  161. LPWSTR pObjectClass;
  162. CLASSCACHEGETINFO ccgi = { 0 };
  163. LPCLASSCACHEENTRY pCacheEntry = NULL;
  164. USES_CONVERSION;
  165. INT i;
  166. HDPA hdpa = NULL;
  167. TraceEnter(TRACE_TABS, "TabCollector_Collect");
  168. if ( !pDataObject || !pAddPageProc )
  169. ExitGracefully(hres, E_INVALIDARG, "pDataObject || pAddPageProc == NULL");
  170. // From the IDataObject we must attempt to get the DSOBJECTNAMES structure
  171. // that defines the objects we are being invoked on. If we cannot get that
  172. // format, or the structure doesn't contain enough entries then bail out.
  173. hres = pDataObject->GetData(&fmte, &medium);
  174. FailGracefully(hres, "Failed to GetData using CF_DSOBJECTNAMES");
  175. pDsObjectNames = (LPDSOBJECTNAMES)medium.hGlobal;
  176. if ( pDsObjectNames->cItems < 1 )
  177. ExitGracefully(hres, E_FAIL, "Not enough objects in DSOBJECTNAMES structure");
  178. pPath = (LPWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetName);
  179. pObjectClass = (LPWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetClass);
  180. // fill the CLASSCACHEGETINFO record so we can cache the information from the
  181. // display specifiers.
  182. ccgi.dwFlags = CLASSCACHE_PROPPAGES;
  183. ccgi.pPath = pPath;
  184. ccgi.pObjectClass = pObjectClass;
  185. ccgi.pDataObject = pDataObject;
  186. hres = GetServerAndCredentails(&ccgi);
  187. FailGracefully(hres, "Failed to get the server name");
  188. hres = GetAttributePrefix(&ccgi.pAttributePrefix, pDataObject);
  189. FailGracefully(hres, "Failed to get attributePrefix");
  190. Trace(TEXT("Class: %s; Attribute Prefix: %s; Server: %s"),
  191. W2T(pObjectClass), W2T(ccgi.pAttributePrefix), ccgi.pServer ? W2T(ccgi.pServer):TEXT("<none>"));
  192. hres = ClassCache_GetClassInfo(&ccgi, &pCacheEntry);
  193. FailGracefully(hres, "Failed to get page list (via the cache)");
  194. // Just keep what is needed and then release the cache
  195. if ( (pCacheEntry->dwCached & CLASSCACHE_PROPPAGES) && pCacheEntry->hdsaPropertyPages )
  196. {
  197. hdpa = DPA_Create(16); // grow size
  198. if ( !hdpa )
  199. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create DPA");
  200. for ( i = 0 ; i < DSA_GetItemCount(pCacheEntry->hdsaPropertyPages); i++ )
  201. {
  202. LPDSPROPERTYPAGE pPage =(LPDSPROPERTYPAGE)DSA_GetItemPtr(pCacheEntry->hdsaPropertyPages, i);
  203. TraceAssert(pPage);
  204. hres = StringDPA_AppendStringW(hdpa, pPage->pPageReference, NULL);
  205. FailGracefully(hres, "Failed to append the string");
  206. }
  207. }
  208. ClassCache_ReleaseClassInfo(&pCacheEntry);
  209. if (NULL != hdpa)
  210. {
  211. for ( i = 0 ; i < DPA_GetPtrCount(hdpa); i++ )
  212. {
  213. LPCWSTR pwszPageRef = StringDPA_GetStringW(hdpa, i);
  214. hres = TabCollector_AddPages(const_cast<LPWSTR>(pwszPageRef),
  215. pPath,
  216. punkSite,
  217. pDataObject,
  218. pAddPageProc,
  219. lParam);
  220. FailGracefully(hres, "Failed to add page to the list");
  221. }
  222. }
  223. hres = S_OK;
  224. exit_gracefully:
  225. StringDPA_Destroy(&hdpa);
  226. ClassCache_ReleaseClassInfo(&pCacheEntry);
  227. ReleaseStgMedium(&medium);
  228. LocalFreeStringW(&ccgi.pAttributePrefix);
  229. LocalFreeStringW(&ccgi.pUserName);
  230. LocalFreeStringW(&ccgi.pPassword);
  231. LocalFreeStringW(&ccgi.pServer);
  232. TraceLeaveResult(hres);
  233. }
  234. /*-----------------------------------------------------------------------------
  235. / CDsPropPageDataObject
  236. /----------------------------------------------------------------------------*/
  237. CDsPropPageDataObject::CDsPropPageDataObject(IDataObject* pDataObject, LPWSTR pParameters) :
  238. _cRef(1)
  239. {
  240. _pDataObject = pDataObject;
  241. _pDataObject->AddRef();
  242. LocalAllocStringW(&_pParameters, pParameters);
  243. DllAddRef();
  244. }
  245. CDsPropPageDataObject::~CDsPropPageDataObject()
  246. {
  247. DoRelease(_pDataObject);
  248. LocalFreeStringW(&_pParameters);
  249. DllRelease();
  250. }
  251. // IUnknown
  252. ULONG CDsPropPageDataObject::AddRef()
  253. {
  254. return InterlockedIncrement(&_cRef);
  255. }
  256. ULONG CDsPropPageDataObject::Release()
  257. {
  258. if (InterlockedDecrement(&_cRef))
  259. return _cRef;
  260. delete this;
  261. return 0;
  262. }
  263. HRESULT CDsPropPageDataObject::QueryInterface(REFIID riid, void **ppv)
  264. {
  265. static const QITAB qit[] =
  266. {
  267. QITABENT(CDsPropPageDataObject, IDataObject), // IID_IDataObject
  268. {0, 0 },
  269. };
  270. return QISearch(this, qit, riid, ppv);
  271. }
  272. // IDataObject methods
  273. STDMETHODIMP CDsPropPageDataObject::GetData(FORMATETC* pFmt, STGMEDIUM* pMedium)
  274. {
  275. HRESULT hres;
  276. TraceEnter(TRACE_TABS, "CDsPropPageDataObject::GetData");
  277. if ( !pFmt || !pMedium )
  278. ExitGracefully(hres, E_INVALIDARG, "Bad arguments to GetData");
  279. // if its not our clipboard format, or there are no parameters
  280. // then we call the original handler, otherwise we add our stuff
  281. if ( !g_cfDsPropPageInfo )
  282. {
  283. g_cfDsPropPageInfo = RegisterClipboardFormat(CFSTR_DSPROPERTYPAGEINFO);
  284. TraceAssert(g_cfDsPropPageInfo);
  285. }
  286. if ( (pFmt->cfFormat == g_cfDsPropPageInfo) && _pParameters )
  287. {
  288. LPDSPROPERTYPAGEINFO pPropPageInfo;
  289. DWORD cbSize = SIZEOF(LPDSPROPERTYPAGEINFO)+StringByteSizeW(_pParameters);
  290. // allocate a structure that contains the propage page information
  291. // we were initialized with
  292. Trace(TEXT("Property page parameter: %s"), _pParameters);
  293. Trace(TEXT("Size of structure for DSPROPPAGEINFO %d"), cbSize);
  294. hres = AllocStorageMedium(pFmt, pMedium, cbSize, (LPVOID*)&pPropPageInfo);
  295. FailGracefully(hres, "Failed to allocate the storage medium");
  296. pPropPageInfo->offsetString = SIZEOF(DSPROPERTYPAGEINFO);
  297. StringByteCopyW(pPropPageInfo, pPropPageInfo->offsetString, _pParameters);
  298. hres = S_OK; // success
  299. }
  300. else
  301. {
  302. hres = _pDataObject->GetData(pFmt, pMedium);
  303. FailGracefully(hres, "Failed when calling real IDataObject");
  304. }
  305. exit_gracefully:
  306. TraceLeaveResult(hres);
  307. }