filecore.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include "stdafx.h"
  11. #include <winnetwk.h>
  12. #include <shlobj.h>
  13. #include <shellapi.h>
  14. #ifdef AFX_CORE1_SEG
  15. #pragma code_seg(AFX_CORE1_SEG)
  16. #endif
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21. #define new DEBUG_NEW
  22. AFX_STATIC inline BOOL IsDirSep(TCHAR ch)
  23. {
  24. return (ch == '\\' || ch == '/');
  25. }
  26. #ifndef _AFX_NO_OLE_SUPPORT
  27. #undef DEFINE_GUID
  28. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  29. EXTERN_C AFX_COMDAT const GUID afx##name \
  30. = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
  31. #define DEFINE_SHLGUID(name, l, w1, w2) DEFINE_GUID(name, l, w1, w2, 0xC0,0,0,0,0,0,0,0x46)
  32. DEFINE_SHLGUID(CLSID_ShellLink, 0x00021401L, 0, 0);
  33. #ifndef _UNICODE
  34. DEFINE_SHLGUID(IID_IShellLinkA, 0x000214EEL, 0, 0);
  35. #else
  36. DEFINE_SHLGUID(IID_IShellLinkW, 0x000214F9L, 0, 0);
  37. #endif
  38. #define CLSID_ShellLink afxCLSID_ShellLink
  39. #undef IID_IShellLink
  40. #undef IShellLink
  41. #ifndef _UNICODE
  42. #define IID_IShellLink afxIID_IShellLinkA
  43. #define IShellLink IShellLinkA
  44. #else
  45. #define IID_IShellLink afxIID_IShellLinkW
  46. #define IShellLink IShellLinkW
  47. #endif
  48. #endif !_AFX_NO_OLE_SUPPORT
  49. ////////////////////////////////////////////////////////////////////////////
  50. // CFile implementation
  51. CFile::CFile()
  52. {
  53. m_hFile = (UINT) hFileNull;
  54. m_bCloseOnDelete = FALSE;
  55. }
  56. CFile::CFile(int hFile)
  57. {
  58. m_hFile = hFile;
  59. m_bCloseOnDelete = FALSE;
  60. }
  61. CFile::CFile(LPCTSTR lpszFileName, UINT nOpenFlags)
  62. {
  63. ASSERT(AfxIsValidString(lpszFileName));
  64. CFileException e;
  65. if (!Open(lpszFileName, nOpenFlags, &e))
  66. AfxThrowFileException(e.m_cause, e.m_lOsError, e.m_strFileName);
  67. }
  68. CFile::~CFile()
  69. {
  70. if (m_hFile != (UINT)hFileNull && m_bCloseOnDelete)
  71. Close();
  72. }
  73. CFile* CFile::Duplicate() const
  74. {
  75. ASSERT_VALID(this);
  76. ASSERT(m_hFile != (UINT)hFileNull);
  77. CFile* pFile = new CFile(hFileNull);
  78. HANDLE hFile;
  79. if (!::DuplicateHandle(::GetCurrentProcess(), (HANDLE)m_hFile,
  80. ::GetCurrentProcess(), &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS))
  81. {
  82. delete pFile;
  83. CFileException::ThrowOsError((LONG)::GetLastError());
  84. }
  85. pFile->m_hFile = (UINT)hFile;
  86. ASSERT(pFile->m_hFile != (UINT)hFileNull);
  87. pFile->m_bCloseOnDelete = m_bCloseOnDelete;
  88. return pFile;
  89. }
  90. BOOL CFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags,
  91. CFileException* pException)
  92. {
  93. ASSERT_VALID(this);
  94. ASSERT(AfxIsValidString(lpszFileName));
  95. ASSERT(pException == NULL ||
  96. AfxIsValidAddress(pException, sizeof(CFileException)));
  97. ASSERT((nOpenFlags & typeText) == 0); // text mode not supported
  98. // CFile objects are always binary and CreateFile does not need flag
  99. nOpenFlags &= ~(UINT)typeBinary;
  100. m_bCloseOnDelete = FALSE;
  101. m_hFile = (UINT)hFileNull;
  102. m_strFileName.Empty();
  103. TCHAR szTemp[_MAX_PATH];
  104. AfxFullPath(szTemp, lpszFileName);
  105. m_strFileName = szTemp;
  106. ASSERT(sizeof(HANDLE) == sizeof(UINT));
  107. ASSERT(shareCompat == 0);
  108. // map read/write mode
  109. ASSERT((modeRead|modeWrite|modeReadWrite) == 3);
  110. DWORD dwAccess = 0;
  111. switch (nOpenFlags & 3)
  112. {
  113. case modeRead:
  114. dwAccess = GENERIC_READ;
  115. break;
  116. case modeWrite:
  117. dwAccess = GENERIC_WRITE;
  118. break;
  119. case modeReadWrite:
  120. dwAccess = GENERIC_READ|GENERIC_WRITE;
  121. break;
  122. default:
  123. ASSERT(FALSE); // invalid share mode
  124. }
  125. // map share mode
  126. DWORD dwShareMode = 0;
  127. switch (nOpenFlags & 0x70) // map compatibility mode to exclusive
  128. {
  129. default:
  130. ASSERT(FALSE); // invalid share mode?
  131. case shareCompat:
  132. case shareExclusive:
  133. dwShareMode = 0;
  134. break;
  135. case shareDenyWrite:
  136. dwShareMode = FILE_SHARE_READ;
  137. break;
  138. case shareDenyRead:
  139. dwShareMode = FILE_SHARE_WRITE;
  140. break;
  141. case shareDenyNone:
  142. dwShareMode = FILE_SHARE_WRITE|FILE_SHARE_READ;
  143. break;
  144. }
  145. // Note: typeText and typeBinary are used in derived classes only.
  146. // map modeNoInherit flag
  147. SECURITY_ATTRIBUTES sa;
  148. sa.nLength = sizeof(sa);
  149. sa.lpSecurityDescriptor = NULL;
  150. sa.bInheritHandle = (nOpenFlags & modeNoInherit) == 0;
  151. // map creation flags
  152. DWORD dwCreateFlag;
  153. if (nOpenFlags & modeCreate)
  154. {
  155. if (nOpenFlags & modeNoTruncate)
  156. dwCreateFlag = OPEN_ALWAYS;
  157. else
  158. dwCreateFlag = CREATE_ALWAYS;
  159. }
  160. else
  161. dwCreateFlag = OPEN_EXISTING;
  162. // attempt file creation
  163. HANDLE hFile = ::CreateFile(lpszFileName, dwAccess, dwShareMode, &sa,
  164. dwCreateFlag, FILE_ATTRIBUTE_NORMAL, NULL);
  165. if (hFile == INVALID_HANDLE_VALUE)
  166. {
  167. if (pException != NULL)
  168. {
  169. pException->m_lOsError = ::GetLastError();
  170. pException->m_cause =
  171. CFileException::OsErrorToException(pException->m_lOsError);
  172. // use passed file name (not expanded vesion) when reporting
  173. // an error while opening
  174. pException->m_strFileName = lpszFileName;
  175. }
  176. return FALSE;
  177. }
  178. m_hFile = (HFILE)hFile;
  179. m_bCloseOnDelete = TRUE;
  180. return TRUE;
  181. }
  182. UINT CFile::Read(void* lpBuf, UINT nCount)
  183. {
  184. ASSERT_VALID(this);
  185. ASSERT(m_hFile != (UINT)hFileNull);
  186. if (nCount == 0)
  187. return 0; // avoid Win32 "null-read"
  188. ASSERT(lpBuf != NULL);
  189. ASSERT(AfxIsValidAddress(lpBuf, nCount));
  190. DWORD dwRead;
  191. if (!::ReadFile((HANDLE)m_hFile, lpBuf, nCount, &dwRead, NULL))
  192. CFileException::ThrowOsError((LONG)::GetLastError());
  193. return (UINT)dwRead;
  194. }
  195. void CFile::Write(const void* lpBuf, UINT nCount)
  196. {
  197. ASSERT_VALID(this);
  198. ASSERT(m_hFile != (UINT)hFileNull);
  199. if (nCount == 0)
  200. return; // avoid Win32 "null-write" option
  201. ASSERT(lpBuf != NULL);
  202. ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE));
  203. DWORD nWritten;
  204. if (!::WriteFile((HANDLE)m_hFile, lpBuf, nCount, &nWritten, NULL))
  205. CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
  206. // Win32s will not return an error all the time (usually DISK_FULL)
  207. if (nWritten != nCount)
  208. AfxThrowFileException(CFileException::diskFull, -1, m_strFileName);
  209. }
  210. LONG CFile::Seek(LONG lOff, UINT nFrom)
  211. {
  212. ASSERT_VALID(this);
  213. ASSERT(m_hFile != (UINT)hFileNull);
  214. ASSERT(nFrom == begin || nFrom == end || nFrom == current);
  215. ASSERT(begin == FILE_BEGIN && end == FILE_END && current == FILE_CURRENT);
  216. DWORD dwNew = ::SetFilePointer((HANDLE)m_hFile, lOff, NULL, (DWORD)nFrom);
  217. if (dwNew == (DWORD)-1)
  218. CFileException::ThrowOsError((LONG)::GetLastError());
  219. return dwNew;
  220. }
  221. DWORD CFile::GetPosition() const
  222. {
  223. ASSERT_VALID(this);
  224. ASSERT(m_hFile != (UINT)hFileNull);
  225. DWORD dwPos = ::SetFilePointer((HANDLE)m_hFile, 0, NULL, FILE_CURRENT);
  226. if (dwPos == (DWORD)-1)
  227. CFileException::ThrowOsError((LONG)::GetLastError());
  228. return dwPos;
  229. }
  230. void CFile::Flush()
  231. {
  232. ASSERT_VALID(this);
  233. if (m_hFile == (UINT)hFileNull)
  234. return;
  235. if (!::FlushFileBuffers((HANDLE)m_hFile))
  236. CFileException::ThrowOsError((LONG)::GetLastError());
  237. }
  238. void CFile::Close()
  239. {
  240. ASSERT_VALID(this);
  241. ASSERT(m_hFile != (UINT)hFileNull);
  242. BOOL bError = FALSE;
  243. if (m_hFile != (UINT)hFileNull)
  244. bError = !::CloseHandle((HANDLE)m_hFile);
  245. m_hFile = (UINT) hFileNull;
  246. m_bCloseOnDelete = FALSE;
  247. m_strFileName.Empty();
  248. if (bError)
  249. CFileException::ThrowOsError((LONG)::GetLastError());
  250. }
  251. void CFile::Abort()
  252. {
  253. ASSERT_VALID(this);
  254. if (m_hFile != (UINT)hFileNull)
  255. {
  256. // close but ignore errors
  257. ::CloseHandle((HANDLE)m_hFile);
  258. m_hFile = (UINT)hFileNull;
  259. }
  260. m_strFileName.Empty();
  261. }
  262. void CFile::LockRange(DWORD dwPos, DWORD dwCount)
  263. {
  264. ASSERT_VALID(this);
  265. ASSERT(m_hFile != (UINT)hFileNull);
  266. if (!::LockFile((HANDLE)m_hFile, dwPos, 0, dwCount, 0))
  267. CFileException::ThrowOsError((LONG)::GetLastError());
  268. }
  269. void CFile::UnlockRange(DWORD dwPos, DWORD dwCount)
  270. {
  271. ASSERT_VALID(this);
  272. ASSERT(m_hFile != (UINT)hFileNull);
  273. if (!::UnlockFile((HANDLE)m_hFile, dwPos, 0, dwCount, 0))
  274. CFileException::ThrowOsError((LONG)::GetLastError());
  275. }
  276. void CFile::SetLength(DWORD dwNewLen)
  277. {
  278. ASSERT_VALID(this);
  279. ASSERT(m_hFile != (UINT)hFileNull);
  280. Seek((LONG)dwNewLen, (UINT)begin);
  281. if (!::SetEndOfFile((HANDLE)m_hFile))
  282. CFileException::ThrowOsError((LONG)::GetLastError());
  283. }
  284. DWORD CFile::GetLength() const
  285. {
  286. ASSERT_VALID(this);
  287. DWORD dwLen, dwCur;
  288. // Seek is a non const operation
  289. CFile* pFile = (CFile*)this;
  290. dwCur = pFile->Seek(0L, current);
  291. dwLen = pFile->SeekToEnd();
  292. VERIFY(dwCur == (DWORD)pFile->Seek(dwCur, begin));
  293. return dwLen;
  294. }
  295. // CFile does not support direct buffering (CMemFile does)
  296. UINT CFile::GetBufferPtr(UINT nCommand, UINT /*nCount*/,
  297. void** /*ppBufStart*/, void** /*ppBufMax*/)
  298. {
  299. ASSERT(nCommand == bufferCheck);
  300. UNUSED(nCommand); // not used in retail build
  301. return 0; // no support
  302. }
  303. void PASCAL CFile::Rename(LPCTSTR lpszOldName, LPCTSTR lpszNewName)
  304. {
  305. if (!::MoveFile((LPTSTR)lpszOldName, (LPTSTR)lpszNewName))
  306. CFileException::ThrowOsError((LONG)::GetLastError());
  307. }
  308. void PASCAL CFile::Remove(LPCTSTR lpszFileName)
  309. {
  310. if (!::DeleteFile((LPTSTR)lpszFileName))
  311. CFileException::ThrowOsError((LONG)::GetLastError());
  312. }
  313. /////////////////////////////////////////////////////////////////////////////
  314. // CFile implementation helpers
  315. #ifdef AfxGetFileName
  316. #undef AfxGetFileName
  317. #endif
  318. #ifndef _AFX_NO_OLE_SUPPORT
  319. HRESULT AFX_COM::CreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter,
  320. REFIID riid, LPVOID* ppv)
  321. {
  322. // find the object's class factory
  323. LPCLASSFACTORY pf = NULL;
  324. HRESULT hRes = GetClassObject(rclsid, IID_IClassFactory, (LPVOID*)&pf);
  325. if (FAILED(hRes))
  326. return hRes;
  327. // call it to create the instance
  328. ASSERT(pf != NULL);
  329. hRes = pf->CreateInstance(pUnkOuter, riid, ppv);
  330. // let go of the factory
  331. pf->Release();
  332. return hRes;
  333. }
  334. HRESULT AFX_COM::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  335. {
  336. *ppv = NULL;
  337. HINSTANCE hInst = NULL;
  338. // find server name for this class ID
  339. CString strCLSID = AfxStringFromCLSID(rclsid);
  340. CString strServer;
  341. if (!AfxGetInProcServer(strCLSID, strServer))
  342. return REGDB_E_CLASSNOTREG;
  343. // try to load it
  344. hInst = LoadLibrary(strServer);
  345. if (hInst == NULL)
  346. return REGDB_E_CLASSNOTREG;
  347. #pragma warning(disable:4191)
  348. // get its entry point
  349. HRESULT (STDAPICALLTYPE* pfn)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
  350. pfn = (HRESULT (STDAPICALLTYPE*)(REFCLSID rclsid, REFIID riid, LPVOID* ppv))
  351. GetProcAddress(hInst, "DllGetClassObject");
  352. #pragma warning(default:4191)
  353. // call it, if it worked
  354. if (pfn != NULL)
  355. return pfn(rclsid, riid, ppv);
  356. return CO_E_ERRORINDLL;
  357. }
  358. CString AFXAPI AfxStringFromCLSID(REFCLSID rclsid)
  359. {
  360. TCHAR szCLSID[256];
  361. wsprintf(szCLSID, _T("{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"),
  362. rclsid.Data1, rclsid.Data2, rclsid.Data3,
  363. rclsid.Data4[0], rclsid.Data4[1], rclsid.Data4[2], rclsid.Data4[3],
  364. rclsid.Data4[4], rclsid.Data4[5], rclsid.Data4[6], rclsid.Data4[7]);
  365. return szCLSID;
  366. }
  367. BOOL AFXAPI AfxGetInProcServer(LPCTSTR lpszCLSID, CString& str)
  368. {
  369. HKEY hKey = NULL;
  370. BOOL b = FALSE;
  371. if (RegOpenKey(HKEY_CLASSES_ROOT, _T("CLSID"), &hKey) == ERROR_SUCCESS)
  372. {
  373. HKEY hKeyCLSID = NULL;
  374. if (RegOpenKey(hKey, lpszCLSID, &hKeyCLSID) == ERROR_SUCCESS)
  375. {
  376. HKEY hKeyInProc = NULL;
  377. if (RegOpenKey(hKeyCLSID, _T("InProcServer32"), &hKeyInProc) ==
  378. ERROR_SUCCESS)
  379. {
  380. LPTSTR lpsz = str.GetBuffer(_MAX_PATH);
  381. DWORD dwSize = _MAX_PATH * sizeof(TCHAR);
  382. DWORD dwType;
  383. LONG lRes = ::RegQueryValueEx(hKeyInProc, _T(""),
  384. NULL, &dwType, (BYTE*)lpsz, &dwSize);
  385. str.ReleaseBuffer();
  386. b = (lRes == ERROR_SUCCESS);
  387. RegCloseKey(hKeyInProc);
  388. }
  389. RegCloseKey(hKeyCLSID);
  390. }
  391. RegCloseKey(hKey);
  392. }
  393. return b;
  394. }
  395. BOOL AFXAPI AfxResolveShortcut(CWnd* pWnd, LPCTSTR lpszFileIn,
  396. LPTSTR lpszFileOut, int cchPath)
  397. {
  398. USES_CONVERSION;
  399. AFX_COM com;
  400. IShellLink* psl;
  401. *lpszFileOut = 0; // assume failure
  402. SHFILEINFO info;
  403. if ((SHGetFileInfo(lpszFileIn, 0, &info, sizeof(info),
  404. SHGFI_ATTRIBUTES) == 0) || !(info.dwAttributes & SFGAO_LINK))
  405. {
  406. return FALSE;
  407. }
  408. if (FAILED(com.CreateInstance(CLSID_ShellLink, NULL, IID_IShellLink,
  409. (LPVOID*)&psl)))
  410. {
  411. return FALSE;
  412. }
  413. IPersistFile *ppf;
  414. if (SUCCEEDED(psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
  415. {
  416. if (SUCCEEDED(ppf->Load(T2COLE(lpszFileIn), STGM_READ)))
  417. {
  418. /* Resolve the link, this may post UI to find the link */
  419. if (SUCCEEDED(psl->Resolve(pWnd->GetSafeHwnd(),
  420. SLR_ANY_MATCH)))
  421. {
  422. psl->GetPath(lpszFileOut, cchPath, NULL, 0);
  423. ppf->Release();
  424. psl->Release();
  425. return TRUE;
  426. }
  427. }
  428. ppf->Release();
  429. }
  430. psl->Release();
  431. return FALSE;
  432. }
  433. #endif //!_AFX_NO_OLE_SUPPORT
  434. // turn a file, relative path or other into an absolute path
  435. BOOL AFXAPI AfxFullPath(LPTSTR lpszPathOut, LPCTSTR lpszFileIn)
  436. // lpszPathOut = buffer of _MAX_PATH
  437. // lpszFileIn = file, relative path or absolute path
  438. // (both in ANSI character set)
  439. {
  440. ASSERT(AfxIsValidAddress(lpszPathOut, _MAX_PATH));
  441. // first, fully qualify the path name
  442. LPTSTR lpszFilePart;
  443. if (!GetFullPathName(lpszFileIn, _MAX_PATH, lpszPathOut, &lpszFilePart))
  444. {
  445. #ifdef _DEBUG
  446. if (lpszFileIn[0] != '\0')
  447. TRACE1("Warning: could not parse the path '%s'.\n", lpszFileIn);
  448. #endif
  449. lstrcpyn(lpszPathOut, lpszFileIn, _MAX_PATH); // take it literally
  450. return FALSE;
  451. }
  452. CString strRoot;
  453. // determine the root name of the volume
  454. AfxGetRoot(lpszPathOut, strRoot);
  455. // get file system information for the volume
  456. DWORD dwFlags, dwDummy;
  457. if (!GetVolumeInformation(strRoot, NULL, 0, NULL, &dwDummy, &dwFlags,
  458. NULL, 0))
  459. {
  460. TRACE1("Warning: could not get volume information '%s'.\n",
  461. (LPCTSTR)strRoot);
  462. return FALSE; // preserving case may not be correct
  463. }
  464. // not all characters have complete uppercase/lowercase
  465. if (!(dwFlags & FS_CASE_IS_PRESERVED))
  466. CharUpper(lpszPathOut);
  467. // assume non-UNICODE file systems, use OEM character set
  468. if (!(dwFlags & FS_UNICODE_STORED_ON_DISK))
  469. {
  470. WIN32_FIND_DATA data;
  471. HANDLE h = FindFirstFile(lpszFileIn, &data);
  472. if (h != INVALID_HANDLE_VALUE)
  473. {
  474. FindClose(h);
  475. lstrcpy(lpszFilePart, data.cFileName);
  476. }
  477. }
  478. return TRUE;
  479. }
  480. void AFXAPI AfxGetRoot(LPCTSTR lpszPath, CString& strRoot)
  481. {
  482. ASSERT(lpszPath != NULL);
  483. // determine the root name of the volume
  484. LPTSTR lpszRoot = strRoot.GetBuffer(_MAX_PATH);
  485. memset(lpszRoot, 0, _MAX_PATH);
  486. lstrcpyn(lpszRoot, lpszPath, _MAX_PATH);
  487. for (LPTSTR lpsz = lpszRoot; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  488. {
  489. // find first double slash and stop
  490. if (IsDirSep(lpsz[0]) && IsDirSep(lpsz[1]))
  491. break;
  492. }
  493. if (*lpsz != '\0')
  494. {
  495. // it is a UNC name, find second slash past '\\'
  496. ASSERT(IsDirSep(lpsz[0]));
  497. ASSERT(IsDirSep(lpsz[1]));
  498. lpsz += 2;
  499. while (*lpsz != '\0' && (!IsDirSep(*lpsz)))
  500. lpsz = _tcsinc(lpsz);
  501. if (*lpsz != '\0')
  502. lpsz = _tcsinc(lpsz);
  503. while (*lpsz != '\0' && (!IsDirSep(*lpsz)))
  504. lpsz = _tcsinc(lpsz);
  505. // terminate it just after the UNC root (ie. '\\server\share\')
  506. if (*lpsz != '\0')
  507. lpsz[1] = '\0';
  508. }
  509. else
  510. {
  511. // not a UNC, look for just the first slash
  512. lpsz = lpszRoot;
  513. while (*lpsz != '\0' && (!IsDirSep(*lpsz)))
  514. lpsz = _tcsinc(lpsz);
  515. // terminate it just after root (ie. 'x:\')
  516. if (*lpsz != '\0')
  517. lpsz[1] = '\0';
  518. }
  519. strRoot.ReleaseBuffer();
  520. }
  521. BOOL AFXAPI AfxComparePath(LPCTSTR lpszPath1, LPCTSTR lpszPath2)
  522. {
  523. // use case insensitive compare as a starter
  524. if (lstrcmpi(lpszPath1, lpszPath2) != 0)
  525. return FALSE;
  526. // on non-DBCS systems, we are done
  527. if (!GetSystemMetrics(SM_DBCSENABLED))
  528. return TRUE;
  529. // on DBCS systems, the file name may not actually be the same
  530. // in particular, the file system is case sensitive with respect to
  531. // "full width" roman characters.
  532. // (ie. fullwidth-R is different from fullwidth-r).
  533. int nLen = lstrlen(lpszPath1);
  534. if (nLen != lstrlen(lpszPath2))
  535. return FALSE;
  536. ASSERT(nLen < _MAX_PATH);
  537. // need to get both CT_CTYPE1 and CT_CTYPE3 for each filename
  538. LCID lcid = GetThreadLocale();
  539. WORD aCharType11[_MAX_PATH];
  540. VERIFY(GetStringTypeEx(lcid, CT_CTYPE1, lpszPath1, -1, aCharType11));
  541. WORD aCharType13[_MAX_PATH];
  542. VERIFY(GetStringTypeEx(lcid, CT_CTYPE3, lpszPath1, -1, aCharType13));
  543. WORD aCharType21[_MAX_PATH];
  544. VERIFY(GetStringTypeEx(lcid, CT_CTYPE1, lpszPath2, -1, aCharType21));
  545. #ifdef _DEBUG
  546. WORD aCharType23[_MAX_PATH];
  547. VERIFY(GetStringTypeEx(lcid, CT_CTYPE3, lpszPath2, -1, aCharType23));
  548. #endif
  549. // for every C3_FULLWIDTH character, make sure it has same C1 value
  550. int i = 0;
  551. for (LPCTSTR lpsz = lpszPath1; *lpsz != 0; lpsz = _tcsinc(lpsz))
  552. {
  553. // check for C3_FULLWIDTH characters only
  554. if (aCharType13[i] & C3_FULLWIDTH)
  555. {
  556. #ifdef _DEBUG
  557. ASSERT(aCharType23[i] & C3_FULLWIDTH); // should always match!
  558. #endif
  559. // if CT_CTYPE1 is different then file system considers these
  560. // file names different.
  561. if (aCharType11[i] != aCharType21[i])
  562. return FALSE;
  563. }
  564. ++i; // look at next character type
  565. }
  566. return TRUE; // otherwise file name is truly the same
  567. }
  568. #ifndef WINSCP
  569. UINT AFXAPI AfxGetFileTitle(LPCTSTR lpszPathName, LPTSTR lpszTitle, UINT nMax)
  570. {
  571. ASSERT(lpszTitle == NULL ||
  572. AfxIsValidAddress(lpszTitle, _MAX_FNAME));
  573. ASSERT(AfxIsValidString(lpszPathName));
  574. // use a temporary to avoid bugs in ::GetFileTitle when lpszTitle is NULL
  575. TCHAR szTemp[_MAX_PATH];
  576. LPTSTR lpszTemp = lpszTitle;
  577. if (lpszTemp == NULL)
  578. {
  579. lpszTemp = szTemp;
  580. nMax = _countof(szTemp);
  581. }
  582. if (::GetFileTitle(lpszPathName, lpszTemp, (WORD)nMax) != 0)
  583. {
  584. // when ::GetFileTitle fails, use cheap imitation
  585. return AfxGetFileName(lpszPathName, lpszTitle, nMax);
  586. }
  587. return lpszTitle == NULL ? lstrlen(lpszTemp)+1 : 0;
  588. }
  589. #endif
  590. void AFXAPI AfxGetModuleShortFileName(HINSTANCE hInst, CString& strShortName)
  591. {
  592. TCHAR szLongPathName[_MAX_PATH];
  593. ::GetModuleFileName(hInst, szLongPathName, _MAX_PATH);
  594. if (::GetShortPathName(szLongPathName,
  595. strShortName.GetBuffer(_MAX_PATH), _MAX_PATH) == 0)
  596. {
  597. // rare failure case (especially on not-so-modern file systems)
  598. strShortName = szLongPathName;
  599. }
  600. strShortName.ReleaseBuffer();
  601. }
  602. /////////////////////////////////////////////////////////////////////////////
  603. // CFile diagnostics
  604. #ifdef _DEBUG
  605. void CFile::AssertValid() const
  606. {
  607. CObject::AssertValid();
  608. // we permit the descriptor m_hFile to be any value for derived classes
  609. }
  610. void CFile::Dump(CDumpContext& dc) const
  611. {
  612. CObject::Dump(dc);
  613. dc << "with handle " << (UINT)m_hFile;
  614. dc << " and name \"" << m_strFileName << "\"";
  615. dc << "\n";
  616. }
  617. #endif
  618. #ifdef AFX_INIT_SEG
  619. #pragma code_seg(AFX_INIT_SEG)
  620. #endif
  621. IMPLEMENT_DYNAMIC(CFile, CObject)
  622. /////////////////////////////////////////////////////////////////////////////