windows-nt/Source/XPSP1/NT/sdktools/checksym/utilityfunctions.cpp
2020-09-26 16:20:57 +08:00

1874 lines
52 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1999 - 2000
//
// File: utilityfunctions.cpp
//
//--------------------------------------------------------------------------
// UtilityFunctions.cpp: implementation of the CUtilityFunctions class.
//
//////////////////////////////////////////////////////////////////////
#ifndef NO_STRICT
#ifndef STRICT
#define STRICT 1
#endif
#endif /* NO_STRICT */
#include <WINDOWS.H>
#include <STDIO.H>
#include <TCHAR.H>
#include <stdlib.h>
#include "Globals.h"
#include "UtilityFunctions.h"
#include "ModuleInfo.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
typedef struct
{
LPTSTR tszEnvironmentVariable;
LPTSTR tszRegistryKey;
LPTSTR tszRegistryValue;
} ENVBLOCK;
ENVBLOCK g_tszEnvironmentVariables[] =
{
// Support for Exchange Server
TEXT("EXCHSRVR"),
TEXT("SOFTWARE\\Microsoft\\Exchange\\Setup"),
TEXT("Services"),
// Support for SNA Server
TEXT("SNASERVER"),
TEXT("SOFTWARE\\Microsoft\\Sna Server\\CurrentVersion"),
TEXT("PathName"),
// Support for SQL Server
TEXT("SQLSERVER"),
TEXT("SOFTWARE\\Microsoft\\MSSQLServer\\Setup"),
TEXT("SQLPath"),
// Support for SMS Server
TEXT("SMSSERVER"),
TEXT("SOFTWARE\\Microsoft\\SMS\\Identification"),
TEXT("Installation Directory"),
// Support for INETSRV Server
TEXT("INETSRV"),
TEXT("SOFTWARE\\Microsoft\\INetStp"),
TEXT("InstallPath"),
// Support for WSPSRV Server
TEXT("WSPSRV"),
TEXT("SYSTEM\\CurrentControlSet\\Services\\WSPSrv\\Parameters"),
TEXT("InstallRoot"),
NULL,
NULL,
NULL
};
CUtilityFunctions::CUtilityFunctions()
{
}
CUtilityFunctions::~CUtilityFunctions()
{
}
/*++
Function Name
LPTSTR CUtilityFunctions::ExpandPath(LPCTSTR tszInputPath)
Routine Description:
This routine copies the provided tszInputPath to a new
buffer which is returned to the caller. Any environment variables (or
pseudo-environment variables) included in the tszInputPath are expanded
before being copied to the destination string.
This routine allocates storage for the return string, it is the responsibility
of the caller to release it.
Arguments:
[IN] LPCTSTR tszInputString - Input string
Return Value:
[OUT ] LPTSTR Returns the new string
--*/
LPTSTR CUtilityFunctions::ExpandPath(LPCTSTR tszInputPath)
{
// Pointer to our input path buffer
LPCTSTR ptszInputPathPointer;
// Buffer to hold pre-translated Environment Variable
TCHAR tszEnvironmentVariableBuffer[MAX_PATH];
// Buffer to hold translated environment variables
TCHAR tszTranslatedEnvironmentVariable[MAX_PATH];
LPTSTR ptszTranslatedEnvironmentVariablePointer;
// Generic counter variable
ULONG iCharIndex;
// Buffer to hold Output Path
LPTSTR tszOutputPathBuffer, ptszOutputPathPointer;
ULONG iOutputPathBufferSize;
if (!tszInputPath) {
return(NULL);
}
// Setup our pointer to our input buffer
ptszInputPathPointer = tszInputPath;
#ifdef _DEBUG
// This puts stress on the re-alloc code...
iOutputPathBufferSize = MAX_PATH; // We need less stress here (numega has probs)
#else
iOutputPathBufferSize = _tcslen(tszInputPath) + MAX_PATH + 1;
#endif
// Create our output buffer...
//#ifdef _DEBUG
// _tprintf(TEXT("ExpandPath() - Output Buffer created\n"));
//#endif
ptszOutputPathPointer = tszOutputPathBuffer = new TCHAR[iOutputPathBufferSize];
if (!tszOutputPathBuffer)
{
return(NULL);
}
DWORD iTranslatedCharacters = 0;
// Loop through our input buffer until we're done...
while( ptszInputPathPointer && *ptszInputPathPointer)
{
// We're searching for % to designate the start of an env. var...
if (*ptszInputPathPointer == '%')
{
iCharIndex = 0;
// Advance to just beyond the % character
ptszInputPathPointer++;
// While we have more environment variable chars...
while (ptszInputPathPointer && *ptszInputPathPointer && *ptszInputPathPointer != '%')
{
// Copy the environment variable into our buffer
tszEnvironmentVariableBuffer[iCharIndex++] = *ptszInputPathPointer++;
}
// Advanced to just beyond the closing % character
ptszInputPathPointer++;
// Null terminate our Environment Variable Buffer
tszEnvironmentVariableBuffer[iCharIndex] = '\0';
// Setup the Translated Env. Variable Buffer
ptszTranslatedEnvironmentVariablePointer = tszTranslatedEnvironmentVariable;
*ptszTranslatedEnvironmentVariablePointer = 0;
// Translate the Environment Variables!
iTranslatedCharacters = GetEnvironmentVariable( tszEnvironmentVariableBuffer, ptszTranslatedEnvironmentVariablePointer, MAX_PATH );
// If we didn't translate anything... we need to look for this as a special env. variable...
if (iTranslatedCharacters == 0)
{
bool fSpecialEnvironmentVariable = false;
// Scan our special variables...
for (int i = 0; g_tszEnvironmentVariables[i].tszEnvironmentVariable && !fSpecialEnvironmentVariable; i++)
{
if (!_tcsicmp(g_tszEnvironmentVariables[i].tszEnvironmentVariable,
tszEnvironmentVariableBuffer) )
{
// MATCHES!!!!
HKEY hKey;
DWORD lpType = 0;
LONG Results = ERROR_SUCCESS;
DWORD lpcbData = MAX_PATH;
BYTE outBuf[MAX_PATH];
Results = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
g_tszEnvironmentVariables[i].tszRegistryKey,
0,
KEY_READ || KEY_QUERY_VALUE,
&hKey);
fSpecialEnvironmentVariable = (Results == ERROR_SUCCESS);
if (Results != ERROR_SUCCESS)
{
_tprintf(TEXT("ERROR: Unable to open registry key [%s]\n"), g_tszEnvironmentVariables[i].tszRegistryKey);
_tprintf(TEXT("ERROR: Unable to open registry key - Error = 0x%x\n"), Results);
}
if (fSpecialEnvironmentVariable)
{
// Now, read the value that has our install path...
Results = RegQueryValueEx(
hKey, // handle of key to query
g_tszEnvironmentVariables[i].tszRegistryValue, // address of name of value to query
NULL, // reserved
&lpType, // address of buffer for value type
outBuf, // address of data buffer
&lpcbData); // address of data buffer size
// Is it still succesful?
fSpecialEnvironmentVariable = ( (Results == ERROR_SUCCESS) &&
(lpType == REG_SZ) );
if (Results != ERROR_SUCCESS)
{
_tprintf(TEXT("ERROR: Registry key opened [%s]\n"), g_tszEnvironmentVariables[i].tszRegistryKey);
_tprintf(TEXT("ERROR: Unable to query registry value [%s]\n"), g_tszEnvironmentVariables[i].tszRegistryValue);
_tprintf(TEXT("ERROR: Unable to query registry value - Error = 0x%x\n"), Results);
}
// Copy only if we got something?
RegCloseKey(hKey);
}
if (fSpecialEnvironmentVariable)
{
// Copy the new data!!!
_tcscpy(tszTranslatedEnvironmentVariable, (LPTSTR)outBuf);
}
}
}
if (!fSpecialEnvironmentVariable)
{
#ifdef _DEBUG
_tprintf(TEXT("Unrecognized Environment variable found! [%%%s%%]\n"), tszEnvironmentVariableBuffer);
#endif
// Error copy the original environment variable provided back to the "translated env
// buffer to be copied back below...
_tcscpy(tszTranslatedEnvironmentVariable, TEXT("%"));
_tcscat(tszTranslatedEnvironmentVariable, tszEnvironmentVariableBuffer);
_tcscat(tszTranslatedEnvironmentVariable, TEXT("%"));
}
}
// Iterate through the Translated Env. Variable Buffer, and copy to the output buffer
while (ptszTranslatedEnvironmentVariablePointer && *ptszTranslatedEnvironmentVariablePointer)
{
// ISSUE-2000/07/24-GREGWI: Check to ensure this works properly *var++ changed to *(var++)
// Copy a char
*(ptszOutputPathPointer++) = *(ptszTranslatedEnvironmentVariablePointer++);
// If our output buffer is full, we need to allocate a new buffer...
if (ptszOutputPathPointer >= tszOutputPathBuffer + iOutputPathBufferSize)
{
// Bump up our new size by MAX_PATH
iOutputPathBufferSize += MAX_PATH;
// We need to enlarge the buffer our string is in...
tszOutputPathBuffer = ReAlloc(tszOutputPathBuffer, &ptszOutputPathPointer, iOutputPathBufferSize);
if (tszOutputPathBuffer == NULL)
return NULL;
}
}
}
// Probe to see if we're pointing at a NULL... this can happen if we've just completed
// environment variable expansion...
if ( *ptszInputPathPointer == '\0')
continue;
// Before we copy the char we're looking at... we need to test
// for a trailing backslash (\) on the end (which we'll silently remove)...
if ( (*ptszInputPathPointer == '\\') && // Do we have a slash
( (*(ptszInputPathPointer+1) == ';') || (*(ptszInputPathPointer+1) == '\0') ) && // and the next char is a NULL or semi-colon?
( ptszInputPathPointer != tszInputPath ) && // and we're not on the first char
( *(ptszInputPathPointer-1) != ':' ) // and the previous char is not a colon...
)
{
// Advance the pointer only... (remove the trailing slash)
*(ptszInputPathPointer++);
}
else
{
// ISSUE-2000/07/24-GREGWI: Ensure this works.. changing *var++ to *(var++)
// Copy a char from the input path, to the output path
*(ptszOutputPathPointer++) = *(ptszInputPathPointer++);
}
// If our output buffer is full, we need to allocate a new buffer...
if (ptszOutputPathPointer >= tszOutputPathBuffer + iOutputPathBufferSize)
{
// Bump up our new size by MAX_PATH
iOutputPathBufferSize += MAX_PATH;
// We need to enlarge the buffer our string is in...
tszOutputPathBuffer = ReAlloc(tszOutputPathBuffer, &ptszOutputPathPointer, iOutputPathBufferSize);
if (tszOutputPathBuffer == NULL)
return NULL;
}
}
// Null terminate our output buffer
*ptszOutputPathPointer = '\0';
// Return our results...
return tszOutputPathBuffer;
}
bool CUtilityFunctions::ContainsWildCardCharacter(LPCTSTR tszPathToSearch)
{
if (!tszPathToSearch)
return false;
LPCTSTR ptszPointer = tszPathToSearch;
while (*ptszPointer)
{
switch (*ptszPointer)
{
case '*':
case '?':
return true;
}
ptszPointer++;
}
return false;
}
/*
bool CUtilityFunctions::IsDirectoryPath(LPCTSTR tszFilePath)
{
if (!tszFilePath)
return false;
WIN32_FIND_DATA lpFindFileData;
HANDLE hFileOrDirectory = FindFirstFile(tszFilePath, &lpFindFileData);
if (INVALID_HANDLE_VALUE == hFileOrDirectory)
return false;
FindClose(hFileOrDirectory);
if (lpFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
return false;
}
*/
void CUtilityFunctions::PrintMessageString(DWORD dwMessageId)
{
// Define a constant for our "private" buffer...
enum {MESSAGE_BUFFER_SIZE = 1024};
TCHAR tszMessageBuffer[MESSAGE_BUFFER_SIZE];
DWORD dwBytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwMessageId,
0,
tszMessageBuffer,
MESSAGE_BUFFER_SIZE,
NULL);
if (dwBytes)
{
// We got something!
// Should we null terminate?
if ( (dwBytes > 2) &&
(tszMessageBuffer[dwBytes-2] == '\r') &&
(tszMessageBuffer[dwBytes-1] == '\n') )
{
tszMessageBuffer[dwBytes-2] = 0; // Null terminate this puppy...
}
_tprintf(TEXT("Error = %d (0x%x)\n[%s]\n"), dwMessageId, dwMessageId, tszMessageBuffer);
}
}
bool CUtilityFunctions::CopySymbolFileToSymbolTree(LPCTSTR tszImageModuleName, LPTSTR * lplptszOriginalPathToSymbolFile, LPCTSTR tszSymbolTreePath)
{
// Before we start to copying... is the source location already in the symbol tree we're going to build?
int iLengthOfFileName = _tcslen(*lplptszOriginalPathToSymbolFile);
int iLengthOfSymbolTreeToBuild = _tcslen(tszSymbolTreePath);
if (_tcsnicmp(*lplptszOriginalPathToSymbolFile,
tszSymbolTreePath,
iLengthOfFileName < iLengthOfSymbolTreeToBuild ?
iLengthOfFileName : iLengthOfSymbolTreeToBuild) )
{
// Okay, we need to take the original module name, and get the extension...
TCHAR tszExtension[_MAX_EXT];
TCHAR tszPathToCopySymbolFileTo[_MAX_PATH];
_tsplitpath(tszImageModuleName, NULL, NULL, NULL, tszExtension);
_tcscpy( tszPathToCopySymbolFileTo, tszSymbolTreePath);
// This directory should exist already... let's tag on the extension directory (if one exists)...
if (_tcsclen(tszExtension) > 1)
{
// Copy the extension (skipping the period)
_tcscat( tszPathToCopySymbolFileTo, &tszExtension[1] );
_tcscat( tszPathToCopySymbolFileTo, TEXT("\\") );
// Now, we need to ensure this directory exists (we'll cache these checks so we don't need to
// keep checking the same directory over and over...
if (!g_lpDelayLoad->MakeSureDirectoryPathExists(tszPathToCopySymbolFileTo) )
{
_tprintf(TEXT("ERROR: Unable to create symbol subdirectory [%s]\n"), tszPathToCopySymbolFileTo );
PrintMessageString(GetLastError());
}
}
TCHAR tszSymbolFileName[_MAX_FNAME];
TCHAR tszSymbolFileExt[_MAX_EXT];
_tsplitpath(*lplptszOriginalPathToSymbolFile, NULL, NULL, tszSymbolFileName, tszSymbolFileExt);
// Okay... it's time to copy the file!!!
_tcscat( tszPathToCopySymbolFileTo, tszSymbolFileName );
_tcscat( tszPathToCopySymbolFileTo, tszSymbolFileExt );
// We don't know if the destination file exists.. but if it does, we'll change
// the attributes (to remove the read-only bit at least
DWORD dwFileAttributes = GetFileAttributes(tszPathToCopySymbolFileTo);
if (dwFileAttributes != 0xFFFFFFFF)
{
if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
{
// The read-only attribute is set... we must remove it...
dwFileAttributes = dwFileAttributes & (~FILE_ATTRIBUTE_READONLY);
SetFileAttributes(tszPathToCopySymbolFileTo, dwFileAttributes);
}
}
if ( CopyFile(*lplptszOriginalPathToSymbolFile, tszPathToCopySymbolFileTo, FALSE) )
{
// Success!!! Let's go ahead and give a visual indicator as to where we copied
// the file from...
_tprintf(TEXT("VERIFIED: [%s] copied to Symbol Tree\n"), *lplptszOriginalPathToSymbolFile);
// Okay, since we've copied this to our symbol tree... we should update
// our modulepath...
// Nuke the old one...
delete [] *lplptszOriginalPathToSymbolFile;
// Copy in the new one...
*lplptszOriginalPathToSymbolFile = CopyString(tszPathToCopySymbolFileTo);
if (!*lplptszOriginalPathToSymbolFile)
return false;
} else
{
_tprintf(TEXT("ERROR: Unable to copy symbol file to [%s]\n"), tszPathToCopySymbolFileTo );
PrintMessageString(GetLastError());
}
}
return true;
}
/*++
Function Name
LPTSTR CUtilityFunctions::CopyString(LPCTSTR tszInputString)
Routine Description:
This routine copies the provided tszInputString to the destination address.
This routine allocates storage for the string, it is the responsibility
of the caller to release it.
Arguments:
[IN] LPCTSTR tszInputString - Input string
Return Value:
Returns the new string
--*/
LPTSTR CUtilityFunctions::CopyString(LPCTSTR tszInputString)
{
// Did we get a proper input string?
if (!tszInputString)
return NULL;
LPTSTR tszDestinationString = new TCHAR[(_tcsclen(tszInputString)+1)];
if (!tszDestinationString )
return NULL;
_tcscpy(tszDestinationString, tszInputString);
return tszDestinationString;
}
LPTSTR CUtilityFunctions::CopyAnsiStringToTSTR(LPCSTR szInputString, LPTSTR tszOutputBuffer, unsigned int iBufferLength)
{
// Did we get a proper input string?
if (!szInputString)
return NULL;
if (iBufferLength && !tszOutputBuffer)
return NULL;
LPTSTR tszDestinationString;
#ifdef _UNICODE
// Get the size of the source of the Ansi string...
// Saving the value keeps MultiByteToWideChar from having to
// calculate it twice...
unsigned int cbMultiByte = strlen(szInputString);
DWORD cbStringLength = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
szInputString,
cbMultiByte,
NULL,
0);
if (!cbStringLength)
return NULL;
// Do we need to allocate storage???
if (iBufferLength == 0)
{
// Allocate storage
tszDestinationString = new TCHAR[cbStringLength+1];
if (!tszDestinationString)
return NULL;
} else
{
if ( cbStringLength+1 > iBufferLength )
return NULL;
// Set the two strings to the same buffer...
tszDestinationString = tszOutputBuffer;
}
// Do the actual conversion
cbStringLength = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
szInputString,
cbMultiByte,
tszDestinationString,
(iBufferLength == 0) ? cbStringLength+1 : iBufferLength);
if (!cbStringLength)
return NULL;
tszDestinationString[cbStringLength] = '\0';
#else
unsigned int cbMultiByte = strlen(szInputString);
if (iBufferLength == 0)
{
iBufferLength = strlen(szInputString)+1;
tszDestinationString = new TCHAR[iBufferLength];
if (!tszDestinationString)
return NULL;
} else
{
if (cbMultiByte+1 > iBufferLength)
return NULL;
// Set the two strings to the same buffer...
tszDestinationString = tszOutputBuffer;
}
strncpy(tszDestinationString, szInputString, iBufferLength);
#endif
return tszDestinationString;
}
LPTSTR CUtilityFunctions::CopyUnicodeStringToTSTR(LPCWSTR wszInputString, LPTSTR tszOutputBuffer, unsigned int iBufferLength)
{
// Did we get a proper input string?
if (!wszInputString)
return NULL;
// Check for proper buffers and lengths if provided...
if (iBufferLength && !tszOutputBuffer)
return NULL;
LPTSTR tszDestinationString;
#ifdef _UNICODE
unsigned int cbMultiByte = wcslen(wszInputString);
if (iBufferLength == 0)
{
tszDestinationString = new TCHAR[wcslen(wszInputString)+1];
if (!tszDestinationString)
return NULL;
} else
{
if (cbMultiByte+1 > iBufferLength)
return NULL;
// Set the two strings to the same buffer...
tszDestinationString = tszOutputBuffer;
}
wcscpy(tszDestinationString, wszInputString);
#else
int cchWideChar = wcslen(wszInputString);
DWORD cbStringLength = WideCharToMultiByte( CP_ACP,
0,
wszInputString,
cchWideChar,
NULL,
0,
NULL,
NULL);
if (cbStringLength)
return NULL;
// Do we need to allocate storage???
if (iBufferLength == 0)
{
tszDestinationString = new TCHAR[cbStringLength+1];
if (!tszDestinationString)
return NULL;
} else
{
if ( cbStringLength+1 > iBufferLength )
return NULL;
// Set the two strings to the same buffer...
tszDestinationString = tszOutputBuffer;
}
// Do the actual conversion...
cbStringLength = WideCharToMultiByte( CP_ACP,
0,
wszInputString,
cchWideChar,
tszDestinationString,
(iBufferLength == 0) ? cbStringLength+1 : iBufferLength,
NULL,
NULL);
if (!cbStringLength)
return NULL;
tszDestinationString[cbStringLength] = '\0';
#endif
return tszDestinationString;
}
//
// CUtilityFunctions::CopyTSTRStringToAnsi()
//
// This routine copies from a TSTR source to an ANSI destination with optional allocation
// of the destination buffer... the default is to allocate storage, but if you provide
// a buffer length, we will assume it's available...
//
LPSTR CUtilityFunctions::CopyTSTRStringToAnsi(LPCTSTR tszInputString, LPSTR szOutputBuffer, unsigned int iBufferLength)
{
// Did we get a proper input string?
if (!tszInputString)
return NULL;
if (iBufferLength && !szOutputBuffer)
return NULL;
LPSTR szDestinationString;
#ifdef _UNICODE
// Get the size of the source of the Unicode string...
// Saving the value keeps WideCharToMultiByte from having to
// calculate it twice...
unsigned int cchWideChar = wcslen(tszInputString);
// This is a probe to see how much we'll be copying...
DWORD cbStringLength = WideCharToMultiByte( CP_ACP,
0,
tszInputString,
cchWideChar,
NULL,
0,
NULL,
NULL);
if (!cbStringLength)
return NULL;
// Do we need to allocate storage???
if (iBufferLength == 0)
{
// Allocate storage
szDestinationString = new char[cbStringLength+1];
if (!szDestinationString)
return NULL;
} else
{
if ( cbStringLength+1 > iBufferLength )
return NULL;
// Set the two strings to the same buffer...
szDestinationString = szOutputBuffer;
}
// Do the actual conversion
cbStringLength = WideCharToMultiByte( CP_ACP,
0,
tszInputString,
cchWideChar,
szDestinationString,
(iBufferLength == 0) ? cbStringLength+1 : iBufferLength,
NULL,
NULL);
if (!cbStringLength)
return NULL;
szDestinationString[cbStringLength] = '\0';
#else
unsigned int cchAnsiChar = strlen(tszInputString);
if (iBufferLength == 0)
{
szDestinationString = new char[cchAnsiChar+1]; // One extra for the NULL
if (!szDestinationString)
return NULL;
} else
{
if (cchAnsiChar+1 > iBufferLength)
return NULL;
// Set the two strings to the same buffer...
szDestinationString = szOutputBuffer;
}
strcpy(szDestinationString, tszInputString);
#endif
return szDestinationString;
}
LPWSTR CUtilityFunctions::CopyTSTRStringToUnicode(LPCTSTR tszInputString)
{
// Did we get a proper input string?
if (!tszInputString)
return NULL;
LPWSTR wszDestinationString;
#ifdef _UNICODE
wszDestinationString = new TCHAR[wcslen(tszInputString)+1];
if (!wszDestinationString)
return NULL;
wcscpy(wszDestinationString, tszInputString);
#else
int cbMultiByte = strlen(tszInputString);
DWORD cbStringLength = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
tszInputString,
cbMultiByte,
NULL,
0);
if (!cbStringLength)
return NULL;
wszDestinationString = new wchar_t[cbStringLength+1];
if (!wszDestinationString)
return NULL;
cbStringLength = MultiByteToWideChar( CP_ACP,
MB_PRECOMPOSED,
tszInputString,
cbMultiByte,
wszDestinationString,
cbStringLength+1);
wszDestinationString[cbStringLength] = '\0';
#endif
return wszDestinationString;
}
/*++
HANDLE CUtilityFunctions::FindDebugInfoFileEx2(
[IN] LPTSTR tszFileName,
[IN] LPTSTR SymbolPath,
[IN] PFIND_DEBUG_FILE_CALLBACK Callback,
[IN] PVOID CallerData
Routine Description:
The rules are, the name of the DBG/PDB file being searched for is provided,
and when found the routine returns a file handle to it... if a callback is
provided then the callback is invoked and a decision is made to return the
file handle based on the callback response...
Arguments:
tszFileName - Supplies a symbol name to search for.
SymbolPath - semi-colon delimited
DebugFilePath -
Callback - May be NULL. Callback that indicates whether the Symbol file is valid, or whether
the function should continue searching for another Symbol file.
The callback returns TRUE if the Symbol file is valid, or FALSE if the function should
continue searching.
CallerData - May be NULL. Data passed to the callback.
Return Value:
The handle for the DBG/PDB file if any...
In an effort to emulate FindDebugInfoFile(), this function will return 0 on failure or
the handle to the file otherwise...
--*/
HANDLE CUtilityFunctions::FindDebugInfoFileEx2(LPTSTR tszFileName, LPTSTR SymbolPath, PFIND_DEBUG_FILE_CALLBACK Callback, PVOID CallerData)
{
HANDLE FileHandle = INVALID_HANDLE_VALUE;
bool fProcessPath = true;
bool fScavengeSuccessful = false;
LPTSTR tszSymbolPathStart, tszSymbolPathEnd;
tszSymbolPathStart = SymbolPath;
// Find the end of the path
tszSymbolPathEnd = _tcschr( tszSymbolPathStart, ';' );
// If tszSymbolPathEnd is non-zero, then there is another path following...
if (tszSymbolPathEnd)
*tszSymbolPathEnd = '\0'; // Change the ';' to a Null temporarily...
while (fProcessPath)
{
//#ifdef _DEBUG
// _tprintf(TEXT("\n\nProcessing Path [%s]\n"), tszSymbolPathStart);
//#endif
// Begin the "madness"... ;)
// Search until we make a perfect hit... construct the directory path...
TCHAR tszSymbolPath[_MAX_PATH];
// Copy what we have...
_tcscpy(tszSymbolPath, tszSymbolPathStart);
// We should have at least a few chars to search on...
if (_tcslen(tszSymbolPath) < 2)
{
// Repair the search string if needed...
if (tszSymbolPathEnd)
{
*tszSymbolPathEnd = ';';
}
break;
};
fScavengeSuccessful = ScavengeForSymbolFiles(tszSymbolPath, tszFileName, Callback, CallerData, &FileHandle, 1);
// Repair the search string now!
if (tszSymbolPathEnd)
{
*tszSymbolPathEnd = ';';
}
// If were successful on our hunt or there is no symbol path left to search... break...
if (fScavengeSuccessful || !tszSymbolPathEnd)
{
break;
} else
{
// Advance to next string
tszSymbolPathStart = tszSymbolPathEnd + 1;
tszSymbolPathEnd = _tcschr( tszSymbolPathStart, ';' );
if (tszSymbolPathEnd)
{
*tszSymbolPathEnd = '\0';
};
}
}
return ( (FileHandle == INVALID_HANDLE_VALUE) ? 0 : FileHandle);
}
/*++
bool CUtilityFunctions::ScavengeForSymbolFiles(
[IN] LPCTSTR tszSymbolPathStart,
[IN] LPCTSTR tszSymbolToSearchFor,
[IN] PFIND_DEBUG_FILE_CALLBACK Callback,
[IN] PVOID CallerData,
[OUT] LPHANDLE lpFileHandle,
[IN] int iRecurseDepth )
Routine Description:
This routine is used to perform a recursive search for a Symbol File
(tszSymbolToSearchFor). The routine will do a depth search, looking
for the symbol at a current depth before going into sub-directories...
If a Callback function is provided, then it will be invoked when the
file we're looking for (by name) has been successfully opened. It is
unknown to this routine, however, if the file we found is actually the
correct one... the callback function's responsibility is to perform this
evaluation and return to use success/failure. If failure (then we continue
searching), if success (or no callback) then we return the filehandle
associated with the file we found.
It is the responsibility of the caller of this function to close any file
handle returned.
Arguments:
tszSymbolPathStart - This is the directory to search
tszSymbolToSearchFor - This is the symbol we're searching for
Callback - May be NULL. This is a function used to evaluate if the symbol found is correct.
CallerData - May be NULL. This data is passed to the callback (it is typically a CModuleInfo *)
lpfileHandle - This is the file handle for the file found (if any)
iRecurseDepth - This is the current depth of our search (defaults to 0)
Return Value:
The handle for the DBG/PDB file if any...
--*/
bool CUtilityFunctions::ScavengeForSymbolFiles(LPCTSTR tszSymbolPathStart, LPCTSTR tszSymbolToSearchFor, PFIND_DEBUG_FILE_CALLBACK Callback, PVOID CallerData, LPHANDLE lpFileHandle, int iRecurseDepth )
{
bool fSuccess = false;
// Bale if we're in too deep...
if (iRecurseDepth > MAX_RECURSE_DEPTH)
return fSuccess;
TCHAR tszFileBuffer[MAX_PATH+1];
//
// First, we'll look to see if we can open the file we're looking for AT this directory location
//
_tcscpy(tszFileBuffer, tszSymbolPathStart);
if (tszFileBuffer[_tcslen(tszFileBuffer)] != '\\') // Do we need a backslash separator?
_tcscat(tszFileBuffer, TEXT("\\"));
_tcscat(tszFileBuffer, tszSymbolToSearchFor);
if (g_lpProgramOptions->fDebugSearchPaths())
{
_tprintf(TEXT("DBG/PDB Search - Search here [%s]\n"), tszFileBuffer);
}
// Attempt to open the file...
*lpFileHandle = CreateFile( tszFileBuffer,
GENERIC_READ,
(FILE_SHARE_READ | FILE_SHARE_WRITE),
NULL,
OPEN_EXISTING,
0,
NULL
);
// Did we open it?
if (*lpFileHandle != INVALID_HANDLE_VALUE)
{
// Yes!
// If no callback... then we need to exit on out...
if (!Callback)
{
// Assume success (well... we found a symbol file you asked for)
fSuccess = true;
} else
{
fSuccess = (TRUE == Callback(*lpFileHandle, tszFileBuffer, CallerData));
}
// Return from here only on success!
if (fSuccess)
return fSuccess;
}
// We either did NOT find the file, or we found a file but it was not the right one...
//
// Second, we search for sub-directories, invoking this function for each sub-dir we find...
//
TCHAR drive[_MAX_DRIVE];
TCHAR dir[_MAX_DIR];
TCHAR fname[_MAX_FNAME];
TCHAR ext[_MAX_EXT];
//
// Compose the path to search...
//
_tcscpy(tszFileBuffer, tszSymbolPathStart);
if (tszFileBuffer[_tcslen(tszFileBuffer)-1] != '\\') // Do we need a backslash separator?
_tcscat(tszFileBuffer, TEXT("\\"));
_tcscat(tszFileBuffer, TEXT("*.*"));
// We want the component parts for later (so we can compose the full path)
_tsplitpath(tszFileBuffer, drive, dir, fname, ext);
WIN32_FIND_DATA lpFindFileData;
// Okay, begin the search...
HANDLE hFileOrDirectoryHandle = FindFirstFile(tszFileBuffer, &lpFindFileData);
while ( INVALID_HANDLE_VALUE != hFileOrDirectoryHandle )
{
if (lpFindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Check to see if we've got the . or .. directories!
if ( ( 0 == _tcscmp(lpFindFileData.cFileName, TEXT(".")) ) ||
( 0 == _tcscmp(lpFindFileData.cFileName, TEXT("..")) )
)
{
goto getnextmodule;
}
// Compose the path to the directory...
_tmakepath(tszFileBuffer, drive, dir, NULL, NULL);
_tcscat(tszFileBuffer, lpFindFileData.cFileName);
// Look to see if we can find the file we're after!
fSuccess = ScavengeForSymbolFiles(tszFileBuffer, tszSymbolToSearchFor, Callback, CallerData, lpFileHandle, iRecurseDepth+1 );
// On success from ScavengeForSymbolFiles, we have a file handle (hopefully the right one).
// We want to terminate our recursive search
if (fSuccess)
break;
};
getnextmodule:
if (!FindNextFile(hFileOrDirectoryHandle, &lpFindFileData))
break;
}
if ( INVALID_HANDLE_VALUE != hFileOrDirectoryHandle )
FindClose(hFileOrDirectoryHandle);
return fSuccess;
}
LPTSTR CUtilityFunctions::ReAlloc(LPTSTR tszOutputPathBuffer, LPTSTR * ptszOutputPathPointer, size_t size)
{
// Save our old size... and position in the buffer...
UINT iOldOutputPathBufferSize = (*ptszOutputPathPointer)-tszOutputPathBuffer;
// Allocate our new bigger buffer...
LPTSTR ptszNewOutputPathBuffer = new TCHAR[size];
// Did we fail to allocate the new buffer?
if (ptszNewOutputPathBuffer == NULL)
return(NULL);
#ifdef _DEBUG
// This bogus code is here to protect a string copy which should always work...
// but Numega Bounds Checker will sometimes AV in here... and we have to protect
// ourselves or else it will appear we're leaking way above...
__try
{
#endif
// Now, we should copy from the old to the new buffer...
_tcsncpy(ptszNewOutputPathBuffer, tszOutputPathBuffer, iOldOutputPathBufferSize);
#ifdef _DEBUG
} __except(EXCEPTION_EXECUTE_HANDLER)
{
_tprintf(TEXT("ReAlloc() - Exception Hit during stringcopy!!!\n"));
}
#endif
// Calculate our position in our new buffer
*ptszOutputPathPointer = ptszNewOutputPathBuffer + iOldOutputPathBufferSize;
// Delete the old buffer
delete [] tszOutputPathBuffer;
return ptszNewOutputPathBuffer;
}
bool CUtilityFunctions::UnMungePathIfNecessary(LPTSTR tszPossibleBizarrePath)
{
/*
// We have three known odd-ball cases...
\SystemRoot\System32\smss.exe
\??\C:\WINNT\system32\winlogon.exe
\WINNT\System32\ntoskrnl.exe
*/
if (tszPossibleBizarrePath[0] != '\\')
return false; // Isn't a bizarre path (one we know about anyway)...
// Setup Variables to Use
TCHAR tszTempPath[_MAX_PATH], tszExpandedSystemRoot[_MAX_PATH];
const TCHAR tszSystemRoot[] = TEXT("\\SystemRoot");
const unsigned int iSystemRootLength = _tcslen(tszSystemRoot);
const TCHAR tszNameSpace[] = TEXT("\\??\\");
const unsigned int iNameSpaceLength = _tcslen(tszNameSpace);
ExpandEnvironmentStrings(TEXT("%systemroot%"), tszExpandedSystemRoot, _MAX_PATH);
const unsigned int iExpandedSystemRoot = _tcslen(tszExpandedSystemRoot);
/*
#ifdef _DEBUG
_tprintf(TEXT("Bizarre module path found! [%s]\n"), tszPossibleBizarrePath);
#endif
*/
if ( _tcsnicmp(tszPossibleBizarrePath, tszSystemRoot, iSystemRootLength) == 0)
{ // We have a match...
/*
#ifdef _DEBUG
_tprintf(TEXT("Matches [%s] sequence...\n"), tszSystemRoot);
#endif
*/
// We simply replace \systemroot with %systemroot% and expand the
// environement variables
LPTSTR tszPointer = tszPossibleBizarrePath;
for (unsigned int i = 0; i < iSystemRootLength; i++)
{
// Advance by the name space length...
tszPointer = CharNext(tszPointer);
}
_tcscpy(tszTempPath, TEXT("%systemroot%"));
_tcscat(tszTempPath, tszPointer);
ExpandEnvironmentStrings(tszTempPath, tszPossibleBizarrePath, _MAX_PATH);
/*
#ifdef _DEBUG
_tprintf(TEXT("Bizarre module path changed to [%s]\n"), tszPossibleBizarrePath);
#endif
*/
} else
if (_tcsnicmp(tszPossibleBizarrePath, tszNameSpace, iNameSpaceLength) == 0)
{ // We have a match...
/*
#ifdef _DEBUG
_tprintf(TEXT("Matches [%s] sequence...\n"), tszNameSpace);
#endif
*/
// We simply remove the \??\ sequence from the namespace...
LPTSTR tszPointer = tszPossibleBizarrePath;
for (unsigned int i = 0; i < iNameSpaceLength; i++)
{
// Advance by the name space length...
tszPointer = CharNext(tszPointer);
}
// We have to do this double copy since the strings would overlap
_tcscpy(tszTempPath, tszPointer);
_tcscpy(tszPossibleBizarrePath, tszTempPath);
/*
#ifdef _DEBUG
_tprintf(TEXT("Bizarre module path changed to [%s]\n"), tszPossibleBizarrePath);
#endif
*/
} else
if (( iExpandedSystemRoot > 2) && _tcsnicmp(tszPossibleBizarrePath, &tszExpandedSystemRoot[2], iExpandedSystemRoot-2) == 0)
{ // We need to match on the SystemRoot (without the SystemDrive)
/*
#ifdef _DEBUG
_tprintf(TEXT("Matches [%s] sequence...\n"), tszSystemRoot);
#endif
*/
// This little algorithm assumes that the Drive Letter is a single char...
_tcscpy(tszTempPath, tszExpandedSystemRoot);
_tcscat(tszTempPath, &tszPossibleBizarrePath[iExpandedSystemRoot-2]);
_tcscpy(tszPossibleBizarrePath, tszTempPath);
/*
#ifdef _DEBUG
_tprintf(TEXT("Bizarre module path changed to [%s]\n"), tszPossibleBizarrePath);
#endif
*/
}
return true;
}
bool CUtilityFunctions::FixupDeviceDriverPathIfNecessary(LPTSTR tszPossibleBaseDeviceDriverName, unsigned int iBufferLength)
{
TCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
// First, split the device driver name up into it's component parts...
_tsplitpath(tszPossibleBaseDeviceDriverName, drive, dir, fname, ext);
// Second, look to see if it's missing the drive and dir...
if ( _tcsicmp(drive, TEXT("")) || _tcsicmp(dir, TEXT("")) )
return true;
// Third, create a new path... assuming that we'll find device drivers in the %systemroot%\system32\drivers directory
TCHAR tszTempBuffer[_MAX_PATH];
_tcscpy(tszTempBuffer, TEXT("%systemroot%\\system32\\drivers\\"));
_tcscat(tszTempBuffer, tszPossibleBaseDeviceDriverName);
ExpandEnvironmentStrings(tszTempBuffer, tszPossibleBaseDeviceDriverName, iBufferLength);
return true;
}
// This function is provided in a Windows 2000 (NT 5.0) Version of IMAGEHLP.DLL. By adding
// this function manually, I should run fine on NT 4.0 (and possibly Win9x)
/*++
Routine Description:
The rules are:
if Filename doesn't have a .dbg extension
Look for
1. <SymbolPath>\Symbols\<ext>\<filename>.dbg
2. <SymbolPath>\Symbols\<ext>\<filename>.sym
3. <SymbolPath>\<ext>\<filename>.dbg
4. <SymbolPath>\<ext>\<filename>.sym
5. <SymbolPath>\<filename>.dbg
6. <SymbolPath>\<filename>.sym
7. <FileNamePath>\<filename>.dbg
8. <FileNamePath>\<filename>.sym
if it does, skip the .sym lookup.
Arguments:
tszFileName - Supplies a file name in one of three forms: fully qualified,
<ext>\<filename>.dbg, or just filename.dbg
SymbolPath - semi-colon delimited
DebugFilePath -
Callback - May be NULL. Callback that indicates whether the Symbol file is valid, or whether
the function should continue searching for another Symbol file.
The callback returns TRUE if the Symbol file is valid, or FALSE if the function should
continue searching.
CallerData - May be NULL. Data passed to the callback.
Return Value:
The name of the Symbol file (either .dbg or .sym) and a handle to that file.
--*/
HANDLE CUtilityFunctions::FindDebugInfoFileEx(LPTSTR tszFileName, LPTSTR SymbolPath, LPTSTR DebugFilePath, PFIND_DEBUG_FILE_CALLBACK Callback, PVOID CallerData)
{
return fnFindDebugInfoFileEx(tszFileName,
SymbolPath,
DebugFilePath,
Callback,
CallerData,
0);
}
/*++
Routine Description:
The rules are:
Look for
1. <SymbolPath>\Symbols\<ext>\<filename>.dbg
3. <SymbolPath>\<ext>\<filename>.dbg
5. <SymbolPath>\<filename>.dbg
7. <FileNamePath>\<filename>.dbg
Arguments:
tszFileName - Supplies a file name in one of three forms: fully qualified,
<ext>\<filename>.dbg, or just filename.dbg
SymbolPath - semi-colon delimited
DebugFilePath -
Callback - May be NULL. Callback that indicates whether the Symbol file
is valid, or whether
the function should continue searching for another Symbol file.
The callback returns TRUE if the Symbol file is valid, or FALSE if
the function should
continue searching.
CallerData - May be NULL. Data passed to the callback.
Flag - indicates that PDBs shouldn't be searched for
Return Value:
The name of the Symbol file (either .dbg or .sym) and a handle to that file.
--*/
HANDLE
CUtilityFunctions::fnFindDebugInfoFileEx(
IN LPTSTR tszFileName,
IN LPTSTR SymbolPath,
OUT LPTSTR DebugFilePath,
IN PFIND_DEBUG_FILE_CALLBACK Callback,
IN PVOID CallerData,
IN DWORD flag
)
{
HANDLE FileHandle = INVALID_HANDLE_VALUE;
LPTSTR ExpSymbolPath = NULL, SymPathStart, PathEnd;
DWORD ShareAttributes, cnt;
LPTSTR InitialPath = NULL, Sub1 = NULL, Sub2 = NULL;
TCHAR FilePath[_MAX_PATH + 1];
TCHAR Drive[_MAX_DRIVE], Dir[_MAX_DIR], FilePart[_MAX_FNAME], Ext[_MAX_EXT];
TCHAR *ExtDir;
BOOL found = FALSE;
BOOL symsrv = TRUE;
bool fDebugSearchPaths = g_lpProgramOptions->fDebugSearchPaths();
//if (OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
if (g_lpProgramOptions->IsRunningWindowsNT())
{
ShareAttributes = (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE);
} else {
ShareAttributes = (FILE_SHARE_READ | FILE_SHARE_WRITE);
}
__try {
*DebugFilePath = '\0';
// Step 1. What do we have?
_tsplitpath(tszFileName, Drive, Dir, FilePart, Ext);
if (!_tcsicmp(Ext, TEXT(".dbg"))) {
// We got a filename of the form: ext\filename.dbg. Dir holds the extension already.
ExtDir = Dir;
} else {
// Otherwise, skip the period and null out the Dir.
ExtDir = CharNext(Ext);
}
ExpSymbolPath = ExpandPath(SymbolPath);
SymPathStart = ExpSymbolPath;
cnt = 0;
do {
PathEnd = _tcschr( SymPathStart, ';' );
if (PathEnd) {
*PathEnd = '\0';
}
if (!_tcsnicmp(SymPathStart, TEXT("SYMSRV*"), 7)) {
*DebugFilePath = 0;
if (symsrv && CallerData)
{
_tcscpy(FilePath, FilePart);
_tcscat(FilePath, TEXT(".dbg"));
CModuleInfo * lpModuleInfo = (CModuleInfo *)CallerData;
if (fDebugSearchPaths)
{
_tprintf(TEXT("DBG Search - SYMSRV [%s,0x%x,0x%x]\n"),
SymPathStart,
lpModuleInfo->GetPEImageTimeDateStamp(),
lpModuleInfo->GetPEImageSizeOfImage());
}
GetSymbolFileFromServer(SymPathStart,
FilePath,
lpModuleInfo->GetPEImageTimeDateStamp(),
lpModuleInfo->GetPEImageSizeOfImage(),
0,
DebugFilePath);
symsrv = FALSE;
}
} else {
switch (cnt) {
case 0: // <SymbolPath>\symbols\<ext>\<filename>.ext
InitialPath = SymPathStart;
Sub1 = TEXT("symbols");
Sub2 = ExtDir;
break;
case 1: // <SymbolPath>\<ext>\<filename>.ext
InitialPath = SymPathStart;
Sub1 = TEXT("");
Sub2 = ExtDir;
break;
case 2: // <SymbolPath>\<filename>.ext
InitialPath = SymPathStart;
Sub1 = TEXT("");
Sub2 = TEXT("");
break;
case 3: // <FileNamePath>\<filename>.ext - A.K.A. what was passed to us
InitialPath = Drive;
Sub1 = TEXT("");
Sub2 = Dir;
// this stops us from checking out everything in the sympath
cnt++;
break;
}
// build fully-qualified filepath to look for
_tcscpy(FilePath, InitialPath);
EnsureTrailingBackslash(FilePath);
_tcscat(FilePath, Sub1);
EnsureTrailingBackslash(FilePath);
_tcscat(FilePath, Sub2);
EnsureTrailingBackslash(FilePath);
_tcscat(FilePath, FilePart);
_tcscpy(DebugFilePath, FilePath);
_tcscat(DebugFilePath, TEXT(".dbg"));
}
// try to open the file
if (*DebugFilePath) {
//#ifdef _DEBUG
// _tprintf(TEXT("FindDebugInfoFileEx-> Looking for %s... "), DebugFilePath);
//#endif
if (fDebugSearchPaths)
{
_tprintf(TEXT("DBG Search - Search here [%s]\n"), DebugFilePath);
}
FileHandle = CreateFile(DebugFilePath,
GENERIC_READ,
ShareAttributes,
NULL,
OPEN_EXISTING,
0,
NULL);
// if the file opens, bail from this loop
if (FileHandle != INVALID_HANDLE_VALUE)
{
found = TRUE;
// If a callback exists... call it...
if (!Callback)
{
break;
} else if (Callback(FileHandle, DebugFilePath, CallerData))
{
break;
} else {
//#ifdef _DEBUG
// _tprintf(TEXT("mismatched timestamp\n"));
//#endif
CloseHandle(FileHandle);
FileHandle = INVALID_HANDLE_VALUE;
}
}
// if file is open, bail from this loop too - else continue
if (FileHandle != INVALID_HANDLE_VALUE)
break;
}
// go to next item in the sympath
if (PathEnd) {
*PathEnd = ';';
SymPathStart = PathEnd + 1;
symsrv = TRUE;
} else {
SymPathStart = ExpSymbolPath;
cnt++;
}
} while (cnt < 4);
} __except(EXCEPTION_EXECUTE_HANDLER)
{
if (FileHandle != INVALID_HANDLE_VALUE) {
CloseHandle(FileHandle);
}
FileHandle = INVALID_HANDLE_VALUE;
}
if (ExpSymbolPath)
{
delete [] ExpSymbolPath;
ExpSymbolPath = NULL;
}
if (FileHandle == INVALID_HANDLE_VALUE)
{
FileHandle = NULL;
DebugFilePath[0] = '\0';
}
if (!FileHandle // if we didn't get the right file...
&& found // but we found some file...
&& (flag & fdifRECURSIVE)) // and we were told to run recursively...
{
// try again without timestamp checking
FileHandle = fnFindDebugInfoFileEx(tszFileName,
SymbolPath,
FilePath,
NULL,
0,
flag);
if (FileHandle && FileHandle != INVALID_HANDLE_VALUE)
_tcscpy(DebugFilePath, FilePath);
}
return FileHandle;
}
void
CUtilityFunctions::EnsureTrailingBackslash(
LPTSTR tsz
)
{
int i;
i = _tcslen(tsz);
if (!i)
return;
if (tsz[i - 1] == '\\')
return;
tsz[i] = '\\';
tsz[i + 1] = '\0';
}
bool CUtilityFunctions::GetSymbolFileFromServer(
LPCTSTR tszServerInfo,
LPCTSTR tszFileName,
DWORD num1,
DWORD num2,
DWORD num3,
LPTSTR tszFilePath
)
{
TCHAR tszSrvName[_MAX_PATH * 2];
LPTSTR tszParams;
bool rc = false;
LPSTR szParams = NULL;
char szFilePath[_MAX_PATH+1]; // Temporary file buffer (for returned data)
LPSTR szFileName = NULL;
// It's a little extra work... but let's extract the SYMSRV DLL name
// so we can see if we're already loaded (by name)..
// Copy the new server name in...
_tcscpy(tszSrvName, &tszServerInfo[7]);
if (!(*tszSrvName))
goto cleanup;
// Parameters start after the separator
tszParams = _tcschr(tszSrvName, '*');
if (!tszParams)
goto cleanup;
// Null terminate and advance...
*(tszParams++) = '\0';
// Determine if this SYMSRV compatible DLL is the same
// as the one we have loaded already... (if one is loaded)
if( !g_lpDelayLoad->GetCurrentSymSrvDLL() ||
_tcscmp(g_lpDelayLoad->GetCurrentSymSrvDLL(), tszSrvName))
{
if (!g_lpDelayLoad->Initialize_SYMSRV(tszSrvName))
goto cleanup;
}
tszParams = _tcschr(tszServerInfo, '*');
if (!tszParams)
goto cleanup;
tszParams = _tcschr(tszParams+1, '*');
if (!tszParams)
goto cleanup;
// Ready to make the call... need to convert to lame ANSI for the function call...
szParams = CopyTSTRStringToAnsi(tszParams+1);
szFileName = CopyTSTRStringToAnsi(tszFileName);
rc = (TRUE == g_lpDelayLoad->SymbolServer(szParams, szFileName, num1, num2, num3, szFilePath));
if (rc)
{
tszFilePath = CopyAnsiStringToTSTR(szFilePath, tszFilePath, _MAX_PATH+1);
}
cleanup:
if (szParams)
delete [] szParams;
if (szFileName)
delete [] szFileName;
return rc;
}
//
// Taken from UTF8.CPP (from the VC Linker code)
//
#define BIT7(a) ((a) & 0x80)
#define BIT6(a) ((a) & 0x40)
#define LOWER_6_BIT(u) ((u) & 0x003f)
#define HIGH_SURROGATE_START 0xd800
#define LOW_SURROGATE_START 0xdc00
////////////////////////////////////////////////////////////////////////////
//
// UTF8ToUnicode
//
// Maps a UTF-8 character string to its wide character string counterpart.
//
// 02-06-96 JulieB Created.
////////////////////////////////////////////////////////////////////////////
size_t CUtilityFunctions::UTF8ToUnicode(
LPCSTR lpSrcStr,
LPWSTR lpDestStr,
size_t cchDest)
{
return UTF8ToUnicodeCch(lpSrcStr, strlen(lpSrcStr) + 1, lpDestStr, cchDest);
}
#pragma warning( push )
#pragma warning( disable : 4244 ) // conversion from 'int' to 'unsigned short', possible loss of data
size_t CUtilityFunctions::UTF8ToUnicodeCch(
LPCSTR lpSrcStr,
size_t cchSrc,
LPWSTR lpDestStr,
size_t cchDest)
{
int nTB = 0; // # trail bytes to follow
size_t cchWC = 0; // # of Unicode code points generated
LPCSTR pUTF8 = lpSrcStr;
DWORD dwSurrogateChar = 0; // Full surrogate char
BOOL bSurrogatePair = FALSE; // Indicate we'r collecting a surrogate pair
char UTF8;
while ((cchSrc--) && ((cchDest == 0) || (cchWC < cchDest)))
{
//
// See if there are any trail bytes.
//
if (BIT7(*pUTF8) == 0)
{
//
// Found ASCII.
//
if (cchDest)
{
lpDestStr[cchWC] = (WCHAR)*pUTF8;
}
bSurrogatePair = FALSE;
cchWC++;
}
else if (BIT6(*pUTF8) == 0)
{
//
// Found a trail byte.
// Note : Ignore the trail byte if there was no lead byte.
//
if (nTB != 0)
{
//
// Decrement the trail byte counter.
//
nTB--;
if (bSurrogatePair)
{
dwSurrogateChar <<= 6;
dwSurrogateChar |= LOWER_6_BIT(*pUTF8);
if (nTB == 0)
{
if (cchDest)
{
if ((cchWC + 1) < cchDest)
{
lpDestStr[cchWC] = (WCHAR)
(((dwSurrogateChar - 0x10000) >> 10) + HIGH_SURROGATE_START);
lpDestStr[cchWC+1] = (WCHAR)
((dwSurrogateChar - 0x10000)%0x400 + LOW_SURROGATE_START);
}
}
cchWC += 2;
bSurrogatePair = FALSE;
}
}
else
{
//
// Make room for the trail byte and add the trail byte
// value.
//
if (cchDest)
{
lpDestStr[cchWC] <<= 6;
lpDestStr[cchWC] |= LOWER_6_BIT(*pUTF8);
}
if (nTB == 0)
{
//
// End of sequence. Advance the output counter.
//
cchWC++;
}
}
}
else
{
// error - not expecting a trail byte
bSurrogatePair = FALSE;
}
}
else
{
//
// Found a lead byte.
//
if (nTB > 0)
{
//
// Error - previous sequence not finished.
//
nTB = 0;
bSurrogatePair = FALSE;
cchWC++;
}
else
{
//
// Calculate the number of bytes to follow.
// Look for the first 0 from left to right.
//
UTF8 = *pUTF8;
while (BIT7(UTF8) != 0)
{
UTF8 <<= 1;
nTB++;
}
//
// If this is a surrogate unicode pair
//
if (nTB == 4)
{
dwSurrogateChar = UTF8 >> nTB;
bSurrogatePair = TRUE;
}
//
// Store the value from the first byte and decrement
// the number of bytes to follow.
//
if (cchDest)
{
lpDestStr[cchWC] = UTF8 >> nTB;
}
nTB--;
}
}
pUTF8++;
}
//
// Make sure the destination buffer was large enough.
//
if (cchDest && cchSrc != (size_t)-1)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
//
// Return the number of Unicode characters written.
//
return cchWC;
}
#pragma warning( pop )