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.
533 lines
15 KiB
533 lines
15 KiB
#include "precomp.h"
|
|
|
|
// this class is used by our private wrappers to thunk unicode to ansi and take care of
|
|
// all the allocation goo. There are three constructors: use LPCWSTR if you just need
|
|
// to thunk a normal string to ansi, use LPCWSTR, LPDWORD if you need to thunk a list of
|
|
// null-terminated strings to ansi, and use DWORD if you need a buffer for an out
|
|
// parameter
|
|
|
|
class CAnsiStr
|
|
{
|
|
private:
|
|
CHAR m_szBuf[MAX_PATH];
|
|
BOOL m_fFree;
|
|
|
|
public:
|
|
LPSTR pszStr;
|
|
|
|
CAnsiStr(LPCWSTR);
|
|
CAnsiStr(LPCWSTR, LPDWORD pcchSize);
|
|
CAnsiStr(DWORD cchSize);
|
|
~CAnsiStr();
|
|
};
|
|
|
|
CAnsiStr::CAnsiStr(LPCWSTR pcwszStr)
|
|
{
|
|
if (pcwszStr == NULL)
|
|
{
|
|
m_fFree = FALSE;
|
|
pszStr = NULL;
|
|
}
|
|
else
|
|
{
|
|
DWORD cchSize = StrLenW(pcwszStr);
|
|
DWORD cbSize, dwErr;
|
|
|
|
m_fFree = (cchSize > (countof(m_szBuf) - 1));
|
|
if (m_fFree)
|
|
{
|
|
pszStr = (LPSTR)CoTaskMemAlloc(cchSize+1);
|
|
if (pszStr == NULL)
|
|
{
|
|
m_fFree = FALSE;
|
|
return;
|
|
}
|
|
else
|
|
ZeroMemory(pszStr, cchSize+1);
|
|
}
|
|
else
|
|
pszStr = m_szBuf;
|
|
|
|
cbSize = WideCharToMultiByte(CP_ACP, 0, pcwszStr, cchSize+1, pszStr, cchSize+1, NULL, NULL);
|
|
dwErr = GetLastError();
|
|
|
|
// NOTE: check to see if we fail, in which case we might be dealing with DBCS chars and
|
|
// need to reallocate or allocate
|
|
|
|
if ((cbSize == 0) && (dwErr == ERROR_INSUFFICIENT_BUFFER))
|
|
{
|
|
cbSize = WideCharToMultiByte(CP_ACP, 0, pcwszStr, cchSize+1, pszStr, 0, NULL, NULL);
|
|
|
|
if (m_fFree)
|
|
{
|
|
LPSTR pszStr2;
|
|
|
|
// need this second ptr because CoTaskMemRealloc doesn't free the old block if
|
|
// not enough mem for the new one
|
|
|
|
pszStr2 = (LPSTR)CoTaskMemRealloc(pszStr, cbSize);
|
|
|
|
if (pszStr2 == NULL)
|
|
CoTaskMemFree(pszStr);
|
|
|
|
pszStr = pszStr2;
|
|
}
|
|
else
|
|
{
|
|
m_fFree = (cbSize > countof(m_szBuf));
|
|
|
|
if (m_fFree)
|
|
pszStr = (LPSTR)CoTaskMemAlloc(cbSize);
|
|
}
|
|
|
|
if (m_fFree && (pszStr == NULL))
|
|
{
|
|
m_fFree = FALSE;
|
|
return;
|
|
}
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, pcwszStr, cchSize+1, pszStr, cbSize, NULL, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
CAnsiStr::CAnsiStr(LPCWSTR pcwszStr, LPDWORD pcchSize)
|
|
{
|
|
if (pcchSize != NULL)
|
|
*pcchSize = 0;
|
|
|
|
if (pcwszStr == NULL)
|
|
{
|
|
m_fFree = FALSE;
|
|
pszStr = NULL;
|
|
}
|
|
else
|
|
{
|
|
DWORD cchSize = 0;
|
|
DWORD cbSize, dwErr;
|
|
|
|
for (LPCWSTR pcwsz = pcwszStr; *pcwsz; )
|
|
{
|
|
DWORD cchStrSize = StrLenW(pcwsz)+1;
|
|
cchSize += cchStrSize;
|
|
pcwsz += cchStrSize;
|
|
}
|
|
|
|
m_fFree = (cchSize > (ARRAYSIZE(m_szBuf) - 1));
|
|
if (m_fFree)
|
|
{
|
|
pszStr = (LPSTR)CoTaskMemAlloc(cchSize+1);
|
|
if (pszStr == NULL)
|
|
{
|
|
m_fFree = FALSE;
|
|
return;
|
|
}
|
|
else
|
|
ZeroMemory(pszStr, cchSize+1);
|
|
}
|
|
else
|
|
pszStr = m_szBuf;
|
|
|
|
cbSize = WideCharToMultiByte(CP_ACP, 0, pcwszStr, cchSize+1, pszStr, cchSize+1, NULL, NULL);
|
|
dwErr = GetLastError();
|
|
|
|
// NOTE: check to see if we fail, in which case we might be dealing with DBCS chars and
|
|
// need to reallocate or allocate
|
|
|
|
if ((cbSize == 0) && (dwErr == ERROR_INSUFFICIENT_BUFFER))
|
|
{
|
|
cbSize = WideCharToMultiByte(CP_ACP, 0, pcwszStr, cchSize+1, pszStr, 0, NULL, NULL);
|
|
|
|
if (m_fFree)
|
|
{
|
|
LPSTR pszStr2;
|
|
|
|
// need this second ptr because CoTaskMemRealloc doesn't free the old block if
|
|
// not enough mem for the new one
|
|
|
|
pszStr2 = (LPSTR)CoTaskMemRealloc(pszStr, cbSize);
|
|
|
|
if (pszStr2 == NULL)
|
|
CoTaskMemFree(pszStr);
|
|
|
|
pszStr = pszStr2;
|
|
}
|
|
else
|
|
{
|
|
m_fFree = (cbSize > countof(m_szBuf));
|
|
|
|
if (m_fFree)
|
|
pszStr = (LPSTR)CoTaskMemAlloc(cbSize);
|
|
}
|
|
|
|
if (m_fFree && (pszStr == NULL))
|
|
{
|
|
m_fFree = FALSE;
|
|
return;
|
|
}
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, pcwszStr, cchSize+1, pszStr, cbSize, NULL, NULL);
|
|
}
|
|
|
|
if (pcchSize != NULL)
|
|
*pcchSize = cchSize;
|
|
}
|
|
}
|
|
|
|
CAnsiStr::CAnsiStr(DWORD cchSize)
|
|
{
|
|
m_fFree = (cchSize > ARRAYSIZE(m_szBuf));
|
|
if (m_fFree)
|
|
{
|
|
pszStr = (LPSTR)CoTaskMemAlloc(cchSize);
|
|
if (pszStr == NULL)
|
|
{
|
|
m_fFree = FALSE;
|
|
return;
|
|
}
|
|
else
|
|
ZeroMemory(pszStr, cchSize);
|
|
}
|
|
else
|
|
{
|
|
pszStr = m_szBuf;
|
|
ZeroMemory(pszStr, cchSize);
|
|
}
|
|
}
|
|
|
|
CAnsiStr::~CAnsiStr()
|
|
{
|
|
if (m_fFree && (pszStr != NULL))
|
|
CoTaskMemFree(pszStr);
|
|
}
|
|
|
|
//------ advpack wrappers --------
|
|
// advpack is exclusively ANSI so have to thunk for UNICODE
|
|
|
|
HRESULT ExtractFilesWrapW(LPCWSTR pszCabName, LPCWSTR pszExpandDir, DWORD dwFlags,
|
|
LPCWSTR pszFileList, LPVOID lpReserved, DWORD dwReserved)
|
|
{
|
|
CAnsiStr astrFileList(pszFileList, NULL);
|
|
|
|
USES_CONVERSION;
|
|
|
|
if ((pszFileList != NULL) && (astrFileList.pszStr == NULL))
|
|
{
|
|
// class memory allocation failed
|
|
|
|
ASSERT(FALSE);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return ExtractFiles(W2CA(pszCabName), W2CA(pszExpandDir), dwFlags,
|
|
(LPCSTR)astrFileList.pszStr, lpReserved, dwReserved);
|
|
}
|
|
|
|
HRESULT GetVersionFromFileWrapW(LPWSTR lpszFilename, LPDWORD pdwMSVer, LPDWORD pdwLSVer, BOOL bVersion)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
return GetVersionFromFile(W2A(lpszFilename), pdwMSVer, pdwLSVer, bVersion);
|
|
}
|
|
|
|
HRESULT RunSetupCommandWrapW(HWND hWnd, LPCWSTR szCmdName, LPCWSTR szInfSection, LPCWSTR szDir,
|
|
LPCWSTR lpszTitle, HANDLE *phEXE, DWORD dwFlags, LPVOID pvReserved )
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
return RunSetupCommand(hWnd, W2CA(szCmdName), W2CA(szInfSection), W2CA(szDir),
|
|
W2CA(lpszTitle), phEXE, dwFlags, pvReserved);
|
|
}
|
|
|
|
//------ inseng wrappers --------
|
|
// inseng is exclusively ANSI so have to thunk for UNICODE
|
|
|
|
HRESULT CheckTrustExWrapW(LPCWSTR wszUrl, LPCWSTR wszFilename, HWND hwndForUI, BOOL bShowBadUI, DWORD dwReserved)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
return CheckTrustEx(W2CA(wszUrl), W2CA(wszFilename), hwndForUI, bShowBadUI, dwReserved);
|
|
}
|
|
|
|
// either shlwapi doesn't implement wrappers or their wrappers have limitations on these APIs
|
|
|
|
//------ kernel32 wrappers --------
|
|
|
|
// this is the equivalent of GetPrivateProfileString and should only be called if lpAppName
|
|
// and/or lpSectionName is NULL. shlwapi's wrappers doesn't handle the series of NULL-terminated
|
|
// strings
|
|
|
|
DWORD GetPrivateProfileStringW_p(LPCWSTR lpAppName, LPCWSTR lpSectionName, LPCWSTR lpDefault,
|
|
LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName)
|
|
{
|
|
DWORD dwRetLen;
|
|
|
|
USES_CONVERSION;
|
|
|
|
// this occurence of GetPrivateProfileStringW is actually wrapped by shlwapi itself so
|
|
// you won't actually ever see GetPrivateProfileStringW in the import table for your module
|
|
|
|
if (IsOS(OS_NT))
|
|
dwRetLen = GetPrivateProfileStringW(lpAppName, lpSectionName, lpDefault, lpReturnedString, nSize, lpFileName);
|
|
else
|
|
{
|
|
CAnsiStr astrReturnedString(nSize);
|
|
|
|
if (astrReturnedString.pszStr == NULL)
|
|
{
|
|
// class memory allocation failed
|
|
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
dwRetLen = GetPrivateProfileStringA(W2CA(lpAppName), W2CA(lpSectionName), W2CA(lpDefault),
|
|
astrReturnedString.pszStr, nSize, W2CA(lpFileName));
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, astrReturnedString.pszStr, dwRetLen+1, lpReturnedString, nSize);
|
|
|
|
// handle possible truncation
|
|
|
|
if (((lpAppName == NULL) || (lpSectionName == NULL))
|
|
&& (dwRetLen == (nSize - 2)))
|
|
lpReturnedString[nSize - 1] = TEXT('\0');
|
|
}
|
|
|
|
return dwRetLen;
|
|
}
|
|
|
|
DWORD GetPrivateProfileSectionWrapW(LPCWSTR lpAppName, LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName)
|
|
{
|
|
DWORD dwRetLen;
|
|
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
dwRetLen = GetPrivateProfileSectionW(lpAppName, lpReturnedString, nSize, lpFileName);
|
|
else
|
|
{
|
|
CAnsiStr astrReturnedString(nSize);
|
|
|
|
if (astrReturnedString.pszStr == NULL)
|
|
{
|
|
// class memory allocation failed
|
|
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
dwRetLen = GetPrivateProfileSectionA(W2CA(lpAppName), astrReturnedString.pszStr, nSize, W2CA(lpFileName));
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, astrReturnedString.pszStr, dwRetLen+1, lpReturnedString, nSize);
|
|
|
|
// null terminate the end of the buffer if size is insufficient
|
|
|
|
if (dwRetLen == (nSize - 2))
|
|
lpReturnedString[nSize - 1] = TEXT('\0');
|
|
}
|
|
|
|
|
|
return dwRetLen;
|
|
}
|
|
|
|
BOOL WritePrivateProfileSectionWrapW(LPCWSTR lpAppName, LPCWSTR lpString, LPCWSTR lpFileName)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
return WritePrivateProfileSectionW(lpAppName, lpString, lpFileName);
|
|
else
|
|
{
|
|
CAnsiStr astrString(lpString, NULL);
|
|
|
|
return WritePrivateProfileSectionA(W2CA(lpAppName), astrString.pszStr, W2CA(lpFileName));
|
|
}
|
|
}
|
|
|
|
UINT GetDriveTypeWrapW(LPCWSTR lpRootPathName)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
return GetDriveTypeW(lpRootPathName);
|
|
else
|
|
return GetDriveTypeA(W2CA(lpRootPathName));
|
|
}
|
|
|
|
HANDLE OpenMutexWrapW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
return OpenMutexW(dwDesiredAccess, bInheritHandle, lpName);
|
|
else
|
|
return OpenMutexA(dwDesiredAccess, bInheritHandle, W2CA(lpName));
|
|
}
|
|
|
|
//------ advapi32 wrappers --------
|
|
|
|
BOOL LookupPrivilegeValueWrapW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
return LookupPrivilegeValueW(lpSystemName, lpName, lpLuid);
|
|
else
|
|
return LookupPrivilegeValueA(W2CA(lpSystemName), W2CA(lpName), lpLuid);
|
|
}
|
|
|
|
LONG RegLoadKeyWrapW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpFile)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
return RegLoadKeyW(hKey, lpSubKey, lpFile);
|
|
else
|
|
return RegLoadKeyA(hKey, W2CA(lpSubKey), W2CA(lpFile));
|
|
}
|
|
|
|
LONG RegUnLoadKeyWrapW(HKEY hKey, LPCWSTR lpSubKey)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
return RegUnLoadKeyW(hKey, lpSubKey);
|
|
else
|
|
return RegUnLoadKeyA(hKey, W2CA(lpSubKey));
|
|
}
|
|
|
|
LONG RegSaveKeyWrapW(HKEY hKey, LPCWSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
return RegSaveKeyW(hKey, lpFile, lpSecurityAttributes);
|
|
else
|
|
return RegSaveKeyA(hKey, W2CA(lpFile), lpSecurityAttributes);
|
|
}
|
|
|
|
//------ shell32 wrappers --------
|
|
|
|
int SHFileOperationW_p(LPSHFILEOPSTRUCTW lpFileOpW)
|
|
{
|
|
int iRet;
|
|
|
|
USES_CONVERSION;
|
|
|
|
if (IsOS(OS_NT))
|
|
iRet = SHFileOperationW(lpFileOpW);
|
|
else
|
|
{
|
|
SHFILEOPSTRUCTA shInfo;
|
|
CAnsiStr * pastrIn = NULL;
|
|
CAnsiStr * pastrOut = NULL;
|
|
|
|
|
|
ZeroMemory(&shInfo, sizeof(shInfo));
|
|
|
|
shInfo.fAnyOperationsAborted = lpFileOpW->fAnyOperationsAborted;
|
|
shInfo.fFlags = lpFileOpW->fFlags;
|
|
shInfo.hNameMappings = lpFileOpW->hNameMappings;
|
|
shInfo.hwnd = lpFileOpW->hwnd;
|
|
shInfo.lpszProgressTitle = W2A(lpFileOpW->lpszProgressTitle);
|
|
shInfo.wFunc = lpFileOpW->wFunc;
|
|
|
|
pastrIn = new CAnsiStr(lpFileOpW->pFrom, NULL);
|
|
|
|
if ((pastrIn == NULL) || (pastrIn->pszStr == NULL))
|
|
{
|
|
// allocation failed
|
|
|
|
ASSERT(FALSE);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
shInfo.pFrom = pastrIn->pszStr;
|
|
|
|
|
|
if (lpFileOpW->fFlags & FOF_MULTIDESTFILES)
|
|
{
|
|
pastrOut = new CAnsiStr(lpFileOpW->pTo, NULL);
|
|
if ((pastrOut == NULL) || (pastrOut->pszStr == NULL))
|
|
{
|
|
// allocation failed
|
|
|
|
ASSERT(FALSE);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
shInfo.pTo = pastrOut->pszStr;
|
|
}
|
|
else
|
|
shInfo.pTo = W2A(lpFileOpW->pTo);
|
|
|
|
iRet = SHFileOperationA(&shInfo);
|
|
|
|
if (pastrIn != NULL)
|
|
delete pastrIn;
|
|
|
|
if (pastrOut != NULL)
|
|
delete pastrOut;
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
//------ private util wrappers --------
|
|
|
|
BOOL RunAndWaitA(LPSTR pszCmd, LPCSTR pcszDir, WORD wShow, LPDWORD lpExitCode /* = NULL */)
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFOA stiA;
|
|
MSG msg;
|
|
|
|
ZeroMemory(&stiA, sizeof(stiA));
|
|
stiA.cb = sizeof(stiA);
|
|
stiA.dwFlags = STARTF_USESHOWWINDOW;
|
|
stiA.wShowWindow = wShow;
|
|
|
|
USES_CONVERSION;
|
|
if (!CreateProcessA(NULL, pszCmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, pcszDir, &stiA, &pi))
|
|
return FALSE;
|
|
|
|
// wait for the process to finish
|
|
while (MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0)
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (lpExitCode)
|
|
GetExitCodeProcess(pi.hProcess, lpExitCode);
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL RunAndWaitW(LPWSTR pwszCmd, LPCWSTR pcwszDir, WORD wShow, LPDWORD lpExitCode /* = NULL */)
|
|
{
|
|
PROCESS_INFORMATION pi;
|
|
STARTUPINFOW stiW;
|
|
MSG msg;
|
|
|
|
ZeroMemory(&stiW, sizeof(stiW));
|
|
stiW.cb = sizeof(stiW);
|
|
stiW.dwFlags = STARTF_USESHOWWINDOW;
|
|
stiW.wShowWindow = wShow;
|
|
|
|
USES_CONVERSION;
|
|
if (!CreateProcessW(NULL, pwszCmd, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, pcwszDir, &stiW, &pi))
|
|
return FALSE;
|
|
|
|
// wait for the process to finish
|
|
while (MsgWaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0)
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (lpExitCode)
|
|
GetExitCodeProcess(pi.hProcess, lpExitCode);
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
return TRUE;
|
|
}
|