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.
627 lines
19 KiB
627 lines
19 KiB
|
|
|
|
#include "pch.h"
|
|
#include <ole2.h>
|
|
#include "advpub.h"
|
|
#include "sdsutils.h"
|
|
#include "migrate.h"
|
|
#include "utils.h"
|
|
|
|
|
|
BOOL AppendString(LPSTR *lpBuffer, DWORD *lpdwSize, LPCSTR lpStr)
|
|
{
|
|
DWORD cbBufferUsed = 0;
|
|
DWORD dwNewSize = 0;
|
|
LPSTR lpTmp = NULL;
|
|
DWORD dwLen = 0;
|
|
|
|
// Sanity check
|
|
if (lpStr == NULL || *lpStr == '\0')
|
|
return FALSE;
|
|
|
|
if (*lpBuffer == NULL)
|
|
{
|
|
// Allocate the buffer.
|
|
*lpdwSize = sizeof(char) * MAX_PATH;
|
|
*lpBuffer = (char *) LocalAlloc(LPTR, *lpdwSize);
|
|
if (*lpBuffer == NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
SetupLogError("IE6: AppendString memory failure\r\n",LogSevInformation);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
dwNewSize = lstrlen(lpStr);
|
|
|
|
// Get the number of bytes used up, excluding the second terminating NULL (-1)
|
|
cbBufferUsed = CountMultiStringBytes((LPCSTR)*lpBuffer) - 1;
|
|
|
|
if ( (*lpdwSize - cbBufferUsed) < (dwNewSize + 2))
|
|
{
|
|
LPSTR lpNewBuffer = NULL;
|
|
DWORD dwTemp = 0;
|
|
|
|
// Need to reallocate.
|
|
dwTemp = *lpdwSize + (max((sizeof(char) * MAX_PATH), dwNewSize+2));
|
|
lpNewBuffer = (char *) LocalAlloc(LPTR,dwTemp);
|
|
|
|
if ( lpNewBuffer == NULL)
|
|
{
|
|
#ifdef DEBUG
|
|
SetupLogError("IE6: AppendString memory failure\r\n",LogSevInformation);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Rearrange the IN pointer to point to the new block.
|
|
// Copy over the old info to the new allocated block.
|
|
// +1 for the one that we subtracted above.
|
|
CopyMemory(lpNewBuffer, *lpBuffer, cbBufferUsed+1);
|
|
|
|
// Free the old buffer.
|
|
LocalFree(*lpBuffer);
|
|
|
|
// Point to the new buffer.
|
|
*lpBuffer = (char *) lpNewBuffer;
|
|
*lpdwSize = dwTemp;
|
|
}
|
|
}
|
|
|
|
// Append the new string now.
|
|
lpTmp = *lpBuffer + cbBufferUsed;
|
|
lstrcpy(lpTmp,lpStr);
|
|
|
|
// Add the second terminating NULL to it now.
|
|
lpTmp += (dwNewSize + 1);
|
|
*lpTmp = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// NOTE NOTE: This function is called during the QueryVersion phase. Hence it needs to be small and fast
|
|
// So we just do the check for the presence of the "HKLM\S\M\W\CV\Policies\Ratings" key and don't try to
|
|
// verify using MSRating API.
|
|
|
|
#define REGVAL_KEY "Key"
|
|
|
|
BOOL IsRatingsEnabled()
|
|
{
|
|
HKEY hKey;
|
|
BOOL bRet = FALSE;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,REGKEY_RATING,KEY_READ,NULL,&hKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwType;
|
|
if (RegQueryValueEx(hKey,REGVAL_KEY,NULL,&dwType, NULL, NULL) == ERROR_SUCCESS
|
|
&& dwType == REG_BINARY)
|
|
{
|
|
#ifdef DEBUG
|
|
SetupLogError("IE6: Located RATINGS\Key", LogSevInformation);
|
|
#endif
|
|
// The Ratings key exists and Password has been set. Means Ratings
|
|
// is enabled.
|
|
bRet = TRUE;
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// Returns the number of used bytes in a double NULL terminated string, including the two NULLS.
|
|
DWORD CountMultiStringBytes (LPCSTR lpString)
|
|
{
|
|
DWORD cbBytes;
|
|
LPSTR lpTmp;
|
|
DWORD dwLen;
|
|
|
|
// Sanity check
|
|
if (lpString == NULL)
|
|
return 0;
|
|
|
|
// Get to the double \0 termination of lpBuffer
|
|
lpTmp = (LPSTR)lpString;
|
|
cbBytes = 1;
|
|
while (lpTmp && *lpTmp != '\0')
|
|
{
|
|
dwLen = lstrlen(lpTmp) + 1;
|
|
lpTmp = lpTmp + dwLen;
|
|
cbBytes += dwLen;
|
|
}
|
|
|
|
return cbBytes;
|
|
}
|
|
|
|
BOOL PathEndsInFile(LPSTR lpPath, LPCSTR lpFile)
|
|
{
|
|
LPSTR pTmp = lpPath;
|
|
|
|
// Sanity check
|
|
if (lpPath == NULL || lpFile == NULL)
|
|
return FALSE;
|
|
|
|
#ifdef DEBUG
|
|
char szDebug[MAX_PATH*3];
|
|
wsprintf(szDebug,"IE5 (PathEndsInFile): %s :: %s \r\n", lpPath, lpFile);
|
|
SetupLogError(szDebug,LogSevInformation);
|
|
#endif
|
|
|
|
// Point pTmp to the terminating NULL
|
|
pTmp = lpPath + lstrlen(lpPath);
|
|
|
|
while (*pTmp != '\\' && pTmp != lpPath)
|
|
{
|
|
pTmp = CharPrev(lpPath, pTmp);
|
|
}
|
|
|
|
pTmp = CharNext(pTmp);
|
|
|
|
#ifdef DEBUG
|
|
wsprintf(szDebug,"IE5 (PathEndsInFile): %s :: %s \r\n", pTmp, lpFile);
|
|
SetupLogError(szDebug,LogSevInformation);
|
|
#endif
|
|
|
|
return (lstrcmpi(pTmp, lpFile) == 0);
|
|
}
|
|
|
|
|
|
// Helper function to get the path for "Ratings.pol" from the MIGRATE.INF
|
|
// The path is returned in a buffer allocated by the function.
|
|
// **********************************************************************
|
|
// *** NOTE *** : It is the caller function responsibilty to free memory.
|
|
// **********************************************************************
|
|
// Parameters:
|
|
// lpOutBuffer: Ptr to variable to hold the new string allocated.
|
|
// User can pass in NULL if only interested in existance of Ratings.pol
|
|
// and not the actual path to it.
|
|
BOOL GetRatingsPathFromMigInf( LPSTR *lpOutBuffer)
|
|
{
|
|
INFCONTEXT ic;
|
|
HINF hInf;
|
|
BOOL bFound = FALSE;
|
|
LPSTR lpBuf = NULL;
|
|
DWORD dwSize, dwNewSize;
|
|
|
|
if (lpOutBuffer)
|
|
*lpOutBuffer = NULL;
|
|
|
|
dwSize = MAX_PATH;
|
|
lpBuf = (char *) LocalAlloc(LPTR, sizeof(char)*dwSize);
|
|
if (lpBuf == NULL)
|
|
return FALSE;
|
|
|
|
// Before calling the migration DLL, Setup sets the CurrentDirectory to
|
|
// the directory assigned to that migration DLL. Hence can use this.
|
|
//hInf = SetupOpenInfFile(cszMIGRATEINF, NULL, INF_STYLE_WIN4, NULL);
|
|
hInf = SetupOpenInfFile(g_szMigrateInf, NULL, INF_STYLE_WIN4, NULL);
|
|
if (hInf)
|
|
{
|
|
#ifdef DEBUG
|
|
SetupLogError("IE6: Opened Miginf.inf \r\n", LogSevInformation);
|
|
#endif
|
|
if (SetupFindFirstLine(hInf,cszMIGINF_MIGRATION_PATHS,NULL,&ic))
|
|
{
|
|
do
|
|
{
|
|
dwNewSize = 0;
|
|
if( SetupGetLineTextA(&ic,hInf,NULL,NULL,lpBuf,dwSize,&dwNewSize) == 0 && dwNewSize > dwSize)
|
|
{ // Need more buffer space
|
|
// Free the old buffer space.
|
|
LocalFree(lpBuf);
|
|
|
|
// Try and allocate a new buffer.
|
|
dwSize = dwNewSize;
|
|
lpBuf = (char *) LocalAlloc(LPTR, sizeof(char)*dwSize);
|
|
|
|
if (lpBuf == NULL)
|
|
{
|
|
// Memory Error - break out.
|
|
break;
|
|
}
|
|
|
|
if (!SetupGetLineTextA(&ic,hInf,NULL,NULL,lpBuf,dwSize,&dwNewSize))
|
|
{
|
|
// The bFound check below takes care of LocalFree(lpBuf);
|
|
#ifdef DEBUG
|
|
SetupLogError("IE6: Error doing SetupGetTextLineA \r\n", LogSevInformation);
|
|
#endif
|
|
break; // Failure can't help it.
|
|
}
|
|
}
|
|
|
|
// So managed to read out the line. Check if it contains .pol
|
|
if (PathEndsInFile(lpBuf,cszRATINGSFILE))
|
|
{
|
|
if (lpOutBuffer)
|
|
{
|
|
*lpOutBuffer = lpBuf;
|
|
}
|
|
else
|
|
{ // User is not interested in Path. Free the block.
|
|
LocalFree(lpBuf);
|
|
}
|
|
bFound = TRUE;
|
|
#ifdef DEBUG
|
|
SetupLogError("IE6: Found Ratings.Pol in Migrate.Inf \r\n", LogSevInformation);
|
|
#endif
|
|
}
|
|
}
|
|
while (!bFound && SetupFindNextLine(&ic,&ic));
|
|
|
|
}
|
|
|
|
SetupCloseInfFile(hInf);
|
|
}
|
|
|
|
if (!bFound)
|
|
{
|
|
// Free the local buffer.
|
|
LocalFree(lpBuf);
|
|
}
|
|
|
|
return bFound;
|
|
}
|
|
|
|
|
|
//******************************************************************************
|
|
// GenerateFilePaths:
|
|
// NOTE NOTE NOTE: The migration DLL remains loaded from the "Initialize9x" phase
|
|
// right till the end of the "MigrateSystem9x" phase. And again from "InitializeNT" phase
|
|
// right till the end of the "MigrateSystemNT" phase. Hence these paths are usable
|
|
// through out.
|
|
//*******************************************************************************
|
|
void GenerateFilePaths()
|
|
{
|
|
|
|
*g_szMigrateInf = '\0';
|
|
*g_szPrivateInf = '\0';
|
|
|
|
if (g_lpWorkingDir)
|
|
{
|
|
// generate the path to the Migrate.Inf file
|
|
wsprintf(g_szMigrateInf, "%s\\%s", g_lpWorkingDir, cszMIGRATEINF);
|
|
#ifdef DEBUG
|
|
char szDebug[MAX_PATH];
|
|
wsprintf(szDebug,"IE6: g_szMigrateInf: %s \r\n",g_szMigrateInf);
|
|
|
|
SetupLogError(szDebug,LogSevInformation);
|
|
#endif
|
|
|
|
// generate the path to the Private.Inf file
|
|
wsprintf(g_szPrivateInf, "%s\\%s", g_lpWorkingDir, cszPRIVATEINF);
|
|
#ifdef DEBUG
|
|
wsprintf(szDebug,"IE6: g_szPrivateInf: %s \r\n",g_szPrivateInf);
|
|
|
|
SetupLogError(szDebug,LogSevInformation);
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
#define IE_KEY "Software\\Microsoft\\Internet Explorer"
|
|
#define VERSION_KEY "Version"
|
|
|
|
BOOL NeedToMigrateIE()
|
|
{
|
|
BOOL bRet = FALSE;
|
|
char szPath[MAX_PATH];
|
|
DWORD dwInstalledVer, dwInstalledBuild;
|
|
|
|
// Currently, the only thing we are interested in are the Ratings settings.
|
|
if (IsRatingsEnabled())
|
|
{
|
|
// Append the "ratings.pol" filename to the list of files needed.
|
|
// NOTE: AppendString allocates memory for the 1st parameter. User
|
|
// must remember to free it.
|
|
bRet |= AppendString(&g_lpNameBuf, &g_dwNameBufSize, cszRATINGSFILE);
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
GetSystemDirectory(szPath, sizeof(szPath));
|
|
AddPath(szPath, "shdocvw.dll");
|
|
GetVersionFromFile(szPath, &dwInstalledVer, &dwInstalledBuild, TRUE);
|
|
// are running with IE5.5 installed.
|
|
bRet = (dwInstalledVer == 0x00050032);
|
|
}
|
|
// Can add other modules that need to be migrated over here.
|
|
// use bRet |= (....) so that you don't stomp previous bRet settings.
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void MyDelRegTree(HKEY hRoot, LPSTR szSubKey)
|
|
{
|
|
char szName[MAX_PATH];
|
|
DWORD dwIndex;
|
|
DWORD dwNameSize;
|
|
HKEY hKey;
|
|
|
|
dwIndex = 0;
|
|
dwNameSize = sizeof(szName);
|
|
if (RegOpenKeyEx(hRoot, szSubKey, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
while (RegEnumKey(hKey, dwIndex, szName, dwNameSize) == ERROR_SUCCESS)
|
|
{
|
|
MyDelRegTree(hKey,szName);
|
|
|
|
// dwIndex++; DONT INCR. SINCE WE HAVE DELETED A SUBKEY.
|
|
dwNameSize = sizeof(szName);
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
//Finally delete the named subkey supplied above.
|
|
RegDeleteKey(hRoot, szSubKey);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recursively Enum values and subkey and copy them over. And then
|
|
// delete all subkeys of the Source key.
|
|
void MoveRegBranch(HKEY hFromKey, HKEY hToKey)
|
|
{
|
|
|
|
char szName[MAX_PATH];
|
|
char szValue[MAX_PATH];
|
|
DWORD dwNameSize;
|
|
DWORD dwValueSize;
|
|
DWORD dwType;
|
|
DWORD dwIndex;
|
|
|
|
// Enumerate all the values here and copy them over to the right
|
|
// location.
|
|
dwIndex = 0;
|
|
dwNameSize = sizeof(szName);
|
|
dwValueSize = sizeof(szValue);
|
|
while (RegEnumValue(hFromKey,dwIndex, szName, &dwNameSize, NULL,
|
|
&dwType, (LPBYTE)szValue, &dwValueSize) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(hToKey,szName,0,dwType,(LPBYTE)szValue, dwValueSize);
|
|
|
|
// Get ready for the next round.
|
|
dwIndex++;
|
|
dwNameSize = sizeof(szName);
|
|
dwValueSize = sizeof(szValue);
|
|
}
|
|
|
|
// Next Enum all the subkeys under source and move them over.
|
|
dwIndex = 0;
|
|
dwNameSize = sizeof(szName);
|
|
while (RegEnumKey(hFromKey, dwIndex, szName, dwNameSize) == ERROR_SUCCESS)
|
|
{
|
|
HKEY hFromSubKey = NULL;
|
|
HKEY hToSubKey = NULL;
|
|
|
|
// Open this SubKey that we enumerated.
|
|
if (RegOpenKeyEx(hFromKey, szName, 0, KEY_ALL_ACCESS, &hFromSubKey) == ERROR_SUCCESS)
|
|
{
|
|
// Create the destination subkey.
|
|
if (RegCreateKeyEx(hToKey, szName, 0, NULL,REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS, NULL, &hToSubKey, NULL) == ERROR_SUCCESS)
|
|
{
|
|
// Move the subkeys...
|
|
MoveRegBranch(hFromSubKey, hToSubKey);
|
|
RegCloseKey(hToSubKey);
|
|
}
|
|
RegCloseKey(hFromSubKey);
|
|
}
|
|
|
|
// Get ready for the next round
|
|
dwIndex++;
|
|
dwNameSize = sizeof(szName);
|
|
}
|
|
|
|
|
|
// Now Delete all the SubKeys. The above recursive call ensures that
|
|
// the Subkeys are one-level deep and hence deletable.
|
|
dwIndex = 0;
|
|
dwNameSize = sizeof(szName);
|
|
while (RegEnumKey(hFromKey, dwIndex, szName, dwNameSize) == ERROR_SUCCESS)
|
|
{
|
|
RegDeleteKey(hFromKey,szName);
|
|
|
|
// dwIndex++; DONT INCR. SINCE WE HAVE DELETED A SUBKEY.
|
|
dwNameSize = sizeof(szName);
|
|
}
|
|
}
|
|
|
|
|
|
#define REGKEY_DEFAULT ".Default"
|
|
#define REGKEY_MIGRATE_HIVE "Software\\Microsoft\\Policies\\Users"
|
|
#define REGKEY_MIGRATE_PICSRULES "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Ratings\\PICSRules"
|
|
#define REGKEY_RATING_PICSRULES "PICSRules"
|
|
|
|
BOOL UpgradeRatings()
|
|
{
|
|
// Real Ratings locations...
|
|
// HKLM\S\M\W\CV\Policies\Ratings (called RATING)
|
|
// Open HKLM\software\Microsoft\Policies\Users.. This is where NT Setup puts
|
|
// the migrated Ratings HIVE.
|
|
// Users [FileNamex] gets copied to RATING [FileNamex]
|
|
// NOTE: Need to take care of SYSTEM/SYSTEM32.
|
|
// Users\.Default branch gets moved to RATING
|
|
// Users\S\M\W\CV\Policies\Ratings\PICSRules branch gets moved to RATING.
|
|
|
|
HKEY hRealRatings = NULL;
|
|
HKEY hRealDefault = NULL;
|
|
HKEY hRealPicsRules = NULL;
|
|
HKEY hMigratedRoot = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
// Open the RegKey to the real location of Ratings.
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_RATING, 0, KEY_ALL_ACCESS,
|
|
&hRealRatings) != ERROR_SUCCESS)
|
|
goto Done;
|
|
// Open the RegKey to the real location of .Default
|
|
if (RegCreateKeyEx(hRealRatings, REGKEY_DEFAULT, 0,
|
|
NULL,REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hRealDefault, NULL) != ERROR_SUCCESS)
|
|
goto Done;
|
|
// Open the RegKey to the real location of PICSRules
|
|
if (RegCreateKeyEx(hRealRatings, REGKEY_RATING_PICSRULES, 0,
|
|
NULL,REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hRealPicsRules, NULL) != ERROR_SUCCESS)
|
|
goto Done;
|
|
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_MIGRATE_HIVE, 0, KEY_ALL_ACCESS, &hMigratedRoot) == ERROR_SUCCESS)
|
|
{
|
|
HKEY hMigrateSubKey = NULL;
|
|
char szName[MAX_PATH];
|
|
char szValue[MAX_PATH];
|
|
DWORD dwNameSize;
|
|
DWORD dwValueSize;
|
|
DWORD dwType;
|
|
char szNewPath[MAX_PATH];
|
|
DWORD dwNewPathSize;
|
|
DWORD dwIndex;
|
|
|
|
// Enumerate all the values here and copy them over to the right
|
|
// location. Make sure to replace 'System' with 'System32'
|
|
dwIndex = 0;
|
|
dwNameSize = sizeof(szName);
|
|
dwValueSize = sizeof(szValue);
|
|
while (RegEnumValue(hMigratedRoot,dwIndex, szName, &dwNameSize, NULL,
|
|
&dwType, (LPBYTE)szValue, &dwValueSize) == ERROR_SUCCESS)
|
|
{
|
|
// Munge the Value and replace 'System' with System32.
|
|
// Return value includes the terminating NULL char, which is
|
|
// need by the RegSetValueEx API.
|
|
dwNewPathSize = GetFixedPath(szNewPath, MAX_PATH, szValue);
|
|
|
|
// Set the correct Ratings setting.
|
|
RegSetValueEx(hRealRatings,szName,0,dwType,(LPBYTE)szNewPath, dwNewPathSize);
|
|
// Get ready for the next round.
|
|
dwIndex++;
|
|
dwNameSize = sizeof(szName);
|
|
dwValueSize = sizeof(szValue);
|
|
}
|
|
|
|
// Now grab Users\.Default and move it to the right location.
|
|
if (RegOpenKeyEx(hMigratedRoot, REGKEY_DEFAULT, 0, KEY_ALL_ACCESS, &hMigrateSubKey) == ERROR_SUCCESS)
|
|
{
|
|
MoveRegBranch(hMigrateSubKey,hRealDefault);
|
|
RegCloseKey(hMigrateSubKey);
|
|
}
|
|
|
|
// Now grab Users\...\PICSRules and move it to the right location.
|
|
if (RegOpenKeyEx(hMigratedRoot, REGKEY_MIGRATE_PICSRULES, 0, KEY_ALL_ACCESS, &hMigrateSubKey) == ERROR_SUCCESS)
|
|
{
|
|
MoveRegBranch(hMigrateSubKey,hRealPicsRules);
|
|
RegCloseKey(hMigrateSubKey);
|
|
}
|
|
|
|
RegCloseKey(hMigratedRoot);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
// Now clean the Migrated Hive.
|
|
MyDelRegTree(HKEY_LOCAL_MACHINE, REGKEY_MIGRATE_HIVE);
|
|
|
|
Done:
|
|
if (hRealRatings)
|
|
RegCloseKey(hRealRatings);
|
|
if (hRealDefault)
|
|
RegCloseKey(hRealDefault);
|
|
if (hRealPicsRules)
|
|
RegCloseKey(hRealPicsRules);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
// Returns the size of NewPath including the terminating NULL.
|
|
DWORD GetFixedPath(LPSTR lpBuf, DWORD dwSize, LPCSTR lpPath)
|
|
{
|
|
char lpLocalCopy[MAX_PATH], szTemp[5];
|
|
char chSave;
|
|
DWORD dwCount = 0;
|
|
LPSTR pTmp, pTmp2;
|
|
|
|
if (lpBuf == NULL || lpPath == NULL)
|
|
return 0;
|
|
|
|
// Create a local copy to party on.
|
|
lstrcpy(lpLocalCopy, lpPath);
|
|
|
|
pTmp = lpLocalCopy;
|
|
*lpBuf = '\0';
|
|
|
|
while (*pTmp && dwCount < dwSize)
|
|
{
|
|
pTmp2 = pTmp;
|
|
while(*pTmp2 && *pTmp2 != '\\')
|
|
pTmp2 = CharNext(pTmp2);
|
|
|
|
chSave = *pTmp2;
|
|
*pTmp2 = '\0';
|
|
|
|
if (lstrcmpi(pTmp,"system")==0)
|
|
{
|
|
dwCount += 8;
|
|
if (dwSize <= dwCount)
|
|
{ //Error
|
|
*lpBuf = '\0';
|
|
return 0;
|
|
}
|
|
lstrcat(lpBuf,"system32");
|
|
}
|
|
else
|
|
{
|
|
dwCount += lstrlen(pTmp);
|
|
if (dwSize <= dwCount)
|
|
{ // Error
|
|
*lpBuf = '\0';
|
|
return 0;
|
|
}
|
|
lstrcat(lpBuf,pTmp);
|
|
}
|
|
|
|
// Append the saved character to Output buffer also.
|
|
wsprintf(szTemp,"%c",chSave);
|
|
dwCount += lstrlen(szTemp);
|
|
if (dwSize <= dwCount)
|
|
{ // Error
|
|
*lpBuf = '\0';
|
|
return 0;
|
|
}
|
|
lstrcat(lpBuf, szTemp);
|
|
|
|
*pTmp2 = chSave;
|
|
pTmp = CharNext(pTmp2);
|
|
}
|
|
|
|
return dwCount;
|
|
}
|
|
|
|
LPWSTR MakeWideStrFromAnsi(LPSTR psz)
|
|
{
|
|
LPWSTR pwsz;
|
|
int i;
|
|
|
|
// arg checking.
|
|
//
|
|
if (!psz)
|
|
return NULL;
|
|
|
|
// compute the length of the required BSTR
|
|
//
|
|
i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
|
|
if (i <= 0) return NULL;
|
|
|
|
// allocate the widestr
|
|
//
|
|
pwsz = (LPWSTR) CoTaskMemAlloc(i * sizeof(WCHAR));
|
|
|
|
if (!pwsz)
|
|
return NULL;
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, i);
|
|
pwsz[i - 1] = 0;
|
|
return pwsz;
|
|
}
|