home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / FILECORE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  19.5 KB  |  764 lines

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