windows-nt/Source/XPSP1/NT/windows/appcompat/shims/lib/cstringapi.cpp
2020-09-26 16:20:57 +08:00

290 lines
6.1 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
CStringPI.cpp
Abstract:
Win32 API wrappers for CString
Created:
02/27/2001 robkenny Created
08/14/2001 robkenny Moved code inside the ShimLib namespace.
--*/
#include "ShimLib.h"
#include "Shlobj.h"
namespace ShimLib
{
/*====================================================================================*/
/*++
Read a registry value into this CString.
REG_EXPAND_SZ is automatically expanded and the type is changed to REG_SZ
If the type is not REG_SZ or REG_EXPAND_SZ, then csRegValue.GetLength()
is the number of *bytes* in the string.
This should, really, only be used to read REG_SZ/REG_EXPAND_SZ registry values.
--*/
LONG RegQueryValueExW(
CString & csValue,
HKEY hKeyRoot,
const WCHAR * lpszKey,
const WCHAR * lpszValue,
LPDWORD lpType)
{
LONG success;
HKEY hKey;
success = RegOpenKeyW(hKeyRoot, lpszKey, &hKey);
if (success == ERROR_SUCCESS)
{
DWORD dwSizeBytes;
success = ::RegQueryValueExW(hKey, lpszValue, 0, lpType, NULL, &dwSizeBytes);
if (success == ERROR_SUCCESS)
{
int nChars = dwSizeBytes / sizeof(WCHAR);
nChars -= 1; // size included null
WCHAR * lpszBuffer = csValue.GetBuffer(nChars);
success = ::RegQueryValueExW(hKey, lpszValue, 0, lpType, (BYTE*)lpszBuffer, &dwSizeBytes);
if (success == ERROR_SUCCESS)
{
csValue.ReleaseBuffer(nChars);
if (*lpType == REG_EXPAND_SZ)
{
csValue.ExpandEnvironmentStringsW();
*lpType = REG_SZ;
}
}
else
{
csValue.ReleaseBuffer(0);
}
}
::RegCloseKey(hKey);
}
if (success != ERROR_SUCCESS)
{
csValue.Truncate(0);
}
return success;
}
/*====================================================================================*/
BOOL SHGetSpecialFolderPathW(
CString & csFolder,
int nFolder,
HWND hwndOwner
)
{
// Force the size to MAX_PATH because there is no way to determine necessary buffer size.
WCHAR * lpsz = csFolder.GetBuffer(MAX_PATH);
BOOL bSuccess = ::SHGetSpecialFolderPathW(hwndOwner, lpsz, nFolder, FALSE);
csFolder.ReleaseBuffer(-1); // Don't know the length of the resulting string
return bSuccess;
}
/*====================================================================================*/
CStringToken::CStringToken(const CString & csToken, const CString & csDelimit)
{
m_nPos = 0;
m_csToken = csToken;
m_csDelimit = csDelimit;
}
/*++
Grab the next token
--*/
BOOL CStringToken::GetToken(CString & csNextToken, int & nPos) const
{
// Already reached the end of the string
if (nPos > m_csToken.GetLength())
{
csNextToken.Truncate(0);
return FALSE;
}
int nNextToken;
// Skip past all the leading seperators
nPos = m_csToken.FindOneNotOf(m_csDelimit, nPos);
if (nPos < 0)
{
// Nothing but seperators
csNextToken.Truncate(0);
nPos = m_csToken.GetLength() + 1;
return FALSE;
}
// Find the next seperator
nNextToken = m_csToken.FindOneOf(m_csDelimit, nPos);
if (nNextToken < 0)
{
// Did not find a seperator, return remaining string
m_csToken.Mid(nPos, csNextToken);
nPos = m_csToken.GetLength() + 1;
return TRUE;
}
// Found a seperator, return the string
m_csToken.Mid(nPos, nNextToken - nPos, csNextToken);
nPos = nNextToken;
return TRUE;
}
/*++
Grab the next token
--*/
BOOL CStringToken::GetToken(CString & csNextToken)
{
return GetToken(csNextToken, m_nPos);
}
/*++
Count the number of remaining tokens.
--*/
int CStringToken::GetCount() const
{
int nTokenCount = 0;
int nNextToken = m_nPos;
CString csTok;
while (GetToken(csTok, nNextToken))
{
nTokenCount += 1;
}
return nTokenCount;
}
/*====================================================================================*/
/*====================================================================================*/
/*++
A simple class to assist in command line parsing
--*/
CStringParser::CStringParser(const WCHAR * lpszCl, const WCHAR * lpszSeperators)
{
m_ncsArgList = 0;
m_csArgList = NULL;
if (!lpszCl || !*lpszCl)
{
return; // no command line == no tokens
}
CString csCl(lpszCl);
CString csSeperator(lpszSeperators);
if (csSeperator[0] == L' ')
{
// Special processing for blank seperated cl
SplitWhite(csCl);
}
else
{
SplitSeperator(csCl, csSeperator);
}
}
CStringParser::~CStringParser()
{
if (m_csArgList)
{
delete [] m_csArgList;
}
}
/*++
Split up the command line based on the seperators
--*/
void CStringParser::SplitSeperator(const CString & csCl, const CString & csSeperator)
{
CStringToken csParser(csCl, csSeperator);
CString csTok;
m_ncsArgList = csParser.GetCount();
m_csArgList = new CString[m_ncsArgList];
if (!m_csArgList)
{
CSTRING_THROW_EXCEPTION
}
// Break the command line into seperate tokens
for (int i = 0; i < m_ncsArgList; ++i)
{
csParser.GetToken(m_csArgList[i]);
}
}
/*++
Split up the command line based on whitespace,
this works exactly like the CMD's command line.
--*/
void CStringParser::SplitWhite(const CString & csCl)
{
LPWSTR * argv = _CommandLineToArgvW(csCl, &m_ncsArgList);
if (!argv)
{
CSTRING_THROW_EXCEPTION
}
m_csArgList = new CString[m_ncsArgList];
if (!m_csArgList)
{
CSTRING_THROW_EXCEPTION
}
for (int i = 0; i < m_ncsArgList; ++i)
{
m_csArgList[i] = argv[i];
}
LocalFree(argv);
}
/*====================================================================================*/
/*====================================================================================*/
}; // end of namespace ShimLib