|
|
/******************************************************************************
Copyright (c) 1999 Microsoft Corporation
Module Name: Utils.cpp
Abstract: This file contains the implementation of various utility functions.
Revision History: Davide Massarenti (Dmassare) 04/17/99 created
******************************************************************************/
#include "stdafx.h"
#define BUFFER_TMP_SIZE 1024
////////////////////////////////////////////////////////////////////////////////
int MPC::HexToNum( int c ) { if(c >= '0' && c <= '9') return c - '0'; if(c >= 'A' && c <= 'F') return c - 'A' + 10; if(c >= 'a' && c <= 'f') return c - 'a' + 10;
return -1; }
char MPC::NumToHex( int c ) { static char s_lookup[] = { '0', '1', '2', '3' , '4', '5', '6', '7' , '8', '9', 'A', 'B' , 'C', 'D', 'E', 'F' };
return s_lookup[ c & 0xF ]; }
////////////////////////////////////////////////////////////////////////////////
void MPC::RemoveTrailingBackslash( /*[in/out]*/ LPWSTR szPath ) { LPWSTR szEnd = szPath + wcslen( szPath );
while(szEnd-- > szPath) { if(szEnd[0] != '\\' && szEnd[0] != '/' ) { szEnd[1] = 0; break; } } }
HRESULT MPC::GetProgramDirectory( /*[out]*/ MPC::wstring& szPath ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::GetProgramDirectory" );
HRESULT hr; WCHAR rgFileName[MAX_PATH+1]; LPWSTR szEnd;
__MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetModuleFileNameW( NULL, rgFileName, MAX_PATH )); rgFileName[MAX_PATH] = 0;
// Remove file name.
if((szEnd = wcsrchr( rgFileName, '\\' ))) szEnd[0] = 0;
szPath = rgFileName; hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::GetUserWritablePath( /*[out]*/ MPC::wstring& strPath, /*[in]*/ LPCWSTR szSubDir ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::GetUserWritablePath");
HRESULT hr; LPITEMIDLIST pidl = NULL; WCHAR rgAppDataPath[MAX_PATH+1]; LPWSTR szPtr;
__MPC_EXIT_IF_METHOD_FAILS(hr, ::SHGetSpecialFolderLocation( NULL, CSIDL_LOCAL_APPDATA, &pidl ));
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::SHGetPathFromIDListW( pidl, rgAppDataPath ));
MPC::RemoveTrailingBackslash( rgAppDataPath );
if(szSubDir) { StringCchCatW( rgAppDataPath, ARRAYSIZE(rgAppDataPath), L"\\" ); StringCchCatW( rgAppDataPath, ARRAYSIZE(rgAppDataPath), szSubDir );
MPC::RemoveTrailingBackslash( rgAppDataPath ); }
strPath = rgAppDataPath; hr = S_OK;
__MPC_FUNC_CLEANUP;
//
// Get the shell's allocator to free PIDLs
//
if(pidl != NULL) { LPMALLOC lpMalloc = NULL;
if(SUCCEEDED(SHGetMalloc( &lpMalloc )) && lpMalloc != NULL) { lpMalloc->Free( pidl ); lpMalloc->Release(); } }
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::GetCanonialPathName( /*[out]*/ MPC::wstring& szPathNameOut, /*[in]*/ LPCWSTR szPathNameIn ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::GetCanonialPathName");
HRESULT hr; WCHAR rgFullPath [MAX_PATH+1]; WCHAR rgCurrentDir[MAX_PATH+1]; DWORD dwLength; LPWSTR szFilePart;
__MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetFullPathNameW( szPathNameIn, MAXSTRLEN(rgFullPath), rgFullPath, &szFilePart ));
dwLength = ::GetCurrentDirectoryW( MAXSTRLEN(rgCurrentDir), rgCurrentDir ); __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, dwLength);
if((0 != _wcsnicmp( rgFullPath, rgCurrentDir, dwLength )) || (L'\\' != rgFullPath[dwLength])) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_INVALID_PARAMETER); }
szPathNameOut = rgFullPath + dwLength + 1; hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::GetTemporaryFileName( /*[out]*/ MPC::wstring& szFile, /*[in]*/ LPCWSTR szBase, /*[in]*/ LPCWSTR szPrefix ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::GetTemporaryFileName");
HRESULT hr; WCHAR rgTmp [MAX_PATH+1]; WCHAR rgBase[MAX_PATH+1];
if(szBase) { StringCchCopyW( rgBase, ARRAYSIZE(rgBase), szBase ); } else { __MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetTempPathW( MAXSTRLEN(rgBase), rgBase )); }
MPC::RemoveTrailingBackslash( rgBase );
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( rgBase, false )); // Make sure the directory exists.
__MPC_EXIT_IF_CALL_RETURNS_ZERO(hr, ::GetTempFileNameW( rgBase, szPrefix ? szPrefix : L"MPC", 0, rgTmp ));
szFile = rgTmp; hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::RemoveTemporaryFile( /*[in/out]*/ MPC::wstring& szFile ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::RemoveTemporaryFile");
HRESULT hr;
if(szFile.size() > 0) { __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::DeleteFile( szFile ));
szFile = L""; }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
HRESULT MPC::SubstituteEnvVariables( /*[in/out]*/ MPC::wstring& szEnv ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::SubstituteEnvVariables" );
HRESULT hr; WCHAR rgTmp[BUFFER_TMP_SIZE]; LPWSTR szPtr = rgTmp; LPWSTR szBuf = NULL; DWORD dwSize;
dwSize = ::ExpandEnvironmentStringsW( szEnv.c_str(), szPtr, MAXSTRLEN(rgTmp) ); if(dwSize >= MAXSTRLEN(rgTmp)) { __MPC_EXIT_IF_ALLOC_FAILS(hr, szBuf, new WCHAR[dwSize+2]);
(void)::ExpandEnvironmentStringsW( szEnv.c_str(), szBuf, dwSize+1 );
szPtr = szBuf; }
szEnv = szPtr; hr = S_OK;
__MPC_FUNC_CLEANUP;
delete [] szBuf;
__MPC_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
DATE MPC::GetSystemTime() { SYSTEMTIME stNow; DATE dDate;
::GetSystemTime( &stNow );
::SystemTimeToVariantTime( &stNow, &dDate );
return dDate; }
DATE MPC::GetLocalTime() { SYSTEMTIME stNow; DATE dDate;
::GetLocalTime( &stNow );
::SystemTimeToVariantTime( &stNow, &dDate );
return dDate; }
static DATE local_FixSubSecondTime( /*[in]*/ DATE dDate, /*[in]*/ bool fHighPrecision ) { double dCount; double dFreq; long iCount;
if(fHighPrecision) { LARGE_INTEGER liCount; LARGE_INTEGER liFreq;
::QueryPerformanceCounter ( &liCount ); dCount = (double)liCount.QuadPart; ::QueryPerformanceFrequency( &liFreq ); dFreq = (double)liFreq .QuadPart; } else { dCount = ::GetTickCount(); dFreq = 1000; }
if(dFreq) { dCount /= dFreq; iCount = dCount;
dDate += (dCount - iCount) / (24 * 60 * 60 * 1000.0); }
return dDate; }
DATE MPC::GetSystemTimeEx( /*[in]*/ bool fHighPrecision ) { return local_FixSubSecondTime( MPC::GetSystemTime(), fHighPrecision ); }
DATE MPC::GetLocalTimeEx( /*[in]*/ bool fHighPrecision ) { return local_FixSubSecondTime( MPC::GetLocalTime(), fHighPrecision ); }
DATE MPC::GetLastModifiedDate( /*[out]*/ const MPC::wstring& strFile ) { WIN32_FILE_ATTRIBUTE_DATA wfadInfo; SYSTEMTIME sys; DATE dFile;
if(::GetFileAttributesExW( strFile.c_str(), GetFileExInfoStandard, &wfadInfo ) == FALSE || ::FileTimeToSystemTime( &wfadInfo.ftLastWriteTime , &sys ) == FALSE ) { return 0; // File doesn't exist.
}
::SystemTimeToVariantTime( &sys, &dFile );
return dFile; }
HRESULT MPC::ConvertSizeUnit( /*[in] */ const MPC::wstring& szStr , /*[out]*/ DWORD& dwRes ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertSizeUnit" );
MPC::string::size_type iUnit = 0; int nMult = 1;
// CODEWORK: no proper format checking...
do { if((iUnit = szStr.find( L"KB" )) != MPC::string::npos) { nMult = 1024; break; } if((iUnit = szStr.find( L"MB" )) != MPC::string::npos) { nMult = 1024*1024; break; }
} while(0);
dwRes = nMult * _wtoi( szStr.c_str() );
__MPC_FUNC_EXIT(S_OK); }
HRESULT MPC::ConvertTimeUnit( /*[in] */ const MPC::wstring& szStr , /*[out]*/ DWORD& dwRes ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertTimeUnit" );
MPC::string::size_type iUnit = 0; int nMult = 1;
// CODEWORK: no proper format checking...
do { if((iUnit = szStr.find( L"m" )) != MPC::string::npos) { nMult = 60; break; } if((iUnit = szStr.find( L"h" )) != MPC::string::npos) { nMult = 60*60; break; } if((iUnit = szStr.find( L"d" )) != MPC::string::npos) { nMult = 24*60*60; break; }
} while(0);
dwRes = nMult * _wtoi( szStr.c_str() );
__MPC_FUNC_EXIT(S_OK); }
////////////////////////////////////////
HRESULT MPC::ConvertDateToString( /*[in] */ DATE dDate , /*[out]*/ MPC::wstring& szDate , /*[in] */ bool fGMT , /*[in] */ bool fCIM , /*[in] */ LCID lcid ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertDateToString" );
HRESULT hr; double dTimeZone;
if(fGMT) { TIME_ZONE_INFORMATION tzi;
if(::GetTimeZoneInformation( &tzi ) == TIME_ZONE_ID_DAYLIGHT) { tzi.Bias += tzi.DaylightBias; }
dTimeZone = (DATE)tzi.Bias / (24 * 60); // Convert BIAS from minutes to days.
} else { dTimeZone = 0.0; }
dDate += dTimeZone;
if(fCIM) { SYSTEMTIME st; WCHAR rgBuf[256]; char cTimeZone = (dTimeZone > 0) ? '+' : '-'; int iTimeZone = (int)abs(dTimeZone ) * 24 * 60;
::VariantTimeToSystemTime( dDate, &st );
// supposedly the CIM format for dates is the following (grabbed from
// http://wmig/wbem/docs/cimdoc20.doc)
// yyyymmddhhmmss.mmmmmmsutc
// where
// yyyy is a 4 digit year
// mm is the month
// dd is the day
// hh is the hour (24-hour clock)
// mm is the minute
// ss is the second
// mmmmmm is the number of microseconds
// s is a "+" or "-", indicating the sign of the UTC (Universal
// Coordinated Time; for all intents and purposes the same as Greenwich
// Mean Time) correction field, or a ":". In this case, the value is
// interpreted as a time interval, and yyyymm are interpreted as days.
// utc is the offset from UTC in minutes (using the sign indicated by s)
// It is ignored for a time interval.
//
// For example, Monday, May 25, 1998, at 1:30:15 PM EST would be
// represented as 19980525133015.000000-300
StringCchPrintfW( rgBuf, ARRAYSIZE(rgBuf), L"%04d%02d%02d%02d%02d%02d.%06d%c%03d", st.wYear , st.wMonth , st.wDay , st.wHour , st.wMinute , st.wSecond , st.wMilliseconds * 1000, cTimeZone , iTimeZone );
szDate = rgBuf; } else { CComVariant vValue;
switch(lcid) { case 0: lcid = ::GetUserDefaultLCID(); break; case -1: lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT ); break; }
vValue = dDate; vValue.vt = VT_DATE; // The assignment is not enough to set the DATE type.
__MPC_EXIT_IF_METHOD_FAILS(hr, ::VariantChangeTypeEx( &vValue, &vValue, lcid, 0, VT_BSTR )); szDate = SAFEBSTR( vValue.bstrVal ); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::ConvertStringToDate( /*[in] */ const MPC::wstring& szDate , /*[out]*/ DATE& dDate , /*[in] */ bool fGMT , /*[in] */ bool fCIM , /*[in] */ LCID lcid ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertStringToDate" );
HRESULT hr; double dTimeZone;
if(fGMT) { TIME_ZONE_INFORMATION tzi;
if(::GetTimeZoneInformation( &tzi ) == TIME_ZONE_ID_DAYLIGHT) { tzi.Bias += tzi.DaylightBias; }
dTimeZone = (DATE)tzi.Bias / (24 * 60); // Convert BIAS from minutes to days.
} else { dTimeZone = 0.0; }
if(fCIM) { SYSTEMTIME st; int iYear; int iMonth; int iDay; int iHour; int iMinute; int iSecond; int iMicroseconds; wchar_t cTimezone; int iTimezone;
if(swscanf( szDate.c_str(), L"%04d%02d%02d%02d%02d%02d.%06d%c%03d", &iYear , &iMonth , &iDay , &iHour , &iMinute , &iSecond , &iMicroseconds , &cTimezone , &iTimezone ) != 9) { __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL); }
st.wYear = (WORD)(iYear ); st.wMonth = (WORD)(iMonth ); st.wDay = (WORD)(iDay ); st.wHour = (WORD)(iHour ); st.wMinute = (WORD)(iMinute ); st.wSecond = (WORD)(iSecond ); st.wMilliseconds = (WORD)(iMicroseconds / 1000);
::SystemTimeToVariantTime( &st, &dDate ); } else { CComVariant vValue = szDate.c_str();
switch(lcid) { case 0: lcid = ::GetUserDefaultLCID(); break; case -1: lcid = MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), SORT_DEFAULT ); break; }
__MPC_EXIT_IF_METHOD_FAILS(hr, ::VariantChangeTypeEx( &vValue, &vValue, lcid, 0, VT_DATE )); dDate = vValue.date; }
dDate -= dTimeZone; hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT MPC::ConvertStringToHex( /*[in] */ const CComBSTR& bstrText , /*[out]*/ CComBSTR& bstrHex ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertStringToHex" );
HRESULT hr; int iLen = bstrText.Length();
if(iLen) { BSTR bstrNew; LPCWSTR szIn; LPWSTR szOut;
__MPC_EXIT_IF_ALLOC_FAILS(hr, bstrNew, ::SysAllocStringLen( NULL, iLen*4 )); bstrHex.Attach( bstrNew );
szIn = bstrText; szOut = bstrHex;
while(iLen > 0) { WCHAR c = szIn[0];
szOut[0] = NumToHex( c >> 12 ); szOut[1] = NumToHex( c >> 8 ); szOut[2] = NumToHex( c >> 4 ); szOut[3] = NumToHex( c );
iLen -= 1; szIn += 1; szOut += 4; } } else { bstrHex.Empty(); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::ConvertHexToString( /*[in] */ const CComBSTR& bstrHex , /*[out]*/ CComBSTR& bstrText ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertHexToString" );
HRESULT hr; int iLen = bstrHex.Length();
if(iLen) { BSTR bstrNew; LPCWSTR szIn; LPWSTR szOut;
iLen /= 4;
__MPC_EXIT_IF_ALLOC_FAILS(hr, bstrNew, ::SysAllocStringLen( NULL, iLen )); bstrText.Attach( bstrNew );
szIn = bstrHex; szOut = bstrText;
while(iLen > 0) { szOut[0] = (HexToNum( szIn[0] ) << 12) | (HexToNum( szIn[1] ) << 8) | (HexToNum( szIn[2] ) << 4) | HexToNum( szIn[3] );
iLen -= 1; szIn += 4; szOut += 1; } } else { bstrText.Empty(); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT MPC::ConvertHGlobalToHex( /*[in]*/ HGLOBAL hg , /*[out]*/ CComBSTR& bstrHex , /*[in ]*/ bool fNullAllowed , /*[in ]*/ DWORD* pdwCount /* = NULL */ ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertHGlobalToHex" );
HRESULT hr; int iLen = hg ? (pdwCount ? (int)*pdwCount : ::GlobalSize( hg )) : 0;
if(iLen) { BSTR bstrNew; BYTE* pIn; LPWSTR szOut;
__MPC_EXIT_IF_ALLOC_FAILS(hr, bstrNew, ::SysAllocStringLen( NULL, iLen*2 )); bstrHex.Attach( bstrNew );
pIn = (BYTE*)::GlobalLock( hg ); szOut = bstrHex;
while(iLen > 0) { BYTE c = pIn[0];
szOut[0] = NumToHex( c >> 4 ); szOut[1] = NumToHex( c );
iLen -= 1; pIn += 1; szOut += 2; }
::GlobalUnlock( hg ); } else { bstrHex.Empty();
if(fNullAllowed == false) __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::ConvertHexToHGlobal( /*[in] */ const CComBSTR& bstrText , /*[out]*/ HGLOBAL& hg , /*[in ]*/ bool fNullAllowed ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertHexToHGlobal" );
HRESULT hr; int iLen = bstrText.Length();
if(iLen) { LPCWSTR szIn; BYTE* pOut;
iLen /= 2;
__MPC_EXIT_IF_ALLOC_FAILS(hr, hg, ::GlobalAlloc( GMEM_FIXED, iLen ));
szIn = bstrText; pOut = (BYTE*)hg;
while(iLen > 0) { pOut[0] = (HexToNum( szIn[0] ) << 4) | HexToNum( szIn[1] );
iLen -= 1; szIn += 2; pOut += 1; } } else { hg = NULL;
if(fNullAllowed == false) __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT MPC::ConvertBufferToVariant( /*[in] */ const BYTE* pBuf , /*[in] */ DWORD dwLen , /*[out]*/ CComVariant& v ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertBufferToVariant" );
HRESULT hr;
v.Clear();
if(pBuf && dwLen) { BYTE* rgArrayData;
v.vt = VT_ARRAY | VT_UI1;
__MPC_EXIT_IF_ALLOC_FAILS(hr, v.parray, ::SafeArrayCreateVector( VT_UI1, 0, dwLen ));
__MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v.parray, (LPVOID*)&rgArrayData ));
::CopyMemory( rgArrayData, pBuf, dwLen );
::SafeArrayUnaccessData( v.parray ); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::ConvertVariantToBuffer( /*[in] */ const VARIANT* v , /*[out]*/ BYTE*& pBuf , /*[out]*/ DWORD& dwLen ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertVariantToBuffer" );
HRESULT hr; BYTE* pSrc;
if(pBuf) delete [] pBuf;
pBuf = NULL; dwLen = 0;
switch(v->vt) { case VT_ARRAY | VT_UI1: { long lBound; ::SafeArrayGetLBound( v->parray, 1, &lBound ); long uBound; ::SafeArrayGetUBound( v->parray, 1, &uBound );
__MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v->parray, (LPVOID*)&pSrc ));
dwLen = uBound - lBound + 1; } break;
case VT_I1: case VT_UI1: pSrc = (BYTE*)&v->bVal ; dwLen = 1; break; case VT_I2: case VT_UI2: pSrc = (BYTE*)&v->iVal ; dwLen = 2; break; case VT_I4: case VT_UI4: case VT_R4: pSrc = (BYTE*)&v->lVal ; dwLen = 4; break; case VT_I8: case VT_UI8: case VT_R8: pSrc = (BYTE*)&v->llVal; dwLen = 8; break;
default: __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
if(dwLen) { __MPC_EXIT_IF_ALLOC_FAILS(hr, pBuf, new BYTE[dwLen]);
::CopyMemory( pBuf, pSrc, dwLen ); }
if(v->vt == (VT_ARRAY | VT_UI1)) { ::SafeArrayUnaccessData( v->parray ); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////
HRESULT MPC::ConvertIStreamToVariant( /*[in]*/ IStream* stream, /*[out]*/ CComVariant& v ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertIStreamToVariant" );
HRESULT hr; CComPtr<IStream> stream2; STATSTG stg; ::ZeroMemory( &stg, sizeof(stg) ); BYTE* pBuf = NULL; DWORD dwLen; ULONG lRead;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(stream); __MPC_PARAMCHECK_END();
v.Clear();
//
// If Stat fails, it can be that the size is unknown, so let's make a copy to another stream and retry.
//
if(FAILED(stream->Stat( &stg, STATFLAG_NONAME ))) {
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CreateStreamOnHGlobal( NULL, TRUE, &stream2 ));
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::BaseStream::TransferData( stream, stream2 ));
stream = stream2; }
//
// Rewind to the beginning.
//
{ LARGE_INTEGER li = { 0, 0 };
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->Seek( li, STREAM_SEEK_SET, NULL )); }
//
// Get the size of the stream.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->Stat( &stg, STATFLAG_NONAME ));
//
// Sorry, we don't handle streams longer than 4GB!!
//
if(stg.cbSize.u.HighPart) { __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); }
//
// Allocate buffer for the whole stream.
//
dwLen = stg.cbSize.u.LowPart; __MPC_EXIT_IF_ALLOC_FAILS(hr, pBuf, new BYTE[dwLen]);
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->Read( pBuf, dwLen, &lRead )); if(dwLen != lRead) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_HANDLE_EOF); }
__MPC_EXIT_IF_METHOD_FAILS(hr, ConvertBufferToVariant( pBuf, dwLen, v ));
hr = S_OK;
__MPC_FUNC_CLEANUP;
if(pBuf) delete [] pBuf;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::ConvertVariantToIStream( /*[in ]*/ const VARIANT* v , /*[out]*/ IStream* *pStream ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertVariantToBuffer" );
HRESULT hr; CComPtr<IStream> stream; BYTE* pBuf = NULL; DWORD dwLen; ULONG lWritten;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(v); __MPC_PARAMCHECK_POINTER_AND_SET(pStream,NULL); __MPC_PARAMCHECK_END();
__MPC_EXIT_IF_METHOD_FAILS(hr, ConvertVariantToBuffer( v, pBuf, dwLen ));
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CreateStreamOnHGlobal( NULL, TRUE, &stream ));
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->Write( pBuf, dwLen, &lWritten )); if(dwLen != lWritten) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_HANDLE_DISK_FULL ); }
//
// Rewind to the beginning.
//
{ LARGE_INTEGER li = { 0, 0 };
__MPC_EXIT_IF_METHOD_FAILS(hr, stream->Seek( li, STREAM_SEEK_SET, NULL )); }
*pStream = stream.Detach(); hr = S_OK;
__MPC_FUNC_CLEANUP;
if(pBuf) delete [] pBuf;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
HRESULT MPC::ConvertListToSafeArray( /*[in]*/ const MPC::WStringList& lst, /*[out]*/ VARIANT& v, /*[in]*/ VARTYPE vt ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertListToSafeArray" );
HRESULT hr; LPVOID pData; MPC::WStringIterConst it;
__MPC_EXIT_IF_METHOD_FAILS(hr, ::VariantClear( &v ));
if(vt != VT_VARIANT && vt != VT_BSTR ) { __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
v.vt = VT_ARRAY | vt; __MPC_EXIT_IF_ALLOC_FAILS(hr, v.parray, ::SafeArrayCreateVector( vt, 0, lst.size() ));
__MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v.parray, &pData ));
hr = S_OK;
{ BSTR* rgArrayData1 = (BSTR *)pData; VARIANT* rgArrayData2 = (VARIANT*)pData;
for(it = lst.begin(); it != lst.end(); it++) { BSTR bstr;
if((bstr = ::SysAllocString( it->c_str() )) == NULL) { hr = E_OUTOFMEMORY; break; }
if(vt == VT_BSTR) { *rgArrayData1++ = bstr; } else { rgArrayData2->vt = VT_BSTR; rgArrayData2->bstrVal = bstr; rgArrayData2++; } } }
::SafeArrayUnaccessData( v.parray );
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::ConvertSafeArrayToList( /*[in]*/ const VARIANT& v, /*[out]*/ MPC::WStringList& lst ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertSafeArrayToList" );
HRESULT hr; LPVOID pData; long lBound; long uBound; long l;
if(v.vt != (VT_ARRAY | VT_BSTR ) && v.vt != (VT_ARRAY | VT_VARIANT) ) { __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
::SafeArrayGetLBound( v.parray, 1, &lBound ); ::SafeArrayGetUBound( v.parray, 1, &uBound );
__MPC_EXIT_IF_METHOD_FAILS(hr, ::SafeArrayAccessData( v.parray, &pData ));
{ BSTR* rgArrayData1 = (BSTR *)pData; VARIANT* rgArrayData2 = (VARIANT*)pData;
for(l=lBound; l<=uBound; l++) { BSTR bstr = NULL; CComVariant v2;
if(v.vt == (VT_ARRAY | VT_BSTR)) { bstr = *rgArrayData1++; } else { v2 = *rgArrayData2++;
if(SUCCEEDED(v2.ChangeType( VT_BSTR ))) { bstr = v2.bstrVal; } }
lst.push_back( SAFEBSTR( bstr ) ); } }
::SafeArrayUnaccessData( v.parray );
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
static void Parse_SkipWhite( WCHAR*& szStr ) { while(iswspace( szStr[0] )) szStr++; }
static void Parse_GetQuoted( WCHAR*& szSrc , WCHAR* szDst , WCHAR quote , bool fBackslashForEscape ) { WCHAR c;
while((c = *++szSrc)) { if(c == quote) { szSrc++; break; }
if(fBackslashForEscape && c == '\\' && szSrc[1]) c = *++szSrc;
*szDst++ = c; }
*szDst = 0; }
static void Parse_GetNonBlank( WCHAR*& szSrc , WCHAR* szDst ) { WCHAR c;
szSrc--;
while((c = *++szSrc)) { if(iswspace( c )) break;
*szDst++ = c; }
*szDst = 0; }
HRESULT MPC::CommandLine_Parse( /*[out]*/ int& argc , /*[out]*/ LPCWSTR*& argv , /*[in] */ LPWSTR lpCmdLine , /*[in] */ bool fBackslashForEscape ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::CommandLine_Parse" );
HRESULT hr; LPWSTR szArgument = NULL; int iPass;
argc = 0; argv = NULL;
//
// If no command line is supplied, use the one from the system.
//
if(lpCmdLine == NULL) { lpCmdLine = ::GetCommandLineW(); }
//
// Nothing to parse, exit...
//
if(lpCmdLine == NULL) { __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); }
//
// Allocate a temporary buffer.
//
__MPC_EXIT_IF_ALLOC_FAILS(hr, szArgument, new WCHAR[wcslen( lpCmdLine ) + 1]);
//
// Two passes, one to count the arguments, the other to allocate them.
//
for(iPass=0; iPass < 2; iPass++) { LPWSTR szSrc = lpCmdLine; int i = 0;
Parse_SkipWhite( szSrc ); while(szSrc[0]) { if(szSrc[0] == '"' || szSrc[0] == '\'' ) { Parse_GetQuoted( szSrc, szArgument, szSrc[0], fBackslashForEscape ); } else { Parse_GetNonBlank( szSrc, szArgument ); }
if(argv) { LPWSTR szNewParam;
__MPC_EXIT_IF_ALLOC_FAILS(hr, szNewParam, _wcsdup( szArgument ));
argv[i] = szNewParam; }
i++;
Parse_SkipWhite( szSrc ); }
if(iPass == 0) { argc = i;
__MPC_EXIT_IF_ALLOC_FAILS(hr, argv, new LPCWSTR[argc]); for(i=0; i<argc; i++) { argv[i] = NULL; } } }
hr = S_OK;
__MPC_FUNC_CLEANUP;
if(FAILED(hr)) { CommandLine_Free( argc, argv ); }
delete [] szArgument;
__MPC_FUNC_EXIT(hr); }
void MPC::CommandLine_Free( /*[in ]*/ int& argc , /*[in ]*/ LPCWSTR*& argv ) { if(argv) { for(int i=0; i<argc; i++) { free( (void*)argv[i] ); }
delete [] argv;
argv = NULL; }
argc = 0; }
////////////////////////////////////////////////////////////////////////////////
HRESULT MPC::ConvertStringToBitField( /*[in] */ LPCWSTR szText , /*[out]*/ DWORD& dwBitField , /*[in] */ const StringToBitField* pLookup , /*[in] */ bool fUseTilde ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertStringToBitField" );
HRESULT hr; DWORD dwVal = 0;
if(szText && pLookup) { std::vector<MPC::wstring> vec; std::vector<MPC::wstring>::iterator it;
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SplitAtDelimiter( vec, szText, L" ,", false, true ));
for(it=vec.begin(); it!=vec.end(); it++) { LPCWSTR szToken = it->c_str(); int iNum = 0;
if(!_wcsnicmp( L"0x", szToken, 2 ) && swscanf( &szToken[2], L"%x", &iNum ) == 1) { dwVal |= iNum; } else { const StringToBitField* pPtr = pLookup; bool fReverse = false;
if(fUseTilde && szToken[0] == '~') { fReverse = true; szToken++; }
while(pPtr->szName) { if(!_wcsicmp( pPtr->szName, szToken )) { DWORD dwMask = pPtr->dwMask; DWORD dwSet = pPtr->dwSet; DWORD dwReset = pPtr->dwReset; DWORD dwSelected = dwVal & dwMask; DWORD dwRemainder = dwVal & (~ dwMask);
if(fReverse) { dwSelected &= ~dwSet; } else { dwSelected &= ~dwReset; dwSelected |= dwSet; }
dwVal = (dwSelected & dwMask) | dwRemainder; break; }
pPtr++; } } } }
hr = S_OK;
__MPC_FUNC_CLEANUP;
dwBitField = dwVal;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::ConvertBitFieldToString( /*[in] */ DWORD dwBitField , /*[out]*/ MPC::wstring& szText , /*[in] */ const StringToBitField* pLookup ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ConvertBitFieldToString" );
HRESULT hr; DWORD dwVal = 0;
szText = L"";
if(pLookup) { while(pLookup->szName) { DWORD dwMask = pLookup->dwMask; DWORD dwSet = pLookup->dwSet; DWORD dwReset = pLookup->dwReset;
if((dwBitField & (dwMask & dwReset)) == dwSet) { if(szText.size()) szText += L" "; szText += pLookup->szName;
dwBitField = (dwBitField & ~dwMask) | ((dwBitField & ~dwReset) & dwMask); }
pLookup++; } }
if(dwBitField) { WCHAR rgBuf[64];
StringCchPrintfW( rgBuf, ARRAYSIZE(rgBuf), L"0x%x", dwBitField );
if(szText.size()) szText += L" "; szText += rgBuf; }
hr = S_OK;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
//
// This algorithm is not a very efficient one, O(N * M), but it's ok as long as "delims" is short (M small).
//
template <class E> static HRESULT InnerSplitAtDelimiter( std::vector< std::basic_stringNR<E> >& vec , const E* str , const E* delims , bool fDelimIsAString , bool fSkipAdjacentDelims ) { std::basic_stringNR<E> szText ( str ); std::basic_stringNR<E> szDelims( delims ); std::basic_stringNR<E>::size_type iPos = 0; std::basic_stringNR<E>::size_type iStart = 0; std::basic_stringNR<E>::size_type iDelimsLen = szDelims.length(); bool fSkip = false;
vec.clear();
if(fDelimIsAString) { while(1) { iPos = szText.find( szDelims, iStart ); if(iPos == std::basic_stringNR<E>::npos) { vec.push_back( &szText[iStart] ); break; } else { if(fSkip && iPos == iStart) { ; } else { fSkip = fSkipAdjacentDelims;
vec.push_back( std::basic_stringNR<E>( &szText[iStart], &szText[iPos] ) ); }
iStart = iPos + iDelimsLen; } } } else { std::basic_stringNR<E>::size_type iTextEnd = szText.length();
while(iPos < iTextEnd) { if(szDelims.find( szText[iPos] ) != std::basic_stringNR<E>::npos) { if(fSkip == false) { fSkip = fSkipAdjacentDelims;
vec.push_back( std::basic_stringNR<E>( &szText[iStart], &szText[iPos] ) ); }
iStart = iPos + 1; } else { if(fSkip) { iStart = iPos;
fSkip = false; } }
iPos++; }
vec.push_back( std::basic_stringNR<E>( &szText[iStart] ) ); }
//
// In case of single string, don't return anything.
//
if(vec.size() == 1 && vec[0].empty()) { vec.clear(); }
return S_OK; }
HRESULT MPC::SplitAtDelimiter( StringVector& vec , LPCSTR str , LPCSTR delims , bool fDelimIsAString , bool fSkipAdjacentDelims ) { return InnerSplitAtDelimiter( vec, str, delims, fDelimIsAString, fSkipAdjacentDelims ); }
HRESULT MPC::SplitAtDelimiter( WStringVector& vec , LPCWSTR str , LPCWSTR delims , bool fDelimIsAString , bool fSkipAdjacentDelims ) { return InnerSplitAtDelimiter( vec, str, delims, fDelimIsAString, fSkipAdjacentDelims ); }
////////////////////////////////////////
template <class E> static HRESULT InnerJoinWithDelimiter( const std::vector< std::basic_stringNR<E> >& vec , std::basic_stringNR<E>& str , const E* delims ) { int i;
for(i=0; i<vec.size(); i++) { if(i) str += delims;
str += vec[i]; }
return S_OK; }
HRESULT MPC::JoinWithDelimiter( const StringVector& vec , MPC::string& str , LPCSTR delims ) { return InnerJoinWithDelimiter( vec, str, delims ); }
HRESULT MPC::JoinWithDelimiter( const WStringVector& vec , MPC::wstring& str , LPCWSTR delims ) { return InnerJoinWithDelimiter( vec, str, delims ); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// Function Name : MPC::MakeDir
//
// Parameters : MPC::wstring& szStr : path to a directory or a file.
//
// Return : HRESULT
//
// Synopsis : Given a path in the form '[<dir>\]*\[<file>]',
// it creates all the needed directories.
//
/////////////////////////////////////////////////////////////////////////////
HRESULT MPC::MakeDir( /*[in]*/ const MPC::wstring& strPath, /*[in]*/ bool fCreateParent ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::MakeDir");
HRESULT hr; MPC::wstring szParent; BOOL fRes; DWORD dwRes;
if(fCreateParent) { MPC::wstring::size_type iPos = strPath.rfind( '\\' );
if(iPos == strPath.npos) { __MPC_SET_ERROR_AND_EXIT(hr, S_OK); }
szParent = strPath.substr( 0, iPos ); } else { szParent = strPath; }
//
// Try to create parent directory...
//
fRes = ::CreateDirectoryW( szParent.c_str(), NULL ); dwRes = ::GetLastError();
if(fRes == TRUE || dwRes == ERROR_ALREADY_EXISTS) { //
// Success, exit.
//
__MPC_SET_ERROR_AND_EXIT(hr, S_OK); }
//
// If the error is not PATH_NOT_FOUND, exit.
//
if(dwRes != ERROR_PATH_NOT_FOUND) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, dwRes ); }
//
// Recursively build the parent directories.
//
__MPC_EXIT_IF_METHOD_FAILS(hr, MakeDir( szParent, true ) );
//
// Try again to create parent directory.
//
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CreateDirectoryW( szParent.c_str(), NULL ));
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
//
// Function Name : MPC::GetDiskSpace
//
// Parameters : MPC::wstring& szFile : path to a directory or a file.
// ULARGE_INTEGER& liFree : number of bytes free on that disk.
// ULARGE_INTEGER& liTotal : total number of bytes on that disk.
//
// Return : HRESULT
//
// Synopsis : Given a path, it calculates the total and available disk space.
//
/////////////////////////////////////////////////////////////////////////////
HRESULT MPC::GetDiskSpace( /*[in]*/ const MPC::wstring& szFile , /*[out]*/ ULARGE_INTEGER& liFree , /*[out]*/ ULARGE_INTEGER& liTotal ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::GetDiskSpace");
HRESULT hr; MPC::wstring szParent; MPC::wstring::size_type iPos; DWORD dwSectorsPerCluster; DWORD dwBytesPerSector; DWORD dwNumberOfFreeClusters; DWORD dwTotalNumberOfClusters;
//
// Initialize the Parent variable.
//
szParent = szFile;
//
// Normal <DRIVE>:\... format?
//
iPos = szFile.find( L":\\" ); if(iPos != szFile.npos) { szParent = szFile.substr( 0, iPos+2 ); } else { //
// If the path a UNC?
//
iPos = szFile.find( L"\\\\" ); if(iPos != szFile.npos && iPos == 0) { //
// Find slash after server name.
//
iPos = szFile.find( L"\\", 2 ); if(iPos != szFile.npos) { //
// Is a slash present after the share name?
//
iPos = szFile.find( L"\\", iPos+1 ); if(iPos != szFile.npos) { szParent = szFile.substr( 0, iPos+1 ); } else { szParent = szFile; szParent.append( L"\\" ); // Share names must end with a trailing slash.
} } } }
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::GetDiskFreeSpaceW( szParent.c_str() , &dwSectorsPerCluster , &dwBytesPerSector , &dwNumberOfFreeClusters , &dwTotalNumberOfClusters ));
liFree .QuadPart = (ULONGLONG)(dwBytesPerSector * dwSectorsPerCluster) * (ULONGLONG)dwNumberOfFreeClusters; liTotal.QuadPart = (ULONGLONG)(dwBytesPerSector * dwSectorsPerCluster) * (ULONGLONG)dwTotalNumberOfClusters;
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
////////////////////////////////////////////////////////////////////////////////
HRESULT MPC::FailOnLowDiskSpace( /*[in]*/ LPCWSTR szFile, /*[in]*/ DWORD dwLowLevel ) { MPC::wstring szExpandedFile( szFile ); MPC::SubstituteEnvVariables( szExpandedFile ); ULARGE_INTEGER liFree; ULARGE_INTEGER liTotal;
if(SUCCEEDED(MPC::GetDiskSpace( szExpandedFile, liFree, liTotal ))) { if(liFree.HighPart > 0 || liFree.LowPart > dwLowLevel ) { return S_OK; } }
return HRESULT_FROM_WIN32(ERROR_DISK_FULL); }
HRESULT MPC::FailOnLowMemory( /*[in]*/ DWORD dwLowLevel ) { MEMORYSTATUSEX ms;
::ZeroMemory( &ms, sizeof(ms) ); ms.dwLength = sizeof(ms);
if(::GlobalMemoryStatusEx( &ms )) { if(ms.ullAvailVirtual > dwLowLevel) { return S_OK; } }
return E_OUTOFMEMORY; }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT MPC::ExecuteCommand( /*[in]*/ const MPC::wstring& szCommandLine ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::ExecuteCommand" );
HRESULT hr; PROCESS_INFORMATION piProcessInformation; STARTUPINFOW siStartupInfo; DWORD dwExitCode;
::ZeroMemory( (PVOID)&piProcessInformation, sizeof( piProcessInformation ) ); ::ZeroMemory( (PVOID)&siStartupInfo , sizeof( siStartupInfo ) ); siStartupInfo.cb = sizeof( siStartupInfo );
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::CreateProcessW( NULL, (LPWSTR)szCommandLine.c_str(), NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &siStartupInfo, &piProcessInformation ));
MPC::WaitForSingleObject( piProcessInformation.hProcess, INFINITE );
__MPC_EXIT_IF_CALL_RETURNS_FALSE(hr, ::GetExitCodeProcess( piProcessInformation.hProcess, &dwExitCode ));
if(dwExitCode != 0) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, dwExitCode ); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
if(piProcessInformation.hProcess) ::CloseHandle( piProcessInformation.hProcess ); if(piProcessInformation.hThread ) ::CloseHandle( piProcessInformation.hThread );
__MPC_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT MPC::GetBSTR( /*[in] */ LPCWSTR bstr , /*[out]*/ BSTR *pVal , /*[in] */ bool fNullOk ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::GetBSTR" );
HRESULT hr;
__MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pVal,NULL); if(fNullOk == false) __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstr); __MPC_PARAMCHECK_END();
*pVal = ::SysAllocString( bstr ); if(*pVal == NULL && bstr) { __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::PutBSTR( /*[out]*/ CComBSTR& bstr , /*[in ]*/ LPCWSTR newVal , /*[in] */ bool fNullOk ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::PutBSTR" );
HRESULT hr;
__MPC_PARAMCHECK_BEGIN(hr) if(fNullOk == false) __MPC_PARAMCHECK_STRING_NOT_EMPTY(newVal); __MPC_PARAMCHECK_END();
bstr = newVal; if(!bstr && newVal != NULL) { __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
HRESULT MPC::PutBSTR( /*[out]*/ CComBSTR& bstr , /*[in ]*/ VARIANT* newVal , /*[in] */ bool fNullOk ) { __MPC_FUNC_ENTRY( COMMONID, "MPC::PutBSTR" );
HRESULT hr; CComVariant v; bool fEmpty;
if(newVal) { if(newVal->vt != VT_BSTR) { v.ChangeType( VT_BSTR, newVal );
newVal = &v; } }
if(newVal == NULL || // Null pointer.
newVal->vt != VT_BSTR || // Not a string.
newVal->bstrVal == NULL || // Missing string.
newVal->bstrVal[0] == 0 ) // Empty string.
{ if(fNullOk == false) { __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); }
fEmpty = true; } else { fEmpty = false; }
if(fEmpty) { bstr.Empty(); } else { bstr = newVal->bstrVal; if(!bstr) { __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY); } }
hr = S_OK;
__MPC_FUNC_CLEANUP;
__MPC_FUNC_EXIT(hr); }
/////////////////////////////////////////////////////////////////////////////
bool MPC::NocaseLess::operator()( /*[in]*/ const MPC::string& szX, /*[in]*/ const MPC::string& szY ) const { return _stricmp( szX.c_str(), szY.c_str() ) < 0; }
bool MPC::NocaseLess::operator()( /*[in]*/ const MPC::wstring& szX, /*[in]*/ const MPC::wstring& szY ) const { return _wcsicmp( szX.c_str(), szY.c_str() ) < 0; }
bool MPC::NocaseLess::operator()( /*[in]*/ const BSTR bstrX, /*[in]*/ const BSTR bstrY ) const { return MPC::StrICmp( bstrX, bstrY ) < 0; }
////////////////////////////////////////
bool MPC::NocaseCompare::operator()( /*[in]*/ const MPC::string& szX, /*[in]*/ const MPC::string& szY ) const { return _stricmp( szX.c_str(), szY.c_str() ) == 0; }
bool MPC::NocaseCompare::operator()( /*[in]*/ const MPC::wstring& szX, /*[in]*/ const MPC::wstring& szY ) const { return _wcsicmp( szX.c_str(), szY.c_str() ) == 0; }
bool MPC::NocaseCompare::operator()( /*[in]*/ const BSTR bstrX, /*[in]*/ const BSTR bstrY ) const { return MPC::StrICmp( bstrX, bstrY ) == 0; }
|