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.

678 lines
14 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-2001 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. #ifndef __ATLFILE_H__
  11. #define __ATLFILE_H__
  12. #pragma once
  13. #include <atlbase.h>
  14. namespace ATL
  15. {
  16. class CAtlFile : public CHandle
  17. {
  18. public:
  19. CAtlFile() throw()
  20. {
  21. }
  22. CAtlFile( CAtlFile& file ) throw() :
  23. CHandle( file ) // Transfers ownership
  24. {
  25. }
  26. explicit CAtlFile( HANDLE hFile ) throw() :
  27. CHandle( hFile ) // Takes ownership
  28. {
  29. }
  30. HRESULT Create(
  31. LPCTSTR szFilename,
  32. DWORD dwDesiredAccess,
  33. DWORD dwShareMode,
  34. DWORD dwCreationDisposition,
  35. DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL,
  36. LPSECURITY_ATTRIBUTES lpsa = NULL,
  37. HANDLE hTemplateFile = NULL) throw()
  38. {
  39. ATLASSERT(m_h == NULL);
  40. HANDLE hFile = ::CreateFile(
  41. szFilename,
  42. dwDesiredAccess,
  43. dwShareMode,
  44. lpsa,
  45. dwCreationDisposition,
  46. dwFlagsAndAttributes,
  47. hTemplateFile);
  48. if (hFile == INVALID_HANDLE_VALUE)
  49. return AtlHresultFromLastError();
  50. Attach(hFile);
  51. return S_OK;
  52. }
  53. HRESULT Read(
  54. LPVOID pBuffer,
  55. DWORD nBufSize) throw()
  56. {
  57. ATLASSERT(m_h != NULL);
  58. DWORD nBytesRead = 0;
  59. BOOL bSuccess = ::ReadFile(m_h, pBuffer, nBufSize, &nBytesRead, NULL);
  60. if (!bSuccess )
  61. return AtlHresultFromLastError();
  62. if (nBytesRead != nBufSize)
  63. return HRESULT_FROM_WIN32( ERROR_HANDLE_EOF );
  64. return S_OK;
  65. }
  66. HRESULT Read(
  67. LPVOID pBuffer,
  68. DWORD nBufSize,
  69. DWORD& nBytesRead) throw()
  70. {
  71. ATLASSERT(m_h != NULL);
  72. BOOL b = ::ReadFile(m_h, pBuffer, nBufSize, &nBytesRead, NULL);
  73. if (!b)
  74. return AtlHresultFromLastError();
  75. return S_OK;
  76. }
  77. // this function will usually return HRESULT_FROM_WIN32(ERROR_IO_PENDING)
  78. // indicating succesful queueing of the operation
  79. HRESULT Read(
  80. LPVOID pBuffer,
  81. DWORD nBufSize,
  82. LPOVERLAPPED pOverlapped) throw()
  83. {
  84. ATLASSERT(m_h != NULL);
  85. BOOL b = ::ReadFile(m_h, pBuffer, nBufSize, NULL, pOverlapped);
  86. if (!b)
  87. return AtlHresultFromLastError();
  88. return S_OK;
  89. }
  90. HRESULT Read(
  91. LPVOID pBuffer,
  92. DWORD nBufSize,
  93. LPOVERLAPPED pOverlapped,
  94. LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine) throw()
  95. {
  96. ATLASSERT(m_h != NULL);
  97. BOOL b = ::ReadFileEx(m_h, pBuffer, nBufSize, pOverlapped, pfnCompletionRoutine);
  98. if (!b)
  99. return AtlHresultFromLastError();
  100. return S_OK;
  101. }
  102. HRESULT Write(
  103. LPCVOID pBuffer,
  104. DWORD nBufSize,
  105. DWORD* pnBytesWritten = NULL) throw()
  106. {
  107. ATLASSERT(m_h != NULL);
  108. DWORD nBytesWritten;
  109. if (pnBytesWritten == NULL)
  110. pnBytesWritten = &nBytesWritten;
  111. BOOL b = ::WriteFile(m_h, pBuffer, nBufSize, pnBytesWritten, NULL);
  112. if (!b)
  113. return AtlHresultFromLastError();
  114. return S_OK;
  115. }
  116. // this function will usually return HRESULT_FROM_WIN32(ERROR_IO_PENDING)
  117. // indicating succesful queueing of the operation
  118. HRESULT Write(
  119. LPCVOID pBuffer,
  120. DWORD nBufSize,
  121. LPOVERLAPPED pOverlapped) throw()
  122. {
  123. ATLASSERT(m_h != NULL);
  124. BOOL b = ::WriteFile(m_h, pBuffer, nBufSize, NULL, pOverlapped);
  125. if (!b)
  126. return AtlHresultFromLastError();
  127. return S_OK;
  128. }
  129. HRESULT Write(
  130. LPCVOID pBuffer,
  131. DWORD nBufSize,
  132. LPOVERLAPPED pOverlapped,
  133. LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine) throw()
  134. {
  135. ATLASSERT(m_h != NULL);
  136. BOOL b = ::WriteFileEx(m_h, pBuffer, nBufSize, pOverlapped, pfnCompletionRoutine);
  137. if (!b)
  138. return AtlHresultFromLastError();
  139. return S_OK;
  140. }
  141. // this function returns HRESULT_FROM_WIN32(ERROR_IO_INCOMPLETE)
  142. // if bWait is false and the operation is still pending
  143. HRESULT GetOverlappedResult(
  144. LPOVERLAPPED pOverlapped,
  145. DWORD& dwBytesTransferred,
  146. BOOL bWait) throw()
  147. {
  148. BOOL b = ::GetOverlappedResult(m_h, pOverlapped, &dwBytesTransferred, bWait);
  149. if (!b)
  150. return AtlHresultFromLastError();
  151. return S_OK;
  152. }
  153. HRESULT Seek(LONGLONG nOffset, DWORD dwFrom = FILE_CURRENT) throw()
  154. {
  155. ATLASSERT(m_h != NULL);
  156. ATLASSERT(dwFrom == FILE_BEGIN || dwFrom == FILE_END || dwFrom == FILE_CURRENT);
  157. LARGE_INTEGER liOffset;
  158. liOffset.QuadPart = nOffset;
  159. DWORD nNewPos = ::SetFilePointer(m_h, liOffset.LowPart, &liOffset.HighPart, dwFrom);
  160. if (nNewPos == INVALID_SET_FILE_POINTER)
  161. {
  162. HRESULT hr;
  163. hr = AtlHresultFromLastError();
  164. if (FAILED(hr))
  165. return hr;
  166. }
  167. return S_OK;
  168. }
  169. HRESULT GetPosition(ULONGLONG& nPos) const throw()
  170. {
  171. ATLASSERT(m_h != NULL);
  172. LARGE_INTEGER liOffset;
  173. liOffset.QuadPart = 0;
  174. liOffset.LowPart = ::SetFilePointer(m_h, 0, &liOffset.HighPart, FILE_CURRENT);
  175. if (liOffset.LowPart == INVALID_SET_FILE_POINTER)
  176. {
  177. HRESULT hr;
  178. hr = AtlHresultFromLastError();
  179. if (FAILED(hr))
  180. return hr;
  181. }
  182. nPos = liOffset.QuadPart;
  183. return S_OK;
  184. }
  185. HRESULT Flush() throw()
  186. {
  187. ATLASSERT(m_h != NULL);
  188. if (!::FlushFileBuffers(m_h))
  189. return AtlHresultFromLastError();
  190. return S_OK;
  191. }
  192. HRESULT LockRange(ULONGLONG nPos, ULONGLONG nCount) throw()
  193. {
  194. ATLASSERT(m_h != NULL);
  195. LARGE_INTEGER liPos;
  196. liPos.QuadPart = nPos;
  197. LARGE_INTEGER liCount;
  198. liCount.QuadPart = nCount;
  199. if (!::LockFile(m_h, liPos.LowPart, liPos.HighPart, liCount.LowPart, liCount.HighPart))
  200. return AtlHresultFromLastError();
  201. return S_OK;
  202. }
  203. HRESULT UnlockRange(ULONGLONG nPos, ULONGLONG nCount) throw()
  204. {
  205. ATLASSERT(m_h != NULL);
  206. LARGE_INTEGER liPos;
  207. liPos.QuadPart = nPos;
  208. LARGE_INTEGER liCount;
  209. liCount.QuadPart = nCount;
  210. if (!::UnlockFile(m_h, liPos.LowPart, liPos.HighPart, liCount.LowPart, liCount.HighPart))
  211. return AtlHresultFromLastError();
  212. return S_OK;
  213. }
  214. HRESULT SetSize(ULONGLONG nNewLen) throw()
  215. {
  216. ATLASSERT(m_h != NULL);
  217. HRESULT hr = Seek(nNewLen, FILE_BEGIN);
  218. if (FAILED(hr))
  219. return hr;
  220. if (!::SetEndOfFile(m_h))
  221. return AtlHresultFromLastError();
  222. return S_OK;
  223. }
  224. HRESULT GetSize(ULONGLONG& nLen) const throw()
  225. {
  226. ATLASSERT(m_h != NULL);
  227. ULARGE_INTEGER liFileSize;
  228. liFileSize.LowPart = ::GetFileSize(m_h, &liFileSize.HighPart);
  229. if (liFileSize.LowPart == 0xFFFFFFFF)
  230. {
  231. HRESULT hr;
  232. hr = AtlHresultFromLastError();
  233. if (FAILED(hr))
  234. return hr;
  235. }
  236. nLen = liFileSize.QuadPart;
  237. return S_OK;
  238. }
  239. };
  240. // This class allows the creation of a temporary file that is written to.
  241. // When the entire file has been successfully written it will be closed and given
  242. // it's proper file name if required.
  243. class CAtlTemporaryFile
  244. {
  245. public:
  246. CAtlTemporaryFile() throw()
  247. {
  248. }
  249. ~CAtlTemporaryFile() throw()
  250. {
  251. // Ensure that the temporary file is closed and deleted,
  252. // if necessary.
  253. if (m_file.m_h != NULL)
  254. {
  255. Close();
  256. }
  257. }
  258. HRESULT Create(LPCTSTR pszDir = NULL, DWORD dwDesiredAccess = GENERIC_WRITE) throw()
  259. {
  260. TCHAR szPath[_MAX_DIR+1];
  261. ATLASSERT(m_file.m_h == NULL);
  262. if (pszDir == NULL)
  263. {
  264. if (!GetTempPath(_MAX_DIR, szPath))
  265. {
  266. // Couldn't find temporary path;
  267. return AtlHresultFromLastError();
  268. }
  269. }
  270. else
  271. {
  272. _tcsncpy(szPath, pszDir, _MAX_DIR);
  273. szPath[_MAX_DIR] = 0;
  274. }
  275. if (!GetTempFileName(szPath, _T("TFR"), 0, m_szTempFileName))
  276. {
  277. // Couldn't create temporary filename;
  278. return AtlHresultFromLastError();
  279. }
  280. SECURITY_ATTRIBUTES secatt;
  281. secatt.nLength = sizeof(secatt);
  282. secatt.lpSecurityDescriptor = NULL;
  283. secatt.bInheritHandle = TRUE;
  284. m_dwAccess = dwDesiredAccess;
  285. return m_file.Create(
  286. m_szTempFileName,
  287. m_dwAccess,
  288. 0,
  289. CREATE_ALWAYS,
  290. FILE_ATTRIBUTE_NORMAL,
  291. &secatt);
  292. }
  293. HRESULT Close(LPCTSTR szNewName = NULL) throw()
  294. {
  295. ATLASSERT(m_file.m_h != NULL);
  296. // This routine is called when we are finished writing to the
  297. // temporary file, so we now just want to close it and copy
  298. // it to the actual filename we want it to be called.
  299. // So let's close it first.
  300. m_file.Close();
  301. // no new name so delete it
  302. if (szNewName == NULL)
  303. {
  304. ::DeleteFile(m_szTempFileName);
  305. return S_OK;
  306. }
  307. // delete any existing file and move our temp file into it's place
  308. if (!::DeleteFile(szNewName))
  309. {
  310. DWORD dwError = GetLastError();
  311. if (dwError != ERROR_FILE_NOT_FOUND)
  312. return AtlHresultFromWin32(dwError);
  313. }
  314. if (!::MoveFile(m_szTempFileName, szNewName))
  315. return AtlHresultFromLastError();
  316. return S_OK;
  317. }
  318. HRESULT HandsOff() throw()
  319. {
  320. m_file.Flush();
  321. m_file.Close();
  322. return S_OK;
  323. }
  324. HRESULT HandsOn() throw()
  325. {
  326. HRESULT hr = m_file.Create(
  327. m_szTempFileName,
  328. m_dwAccess,
  329. 0,
  330. OPEN_EXISTING);
  331. if (FAILED(hr))
  332. return hr;
  333. return m_file.Seek(0, FILE_END);
  334. }
  335. HRESULT Read(
  336. LPVOID pBuffer,
  337. DWORD nBufSize,
  338. DWORD& nBytesRead) throw()
  339. {
  340. return m_file.Read(pBuffer, nBufSize, nBytesRead);
  341. }
  342. HRESULT Write(
  343. LPCVOID pBuffer,
  344. DWORD nBufSize,
  345. DWORD* pnBytesWritten = NULL) throw()
  346. {
  347. return m_file.Write(pBuffer, nBufSize, pnBytesWritten);
  348. }
  349. HRESULT Seek(LONGLONG nOffset, DWORD dwFrom = FILE_CURRENT) throw()
  350. {
  351. return m_file.Seek(nOffset, dwFrom);
  352. }
  353. HRESULT GetPosition(ULONGLONG& nPos) const throw()
  354. {
  355. return m_file.GetPosition(nPos);
  356. }
  357. HRESULT Flush() throw()
  358. {
  359. return m_file.Flush();
  360. }
  361. HRESULT LockRange(ULONGLONG nPos, ULONGLONG nCount) throw()
  362. {
  363. return m_file.LockRange(nPos, nCount);
  364. }
  365. HRESULT UnlockRange(ULONGLONG nPos, ULONGLONG nCount) throw()
  366. {
  367. return m_file.UnlockRange(nPos, nCount);
  368. }
  369. HRESULT SetSize(ULONGLONG nNewLen) throw()
  370. {
  371. return m_file.SetSize(nNewLen);
  372. }
  373. HRESULT GetSize(ULONGLONG& nLen) const throw()
  374. {
  375. return m_file.GetSize(nLen);
  376. }
  377. operator HANDLE() throw()
  378. {
  379. return m_file;
  380. }
  381. LPCTSTR TempFileName() throw()
  382. {
  383. return m_szTempFileName;
  384. }
  385. private:
  386. CAtlFile m_file;
  387. TCHAR m_szTempFileName[_MAX_FNAME+1];
  388. DWORD m_dwAccess;
  389. };
  390. class CAtlFileMappingBase
  391. {
  392. public:
  393. CAtlFileMappingBase() throw()
  394. {
  395. m_pData = NULL;
  396. m_hMapping = NULL;
  397. }
  398. ~CAtlFileMappingBase() throw()
  399. {
  400. Unmap();
  401. }
  402. HRESULT MapFile(
  403. HANDLE hFile,
  404. DWORD nMappingSize = 0,
  405. ULONGLONG nOffset = 0,
  406. DWORD dwMappingProtection = PAGE_READONLY,
  407. DWORD dwViewDesiredAccess = FILE_MAP_READ) throw()
  408. {
  409. ATLASSERT(m_pData == NULL);
  410. ATLASSERT(m_hMapping == NULL);
  411. ATLASSERT(hFile != INVALID_HANDLE_VALUE && hFile != NULL);
  412. ULARGE_INTEGER liFileSize;
  413. liFileSize.LowPart = ::GetFileSize(hFile, &liFileSize.HighPart);
  414. if (liFileSize.QuadPart < nMappingSize)
  415. liFileSize.QuadPart = nMappingSize;
  416. m_hMapping = ::CreateFileMapping(hFile, NULL, dwMappingProtection, liFileSize.HighPart, liFileSize.LowPart, 0);
  417. if (m_hMapping == NULL)
  418. return AtlHresultFromLastError();
  419. if (nMappingSize == 0)
  420. m_dwMappingSize = (DWORD) (liFileSize.QuadPart - nOffset);
  421. else
  422. m_dwMappingSize = nMappingSize;
  423. m_dwViewDesiredAccess = dwViewDesiredAccess;
  424. m_nOffset.QuadPart = nOffset;
  425. m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_dwMappingSize, NULL);
  426. if (m_pData == NULL)
  427. {
  428. HRESULT hr;
  429. hr = AtlHresultFromLastError();
  430. ::CloseHandle(m_hMapping);
  431. m_hMapping = NULL;
  432. return hr;
  433. }
  434. return S_OK;
  435. }
  436. HRESULT MapSharedMem(
  437. DWORD nMappingSize,
  438. LPCTSTR szName,
  439. BOOL* pbAlreadyExisted = NULL,
  440. LPSECURITY_ATTRIBUTES lpsa = NULL,
  441. DWORD dwMappingProtection = PAGE_READWRITE,
  442. DWORD dwViewDesiredAccess = FILE_MAP_ALL_ACCESS) throw()
  443. {
  444. ATLASSERT(m_pData == NULL);
  445. ATLASSERT(m_hMapping == NULL);
  446. ATLASSERT(nMappingSize > 0);
  447. ATLASSERT(szName != NULL); // if you just want a regular chunk of memory, use a heap allocator
  448. m_dwMappingSize = nMappingSize;
  449. m_hMapping = ::CreateFileMapping(NULL, lpsa, dwMappingProtection, 0, m_dwMappingSize, szName);
  450. if (m_hMapping == NULL)
  451. return AtlHresultFromLastError();
  452. if (pbAlreadyExisted != NULL)
  453. *pbAlreadyExisted = (GetLastError() == ERROR_ALREADY_EXISTS);
  454. m_dwViewDesiredAccess = dwViewDesiredAccess;
  455. m_nOffset.QuadPart = 0;
  456. m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_dwMappingSize, NULL);
  457. if (m_pData == NULL)
  458. {
  459. HRESULT hr;
  460. hr = AtlHresultFromLastError();
  461. ::CloseHandle(m_hMapping);
  462. return hr;
  463. }
  464. return S_OK;
  465. }
  466. HRESULT Unmap() throw()
  467. {
  468. HRESULT hr = S_OK;
  469. if (m_pData != NULL)
  470. {
  471. if (!::UnmapViewOfFile(m_pData))
  472. hr = AtlHresultFromLastError();
  473. m_pData = NULL;
  474. }
  475. if (m_hMapping != NULL)
  476. {
  477. if (!::CloseHandle(m_hMapping) && SUCCEEDED(hr))
  478. hr = AtlHresultFromLastError();
  479. m_hMapping = NULL;
  480. }
  481. return hr;
  482. }
  483. void* GetData() const throw()
  484. {
  485. return m_pData;
  486. }
  487. DWORD GetMappingSize() throw()
  488. {
  489. return m_dwMappingSize;
  490. }
  491. HRESULT CopyFrom(CAtlFileMappingBase& orig) throw()
  492. {
  493. ATLASSERT(m_pData == NULL);
  494. ATLASSERT(m_hMapping == NULL);
  495. ATLASSERT(orig.m_pData != NULL);
  496. ATLASSERT(orig.m_hMapping != NULL);
  497. m_dwViewDesiredAccess = orig.m_dwViewDesiredAccess;
  498. m_nOffset.QuadPart = orig.m_nOffset.QuadPart;
  499. m_dwMappingSize = orig.m_dwMappingSize;
  500. if (!::DuplicateHandle(GetCurrentProcess(), orig.m_hMapping, GetCurrentProcess(),
  501. &m_hMapping, NULL, TRUE, DUPLICATE_SAME_ACCESS))
  502. return AtlHresultFromLastError();
  503. m_pData = ::MapViewOfFileEx(m_hMapping, m_dwViewDesiredAccess, m_nOffset.HighPart, m_nOffset.LowPart, m_dwMappingSize, NULL);
  504. if (m_pData == NULL)
  505. {
  506. HRESULT hr;
  507. hr = AtlHresultFromLastError();
  508. ::CloseHandle(m_hMapping);
  509. m_hMapping = NULL;
  510. return hr;
  511. }
  512. return S_OK;
  513. }
  514. CAtlFileMappingBase(CAtlFileMappingBase& orig)
  515. {
  516. m_pData = NULL;
  517. m_hMapping = NULL;
  518. HRESULT hr = CopyFrom(orig);
  519. if (FAILED(hr))
  520. AtlThrow(hr);
  521. }
  522. CAtlFileMappingBase& operator=(CAtlFileMappingBase& orig)
  523. {
  524. HRESULT hr = CopyFrom(orig);
  525. if (FAILED(hr))
  526. AtlThrow(hr);
  527. return *this;
  528. }
  529. private:
  530. void* m_pData;
  531. DWORD m_dwMappingSize;
  532. HANDLE m_hMapping;
  533. ULARGE_INTEGER m_nOffset;
  534. DWORD m_dwViewDesiredAccess;
  535. };
  536. template <typename T = char>
  537. class CAtlFileMapping : public CAtlFileMappingBase
  538. {
  539. public:
  540. operator T*() const throw()
  541. {
  542. return reinterpret_cast<T*>(GetData());
  543. }
  544. };
  545. }; //namespace ATL
  546. #endif //__ATLFILE_H__