Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1005 lines
25 KiB

#include "util.h"
#include "patchdownload.h"
#include "sdsutils.h"
extern "C"
{
#include "crc32.h"
}
#define CR 13
HANDLE g_hLogFile = NULL;
extern HINF g_hInf;
extern HINSTANCE g_hInstance;
struct LangID
{
DWORD dwLangID;
char szLanguage[3];
};
const LangID g_LangID [] =
{
{0x404, "TW"},
{0x804, "CN"},
{0x405, "CS"},
{0x406, "DA"},
{0x413, "NL"},
{0x409, "EN"},
{0x40B, "FI"},
{0x40C, "FR"},
{0x407, "DE"},
{0x408, "EL"},
{0x40E, "HU"},
{0x410, "IT"},
{0x411, "JA"},
{0x412, "KO"},
{0x414, "NO"},
{0x415, "PL"},
{0x416, "BR"},
{0x816, "PT"},
{0x419, "RU"},
{0x424, "SL"},
{0xC0A, "ES"},
{0x41D, "SV"},
{0x41E, "TH"},
{0x41F, "TR"},
{0x42A, "VI"},
{0x41B, "SK"},
{0x401, "AR"},
{0x403, "CA"},
{0x42D, "EU"},
{0x40D, "HE"},
{0x40F, "IS"},
{-1, NULL}
};
extern PFSetupFindFirstLine pfSetupFindFirstLine;
extern PFSetupGetStringField pfSetupGetStringField;
extern PFSetupDecompressOrCopyFile pfSetupDecompressOrCopyFile;
PVOID __fastcall MyVirtualAlloc(ULONG Size)
{
return VirtualAlloc( NULL, Size, MEM_COMMIT, PAGE_READWRITE );
}
VOID __fastcall MyVirtualFree(PVOID Allocation)
{
VirtualFree( Allocation, 0, MEM_RELEASE );
}
extern "C" HANDLE CreateSubAllocator(IN ULONG InitialCommitSize, IN ULONG GrowthCommitSize)
{
PSUBALLOCATOR SubAllocator;
ULONG InitialSize;
ULONG GrowthSize;
InitialSize = ROUNDUP2( InitialCommitSize, MINIMUM_VM_ALLOCATION );
GrowthSize = ROUNDUP2( GrowthCommitSize, MINIMUM_VM_ALLOCATION );
SubAllocator = (PSUBALLOCATOR)MyVirtualAlloc( InitialSize );
//
// If can't allocate entire initial size, back off to minimum size.
// Very large initial requests sometimes cannot be allocated simply
// because there is not enough contiguous address space.
//
if ( SubAllocator == NULL )
{
SubAllocator = (PSUBALLOCATOR)MyVirtualAlloc( GrowthSize );
}
if ( SubAllocator == NULL )
{
SubAllocator = (PSUBALLOCATOR)MyVirtualAlloc( MINIMUM_VM_ALLOCATION );
}
if ( SubAllocator != NULL )
{
SubAllocator->NextAvailable = (PCHAR)SubAllocator + ROUNDUP2( sizeof( SUBALLOCATOR ), SUBALLOCATOR_ALIGNMENT );
SubAllocator->LastAvailable = (PCHAR)SubAllocator + InitialSize;
SubAllocator->VirtualList = (PVOID*)SubAllocator;
SubAllocator->GrowSize = GrowthSize;
}
return (HANDLE) SubAllocator;
}
extern "C" PVOID __fastcall SubAllocate(IN HANDLE hAllocator, IN ULONG Size)
{
PSUBALLOCATOR SubAllocator = (PSUBALLOCATOR) hAllocator;
PCHAR NewVirtual;
PCHAR Allocation;
ULONG AllocSize;
ULONG Available;
ULONG GrowSize;
ASSERT( Size < (ULONG)( ~(( SUBALLOCATOR_ALIGNMENT * 2 ) - 1 )));
AllocSize = ROUNDUP2( Size, SUBALLOCATOR_ALIGNMENT );
Available = SubAllocator->LastAvailable - SubAllocator->NextAvailable;
if ( AllocSize <= Available )
{
Allocation = SubAllocator->NextAvailable;
SubAllocator->NextAvailable = Allocation + AllocSize;
return Allocation;
}
//
// Insufficient VM, so grow it. Make sure we grow it enough to satisfy
// the allocation request in case the request is larger than the grow
// size specified in CreateSubAllocator.
//
GrowSize = SubAllocator->GrowSize;
if ( GrowSize < ( AllocSize + SUBALLOCATOR_ALIGNMENT ))
{
GrowSize = ROUNDUP2(( AllocSize + SUBALLOCATOR_ALIGNMENT ), MINIMUM_VM_ALLOCATION );
}
NewVirtual = (PCHAR)MyVirtualAlloc( GrowSize );
// If failed to alloc GrowSize VM, and the allocation could be satisfied
// with a minimum VM allocation, try allocating minimum VM to satisfy
// this request.
//
if (( NewVirtual == NULL ) && ( AllocSize <= ( MINIMUM_VM_ALLOCATION - SUBALLOCATOR_ALIGNMENT )))
{
GrowSize = MINIMUM_VM_ALLOCATION;
NewVirtual = (PCHAR)MyVirtualAlloc( GrowSize );
}
if ( NewVirtual != NULL )
{
// Set LastAvailable to end of new VM block.
SubAllocator->LastAvailable = NewVirtual + GrowSize;
// Link new VM into list of VM allocations.
*(PVOID*)NewVirtual = SubAllocator->VirtualList;
SubAllocator->VirtualList = (PVOID*)NewVirtual;
// Requested allocation comes next.
Allocation = NewVirtual + SUBALLOCATOR_ALIGNMENT;
// Then set the NextAvailable for what's remaining.
SubAllocator->NextAvailable = Allocation + AllocSize;
// And return the allocation.
return Allocation;
}
// Could not allocate enough VM to satisfy request.
return NULL;
}
extern "C" VOID DestroySubAllocator(IN HANDLE hAllocator)
{
PSUBALLOCATOR SubAllocator = (PSUBALLOCATOR) hAllocator;
PVOID VirtualBlock = SubAllocator->VirtualList;
PVOID NextVirtualBlock;
do
{
NextVirtualBlock = *(PVOID*)VirtualBlock;
MyVirtualFree( VirtualBlock );
VirtualBlock = NextVirtualBlock;
}while (VirtualBlock != NULL);
}
HLOCAL ResizeBuffer(IN HLOCAL BufferHandle, IN DWORD Size, IN BOOL Moveable)
{
if (BufferHandle == NULL)
{
if (Size != 0)
{
BufferHandle = LocalAlloc(Moveable ? LMEM_MOVEABLE : LMEM_FIXED, Size);
}
}
else if (Size == 0)
{
BufferHandle = LocalFree(BufferHandle);
BufferHandle=NULL;
}
else
{
HLOCAL TempBufferHandle = LocalReAlloc(BufferHandle, Size, LMEM_MOVEABLE);
if ( TempBufferHandle )
{
BufferHandle = TempBufferHandle;
}
else
{
LocalFree(BufferHandle);
BufferHandle = NULL;
}
}
return BufferHandle;
}
VOID MyLowercase(IN OUT LPSTR String)
{
LPSTR p;
for ( p = String; *p; p++ )
{
if (( *p >= 'A' ) && ( *p <= 'Z' ))
{
*p |= 0x20;
}
}
}
void InitLogFile()
{
char szLogFileName[MAX_PATH], szTmp[MAX_PATH];
HKEY hKey;
BYTE cbData[MAX_PATH];
DWORD dwSize = sizeof(cbData);
if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Advanced INF Setup", 0,
KEY_ALL_ACCESS, &hKey))
{
return;
}
if(ERROR_SUCCESS != RegQueryValueEx(hKey, "AdvpextLog", 0, 0, cbData, &dwSize) ||
lstrcmpi((char*)cbData, "yes"))
{
RegCloseKey(hKey);
return;
}
RegCloseKey(hKey);
if (GetWindowsDirectory(szTmp, sizeof(szTmp)))
{
wsprintf(szLogFileName, "%s\\%s", szTmp, LOGFILENAME);
if (GetFileAttributes(szLogFileName) != 0xFFFFFFFF)
{
// Make a backup of the current log file
lstrcpyn(szTmp, szLogFileName, lstrlen(szLogFileName) - 2 ); // don't copy extension
lstrcat(szTmp, "BAK");
SetFileAttributes(szTmp, FILE_ATTRIBUTE_NORMAL);
DeleteFile(szTmp);
MoveFile(szLogFileName, szTmp);
}
g_hLogFile = CreateFile(szLogFileName, GENERIC_WRITE|GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0,0);
}
}
void WriteToLog(char *pszFormatString, ...)
{
va_list args;
char *pszFullErrMsg = NULL;
DWORD dwBytesWritten;
if (g_hLogFile && g_hLogFile != INVALID_HANDLE_VALUE)
{
va_start(args, pszFormatString);
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_STRING,
(LPCVOID) pszFormatString, 0, 0, (LPTSTR) &pszFullErrMsg, 0, &args);
if (pszFullErrMsg)
{
WriteFile(g_hLogFile, pszFullErrMsg, lstrlen(pszFullErrMsg), &dwBytesWritten, NULL);
LocalFree(pszFullErrMsg);
}
}
}
DWORD GenerateUniqueClientId()
{
CHAR MachineName[MAX_COMPUTERNAME_LENGTH + 1 ];
DWORD MachineNameLength;
DWORD UniqueId;
MachineNameLength = sizeof( MachineName );
GetComputerName( MachineName, &MachineNameLength );
do
{
UniqueId = GetTickCount();
UniqueId = Crc32( UniqueId, MachineName, MachineNameLength );
UniqueId = UniqueId & 0xFFFFFFF0;
}while ( UniqueId == 0 );
return UniqueId;
}
BOOL MySetupDecompressOrCopyFile(IN LPCSTR SourceFile, IN LPCSTR TargetFile)
{
DWORD ErrorCode = pfSetupDecompressOrCopyFile( SourceFile, TargetFile, 0 );
if ( ErrorCode != NO_ERROR ) {
SetLastError( ErrorCode );
return FALSE;
}
else {
SetFileAttributes( TargetFile, FILE_ATTRIBUTE_NORMAL );
return TRUE;
}
}
ULONG __fastcall TextToUnsignedNum(IN LPCSTR Text)
{
LPCSTR p = Text;
ULONG n = 0;
//
// Very simplistic conversion stops at first non digit character, does
// not require null-terminated string, and does not skip any whitespace
// or commas.
//
while (( *p >= '0' ) && ( *p <= '9' )) {
n = ( n * 10 ) + ( *p++ - '0' );
}
return n;
}
LPSTR CombinePaths(
IN LPCSTR ParentPath,
IN LPCSTR ChildPath,
OUT LPSTR TargetPath // can be same as ParentPath if want to append
)
{
ULONG ParentLength = strlen( ParentPath );
LPSTR p;
if ( ParentPath != TargetPath ) {
memcpy( TargetPath, ParentPath, ParentLength );
}
p = TargetPath + ParentLength;
if (( ParentLength > 0 ) &&
( *( p - 1 ) != '\\' ) &&
( *( p - 1 ) != '/' )) {
*p++ = '\\';
}
strcpy( p, ChildPath );
return TargetPath;
}
BOOL FixTimeStampOnCompressedFile(IN LPCSTR FileName)
{
//
// NT4 setupapi uses timestamp on compressed file to set on
// the target decompressed file. With streaming download, we
// lose the timestamp on the file. But, the correct timestamp
// lives inside the compressed file, so we'll open the file
// to see if it is a diamond compressed file and if so,
// extract the timestamp and set it on the compressed file.
// Then, when setupapi expands the compressed file, it will
// use that timestamp on the expanded file.
//
// A better fix is probably to tunnel the timestamp in the
// pstream protocol, but too late to change that at this
// point.
//
FILETIME LocalFileTime;
FILETIME UtcFileTime;
BOOL TimeSuccess;
BOOL MapSuccess;
HANDLE hSourceFile;
PUCHAR pSourceFileMapped;
DWORD dwSourceFileSize;
DWORD dwOffset;
USHORT DosDate;
USHORT DosTime;
PUCHAR p;
TimeSuccess = FALSE;
MapSuccess = MyMapViewOfFile(FileName, &dwSourceFileSize, &hSourceFile, (void**)&pSourceFileMapped);
if ( MapSuccess )
{
__try {
p = pSourceFileMapped;
if (( *(DWORD*)( p ) == 'FCSM' ) && // "MSCF"
( *(BYTE *)( p + 24 ) == 3 ) && // minor version
( *(BYTE *)( p + 25 ) == 1 ) && // major version
( *(WORD *)( p + 26 ) == 1 ) && // 1 folder
( *(WORD *)( p + 28 ) == 1 )) { // 1 file
dwOffset = *(DWORD*)( p + 16 );
if (( dwOffset + 16 ) < dwSourceFileSize ) {
DosDate = *(UNALIGNED WORD*)( p + dwOffset + 10 );
DosTime = *(UNALIGNED WORD*)( p + dwOffset + 12 );
if ( DosDateTimeToFileTime( DosDate, DosTime, &LocalFileTime ) &&
LocalFileTimeToFileTime( &LocalFileTime, &UtcFileTime )) {
TimeSuccess = TRUE;
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
MyUnmapViewOfFile( hSourceFile, pSourceFileMapped );
}
if ( TimeSuccess ) {
hSourceFile = CreateFile(
FileName,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if ( hSourceFile != INVALID_HANDLE_VALUE ) {
if ( ! SetFileTime( hSourceFile, &UtcFileTime, &UtcFileTime, &UtcFileTime )) {
TimeSuccess = FALSE;
}
CloseHandle( hSourceFile );
}
}
return TimeSuccess;
}
BOOL Assert(LPCSTR szText, LPCSTR szFile, DWORD dwLine)
{
CHAR Buffer[ 256 ];
wsprintf( Buffer, "ASSERT( %s ) FAILED, %s (%d)\n", szText, szFile, dwLine );
OutputDebugString( Buffer );
DebugBreak();
return FALSE;
}
BOOL MyMapViewOfFileByHandle(IN HANDLE FileHandle, OUT ULONG *FileSize, OUT PVOID *MapBase)
{
ULONG InternalFileSize;
ULONG InternalFileSizeHigh;
HANDLE InternalMapHandle;
PVOID InternalMapBase;
InternalFileSize = GetFileSize( FileHandle, &InternalFileSizeHigh );
if ( InternalFileSizeHigh != 0 )
{
SetLastError( ERROR_OUTOFMEMORY );
return FALSE;
}
if ( InternalFileSize == 0 )
{
*MapBase = NULL;
*FileSize = 0;
return TRUE;
}
if ( InternalFileSize != 0xFFFFFFFF )
{
InternalMapHandle = CreateFileMapping(
FileHandle,
NULL,
PAGE_WRITECOPY,
0,
0,
NULL
);
if ( InternalMapHandle != NULL )
{
InternalMapBase = MapViewOfFile(InternalMapHandle, FILE_MAP_COPY, 0, 0, 0);
CloseHandle( InternalMapHandle );
if ( InternalMapBase != NULL )
{
DWORD dw = ROUNDUP2(InternalFileSize, 64);
if(dw != InternalFileSize)
{
ZeroMemory((PBYTE)InternalMapBase + InternalFileSize, dw - InternalFileSize);
}
*MapBase = InternalMapBase;
*FileSize = InternalFileSize;
return TRUE;
}
}
}
return FALSE;
}
BOOL MyMapViewOfFile(IN LPCSTR FileName, OUT ULONG *FileSize, OUT HANDLE *FileHandle, OUT PVOID *MapBase)
{
HANDLE InternalFileHandle;
BOOL Success;
InternalFileHandle = CreateFileA(
FileName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if ( InternalFileHandle != INVALID_HANDLE_VALUE )
{
Success = MyMapViewOfFileByHandle(InternalFileHandle, FileSize, MapBase);
if ( Success )
{
*FileHandle = InternalFileHandle;
return TRUE;
}
CloseHandle( InternalFileHandle );
}
return FALSE;
}
VOID MyUnmapViewOfFile(IN HANDLE FileHandle, IN PVOID MapBase )
{
ULONG LastError = GetLastError();
UnmapViewOfFile( MapBase );
CloseHandle( FileHandle );
SetLastError( LastError );
}
VOID __fastcall ConvertToCompressedFileName(IN OUT LPSTR FileName)
{
ULONG NameLength = strlen( FileName );
ULONG DotIndex = NameLength;
while (( DotIndex > 0 ) && ( FileName[ --DotIndex ] != '.' )) {
if ( FileName[ DotIndex ] == '\\' ) { // end of filename part of path
DotIndex = 0; // name has no extension
break;
}
}
if ( DotIndex > 0 ) { // name has an extension
if (( NameLength - DotIndex ) <= 3 ) { // extension less than 3 chars
FileName[ NameLength++ ] = '_'; // append '_' to extension
FileName[ NameLength ] = 0; // terminate
}
else { // extension more than 3 chars
FileName[ NameLength - 1 ] = '_'; // replace last char with '_'
}
}
else { // name has no extension
FileName[ NameLength++ ] = '.'; // append '.'
FileName[ NameLength++ ] = '_'; // append '_'
FileName[ NameLength ] = 0; // terminate
}
}
LPTSTR __fastcall MySubAllocStrDup(IN HANDLE SubAllocator, IN LPCSTR String)
{
ULONG Length = lstrlen( String );
LPTSTR Buffer = (LPTSTR)SubAllocate( SubAllocator, Length + 1 );
if ( Buffer )
{
memcpy( Buffer, String, Length ); // no need to copy NULL terminator
}
return Buffer;
}
//
// Copied from Windows 95 unistal.exe cfg.c function CfgGetField
BOOL GetFieldString(LPSTR lpszLine, int iField, LPSTR lpszField, int cbSize)
{
int cbField;
LPSTR lpszChar, lpszEnd;
// Find the field we are looking for
lpszChar = lpszLine;
// Each time we see a separator, decrement iField
while (iField > 0 && (BYTE)*lpszChar > CR) {
if (*lpszChar == '=' || *lpszChar == ',' || *lpszChar == ' ' ) {
iField--;
while (*lpszChar == '=' || *lpszChar== ',' || *lpszChar == ' ' && (BYTE)*lpszChar > 13)
lpszChar++;
}
else
lpszChar++;
}
// If we still have fields remaining then something went wrong
if (iField)
return FALSE;
// Now find the end of this field
lpszEnd = lpszChar;
while (*lpszEnd != '=' && *lpszEnd != ',' && *lpszEnd != ' ' && (BYTE)*lpszEnd > CR)
lpszEnd++;
// Find the length of this field - make sure it'll fit in the buffer
cbField = (int)((lpszEnd - lpszChar) + 1);
if (cbField > cbSize) { // I return an error if the requested
//cbField = cbSize; // data won't fit, rather than truncating
return FALSE; // it at some random point! -JTP
}
// Note that the C runtime treats cbField as the number of characters
// to copy from the source, and if that doesn't happen to transfer a NULL,
// too bad. The Windows implementation of _lstrcpyn treats cbField as
// the number of characters that can be stored in the destination, and
// always copies a NULL (even if it means copying only cbField-1 characters
// from the source).
// The C runtime also pads the destination with NULLs if a NULL in the
// source is found before cbField is exhausted. _lstrcpyn essentially quits
// after copying a NULL.
lstrcpyn(lpszField, lpszChar, cbField);
return TRUE;
}
#define NUM_VERSION_NUM 4
void ConvertVersionStrToDwords(LPSTR pszVer, LPDWORD pdwVer, LPDWORD pdwBuild)
{
WORD rwVer[NUM_VERSION_NUM];
for(int i = 0; i < NUM_VERSION_NUM; i++)
rwVer[i] = 0;
for(i = 0; i < NUM_VERSION_NUM && pszVer; i++)
{
rwVer[i] = (WORD) StrToInt(pszVer);
pszVer = ScanForChar(pszVer, '.', lstrlen(pszVer));
if (pszVer)
pszVer++;
}
*pdwVer = (rwVer[0]<< 16) + rwVer[1];
*pdwBuild = (rwVer[2] << 16) + rwVer[3];
}
LPSTR FindChar(LPSTR pszStr, char ch)
{
while( *pszStr != 0 && *pszStr != ch )
pszStr++;
return pszStr;
}
DWORD GetStringField(LPSTR szStr, UINT uField, LPSTR szBuf, UINT cBufSize)
{
LPSTR pszBegin = szStr;
LPSTR pszEnd;
UINT i = 0;
DWORD dwToCopy;
if(cBufSize == 0)
return 0;
szBuf[0] = 0;
if(szStr == NULL)
return 0;
while(*pszBegin != 0 && i < uField)
{
pszBegin = FindChar(pszBegin, ',');
if(*pszBegin != 0)
pszBegin++;
i++;
}
// we reached end of string, no field
if(*pszBegin == 0)
{
return 0;
}
pszEnd = FindChar(pszBegin, ',');
while(pszBegin <= pszEnd && *pszBegin == ' ')
pszBegin++;
while(pszEnd > pszBegin && *(pszEnd - 1) == ' ')
pszEnd--;
if(pszEnd > (pszBegin + 1) && *pszBegin == '"' && *(pszEnd-1) == '"')
{
pszBegin++;
pszEnd--;
}
dwToCopy = pszEnd - pszBegin + 1;
if(dwToCopy > cBufSize)
dwToCopy = cBufSize;
lstrcpynA(szBuf, pszBegin, dwToCopy);
return dwToCopy - 1;
}
BOOL GetHashidFromINF(LPCTSTR lpFileName, LPTSTR lpszHash, DWORD dwSize)
{
INFCONTEXT InfContext;
if (pfSetupFindFirstLine(g_hInf, "SourceDisksFiles", lpFileName, &InfContext ))
{
if (pfSetupGetStringField(&InfContext, 5, lpszHash, dwSize, NULL ))
{
return TRUE;
}
}
return FALSE;
}
#ifdef _M_IX86
//
// Stupid x86 compiler doesn't have an intrinsic memchr, so we'll do our own.
//
#pragma warning( disable: 4035 ) // no return value
LPSTR ScanForChar(
IN LPSTR Buffer,
IN CHAR SearchFor,
IN ULONG MaxLength
)
{
__asm {
mov edi, Buffer // pointer for scasb in edi
mov al, SearchFor // looking for this char
mov ecx, MaxLength // don't scan past this
repne scasb // find the char
lea eax, [edi-1] // edi points one past the found char
jz RETURNIT // if didn't find it,
xor eax, eax // return NULL
RETURNIT:
}
}
#pragma warning( default: 4035 ) // no return value
#else // ! _M_IX86
LPSTR ScanForChar(IN LPSTR Buffer, IN CHAR SearchFor, IN ULONG MaxLength)
{
return memchr( Buffer, SearchFor, MaxLength );
}
#endif // ! _M_IX86
PCHAR ScanForSequence(IN PCHAR Buffer, IN ULONG BufferLength, IN PCHAR Sequence, IN ULONG SequenceLength)
{
if ( BufferLength >= SequenceLength )
{
PCHAR ScanEnd = Buffer + ( BufferLength - SequenceLength ) + 1;
PCHAR ScanPtr = Buffer;
while ( ScanPtr < ScanEnd )
{
ScanPtr = ScanForChar( ScanPtr, *Sequence, ScanEnd - ScanPtr );
if ( ScanPtr == NULL )
{
return NULL;
}
if ( memcmp( ScanPtr, Sequence, SequenceLength ) == 0 )
{
return ScanPtr;
}
++ScanPtr;
}
}
return NULL;
}
//From shlwapi....
#define FAST_CharNext(p) CharNext(p)
#define FILENAME_SEPARATOR '\\'
#define CH_WHACK TEXT(FILENAME_SEPARATOR)
LPTSTR PathFindFileName(LPCTSTR pPath)
{
LPCTSTR pT = pPath;
if (pPath)
{
for ( ; *pPath; pPath = FAST_CharNext(pPath))
{
if ((pPath[0] == TEXT('\\') || pPath[0] == TEXT(':') || pPath[0] == TEXT('/'))
&& pPath[1] && pPath[1] != TEXT('\\') && pPath[1] != TEXT('/'))
pT = pPath + 1;
}
}
return (LPTSTR)pT; // const -> non const
}
LPTSTR PathFindExtension(LPCTSTR pszPath)
{
LPCTSTR pszDot = NULL;
if (pszPath)
{
for (; *pszPath; pszPath = FAST_CharNext(pszPath))
{
switch (*pszPath) {
case TEXT('.'):
pszDot = pszPath; // remember the last dot
break;
case CH_WHACK:
case TEXT(' '): // extensions can't have spaces
pszDot = NULL; // forget last dot, it was in a directory
break;
}
}
}
// if we found the extension, return ptr to the dot, else
// ptr to end of the string (NULL extension) (cast->non const)
return pszDot ? (LPTSTR)pszDot : (LPTSTR)pszPath;
}
LPSTR StrDup(LPCSTR psz)
{
LPSTR pszRet = (LPSTR)LocalAlloc(LPTR, (lstrlenA(psz) + 1) * sizeof(*pszRet));
if (pszRet)
{
lstrcpyA(pszRet, psz);
}
return pszRet;
}
DWORD MyFileSize( PCSTR pszFile )
{
HFILE hFile;
OFSTRUCT ofStru;
DWORD dwSize = 0;
if ( *pszFile == 0 )
return 0;
hFile = OpenFile( pszFile, &ofStru, OF_READ );
if ( hFile != HFILE_ERROR )
{
dwSize = GetFileSize( (HANDLE)hFile, NULL );
_lclose( hFile );
}
return dwSize;
}
void GetLanguageString(LPTSTR lpszLang)
{
char szTmp[MAX_PATH];
DWORD dwLang, dwCharSet;
//default to EN
lstrcpy(lpszLang, "EN");
GetModuleFileName( g_hInstance, szTmp, sizeof(szTmp) );
MyGetVersionFromFile(szTmp, &dwLang, &dwCharSet, FALSE);
for(int i = 0; g_LangID[i].dwLangID != -1; i++)
{
if(g_LangID[i].dwLangID == dwLang)
{
lstrcpy(lpszLang, g_LangID[i].szLanguage);
break;
}
}
}
BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
{
RECT rChild, rParent;
int wChild, hChild, wParent, hParent;
int wScreen, hScreen, xNew, yNew;
HDC hdc;
// Get the Height and Width of the child window
GetWindowRect (hwndChild, &rChild);
wChild = rChild.right - rChild.left;
hChild = rChild.bottom - rChild.top;
// Get the Height and Width of the parent window
GetWindowRect (hwndParent, &rParent);
wParent = rParent.right - rParent.left;
hParent = rParent.bottom - rParent.top;
// Get the display limits
hdc = GetDC (hwndChild);
wScreen = GetDeviceCaps (hdc, HORZRES);
hScreen = GetDeviceCaps (hdc, VERTRES);
ReleaseDC (hwndChild, hdc);
// Calculate new X position, then adjust for screen
xNew = rParent.left + ((wParent - wChild) /2);
if (xNew < 0) {
xNew = 0;
} else if ((xNew+wChild) > wScreen) {
xNew = wScreen - wChild;
}
// Calculate new Y position, then adjust for screen
yNew = rParent.top + ((hParent - hChild) /2);
if (yNew < 0) {
yNew = 0;
} else if ((yNew+hChild) > hScreen) {
yNew = hScreen - hChild;
}
// Set it, and return
return SetWindowPos (hwndChild, NULL,
xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}