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.

1960 lines
51 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. Utils.cpp
  5. Abstract:
  6. This file contains the implementation of various utility functions.
  7. Revision History:
  8. Davide Massarenti (Dmassare) 04/17/99
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. #define BUFFER_TMP_SIZE 1024
  13. ////////////////////////////////////////////////////////////////////////////////
  14. int MPC::HexToNum( int c )
  15. {
  16. if(c >= '0' && c <= '9') return c - '0';
  17. if(c >= 'A' && c <= 'F') return c - 'A' + 10;
  18. if(c >= 'a' && c <= 'f') return c - 'a' + 10;
  19. return -1;
  20. }
  21. char MPC::NumToHex( int c )
  22. {
  23. static char s_lookup[] = { '0', '1', '2', '3' ,
  24. '4', '5', '6', '7' ,
  25. '8', '9', 'A', 'B' ,
  26. 'C', 'D', 'E', 'F' };
  27. return s_lookup[ c & 0xF ];
  28. }
  29. ////////////////////////////////////////////////////////////////////////////////
  30. void MPC::RemoveTrailingBackslash( /*[in/out]*/ LPWSTR szPath )
  31. {
  32. LPWSTR szEnd = szPath + wcslen( szPath );
  33. while(szEnd-- > szPath)
  34. {
  35. if(szEnd[0] != '\\' &&
  36. szEnd[0] != '/' )
  37. {
  38. szEnd[1] = 0;
  39. break;
  40. }
  41. }
  42. }
  43. HRESULT MPC::GetProgramDirectory( /*[out]*/ MPC::wstring& szPath )
  44. {
  45. __MPC_FUNC_ENTRY( COMMONID, "MPC::GetProgramDirectory" );
  46. HRESULT hr;
  47. WCHAR rgFileName[MAX_PATH+1];
  48. LPWSTR szEnd;
  49. __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetModuleFileNameW( NULL, rgFileName, MAX_PATH ));
  50. rgFileName[MAX_PATH] = 0;
  51. // Remove file name.
  52. if((szEnd = wcsrchr( rgFileName, '\\' ))) szEnd[0] = 0;
  53. szPath = rgFileName;
  54. hr = S_OK;
  55. __MPC_FUNC_CLEANUP;
  56. __MPC_FUNC_EXIT(hr);
  57. }
  58. HRESULT MPC::GetUserWritablePath( /*[out]*/ MPC::wstring& strPath, /*[in]*/ LPCWSTR szSubDir )
  59. {
  60. __MPC_FUNC_ENTRY( COMMONID, "MPC::GetUserWritablePath");
  61. HRESULT hr;
  62. LPITEMIDLIST pidl = NULL;
  63. WCHAR rgAppDataPath[MAX_PATH+1];
  64. LPWSTR szPtr;
  65. __MPC_EXIT_IF_METHOD_FAILS(hr, ::SHGetSpecialFolderLocation( NULL, CSIDL_LOCAL_APPDATA, &pidl ));
  66. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::SHGetPathFromIDListW( pidl, rgAppDataPath ));
  67. MPC::RemoveTrailingBackslash( rgAppDataPath );
  68. if(szSubDir)
  69. {
  70. StringCchCatW( rgAppDataPath, ARRAYSIZE(rgAppDataPath), L"\\" );
  71. StringCchCatW( rgAppDataPath, ARRAYSIZE(rgAppDataPath), szSubDir );
  72. MPC::RemoveTrailingBackslash( rgAppDataPath );
  73. }
  74. strPath = rgAppDataPath;
  75. hr = S_OK;
  76. __MPC_FUNC_CLEANUP;
  77. //
  78. // Get the shell's allocator to free PIDLs
  79. //
  80. if(pidl != NULL)
  81. {
  82. LPMALLOC lpMalloc = NULL;
  83. if(SUCCEEDED(SHGetMalloc( &lpMalloc )) && lpMalloc != NULL)
  84. {
  85. lpMalloc->Free( pidl );
  86. lpMalloc->Release();
  87. }
  88. }
  89. __MPC_FUNC_EXIT(hr);
  90. }
  91. HRESULT MPC::GetCanonialPathName( /*[out]*/ MPC::wstring& szPathNameOut, /*[in]*/ LPCWSTR szPathNameIn )
  92. {
  93. __MPC_FUNC_ENTRY( COMMONID, "MPC::GetCanonialPathName");
  94. HRESULT hr;
  95. WCHAR rgFullPath [MAX_PATH+1];
  96. WCHAR rgCurrentDir[MAX_PATH+1];
  97. DWORD dwLength;
  98. LPWSTR szFilePart;
  99. __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetFullPathNameW( szPathNameIn, MAXSTRLEN(rgFullPath), rgFullPath, &szFilePart ));
  100. dwLength = ::GetCurrentDirectoryW( MAXSTRLEN(rgCurrentDir), rgCurrentDir );
  101. __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, dwLength);
  102. if((0 != _wcsnicmp( rgFullPath, rgCurrentDir, dwLength )) ||
  103. (L'\\' != rgFullPath[dwLength]))
  104. {
  105. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_INVALID_PARAMETER);
  106. }
  107. szPathNameOut = rgFullPath + dwLength + 1;
  108. hr = S_OK;
  109. __MPC_FUNC_CLEANUP;
  110. __MPC_FUNC_EXIT(hr);
  111. }
  112. HRESULT MPC::GetTemporaryFileName( /*[out]*/ MPC::wstring& szFile, /*[in]*/ LPCWSTR szBase, /*[in]*/ LPCWSTR szPrefix )
  113. {
  114. __MPC_FUNC_ENTRY( COMMONID, "MPC::GetTemporaryFileName");
  115. HRESULT hr;
  116. WCHAR rgTmp [MAX_PATH+1];
  117. WCHAR rgBase[MAX_PATH+1];
  118. if(szBase)
  119. {
  120. StringCchCopyW( rgBase, ARRAYSIZE(rgBase), szBase );
  121. }
  122. else
  123. {
  124. __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetTempPathW( MAXSTRLEN(rgBase), rgBase ));
  125. }
  126. MPC::RemoveTrailingBackslash( rgBase );
  127. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( rgBase, false )); // Make sure the directory exists.
  128. __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetTempFileNameW( rgBase, szPrefix ? szPrefix : L"MPC", 0, rgTmp ));
  129. szFile = rgTmp;
  130. hr = S_OK;
  131. __MPC_FUNC_CLEANUP;
  132. __MPC_FUNC_EXIT(hr);
  133. }
  134. HRESULT MPC::RemoveTemporaryFile( /*[in/out]*/ MPC::wstring& szFile )
  135. {
  136. __MPC_FUNC_ENTRY( COMMONID, "MPC::RemoveTemporaryFile");
  137. HRESULT hr;
  138. if(szFile.size() > 0)
  139. {
  140. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::DeleteFile( szFile ));
  141. szFile = L"";
  142. }
  143. hr = S_OK;
  144. __MPC_FUNC_CLEANUP;
  145. __MPC_FUNC_EXIT(hr);
  146. }
  147. ////////////////////////////////////////////////////////////////////////////////
  148. HRESULT MPC::SubstituteEnvVariables( /*[in/out]*/ MPC::wstring& szEnv )
  149. {
  150. __MPC_FUNC_ENTRY( COMMONID, "MPC::SubstituteEnvVariables" );
  151. HRESULT hr;
  152. WCHAR rgTmp[BUFFER_TMP_SIZE];
  153. LPWSTR szPtr = rgTmp;
  154. LPWSTR szBuf = NULL;
  155. DWORD dwSize;
  156. dwSize = ::ExpandEnvironmentStringsW( szEnv.c_str(), szPtr, MAXSTRLEN(rgTmp) );
  157. if(dwSize >= MAXSTRLEN(rgTmp))
  158. {
  159. __MPC_EXIT_IF_ALLOC_FAILS(hr, szBuf, new WCHAR[dwSize+2]);
  160. (void)::ExpandEnvironmentStringsW( szEnv.c_str(), szBuf, dwSize+1 );
  161. szPtr = szBuf;
  162. }
  163. szEnv = szPtr;
  164. hr = S_OK;
  165. __MPC_FUNC_CLEANUP;
  166. delete [] szBuf;
  167. __MPC_FUNC_EXIT(hr);
  168. }
  169. /////////////////////////////////////////////////////////////////////////////
  170. /////////////////////////////////////////////////////////////////////////////
  171. /////////////////////////////////////////////////////////////////////////////
  172. DATE MPC::GetSystemTime()
  173. {
  174. SYSTEMTIME stNow;
  175. DATE dDate;
  176. ::GetSystemTime( &stNow );
  177. ::SystemTimeToVariantTime( &stNow, &dDate );
  178. return dDate;
  179. }
  180. DATE MPC::GetLocalTime()
  181. {
  182. SYSTEMTIME stNow;
  183. DATE dDate;
  184. ::GetLocalTime( &stNow );
  185. ::SystemTimeToVariantTime( &stNow, &dDate );
  186. return dDate;
  187. }
  188. static DATE local_FixSubSecondTime( /*[in]*/ DATE dDate, /*[in]*/ bool fHighPrecision )
  189. {
  190. double dCount;
  191. double dFreq;
  192. long iCount;
  193. if(fHighPrecision)
  194. {
  195. LARGE_INTEGER liCount;
  196. LARGE_INTEGER liFreq;
  197. ::QueryPerformanceCounter ( &liCount ); dCount = (double)liCount.QuadPart;
  198. ::QueryPerformanceFrequency( &liFreq ); dFreq = (double)liFreq .QuadPart;
  199. }
  200. else
  201. {
  202. dCount = ::GetTickCount();
  203. dFreq = 1000;
  204. }
  205. if(dFreq)
  206. {
  207. dCount /= dFreq;
  208. iCount = dCount;
  209. dDate += (dCount - iCount) / (24 * 60 * 60 * 1000.0);
  210. }
  211. return dDate;
  212. }
  213. DATE MPC::GetSystemTimeEx( /*[in]*/ bool fHighPrecision )
  214. {
  215. return local_FixSubSecondTime( MPC::GetSystemTime(), fHighPrecision );
  216. }
  217. DATE MPC::GetLocalTimeEx( /*[in]*/ bool fHighPrecision )
  218. {
  219. return local_FixSubSecondTime( MPC::GetLocalTime(), fHighPrecision );
  220. }
  221. DATE MPC::GetLastModifiedDate( /*[out]*/ const MPC::wstring& strFile )
  222. {
  223. WIN32_FILE_ATTRIBUTE_DATA wfadInfo;
  224. SYSTEMTIME sys;
  225. DATE dFile;
  226. if(::GetFileAttributesExW( strFile.c_str(), GetFileExInfoStandard, &wfadInfo ) == FALSE ||
  227. ::FileTimeToSystemTime( &wfadInfo.ftLastWriteTime , &sys ) == FALSE )
  228. {
  229. return 0; // File doesn't exist.
  230. }
  231. ::SystemTimeToVariantTime( &sys, &dFile );
  232. return dFile;
  233. }
  234. HRESULT MPC::ConvertSizeUnit( /*[in] */ const MPC::wstring& szStr ,
  235. /*[out]*/ DWORD& dwRes )
  236. {
  237. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertSizeUnit" );
  238. MPC::string::size_type iUnit = 0;
  239. int nMult = 1;
  240. // CODEWORK: no proper format checking...
  241. do
  242. {
  243. if((iUnit = szStr.find( L"KB" )) != MPC::string::npos) { nMult = 1024; break; }
  244. if((iUnit = szStr.find( L"MB" )) != MPC::string::npos) { nMult = 1024*1024; break; }
  245. } while(0);
  246. dwRes = nMult * _wtoi( szStr.c_str() );
  247. __MPC_FUNC_EXIT(S_OK);
  248. }
  249. HRESULT MPC::ConvertTimeUnit( /*[in] */ const MPC::wstring& szStr ,
  250. /*[out]*/ DWORD& dwRes )
  251. {
  252. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertTimeUnit" );
  253. MPC::string::size_type iUnit = 0;
  254. int nMult = 1;
  255. // CODEWORK: no proper format checking...
  256. do
  257. {
  258. if((iUnit = szStr.find( L"m" )) != MPC::string::npos) { nMult = 60; break; }
  259. if((iUnit = szStr.find( L"h" )) != MPC::string::npos) { nMult = 60*60; break; }
  260. if((iUnit = szStr.find( L"d" )) != MPC::string::npos) { nMult = 24*60*60; break; }
  261. } while(0);
  262. dwRes = nMult * _wtoi( szStr.c_str() );
  263. __MPC_FUNC_EXIT(S_OK);
  264. }
  265. ////////////////////////////////////////
  266. HRESULT MPC::ConvertDateToString( /*[in] */ DATE dDate ,
  267. /*[out]*/ MPC::wstring& szDate ,
  268. /*[in] */ bool fGMT ,
  269. /*[in] */ bool fCIM ,
  270. /*[in] */ LCID lcid )
  271. {
  272. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertDateToString" );
  273. HRESULT hr;
  274. double dTimeZone;
  275. if(fGMT)
  276. {
  277. TIME_ZONE_INFORMATION tzi;
  278. if(::GetTimeZoneInformation( &tzi ) == TIME_ZONE_ID_DAYLIGHT)
  279. {
  280. tzi.Bias += tzi.DaylightBias;
  281. }
  282. dTimeZone = (DATE)tzi.Bias / (24 * 60); // Convert BIAS from minutes to days.
  283. }
  284. else
  285. {
  286. dTimeZone = 0.0;
  287. }
  288. dDate += dTimeZone;
  289. if(fCIM)
  290. {
  291. SYSTEMTIME st;
  292. WCHAR rgBuf[256];
  293. char cTimeZone = (dTimeZone > 0) ? '+' : '-';
  294. int iTimeZone = (int)abs(dTimeZone ) * 24 * 60;
  295. ::VariantTimeToSystemTime( dDate, &st );
  296. // supposedly the CIM format for dates is the following (grabbed from
  297. // http://wmig/wbem/docs/cimdoc20.doc)
  298. // yyyymmddhhmmss.mmmmmmsutc
  299. // where
  300. // yyyy is a 4 digit year
  301. // mm is the month
  302. // dd is the day
  303. // hh is the hour (24-hour clock)
  304. // mm is the minute
  305. // ss is the second
  306. // mmmmmm is the number of microseconds
  307. // s is a "+" or "-", indicating the sign of the UTC (Universal
  308. // Coordinated Time; for all intents and purposes the same as Greenwich
  309. // Mean Time) correction field, or a ":". In this case, the value is
  310. // interpreted as a time interval, and yyyymm are interpreted as days.
  311. // utc is the offset from UTC in minutes (using the sign indicated by s)
  312. // It is ignored for a time interval.
  313. //
  314. // For example, Monday, May 25, 1998, at 1:30:15 PM EST would be
  315. // represented as 19980525133015.000000-300
  316. StringCchPrintfW( rgBuf, ARRAYSIZE(rgBuf), L"%04d%02d%02d%02d%02d%02d.%06d%c%03d",
  317. st.wYear ,
  318. st.wMonth ,
  319. st.wDay ,
  320. st.wHour ,
  321. st.wMinute ,
  322. st.wSecond ,
  323. st.wMilliseconds * 1000,
  324. cTimeZone ,
  325. iTimeZone );
  326. szDate = rgBuf;
  327. }
  328. else
  329. {
  330. CComVariant vValue;
  331. switch(lcid)
  332. {
  333. case 0: lcid = ::GetUserDefaultLCID(); break;
  334. case -1: lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT ); break;
  335. }
  336. vValue = dDate; vValue.vt = VT_DATE; // The assignment is not enough to set the DATE type.
  337. __MPC_EXIT_IF_METHOD_FAILS(hr, ::VariantChangeTypeEx( &vValue, &vValue, lcid, 0, VT_BSTR ));
  338. szDate = SAFEBSTR( vValue.bstrVal );
  339. }
  340. hr = S_OK;
  341. __MPC_FUNC_CLEANUP;
  342. __MPC_FUNC_EXIT(hr);
  343. }
  344. HRESULT MPC::ConvertStringToDate( /*[in] */ const MPC::wstring& szDate ,
  345. /*[out]*/ DATE& dDate ,
  346. /*[in] */ bool fGMT ,
  347. /*[in] */ bool fCIM ,
  348. /*[in] */ LCID lcid )
  349. {
  350. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertStringToDate" );
  351. HRESULT hr;
  352. double dTimeZone;
  353. if(fGMT)
  354. {
  355. TIME_ZONE_INFORMATION tzi;
  356. if(::GetTimeZoneInformation( &tzi ) == TIME_ZONE_ID_DAYLIGHT)
  357. {
  358. tzi.Bias += tzi.DaylightBias;
  359. }
  360. dTimeZone = (DATE)tzi.Bias / (24 * 60); // Convert BIAS from minutes to days.
  361. }
  362. else
  363. {
  364. dTimeZone = 0.0;
  365. }
  366. if(fCIM)
  367. {
  368. SYSTEMTIME st;
  369. int iYear;
  370. int iMonth;
  371. int iDay;
  372. int iHour;
  373. int iMinute;
  374. int iSecond;
  375. int iMicroseconds;
  376. wchar_t cTimezone;
  377. int iTimezone;
  378. if(swscanf( szDate.c_str(), L"%04d%02d%02d%02d%02d%02d.%06d%c%03d",
  379. &iYear ,
  380. &iMonth ,
  381. &iDay ,
  382. &iHour ,
  383. &iMinute ,
  384. &iSecond ,
  385. &iMicroseconds ,
  386. &cTimezone ,
  387. &iTimezone ) != 9)
  388. {
  389. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  390. }
  391. st.wYear = (WORD)(iYear );
  392. st.wMonth = (WORD)(iMonth );
  393. st.wDay = (WORD)(iDay );
  394. st.wHour = (WORD)(iHour );
  395. st.wMinute = (WORD)(iMinute );
  396. st.wSecond = (WORD)(iSecond );
  397. st.wMilliseconds = (WORD)(iMicroseconds / 1000);
  398. ::SystemTimeToVariantTime( &st, &dDate );
  399. }
  400. else
  401. {
  402. CComVariant vValue = szDate.c_str();
  403. switch(lcid)
  404. {
  405. case 0: lcid = ::GetUserDefaultLCID(); break;
  406. case -1: lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT ); break;
  407. }
  408. __MPC_EXIT_IF_METHOD_FAILS(hr, ::VariantChangeTypeEx( &vValue, &vValue, lcid, 0, VT_DATE ));
  409. dDate = vValue.date;
  410. }
  411. dDate -= dTimeZone;
  412. hr = S_OK;
  413. __MPC_FUNC_CLEANUP;
  414. __MPC_FUNC_EXIT(hr);
  415. }
  416. ////////////////////////////////////////
  417. HRESULT MPC::ConvertStringToHex( /*[in] */ const CComBSTR& bstrText ,
  418. /*[out]*/ CComBSTR& bstrHex )
  419. {
  420. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertStringToHex" );
  421. HRESULT hr;
  422. int iLen = bstrText.Length();
  423. if(iLen)
  424. {
  425. BSTR bstrNew;
  426. LPCWSTR szIn;
  427. LPWSTR szOut;
  428. __MPC_EXIT_IF_ALLOC_FAILS(hr, bstrNew, ::SysAllocStringLen( NULL, iLen*4 ));
  429. bstrHex.Attach( bstrNew );
  430. szIn = bstrText;
  431. szOut = bstrHex;
  432. while(iLen > 0)
  433. {
  434. WCHAR c = szIn[0];
  435. szOut[0] = NumToHex( c >> 12 );
  436. szOut[1] = NumToHex( c >> 8 );
  437. szOut[2] = NumToHex( c >> 4 );
  438. szOut[3] = NumToHex( c );
  439. iLen -= 1;
  440. szIn += 1;
  441. szOut += 4;
  442. }
  443. }
  444. else
  445. {
  446. bstrHex.Empty();
  447. }
  448. hr = S_OK;
  449. __MPC_FUNC_CLEANUP;
  450. __MPC_FUNC_EXIT(hr);
  451. }
  452. HRESULT MPC::ConvertHexToString( /*[in] */ const CComBSTR& bstrHex ,
  453. /*[out]*/ CComBSTR& bstrText )
  454. {
  455. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertHexToString" );
  456. HRESULT hr;
  457. int iLen = bstrHex.Length();
  458. if(iLen)
  459. {
  460. BSTR bstrNew;
  461. LPCWSTR szIn;
  462. LPWSTR szOut;
  463. iLen /= 4;
  464. __MPC_EXIT_IF_ALLOC_FAILS(hr, bstrNew, ::SysAllocStringLen( NULL, iLen ));
  465. bstrText.Attach( bstrNew );
  466. szIn = bstrHex;
  467. szOut = bstrText;
  468. while(iLen > 0)
  469. {
  470. szOut[0] = (HexToNum( szIn[0] ) << 12) |
  471. (HexToNum( szIn[1] ) << 8) |
  472. (HexToNum( szIn[2] ) << 4) |
  473. HexToNum( szIn[3] );
  474. iLen -= 1;
  475. szIn += 4;
  476. szOut += 1;
  477. }
  478. }
  479. else
  480. {
  481. bstrText.Empty();
  482. }
  483. hr = S_OK;
  484. __MPC_FUNC_CLEANUP;
  485. __MPC_FUNC_EXIT(hr);
  486. }
  487. ////////////////////////////////////////
  488. HRESULT MPC::ConvertHGlobalToHex( /*[in]*/ HGLOBAL hg ,
  489. /*[out]*/ CComBSTR& bstrHex ,
  490. /*[in ]*/ bool fNullAllowed ,
  491. /*[in ]*/ DWORD* pdwCount /* = NULL */ )
  492. {
  493. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertHGlobalToHex" );
  494. HRESULT hr;
  495. int iLen = hg ? (pdwCount ? (int)*pdwCount : ::GlobalSize( hg )) : 0;
  496. if(iLen)
  497. {
  498. BSTR bstrNew;
  499. BYTE* pIn;
  500. LPWSTR szOut;
  501. __MPC_EXIT_IF_ALLOC_FAILS(hr, bstrNew, ::SysAllocStringLen( NULL, iLen*2 ));
  502. bstrHex.Attach( bstrNew );
  503. pIn = (BYTE*)::GlobalLock( hg );
  504. szOut = bstrHex;
  505. while(iLen > 0)
  506. {
  507. BYTE c = pIn[0];
  508. szOut[0] = NumToHex( c >> 4 );
  509. szOut[1] = NumToHex( c );
  510. iLen -= 1;
  511. pIn += 1;
  512. szOut += 2;
  513. }
  514. ::GlobalUnlock( hg );
  515. }
  516. else
  517. {
  518. bstrHex.Empty();
  519. if(fNullAllowed == false) __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  520. }
  521. hr = S_OK;
  522. __MPC_FUNC_CLEANUP;
  523. __MPC_FUNC_EXIT(hr);
  524. }
  525. HRESULT MPC::ConvertHexToHGlobal( /*[in] */ const CComBSTR& bstrText ,
  526. /*[out]*/ HGLOBAL& hg ,
  527. /*[in ]*/ bool fNullAllowed )
  528. {
  529. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertHexToHGlobal" );
  530. HRESULT hr;
  531. int iLen = bstrText.Length();
  532. if(iLen)
  533. {
  534. LPCWSTR szIn;
  535. BYTE* pOut;
  536. iLen /= 2;
  537. __MPC_EXIT_IF_ALLOC_FAILS(hr, hg, ::GlobalAlloc( GMEM_FIXED, iLen ));
  538. szIn = bstrText;
  539. pOut = (BYTE*)hg;
  540. while(iLen > 0)
  541. {
  542. pOut[0] = (HexToNum( szIn[0] ) << 4) |
  543. HexToNum( szIn[1] );
  544. iLen -= 1;
  545. szIn += 2;
  546. pOut += 1;
  547. }
  548. }
  549. else
  550. {
  551. hg = NULL;
  552. if(fNullAllowed == false) __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  553. }
  554. hr = S_OK;
  555. __MPC_FUNC_CLEANUP;
  556. __MPC_FUNC_EXIT(hr);
  557. }
  558. ////////////////////////////////////////
  559. HRESULT MPC::ConvertBufferToVariant( /*[in] */ const BYTE* pBuf ,
  560. /*[in] */ DWORD dwLen ,
  561. /*[out]*/ CComVariant& v )
  562. {
  563. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertBufferToVariant" );
  564. HRESULT hr;
  565. v.Clear();
  566. if(pBuf && dwLen)
  567. {
  568. BYTE* rgArrayData;
  569. v.vt = VT_ARRAY | VT_UI1;
  570. __MPC_EXIT_IF_ALLOC_FAILS(hr, v.parray, ::SafeArrayCreateVector( VT_UI1, 0, dwLen ));
  571. __MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v.parray, (LPVOID*)&rgArrayData ));
  572. ::CopyMemory( rgArrayData, pBuf, dwLen );
  573. ::SafeArrayUnaccessData( v.parray );
  574. }
  575. hr = S_OK;
  576. __MPC_FUNC_CLEANUP;
  577. __MPC_FUNC_EXIT(hr);
  578. }
  579. HRESULT MPC::ConvertVariantToBuffer( /*[in] */ const VARIANT* v ,
  580. /*[out]*/ BYTE*& pBuf ,
  581. /*[out]*/ DWORD& dwLen )
  582. {
  583. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertVariantToBuffer" );
  584. HRESULT hr;
  585. BYTE* pSrc;
  586. if(pBuf) delete [] pBuf;
  587. pBuf = NULL;
  588. dwLen = 0;
  589. switch(v->vt)
  590. {
  591. case VT_ARRAY | VT_UI1:
  592. {
  593. long lBound; ::SafeArrayGetLBound( v->parray, 1, &lBound );
  594. long uBound; ::SafeArrayGetUBound( v->parray, 1, &uBound );
  595. __MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v->parray, (LPVOID*)&pSrc ));
  596. dwLen = uBound - lBound + 1;
  597. }
  598. break;
  599. case VT_I1: case VT_UI1: pSrc = (BYTE*)&v->bVal ; dwLen = 1; break;
  600. case VT_I2: case VT_UI2: pSrc = (BYTE*)&v->iVal ; dwLen = 2; break;
  601. case VT_I4: case VT_UI4: case VT_R4: pSrc = (BYTE*)&v->lVal ; dwLen = 4; break;
  602. case VT_I8: case VT_UI8: case VT_R8: pSrc = (BYTE*)&v->llVal; dwLen = 8; break;
  603. default:
  604. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  605. }
  606. if(dwLen)
  607. {
  608. __MPC_EXIT_IF_ALLOC_FAILS(hr, pBuf, new BYTE[dwLen]);
  609. ::CopyMemory( pBuf, pSrc, dwLen );
  610. }
  611. if(v->vt == (VT_ARRAY | VT_UI1))
  612. {
  613. ::SafeArrayUnaccessData( v->parray );
  614. }
  615. hr = S_OK;
  616. __MPC_FUNC_CLEANUP;
  617. __MPC_FUNC_EXIT(hr);
  618. }
  619. ////////////////////////////////////////
  620. HRESULT MPC::ConvertIStreamToVariant( /*[in]*/ IStream* stream, /*[out]*/ CComVariant& v )
  621. {
  622. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertIStreamToVariant" );
  623. HRESULT hr;
  624. CComPtr<IStream> stream2;
  625. STATSTG stg; ::ZeroMemory( &stg, sizeof(stg) );
  626. BYTE* pBuf = NULL;
  627. DWORD dwLen;
  628. ULONG lRead;
  629. __MPC_PARAMCHECK_BEGIN(hr)
  630. __MPC_PARAMCHECK_NOTNULL(stream);
  631. __MPC_PARAMCHECK_END();
  632. v.Clear();
  633. //
  634. // If Stat fails, it can be that the size is unknown, so let's make a copy to another stream and retry.
  635. //
  636. if(FAILED(stream->Stat( &stg, STATFLAG_NONAME )))
  637. {
  638. __MPC_EXIT_IF_METHOD_FAILS(hr, ::CreateStreamOnHGlobal( NULL, TRUE, &stream2 ));
  639. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::BaseStream::TransferData( stream, stream2 ));
  640. stream = stream2;
  641. }
  642. //
  643. // Rewind to the beginning.
  644. //
  645. {
  646. LARGE_INTEGER li = { 0, 0 };
  647. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->Seek( li, STREAM_SEEK_SET, NULL ));
  648. }
  649. //
  650. // Get the size of the stream.
  651. //
  652. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->Stat( &stg, STATFLAG_NONAME ));
  653. //
  654. // Sorry, we don't handle streams longer than 4GB!!
  655. //
  656. if(stg.cbSize.u.HighPart)
  657. {
  658. __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  659. }
  660. //
  661. // Allocate buffer for the whole stream.
  662. //
  663. dwLen = stg.cbSize.u.LowPart;
  664. __MPC_EXIT_IF_ALLOC_FAILS(hr, pBuf, new BYTE[dwLen]);
  665. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->Read( pBuf, dwLen, &lRead ));
  666. if(dwLen != lRead)
  667. {
  668. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_HANDLE_EOF);
  669. }
  670. __MPC_EXIT_IF_METHOD_FAILS(hr, ConvertBufferToVariant( pBuf, dwLen, v ));
  671. hr = S_OK;
  672. __MPC_FUNC_CLEANUP;
  673. if(pBuf) delete [] pBuf;
  674. __MPC_FUNC_EXIT(hr);
  675. }
  676. HRESULT MPC::ConvertVariantToIStream( /*[in ]*/ const VARIANT* v ,
  677. /*[out]*/ IStream* *pStream )
  678. {
  679. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertVariantToBuffer" );
  680. HRESULT hr;
  681. CComPtr<IStream> stream;
  682. BYTE* pBuf = NULL;
  683. DWORD dwLen;
  684. ULONG lWritten;
  685. __MPC_PARAMCHECK_BEGIN(hr)
  686. __MPC_PARAMCHECK_NOTNULL(v);
  687. __MPC_PARAMCHECK_POINTER_AND_SET(pStream,NULL);
  688. __MPC_PARAMCHECK_END();
  689. __MPC_EXIT_IF_METHOD_FAILS(hr, ConvertVariantToBuffer( v, pBuf, dwLen ));
  690. __MPC_EXIT_IF_METHOD_FAILS(hr, ::CreateStreamOnHGlobal( NULL, TRUE, &stream ));
  691. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->Write( pBuf, dwLen, &lWritten ));
  692. if(dwLen != lWritten)
  693. {
  694. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_HANDLE_DISK_FULL );
  695. }
  696. //
  697. // Rewind to the beginning.
  698. //
  699. {
  700. LARGE_INTEGER li = { 0, 0 };
  701. __MPC_EXIT_IF_METHOD_FAILS(hr, stream->Seek( li, STREAM_SEEK_SET, NULL ));
  702. }
  703. *pStream = stream.Detach();
  704. hr = S_OK;
  705. __MPC_FUNC_CLEANUP;
  706. if(pBuf) delete [] pBuf;
  707. __MPC_FUNC_EXIT(hr);
  708. }
  709. ////////////////////////////////////////////////////////////////////////////////
  710. HRESULT MPC::ConvertListToSafeArray( /*[in]*/ const MPC::WStringList& lst, /*[out]*/ VARIANT& v, /*[in]*/ VARTYPE vt )
  711. {
  712. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertListToSafeArray" );
  713. HRESULT hr;
  714. LPVOID pData;
  715. MPC::WStringIterConst it;
  716. __MPC_EXIT_IF_METHOD_FAILS(hr, ::VariantClear( &v ));
  717. if(vt != VT_VARIANT &&
  718. vt != VT_BSTR )
  719. {
  720. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  721. }
  722. v.vt = VT_ARRAY | vt; __MPC_EXIT_IF_ALLOC_FAILS(hr, v.parray, ::SafeArrayCreateVector( vt, 0, lst.size() ));
  723. __MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v.parray, &pData ));
  724. hr = S_OK;
  725. {
  726. BSTR* rgArrayData1 = (BSTR *)pData;
  727. VARIANT* rgArrayData2 = (VARIANT*)pData;
  728. for(it = lst.begin(); it != lst.end(); it++)
  729. {
  730. BSTR bstr;
  731. if((bstr = ::SysAllocString( it->c_str() )) == NULL)
  732. {
  733. hr = E_OUTOFMEMORY;
  734. break;
  735. }
  736. if(vt == VT_BSTR)
  737. {
  738. *rgArrayData1++ = bstr;
  739. }
  740. else
  741. {
  742. rgArrayData2->vt = VT_BSTR;
  743. rgArrayData2->bstrVal = bstr;
  744. rgArrayData2++;
  745. }
  746. }
  747. }
  748. ::SafeArrayUnaccessData( v.parray );
  749. __MPC_FUNC_CLEANUP;
  750. __MPC_FUNC_EXIT(hr);
  751. }
  752. HRESULT MPC::ConvertSafeArrayToList( /*[in]*/ const VARIANT& v, /*[out]*/ MPC::WStringList& lst )
  753. {
  754. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertSafeArrayToList" );
  755. HRESULT hr;
  756. LPVOID pData;
  757. long lBound;
  758. long uBound;
  759. long l;
  760. if(v.vt != (VT_ARRAY | VT_BSTR ) &&
  761. v.vt != (VT_ARRAY | VT_VARIANT) )
  762. {
  763. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  764. }
  765. ::SafeArrayGetLBound( v.parray, 1, &lBound );
  766. ::SafeArrayGetUBound( v.parray, 1, &uBound );
  767. __MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v.parray, &pData ));
  768. {
  769. BSTR* rgArrayData1 = (BSTR *)pData;
  770. VARIANT* rgArrayData2 = (VARIANT*)pData;
  771. for(l=lBound; l<=uBound; l++)
  772. {
  773. BSTR bstr = NULL;
  774. CComVariant v2;
  775. if(v.vt == (VT_ARRAY | VT_BSTR))
  776. {
  777. bstr = *rgArrayData1++;
  778. }
  779. else
  780. {
  781. v2 = *rgArrayData2++;
  782. if(SUCCEEDED(v2.ChangeType( VT_BSTR )))
  783. {
  784. bstr = v2.bstrVal;
  785. }
  786. }
  787. lst.push_back( SAFEBSTR( bstr ) );
  788. }
  789. }
  790. ::SafeArrayUnaccessData( v.parray );
  791. hr = S_OK;
  792. __MPC_FUNC_CLEANUP;
  793. __MPC_FUNC_EXIT(hr);
  794. }
  795. /////////////////////////////////////////////////////////////////////////////
  796. /////////////////////////////////////////////////////////////////////////////
  797. /////////////////////////////////////////////////////////////////////////////
  798. /////////////////////////////////////////////////////////////////////////////
  799. static void Parse_SkipWhite( WCHAR*& szStr )
  800. {
  801. while(iswspace( szStr[0] )) szStr++;
  802. }
  803. static void Parse_GetQuoted( WCHAR*& szSrc ,
  804. WCHAR* szDst ,
  805. WCHAR quote ,
  806. bool fBackslashForEscape )
  807. {
  808. WCHAR c;
  809. while((c = *++szSrc))
  810. {
  811. if(c == quote) { szSrc++; break; }
  812. if(fBackslashForEscape && c == '\\' && szSrc[1]) c = *++szSrc;
  813. *szDst++ = c;
  814. }
  815. *szDst = 0;
  816. }
  817. static void Parse_GetNonBlank( WCHAR*& szSrc ,
  818. WCHAR* szDst )
  819. {
  820. WCHAR c;
  821. szSrc--;
  822. while((c = *++szSrc))
  823. {
  824. if(iswspace( c )) break;
  825. *szDst++ = c;
  826. }
  827. *szDst = 0;
  828. }
  829. HRESULT MPC::CommandLine_Parse( /*[out]*/ int& argc ,
  830. /*[out]*/ LPCWSTR*& argv ,
  831. /*[in] */ LPWSTR lpCmdLine ,
  832. /*[in] */ bool fBackslashForEscape )
  833. {
  834. __MPC_FUNC_ENTRY( COMMONID, "MPC::CommandLine_Parse" );
  835. HRESULT hr;
  836. LPWSTR szArgument = NULL;
  837. int iPass;
  838. argc = 0;
  839. argv = NULL;
  840. //
  841. // If no command line is supplied, use the one from the system.
  842. //
  843. if(lpCmdLine == NULL)
  844. {
  845. lpCmdLine = ::GetCommandLineW();
  846. }
  847. //
  848. // Nothing to parse, exit...
  849. //
  850. if(lpCmdLine == NULL)
  851. {
  852. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  853. }
  854. //
  855. // Allocate a temporary buffer.
  856. //
  857. __MPC_EXIT_IF_ALLOC_FAILS(hr, szArgument, new WCHAR[wcslen( lpCmdLine ) + 1]);
  858. //
  859. // Two passes, one to count the arguments, the other to allocate them.
  860. //
  861. for(iPass=0; iPass < 2; iPass++)
  862. {
  863. LPWSTR szSrc = lpCmdLine;
  864. int i = 0;
  865. Parse_SkipWhite( szSrc );
  866. while(szSrc[0])
  867. {
  868. if(szSrc[0] == '"' ||
  869. szSrc[0] == '\'' )
  870. {
  871. Parse_GetQuoted( szSrc, szArgument, szSrc[0], fBackslashForEscape );
  872. }
  873. else
  874. {
  875. Parse_GetNonBlank( szSrc, szArgument );
  876. }
  877. if(argv)
  878. {
  879. LPWSTR szNewParam;
  880. __MPC_EXIT_IF_ALLOC_FAILS(hr, szNewParam, _wcsdup( szArgument ));
  881. argv[i] = szNewParam;
  882. }
  883. i++;
  884. Parse_SkipWhite( szSrc );
  885. }
  886. if(iPass == 0)
  887. {
  888. argc = i;
  889. __MPC_EXIT_IF_ALLOC_FAILS(hr, argv, new LPCWSTR[argc]);
  890. for(i=0; i<argc; i++)
  891. {
  892. argv[i] = NULL;
  893. }
  894. }
  895. }
  896. hr = S_OK;
  897. __MPC_FUNC_CLEANUP;
  898. if(FAILED(hr))
  899. {
  900. CommandLine_Free( argc, argv );
  901. }
  902. delete [] szArgument;
  903. __MPC_FUNC_EXIT(hr);
  904. }
  905. void MPC::CommandLine_Free( /*[in ]*/ int& argc ,
  906. /*[in ]*/ LPCWSTR*& argv )
  907. {
  908. if(argv)
  909. {
  910. for(int i=0; i<argc; i++)
  911. {
  912. free( (void*)argv[i] );
  913. }
  914. delete [] argv;
  915. argv = NULL;
  916. }
  917. argc = 0;
  918. }
  919. ////////////////////////////////////////////////////////////////////////////////
  920. HRESULT MPC::ConvertStringToBitField( /*[in] */ LPCWSTR szText ,
  921. /*[out]*/ DWORD& dwBitField ,
  922. /*[in] */ const StringToBitField* pLookup ,
  923. /*[in] */ bool fUseTilde )
  924. {
  925. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertStringToBitField" );
  926. HRESULT hr;
  927. DWORD dwVal = 0;
  928. if(szText && pLookup)
  929. {
  930. std::vector<MPC::wstring> vec;
  931. std::vector<MPC::wstring>::iterator it;
  932. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SplitAtDelimiter( vec, szText, L" ,", false, true ));
  933. for(it=vec.begin(); it!=vec.end(); it++)
  934. {
  935. LPCWSTR szToken = it->c_str();
  936. int iNum = 0;
  937. if(!_wcsnicmp( L"0x", szToken, 2 ) && swscanf( &szToken[2], L"%x", &iNum ) == 1)
  938. {
  939. dwVal |= iNum;
  940. }
  941. else
  942. {
  943. const StringToBitField* pPtr = pLookup;
  944. bool fReverse = false;
  945. if(fUseTilde && szToken[0] == '~')
  946. {
  947. fReverse = true;
  948. szToken++;
  949. }
  950. while(pPtr->szName)
  951. {
  952. if(!_wcsicmp( pPtr->szName, szToken ))
  953. {
  954. DWORD dwMask = pPtr->dwMask;
  955. DWORD dwSet = pPtr->dwSet;
  956. DWORD dwReset = pPtr->dwReset;
  957. DWORD dwSelected = dwVal & dwMask;
  958. DWORD dwRemainder = dwVal & (~ dwMask);
  959. if(fReverse)
  960. {
  961. dwSelected &= ~dwSet;
  962. }
  963. else
  964. {
  965. dwSelected &= ~dwReset;
  966. dwSelected |= dwSet;
  967. }
  968. dwVal = (dwSelected & dwMask) | dwRemainder;
  969. break;
  970. }
  971. pPtr++;
  972. }
  973. }
  974. }
  975. }
  976. hr = S_OK;
  977. __MPC_FUNC_CLEANUP;
  978. dwBitField = dwVal;
  979. __MPC_FUNC_EXIT(hr);
  980. }
  981. HRESULT MPC::ConvertBitFieldToString( /*[in] */ DWORD dwBitField ,
  982. /*[out]*/ MPC::wstring& szText ,
  983. /*[in] */ const StringToBitField* pLookup )
  984. {
  985. __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertBitFieldToString" );
  986. HRESULT hr;
  987. DWORD dwVal = 0;
  988. szText = L"";
  989. if(pLookup)
  990. {
  991. while(pLookup->szName)
  992. {
  993. DWORD dwMask = pLookup->dwMask;
  994. DWORD dwSet = pLookup->dwSet;
  995. DWORD dwReset = pLookup->dwReset;
  996. if((dwBitField & (dwMask & dwReset)) == dwSet)
  997. {
  998. if(szText.size()) szText += L" ";
  999. szText += pLookup->szName;
  1000. dwBitField = (dwBitField & ~dwMask) | ((dwBitField & ~dwReset) & dwMask);
  1001. }
  1002. pLookup++;
  1003. }
  1004. }
  1005. if(dwBitField)
  1006. {
  1007. WCHAR rgBuf[64];
  1008. StringCchPrintfW( rgBuf, ARRAYSIZE(rgBuf), L"0x%x", dwBitField );
  1009. if(szText.size()) szText += L" ";
  1010. szText += rgBuf;
  1011. }
  1012. hr = S_OK;
  1013. __MPC_FUNC_EXIT(hr);
  1014. }
  1015. ////////////////////////////////////////////////////////////////////////////////
  1016. //
  1017. // This algorithm is not a very efficient one, O(N * M), but it's ok as long as "delims" is short (M small).
  1018. //
  1019. template <class E> static HRESULT InnerSplitAtDelimiter( std::vector< std::basic_stringNR<E> >& vec ,
  1020. const E* str ,
  1021. const E* delims ,
  1022. bool fDelimIsAString ,
  1023. bool fSkipAdjacentDelims )
  1024. {
  1025. std::basic_stringNR<E> szText ( str );
  1026. std::basic_stringNR<E> szDelims( delims );
  1027. std::basic_stringNR<E>::size_type iPos = 0;
  1028. std::basic_stringNR<E>::size_type iStart = 0;
  1029. std::basic_stringNR<E>::size_type iDelimsLen = szDelims.length();
  1030. bool fSkip = false;
  1031. vec.clear();
  1032. if(fDelimIsAString)
  1033. {
  1034. while(1)
  1035. {
  1036. iPos = szText.find( szDelims, iStart );
  1037. if(iPos == std::basic_stringNR<E>::npos)
  1038. {
  1039. vec.push_back( &szText[iStart] );
  1040. break;
  1041. }
  1042. else
  1043. {
  1044. if(fSkip && iPos == iStart)
  1045. {
  1046. ;
  1047. }
  1048. else
  1049. {
  1050. fSkip = fSkipAdjacentDelims;
  1051. vec.push_back( std::basic_stringNR<E>( &szText[iStart], &szText[iPos] ) );
  1052. }
  1053. iStart = iPos + iDelimsLen;
  1054. }
  1055. }
  1056. }
  1057. else
  1058. {
  1059. std::basic_stringNR<E>::size_type iTextEnd = szText.length();
  1060. while(iPos < iTextEnd)
  1061. {
  1062. if(szDelims.find( szText[iPos] ) != std::basic_stringNR<E>::npos)
  1063. {
  1064. if(fSkip == false)
  1065. {
  1066. fSkip = fSkipAdjacentDelims;
  1067. vec.push_back( std::basic_stringNR<E>( &szText[iStart], &szText[iPos] ) );
  1068. }
  1069. iStart = iPos + 1;
  1070. }
  1071. else
  1072. {
  1073. if(fSkip)
  1074. {
  1075. iStart = iPos;
  1076. fSkip = false;
  1077. }
  1078. }
  1079. iPos++;
  1080. }
  1081. vec.push_back( std::basic_stringNR<E>( &szText[iStart] ) );
  1082. }
  1083. //
  1084. // In case of single string, don't return anything.
  1085. //
  1086. if(vec.size() == 1 && vec[0].empty())
  1087. {
  1088. vec.clear();
  1089. }
  1090. return S_OK;
  1091. }
  1092. HRESULT MPC::SplitAtDelimiter( StringVector& vec ,
  1093. LPCSTR str ,
  1094. LPCSTR delims ,
  1095. bool fDelimIsAString ,
  1096. bool fSkipAdjacentDelims )
  1097. {
  1098. return InnerSplitAtDelimiter( vec, str, delims, fDelimIsAString, fSkipAdjacentDelims );
  1099. }
  1100. HRESULT MPC::SplitAtDelimiter( WStringVector& vec ,
  1101. LPCWSTR str ,
  1102. LPCWSTR delims ,
  1103. bool fDelimIsAString ,
  1104. bool fSkipAdjacentDelims )
  1105. {
  1106. return InnerSplitAtDelimiter( vec, str, delims, fDelimIsAString, fSkipAdjacentDelims );
  1107. }
  1108. ////////////////////////////////////////
  1109. template <class E> static HRESULT InnerJoinWithDelimiter( const std::vector< std::basic_stringNR<E> >& vec ,
  1110. std::basic_stringNR<E>& str ,
  1111. const E* delims )
  1112. {
  1113. int i;
  1114. for(i=0; i<vec.size(); i++)
  1115. {
  1116. if(i) str += delims;
  1117. str += vec[i];
  1118. }
  1119. return S_OK;
  1120. }
  1121. HRESULT MPC::JoinWithDelimiter( const StringVector& vec ,
  1122. MPC::string& str ,
  1123. LPCSTR delims )
  1124. {
  1125. return InnerJoinWithDelimiter( vec, str, delims );
  1126. }
  1127. HRESULT MPC::JoinWithDelimiter( const WStringVector& vec ,
  1128. MPC::wstring& str ,
  1129. LPCWSTR delims )
  1130. {
  1131. return InnerJoinWithDelimiter( vec, str, delims );
  1132. }
  1133. /////////////////////////////////////////////////////////////////////////////
  1134. /////////////////////////////////////////////////////////////////////////////
  1135. /////////////////////////////////////////////////////////////////////////////
  1136. /////////////////////////////////////////////////////////////////////////////
  1137. //
  1138. // Function Name : MPC::MakeDir
  1139. //
  1140. // Parameters : MPC::wstring& szStr : path to a directory or a file.
  1141. //
  1142. // Return : HRESULT
  1143. //
  1144. // Synopsis : Given a path in the form '[<dir>\]*\[<file>]',
  1145. // it creates all the needed directories.
  1146. //
  1147. /////////////////////////////////////////////////////////////////////////////
  1148. HRESULT MPC::MakeDir( /*[in]*/ const MPC::wstring& strPath, /*[in]*/ bool fCreateParent )
  1149. {
  1150. __MPC_FUNC_ENTRY( COMMONID, "MPC::MakeDir");
  1151. HRESULT hr;
  1152. MPC::wstring szParent;
  1153. BOOL fRes;
  1154. DWORD dwRes;
  1155. if(fCreateParent)
  1156. {
  1157. MPC::wstring::size_type iPos = strPath.rfind( '\\' );
  1158. if(iPos == strPath.npos)
  1159. {
  1160. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1161. }
  1162. szParent = strPath.substr( 0, iPos );
  1163. }
  1164. else
  1165. {
  1166. szParent = strPath;
  1167. }
  1168. //
  1169. // Try to create parent directory...
  1170. //
  1171. fRes = ::CreateDirectoryW( szParent.c_str(), NULL );
  1172. dwRes = ::GetLastError();
  1173. if(fRes == TRUE || dwRes == ERROR_ALREADY_EXISTS)
  1174. {
  1175. //
  1176. // Success, exit.
  1177. //
  1178. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1179. }
  1180. //
  1181. // If the error is not PATH_NOT_FOUND, exit.
  1182. //
  1183. if(dwRes != ERROR_PATH_NOT_FOUND)
  1184. {
  1185. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, dwRes );
  1186. }
  1187. //
  1188. // Recursively build the parent directories.
  1189. //
  1190. __MPC_EXIT_IF_METHOD_FAILS(hr, MakeDir( szParent, true ) );
  1191. //
  1192. // Try again to create parent directory.
  1193. //
  1194. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CreateDirectoryW( szParent.c_str(), NULL ));
  1195. hr = S_OK;
  1196. __MPC_FUNC_CLEANUP;
  1197. __MPC_FUNC_EXIT(hr);
  1198. }
  1199. /////////////////////////////////////////////////////////////////////////////
  1200. //
  1201. // Function Name : MPC::GetDiskSpace
  1202. //
  1203. // Parameters : MPC::wstring& szFile : path to a directory or a file.
  1204. // ULARGE_INTEGER& liFree : number of bytes free on that disk.
  1205. // ULARGE_INTEGER& liTotal : total number of bytes on that disk.
  1206. //
  1207. // Return : HRESULT
  1208. //
  1209. // Synopsis : Given a path, it calculates the total and available disk space.
  1210. //
  1211. /////////////////////////////////////////////////////////////////////////////
  1212. HRESULT MPC::GetDiskSpace( /*[in]*/ const MPC::wstring& szFile ,
  1213. /*[out]*/ ULARGE_INTEGER& liFree ,
  1214. /*[out]*/ ULARGE_INTEGER& liTotal )
  1215. {
  1216. __MPC_FUNC_ENTRY( COMMONID, "MPC::GetDiskSpace");
  1217. HRESULT hr;
  1218. MPC::wstring szParent;
  1219. MPC::wstring::size_type iPos;
  1220. DWORD dwSectorsPerCluster;
  1221. DWORD dwBytesPerSector;
  1222. DWORD dwNumberOfFreeClusters;
  1223. DWORD dwTotalNumberOfClusters;
  1224. //
  1225. // Initialize the Parent variable.
  1226. //
  1227. szParent = szFile;
  1228. //
  1229. // Normal <DRIVE>:\... format?
  1230. //
  1231. iPos = szFile.find( L":\\" );
  1232. if(iPos != szFile.npos)
  1233. {
  1234. szParent = szFile.substr( 0, iPos+2 );
  1235. }
  1236. else
  1237. {
  1238. //
  1239. // If the path a UNC?
  1240. //
  1241. iPos = szFile.find( L"\\\\" );
  1242. if(iPos != szFile.npos && iPos == 0)
  1243. {
  1244. //
  1245. // Find slash after server name.
  1246. //
  1247. iPos = szFile.find( L"\\", 2 );
  1248. if(iPos != szFile.npos)
  1249. {
  1250. //
  1251. // Is a slash present after the share name?
  1252. //
  1253. iPos = szFile.find( L"\\", iPos+1 );
  1254. if(iPos != szFile.npos)
  1255. {
  1256. szParent = szFile.substr( 0, iPos+1 );
  1257. }
  1258. else
  1259. {
  1260. szParent = szFile;
  1261. szParent.append( L"\\" ); // Share names must end with a trailing slash.
  1262. }
  1263. }
  1264. }
  1265. }
  1266. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::GetDiskFreeSpaceW( szParent.c_str() ,
  1267. &dwSectorsPerCluster ,
  1268. &dwBytesPerSector ,
  1269. &dwNumberOfFreeClusters ,
  1270. &dwTotalNumberOfClusters ));
  1271. liFree .QuadPart = (ULONGLONG)(dwBytesPerSector * dwSectorsPerCluster) * (ULONGLONG)dwNumberOfFreeClusters;
  1272. liTotal.QuadPart = (ULONGLONG)(dwBytesPerSector * dwSectorsPerCluster) * (ULONGLONG)dwTotalNumberOfClusters;
  1273. hr = S_OK;
  1274. __MPC_FUNC_CLEANUP;
  1275. __MPC_FUNC_EXIT(hr);
  1276. }
  1277. ////////////////////////////////////////////////////////////////////////////////
  1278. HRESULT MPC::FailOnLowDiskSpace( /*[in]*/ LPCWSTR szFile, /*[in]*/ DWORD dwLowLevel )
  1279. {
  1280. MPC::wstring szExpandedFile( szFile ); MPC::SubstituteEnvVariables( szExpandedFile );
  1281. ULARGE_INTEGER liFree;
  1282. ULARGE_INTEGER liTotal;
  1283. if(SUCCEEDED(MPC::GetDiskSpace( szExpandedFile, liFree, liTotal )))
  1284. {
  1285. if(liFree.HighPart > 0 ||
  1286. liFree.LowPart > dwLowLevel )
  1287. {
  1288. return S_OK;
  1289. }
  1290. }
  1291. return HRESULT_FROM_WIN32(ERROR_DISK_FULL);
  1292. }
  1293. HRESULT MPC::FailOnLowMemory( /*[in]*/ DWORD dwLowLevel )
  1294. {
  1295. MEMORYSTATUSEX ms;
  1296. ::ZeroMemory( &ms, sizeof(ms) ); ms.dwLength = sizeof(ms);
  1297. if(::GlobalMemoryStatusEx( &ms ))
  1298. {
  1299. if(ms.ullAvailVirtual > dwLowLevel)
  1300. {
  1301. return S_OK;
  1302. }
  1303. }
  1304. return E_OUTOFMEMORY;
  1305. }
  1306. /////////////////////////////////////////////////////////////////////////////
  1307. /////////////////////////////////////////////////////////////////////////////
  1308. /////////////////////////////////////////////////////////////////////////////
  1309. HRESULT MPC::ExecuteCommand( /*[in]*/ const MPC::wstring& szCommandLine )
  1310. {
  1311. __MPC_FUNC_ENTRY( COMMONID, "MPC::ExecuteCommand" );
  1312. HRESULT hr;
  1313. PROCESS_INFORMATION piProcessInformation;
  1314. STARTUPINFOW siStartupInfo;
  1315. DWORD dwExitCode;
  1316. ::ZeroMemory( (PVOID)&piProcessInformation, sizeof( piProcessInformation ) );
  1317. ::ZeroMemory( (PVOID)&siStartupInfo , sizeof( siStartupInfo ) ); siStartupInfo.cb = sizeof( siStartupInfo );
  1318. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CreateProcessW( NULL,
  1319. (LPWSTR)szCommandLine.c_str(),
  1320. NULL,
  1321. NULL,
  1322. FALSE,
  1323. DETACHED_PROCESS,
  1324. NULL,
  1325. NULL,
  1326. &siStartupInfo,
  1327. &piProcessInformation ));
  1328. MPC::WaitForSingleObject( piProcessInformation.hProcess, INFINITE );
  1329. __MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::GetExitCodeProcess( piProcessInformation.hProcess, &dwExitCode ));
  1330. if(dwExitCode != 0)
  1331. {
  1332. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, dwExitCode );
  1333. }
  1334. hr = S_OK;
  1335. __MPC_FUNC_CLEANUP;
  1336. if(piProcessInformation.hProcess) ::CloseHandle( piProcessInformation.hProcess );
  1337. if(piProcessInformation.hThread ) ::CloseHandle( piProcessInformation.hThread );
  1338. __MPC_FUNC_EXIT(hr);
  1339. }
  1340. /////////////////////////////////////////////////////////////////////////////
  1341. /////////////////////////////////////////////////////////////////////////////
  1342. /////////////////////////////////////////////////////////////////////////////
  1343. HRESULT MPC::GetBSTR( /*[in] */ LPCWSTR bstr ,
  1344. /*[out]*/ BSTR *pVal ,
  1345. /*[in] */ bool fNullOk )
  1346. {
  1347. __MPC_FUNC_ENTRY( COMMONID, "MPC::GetBSTR" );
  1348. HRESULT hr;
  1349. __MPC_PARAMCHECK_BEGIN(hr)
  1350. __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL);
  1351. if(fNullOk == false) __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstr);
  1352. __MPC_PARAMCHECK_END();
  1353. *pVal = ::SysAllocString( bstr );
  1354. if(*pVal == NULL && bstr)
  1355. {
  1356. __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  1357. }
  1358. hr = S_OK;
  1359. __MPC_FUNC_CLEANUP;
  1360. __MPC_FUNC_EXIT(hr);
  1361. }
  1362. HRESULT MPC::PutBSTR( /*[out]*/ CComBSTR& bstr ,
  1363. /*[in ]*/ LPCWSTR newVal ,
  1364. /*[in] */ bool fNullOk )
  1365. {
  1366. __MPC_FUNC_ENTRY( COMMONID, "MPC::PutBSTR" );
  1367. HRESULT hr;
  1368. __MPC_PARAMCHECK_BEGIN(hr)
  1369. if(fNullOk == false) __MPC_PARAMCHECK_STRING_NOT_EMPTY(newVal);
  1370. __MPC_PARAMCHECK_END();
  1371. bstr = newVal;
  1372. if(!bstr && newVal != NULL)
  1373. {
  1374. __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  1375. }
  1376. hr = S_OK;
  1377. __MPC_FUNC_CLEANUP;
  1378. __MPC_FUNC_EXIT(hr);
  1379. }
  1380. HRESULT MPC::PutBSTR( /*[out]*/ CComBSTR& bstr ,
  1381. /*[in ]*/ VARIANT* newVal ,
  1382. /*[in] */ bool fNullOk )
  1383. {
  1384. __MPC_FUNC_ENTRY( COMMONID, "MPC::PutBSTR" );
  1385. HRESULT hr;
  1386. CComVariant v;
  1387. bool fEmpty;
  1388. if(newVal)
  1389. {
  1390. if(newVal->vt != VT_BSTR)
  1391. {
  1392. v.ChangeType( VT_BSTR, newVal );
  1393. newVal = &v;
  1394. }
  1395. }
  1396. if(newVal == NULL || // Null pointer.
  1397. newVal->vt != VT_BSTR || // Not a string.
  1398. newVal->bstrVal == NULL || // Missing string.
  1399. newVal->bstrVal[0] == 0 ) // Empty string.
  1400. {
  1401. if(fNullOk == false)
  1402. {
  1403. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  1404. }
  1405. fEmpty = true;
  1406. }
  1407. else
  1408. {
  1409. fEmpty = false;
  1410. }
  1411. if(fEmpty)
  1412. {
  1413. bstr.Empty();
  1414. }
  1415. else
  1416. {
  1417. bstr = newVal->bstrVal;
  1418. if(!bstr)
  1419. {
  1420. __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  1421. }
  1422. }
  1423. hr = S_OK;
  1424. __MPC_FUNC_CLEANUP;
  1425. __MPC_FUNC_EXIT(hr);
  1426. }
  1427. /////////////////////////////////////////////////////////////////////////////
  1428. bool MPC::NocaseLess::operator()( /*[in]*/ const MPC::string& szX, /*[in]*/ const MPC::string& szY ) const
  1429. {
  1430. return _stricmp( szX.c_str(), szY.c_str() ) < 0;
  1431. }
  1432. bool MPC::NocaseLess::operator()( /*[in]*/ const MPC::wstring& szX, /*[in]*/ const MPC::wstring& szY ) const
  1433. {
  1434. return _wcsicmp( szX.c_str(), szY.c_str() ) < 0;
  1435. }
  1436. bool MPC::NocaseLess::operator()( /*[in]*/ const BSTR bstrX, /*[in]*/ const BSTR bstrY ) const
  1437. {
  1438. return MPC::StrICmp( bstrX, bstrY ) < 0;
  1439. }
  1440. ////////////////////////////////////////
  1441. bool MPC::NocaseCompare::operator()( /*[in]*/ const MPC::string& szX, /*[in]*/ const MPC::string& szY ) const
  1442. {
  1443. return _stricmp( szX.c_str(), szY.c_str() ) == 0;
  1444. }
  1445. bool MPC::NocaseCompare::operator()( /*[in]*/ const MPC::wstring& szX, /*[in]*/ const MPC::wstring& szY ) const
  1446. {
  1447. return _wcsicmp( szX.c_str(), szY.c_str() ) == 0;
  1448. }
  1449. bool MPC::NocaseCompare::operator()( /*[in]*/ const BSTR bstrX, /*[in]*/ const BSTR bstrY ) const
  1450. {
  1451. return MPC::StrICmp( bstrX, bstrY ) == 0;
  1452. }