aspnetcore/src/IISLib/stringu.cpp

1272 lines
25 KiB
C++

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
#pragma warning (disable : 4267)
#include "precomp.h"
STRU::STRU(
VOID
) : m_cchLen( 0 )
{
*(QueryStr()) = L'\0';
}
STRU::STRU(
__inout_ecount(cchInit) WCHAR* pbInit,
__in DWORD cchInit
) : m_Buff( pbInit, cchInit * sizeof( WCHAR ) ),
m_cchLen( 0 )
/*++
Description:
Used by STACK_STRU. Initially populates underlying buffer with pbInit.
pbInit is not freed.
Arguments:
pbInit - initial memory to use
cchInit - count, in characters, of pbInit
Returns:
None.
--*/
{
_ASSERTE( cchInit <= (MAXDWORD / sizeof( WCHAR )) );
_ASSERTE( NULL != pbInit );
_ASSERTE(cchInit > 0 );
_ASSERTE(pbInit[0] == L'\0');
}
BOOL
STRU::IsEmpty(
VOID
) const
{
return ( m_cchLen == 0 );
}
DWORD
STRU::QueryCB(
VOID
) const
//
// Returns the number of bytes in the string excluding the terminating NULL
//
{
return m_cchLen * sizeof( WCHAR );
}
DWORD
STRU::QueryCCH(
VOID
) const
//
// Returns the number of characters in the string excluding the terminating NULL
//
{
return m_cchLen;
}
DWORD
STRU::QuerySizeCCH(
VOID
) const
//
// Returns size of the underlying storage buffer, in characters
//
{
return m_Buff.QuerySize() / sizeof( WCHAR );
}
__nullterminated
__ecount(this->m_cchLen)
WCHAR*
STRU::QueryStr(
VOID
) const
//
// Return the string buffer
//
{
return m_Buff.QueryPtr();
}
VOID
STRU::Reset(
VOID
)
//
// Resets the internal string to be NULL string. Buffer remains cached.
//
{
_ASSERTE( QueryStr() != NULL );
*(QueryStr()) = L'\0';
m_cchLen = 0;
}
HRESULT
STRU::Resize(
DWORD cchSize
)
{
SIZE_T cbSize = cchSize * sizeof( WCHAR );
if ( cbSize > MAXDWORD )
{
return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
}
if( !m_Buff.Resize( cbSize ) )
{
return E_OUTOFMEMORY;
}
return S_OK;
}
HRESULT
STRU::SyncWithBuffer(
VOID
)
//
// Recalculate the length of the string, etc. because we've modified
// the buffer directly.
//
{
HRESULT hr;
size_t size;
hr = StringCchLengthW( QueryStr(),
QuerySizeCCH(),
&size );
if ( SUCCEEDED( hr ) )
{
m_cchLen = static_cast<DWORD>(size);
}
return hr;
}
HRESULT
STRU::Copy(
__in PCWSTR pszCopy
)
{
HRESULT hr;
size_t cbStr;
hr = StringCchLengthW( pszCopy,
STRSAFE_MAX_CCH,
&cbStr );
if ( FAILED( hr ) )
{
return hr;
}
_ASSERTE( cbStr <= MAXDWORD );
return Copy( pszCopy,
cbStr );
}
HRESULT
STRU::Copy(
__in_ecount(cchLen)
PCWSTR pszCopy,
SIZE_T cchLen
)
//
// Copy the contents of another string to this one
//
{
return AuxAppend( pszCopy,
cchLen * sizeof(WCHAR),
0);
}
HRESULT
STRU::Copy(
__in const STRU * pstrRhs
)
{
_ASSERTE( NULL != pstrRhs );
return Copy( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
}
HRESULT
STRU::Copy(
__in const STRU & str
)
{
return Copy( str.QueryStr(), str.QueryCCH() );
}
HRESULT
STRU::CopyAndExpandEnvironmentStrings(
__in PCWSTR pszSource
)
{
HRESULT hr = S_OK;
DWORD cchDestReqBuff = 0;
Reset();
cchDestReqBuff = ExpandEnvironmentStringsW( pszSource,
QueryStr(),
QuerySizeCCH() );
if ( cchDestReqBuff == 0 )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
else if ( cchDestReqBuff > QuerySizeCCH() )
{
hr = Resize( cchDestReqBuff );
if ( FAILED( hr ) )
{
goto Finished;
}
cchDestReqBuff = ExpandEnvironmentStringsW( pszSource,
QueryStr(),
QuerySizeCCH() );
if ( cchDestReqBuff == 0 || cchDestReqBuff > QuerySizeCCH() )
{
_ASSERTE( FALSE );
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Finished;
}
}
hr = SyncWithBuffer();
if ( FAILED( hr ) )
{
goto Finished;
}
Finished:
return hr;
}
HRESULT
STRU::CopyA(
__in PCSTR pszCopyA
)
{
HRESULT hr;
size_t cbStr;
hr = StringCbLengthA( pszCopyA,
STRSAFE_MAX_CCH,
&cbStr );
if ( FAILED( hr ) )
{
return hr;
}
_ASSERTE( cbStr <= MAXDWORD );
return CopyA( pszCopyA,
cbStr );
}
HRESULT
STRU::CopyA(
__in_bcount(cchLen)
PCSTR pszCopyA,
SIZE_T cchLen,
UINT CodePage /*= CP_UTF8*/
)
{
return AuxAppendA(
pszCopyA,
cchLen,
0,
CodePage
);
}
HRESULT
STRU::Append(
__in PCWSTR pszAppend
)
{
HRESULT hr;
size_t cbStr;
hr = StringCchLengthW( pszAppend,
STRSAFE_MAX_CCH,
&cbStr );
if ( FAILED( hr ) )
{
return hr;
}
_ASSERTE( cbStr <= MAXDWORD );
return Append( pszAppend,
cbStr );
}
HRESULT
STRU::Append(
__in_ecount(cchLen)
PCWSTR pszAppend,
SIZE_T cchLen
)
//
// Append something to the end of the string
//
{
if ( cchLen == 0 )
{
return S_OK;
}
return AuxAppend( pszAppend,
cchLen * sizeof(WCHAR),
QueryCB() );
}
HRESULT
STRU::Append(
__in const STRU * pstrRhs
)
{
_ASSERTE( NULL != pstrRhs );
return Append( pstrRhs->QueryStr(), pstrRhs->QueryCCH() );
}
HRESULT
STRU::Append(
__in const STRU & strRhs
)
{
return Append( strRhs.QueryStr(), strRhs.QueryCCH() );
}
HRESULT
STRU::AppendA(
__in PCSTR pszAppendA
)
{
HRESULT hr;
size_t cbStr;
hr = StringCbLengthA( pszAppendA,
STRSAFE_MAX_CCH,
&cbStr );
if ( FAILED( hr ) )
{
return hr;
}
_ASSERTE( cbStr <= MAXDWORD );
return AppendA( pszAppendA,
cbStr );
}
HRESULT
STRU::AppendA(
__in_bcount(cchLen)
PCSTR pszAppendA,
SIZE_T cchLen,
UINT CodePage /*= CP_UTF8*/
)
{
if ( cchLen == 0 )
{
return S_OK;
}
return AuxAppendA(
pszAppendA,
cchLen,
QueryCB(),
CodePage
);
}
HRESULT
STRU::CopyToBuffer(
__out_bcount(*pcb) WCHAR* pszBuffer,
PDWORD pcb
) const
//
// Makes a copy of the stored string into the given buffer
//
{
_ASSERTE( NULL != pszBuffer );
_ASSERTE( NULL != pcb );
HRESULT hr = S_OK;
DWORD cbNeeded = QueryCB() + sizeof( WCHAR );
if( *pcb < cbNeeded )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto Finished;
}
//
// BUGBUG: StringCchCopy?
//
memcpy( pszBuffer, QueryStr(), cbNeeded );
Finished:
*pcb = cbNeeded;
return hr;
}
HRESULT
STRU::SetLen(
__in DWORD cchLen
)
/*++
*
Routine Description:
Set the length of the string and null terminate, if there
is sufficient buffer already allocated. Will not reallocate.
Arguments:
cchLen - The number of characters in the new string.
Return Value:
HRESULT
--*/
{
if( cchLen >= QuerySizeCCH() )
{
return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
}
*( QueryStr() + cchLen ) = L'\0';
m_cchLen = cchLen;
return S_OK;
}
HRESULT
STRU::SafeSnwprintf(
__in PCWSTR pwszFormatString,
...
)
/*++
Routine Description:
Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars.
Arguments:
pwszFormatString - printf format
... - printf args
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
va_list argsList;
va_start( argsList, pwszFormatString );
hr = SafeVsnwprintf(pwszFormatString, argsList);
va_end( argsList );
return hr;
}
HRESULT
STRU::SafeVsnwprintf(
__in PCWSTR pwszFormatString,
va_list argsList
)
/*++
Routine Description:
Writes to a STRU, growing it as needed. It arbitrarily caps growth at 64k chars.
Arguments:
pwszFormatString - printf format
argsList - printf va_list
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
int cchOutput;
int cchNeeded;
//
// Format the incoming message using vsnprintf()
// so that the overflows are captured
//
cchOutput = _vsnwprintf_s(
QueryStr(),
QuerySizeCCH(),
QuerySizeCCH() - 1,
pwszFormatString,
argsList
);
if( cchOutput == -1 )
{
//
// Couldn't fit this in the original STRU size.
//
cchNeeded = _vscwprintf( pwszFormatString, argsList );
if( cchNeeded > 64 * 1024 )
{
//
// If we're trying to produce a string > 64k chars, then
// there is probably a problem
//
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
goto Finished;
}
//
// _vscprintf doesn't include terminating null character
//
cchNeeded++;
hr = Resize( cchNeeded );
if( FAILED( hr ) )
{
goto Finished;
}
cchOutput = _vsnwprintf_s(
QueryStr(),
QuerySizeCCH(),
QuerySizeCCH() - 1,
pwszFormatString,
argsList
);
if( -1 == cchOutput )
{
//
// This should never happen, cause we should already have correctly sized memory
//
_ASSERTE( FALSE );
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
goto Finished;
}
}
//
// always null terminate at the last WCHAR
//
QueryStr()[ QuerySizeCCH() - 1 ] = L'\0';
//
// we directly touched the buffer - therefore:
//
hr = SyncWithBuffer();
if ( FAILED( hr ) )
{
goto Finished;
}
Finished:
if( FAILED( hr ) )
{
Reset();
}
return hr;
}
HRESULT
STRU::AuxAppend(
__in_ecount(cNumStrings)
PCWSTR const rgpszStrings[],
SIZE_T cNumStrings
)
/*++
Routine Description:
Appends an array of strings of length cNumStrings
Arguments:
rgStrings - The array of strings to be appened
cNumStrings - The count of String
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
size_t cbStringsTotal = sizeof( WCHAR ); // Account for null-terminator
//
// Compute total size of the string.
// Resize internal buffer
// Copy each array element one by one to backing buffer
// Update backing buffer string length
//
for ( SIZE_T i = 0; i < cNumStrings; i++ )
{
_ASSERTE( rgpszStrings[ i ] != NULL );
if ( NULL == rgpszStrings[ i ] )
{
return E_INVALIDARG;
}
size_t cbString = 0;
hr = StringCbLengthW( rgpszStrings[ i ],
STRSAFE_MAX_CCH * sizeof( WCHAR ),
&cbString );
if ( FAILED( hr ) )
{
return hr;
}
cbStringsTotal += cbString;
if ( cbStringsTotal > MAXDWORD )
{
return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
}
}
size_t cbBufSizeRequired = QueryCB() + cbStringsTotal;
if ( cbBufSizeRequired > MAXDWORD )
{
return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
}
if( m_Buff.QuerySize() < cbBufSizeRequired )
{
if( !m_Buff.Resize( cbBufSizeRequired ) )
{
return E_OUTOFMEMORY;
}
}
STRSAFE_LPWSTR pszStringEnd = QueryStr() + QueryCCH();
size_t cchRemaining = QuerySizeCCH() - QueryCCH();
for ( SIZE_T i = 0; i < cNumStrings; i++ )
{
hr = StringCchCopyExW( pszStringEnd, // pszDest
cchRemaining, // cchDest
rgpszStrings[ i ], // pszSrc
&pszStringEnd, // ppszDestEnd
&cchRemaining, // pcchRemaining
0 ); // dwFlags
if ( FAILED( hr ) )
{
_ASSERTE( FALSE );
HRESULT hr2 = SyncWithBuffer();
if ( FAILED( hr2 ) )
{
return hr2;
}
return hr;
}
}
m_cchLen = static_cast< DWORD >( cbBufSizeRequired ) / sizeof( WCHAR ) - 1;
return S_OK;
}
HRESULT
STRU::AuxAppend(
__in_bcount(cbStr)
const WCHAR* pStr,
SIZE_T cbStr,
DWORD cbOffset
)
/*++
Routine Description:
Appends to the string starting at the (byte) offset cbOffset.
Arguments:
pStr - A unicode string to be appended
cbStr - Length, in bytes, of pStr
cbOffset - Offset, in bytes, at which to begin the append
Return Value:
HRESULT
--*/
{
_ASSERTE( NULL != pStr );
_ASSERTE( 0 == cbStr % sizeof( WCHAR ) );
_ASSERTE( cbOffset <= QueryCB() );
_ASSERTE( 0 == cbOffset % sizeof( WCHAR ) );
ULONGLONG cb64NewSize = (ULONGLONG)cbOffset + cbStr + sizeof( WCHAR );
if( cb64NewSize > MAXDWORD )
{
return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
}
if( m_Buff.QuerySize() < cb64NewSize )
{
if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
{
return E_OUTOFMEMORY;
}
}
memcpy( reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset, pStr, cbStr );
m_cchLen = (static_cast<DWORD>(cbStr) + cbOffset) / sizeof(WCHAR);
*( QueryStr() + m_cchLen ) = L'\0';
return S_OK;
}
HRESULT
STRU::AuxAppendA(
__in_bcount(cbStr)
const CHAR* pStr,
SIZE_T cbStr,
DWORD cbOffset,
UINT CodePage
)
/*++
Routine Description:
Convert and append an ANSI string to the string starting at
the (byte) offset cbOffset
Arguments:
pStr - An ANSI string to be appended
cbStr - Length, in bytes, of pStr
cbOffset - Offset, in bytes, at which to begin the append
CodePage - code page to use for conversion
Return Value:
HRESULT
--*/
{
WCHAR* pszBuffer;
DWORD cchBuffer;
DWORD cchCharsCopied = 0;
_ASSERTE( NULL != pStr );
_ASSERTE( cbOffset <= QueryCB() );
_ASSERTE( 0 == cbOffset % sizeof( WCHAR ) );
if ( NULL == pStr )
{
return E_INVALIDARG;
}
if( 0 == cbStr )
{
return S_OK;
}
//
// Only resize when we have to. When we do resize, we tack on
// some extra space to avoid extra reallocations.
//
if( m_Buff.QuerySize() < (ULONGLONG)cbOffset + (cbStr * sizeof( WCHAR )) + sizeof(WCHAR) )
{
ULONGLONG cb64NewSize = (ULONGLONG)( cbOffset + cbStr * sizeof(WCHAR) + sizeof( WCHAR ) );
//
// Check for the arithmetic overflow
//
if( cb64NewSize > MAXDWORD )
{
return HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
}
if( !m_Buff.Resize( static_cast<SIZE_T>(cb64NewSize) ) )
{
return E_OUTOFMEMORY;
}
}
pszBuffer = reinterpret_cast<WCHAR*>(reinterpret_cast<BYTE*>(m_Buff.QueryPtr()) + cbOffset);
cchBuffer = ( m_Buff.QuerySize() - cbOffset - sizeof( WCHAR ) ) / sizeof( WCHAR );
cchCharsCopied = MultiByteToWideChar(
CodePage,
MB_ERR_INVALID_CHARS,
pStr,
static_cast<int>(cbStr),
pszBuffer,
cchBuffer
);
if( 0 == cchCharsCopied )
{
return HRESULT_FROM_WIN32( GetLastError() );
}
//
// set the new length
//
m_cchLen = cchCharsCopied + cbOffset/sizeof(WCHAR);
//
// Must be less than, cause still need to add NULL
//
_ASSERTE( m_cchLen < QuerySizeCCH() );
//
// append NULL character
//
*(QueryStr() + m_cchLen) = L'\0';
return S_OK;
}
/*++
Routine Description:
Removes leading and trailing whitespace
--*/
VOID
STRU::Trim()
{
PWSTR pwszString = QueryStr();
DWORD cchNewLength = m_cchLen;
DWORD cchLeadingWhitespace = 0;
DWORD cchTempLength = 0;
for (LONG ixString = m_cchLen - 1; ixString >= 0; ixString--)
{
if (iswspace(pwszString[ixString]) != 0)
{
pwszString[ixString] = L'\0';
cchNewLength--;
}
else
{
break;
}
}
cchTempLength = cchNewLength;
for (DWORD ixString = 0; ixString < cchTempLength; ixString++)
{
if (iswspace(pwszString[ixString]) != 0)
{
cchLeadingWhitespace++;
cchNewLength--;
}
else
{
break;
}
}
if (cchNewLength == 0)
{
Reset();
}
else if (cchLeadingWhitespace > 0)
{
memmove(pwszString, pwszString + cchLeadingWhitespace, cchNewLength * sizeof(WCHAR));
pwszString[cchNewLength] = L'\0';
}
SyncWithBuffer();
}
/*++
Routine Description:
Compares the string to the provided prefix to check for equality
Arguments:
pwszPrefix - wide char string to compare with
fIgnoreCase - indicates whether the string comparison should be case-sensitive
Return Value:
TRUE if prefix string matches with internal string, FALSE otherwise
--*/
BOOL
STRU::StartsWith(
__in PCWSTR pwszPrefix,
__in bool fIgnoreCase) const
{
HRESULT hr = S_OK;
BOOL fMatch = FALSE;
size_t cchPrefix = 0;
if (pwszPrefix == NULL)
{
goto Finished;
}
hr = StringCchLengthW( pwszPrefix,
STRSAFE_MAX_CCH,
&cchPrefix );
if (FAILED(hr))
{
goto Finished;
}
_ASSERTE( cchPrefix <= MAXDWORD );
if (cchPrefix > m_cchLen)
{
goto Finished;
}
#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
fMatch = ( CSTR_EQUAL == CompareStringOrdinal( QueryStr(),
cchPrefix,
pwszPrefix,
cchPrefix,
fIgnoreCase ) );
#else
if( fIgnoreCase )
{
fMatch = ( 0 == _wcsnicmp( QueryStr(), pwszPrefix, cchPrefix ) );
}
else
{
fMatch = ( 0 == wcsncmp( QueryStr(), pwszPrefix, cchPrefix ) );
}
#endif
Finished:
return fMatch;
}
/*++
Routine Description:
Compares the string to the provided suffix to check for equality
Arguments:
pwszSuffix - wide char string to compare with
fIgnoreCase - indicates whether the string comparison should be case-sensitive
Return Value:
TRUE if suffix string matches with internal string, FALSE otherwise
--*/
BOOL
STRU::EndsWith(
__in PCWSTR pwszSuffix,
__in bool fIgnoreCase) const
{
HRESULT hr = S_OK;
PWSTR pwszString = QueryStr();
BOOL fMatch = FALSE;
size_t cchSuffix = 0;
ptrdiff_t ixOffset = 0;
if (pwszSuffix == NULL)
{
goto Finished;
}
hr = StringCchLengthW( pwszSuffix,
STRSAFE_MAX_CCH,
&cchSuffix );
if (FAILED(hr))
{
goto Finished;
}
_ASSERTE( cchSuffix <= MAXDWORD );
if (cchSuffix > m_cchLen)
{
goto Finished;
}
ixOffset = m_cchLen - cchSuffix;
_ASSERTE(ixOffset >= 0 && ixOffset <= MAXDWORD);
#if defined( NTDDI_VERSION ) && NTDDI_VERSION >= NTDDI_LONGHORN
fMatch = ( CSTR_EQUAL == CompareStringOrdinal( pwszString + ixOffset,
cchSuffix,
pwszSuffix,
cchSuffix,
fIgnoreCase ) );
#else
if( fIgnoreCase )
{
fMatch = ( 0 == _wcsnicmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) );
}
else
{
fMatch = ( 0 == wcsncmp( pwszString + ixOffset, pwszSuffix, cchSuffix ) );
}
#endif
Finished:
return fMatch;
}
/*++
Routine Description:
Searches the string for the first occurrence of the specified character.
Arguments:
charValue - character to find
dwStartIndex - the initial index.
Return Value:
The index for the first character occurence in the string.
-1 if not found.
--*/
INT
STRU::IndexOf(
__in WCHAR charValue,
__in DWORD dwStartIndex
) const
{
INT nIndex = -1;
// Make sure that there are no buffer overruns.
if( dwStartIndex >= QueryCCH() )
{
goto Finished;
}
const WCHAR* pwChar = wcschr( QueryStr() + dwStartIndex, charValue );
// Determine the index if found
if( pwChar )
{
// nIndex will be set to -1 on failure.
(VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
}
Finished:
return nIndex;
}
/*++
Routine Description:
Searches the string for the first occurrence of the specified substring.
Arguments:
pwszValue - substring to find
dwStartIndex - initial index.
Return Value:
The index for the first character occurence in the string.
-1 if not found.
--*/
INT
STRU::IndexOf(
__in PCWSTR pwszValue,
__in DWORD dwStartIndex
) const
{
HRESULT hr = S_OK;
INT nIndex = -1;
SIZE_T cchValue = 0;
// Validate input parameters
if( dwStartIndex >= QueryCCH() || !pwszValue )
{
goto Finished;
}
const WCHAR* pwChar = wcsstr( QueryStr() + dwStartIndex, pwszValue );
// Determine the index if found
if( pwChar )
{
// nIndex will be set to -1 on failure.
(VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
}
Finished:
return nIndex;
}
/*++
Routine Description:
Searches the string for the last occurrence of the specified character.
Arguments:
charValue - character to find
dwStartIndex - initial index.
Return Value:
The index for the last character occurence in the string.
-1 if not found.
--*/
INT
STRU::LastIndexOf(
__in WCHAR charValue,
__in DWORD dwStartIndex
) const
{
INT nIndex = -1;
// Make sure that there are no buffer overruns.
if( dwStartIndex >= QueryCCH() )
{
goto Finished;
}
const WCHAR* pwChar = wcsrchr( QueryStr() + dwStartIndex, charValue );
// Determine the index if found
if( pwChar )
{
// nIndex will be set to -1 on failure.
(VOID)SizeTToInt( pwChar - QueryStr(), &nIndex );
}
Finished:
return nIndex;
}
//static
HRESULT
STRU::ExpandEnvironmentVariables(
__in PCWSTR pszString,
__out STRU * pstrExpandedString
)
/*++
Routine Description:
Expand the environment variables in a string
Arguments:
pszString - String with environment variables to expand
pstrExpandedString - Receives expanded string on success
Return Value:
HRESULT
--*/
{
HRESULT hr = S_OK;
DWORD cchNewSize = 0;
if ( pszString == NULL ||
pstrExpandedString == NULL )
{
DBG_ASSERT( FALSE );
hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
goto Exit;
}
cchNewSize = ExpandEnvironmentStrings( pszString,
pstrExpandedString->QueryStr(),
pstrExpandedString->QuerySizeCCH() );
if ( cchNewSize == 0 )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Exit;
}
if ( cchNewSize > pstrExpandedString->QuerySizeCCH() )
{
hr = pstrExpandedString->Resize(
( cchNewSize + 1 ) * sizeof( WCHAR )
);
if ( FAILED( hr ) )
{
goto Exit;
}
cchNewSize = ExpandEnvironmentStrings(
pszString,
pstrExpandedString->QueryStr(),
pstrExpandedString->QuerySizeCCH()
);
if ( cchNewSize == 0 ||
cchNewSize > pstrExpandedString->QuerySizeCCH() )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto Exit;
}
}
pstrExpandedString->SyncWithBuffer();
hr = S_OK;
Exit:
return hr;
}
#pragma warning(default:4267)