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.
 
 
 
 
 
 

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;
}