617 lines
16 KiB
C++
617 lines
16 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2000
|
|
//
|
|
// File: Util.cpp
|
|
//
|
|
// Contents: Generic utility functions and classes for dscmd
|
|
//
|
|
// History: 01-Oct-2000 JeffJon Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
|
|
#include "util.h"
|
|
|
|
#ifdef DBG
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
CDebugSpew DebugSpew;
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CDebugSpew::EnterFunction
|
|
//
|
|
// Synopsis: Outputs "Enter " followed by the function name (or any passed
|
|
// in string) and then calls Indent so that any output is indented
|
|
//
|
|
// Arguments: [nDebugLevel - IN] : the level at which this output should
|
|
// be spewed
|
|
// [pszFunction - IN] : a string to output to the console which
|
|
// is proceeded by "Entering "
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 01-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CDebugSpew::EnterFunction(UINT nDebugLevel, PCWSTR pszFunction)
|
|
{
|
|
//
|
|
// Verify input parameter
|
|
//
|
|
if (!pszFunction)
|
|
{
|
|
ASSERT(pszFunction);
|
|
return;
|
|
}
|
|
|
|
CComBSTR sbstrOutput(L"Entering ");
|
|
sbstrOutput += pszFunction;
|
|
|
|
//
|
|
// Output the debug spew
|
|
//
|
|
Output(nDebugLevel, sbstrOutput);
|
|
|
|
//
|
|
// Indent
|
|
//
|
|
Indent();
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CDebugSpew::LeaveFunction
|
|
//
|
|
// Synopsis: Outputs "Exit " followed by the function name (or any passed
|
|
// in string) and then calls Outdent
|
|
//
|
|
// Arguments: [nDebugLevel - IN] : the level at which this output should
|
|
// be spewed
|
|
// [pszFunction - IN] : a string to output to the console which
|
|
// is proceeded by "Leaving "
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 01-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CDebugSpew::LeaveFunction(UINT nDebugLevel, PCWSTR pszFunction)
|
|
{
|
|
//
|
|
// Verify input parameter
|
|
//
|
|
if (!pszFunction)
|
|
{
|
|
ASSERT(pszFunction);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Outdent
|
|
//
|
|
Outdent();
|
|
|
|
CComBSTR sbstrOutput(L"Leaving ");
|
|
sbstrOutput += pszFunction;
|
|
|
|
//
|
|
// Output the debug spew
|
|
//
|
|
Output(nDebugLevel, sbstrOutput);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CDebugSpew::LeaveFunctionHr
|
|
//
|
|
// Synopsis: Outputs "Exit " followed by the function name (or any passed
|
|
// in string), the HRESULT return value, and then calls Outdent
|
|
//
|
|
// Arguments: [nDebugLevel - IN] : the level at which this output should
|
|
// be spewed
|
|
// [pszFunction - IN] : a string to output to the console which
|
|
// is proceeded by "Leaving "
|
|
// [hr - IN] : the HRESULT result value that is being
|
|
// returned by the function
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 01-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CDebugSpew::LeaveFunctionHr(UINT nDebugLevel, PCWSTR pszFunction, HRESULT hr)
|
|
{
|
|
//
|
|
// Verify input parameter
|
|
//
|
|
if (!pszFunction)
|
|
{
|
|
ASSERT(pszFunction);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Outdent
|
|
//
|
|
Outdent();
|
|
|
|
CComBSTR sbstrOutput(L"Leaving ");
|
|
sbstrOutput += pszFunction;
|
|
|
|
//
|
|
// Append the return value
|
|
//
|
|
WCHAR pszReturn[30];
|
|
wsprintf(pszReturn, L" returning 0x%x", hr);
|
|
|
|
sbstrOutput += pszReturn;
|
|
|
|
//
|
|
// Output the debug spew
|
|
//
|
|
Output(nDebugLevel, sbstrOutput);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: OsName
|
|
//
|
|
// Synopsis: Returns a readable string of the platform
|
|
//
|
|
// Arguments: [refInfo IN] : reference the OS version info structure
|
|
// retrieved from GetVersionEx()
|
|
//
|
|
// Returns: PWSTR : returns a pointer to static text describing the
|
|
// platform. The returned string does not have to
|
|
// be freed.
|
|
//
|
|
// History: 20-Dec-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
PWSTR OsName(const OSVERSIONINFO& refInfo)
|
|
{
|
|
switch (refInfo.dwPlatformId)
|
|
{
|
|
case VER_PLATFORM_WIN32s:
|
|
{
|
|
return L"Win32s on Windows 3.1";
|
|
}
|
|
case VER_PLATFORM_WIN32_WINDOWS:
|
|
{
|
|
switch (refInfo.dwMinorVersion)
|
|
{
|
|
case 0:
|
|
{
|
|
return L"Windows 95";
|
|
}
|
|
case 1:
|
|
{
|
|
return L"Windows 98";
|
|
}
|
|
default:
|
|
{
|
|
return L"Windows 9X";
|
|
}
|
|
}
|
|
}
|
|
case VER_PLATFORM_WIN32_NT:
|
|
{
|
|
return L"Windows NT";
|
|
}
|
|
default:
|
|
{
|
|
ASSERT(false);
|
|
break;
|
|
}
|
|
}
|
|
return L"Some Unknown Windows Version";
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CDebugSpew::SpewHeader
|
|
//
|
|
// Synopsis: Outputs debug information like command line and build info
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 20-Dec-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CDebugSpew::SpewHeader()
|
|
{
|
|
//
|
|
// First output the command line
|
|
//
|
|
PWSTR pszCommandLine = GetCommandLine();
|
|
if (pszCommandLine)
|
|
{
|
|
Output(MINIMAL_LOGGING,
|
|
L"Command line: %s",
|
|
GetCommandLine());
|
|
}
|
|
|
|
//
|
|
// Output the module being used
|
|
//
|
|
do // false loop
|
|
{
|
|
//
|
|
// Get the file path
|
|
//
|
|
WCHAR pszFileName[MAX_PATH + 1];
|
|
::ZeroMemory(pszFileName, sizeof(pszFileName));
|
|
|
|
if (::GetModuleFileNameW(::GetModuleHandle(NULL), pszFileName, MAX_PATH) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Output(MINIMAL_LOGGING,
|
|
L"Module: %s",
|
|
pszFileName);
|
|
|
|
//
|
|
// get the file attributes
|
|
//
|
|
WIN32_FILE_ATTRIBUTE_DATA attr;
|
|
::ZeroMemory(&attr, sizeof(attr));
|
|
|
|
if (::GetFileAttributesEx(pszFileName, GetFileExInfoStandard, &attr) == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// convert the filetime to a system time
|
|
//
|
|
FILETIME localtime;
|
|
::FileTimeToLocalFileTime(&attr.ftLastWriteTime, &localtime);
|
|
SYSTEMTIME systime;
|
|
::FileTimeToSystemTime(&localtime, &systime);
|
|
|
|
//
|
|
// output the timestamp
|
|
//
|
|
Output(MINIMAL_LOGGING,
|
|
L"Timestamp: %2d/%2d/%4d %2d:%2d:%d.%d",
|
|
systime.wMonth,
|
|
systime.wDay,
|
|
systime.wYear,
|
|
systime.wHour,
|
|
systime.wMinute,
|
|
systime.wSecond,
|
|
systime.wMilliseconds);
|
|
} while (false);
|
|
|
|
//
|
|
// Get the system info
|
|
//
|
|
OSVERSIONINFO info;
|
|
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
BOOL success = ::GetVersionEx(&info);
|
|
ASSERT(success);
|
|
|
|
//
|
|
// Get the Whistler build lab version
|
|
//
|
|
CComBSTR sbstrLabInfo;
|
|
|
|
do // false loop
|
|
{
|
|
HKEY key = 0;
|
|
LONG err = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
L"Software\\Microsoft\\Windows NT\\CurrentVersion",
|
|
0,
|
|
KEY_READ,
|
|
&key);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
WCHAR buf[MAX_PATH + 1];
|
|
::ZeroMemory(buf, sizeof(buf));
|
|
|
|
DWORD type = 0;
|
|
DWORD bufSize = MAX_PATH + 1;
|
|
|
|
err = ::RegQueryValueEx(key,
|
|
L"BuildLab",
|
|
0,
|
|
&type,
|
|
reinterpret_cast<BYTE*>(buf),
|
|
&bufSize);
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
sbstrLabInfo = buf;
|
|
} while (false);
|
|
|
|
Output(MINIMAL_LOGGING,
|
|
L"Build: %s %d.%d build %d %s (BuildLab:%s)",
|
|
OsName(info),
|
|
info.dwMajorVersion,
|
|
info.dwMinorVersion,
|
|
info.dwBuildNumber,
|
|
info.szCSDVersion,
|
|
sbstrLabInfo);
|
|
|
|
//
|
|
// Output a blank line to separate the header from the rest of the output
|
|
//
|
|
Output(MINIMAL_LOGGING,
|
|
L"\n");
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CDebugSpew::Output
|
|
//
|
|
// Synopsis: Outputs the passed in string to stdout proceeded by the number
|
|
// of spaces specified by GetIndent()
|
|
//
|
|
// Arguments: [nDebugLevel - IN] : the level at which this output should
|
|
// be spewed
|
|
// [pszOutput - IN] : a format string to output to the console
|
|
// [... - IN] : a variable argument list to be formatted
|
|
// into pszOutput similar to wprintf
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 01-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void CDebugSpew::Output(UINT nDebugLevel, PCWSTR pszOutput, ...)
|
|
{
|
|
if (nDebugLevel <= GetDebugLevel())
|
|
{
|
|
//
|
|
// Verify parameters
|
|
//
|
|
if (!pszOutput)
|
|
{
|
|
ASSERT(pszOutput);
|
|
return;
|
|
}
|
|
|
|
va_list args;
|
|
va_start(args, pszOutput);
|
|
|
|
int nBuf;
|
|
WCHAR szBuffer[1024];
|
|
|
|
nBuf = _vsnwprintf(szBuffer, sizeof(szBuffer)/sizeof(WCHAR), pszOutput, args);
|
|
|
|
CComBSTR sbstrOutput;
|
|
|
|
//
|
|
// Insert the spaces for the indent
|
|
//
|
|
for (UINT nCount = 0; nCount < GetIndent(); nCount++)
|
|
{
|
|
sbstrOutput += L" ";
|
|
}
|
|
|
|
//
|
|
// Append the output string
|
|
//
|
|
sbstrOutput += szBuffer;
|
|
|
|
//
|
|
// Output the results
|
|
//
|
|
WriteStandardOut(L"%s\n", sbstrOutput);
|
|
|
|
va_end(args);
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Macro: MyA2WHelper
|
|
//
|
|
// Synopsis: Converts a string from Ansi to Unicode in the OEM codepage
|
|
//
|
|
// Arguments: [lpw - IN/OUT] : buffer to receive the Unicode string
|
|
// [lpa - IN] : Ansi string to be converted
|
|
// [nChars - IN] : maximum number of characters that can fit in the buffer
|
|
// [acp - IN] : the codepage to use
|
|
//
|
|
// Returns: PWSTR : the Unicode string in the OEM codepage
|
|
//
|
|
// History: 04-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
inline PWSTR WINAPI MyA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
|
|
{
|
|
ATLASSERT(lpa != NULL);
|
|
ATLASSERT(lpw != NULL);
|
|
// verify that no illegal character present
|
|
// since lpw was allocated based on the size of lpa
|
|
// don't worry about the number of chars
|
|
lpw[0] = '\0';
|
|
MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
|
|
return lpw;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Macro: A2W_OEM
|
|
//
|
|
// Synopsis: Converts a string from Ansi to Unicode in the OEM codepage
|
|
//
|
|
// Arguments: [lpa - IN] : the string to be converted
|
|
//
|
|
// Returns: PWSTR : the Unicode string in the OEM codepage
|
|
//
|
|
// History: 04-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#define A2W_OEM(lpa) (\
|
|
((_lpaMine = lpa) == NULL) ? NULL : (\
|
|
_convert = (lstrlenA(_lpaMine)+1),\
|
|
MyA2WHelper((LPWSTR) alloca(_convert*2), _lpaMine, _convert, CP_OEMCP)))
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: _UnicodeToOemConvert
|
|
//
|
|
// Synopsis: takes the passed in string (pszUnicode) and converts it to
|
|
// the OEM code page
|
|
//
|
|
// Arguments: [pszUnicode - IN] : the string to be converted
|
|
// [sbstrOemUnicode - OUT] : the converted string
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 04-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
void _UnicodeToOemConvert(PCWSTR pszUnicode, CComBSTR& sbstrOemUnicode)
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
//
|
|
// add this for the macro to work
|
|
//
|
|
LPCSTR _lpaMine = NULL;
|
|
|
|
//
|
|
// convert to CHAR OEM
|
|
//
|
|
int nLen = lstrlen(pszUnicode);
|
|
LPSTR pszOemAnsi = new CHAR[3*(nLen+1)]; // more, to be sure...
|
|
if (pszOemAnsi)
|
|
{
|
|
CharToOem(pszUnicode, pszOemAnsi);
|
|
|
|
//
|
|
// convert it back to WCHAR on OEM CP
|
|
//
|
|
sbstrOemUnicode = A2W_OEM(pszOemAnsi);
|
|
delete[] pszOemAnsi;
|
|
pszOemAnsi = 0;
|
|
}
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: SpewAttrs(ADS_ATTR_INFO* pCreateAttrs, DWORD dwNumAttrs);
|
|
//
|
|
// Synopsis: Uses the DEBUG_OUTPUT macro to output the attributes and the
|
|
// values specified
|
|
//
|
|
// Arguments: [pAttrs - IN] : The ADS_ATTR_INFO
|
|
// [dwNumAttrs - IN] : The number of attributes in pAttrs
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 04-Oct-2000 JeffJon Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
#ifdef DBG
|
|
void SpewAttrs(ADS_ATTR_INFO* pAttrs, DWORD dwNumAttrs)
|
|
{
|
|
for (DWORD dwAttrIdx = 0; dwAttrIdx < dwNumAttrs; dwAttrIdx++)
|
|
{
|
|
if (pAttrs[dwAttrIdx].dwADsType == ADSTYPE_DN_STRING ||
|
|
pAttrs[dwAttrIdx].dwADsType == ADSTYPE_CASE_EXACT_STRING ||
|
|
pAttrs[dwAttrIdx].dwADsType == ADSTYPE_CASE_IGNORE_STRING ||
|
|
pAttrs[dwAttrIdx].dwADsType == ADSTYPE_PRINTABLE_STRING)
|
|
{
|
|
for (DWORD dwValueIdx = 0; dwValueIdx < pAttrs[dwAttrIdx].dwNumValues; dwValueIdx++)
|
|
{
|
|
if (pAttrs[dwAttrIdx].pADsValues[dwValueIdx].CaseIgnoreString)
|
|
{
|
|
DEBUG_OUTPUT(FULL_LOGGING, L" %s = %s",
|
|
pAttrs[dwAttrIdx].pszAttrName,
|
|
pAttrs[dwAttrIdx].pADsValues[dwValueIdx].CaseIgnoreString);
|
|
}
|
|
else
|
|
{
|
|
DEBUG_OUTPUT(FULL_LOGGING, L" %s = value being cleared",
|
|
pAttrs[dwAttrIdx].pszAttrName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: litow
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [li - IN] : reference to large integer to be converted to string
|
|
// [sResult - OUT] : Gets the output string
|
|
// Returns: void
|
|
//
|
|
// History: 25-Sep-2000 hiteshr Created
|
|
// Copied from dsadmin code base, changed work with CComBSTR
|
|
//---------------------------------------------------------------------------
|
|
|
|
void litow(LARGE_INTEGER& li, CComBSTR& sResult)
|
|
{
|
|
LARGE_INTEGER n;
|
|
n.QuadPart = li.QuadPart;
|
|
|
|
if (n.QuadPart == 0)
|
|
{
|
|
sResult = L"0";
|
|
}
|
|
else
|
|
{
|
|
CComBSTR sNeg;
|
|
sResult = L"";
|
|
if (n.QuadPart < 0)
|
|
{
|
|
sNeg = CComBSTR(L'-');
|
|
n.QuadPart *= -1;
|
|
}
|
|
while (n.QuadPart > 0)
|
|
{
|
|
WCHAR ch[2];
|
|
ch[0] = static_cast<WCHAR>(L'0' + static_cast<WCHAR>(n.QuadPart % 10));
|
|
ch[1] = L'\0';
|
|
sResult += ch;
|
|
n.QuadPart = n.QuadPart / 10;
|
|
}
|
|
sResult += sNeg;
|
|
}
|
|
|
|
//Reverse the string
|
|
WCHAR szTemp[256];
|
|
wcscpy(szTemp,sResult);
|
|
LPWSTR pStart,pEnd;
|
|
pStart = szTemp;
|
|
pEnd = pStart + wcslen(pStart) -1;
|
|
while(pStart < pEnd)
|
|
{
|
|
WCHAR ch = *pStart;
|
|
*pStart++ = *pEnd;
|
|
*pEnd-- = ch;
|
|
}
|
|
|
|
sResult = szTemp;
|
|
|
|
}
|