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.

392 lines
14 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. GUID guid;
  74. TraceEnter(TRACE_TABS, "TabCollector_AddPages");
  75. Trace(TEXT("Page reference is %s"), pPageReference);
  76. // The name is either a CLSID, or a URL description. Therefore lets try and
  77. // parse it as a GUID, if that fails then we can just attempt to break out the
  78. // other components.
  79. if ( SUCCEEDED(GetStringElementW(pPageReference, 0, szGUID, ARRAYSIZE(szGUID))) &&
  80. GetGUIDFromString(pPageReference, &guid) )
  81. {
  82. if ( SUCCEEDED(CoCreateInstance(guid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &pUnknown))) )
  83. {
  84. // We have found the object, lets try and initialize it passing it the data
  85. // object we have, if that fails then we ignore this entry.
  86. if ( punkSite && SUCCEEDED(pUnknown->QueryInterface(IID_IObjectWithSite, (void **)&pows)) )
  87. {
  88. hres = pows->SetSite(punkSite);
  89. FailGracefully(hres, "Failed when setting site on the object");
  90. }
  91. if ( SUCCEEDED(pUnknown->QueryInterface(IID_PPV_ARG(IShellExtInit, &pShellExtInit))) )
  92. {
  93. if ( SUCCEEDED(GetStringElementW(pPageReference, 1, szBuffer, ARRAYSIZE(szBuffer))) && szBuffer[0] )
  94. {
  95. CDsPropPageDataObject* pDsPropPageDataObject = new CDsPropPageDataObject(pDataObject, szBuffer);
  96. TraceAssert(pDsPropPageDataObject);
  97. if ( !pDsPropPageDataObject )
  98. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate IDataObject wrapper");
  99. Trace(TEXT("IDsPropPageDataObject constructed with: %s"), szBuffer);
  100. hres = pShellExtInit->Initialize(NULL, pDsPropPageDataObject, NULL);
  101. pDsPropPageDataObject->Release();
  102. }
  103. else
  104. {
  105. TraceMsg("No extra parameters for property page, invoking with original IDataObject");
  106. hres = pShellExtInit->Initialize(NULL, pDataObject, NULL);
  107. }
  108. DoRelease(pShellExtInit);
  109. if ( FAILED(hres) )
  110. ExitGracefully(hres, S_OK, "Failed to Initialize the Win32 extension - PAGE IGNORED");
  111. }
  112. // We have tried to Initialize the object, so lets get it to add the pages if it
  113. // supports the IShellPropSheetExt interface.
  114. if ( SUCCEEDED(pUnknown->QueryInterface(IID_PPV_ARG(IShellPropSheetExt, &pShellPropSheetExt))) )
  115. {
  116. hres = pShellPropSheetExt->AddPages(pAddPageProc, lParam);
  117. DoRelease(pShellPropSheetExt);
  118. if (hres == HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP))
  119. FailGracefully(hres, "Cannot talk to the DC");
  120. }
  121. }
  122. else
  123. {
  124. TraceGUID("Failed to CoCreateInstance ", guid);
  125. }
  126. }
  127. else
  128. {
  129. ExitGracefully(hres, E_NOTIMPL, "HTML property pages are not supported");
  130. }
  131. hres = S_OK; // success
  132. exit_gracefully:
  133. LocalFreeString(&pAbsoluteURL);
  134. DoRelease(pUnknown);
  135. DoRelease(pows);
  136. DoRelease(pShellExtInit);
  137. DoRelease(pShellPropSheetExt);
  138. TraceLeaveResult(hres);
  139. }
  140. /*-----------------------------------------------------------------------------
  141. / TabCollector_Collect
  142. / --------------------
  143. / Given the IDataObject interface and a callback function add the
  144. / pages that represent that object class.
  145. /
  146. / In:
  147. / pDataObject -> data object interface that we can query for the object names
  148. / lpfnAddPage, lParam => parameters used for adding each page
  149. /
  150. / Out:
  151. / HRESULT
  152. /----------------------------------------------------------------------------*/
  153. HRESULT TabCollector_Collect(IUnknown *punkSite, IDataObject* pDataObject, LPFNADDPROPSHEETPAGE pAddPageProc, LPARAM lParam)
  154. {
  155. HRESULT hres;
  156. STGMEDIUM medium = { TYMED_NULL };
  157. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  158. LPDSOBJECTNAMES pDsObjectNames = NULL;
  159. LPWSTR pPath;
  160. LPWSTR pObjectClass;
  161. CLASSCACHEGETINFO ccgi = { 0 };
  162. LPCLASSCACHEENTRY pCacheEntry = NULL;
  163. INT i;
  164. HDPA hdpa = NULL;
  165. TraceEnter(TRACE_TABS, "TabCollector_Collect");
  166. if ( !pDataObject || !pAddPageProc )
  167. ExitGracefully(hres, E_INVALIDARG, "pDataObject || pAddPageProc == NULL");
  168. // From the IDataObject we must attempt to get the DSOBJECTNAMES structure
  169. // that defines the objects we are being invoked on. If we cannot get that
  170. // format, or the structure doesn't contain enough entries then bail out.
  171. hres = pDataObject->GetData(&fmte, &medium);
  172. FailGracefully(hres, "Failed to GetData using CF_DSOBJECTNAMES");
  173. pDsObjectNames = (LPDSOBJECTNAMES)GlobalLock(medium.hGlobal);
  174. if ( pDsObjectNames->cItems < 1 )
  175. ExitGracefully(hres, E_FAIL, "Not enough objects in DSOBJECTNAMES structure");
  176. pPath = (LPWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetName);
  177. pObjectClass = (LPWSTR)ByteOffset(pDsObjectNames, pDsObjectNames->aObjects[0].offsetClass);
  178. // fill the CLASSCACHEGETINFO record so we can cache the information from the
  179. // display specifiers.
  180. ccgi.dwFlags = CLASSCACHE_PROPPAGES;
  181. ccgi.pPath = pPath;
  182. ccgi.pObjectClass = pObjectClass;
  183. ccgi.pDataObject = pDataObject;
  184. hres = GetServerAndCredentails(&ccgi);
  185. FailGracefully(hres, "Failed to get the server name");
  186. hres = GetAttributePrefix(&ccgi.pAttributePrefix, pDataObject);
  187. FailGracefully(hres, "Failed to get attributePrefix");
  188. Trace(TEXT("Class: %s; Attribute Prefix: %s; Server: %s"),
  189. pObjectClass, ccgi.pAttributePrefix, ccgi.pServer ? ccgi.pServer:TEXT("<none>"));
  190. hres = ClassCache_GetClassInfo(&ccgi, &pCacheEntry);
  191. FailGracefully(hres, "Failed to get page list (via the cache)");
  192. // Just keep what is needed and then release the cache
  193. if ( (pCacheEntry->dwCached & CLASSCACHE_PROPPAGES) && pCacheEntry->hdsaPropertyPages )
  194. {
  195. hdpa = DPA_Create(16); // grow size
  196. if ( !hdpa )
  197. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create DPA");
  198. for ( i = 0 ; i < DSA_GetItemCount(pCacheEntry->hdsaPropertyPages); i++ )
  199. {
  200. LPDSPROPERTYPAGE pPage =(LPDSPROPERTYPAGE)DSA_GetItemPtr(pCacheEntry->hdsaPropertyPages, i);
  201. TraceAssert(pPage);
  202. hres = StringDPA_AppendStringW(hdpa, pPage->pPageReference, NULL);
  203. FailGracefully(hres, "Failed to append the string");
  204. }
  205. }
  206. ClassCache_ReleaseClassInfo(&pCacheEntry);
  207. if (NULL != hdpa)
  208. {
  209. for ( i = 0 ; i < DPA_GetPtrCount(hdpa); i++ )
  210. {
  211. LPCWSTR pwszPageRef = StringDPA_GetStringW(hdpa, i);
  212. hres = TabCollector_AddPages(const_cast<LPWSTR>(pwszPageRef),
  213. pPath,
  214. punkSite,
  215. pDataObject,
  216. pAddPageProc,
  217. lParam);
  218. FailGracefully(hres, "Failed to add page to the list");
  219. }
  220. }
  221. hres = S_OK;
  222. exit_gracefully:
  223. StringDPA_Destroy(&hdpa);
  224. ClassCache_ReleaseClassInfo(&pCacheEntry);
  225. if (pDsObjectNames)
  226. GlobalUnlock(medium.hGlobal);
  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. Assert( 0 != _cRef );
  259. ULONG cRef = InterlockedDecrement(&_cRef);
  260. if ( 0 == cRef )
  261. {
  262. delete this;
  263. }
  264. return cRef;
  265. }
  266. HRESULT CDsPropPageDataObject::QueryInterface(REFIID riid, void **ppv)
  267. {
  268. static const QITAB qit[] =
  269. {
  270. QITABENT(CDsPropPageDataObject, IDataObject), // IID_IDataObject
  271. {0, 0 },
  272. };
  273. return QISearch(this, qit, riid, ppv);
  274. }
  275. // IDataObject methods
  276. STDMETHODIMP CDsPropPageDataObject::GetData(FORMATETC* pFmt, STGMEDIUM* pMedium)
  277. {
  278. HRESULT hres;
  279. TraceEnter(TRACE_TABS, "CDsPropPageDataObject::GetData");
  280. if ( !pFmt || !pMedium )
  281. ExitGracefully(hres, E_INVALIDARG, "Bad arguments to GetData");
  282. // if its not our clipboard format, or there are no parameters
  283. // then we call the original handler, otherwise we add our stuff
  284. if ( !g_cfDsPropPageInfo )
  285. {
  286. g_cfDsPropPageInfo = RegisterClipboardFormat(CFSTR_DSPROPERTYPAGEINFO);
  287. TraceAssert(g_cfDsPropPageInfo);
  288. }
  289. if ( (pFmt->cfFormat == g_cfDsPropPageInfo) && _pParameters )
  290. {
  291. LPDSPROPERTYPAGEINFO pPropPageInfo;
  292. DWORD cbSize = SIZEOF(LPDSPROPERTYPAGEINFO)+StringByteSizeW(_pParameters);
  293. // allocate a structure that contains the propage page information
  294. // we were initialized with
  295. Trace(TEXT("Property page parameter: %s"), _pParameters);
  296. Trace(TEXT("Size of structure for DSPROPPAGEINFO %d"), cbSize);
  297. hres = AllocStorageMedium(pFmt, pMedium, cbSize, (LPVOID*)&pPropPageInfo);
  298. FailGracefully(hres, "Failed to allocate the storage medium");
  299. pPropPageInfo->offsetString = SIZEOF(DSPROPERTYPAGEINFO);
  300. StringByteCopyW(pPropPageInfo, pPropPageInfo->offsetString, _pParameters);
  301. hres = S_OK; // success
  302. }
  303. else
  304. {
  305. hres = _pDataObject->GetData(pFmt, pMedium);
  306. FailGracefully(hres, "Failed when calling real IDataObject");
  307. }
  308. exit_gracefully:
  309. TraceLeaveResult(hres);
  310. }