filespecutils.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:21k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: filespecutils.cpp,v 1.2.42.5 2004/07/09 01:44:27 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hxstring.h"
  50. #include "filespecutils.h"
  51. #include "hxtick.h"
  52. #include "hxrand.h"
  53. #include "dbcs.h"
  54. #include "hlxclib/windows.h"
  55. #include <winbase.h>
  56. #include <shlobj.h>
  57. #include "hlxclib/sys/stat.h"
  58. //////////////////////////////////////////////////////////
  59. //
  60. // Utility base class -- CHXFileSpecUtils
  61. //
  62. //////////////////////////////////////////////////////////
  63. typedef BOOL (HXEXPORT_PTR FPGetFreeSpace) (LPCTSTR lpDir,PULARGE_INTEGER lpFree,PULARGE_INTEGER lpTotBytes,PULARGE_INTEGER lpTotFree);
  64. typedef HRESULT (HXEXPORT_PTR FPSHGetSpecialFolderLocation) (HWND hwndOwner, int nFolder, LPITEMIDLIST *ppidl);  
  65. typedef HRESULT (HXEXPORT_PTR FPSHGetPathFromIDList)(LPCITEMIDLIST pidl, LPSTR pszPath);
  66. typedef HRESULT (HXEXPORT_PTR FPSHGetMalloc)(LPMALLOC *ppMalloc);
  67. //******************************************************************************
  68. HX_RESULT CHXFileSpecUtils::GetFreeSpaceOnDisk(const CHXDirSpecifier& volSpec, 
  69.        INT64& freeSpace)
  70. {
  71. CHXDirSpecifier dirRoot = volSpec.GetVolume();
  72. CHXString strDir = dirRoot.GetPathName();
  73. OSVERSIONINFO ver;
  74. HX_RESULT res = HXR_FAIL;
  75. WORD w;
  76. // figure out which version of windows the user is running 
  77. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  78. GetVersionEx(&ver);
  79. w = (WORD)ver.dwBuildNumber;
  80. if (ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && w <= 1000)
  81. {
  82. #if !defined(WIN32_PLATFORM_PSPC)
  83. // the original windows 95
  84. DWORD dwSecPerClu,dwBytPerSec,dwNumFreeClu,dwNumOfClu;
  85. if (GetDiskFreeSpace(strDir,&dwSecPerClu,&dwBytPerSec,&dwNumFreeClu,&dwNumOfClu) != 0)
  86. {
  87. return HXR_FAIL;
  88. }
  89. // do a bit a math to figure out the free space - 
  90. freeSpace = ((INT64)dwSecPerClu) * ((INT64)dwBytPerSec) * ((INT64)dwNumFreeClu);
  91. #else /* !defined(WIN32_PLATFORM_PSPC) */
  92. ULARGE_INTEGER   freeBytesAvailableToCaller;
  93. ULARGE_INTEGER   totalNumberOfBytes;
  94. ULARGE_INTEGER   totalNumberOfFreeBytes;
  95. if (!GetDiskFreeSpaceEx(OS_STRING(strDir),
  96. &freeBytesAvailableToCaller,
  97. &totalNumberOfBytes,
  98. &totalNumberOfFreeBytes))
  99.     return HXR_FAIL;
  100. freeSpace = freeBytesAvailableToCaller.QuadPart;
  101. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  102. }
  103. else
  104. {
  105. // windows 95 osr2 or above or winnt
  106. // the docs for GetDiskFreeSpaceEx say to load kernel32.dll,
  107. // search for the procaddress and then call the function...
  108. HINSTANCE hKernel = ::LoadLibrary(OS_STRING("kernel32.dll"));
  109. if (hKernel)
  110. {
  111. FPGetFreeSpace fpGetFreeSpace = (FPGetFreeSpace) GetProcAddress(hKernel, OS_STRING("GetDiskFreeSpaceExA"));
  112. if (fpGetFreeSpace)
  113. {
  114. ULARGE_INTEGER uFreeBytesCaller,uTotNumBytes,uTotNumFreeBytes;
  115. BOOL b = fpGetFreeSpace(OS_STRING(strDir),&uFreeBytesCaller,&uTotNumBytes,&uTotNumFreeBytes);
  116. if (b)
  117. {
  118. // free space on disk or for the user? That is the question
  119. freeSpace = uFreeBytesCaller.QuadPart;
  120. res = HXR_OK;
  121. }
  122. }
  123. ::FreeLibrary(hKernel);
  124. }
  125. }
  126. return res;
  127. }
  128. //******************************************************************************
  129. HX_RESULT CHXFileSpecUtils::GetTotalSpaceOnDisk(const CHXDirSpecifier& volSpec, 
  130. INT64& totalSpace)
  131. CHXDirSpecifier dirRoot = volSpec.GetVolume();
  132. CHXString strDir = dirRoot.GetPathName();
  133. OSVERSIONINFO ver;
  134. HX_RESULT res = HXR_FAIL;
  135. WORD w;
  136. // figure out which version of windows the user is running 
  137. ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  138. GetVersionEx(&ver);
  139. w = (WORD)ver.dwBuildNumber;
  140. if (ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && w <= 1000)
  141. {
  142. #if !defined(WIN32_PLATFORM_PSPC)
  143. // the original windows 95
  144. DWORD dwSecPerClu,dwBytPerSec,dwNumFreeClu,dwNumOfClu;
  145. if (GetDiskFreeSpace(strDir,&dwSecPerClu,&dwBytPerSec,&dwNumFreeClu,&dwNumOfClu) != 0)
  146. {
  147. return HXR_FAIL;
  148. }
  149. // do a bit a math to figure out the free space - 
  150. totalSpace = ((INT64)dwSecPerClu) * ((INT64)dwBytPerSec) * ((INT64)dwNumOfClu);
  151. #else /* !defined(WIN32_PLATFORM_PSPC) */
  152. ULARGE_INTEGER   freeBytesAvailableToCaller;
  153. ULARGE_INTEGER   totalNumberOfBytes;
  154. ULARGE_INTEGER   totalNumberOfFreeBytes;
  155. if (!GetDiskFreeSpaceEx(OS_STRING(strDir),
  156. &freeBytesAvailableToCaller,
  157. &totalNumberOfBytes,
  158. &totalNumberOfFreeBytes))
  159.     return HXR_FAIL;
  160. totalSpace = totalNumberOfBytes.QuadPart;
  161. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  162. }
  163. else
  164. {
  165. // windows 95 osr2 or above or winnt
  166. // the docs for GetDiskFreeSpaceEx say to load kernel32.dll,
  167. // search for the procaddress and then call the function...
  168. HINSTANCE hKernel = ::LoadLibrary(OS_STRING("kernel32.dll"));
  169. if (hKernel)
  170. {
  171. FPGetFreeSpace fpGetFreeSpace = (FPGetFreeSpace)GetProcAddress(hKernel, OS_STRING("GetDiskFreeSpaceExA"));
  172. if (fpGetFreeSpace)
  173. {
  174. ULARGE_INTEGER uFreeBytesCaller,uTotNumBytes,uTotNumFreeBytes;
  175. BOOL b = fpGetFreeSpace(OS_STRING(strDir),&uFreeBytesCaller,&uTotNumBytes,&uTotNumFreeBytes);
  176. if (b)
  177. {
  178. // free space on disk or for the user? That is the question
  179. totalSpace = uTotNumBytes.QuadPart;
  180. res = HXR_OK;
  181. }
  182. }
  183. ::FreeLibrary(hKernel);
  184. }
  185. }
  186. return res;
  187. }
  188. //******************************************************************************
  189. BOOL CHXFileSpecUtils::IsDiskEjectable(const CHXDirSpecifier& volSpec)
  190. {
  191.      BOOL retval = FALSE;
  192. #if !defined(WIN32_PLATFORM_PSPC)
  193. CHXDirSpecifier dirRoot = volSpec.GetVolume();
  194. CHXString strDir = dirRoot.GetPathName();
  195. UINT uiType = ::GetDriveType(strDir);
  196. switch (uiType)
  197. {
  198. case DRIVE_REMOVABLE:
  199. case DRIVE_CDROM:
  200. retval = TRUE;
  201. break;
  202. default:
  203. retval = FALSE;
  204. break;
  205. }
  206. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  207. return retval;
  208. }
  209. // IsLocal returns TRUE if the file or directory is on a local volume
  210. // (not on a server)
  211. //******************************************************************************
  212. BOOL CHXFileSpecUtils::IsDiskLocal(const CHXDirSpecifier& volSpec)
  213. {
  214.     BOOL retval = TRUE;
  215. #if !defined(WIN32_PLATFORM_PSPC)
  216. CHXDirSpecifier dirRoot = volSpec.GetVolume();
  217. CHXString strDir = dirRoot.GetPathName();
  218. UINT uiType = ::GetDriveType(strDir);
  219. switch (uiType)
  220. {
  221. case DRIVE_FIXED:
  222. case DRIVE_CDROM:
  223. case DRIVE_RAMDISK:
  224. case DRIVE_REMOVABLE:
  225. retval = TRUE;
  226. break;
  227. default:
  228. retval = FALSE;
  229. break;
  230. }
  231. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  232. return retval;
  233. }
  234. // file/dir utilities
  235. //******************************************************************** **********
  236. HX_RESULT CHXFileSpecUtils::RemoveDir(const CHXDirSpecifier& dirSpec)
  237. {
  238.     if (::RemoveDirectory(OS_STRING(dirSpec.GetPathName())))
  239.     {
  240.         return HXR_OK;
  241.     }
  242.     return HXR_FAILED;
  243. };
  244. //******************************************************************** **********
  245. HX_RESULT CHXFileSpecUtils::RemoveFile(const CHXFileSpecifier& fileSpec)
  246. {
  247.     if (::DeleteFile(OS_STRING(fileSpec.GetPathName())))
  248.     {
  249.         return HXR_OK;
  250.     }
  251.     return HXR_FAILED;
  252. };
  253. //******************************************************************************
  254. HX_RESULT CHXFileSpecUtils::GetFileSize(const CHXFileSpecifier& fileSpec, INT64& fSize)
  255. {
  256. CHXString strFile = fileSpec.GetPathName();
  257. // try to open the file
  258. HANDLE hFile = ::CreateFile(OS_STRING(strFile),
  259. GENERIC_READ,
  260. FILE_SHARE_READ,
  261. NULL,
  262. OPEN_EXISTING,
  263. FILE_ATTRIBUTE_NORMAL,
  264. NULL);
  265. if (hFile == INVALID_HANDLE_VALUE)
  266. {
  267. return HXR_FAIL;
  268. }
  269. DWORD dwLow,dwHigh,dwError;
  270. dwLow = ::GetFileSize(hFile,&dwHigh);
  271. if (dwLow == 0xFFFFFFFF && (dwError = GetLastError()) != NO_ERROR)
  272. {
  273. return HXR_FAIL;
  274. }
  275. fSize = dwHigh;
  276. fSize = fSize << 32;
  277. fSize |= dwLow;
  278. ::CloseHandle(hFile);
  279. return HXR_OK;
  280. }
  281. //******************************************************************************
  282. HX_RESULT CHXFileSpecUtils::GetDirectorySize(const CHXDirSpecifier& dirSpec, BOOL shouldDescend, INT64& fSize)
  283. {
  284.     CHXString currentDir = dirSpec.GetPathName();
  285.     CHXString strFindFilePath = currentDir + "\*.*";
  286.     WIN32_FIND_DATA findFileData;
  287.     HANDLE hFile = ::FindFirstFile(OS_STRING(strFindFilePath), &findFileData );
  288.     HX_RESULT outResult = HXR_OK;
  289.     while ( hFile != INVALID_HANDLE_VALUE )
  290.     {
  291. if ((0 != strcmp(".", OS_STRING(findFileData.cFileName))) && 
  292.     (0 != strcmp("..", OS_STRING(findFileData.cFileName))) )
  293. {
  294.     if ( shouldDescend && (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
  295.     {
  296. CHXString subDirectoryPath = currentDir + "\" + OS_STRING(findFileData.cFileName);
  297. CHXDirSpecifier subDirectorySpec( subDirectoryPath );
  298. if ( FAILED(GetDirectorySize( subDirectorySpec, shouldDescend, fSize )) )
  299. {
  300.     fSize = 0;
  301.     outResult = HXR_FAIL;
  302.     break;
  303. }
  304.     }
  305.     else
  306.     {
  307. INT64 dFileSize = 0;
  308. dFileSize = findFileData.nFileSizeHigh;
  309. dFileSize = dFileSize << 32;
  310. dFileSize |= findFileData.nFileSizeLow;
  311. fSize += dFileSize;
  312.     }
  313. }
  314. if ( 0 == ::FindNextFile( hFile, &findFileData ) )
  315. {
  316.     if ( ERROR_NO_MORE_FILES != GetLastError() )
  317.     {
  318. fSize = 0;
  319. outResult = HXR_FAIL;
  320.     }
  321.     break;
  322. }
  323.     }
  324.     ::FindClose( hFile );
  325.     return HXR_OK;
  326. }
  327. //******************************************************************************
  328. CHXFileSpecifier CHXFileSpecUtils::GetCurrentApplication(void)
  329. {
  330. CHXFileSpecifier spec;
  331. char szBuf[_MAX_PATH]; /* Flawfinder: ignore */
  332. if (GetModuleFileName(NULL,OS_STRING2(szBuf,_MAX_PATH),_MAX_PATH))
  333. {
  334. spec = CHXFileSpecifier(szBuf); 
  335. }
  336. return spec;
  337. }
  338. //******************************************************************************
  339. CHXDirSpecifier CHXFileSpecUtils::GetCurrentApplicationDir(void)
  340. {
  341. CHXFileSpecifier  appSpec;
  342. CHXDirSpecifier  dirSpec;
  343. appSpec = GetCurrentApplication();
  344. if (appSpec.IsSet())
  345. {
  346. dirSpec = appSpec.GetParentDirectory();
  347. }
  348. return dirSpec;
  349. }
  350. //******************************************************************************
  351. BOOL CHXFileSpecUtils::FileExists(const CHXFileSpecifier& fileSpec)
  352. {
  353.     BOOL bRet = FALSE;
  354.     //struct stat statBuff;
  355.     //ZeroInit(&statBuff);
  356.     //if ( (stat(fileSpec.GetPathName(), &statBuff) == 0) && (statBuff.st_mode & _S_IFREG))
  357.     //bRet = TRUE;
  358.     ULONG32 ulAtts = ::GetFileAttributes(OS_STRING(fileSpec.GetPathName()));
  359.     if (ulAtts != 0xFFFFFFFF && !(ulAtts & FILE_ATTRIBUTE_DIRECTORY))
  360. bRet = TRUE;
  361.     return bRet;
  362. }
  363. //******************************************************************************
  364. BOOL CHXFileSpecUtils::DirectoryExists(const CHXDirSpecifier& dirSpec)
  365. {
  366. ULONG32 ulAtts = ::GetFileAttributes(OS_STRING(dirSpec.GetPathName()));
  367. if (ulAtts != 0xFFFFFFFF && (ulAtts & FILE_ATTRIBUTE_DIRECTORY))
  368. return TRUE;
  369. return FALSE;
  370. }
  371. //******************************************************************************
  372. HX_RESULT CHXFileSpecUtils::CreateDir(const CHXDirSpecifier& dirSpec)
  373. {
  374.         if (::CreateDirectory(OS_STRING(dirSpec.GetPathName()),NULL))
  375. return TRUE;
  376. return FALSE;
  377. }
  378. //******************************************************************************
  379. static CHXFileSpecifier GetUniqueFileSpecInternal(const CHXDirSpecifier& locationSpec, 
  380. const char *pszNameFirst, const char *pszTemplate, 
  381. const char *pszWildcard, UINT32 nStartNum);
  382. const UINT32 kNumWrapValue = 9999+1; // limit insertions to 4-digit numbers
  383. CHXFileSpecifier CHXFileSpecUtils::GetUniqueFileSpec(const CHXDirSpecifier& locationSpec, 
  384. const char *pszNameFirst, const char *pszTemplate, 
  385. const char *pszWildcard)
  386. {
  387. return GetUniqueFileSpecInternal(locationSpec, pszNameFirst, pszTemplate, pszWildcard, 0);
  388. }
  389. CHXFileSpecifier CHXFileSpecUtils::GetUniqueTempFileSpec(const CHXDirSpecifier& locationSpec, 
  390. const char *pszTemplate, const char *pszWildcard)
  391. {
  392. CMultiplePrimeRandom  rand(HX_GET_TICKCOUNT());
  393. UINT32 num;
  394. num = rand.GetRandomNumber();
  395. num %= kNumWrapValue;
  396. if (num == 0 || num == 1) num = 2;
  397. return GetUniqueFileSpecInternal(locationSpec, NULL, pszTemplate, pszWildcard, num);
  398. }
  399. static CHXFileSpecifier GetUniqueFileSpecInternal(const CHXDirSpecifier& locationSpec, 
  400. const char *pszNameFirst, const char *pszTemplate, 
  401. const char *pszWildcard, UINT32 nStartNum)
  402. {
  403. CHXFileSpecifier  resultFileSpec;
  404. require_return(locationSpec.IsSet(), resultFileSpec);
  405. require_return(pszTemplate != NULL && pszWildcard != NULL, resultFileSpec);
  406. require_return(pszNameFirst != NULL || nStartNum != 0, resultFileSpec);
  407. CHXFileSpecifier  testFileSpec;
  408. CHXDirSpecifier  testDirSpec;
  409. CHXString strNumber;
  410. CHXString strName;
  411. UINT32 nCurrentNum;
  412. nCurrentNum = nStartNum;
  413. while (1) 
  414. {
  415. // if the number is non-zero, make a string from the template;
  416. // if the number is zero, user the initial name string
  417. if (nCurrentNum == 0)
  418. {
  419. // replace the wildcard in the template with the number string
  420. strName = pszNameFirst;
  421. }
  422. else
  423. {
  424. // replace the wildcard in the template with the number string
  425. strNumber.Empty();
  426. strNumber.AppendULONG(nCurrentNum);
  427. strName = pszTemplate;
  428. strName.FindAndReplace(pszWildcard, strNumber); // replace first wildcard with number string
  429. }
  430. // test if a file or directory exists with that name
  431. testFileSpec = locationSpec.SpecifyChildFile(strName);
  432. testDirSpec = locationSpec.SpecifyChildDirectory(strName);
  433. if (CHXFileSpecUtils::FileExists(testFileSpec)
  434. || CHXFileSpecUtils::DirectoryExists(testDirSpec))
  435. {
  436. // an item already has that name, so increment & wrap the number
  437. nCurrentNum++;
  438. nCurrentNum %= kNumWrapValue;
  439. // don't use 0 again, and skip 1 since "MyFile2.txt" logically follows "MyFile.txt"
  440. if (nCurrentNum == 0 || nCurrentNum == 1) 
  441. {
  442. nCurrentNum = 2; 
  443. }
  444. // a quick sanity check
  445. if (nCurrentNum == nStartNum)
  446. {
  447. check(!"GetUniqueFileSpecInternal number wrapped");
  448. break;
  449. }
  450. }
  451. else
  452. {
  453. // the name is unique
  454. resultFileSpec = testFileSpec;
  455. break;
  456. }
  457. } // while
  458. return resultFileSpec;
  459. }
  460. //******************************************************************************
  461. CHXDirSpecifier CHXFileSpecUtils::GetSystemTempDirectory()
  462. {
  463. char szBuf[MAX_PATH] = ""; /* Flawfinder: ignore */
  464. #if !defined(WIN32_PLATFORM_PSPC)
  465. ::GetTempPath(MAX_PATH,szBuf);
  466. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  467. CHXDirSpecifier retSpec(szBuf);
  468. return retSpec;
  469. }
  470. BOOL CHXFileSpecUtils::MakeNameLegal(char *pszName)
  471. {
  472. const char *badChars = "\/:*?"<>|";
  473. const char replacementChar = '-';
  474. const long maxNameLength = 255;
  475. char *pCurrChar = pszName;
  476. BOOL bChanged;
  477. require_nonnull_return(pszName, FALSE);
  478. bChanged = FALSE;
  479. // replace any illegal characters
  480. while (*pCurrChar)
  481. {
  482. if (strchr(badChars, *pCurrChar))
  483. {
  484. *pCurrChar = replacementChar;
  485. bChanged = TRUE;
  486. }
  487. pCurrChar = HXGetNextChar(pCurrChar);
  488. // be sure the name isn't too long
  489. if (pCurrChar - pszName >= maxNameLength)
  490. {
  491. if (pCurrChar - pszName >= maxNameLength + 1)
  492. pCurrChar = HXGetPrevChar(pszName, pCurrChar);
  493. *pCurrChar = 0;
  494. bChanged = TRUE;
  495. }
  496. }
  497. return bChanged;
  498. }
  499. //******************************************************************************
  500. CHXDirSpecifier 
  501. CHXFileSpecUtils::GetAppDataDir(const char* szAppName)
  502. {
  503.     CHXDirSpecifier dirResult;
  504.     CHXString strPath;
  505.     HINSTANCE hShell = ::LoadLibrary(OS_STRING("shell32.dll"));
  506.     FPSHGetSpecialFolderLocation fpSHGetSpecialFolderLocation = NULL;
  507.     FPSHGetPathFromIDList fpSHGetPathFromIDList = NULL;
  508.     FPSHGetMalloc fpSHGetMalloc = NULL;
  509.     if (hShell)
  510.     {
  511. fpSHGetSpecialFolderLocation = (FPSHGetSpecialFolderLocation) GetProcAddress(hShell,OS_STRING("SHGetSpecialFolderLocation"));
  512. fpSHGetPathFromIDList = (FPSHGetPathFromIDList) GetProcAddress(hShell, OS_STRING("SHGetPathFromIDListA"));
  513. // just in case
  514. if (!fpSHGetPathFromIDList)
  515. {
  516.     fpSHGetPathFromIDList = (FPSHGetPathFromIDList) GetProcAddress(hShell, OS_STRING("SHGetPathFromIDList"));
  517. }
  518. fpSHGetMalloc = (FPSHGetMalloc) GetProcAddress(hShell, OS_STRING("SHGetMalloc"));
  519.     }
  520.     if (!fpSHGetSpecialFolderLocation ||
  521. !fpSHGetPathFromIDList ||
  522. !fpSHGetMalloc)
  523.     {
  524. goto exit;
  525.     }
  526. #if !defined(WIN32_PLATFORM_PSPC)
  527.     ITEMIDLIST* pidl;
  528.     pidl = NULL;
  529.     if(fpSHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl) == NOERROR)
  530.     {
  531. HX_ASSERT(pidl);
  532. fpSHGetPathFromIDList(pidl, strPath.GetBuffer(_MAX_PATH + 1));
  533. IMalloc* pMalloc = NULL;
  534. if (SUCCEEDED(fpSHGetMalloc(&pMalloc)))
  535. {
  536.     pMalloc->Free(pidl);
  537.     pMalloc->Release();
  538.     pMalloc = NULL;
  539.     pidl = NULL;
  540. }
  541. strPath.ReleaseBuffer();
  542.     }
  543.     else
  544.     {
  545. // In Win95 OSR2 SHGetSpecialFolderLocation() fails on CSIDL_APPDATA.
  546. HKEY hKey = NULL;
  547. if(RegOpenKey(HKEY_LOCAL_MACHINE, "Software\Microsoft\Windows\CurrentVersion", &hKey) == ERROR_SUCCESS)
  548. {
  549.     DWORD nValueType = REG_NONE;
  550.     DWORD bufSize = _MAX_PATH;
  551.     RegQueryValueEx(hKey, OS_STRING("ProgramFilesDir"), 
  552.     NULL, &nValueType, 
  553.     (Byte *)strPath.GetBuffer(_MAX_PATH + 1), 
  554.     &bufSize);
  555.     strPath.ReleaseBuffer();
  556.     RegCloseKey(hKey);
  557. }
  558.     }
  559. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  560.     if(!strPath.IsEmpty())
  561.     {
  562. dirResult = strPath;
  563. if(!DirectoryExists(dirResult))
  564.     CreateDir(dirResult);
  565. dirResult = dirResult.SpecifyChildDirectory("Real");
  566. if(!DirectoryExists(dirResult))
  567.     CreateDir(dirResult);
  568. if(szAppName)
  569. {
  570.     dirResult = dirResult.SpecifyChildDirectory(szAppName);
  571.     if(!DirectoryExists(dirResult))
  572. CreateDir(dirResult);
  573. }
  574.     }
  575. exit:
  576.     if (hShell)
  577.     {
  578. ::FreeLibrary(hShell);
  579.     }
  580.     return dirResult;
  581. }
  582. //******************************************************************************
  583. HX_RESULT CHXFileSpecUtils::ReadBinaryFile(const CHXFileSpecifier& fileSpec, IHXBuffer*& pOutBuffer)
  584. {
  585. HX_ASSERT(!"Not yet implemented on this platform");
  586. return HXR_FAIL;
  587. }
  588. HX_RESULT CHXFileSpecUtils::ReadTextFile(const CHXFileSpecifier& fileSpec, CHXString& outStr)
  589. {
  590. HX_ASSERT(!"Not yet implemented on this platform");
  591. return HXR_FAIL;
  592. }
  593. HX_RESULT CHXFileSpecUtils::WriteBinaryFile(CHXFileSpecifier& fileSpec, IHXBuffer* inBuffer, BOOL bReplaceExistingFile)
  594. {
  595. // the first parameter is not const because on the Mac it can change during the call
  596. HX_ASSERT(!"Not yet implemented on this platform");
  597. return HXR_FAIL;
  598. }
  599. HX_RESULT CHXFileSpecUtils::WriteTextFile(CHXFileSpecifier& fileSpec, const CHXString& inStr, BOOL bReplaceExistingFile)
  600. {
  601. // the first parameter is not const because on the Mac it can change during the call
  602. HX_ASSERT(!"Not yet implemented on this platform");
  603. return HXR_FAIL;
  604. }