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.

386 lines
15 KiB

  1. #if !defined(_FUSION_INC_PSPIPEHELPER_H_INCLUDED_)
  2. #define _FUSION_INC_PSPIPEHELPER_H_INCLUDED_
  3. #pragma once
  4. #pragma warning(disable: 4127)
  5. #include "fusioncom.h"
  6. #include "smartref.h"
  7. #include "fusewin.h"
  8. #include "fusionbytebuffer.h"
  9. #include "pstream.h"
  10. #define IFFAIL_RETURN(x) \
  11. do { \
  12. const HRESULT __hr = (x); \
  13. if (FAILED(__hr)) \
  14. return __hr; \
  15. } while (0)
  16. #define IFFAIL_SET_PIPE_BAD_AND_RETURN(x) \
  17. do { \
  18. const HRESULT __hr = (x);\
  19. if (FAILED(__hr)) \
  20. { \
  21. m_fPipeBad = true; \
  22. return __hr; \
  23. } \
  24. } while (0)
  25. #define IFFAIL_SET_PIPE_BAD_IF_AND_RETURN(x, cond) \
  26. do { \
  27. const HRESULT __hr = (x);\
  28. if (FAILED(__hr)) \
  29. { \
  30. if ((cond)) m_fPipeBad = true; \
  31. return __hr; \
  32. } \
  33. } while (0)
  34. // SET_PIPE_BAD_IF_AND_EXIT evaluates the first parameter. If it is
  35. // failure and "cond" is true, the pipe is set to be broken. Regardless
  36. // of success vs. failure, the value of the first parameter is returned.
  37. #define SET_PIPE_BAD_IF_AND_EXIT(x, cond) \
  38. do { \
  39. const HRESULT __hr = (x); \
  40. if (FAILED(__hr)) \
  41. { \
  42. if ((cond)) m_fPipeBad = true; \
  43. hr = __hr; \
  44. goto Exit; \
  45. } \
  46. } while (0)
  47. #define UNUSED(x) (x)
  48. extern HRESULT FusionWriteProperty(IPipeByte *pIPipeByte, ULONG propid, const PROPVARIANT &rvarValue, bool &rfAnyDataWritten);
  49. extern HRESULT FusionWriteBlobVectorProperty(IPipeByte *pIPipeByte, ULONG propid, ULONG cElements, va_list ap, bool &rfAnyDataWritten);
  50. extern HRESULT FusionWriteUI2VectorProperty(IPipeByte *pIPipeByte, ULONG propid, ULONG cElements, va_list ap, bool &rfAnyDataWritten);
  51. class CPropertyStreamPipeWriter
  52. {
  53. public:
  54. CPropertyStreamPipeWriter() : m_fInitialized(false), m_dwNextSectionCookie(0), m_fPipeBad(false) { }
  55. ~CPropertyStreamPipeWriter() { }
  56. HRESULT Initialize(IPipeByte *pIPipeByte)
  57. {
  58. if (m_fInitialized) return E_UNEXPECTED;
  59. if (pIPipeByte == NULL) return E_POINTER;
  60. m_srpIPipeByte = pIPipeByte;
  61. m_fInitialized = true;
  62. m_fPipeBad = false;
  63. return NOERROR;
  64. }
  65. // The pipe data stream is considered bad if we started writing some part of a data
  66. // item and failed before completing. Once a pipe is bad, there is nothing
  67. // you can do with it except close it.
  68. bool IsPipeBad() const { return m_fPipeBad; }
  69. HRESULT WriteHeader(REFCLSID rclsidOriginator)
  70. {
  71. if (!m_fInitialized) return E_UNEXPECTED;
  72. if (m_dwNextSectionCookie != 0) return E_UNEXPECTED;
  73. if (m_fPipeBad) return HRESULT_FROM_WIN32(ERROR_BAD_PIPE);
  74. FUSION_PSTREAM_VERSION_1_HEADER hdr;
  75. hdr.vih.wByteOrder = 0xFFFE;
  76. hdr.vih.wFormat = 1;
  77. hdr.vih.dwOSVer = (DWORD) MAKELONG(LOWORD(::GetVersion()), 2); // taken from MSDN mk:@MSITStore:\\infosrv2\msdn_oct99\MSDN\COM.chm::/devdoc/com/stgasstg_44mr.htm
  78. hdr.vih.clsid = rclsidOriginator;
  79. hdr.vih.reserved = 0;
  80. IFFAIL_RETURN(m_srpIPipeByte->Push((LPBYTE) &hdr, sizeof(hdr)));
  81. m_dwNextSectionCookie = 1;
  82. return NOERROR;
  83. }
  84. HRESULT BeginSection(REFGUID rguidSectionSet, ULONG ulSectionID, DWORD &rdwSectionCookie)
  85. {
  86. if (!m_fInitialized) return E_UNEXPECTED;
  87. ASSERT(m_dwNextSectionCookie != 0); // forgot to send header
  88. if (m_dwNextSectionCookie == 0) return E_UNEXPECTED;
  89. if (m_fPipeBad) return HRESULT_FROM_WIN32(ERROR_BAD_PIPE);
  90. FUSION_PSTREAM_ELEMENT elt;
  91. elt.bIndicator = FUSION_PSTREAM_INDICATOR_SECTION_BEGIN;
  92. elt.BeginSectionVal.guidSectionSet = rguidSectionSet;
  93. elt.BeginSectionVal.ulSectionID = ulSectionID;
  94. IFFAIL_RETURN(m_srpIPipeByte->Push((LPBYTE) &elt, FUSION_PSTREAM_SIZEOF_SECTION_BEGIN));
  95. rdwSectionCookie = m_dwNextSectionCookie++;
  96. return NOERROR;
  97. }
  98. HRESULT EndSection(DWORD dwSectionCookie)
  99. {
  100. UNUSED(dwSectionCookie); // Eventually check this so that we can make sure caller doesn't mis-match begins/ends
  101. if (!m_fInitialized) return E_UNEXPECTED;
  102. if (m_fPipeBad) return HRESULT_FROM_WIN32(ERROR_BAD_PIPE);
  103. FUSION_PSTREAM_ELEMENT elt;
  104. elt.bIndicator = FUSION_PSTREAM_INDICATOR_SECTION_END;
  105. IFFAIL_RETURN(m_srpIPipeByte->Push((LPBYTE) &elt, FUSION_PSTREAM_SIZEOF_SECTION_END));
  106. return NOERROR;
  107. }
  108. HRESULT WriteProperty(DWORD dwSectionCookie, ULONG ulPropertyID, PROPVARIANT varValue)
  109. {
  110. UNUSED(dwSectionCookie);
  111. if (!m_fInitialized) return E_UNEXPECTED;
  112. if (m_fPipeBad) return HRESULT_FROM_WIN32(ERROR_BAD_PIPE);
  113. // Too much work to even try to do inline..
  114. bool fAnyDataWritten = false;
  115. IFFAIL_SET_PIPE_BAD_IF_AND_RETURN(::FusionWriteProperty(m_srpIPipeByte, ulPropertyID, varValue, fAnyDataWritten), fAnyDataWritten);
  116. return NOERROR;
  117. }
  118. // cch should not include space for the null...
  119. HRESULT WriteProperty(DWORD dwSectionCookie, ULONG ulPropertyID, LPCWSTR szValue, INT cch = -1)
  120. {
  121. UNUSED(dwSectionCookie);
  122. if (!m_fInitialized) return E_UNEXPECTED;
  123. if (m_fPipeBad) return HRESULT_FROM_WIN32(ERROR_BAD_PIPE);
  124. if (cch < 0)
  125. {
  126. cch = ::wcslen(szValue);
  127. // Handle overflow - crazy case, but might as well not crash.
  128. if (cch < 0)
  129. cch = 0x7fffffff;
  130. }
  131. else {
  132. // Trim off trailing null characters when user passed in cch > 0
  133. while ((cch > 0) && (szValue[cch - 1] == L'\0')) cch--;
  134. }
  135. FUSION_PSTREAM_ELEMENT elt;
  136. elt.bIndicator = FUSION_PSTREAM_INDICATOR_PROPERTY;
  137. elt.PropertyVal.propid = ulPropertyID;
  138. elt.PropertyVal.wType = VT_LPWSTR;
  139. bool fAnyDataWritten = false;
  140. IFFAIL_RETURN(m_srpIPipeByte->Push((LPBYTE) &elt, FUSION_PSTREAM_SIZEOF_PROPERTY));
  141. IFFAIL_SET_PIPE_BAD_AND_RETURN(m_srpIPipeByte->Push((LPBYTE) &cch, sizeof(cch)));
  142. IFFAIL_SET_PIPE_BAD_AND_RETURN(m_srpIPipeByte->Push((LPBYTE) szValue, cch * sizeof(WCHAR)));
  143. return NOERROR;
  144. }
  145. // WriteVector() currently only understands: VT_UI2, VT_BLOB
  146. HRESULT WriteVectorVa(DWORD dwSectionCookie, ULONG ulPropertyID, VARTYPE vt, ULONG cElements, va_list ap)
  147. {
  148. HRESULT hr = NOERROR;
  149. bool fAnyDataWritten = false;
  150. UNUSED(dwSectionCookie);
  151. if (!m_fInitialized) { hr = E_UNEXPECTED; goto Exit; }
  152. if (m_fPipeBad) { hr = HRESULT_FROM_WIN32(ERROR_BAD_PIPE); goto Exit; }
  153. switch (vt)
  154. {
  155. case VT_BLOB:
  156. SET_PIPE_BAD_IF_AND_EXIT(
  157. ::FusionWriteBlobVectorProperty(m_srpIPipeByte, ulPropertyID, cElements, ap, fAnyDataWritten),
  158. fAnyDataWritten);
  159. break;
  160. case VT_UI2:
  161. SET_PIPE_BAD_IF_AND_EXIT(
  162. ::FusionWriteUI2VectorProperty(m_srpIPipeByte, ulPropertyID, cElements, ap, fAnyDataWritten),
  163. fAnyDataWritten);
  164. break;
  165. default:
  166. ASSERT(FALSE);
  167. hr = E_INVALIDARG;
  168. goto Exit;
  169. break;
  170. }
  171. hr = NOERROR;
  172. Exit:
  173. return hr;
  174. }
  175. HRESULT WriteVector(DWORD dwSectionCookie, ULONG ulPropertyID, VARTYPE vt, ULONG cElements, ...)
  176. {
  177. va_list ap;
  178. if (!m_fInitialized) return E_UNEXPECTED;
  179. if (m_fPipeBad) return HRESULT_FROM_WIN32(ERROR_BAD_PIPE);
  180. va_start(ap, cElements);
  181. HRESULT hr = this->WriteVectorVa(dwSectionCookie, ulPropertyID, vt, cElements, ap);
  182. va_end(ap);
  183. if (!FAILED(hr)) hr = NOERROR;
  184. return hr;
  185. }
  186. HRESULT Close()
  187. {
  188. if (!m_fInitialized) return E_UNEXPECTED;
  189. HRESULT hr = m_srpIPipeByte->Push(0, 0);
  190. if (FAILED(hr)) return hr;
  191. m_srpIPipeByte.Release();
  192. m_fInitialized = false;
  193. return NOERROR;
  194. }
  195. protected:
  196. CSmartRef<IPipeByte> m_srpIPipeByte;
  197. bool m_fInitialized;
  198. DWORD m_dwNextSectionCookie;
  199. bool m_fPipeBad;
  200. };
  201. //
  202. // CPropertyStreamPipeReader is an aggregatable/tear-off-able COM object that
  203. // you can instantiate on your class in order to get callbacks when a piped
  204. // property stream has data available on it.
  205. //
  206. // We expect to invoke the following member functions on the T pointer passed in:
  207. //
  208. // HRESULT OnPropertyStreamHeader(PFUSION_PSTREAM_VERSION_INDEPENDENT_HEADER phdr);
  209. // Called when the header has been recognized from the stream in.
  210. // If this function returns a non-successful HRESULT, the remainder of
  211. // the property stream is discarded, and when OnPropertyStreamEnd() is
  212. // called, the caller should call StopParsingPropertyStream().
  213. //
  214. // HRESULT OnPropertyStreamElement(PFUSION_PSTREAM_ELEMENT pelt);
  215. // Called when a property stream element header has been recognized.
  216. // This may be either a section begin (in which case the section guid
  217. // and ID are available in the pelt), a section end (no additional data),
  218. // or a property (in which case the property id and property type are
  219. // available in the pelt). Once a property header has been found, the
  220. // property data is buffered until entirely available.
  221. // If this function returns a non-successful HRESULT, the remainder of
  222. // the property stream is discarded, and when OnPropertyStreamEnd() is
  223. // called, the caller should call StopParsingPropertyStream().
  224. //
  225. // HRESULT OnPropertyStreamPropertyValue(LPCBYTE *prgbValue, ULONG cbValue);
  226. // Called when an entire property value is available. Note that
  227. // the buffer passed in is the raw format of the property value; strings
  228. // are not null terminated and there may or may not be valid data past
  229. // prgbValue[cbValue-1].
  230. // If this function returns a non-successful HRESULT, the remainder of
  231. // the property stream is discarded, and when OnPropertyStreamEnd() is
  232. // called, the caller should call StopParsingPropertyStream().
  233. //
  234. // VOID OnPropertyStreamEnd(CPropertyStreamPipeReaderBase::PropertyStreamEndReason er);
  235. // Called when the pipe is closed/ended.
  236. //
  237. class __declspec(novtable) CPropertyStreamPipeReaderBase : public CFusionCOMObjectBase, public IPipeByte
  238. {
  239. public:
  240. FUSION_BEGIN_COM_MAP(CPropertyStreamPipeReaderBase)
  241. FUSION_COM_INTERFACE_ENTRY(IPipeByte)
  242. FUSION_END_COM_MAP()
  243. HRESULT StartParsingPropertyStream();
  244. HRESULT StopParsingPropertyStream();
  245. // IPipeByte methods:
  246. STDMETHODIMP Pull(BYTE *prgbBuffer, ULONG cRequest, ULONG *pcReturned);
  247. STDMETHODIMP Push(BYTE *prgbBuffer, ULONG cbBuffer);
  248. enum PropertyStreamEndReason
  249. {
  250. eNormalEnd,
  251. eStreamFormatError,
  252. ePropertyTypeError,
  253. eStreamEndEarly,
  254. eInternalError, // indicates a code bug
  255. eOutOfMemory,
  256. eOtherError, // indicates some HRESULT other than E_OUTOFMEMORY was encountered
  257. };
  258. protected:
  259. CPropertyStreamPipeReaderBase() : m_fInitialized(false), m_iByteCurrent(0) { }
  260. ~CPropertyStreamPipeReaderBase() { }
  261. virtual HRESULT FireOnPropertyStreamHeader(PCFUSION_PSTREAM_VERSION_INDEPENDENT_HEADER phdr) = 0;
  262. virtual HRESULT FireOnPropertyStreamElement(PCFUSION_PSTREAM_ELEMENT pelt) = 0;
  263. virtual HRESULT FireOnPropertyStreamPropertyValue(PCBYTE prgbValue, ULONG cbValue) = 0;
  264. virtual VOID FireOnPropertyStreamEnd(PropertyStreamEndReason pser) = 0;
  265. bool m_fInitialized;
  266. CByteBuffer m_buffer;
  267. ULONG m_iByteCurrent;
  268. enum State
  269. {
  270. eIdle, // Not yet started parsing
  271. eWaitingForHeader, // waiting for header bytes
  272. eWaitingForIndicator, // waiting for indicator byte
  273. eWaitingForSection, // waiting for remainder of section header
  274. eWaitingForProperty, // waiting for property
  275. eWaitingForPropertySize, // Waiting for some size/count on the property
  276. eWaitingForPropertyElementSize,
  277. eWaitingForPropertyElementData,
  278. eWaitingForPropertyValue, // waiting for property value
  279. eWaitingForPipeEnd, // Hit end indicator; next push should be length 0 and there should
  280. // be no data in the buffer.
  281. ePipeDone, // end of pipe hit; will transition to idle when parsing is stopped
  282. eDiscarded, // we don't care about the rest of the data pushed to us.
  283. } m_state;
  284. ULONG m_cbRequiredForNextStateTransition;
  285. ULONG m_cVectorElementsLeft; // Used when parsing VT_VECTOR properties; we store the
  286. // total number of elements we still expect to find in the
  287. // data stream here so we can tell when we can fire
  288. // OnPropertyStreamPropertyValue().
  289. ULONG m_iNextVectorSize; // Offset from m_iByteCurrent to the next vector element size.
  290. WORD m_wType; // current property type we're parsing; makes a lot of code
  291. // simpler to just copy it here.
  292. HRESULT OnStateMet();
  293. HRESULT OnWaitingForHeaderStateMet();
  294. HRESULT OnWaitingForIndicatorStateMet();
  295. HRESULT OnWaitingForSectionStateMet();
  296. HRESULT OnWaitingForPropertyStateMet();
  297. HRESULT OnWaitingForPropertySizeStateMet();
  298. HRESULT OnWaitingForPropertyValueStateMet();
  299. HRESULT OnWaitingForPropertyElementSizeStateMet();
  300. HRESULT OnWaitingForPropertyElementDataStateMet();
  301. };
  302. template <class T> class __declspec(novtable) CPropertyStreamPipeReader : public CPropertyStreamPipeReaderBase
  303. {
  304. public:
  305. CPropertyStreamPipeReader() : m_pt(NULL) { }
  306. ~CPropertyStreamPipeReader() { m_pt = NULL; }
  307. HRESULT Initialize(T *pt)
  308. {
  309. if (m_fInitialized) return E_UNEXPECTED;
  310. if (pt == NULL) return E_POINTER;
  311. IFFAIL_RETURN(CFusionCOMObjectBase::Initialize());
  312. m_pt = pt;
  313. m_state = eIdle;
  314. return NOERROR;
  315. }
  316. protected:
  317. T *m_pt;
  318. virtual HRESULT FireOnPropertyStreamHeader(PCFUSION_PSTREAM_VERSION_INDEPENDENT_HEADER phdr)
  319. {
  320. ASSERT(m_fInitialized);
  321. if (!m_fInitialized) return E_UNEXPECTED;
  322. return m_pt->OnPropertyStreamHeader(phdr);
  323. }
  324. virtual HRESULT FireOnPropertyStreamElement(PCFUSION_PSTREAM_ELEMENT pelt)
  325. {
  326. ASSERT(m_fInitialized);
  327. if (!m_fInitialized) return E_UNEXPECTED;
  328. return m_pt->OnPropertyStreamElement(pelt);
  329. }
  330. virtual HRESULT FireOnPropertyStreamPropertyValue(PCBYTE prgbValue, ULONG cbValue)
  331. {
  332. ASSERT(m_fInitialized);
  333. if (!m_fInitialized) return E_UNEXPECTED;
  334. return m_pt->OnPropertyStreamPropertyValue(prgbValue, cbValue);
  335. }
  336. virtual VOID FireOnPropertyStreamEnd(PropertyStreamEndReason er)
  337. {
  338. ASSERT(m_fInitialized);
  339. if (m_fInitialized) m_pt->OnPropertyStreamEnd(er);
  340. }
  341. };
  342. #endif