mirror of https://github.com/tongzx/nt5src
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.
1747 lines
49 KiB
1747 lines
49 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// File: misc.cpp
|
|
//
|
|
// Module: CMUTIL.DLL
|
|
//
|
|
// Synopsis: Misc. utility routines provided by CMUTIL
|
|
//
|
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
|
//
|
|
// Author: henryt Created 03/01/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
#include "cmmaster.h"
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// defines
|
|
//+----------------------------------------------------------------------------
|
|
#define WIN95_OSR2_BUILD_NUMBER 1111
|
|
#define LOADSTRING_BUFSIZE 24
|
|
#define FAREAST_WIN95_LOADSTRING_BUFSIZE 512
|
|
|
|
#define MAX_STR_LEN 512 // Maximum length for Format Message string
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// code
|
|
//+----------------------------------------------------------------------------
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function GetOSVersion
|
|
//
|
|
// Synopsis returns the OS version(platform ID)
|
|
//
|
|
// Arguments NONE
|
|
//
|
|
// Returns: DWORD - VER_PLATFORM_WIN32_WINDOWS or
|
|
// VER_PLATFORM_WIN32_WINDOWS98 or
|
|
// VER_PLATFORM_WIN32_NT
|
|
//
|
|
// History: Created Header 2/13/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
CMUTILAPI DWORD WINAPI GetOSVersion()
|
|
{
|
|
static dwPlatformID = 0;
|
|
|
|
//
|
|
// If this function is called before, reture the saved value
|
|
//
|
|
if (dwPlatformID != 0)
|
|
{
|
|
return dwPlatformID;
|
|
}
|
|
|
|
OSVERSIONINFO oviVersion;
|
|
|
|
ZeroMemory(&oviVersion,sizeof(oviVersion));
|
|
oviVersion.dwOSVersionInfoSize = sizeof(oviVersion);
|
|
GetVersionEx(&oviVersion);
|
|
|
|
if (oviVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
{
|
|
CMASSERTMSG(oviVersion.dwMajorVersion == 4, "Major Version must be 4 for this version of CM");
|
|
|
|
//
|
|
// If this is Win95 then leave it as VER_PLATFORM_WIN32_WINDOWS, however if this
|
|
// is Millennium, Win98 SE, or Win98 Gold we want to modify the returned value
|
|
// as follows: VER_PLATFORM_WIN32_MILLENNIUM -> Millennium
|
|
// VER_PLATFORM_WIN32_WINDOWS98 -> Win98 SE and Win98 Gold
|
|
//
|
|
if (oviVersion.dwMajorVersion == 4)
|
|
{
|
|
if (LOWORD(oviVersion.dwBuildNumber) > 2222)
|
|
{
|
|
//
|
|
// Millennium
|
|
//
|
|
oviVersion.dwPlatformId = VER_PLATFORM_WIN32_MILLENNIUM;
|
|
}
|
|
else if (LOWORD(oviVersion.dwBuildNumber) >= 1998)
|
|
{
|
|
//
|
|
// Win98 Gold and Win98 SE
|
|
//
|
|
|
|
oviVersion.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS98;
|
|
}
|
|
}
|
|
}
|
|
|
|
dwPlatformID = oviVersion.dwPlatformId;
|
|
return(dwPlatformID);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function GetOSBuildNumber
|
|
//
|
|
// Synopsis Get the build number of Operating system
|
|
//
|
|
// Arguments None
|
|
//
|
|
// Returns Build Number of OS
|
|
//
|
|
// History 3/5/97 VetriV Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CMUTILAPI DWORD WINAPI GetOSBuildNumber()
|
|
{
|
|
static dwBuildNumber = 0;
|
|
OSVERSIONINFO oviVersion;
|
|
|
|
if (0 != dwBuildNumber)
|
|
{
|
|
return dwBuildNumber;
|
|
}
|
|
|
|
ZeroMemory(&oviVersion,sizeof(oviVersion));
|
|
oviVersion.dwOSVersionInfoSize = sizeof(oviVersion);
|
|
GetVersionEx(&oviVersion);
|
|
dwBuildNumber = oviVersion.dwBuildNumber;
|
|
return dwBuildNumber;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function GetOSMajorVersion
|
|
//
|
|
// Synopsis Get the Major version number of Operating system
|
|
//
|
|
// Arguments None
|
|
//
|
|
// Returns Major version Number of OS
|
|
//
|
|
// History 2/19/98 VetriV Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CMUTILAPI DWORD WINAPI GetOSMajorVersion(void)
|
|
{
|
|
static dwMajorVersion = 0;
|
|
OSVERSIONINFO oviVersion;
|
|
|
|
if (0 != dwMajorVersion)
|
|
{
|
|
return dwMajorVersion;
|
|
}
|
|
|
|
ZeroMemory(&oviVersion,sizeof(oviVersion));
|
|
oviVersion.dwOSVersionInfoSize = sizeof(oviVersion);
|
|
GetVersionEx(&oviVersion);
|
|
dwMajorVersion = oviVersion.dwMajorVersion;
|
|
return dwMajorVersion;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: IsFarEastNonOSR2Win95()
|
|
//
|
|
// Synopsis: Checks to see if the OS is a far east version of Win95(golden
|
|
// and OPK1, NOT OSR2).
|
|
//
|
|
// Arguments: NONE
|
|
//
|
|
// Returns: TRUE/FALSE
|
|
//
|
|
// History: henryt 07/09/97 Created
|
|
// nickball 03/11/98 Moved to cmutil
|
|
//----------------------------------------------------------------------------
|
|
CMUTILAPI BOOL WINAPI IsFarEastNonOSR2Win95(void)
|
|
{
|
|
OSVERSIONINFO oviVersion;
|
|
|
|
ZeroMemory(&oviVersion, sizeof(oviVersion));
|
|
oviVersion.dwOSVersionInfoSize = sizeof(oviVersion);
|
|
|
|
GetVersionEx(&oviVersion);
|
|
|
|
//
|
|
// Is it (Win95) and (not OSR2) and (DBCS enabled)?
|
|
// Far east Win95 are DBCS enabled while other non-English versions
|
|
// are SBCS-enabled.
|
|
//
|
|
MYDBGTST((oviVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
|
|
LOWORD(oviVersion.dwBuildNumber) != WIN95_OSR2_BUILD_NUMBER &&
|
|
GetSystemMetrics(SM_DBCSENABLED)), (TEXT("It's a Far East non-OSR2 machine!\n")));
|
|
|
|
return (oviVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
|
|
LOWORD(oviVersion.dwBuildNumber) != WIN95_OSR2_BUILD_NUMBER &&
|
|
GetSystemMetrics(SM_DBCSENABLED));
|
|
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CmLoadStringA
|
|
//
|
|
// Synopsis: Loads the ANSI version of the string resource specified by
|
|
// the passed in module instance handle and resource ID. The
|
|
// function returns the requested string in a CmMalloc-ed buffer
|
|
// through the return value. This buffer must be freed by the
|
|
// caller. Note that CmLoadString figures out the proper buffer
|
|
// size by guessing and then calling loadstring again if the buffer
|
|
// is too small.
|
|
//
|
|
// Arguments: HINSTANCE hInst - module to load the string resource from
|
|
// UINT nId - resource ID of the string to load
|
|
//
|
|
// Returns: LPSTR - On success returns a pointer to the requested string
|
|
// resource. On failure the function tries to return
|
|
// a pointer to the Empty string ("") but if the memory
|
|
// allocation fails it can return NULL.
|
|
//
|
|
// History: quintinb Created Header 01/14/2000
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CMUTILAPI LPSTR CmLoadStringA(HINSTANCE hInst, UINT nId)
|
|
{
|
|
//
|
|
// In some far east versions of non-OSR2 win95, LoadString() ignores the
|
|
// nBufferMax paramater when loading DBCS strings. As a result, if the
|
|
// DBCS string is bigger than the buffer, the API overwrites the memory.
|
|
// We workaround the bug by using a larger buffer size.
|
|
//
|
|
static fFarEastNonOSR2Win95 = IsFarEastNonOSR2Win95();
|
|
size_t nLen = fFarEastNonOSR2Win95?
|
|
FAREAST_WIN95_LOADSTRING_BUFSIZE :
|
|
LOADSTRING_BUFSIZE;
|
|
LPSTR pszString;
|
|
|
|
if (!nId)
|
|
{
|
|
return (CmStrCpyAllocA(""));
|
|
}
|
|
while (1)
|
|
{
|
|
size_t nNewLen;
|
|
|
|
pszString = (LPSTR) CmMalloc(nLen*sizeof(CHAR));
|
|
|
|
MYDBGASSERT(pszString);
|
|
if (NULL == pszString)
|
|
{
|
|
return (CmStrCpyAllocA(""));
|
|
}
|
|
|
|
nNewLen = LoadStringA(hInst, nId, pszString, nLen-1);
|
|
//
|
|
// we use nNewLen+3 because a DBCS char len can be 2 and a UNICODE
|
|
// char len is 2. Ideally, we can use nLen in the above LoadString()
|
|
// call and use nNewLen+2 in the line below. But nLen+3 is a safer
|
|
// fix now...
|
|
//
|
|
if ((nNewLen + 3) < nLen)
|
|
{
|
|
return (pszString);
|
|
}
|
|
|
|
//
|
|
// shouldn't reach here for far east non osr2
|
|
// this will allow us to catch DBCS string resources that are
|
|
// longer than FAREAST_WIN95_LOADSTRING_BUFSIZE.
|
|
//
|
|
MYDBGASSERT(!fFarEastNonOSR2Win95);
|
|
|
|
CmFree(pszString);
|
|
nLen *= 2;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CmLoadStringW
|
|
//
|
|
// Synopsis: Loads the Unicode version of the string resource specified by
|
|
// the passed in module instance handle and resource ID. The
|
|
// function returns the requested string in a CmMalloc-ed buffer
|
|
// through the return value. This buffer must be freed by the
|
|
// caller. Note that CmLoadString figures out the proper buffer
|
|
// size by guessing and then calling loadstring again if the buffer
|
|
// is too small.
|
|
//
|
|
// Arguments: HINSTANCE hInst - module to load the string resource from
|
|
// UINT nId - resource ID of the string to load
|
|
//
|
|
// Returns: LPWSTR - On success returns a pointer to the requested string
|
|
// resource. On failure the function tries to return
|
|
// a pointer to the Empty string ("") but if the memory
|
|
// allocation fails it can return NULL.
|
|
//
|
|
// History: quintinb Created Header 01/14/2000
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CMUTILAPI LPWSTR CmLoadStringW(HINSTANCE hInst, UINT nId)
|
|
{
|
|
size_t nLen = LOADSTRING_BUFSIZE;
|
|
|
|
LPWSTR pszString;
|
|
|
|
if (!nId)
|
|
{
|
|
return (CmStrCpyAllocW(L""));
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
size_t nNewLen;
|
|
|
|
pszString = (LPWSTR) CmMalloc(nLen*sizeof(WCHAR));
|
|
|
|
MYDBGASSERT(pszString);
|
|
if (NULL == pszString)
|
|
{
|
|
return (CmStrCpyAllocW(L""));
|
|
}
|
|
|
|
nNewLen = LoadStringU(hInst, nId, pszString, nLen-1);
|
|
//
|
|
// we use nNewLen+3 because a DBCS char len can be 2 and a UNICODE
|
|
// char len is 2. Ideally, we can use nLen in the above LoadString()
|
|
// call and use nNewLen+2 in the line below. But nLen+3 is a safer
|
|
// fix now...
|
|
//
|
|
if ((nNewLen + 3) < nLen)
|
|
{
|
|
return (pszString);
|
|
}
|
|
|
|
CmFree(pszString);
|
|
nLen *= 2;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CmFmtMsgW
|
|
//
|
|
// Synopsis: Simulation of FormatMessage using wvsprintf for cross-platform
|
|
// compatibility.
|
|
//
|
|
// Arguments: hInst - Application instance handle
|
|
// dwMsgId - ID of message to use for formatting final output
|
|
// ... - Variable arguments to used in message fromatting
|
|
//
|
|
// Returns: Allocated to formatted string.
|
|
//
|
|
// History: nickball - Added function header - 5/12/97
|
|
// nickball - Moved to cmutil - 03/30/98
|
|
// quintinb - Added W and A versions - 03/09/99
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CMUTILAPI LPWSTR CmFmtMsgW(HINSTANCE hInst, DWORD dwMsgId, ...)
|
|
{
|
|
LPWSTR pszTmp = NULL;
|
|
LPWSTR lpszOutput = NULL;
|
|
LPWSTR lpszFormat = NULL;
|
|
|
|
if (!dwMsgId)
|
|
{
|
|
return (CmStrCpyAllocW(L""));
|
|
}
|
|
|
|
// Allocate a buffer to receive the RC string with specified msg ID
|
|
|
|
lpszFormat = (LPWSTR) CmMalloc(MAX_STR_LEN*sizeof(WCHAR));
|
|
|
|
if (!lpszFormat)
|
|
{
|
|
CMASSERTMSG(FALSE, "CmFmtMsgW -- CmMalloc returned a NULL pointer for lpszFormat");
|
|
return (CmStrCpyAllocW(L""));
|
|
}
|
|
|
|
// Initialize argument list
|
|
|
|
va_list valArgs;
|
|
va_start(valArgs,dwMsgId);
|
|
|
|
// Load the format string from the RC
|
|
|
|
int nRes = LoadStringU(hInst, (UINT) dwMsgId, lpszFormat, MAX_STR_LEN - 1);
|
|
|
|
#ifdef DEBUG
|
|
if (0 == nRes)
|
|
{
|
|
CMTRACE3(TEXT("MyFmtMsg() LoadString(dwMsgId=0x%x) return %u, GLE=%u."), dwMsgId, nRes,
|
|
nRes ? 0: GetLastError());
|
|
}
|
|
#endif
|
|
|
|
// If nothing loaded, free format buffer and bail
|
|
|
|
if (nRes == 0 || lpszFormat[0] == '\0')
|
|
{
|
|
CMASSERTMSG(FALSE, "CmFmtMsgW -- LoadStringU returned 0 or an empty buffer.");
|
|
pszTmp = (CmStrCpyAllocW(L""));
|
|
goto done;
|
|
}
|
|
|
|
// Allocate another buffer and for use by vsprintf
|
|
|
|
lpszOutput = (LPWSTR) CmMalloc(MAX_STR_LEN*sizeof(WCHAR));
|
|
|
|
if (!lpszOutput)
|
|
{
|
|
CMASSERTMSG(FALSE, "CmFmtMsgW -- CmMalloc returned a NULL pointer for lpszOutput");
|
|
pszTmp = (CmStrCpyAllocW(L""));
|
|
goto done;
|
|
}
|
|
|
|
// Format the final output using vsprintf
|
|
|
|
nRes = wvsprintfU(lpszOutput, lpszFormat, valArgs);
|
|
|
|
// If wvsprintfU failed, we're done
|
|
|
|
if (nRes < 0 || lpszOutput[0] == L'\0')
|
|
{
|
|
CMASSERTMSG(FALSE, "CmFmtMsgW -- wvsprintfU returned 0 or an empty buffer");
|
|
pszTmp = (CmStrCpyAllocW(L""));
|
|
goto done;
|
|
}
|
|
|
|
// Remove trailing spaces
|
|
|
|
pszTmp = lpszOutput + lstrlenU(lpszOutput) - 1;
|
|
while (CmIsSpaceW(pszTmp) && (*pszTmp != L'\n'))
|
|
{
|
|
*pszTmp = 0;
|
|
if (pszTmp == lpszOutput)
|
|
{
|
|
break;
|
|
}
|
|
pszTmp--;
|
|
}
|
|
|
|
pszTmp = CmStrCpyAllocW(lpszOutput); // allocates and copies
|
|
CMASSERTMSG(pszTmp, "CmFmtMsgW -- CmStrCpyAllocW returned a NULL pointer.");
|
|
|
|
done:
|
|
|
|
// Cleanup buffers, etc.
|
|
|
|
if (lpszFormat)
|
|
{
|
|
CmFree(lpszFormat);
|
|
}
|
|
|
|
if (lpszOutput)
|
|
{
|
|
CmFree(lpszOutput);
|
|
}
|
|
|
|
va_end(valArgs);
|
|
|
|
return (pszTmp);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CmFmtMsgA
|
|
//
|
|
// Synopsis: Simulation of FormatMessage using wvsprintf for cross-platform
|
|
// compatibility.
|
|
//
|
|
// Arguments: hInst - Application instance handle
|
|
// dwMsgId - ID of message to use for formatting final output
|
|
// ... - Variable arguments to used in message fromatting
|
|
//
|
|
// Returns: Allocated to formatted string.
|
|
//
|
|
// History: nickball - Added function header - 5/12/97
|
|
// nickball - Moved to cmutil - 03/30/98
|
|
// quintinb - Added W and A versions - 03/09/99
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CMUTILAPI LPSTR CmFmtMsgA(HINSTANCE hInst, DWORD dwMsgId, ...)
|
|
{
|
|
LPSTR pszTmp = NULL;
|
|
LPSTR lpszOutput = NULL;
|
|
LPSTR lpszFormat = NULL;
|
|
|
|
if (!dwMsgId)
|
|
{
|
|
return (CmStrCpyAllocA(""));
|
|
}
|
|
|
|
// Allocate a buffer to receive the RC string with specified msg ID
|
|
|
|
lpszFormat = (LPSTR) CmMalloc(MAX_STR_LEN);
|
|
|
|
if (!lpszFormat)
|
|
{
|
|
CMASSERTMSG(FALSE, "CmFmtMsgA -- CmMalloc returned a NULL pointer for lpszFormat");
|
|
return (CmStrCpyAllocA(""));
|
|
}
|
|
|
|
// Initialize argument list
|
|
|
|
va_list valArgs;
|
|
va_start(valArgs,dwMsgId);
|
|
|
|
// Load the format string from the RC
|
|
|
|
int nRes = LoadStringA(hInst, (UINT) dwMsgId, lpszFormat, MAX_STR_LEN - 1);
|
|
#ifdef DEBUG
|
|
if (0 == nRes)
|
|
{
|
|
CMTRACE3(TEXT("MyFmtMsg() LoadString(dwMsgId=0x%x) return %u, GLE=%u."), dwMsgId, nRes,
|
|
nRes ? 0: GetLastError());
|
|
}
|
|
#endif
|
|
|
|
// If nothing loaded, free format buffer and bail
|
|
|
|
if (nRes == 0 || lpszFormat[0] == '\0')
|
|
{
|
|
pszTmp = (CmStrCpyAllocA(""));
|
|
CMASSERTMSG(FALSE, "CmFmtMsgA -- LoadStringA returned 0 or an empty buffer.");
|
|
goto done;
|
|
}
|
|
|
|
// Allocate another buffer and for use by vsprintf
|
|
|
|
lpszOutput = (LPSTR) CmMalloc(MAX_STR_LEN);
|
|
|
|
if (!lpszOutput)
|
|
{
|
|
pszTmp = (CmStrCpyAllocA(""));
|
|
CMASSERTMSG(FALSE, "CmFmtMsgA -- CmMalloc returned a NULL pointer for lpszOutput");
|
|
goto done;
|
|
}
|
|
|
|
// Format the final output using vsprintf
|
|
|
|
nRes = wvsprintfA(lpszOutput, lpszFormat, valArgs);
|
|
|
|
// If wvsprintfA failed, we're done
|
|
|
|
if (nRes < 0 || lpszOutput[0] == '\0')
|
|
{
|
|
pszTmp = (CmStrCpyAllocA(""));
|
|
CMASSERTMSG(FALSE, "CmFmtMsgA -- wvsprintfA returned 0 or an empty buffer");
|
|
goto done;
|
|
}
|
|
|
|
// Remove trailing spaces
|
|
|
|
pszTmp = lpszOutput + lstrlenA(lpszOutput) - 1;
|
|
while (CmIsSpaceA(pszTmp) && (*pszTmp != '\n'))
|
|
{
|
|
*pszTmp = 0;
|
|
if (pszTmp == lpszOutput)
|
|
{
|
|
break;
|
|
}
|
|
pszTmp--;
|
|
}
|
|
|
|
pszTmp = CmStrCpyAllocA(lpszOutput); // allocates and copies
|
|
CMASSERTMSG(pszTmp, "CmFmtMsgA -- CmStrCpyAllocA returned a NULL pointer.");
|
|
|
|
done:
|
|
|
|
// Cleanup buffers, etc.
|
|
|
|
if (lpszFormat)
|
|
{
|
|
CmFree(lpszFormat);
|
|
}
|
|
|
|
if (lpszOutput)
|
|
{
|
|
CmFree(lpszOutput);
|
|
}
|
|
|
|
va_end(valArgs);
|
|
|
|
return (pszTmp);
|
|
|
|
#if 0
|
|
/*
|
|
// Replaced by the above code because we no longer use the platform specific .MC files
|
|
// All strings resources are now managed via standard .RC files
|
|
|
|
va_list valArgs;
|
|
DWORD dwRes;
|
|
LPTSTR pszBuffer = NULL;
|
|
|
|
if (!dwMsgId)
|
|
{
|
|
return (CmStrCpy(TEXT("")));
|
|
}
|
|
va_start(valArgs,dwMsgId);
|
|
|
|
|
|
dwRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_HMODULE|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
|
hInst,
|
|
dwMsgId,
|
|
LANG_USER_DEFAULT,
|
|
(LPTSTR) &pszBuffer,
|
|
0,
|
|
&valArgs);
|
|
MYDBGTST(dwRes==0,("MyFmtMsg() FormatMessage(dwMsgId=0x%x) return %u, GLE=%u.",dwMsgId,dwRes,dwRes?0:GetLastError()));
|
|
va_end(valArgs);
|
|
if (dwRes == 0)
|
|
{
|
|
if (pszBuffer)
|
|
{
|
|
LocalFree(pszBuffer);
|
|
}
|
|
return (CmStrCpy(TEXT("")));
|
|
}
|
|
if (!CmStrLen(pszBuffer))
|
|
{
|
|
LocalFree(pszBuffer);
|
|
return (CmStrCpy(TEXT("")));
|
|
}
|
|
pszTmp = pszBuffer + CmStrLen(pszBuffer) - 1;
|
|
while (MyIsSpace(*pszTmp) && (*pszTmp != '\n'))
|
|
{
|
|
*pszTmp = 0;
|
|
if (pszTmp == pszBuffer)
|
|
{
|
|
break;
|
|
}
|
|
pszTmp--;
|
|
}
|
|
pszTmp = CmStrCpy(pszBuffer);
|
|
LocalFree(pszBuffer);
|
|
|
|
return (pszTmp);
|
|
*/
|
|
#endif
|
|
|
|
}
|
|
|
|
#if 0 // not used anywhere
|
|
/*
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetMaxStringNumber
|
|
//
|
|
// Synopsis: Given a buffer containing strings in INI section format, determines
|
|
// which is the highest numbered string.
|
|
//
|
|
// Arguments: LPTSTR pszStr - The string containing an INI section
|
|
// LPDWORD pdwMax - Ptr to a DOWRD to be filled with the result
|
|
// *pdwMax gets the highest value of atol() of the strings.
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: Anonymous Created 3/30/98
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI void GetMaxStringNumber(LPTSTR pszStr, LPDWORD pdwMax)
|
|
{
|
|
LPTSTR pszTmp;
|
|
DWORD dwMax = 0;
|
|
|
|
if (pszStr)
|
|
{
|
|
pszTmp = pszStr;
|
|
while (*pszTmp)
|
|
{
|
|
DWORD dwMaxTmp;
|
|
|
|
if (pdwMax)
|
|
{
|
|
dwMaxTmp = (DWORD)CmAtol(pszTmp);
|
|
if (dwMaxTmp > dwMax)
|
|
{
|
|
dwMax = dwMaxTmp;
|
|
}
|
|
}
|
|
pszTmp += lstrlen(pszTmp) + 1;
|
|
}
|
|
}
|
|
if (pdwMax)
|
|
{
|
|
*pdwMax = dwMax;
|
|
}
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CmParsePathW
|
|
//
|
|
// Synopsis: Converts a Cm command line and args path into its component
|
|
// parts. If the command portion is a relative path, it is expanded
|
|
// to a full path. A ptr to the top level service filename is required
|
|
// to make the relative path determination.
|
|
//
|
|
// Arguments: pszCmdLine - Ptr to the full entry
|
|
// pszServiceFile - Ptr to top-level service filename
|
|
// ppszCommand - Ptr-ptr to be allocated and filled with command portion
|
|
// ppszArguments - Ptr-ptr to be allocated and filled with args portion
|
|
//
|
|
// Returns: TRUE if ppszCmd and ppszArgs are allocated/filled. FALSE otherwise.
|
|
//
|
|
// History: 02/19/99 nickball Created
|
|
// 02/21/99 nickball Moved to cmutil
|
|
// 03/09/99 quintinb Created A and W versions
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CMUTILAPI BOOL CmParsePathW(LPCWSTR pszCmdLine, LPCWSTR pszServiceFile, LPWSTR *ppszCommand, LPWSTR *ppszArguments)
|
|
{
|
|
LPWSTR pszArgs = NULL;
|
|
LPWSTR pszCmd = NULL;
|
|
LPWSTR pszTmp = NULL;
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
MYDBGASSERT(pszCmdLine);
|
|
MYDBGASSERT(pszServiceFile);
|
|
MYDBGASSERT(ppszCommand);
|
|
MYDBGASSERT(ppszArguments);
|
|
|
|
if (NULL == pszCmdLine ||
|
|
NULL == pszServiceFile ||
|
|
NULL == ppszCommand ||
|
|
NULL == ppszArguments)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CMTRACE1(TEXT("CmParsePathW() pszCmdLine is %s"), pszCmdLine);
|
|
|
|
//
|
|
// Determine where our string begins and what the delimiting char should
|
|
// be then make a copy of the entire command line string to muck with.
|
|
//
|
|
|
|
WCHAR tchDelim = L'+';
|
|
|
|
if (pszCmdLine == CmStrchrW(pszCmdLine, tchDelim))
|
|
{
|
|
pszCmd = CmStrCpyAllocW(CharNextU(pszCmdLine));
|
|
}
|
|
else
|
|
{
|
|
pszCmd = CmStrCpyAllocW(pszCmdLine);
|
|
tchDelim = L' ';
|
|
}
|
|
|
|
MYDBGASSERT(pszCmd);
|
|
CmStrTrimW(pszCmd);
|
|
|
|
//
|
|
// Assuming valid inputs, pszCmd is now one of the following:
|
|
//
|
|
// "C:\\Program Files\\Custom.Exe+"
|
|
// "C:\\Program Files\\Custom.Exe+ Args"
|
|
// "C:\\Progra~1\\Custom.Exe
|
|
// "C:\\Progra~1\\Custom.Exe Args"
|
|
// "service\custom.exe"
|
|
// "service\custom.exe Args"
|
|
//
|
|
|
|
if (pszCmd && L'\0' != *pszCmd)
|
|
{
|
|
//
|
|
// Locate the right command delimiter
|
|
//
|
|
|
|
pszArgs = CmStrchrW(pszCmd, tchDelim);
|
|
|
|
if (pszArgs)
|
|
{
|
|
//
|
|
// Content of pszTmp is now either "+ Args", "", or "+"
|
|
// Get a pointer to the next char and truncate the pszCmd
|
|
// that we have thus far.
|
|
//
|
|
|
|
pszTmp = CharNextU(pszArgs); // pszArgs is " Args" or ""
|
|
*pszArgs = L'\0'; // The "+" becomes ""
|
|
pszArgs = pszTmp; // pszTmp is " Args" or ""
|
|
}
|
|
|
|
//
|
|
// Fill argument buffer from pszTmp and command buffer
|
|
// from pszCmd with a complete path if necessary.
|
|
//
|
|
|
|
if (NULL == pszArgs)
|
|
{
|
|
*ppszArguments = (LPWSTR)CmMalloc(sizeof(WCHAR)); // one Zero-ed WCHAR
|
|
}
|
|
else
|
|
{
|
|
MYVERIFY(*ppszArguments = CmStrCpyAllocW(pszArgs));
|
|
}
|
|
|
|
MYVERIFY(*ppszCommand = CmConvertRelativePathW(pszServiceFile, pszCmd));
|
|
|
|
//
|
|
// Trim blanks as needed
|
|
//
|
|
|
|
if (*ppszCommand)
|
|
{
|
|
CmStrTrimW(*ppszCommand);
|
|
}
|
|
|
|
if (*ppszArguments)
|
|
{
|
|
CmStrTrimW(*ppszArguments);
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
//
|
|
// Cleanup. Note: pszArgs is never allocated, so we don't have to free it.
|
|
//
|
|
|
|
CmFree(pszCmd);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CmParsePathA
|
|
//
|
|
// Synopsis: Converts a Cm command line and args path into its component
|
|
// parts. If the command portion is a relative path, it is expanded
|
|
// to a full path. A ptr to the top level service filename is required
|
|
// to make the relative path determination.
|
|
//
|
|
// Arguments: pszCmdLine - Ptr to the full entry
|
|
// pszServiceFile - Ptr to top-level service filename
|
|
// ppszCommand - Ptr-ptr to be allocated and filled with command portion
|
|
// ppszArguments - Ptr-ptr to be allocated and filled with args portion
|
|
//
|
|
// Returns: TRUE if ppszCmd and ppszArgs are allocated/filled. FALSE otherwise.
|
|
//
|
|
// History: 02/19/99 nickball Created
|
|
// 02/21/99 nickball Moved to cmutil
|
|
// 03/09/99 quintinb Created A and W versions
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CMUTILAPI BOOL CmParsePathA(LPCSTR pszCmdLine, LPCSTR pszServiceFile, LPSTR *ppszCommand, LPSTR *ppszArguments)
|
|
{
|
|
LPSTR pszArgs = NULL;
|
|
LPSTR pszCmd = NULL;
|
|
LPSTR pszTmp = NULL;
|
|
|
|
BOOL bRet = FALSE;
|
|
|
|
MYDBGASSERT(pszCmdLine);
|
|
MYDBGASSERT(pszServiceFile);
|
|
MYDBGASSERT(ppszCommand);
|
|
MYDBGASSERT(ppszArguments);
|
|
|
|
if (NULL == pszCmdLine ||
|
|
NULL == pszServiceFile ||
|
|
NULL == ppszCommand ||
|
|
NULL == ppszArguments)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CMTRACE1(TEXT("CmParsePathA() pszCmdLine is %s"), pszCmdLine);
|
|
|
|
//
|
|
// Determine where our string begins and what the delimiting char should
|
|
// be then make a copy of the entire command line string to muck with.
|
|
//
|
|
|
|
CHAR tchDelim = '+';
|
|
|
|
if (pszCmdLine == CmStrchrA(pszCmdLine, tchDelim))
|
|
{
|
|
pszCmd = CmStrCpyAllocA(CharNextA(pszCmdLine));
|
|
}
|
|
else
|
|
{
|
|
pszCmd = CmStrCpyAllocA(pszCmdLine);
|
|
tchDelim = ' ';
|
|
}
|
|
|
|
MYDBGASSERT(pszCmd);
|
|
CmStrTrimA(pszCmd);
|
|
|
|
//
|
|
// Assuming valid inputs, pszCmd is now one of the following:
|
|
//
|
|
// "C:\\Program Files\\Custom.Exe+"
|
|
// "C:\\Program Files\\Custom.Exe+ Args"
|
|
// "C:\\Progra~1\\Custom.Exe
|
|
// "C:\\Progra~1\\Custom.Exe Args"
|
|
// "service\custom.exe"
|
|
// "service\custom.exe Args"
|
|
//
|
|
|
|
if (pszCmd && '\0' != *pszCmd)
|
|
{
|
|
//
|
|
// Locate the right command delimiter
|
|
//
|
|
|
|
pszArgs = CmStrchrA(pszCmd, tchDelim);
|
|
|
|
if (pszArgs)
|
|
{
|
|
//
|
|
// Content of pszTmp is now either "+ Args", "", or "+"
|
|
// Get a pointer to the next char and truncate the pszCmd
|
|
// that we have thus far.
|
|
//
|
|
|
|
pszTmp = CharNextA(pszArgs); // pszArgs is " Args" or ""
|
|
*pszArgs = '\0'; // The "+" becomes ""
|
|
pszArgs = pszTmp; // pszTmp is " Args" or ""
|
|
}
|
|
|
|
//
|
|
// Fill argument buffer from pszTmp and command buffer
|
|
// from pszCmd with a complete path if necessary.
|
|
//
|
|
|
|
if (NULL == pszArgs)
|
|
{
|
|
MYVERIFY(*ppszArguments = (LPSTR)CmMalloc(sizeof(CHAR))); // one Zero-ed char
|
|
}
|
|
else
|
|
{
|
|
MYVERIFY(*ppszArguments = CmStrCpyAllocA(pszArgs));
|
|
}
|
|
|
|
MYVERIFY(*ppszCommand = CmConvertRelativePathA(pszServiceFile, pszCmd));
|
|
|
|
//
|
|
// Trim blanks as needed
|
|
//
|
|
|
|
if (*ppszCommand)
|
|
{
|
|
CmStrTrimA(*ppszCommand);
|
|
}
|
|
|
|
if (*ppszArguments)
|
|
{
|
|
CmStrTrimA(*ppszArguments);
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
//
|
|
// Cleanup. Note: pszArgs is never allocated, so we don't have to free it.
|
|
//
|
|
|
|
CmFree(pszCmd);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmConvertRelativePathA
|
|
//
|
|
// Synopsis: Converts the specified relative path to a full path. If the
|
|
// specified path is not a relative path specific to this profile,
|
|
// it is ignored.
|
|
//
|
|
// Arguments: LPCSTR pszServiceFile - Full path to the .cms file
|
|
// LPCSTR pszRelative - The relative path fragment
|
|
//
|
|
// Returns: LPSTR - NULL on failure
|
|
//
|
|
// Note: Do not pass referenced profile service objects to this routine.
|
|
// It is designed to derive the short-service name from the top-level
|
|
// service filename and path.
|
|
//
|
|
// History: 03/11/98 nickball Created
|
|
// 02/03/99 nickball Added header Note
|
|
// 02/21/99 nickball Moved to cmutil
|
|
// 03/09/99 quintinb Added W and A versions
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPSTR CmConvertRelativePathA(LPCSTR pszServiceFile,
|
|
LPSTR pszRelative)
|
|
{
|
|
MYDBGASSERT(pszServiceFile);
|
|
MYDBGASSERT(*pszServiceFile);
|
|
MYDBGASSERT(pszRelative);
|
|
MYDBGASSERT(*pszRelative);
|
|
|
|
if (NULL == pszRelative || 0 == pszRelative[0] ||
|
|
NULL == pszServiceFile || 0 == pszServiceFile[0])
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Get the relative dir that we expect to find
|
|
//
|
|
|
|
LPSTR pszConverted = NULL;
|
|
LPSTR pszRelDir = CmStripPathAndExtA(pszServiceFile);
|
|
|
|
if (pszRelDir && *pszRelDir)
|
|
{
|
|
lstrcatA(pszRelDir, "\\");
|
|
|
|
//
|
|
// Compare against the specifed FRAGMENT. If it matches, convert.
|
|
//
|
|
|
|
CharUpperA(pszRelDir);
|
|
CharUpperA(pszRelative);
|
|
|
|
if (pszRelative == CmStrStrA(pszRelative, pszRelDir))
|
|
{
|
|
//
|
|
// Combine CMS path and relative for complete
|
|
//
|
|
|
|
LPSTR pszTmp = CmStripFileNameA(pszServiceFile, FALSE);
|
|
pszConverted = CmBuildFullPathFromRelativeA(pszTmp, pszRelative);
|
|
CmFree(pszTmp);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Its not a relative path for this profile, just make a copy
|
|
//
|
|
|
|
pszConverted = CmStrCpyAllocA(pszRelative);
|
|
}
|
|
}
|
|
|
|
CmFree(pszRelDir);
|
|
|
|
return pszConverted;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmConvertRelativePathW
|
|
//
|
|
// Synopsis: Converts the specified relative path to a full path. If the
|
|
// specified path is not a relative path specific to this profile,
|
|
// it is ignored.
|
|
//
|
|
// Arguments: LPCWSTR pszServiceFile - Full path to the .cms file
|
|
// LPCWSTR pszRelative - The relative path fragment
|
|
//
|
|
// Returns: LPWSTR - NULL on failure
|
|
//
|
|
// Note: Do not pass referenced profile service objects to this routine.
|
|
// It is designed to derive the short-service name from the top-level
|
|
// service filename and path.
|
|
//
|
|
// History: 03/11/98 nickball Created
|
|
// 02/03/99 nickball Added header Note
|
|
// 02/21/99 nickball Moved to cmutil
|
|
// 03/09/99 quintinb Added W and A versions
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPWSTR CmConvertRelativePathW(LPCWSTR pszServiceFile,
|
|
LPWSTR pszRelative)
|
|
{
|
|
MYDBGASSERT(pszServiceFile);
|
|
MYDBGASSERT(*pszServiceFile);
|
|
MYDBGASSERT(pszRelative);
|
|
MYDBGASSERT(*pszRelative);
|
|
|
|
if (NULL == pszRelative || 0 == pszRelative[0] ||
|
|
NULL == pszServiceFile || 0 == pszServiceFile[0])
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Get the relative dir that we expect to find
|
|
//
|
|
|
|
LPWSTR pszConverted = NULL;
|
|
LPWSTR pszRelDir = CmStripPathAndExtW(pszServiceFile);
|
|
|
|
if (pszRelDir && *pszRelDir)
|
|
{
|
|
lstrcatU(pszRelDir, L"\\");
|
|
|
|
//
|
|
// Compare against the specifed FRAGMENT. If it matches, convert.
|
|
//
|
|
|
|
CharUpperU(pszRelDir);
|
|
CharUpperU(pszRelative);
|
|
|
|
if (pszRelative == CmStrStrW(pszRelative, pszRelDir))
|
|
{
|
|
//
|
|
// Combine CMS path and relative for complete
|
|
//
|
|
|
|
LPWSTR pszTmp = CmStripFileNameW(pszServiceFile, FALSE);
|
|
pszConverted = CmBuildFullPathFromRelativeW(pszTmp, pszRelative);
|
|
CmFree(pszTmp);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Its not a relative path for this profile, just make a copy
|
|
//
|
|
|
|
pszConverted = CmStrCpyAllocW(pszRelative);
|
|
}
|
|
}
|
|
|
|
CmFree(pszRelDir);
|
|
|
|
return pszConverted;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmStripPathAndExtA
|
|
//
|
|
// Synopsis: Helper function, strips path and extension from a filename path
|
|
//
|
|
// Arguments: pszFileName - the filename path to be modified
|
|
//
|
|
// Returns: LPSTR - The base filename sub-string
|
|
//
|
|
// History: nickball Created header 8/12/98
|
|
// nickball Moved to cmutil 02/21/99
|
|
// quintinb Added W and A versions 03/09/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPSTR CmStripPathAndExtA(LPCSTR pszFileName)
|
|
{
|
|
MYDBGASSERT(pszFileName);
|
|
|
|
if (NULL == pszFileName)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
MYDBGASSERT(*pszFileName);
|
|
|
|
//
|
|
// Make a copy of the string and validate format "\\." required.
|
|
//
|
|
|
|
LPSTR pszTmp = CmStrCpyAllocA(pszFileName);
|
|
|
|
if (NULL == pszTmp)
|
|
{
|
|
MYDBGASSERT(pszTmp);
|
|
return NULL;
|
|
}
|
|
|
|
LPSTR pszDot = CmStrrchrA(pszTmp, '.');
|
|
LPSTR pszSlash = CmStrrchrA(pszTmp, '\\');
|
|
|
|
if (NULL == pszDot || NULL == pszSlash || pszDot < pszSlash)
|
|
{
|
|
CmFree(pszTmp);
|
|
MYDBGASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
*pszDot = '\0';
|
|
|
|
//
|
|
// Increment past slash and copy remainder
|
|
//
|
|
|
|
pszSlash = CharNextA(pszSlash);
|
|
|
|
lstrcpyA(pszTmp, pszSlash);
|
|
|
|
return (pszTmp);
|
|
}
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmStripPathAndExtW
|
|
//
|
|
// Synopsis: Helper function, strips path and extension from a filename path
|
|
//
|
|
// Arguments: pszFileName - the filename path to be modified
|
|
//
|
|
// Returns: LPWSTR - The base filename sub-string
|
|
//
|
|
// History: nickball Created header 8/12/98
|
|
// nickball Moved to cmutil 02/21/99
|
|
// quintinb Added W and A versions 03/09/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPWSTR CmStripPathAndExtW(LPCWSTR pszFileName)
|
|
{
|
|
MYDBGASSERT(pszFileName);
|
|
|
|
if (NULL == pszFileName)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
MYDBGASSERT(*pszFileName);
|
|
|
|
//
|
|
// Make a copy of the string and validate format "\\." required.
|
|
//
|
|
|
|
LPWSTR pszTmp = CmStrCpyAllocW(pszFileName);
|
|
|
|
if (NULL == pszTmp)
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
LPWSTR pszDot = CmStrrchrW(pszTmp, L'.');
|
|
LPWSTR pszSlash = CmStrrchrW(pszTmp, L'\\');
|
|
|
|
if (NULL == pszDot || NULL == pszSlash || pszDot < pszSlash)
|
|
{
|
|
CmFree(pszTmp);
|
|
MYDBGASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
*pszDot = L'\0';
|
|
|
|
//
|
|
// Increment past slash and copy remainder
|
|
//
|
|
|
|
pszSlash = CharNextU(pszSlash);
|
|
|
|
lstrcpyU(pszTmp, pszSlash);
|
|
|
|
return (pszTmp);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmStripFileNameA
|
|
//
|
|
// Synopsis: Helper function to deal with the tedium of extracting the path
|
|
// part of a complete filename.
|
|
//
|
|
// Arguments: LPCSTR pszFullNameAndPath - Ptr to the filename
|
|
// BOOL fKeepSlash - Flag indicating that trailing directory '\' should be retained.
|
|
//
|
|
// Returns: LPSTR - Ptr to an allocated buffer containing the dir, or NULL on failure.
|
|
//
|
|
// Note: It is up to the caller to provide reasonable input, the only requirement
|
|
// is that the input contain '\'.
|
|
//
|
|
// History: nickball Created 3/10/98
|
|
// nickball Moved to cmutil 02/21/99
|
|
// quintinb Added W and A versions 03/09/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPSTR CmStripFileNameA(LPCSTR pszFullNameAndPath, BOOL fKeepSlash)
|
|
{
|
|
MYDBGASSERT(pszFullNameAndPath);
|
|
|
|
if (NULL == pszFullNameAndPath)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the filename and locate the last '\'
|
|
//
|
|
|
|
LPSTR pszTmp = CmStrCpyAllocA(pszFullNameAndPath);
|
|
|
|
if (NULL == pszTmp)
|
|
{
|
|
CMASSERTMSG(NULL, "CmStripFileNameA -- CmStrCpyAllocA returned a NULL pointer for pszTmp");
|
|
return NULL;
|
|
}
|
|
|
|
LPSTR pszSlash = CmStrrchrA(pszTmp, '\\');
|
|
|
|
if (NULL == pszSlash)
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
CmFree(pszTmp);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// If slash is desired, move to next char before truncating
|
|
//
|
|
|
|
if (fKeepSlash)
|
|
{
|
|
pszSlash = CharNextA(pszSlash);
|
|
}
|
|
|
|
*pszSlash = '\0';
|
|
|
|
return pszTmp;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmStripFileNameW
|
|
//
|
|
// Synopsis: Helper function to deal with the tedium of extracting the path
|
|
// part of a complete filename.
|
|
//
|
|
// Arguments: LPCWSTR pszFullNameAndPath - Ptr to the filename
|
|
// BOOL fKeepSlash - Flag indicating that trailing directory '\' should be retained.
|
|
//
|
|
// Returns: LPWSTR - Ptr to an allocated buffer containing the dir, or NULL on failure.
|
|
//
|
|
// Note: It is up to the caller to provide reasonable input, the only requirement
|
|
// is that the input contain '\'.
|
|
//
|
|
// History: nickball Created 3/10/98
|
|
// nickball Moved to cmutil 02/21/99
|
|
// quintinb Added W and A versions 03/09/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPWSTR CmStripFileNameW(LPCWSTR pszFullNameAndPath, BOOL fKeepSlash)
|
|
{
|
|
MYDBGASSERT(pszFullNameAndPath);
|
|
|
|
if (NULL == pszFullNameAndPath)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Make a copy of the filename and locate the last '\'
|
|
//
|
|
|
|
LPWSTR pszTmp = CmStrCpyAllocW(pszFullNameAndPath);
|
|
|
|
if (NULL == pszTmp)
|
|
{
|
|
CMASSERTMSG(NULL, "CmStripFileNameW -- CmStrCpyAllocW returned a NULL pointer for pszTmp");
|
|
return NULL;
|
|
}
|
|
|
|
LPWSTR pszSlash = CmStrrchrW(pszTmp, L'\\');
|
|
|
|
if (NULL == pszSlash)
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
CmFree(pszTmp);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// If slash is desired, move to next char before truncating
|
|
//
|
|
|
|
if (fKeepSlash)
|
|
{
|
|
pszSlash = CharNextU(pszSlash);
|
|
}
|
|
|
|
*pszSlash = L'\0';
|
|
|
|
return pszTmp;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmBuildFullPathFromRelativeA
|
|
//
|
|
// Synopsis: Builds a full path by stripping the filename from pszFullFileName
|
|
// and appending pszRelative.
|
|
//
|
|
// Arguments: LPCSTR pszFullFileName - A full path and filename
|
|
// LPCSTR pszRelative - Relative path fragment.
|
|
//
|
|
// Typically used to construct a full path to a file in the profile directory
|
|
// based upon the path to the .CMP file.
|
|
//
|
|
// Returns: LPSTR - Ptr to the completed path which must be freed by the caller.
|
|
//
|
|
// Note: pszRelative must NOT contain a leading "\"
|
|
//
|
|
// History: nickball Created 03/08/98
|
|
// nickball Moved to cmutil 02/21/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPSTR CmBuildFullPathFromRelativeA(LPCSTR pszFullFileName,
|
|
LPCSTR pszRelative)
|
|
{
|
|
MYDBGASSERT(pszFullFileName);
|
|
MYDBGASSERT(pszRelative);
|
|
|
|
//
|
|
// Check assumptions
|
|
//
|
|
|
|
if (NULL == pszFullFileName || NULL == pszRelative)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// No empty strings please
|
|
//
|
|
|
|
MYDBGASSERT(*pszFullFileName);
|
|
MYDBGASSERT(*pszRelative);
|
|
MYDBGASSERT(pszRelative[0] != '\\');
|
|
|
|
//
|
|
// Get the directory name including trailing '\'
|
|
//
|
|
|
|
LPSTR pszFull = NULL;
|
|
LPSTR pszProfile = CmStripFileNameA(pszFullFileName, TRUE);
|
|
|
|
if (pszProfile && *pszProfile)
|
|
{
|
|
pszFull = (LPSTR) CmMalloc(lstrlenA(pszProfile) + lstrlenA(pszRelative) + sizeof(CHAR));
|
|
|
|
MYDBGASSERT(pszFull);
|
|
|
|
if (pszFull)
|
|
{
|
|
//
|
|
// Build the complete path with new relative extension
|
|
//
|
|
|
|
lstrcpyA(pszFull, pszProfile);
|
|
lstrcatA(pszFull, pszRelative);
|
|
}
|
|
}
|
|
|
|
CmFree(pszProfile);
|
|
|
|
return pszFull;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmBuildFullPathFromRelativeW
|
|
//
|
|
// Synopsis: Builds a full path by stripping the filename from pszFullFileName
|
|
// and appending pszRelative.
|
|
//
|
|
// Arguments: LPWTSTR pszFullFileName - A full path and filename
|
|
// LPWTSTR pszRelative - Relative path fragment.
|
|
//
|
|
// Typically used to construct a full path to a file in the profile directory
|
|
// based upon the path to the .CMP file.
|
|
//
|
|
// Returns: LPWSTR - Ptr to the completed path which must be freed by the caller.
|
|
//
|
|
// Note: pszRelative must NOT contain a leading "\"
|
|
//
|
|
// History: nickball Created 3/8/98
|
|
// nickball Moved to cmutil 02/21/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI LPWSTR CmBuildFullPathFromRelativeW(LPCWSTR pszFullFileName,
|
|
LPCWSTR pszRelative)
|
|
{
|
|
MYDBGASSERT(pszFullFileName);
|
|
MYDBGASSERT(pszRelative);
|
|
|
|
//
|
|
// Check assumptions
|
|
//
|
|
|
|
if (NULL == pszFullFileName || NULL == pszRelative)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// No empty strings please
|
|
//
|
|
|
|
MYDBGASSERT(*pszFullFileName);
|
|
MYDBGASSERT(*pszRelative);
|
|
MYDBGASSERT(pszRelative[0] != L'\\');
|
|
|
|
//
|
|
// Get the directory name including trailing '\'
|
|
//
|
|
|
|
LPWSTR pszFull = NULL;
|
|
LPWSTR pszProfile = CmStripFileNameW(pszFullFileName, TRUE);
|
|
|
|
if (pszProfile && *pszProfile)
|
|
{
|
|
pszFull = (LPWSTR) CmMalloc((lstrlenU(pszProfile) + lstrlenU(pszRelative) + 1)*sizeof(WCHAR));
|
|
|
|
MYDBGASSERT(pszFull);
|
|
|
|
if (pszFull)
|
|
{
|
|
//
|
|
// Build the complete path with new relative extension
|
|
//
|
|
|
|
lstrcpyU(pszFull, pszProfile);
|
|
lstrcatU(pszFull, pszRelative);
|
|
}
|
|
}
|
|
|
|
CmFree(pszProfile);
|
|
|
|
return pszFull;
|
|
}
|
|
|
|
//+-----------------------------------------------------------------------------------------
|
|
// Function: CmWinHelp
|
|
//
|
|
// Synopsis: Calls Winhelp using the command line parameters
|
|
//
|
|
// Arguments: See winhelp documentation
|
|
// hWndItem - This is a additional parameter we use to designate the window/control for
|
|
// which help(context) is needed.
|
|
// Returns: TRUE if help was launched successfully otherwise FALSE
|
|
//
|
|
// Notes:
|
|
//
|
|
// History: v-vijayb 7/10/99
|
|
//
|
|
//+-----------------------------------------------------------------------------------------
|
|
|
|
CMUTILAPI BOOL CmWinHelp(HWND hWndMain, HWND hWndItem, CONST WCHAR *lpszHelp, UINT uCommand, ULONG_PTR dwData)
|
|
{
|
|
DWORD cb;
|
|
TCHAR szName[MAX_PATH];
|
|
HDESK hDesk = GetThreadDesktop(GetCurrentThreadId());
|
|
BOOL fRun = FALSE;
|
|
DWORD *prgWinIdHelpId = (DWORD *) dwData;
|
|
|
|
//
|
|
// Get the name of the desktop. Normally returns default or Winlogon or system or WinNT
|
|
// On Win95/98 GetUserObjectInformation is not supported and thus the desktop name
|
|
// will be empty so we will use the good old help API
|
|
//
|
|
szName[0] = 0;
|
|
GetUserObjectInformation(hDesk, UOI_NAME, szName, sizeof(szName), &cb);
|
|
CMTRACE1(TEXT("Desktop = %s"), szName);
|
|
if (lstrcmpi(TEXT("Winlogon"), szName) == 0)
|
|
{
|
|
return FALSE;
|
|
/*
|
|
STARTUPINFOW StartupInfo;
|
|
PROCESS_INFORMATION ProcessInfo;
|
|
WCHAR szCommandLine[MAX_PATH+1];
|
|
|
|
//
|
|
// Launch winhelp
|
|
//
|
|
|
|
ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
|
|
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
|
StartupInfo.cb = sizeof(StartupInfo);
|
|
StartupInfo.lpDesktop = L"Winsta0\\Winlogon";
|
|
StartupInfo.wShowWindow = SW_SHOW;
|
|
|
|
ZeroMemory(&szCommandLine, sizeof(szCommandLine));
|
|
|
|
lstrcpyU(szCommandLine, L"winhlp32.exe ");
|
|
|
|
switch (uCommand)
|
|
{
|
|
case HELP_FORCEFILE:
|
|
break;
|
|
case HELP_QUIT:
|
|
lstrcatU(szCommandLine, L"-G ");
|
|
break;
|
|
case HELP_WM_HELP:
|
|
case HELP_CONTEXTMENU:
|
|
{
|
|
DWORD dwWinId;
|
|
WCHAR szTemp[MAX_PATH];
|
|
|
|
MYDBGASSERT(prgWinIdHelpId);
|
|
dwWinId = GetWindowLong(hWndItem, GWL_ID);
|
|
//
|
|
// Check if user press right click on a valid window.
|
|
// If not abort
|
|
//
|
|
if (dwWinId == 0)
|
|
{
|
|
return (fRun);
|
|
}
|
|
|
|
// Find the context help Id
|
|
while (*prgWinIdHelpId != 0)
|
|
{
|
|
if (*prgWinIdHelpId == dwWinId)
|
|
{
|
|
prgWinIdHelpId ++;
|
|
wsprintfW(szTemp, L"-P -N %d ", *prgWinIdHelpId);
|
|
lstrcatU(szCommandLine, szTemp);
|
|
break;
|
|
}
|
|
|
|
// One for window id & one for help id
|
|
prgWinIdHelpId ++;
|
|
prgWinIdHelpId ++;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
CMTRACE1(TEXT("CMWinHelp Invalid uCommand = %d"), uCommand);
|
|
break;
|
|
}
|
|
|
|
if (lpszHelp)
|
|
{
|
|
lstrcatU(szCommandLine, lpszHelp);
|
|
}
|
|
|
|
CMTRACE1(TEXT("Help() - Launching %s"), szCommandLine);
|
|
|
|
if (NULL == CreateProcessU(NULL, szCommandLine,
|
|
NULL, NULL, FALSE, 0,
|
|
NULL, NULL,
|
|
&StartupInfo, &ProcessInfo))
|
|
{
|
|
LONG lRes;
|
|
|
|
lRes = GetLastError();
|
|
CMTRACE2(TEXT("CMWinHelp CreateProcess() of %s failed, GLE=%u."), szCommandLine, lRes);
|
|
}
|
|
else
|
|
{
|
|
CloseHandle(ProcessInfo.hProcess);
|
|
CloseHandle(ProcessInfo.hThread);
|
|
fRun = TRUE;
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
fRun = WinHelpU(hWndMain, lpszHelp, uCommand, (ULONG_PTR) prgWinIdHelpId);
|
|
}
|
|
|
|
return (fRun);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsLogonAsSystem
|
|
//
|
|
// Synopsis: Whether the current process is running in the system account
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: BOOL - TRUE if running in system account
|
|
//
|
|
// History: fengsun Created Header 7/13/98
|
|
// v-vijayb Modified to use SIDs instead of username
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CMUTILAPI BOOL IsLogonAsSystem()
|
|
{
|
|
static BOOL fLogonAsSystem = -1;
|
|
|
|
//
|
|
// If this function has been called before, return the saved value.
|
|
//
|
|
|
|
if (fLogonAsSystem != -1)
|
|
{
|
|
return fLogonAsSystem;
|
|
}
|
|
|
|
//
|
|
// Runs only under NT
|
|
//
|
|
|
|
if (OS_NT)
|
|
{
|
|
HANDLE hProcess, hAccess;
|
|
DWORD cbTokenInfo, cbRetInfo;
|
|
PTOKEN_USER pTokenInfo;
|
|
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
|
|
PSID pSystemSID = NULL;
|
|
|
|
//
|
|
// On NT, we pick the more stringent value for the default.
|
|
//
|
|
fLogonAsSystem = TRUE;
|
|
|
|
if (AllocateAndInitializeSid(&SIDAuthNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSystemSID))
|
|
{
|
|
hProcess = GetCurrentProcess(); // Pseudo handle, no need to close
|
|
if (OpenProcessToken(hProcess, TOKEN_READ, &hAccess))
|
|
{
|
|
BOOL bRet = GetTokenInformation(hAccess, TokenUser, NULL, 0, &cbRetInfo);
|
|
MYDBGASSERT((FALSE == bRet) && (0 != cbRetInfo));
|
|
|
|
if (cbRetInfo)
|
|
{
|
|
cbTokenInfo = cbRetInfo;
|
|
pTokenInfo = (PTOKEN_USER) CmMalloc( cbTokenInfo * sizeof(BYTE) );
|
|
if (pTokenInfo)
|
|
{
|
|
if (GetTokenInformation(hAccess, TokenUser, (PVOID) pTokenInfo, cbTokenInfo, &cbRetInfo))
|
|
{
|
|
if (EqualSid(pTokenInfo->User.Sid, pSystemSID))
|
|
{
|
|
CMTRACE(TEXT("Running under LOCALSYSTEM account"));
|
|
fLogonAsSystem = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fLogonAsSystem = FALSE;
|
|
}
|
|
}
|
|
CmFree(pTokenInfo);
|
|
}
|
|
}
|
|
CloseHandle(hAccess);
|
|
}
|
|
|
|
FreeSid(pSystemSID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fLogonAsSystem = FALSE;
|
|
}
|
|
|
|
return fLogonAsSystem;
|
|
}
|
|
|
|
|
|
|
|
|