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.

409 lines
13 KiB

  1. #pragma once
  2. #include <spunicode.h>
  3. /****************************************************************************
  4. * SpGenericCopyTo *
  5. *-----------------*
  6. * Description:
  7. * This function is used by stream implementations to implement the CopyTo method of IStream.
  8. * Note that the source stream is not parameter validated since it will be the "this" pointer
  9. * of the object that is calling this function.
  10. *
  11. * Returns:
  12. *
  13. *****************************************************************************/
  14. inline HRESULT SpGenericCopyTo(IStream * pSrc, IStream * pDest, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
  15. {
  16. HRESULT hr = S_OK;
  17. if (::IsBadReadPtr(pDest, sizeof(*pDest)))
  18. {
  19. hr = E_INVALIDARG;
  20. }
  21. else
  22. {
  23. if ((pcbRead && ::IsBadWritePtr(pcbRead, sizeof(*pcbRead))) ||
  24. (pcbWritten && ::IsBadWritePtr(pcbWritten, sizeof(*pcbWritten))))
  25. {
  26. hr = E_POINTER;
  27. }
  28. else
  29. {
  30. BYTE aBuffer[0x1000]; // Do 4k reads
  31. while (cb.QuadPart)
  32. {
  33. ULONG cbThisRead = cb.QuadPart > sizeof(aBuffer) ? sizeof(aBuffer) : cb.LowPart;
  34. ULONG cbActuallyRead = 0;
  35. hr = pSrc->Read(aBuffer, cbThisRead, &cbActuallyRead);
  36. if (pcbRead)
  37. {
  38. pcbRead->QuadPart += cbActuallyRead;
  39. }
  40. if (FAILED(hr) || cbActuallyRead == 0)
  41. {
  42. break;
  43. }
  44. ULONG cbActuallyWritten = 0;
  45. hr = pDest->Write(aBuffer, cbActuallyRead, &cbActuallyWritten);
  46. if (pcbWritten)
  47. {
  48. pcbWritten->QuadPart += cbActuallyWritten;
  49. }
  50. if (FAILED(hr))
  51. {
  52. break;
  53. }
  54. cb.QuadPart -= cbActuallyRead;
  55. }
  56. }
  57. }
  58. return hr;
  59. }
  60. /****************************************************************************
  61. * SPCreateStreamOnHGlobal *
  62. *-------------------------*
  63. * Description:
  64. * Similar to CreateStreamOnHGlobal Win32 API, but allows a stream to be
  65. * created
  66. *
  67. * Returns:
  68. *
  69. *****************************************************************************/
  70. inline HRESULT SPCreateStreamOnHGlobal(
  71. HGLOBAL hGlobal, //Memory handle for the stream object
  72. BOOL fDeleteOnRelease, //Whether to free memory when the object is released
  73. REFGUID rguidFormatId, //Format ID for stream
  74. const WAVEFORMATEX * pwfex, //WaveFormatEx for stream
  75. ISpStream ** ppStream) //Address of variable to receive ISpStream pointer
  76. {
  77. HRESULT hr;
  78. IStream * pMemStream;
  79. *ppStream = NULL;
  80. hr = ::CreateStreamOnHGlobal(hGlobal, fDeleteOnRelease, &pMemStream);
  81. if (SUCCEEDED(hr))
  82. {
  83. hr = ::CoCreateInstance(CLSID_SpStream, NULL, CLSCTX_ALL, __uuidof(*ppStream), (void **)ppStream);
  84. if (SUCCEEDED(hr))
  85. {
  86. hr = (*ppStream)->SetBaseStream(pMemStream, rguidFormatId, pwfex);
  87. if (FAILED(hr))
  88. {
  89. (*ppStream)->Release();
  90. *ppStream = NULL;
  91. }
  92. }
  93. pMemStream->Release();
  94. }
  95. return hr;
  96. }
  97. /****************************************************************************
  98. * CSpFileStream *
  99. *---------------*
  100. * Description:
  101. * This C++ class can be used by applications to turn a Win32 file into
  102. * a COM stream. Usually it is easier to use the CLSD_SpStream implementation
  103. * than to use this class directly, but this class allows for more fine-grained
  104. * control over various attributes, such as security attributes. You can also
  105. * use this class to create a stream from an existing file handle. Note that
  106. * if you want to use this class on an existing Win32 file handle, you should
  107. * either "give ownership" of that handle to this class (and allow this class
  108. * to close the handle) or else you will need to use DuplicateHandle to create
  109. * a handle that can be closed by this class.
  110. *
  111. * NOTE:
  112. * Upon creation of this class, the ref count is set to 1.
  113. *
  114. *****************************************************************************/
  115. class CSpFileStream : public IStream
  116. {
  117. private:
  118. HANDLE m_hFile;
  119. ULONG m_ulRef;
  120. public:
  121. CSpFileStream(HANDLE hFile) : m_hFile(hFile), m_ulRef(1) {}
  122. CSpFileStream(HRESULT * pHR, const TCHAR * pFileName, DWORD dwDesiredAccess = GENERIC_READ, DWORD dwShareMode = FILE_SHARE_READ, DWORD dwCreationDisposition = OPEN_EXISTING,
  123. LPSECURITY_ATTRIBUTES lpSecurityAttrib = NULL, DWORD dwFlagsAndAttrib = 0, HANDLE hTemplate = NULL)
  124. {
  125. m_hFile = ::CreateFile(pFileName, dwDesiredAccess, dwShareMode, lpSecurityAttrib, dwCreationDisposition, dwFlagsAndAttrib, hTemplate);
  126. m_ulRef = 1;
  127. *pHR = (m_hFile != INVALID_HANDLE_VALUE) ? S_OK : SpHrFromLastWin32Error();
  128. }
  129. #ifndef _UNICODE
  130. CSpFileStream(HRESULT * pHR, const WCHAR * pFileName, DWORD dwDesiredAccess = GENERIC_READ, DWORD dwShareMode = FILE_SHARE_READ, DWORD dwCreationDisposition = OPEN_EXISTING,
  131. LPSECURITY_ATTRIBUTES lpSecurityAttrib = NULL, DWORD dwFlagsAndAttrib = 0, HANDLE hTemplate = NULL)
  132. {
  133. CSpUnicodeSupport Unicode;
  134. m_hFile = Unicode.CreateFile(pFileName, dwDesiredAccess, dwShareMode, lpSecurityAttrib, dwCreationDisposition, dwFlagsAndAttrib, hTemplate);
  135. m_ulRef = 1;
  136. *pHR = (m_hFile != INVALID_HANDLE_VALUE) ? S_OK : SpHrFromLastWin32Error();
  137. }
  138. #endif
  139. ~CSpFileStream()
  140. {
  141. if (m_hFile != INVALID_HANDLE_VALUE)
  142. {
  143. ::CloseHandle(m_hFile);
  144. }
  145. }
  146. HANDLE FileHandle()
  147. {
  148. return m_hFile;
  149. }
  150. HRESULT Close(void)
  151. {
  152. HRESULT hr = S_OK;
  153. if (m_hFile != INVALID_HANDLE_VALUE)
  154. {
  155. if (!::CloseHandle(m_hFile))
  156. {
  157. hr = SpHrFromLastWin32Error();
  158. }
  159. m_hFile = INVALID_HANDLE_VALUE;
  160. }
  161. else
  162. {
  163. hr = SPERR_UNINITIALIZED;
  164. }
  165. return hr;
  166. }
  167. STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
  168. {
  169. if (riid == __uuidof(IStream) ||
  170. riid == IID_ISequentialStream ||
  171. riid == __uuidof(IUnknown))
  172. {
  173. *ppv = (IStream *)this;
  174. m_ulRef++;
  175. return S_OK;
  176. }
  177. *ppv = NULL;
  178. return E_NOINTERFACE;
  179. }
  180. STDMETHODIMP_(ULONG) AddRef()
  181. {
  182. return ++m_ulRef;
  183. }
  184. STDMETHODIMP_(ULONG) Release()
  185. {
  186. --m_ulRef;
  187. if (m_ulRef)
  188. {
  189. return m_ulRef;
  190. }
  191. delete this;
  192. return 0;
  193. }
  194. STDMETHODIMP Read(void * pv, ULONG cb, ULONG * pcbRead)
  195. {
  196. ULONG ulRead;
  197. if (::ReadFile(m_hFile, pv, cb, &ulRead, NULL))
  198. {
  199. if (pcbRead) *pcbRead = ulRead;
  200. return S_OK;
  201. }
  202. return SpHrFromLastWin32Error();
  203. }
  204. STDMETHODIMP Write(const void * pv, ULONG cb, ULONG * pcbWritten)
  205. {
  206. ULONG ulWritten;
  207. if (::WriteFile(m_hFile, pv, cb, &ulWritten, NULL))
  208. {
  209. if (pcbWritten) *pcbWritten = ulWritten;
  210. return S_OK;
  211. }
  212. return SpHrFromLastWin32Error();
  213. }
  214. STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  215. {
  216. long lMoveHigh = dlibMove.HighPart;
  217. DWORD dwNewPos = ::SetFilePointer(m_hFile, dlibMove.LowPart, &lMoveHigh, dwOrigin);
  218. if (dwNewPos == 0xFFFFFFFF && ::GetLastError() != NO_ERROR)
  219. {
  220. return SpHrFromLastWin32Error();
  221. }
  222. if (plibNewPosition)
  223. {
  224. plibNewPosition->LowPart = dwNewPos;
  225. plibNewPosition->HighPart = lMoveHigh;
  226. }
  227. return S_OK;
  228. }
  229. STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize)
  230. {
  231. HRESULT hr = S_OK;
  232. LARGE_INTEGER Move = {0};
  233. ULARGE_INTEGER Cur;
  234. hr = Seek(Move, STREAM_SEEK_CUR, &Cur);
  235. if (SUCCEEDED(hr))
  236. {
  237. LARGE_INTEGER li;
  238. li.QuadPart = libNewSize.QuadPart;
  239. hr = Seek(li, STREAM_SEEK_SET, NULL);
  240. if (SUCCEEDED(hr))
  241. {
  242. if (!::SetEndOfFile(m_hFile))
  243. {
  244. hr = SpHrFromLastWin32Error();
  245. }
  246. li.QuadPart = Cur.QuadPart;
  247. Seek(li, STREAM_SEEK_SET, NULL);
  248. }
  249. }
  250. return hr;
  251. }
  252. STDMETHODIMP CopyTo(IStream *pStreamDest, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER __RPC_FAR *pcbWritten)
  253. {
  254. return SpGenericCopyTo(this, pStreamDest, cb, pcbRead, pcbWritten);
  255. }
  256. STDMETHODIMP Commit(DWORD /*grfCommitFlags*/)
  257. {
  258. return S_OK; // Direct mode streams simply ignore this
  259. }
  260. STDMETHODIMP Revert(void)
  261. {
  262. return S_OK; // Direct mode streams simply ignore this
  263. }
  264. STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  265. {
  266. #ifndef _WIN32_WCE
  267. if (dwLockType != LOCK_WRITE && dwLockType != LOCK_EXCLUSIVE)
  268. {
  269. return STG_E_INVALIDFUNCTION;
  270. }
  271. DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
  272. if (dwLockType == LOCK_EXCLUSIVE)
  273. {
  274. dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
  275. }
  276. OVERLAPPED Overlapped;
  277. memset(&Overlapped, 0, sizeof(Overlapped));
  278. Overlapped.Offset = libOffset.LowPart;
  279. Overlapped.OffsetHigh = libOffset.HighPart;
  280. if (::LockFileEx(m_hFile, dwFlags, 0, cb.LowPart, cb.HighPart, &Overlapped))
  281. {
  282. return S_OK;
  283. }
  284. else
  285. {
  286. DWORD dwErr = ::GetLastError();
  287. if (dwErr == ERROR_LOCK_VIOLATION)
  288. {
  289. return STG_E_LOCKVIOLATION;
  290. }
  291. return SpHrFromWin32(dwErr);
  292. }
  293. #else // _WIN32_WCE
  294. return E_NOTIMPL;
  295. #endif // _WIN32_WCE
  296. }
  297. STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  298. {
  299. #ifndef _WIN32_WCE
  300. if (dwLockType != LOCK_WRITE && dwLockType != LOCK_EXCLUSIVE)
  301. {
  302. return STG_E_INVALIDFUNCTION;
  303. }
  304. OVERLAPPED Overlapped;
  305. memset(&Overlapped, 0, sizeof(Overlapped));
  306. Overlapped.Offset = libOffset.LowPart;
  307. Overlapped.OffsetHigh = libOffset.HighPart;
  308. if (::UnlockFileEx(m_hFile, 0, cb.LowPart, cb.HighPart, &Overlapped))
  309. {
  310. return S_OK;
  311. }
  312. else
  313. {
  314. DWORD dwErr = ::GetLastError();
  315. if (dwErr == ERROR_LOCK_VIOLATION)
  316. {
  317. return STG_E_LOCKVIOLATION;
  318. }
  319. return SpHrFromWin32(dwErr);
  320. }
  321. #else // _WIN32_WCE
  322. return E_NOTIMPL;
  323. #endif // _WIN32_WCE
  324. }
  325. STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  326. {
  327. HRESULT hr = S_OK;
  328. if (grfStatFlag & (~STATFLAG_NONAME))
  329. {
  330. hr = E_INVALIDARG;
  331. }
  332. else
  333. {
  334. ZeroMemory(pstatstg, sizeof(*pstatstg));
  335. pstatstg->grfLocksSupported = LOCK_WRITE | LOCK_EXCLUSIVE;
  336. pstatstg->type = STGTY_STREAM;
  337. BY_HANDLE_FILE_INFORMATION fi;
  338. if (::GetFileInformationByHandle(m_hFile, &fi))
  339. {
  340. pstatstg->cbSize.LowPart = fi.nFileSizeLow;
  341. pstatstg->cbSize.HighPart = fi.nFileSizeHigh;
  342. pstatstg->mtime = fi.ftLastWriteTime;
  343. pstatstg->ctime = fi.ftCreationTime;
  344. pstatstg->atime = fi.ftLastAccessTime;
  345. // This implementation does not fill in the mode or the name.
  346. }
  347. }
  348. return hr;
  349. }
  350. STDMETHODIMP Clone(IStream ** ppstm)
  351. {
  352. HANDLE hDupFile;
  353. #ifndef _WIN32_WCE
  354. HANDLE hProcess = ::GetCurrentProcess();
  355. if (::DuplicateHandle(hProcess, m_hFile, hProcess, &hDupFile, 0, TRUE, DUPLICATE_SAME_ACCESS))
  356. {
  357. *ppstm = new CSpFileStream(hDupFile);
  358. if (*ppstm)
  359. {
  360. return S_OK;
  361. }
  362. ::CloseHandle(hDupFile);
  363. return E_OUTOFMEMORY;
  364. }
  365. else
  366. {
  367. return SpHrFromLastWin32Error();
  368. }
  369. #else // _WIN32_WCE
  370. hDupFile = m_hFile;
  371. *ppstm = new CSpFileStream(hDupFile);
  372. if (*ppstm)
  373. {
  374. return S_OK;
  375. }
  376. return E_OUTOFMEMORY;
  377. #endif // _WIN32_WCE
  378. }
  379. };