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.
765 lines
21 KiB
765 lines
21 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1997
|
|
All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
compinfo.hxx
|
|
|
|
Abstract:
|
|
|
|
Local and remote computer information detection.
|
|
|
|
Author:
|
|
|
|
10/17/95 <adamk> created.
|
|
Steve Kiraly (SteveKi) 21-Jan-1996 used for downlevel server detection
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "compinfo.hxx"
|
|
#include "persist.hxx"
|
|
|
|
TCHAR const PROCESSOR_ARCHITECTURE_NAME_INTEL[] = TEXT("Intel");
|
|
TCHAR const PROCESSOR_ARCHITECTURE_NAME_UNKNOWN[] = TEXT("(unknown)");
|
|
|
|
TCHAR const ENVIRONMENT_IA64[] = TEXT("Windows IA64");
|
|
TCHAR const ENVIRONMENT_INTEL[] = TEXT("Windows NT x86");
|
|
TCHAR const ENVIRONMENT_WINDOWS[] = TEXT("Windows 4.0");
|
|
TCHAR const ENVIRONMENT_UNKNOWN[] = TEXT("(unknown)");
|
|
TCHAR const ENVIRONMENT_NATIVE[] = TEXT("");
|
|
|
|
TCHAR const c_szProductOptionsPath[] = TEXT( "System\\CurrentControlSet\\Control\\ProductOptions" );
|
|
TCHAR const c_szProductOptions[] = TEXT( "ProductType" );
|
|
TCHAR const c_szWorkstation[] = TEXT( "WINNT" );
|
|
TCHAR const c_szServer1[] = TEXT( "SERVERNT" );
|
|
TCHAR const c_szServer2[] = TEXT( "LANMANNT" );
|
|
TCHAR const c_szNetApi32Dll[] = TEXT( "netapi32.dll" );
|
|
|
|
CHAR const c_szNetServerGetInfo[] = "NetServerGetInfo";
|
|
CHAR const c_szNetApiBufferFree[] = "NetApiBufferFree";
|
|
|
|
CComputerInfo::
|
|
CComputerInfo(
|
|
IN LPCTSTR pComputerName
|
|
) : ComputerName( pComputerName),
|
|
ProductOption( kNtUnknown ),
|
|
OSIsDebugVersion( FALSE ),
|
|
ProcessorArchitecture( 0 ),
|
|
ProcessorCount( 0 )
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "CComputerInfo::ctor\n" ) );
|
|
memset( &OSInfo, 0, sizeof( OSInfo ) );
|
|
}
|
|
|
|
CComputerInfo::~CComputerInfo()
|
|
{
|
|
DBGMSG( DBG_TRACE, ( "CComputerInfo::dtor\n" ) );
|
|
}
|
|
|
|
LPCTSTR CComputerInfo::GetProcessorArchitectureName() const
|
|
{
|
|
SPLASSERT(IsInfoValid());
|
|
|
|
switch (ProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
{
|
|
return PROCESSOR_ARCHITECTURE_NAME_INTEL;
|
|
}
|
|
default:
|
|
{
|
|
return PROCESSOR_ARCHITECTURE_NAME_UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
LPCTSTR CComputerInfo::GetProcessorArchitectureDirectoryName() const
|
|
{
|
|
SPLASSERT(IsInfoValid());
|
|
|
|
switch (ProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
{
|
|
return TEXT("i386");
|
|
}
|
|
default:
|
|
{
|
|
return PROCESSOR_ARCHITECTURE_NAME_UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
LPCTSTR CComputerInfo::GetNativeEnvironment() const
|
|
{
|
|
SPLASSERT(IsInfoValid());
|
|
|
|
switch (ProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
{
|
|
if (IsRunningWindows95())
|
|
{
|
|
return ENVIRONMENT_WINDOWS;
|
|
}
|
|
else
|
|
{
|
|
return ENVIRONMENT_INTEL;
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
SPLASSERT(FALSE);
|
|
return ENVIRONMENT_UNKNOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CComputerInfo::IsInfoValid() const
|
|
{
|
|
// if OSInfo.dwOSVersionInfoSize is not zero, then the info has been retrieved
|
|
return (BOOL) (OSInfo.dwOSVersionInfoSize != 0);
|
|
}
|
|
|
|
BOOL CComputerInfo::IsRunningWindowsNT() const
|
|
{
|
|
return (OSInfo.dwPlatformId & VER_PLATFORM_WIN32_NT);
|
|
}
|
|
|
|
BOOL CComputerInfo::IsRunningWindows95() const
|
|
{
|
|
return (OSInfo.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS);
|
|
}
|
|
|
|
DWORD CComputerInfo::GetOSBuildNumber() const
|
|
{
|
|
// Build number is the low word of dwBuildNumber
|
|
return (OSInfo.dwBuildNumber & 0xFFFF);
|
|
}
|
|
|
|
WORD CComputerInfo::GetProcessorArchitecture() const
|
|
{
|
|
return ProcessorArchitecture;
|
|
}
|
|
|
|
DWORD CComputerInfo::GetSpoolerVersion() const
|
|
{
|
|
DWORD BuildNumber = GetOSBuildNumber();
|
|
DWORD SpoolerVersion;
|
|
|
|
// Windows NT 4.0 (and beyond)
|
|
if (BuildNumber > 1057)
|
|
{
|
|
SpoolerVersion = 2;
|
|
}
|
|
// Windows NT 3.5 and 3.51
|
|
else if (BuildNumber > 511)
|
|
{
|
|
SpoolerVersion = 1;
|
|
}
|
|
// Windows NT 3.1
|
|
else
|
|
{
|
|
SpoolerVersion = 0;
|
|
}
|
|
|
|
return SpoolerVersion;
|
|
}
|
|
|
|
BOOL CComputerInfo::GetInfo()
|
|
{
|
|
// NOTE: OSInfo.dwOSVersionInfoSize must be non-zero after the info is retrieved.
|
|
DWORD ErrorCode = ERROR_SUCCESS;
|
|
LPTSTR pCPUName = NULL;
|
|
LPTSTR pBuildNumberText = NULL;
|
|
LPTSTR pVersionText = NULL;
|
|
LPTSTR pCSDVersionText = NULL;
|
|
LPTSTR pOSTypeText = NULL;
|
|
|
|
// set size of version info structure
|
|
OSInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
if( ComputerName.bEmpty() )
|
|
{
|
|
SYSTEM_INFO SystemInfo;
|
|
|
|
// get operating system info
|
|
if (!GetVersionEx(&OSInfo))
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
|
|
// get hardware info
|
|
GetSystemInfo(&SystemInfo);
|
|
ProcessorArchitecture = SystemInfo.wProcessorArchitecture;
|
|
ProcessorCount = SystemInfo.dwNumberOfProcessors;
|
|
}
|
|
else
|
|
{
|
|
REGISTRY_KEY_INFO RegistryKeyInfo;
|
|
|
|
// determine operating system
|
|
// if this key is found, then the OS is Windows NT
|
|
// if this key cannot be found, then the OS is Windows 95
|
|
// otherwise, it is an error
|
|
pBuildNumberText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
|
|
TEXT("CurrentBuildNumber"));
|
|
if (GetLastError() == ERROR_CANTOPEN)
|
|
{
|
|
// operating system is Windows 95
|
|
OSInfo.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
|
|
|
|
// get OS version
|
|
pVersionText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
|
|
TEXT("Version"));
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
|
|
// parse OS version
|
|
OSInfo.dwMajorVersion = 0;
|
|
OSInfo.dwMinorVersion = 0;
|
|
OSInfo.dwBuildNumber = 0;
|
|
|
|
//
|
|
// The version string is of the form "X.X" The following
|
|
// code is used to isolate the major and minor verison
|
|
// to place in dwords respectivly.
|
|
//
|
|
LPTSTR p;
|
|
OSInfo.dwMajorVersion = _tcstoul( pVersionText, &p, 10);
|
|
|
|
//
|
|
// We know the conversion will stop at the '.' if it did
|
|
// skip past the '.' and do the minor version conversion.
|
|
//
|
|
if( *p == TEXT('.') )
|
|
{
|
|
p++;
|
|
OSInfo.dwMinorVersion = _tcstoul(p, &p, 10);
|
|
}
|
|
|
|
//
|
|
// We know the conversion will stop at the '.' if it did
|
|
// skip past the '.' and do the build number conversion.
|
|
//
|
|
if( *p == TEXT('.') )
|
|
{
|
|
p++;
|
|
OSInfo.dwBuildNumber = _tcstoul(p, NULL, 10);
|
|
}
|
|
|
|
// get CSD version
|
|
OSInfo.szCSDVersion[0] = TEXT('\0');
|
|
|
|
// processor must be Intel
|
|
ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
|
|
|
|
// processor count must be 1
|
|
ProcessorCount = 1;
|
|
}
|
|
else if (GetLastError() == ERROR_SUCCESS)
|
|
{
|
|
// operating system is Windows NT
|
|
OSInfo.dwPlatformId = VER_PLATFORM_WIN32_NT;
|
|
|
|
// parse build number (which was just retrieved)
|
|
OSInfo.dwBuildNumber = _tcstoul(pBuildNumberText, NULL, 10);
|
|
|
|
// get OS version
|
|
pVersionText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
|
|
TEXT("CurrentVersion"));
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// parse OS version
|
|
//
|
|
OSInfo.dwMajorVersion = 0;
|
|
OSInfo.dwMinorVersion = 0;
|
|
|
|
//
|
|
// The version string is of the form "X.X" The following
|
|
// code is used to isolate the major and minor verison
|
|
// to place in dwords respectivly.
|
|
//
|
|
LPTSTR p;
|
|
OSInfo.dwMajorVersion = _tcstoul( pVersionText, &p, 10);
|
|
|
|
//
|
|
// We know the conversion will stop at the '.' if it did
|
|
// skip past the '.' and do the minor version conversion.
|
|
//
|
|
if( *p == TEXT('.') )
|
|
{
|
|
p++;
|
|
OSInfo.dwMinorVersion = _tcstoul(p, NULL, 10);
|
|
}
|
|
|
|
// get CSD version
|
|
OSInfo.szCSDVersion[0] = TEXT('\0');
|
|
pCSDVersionText = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
|
|
TEXT("CSDVersion"));
|
|
if (GetLastError() == ERROR_SUCCESS)
|
|
{
|
|
StringCchCopy(OSInfo.szCSDVersion, ARRAYSIZE(OSInfo.szCSDVersion), pCSDVersionText);
|
|
}
|
|
|
|
// get name of cpu
|
|
pCPUName = AllocateRegistryString(ComputerName, HKEY_LOCAL_MACHINE,
|
|
TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
|
|
TEXT("Identifier"));
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
|
|
// determine processor architecture from cpu name
|
|
if (!_tcsnicmp(pCPUName, TEXT("80386-"), 6)
|
|
|| !_tcsnicmp(pCPUName, TEXT("80486-"), 6)
|
|
|| !_tcsnicmp(pCPUName, TEXT("x86 "), 4))
|
|
{
|
|
ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
|
|
}
|
|
else if(!_tcsnicmp(pCPUName, TEXT("IA64"), 4))
|
|
{
|
|
ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64;
|
|
}
|
|
else
|
|
{
|
|
SPLASSERT(FALSE);
|
|
ProcessorArchitecture = 0;
|
|
}
|
|
|
|
// get processor count
|
|
// On Windows NT, this can be determined by the number of subkeys of the following
|
|
// registry key.
|
|
if (!GetRegistryKeyInfo(ComputerName, HKEY_LOCAL_MACHINE,
|
|
TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor"),
|
|
&RegistryKeyInfo))
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
ProcessorCount = RegistryKeyInfo.NumSubKeys;
|
|
}
|
|
else
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
|
|
// determine whether OS is retail or debug
|
|
OSIsDebugVersion = FALSE;
|
|
if (OSInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
// get OS type
|
|
pOSTypeText = AllocateRegistryString(ComputerName,
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
|
|
TEXT("CurrentType"));
|
|
if (GetLastError() != ERROR_SUCCESS)
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
|
|
// if the type text contains the word "Checked",
|
|
// then it is a debug build
|
|
OSIsDebugVersion = (_tcsstr(pOSTypeText, TEXT("Checked")) != NULL);
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
if (pCPUName)
|
|
{
|
|
GlobalFree(pCPUName);
|
|
}
|
|
|
|
if (pBuildNumberText)
|
|
{
|
|
GlobalFree(pBuildNumberText);
|
|
}
|
|
|
|
if (pVersionText)
|
|
{
|
|
GlobalFree(pVersionText);
|
|
}
|
|
|
|
if (pCSDVersionText)
|
|
{
|
|
GlobalFree(pCSDVersionText);
|
|
}
|
|
|
|
if (pOSTypeText)
|
|
{
|
|
GlobalFree(pOSTypeText);
|
|
}
|
|
|
|
if (ErrorCode)
|
|
{
|
|
SetLastError(ErrorCode);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CComputerInfo::
|
|
GetProductInfo(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// If the request is for the local machine, do not access the net.
|
|
//
|
|
if( ComputerName.bEmpty() )
|
|
{
|
|
ProductOption = GetLocalProductInfo();
|
|
}
|
|
else
|
|
{
|
|
ProductOption = GetRemoteProductInfo();
|
|
}
|
|
|
|
DBGMSG( DBG_TRACE, ("CComputerInfo::GetPoductInfo %d\n", ProductOption ) );
|
|
|
|
return ProductOption != kNtUnknown;
|
|
}
|
|
|
|
BOOL
|
|
CComputerInfo::
|
|
IsRunningNtServer(
|
|
VOID
|
|
) const
|
|
{
|
|
return ProductOption == kNtServer;
|
|
}
|
|
|
|
BOOL
|
|
CComputerInfo::
|
|
IsRunningNtWorkstation(
|
|
VOID
|
|
) const
|
|
{
|
|
return ProductOption == kNtWorkstation;
|
|
}
|
|
|
|
CComputerInfo::ProductType
|
|
CComputerInfo::
|
|
GetLocalProductInfo(
|
|
VOID
|
|
)
|
|
{
|
|
TStatusB bStatus;
|
|
TString strProduct;
|
|
ProductType Option = kNtUnknown;
|
|
|
|
TPersist Product( c_szProductOptionsPath, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
|
|
|
|
bStatus DBGCHK = VALID_OBJ( Product );
|
|
|
|
if( bStatus )
|
|
{
|
|
bStatus DBGCHK = Product.bRead( c_szProductOptions, strProduct );
|
|
|
|
if( bStatus )
|
|
{
|
|
if( !_tcsicmp( c_szWorkstation, strProduct ) )
|
|
{
|
|
Option = kNtWorkstation;
|
|
}
|
|
else if( !_tcsicmp( c_szServer1, strProduct ) || !_tcsicmp( c_szServer2, strProduct ) )
|
|
{
|
|
Option = kNtServer;
|
|
}
|
|
else
|
|
{
|
|
Option = kNtUnknown;
|
|
}
|
|
}
|
|
}
|
|
return Option;
|
|
}
|
|
|
|
CComputerInfo::ProductType
|
|
CComputerInfo::
|
|
GetRemoteProductInfo(
|
|
VOID
|
|
)
|
|
{
|
|
ProductType Option = kNtUnknown;
|
|
|
|
TLibrary Lib( c_szNetApi32Dll );
|
|
|
|
if( VALID_OBJ( Lib ) )
|
|
{
|
|
typedef NET_API_STATUS (*pf_NetServerGetInfo)(LPCTSTR servername,DWORD level,LPBYTE *bufptr);
|
|
typedef NET_API_STATUS (*pf_NetApiBufferFree)(LPVOID Buffer);
|
|
|
|
pf_NetServerGetInfo pfNetServerGetInfo = (pf_NetServerGetInfo)Lib.pfnGetProc( c_szNetServerGetInfo );
|
|
pf_NetApiBufferFree pfNetApiBufferFree = (pf_NetApiBufferFree)Lib.pfnGetProc( c_szNetApiBufferFree );
|
|
PSERVER_INFO_101 si101 = NULL;
|
|
|
|
if( pfNetServerGetInfo && pfNetApiBufferFree )
|
|
{
|
|
//
|
|
// Get the server info
|
|
//
|
|
if( pfNetServerGetInfo( ComputerName, 101, (LPBYTE *)&si101 ) == NERR_Success )
|
|
{
|
|
DBGMSG( DBG_TRACE, ("Server_Info_101.sv101_type %x\n", si101->sv101_type ) );
|
|
|
|
DWORD dwType = si101->sv101_type;
|
|
|
|
//
|
|
// If the server type is NT and a server.
|
|
//
|
|
if( dwType & ( SV_TYPE_SERVER_NT | SV_TYPE_DOMAIN_CTRL | SV_TYPE_DOMAIN_BAKCTRL ) )
|
|
{
|
|
Option = kNtServer;
|
|
}
|
|
//
|
|
// If the server type is NT and a workstation.
|
|
//
|
|
else if( (dwType & ( SV_TYPE_NT | SV_TYPE_WORKSTATION )) == ( SV_TYPE_NT | SV_TYPE_WORKSTATION ) )
|
|
{
|
|
Option = kNtWorkstation;
|
|
}
|
|
else
|
|
{
|
|
Option = kNtUnknown;
|
|
}
|
|
|
|
//
|
|
// Release the server info structure.
|
|
//
|
|
pfNetApiBufferFree( si101 );
|
|
}
|
|
|
|
}
|
|
}
|
|
return Option;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AllocateRegistryString returns a copy of the string value stored at the
|
|
// specified registry key. The registry can be on either a remote machine or
|
|
// the local machine.
|
|
//
|
|
// Parameter Description
|
|
// -----------------------------------------------------------------------------
|
|
// pServerName Name of server on which registry resides.
|
|
// hRegistryRoot Registry root (i.e. HKEY_LOCAL_MACHINE). See RegConnectRegistry
|
|
// for acceptable values.
|
|
// pKeyName Name of registry key.
|
|
// pValueName Name of registry value. The value must be of type REG_SZ.
|
|
//
|
|
// Returns:
|
|
// If successful, the function returns a pointer to a copy of the string.
|
|
// If the function fails, GetLastError() will return an error code other than
|
|
// ERROR_SUCCESS, and NULL is returned from the function.
|
|
|
|
// Revision History:
|
|
// 10/17/95 <adamk> created.
|
|
//
|
|
LPTSTR
|
|
CComputerInfo::
|
|
AllocateRegistryString(
|
|
LPCTSTR pServerName,
|
|
HKEY hRegistryRoot,
|
|
LPCTSTR pKeyName,
|
|
LPCTSTR pValueName
|
|
)
|
|
{
|
|
DWORD ErrorCode = 0;
|
|
HKEY hRegistry = 0;
|
|
HKEY hRegistryKey = 0;
|
|
DWORD RegistryValueType = 0;
|
|
DWORD cbSize = 0;
|
|
DWORD cchSize = 0;
|
|
LPTSTR pString = NULL;
|
|
|
|
// connect to the registry of the specified machine
|
|
if (ErrorCode = RegConnectRegistry((LPTSTR) pServerName, hRegistryRoot, &hRegistry))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
// open the registry key
|
|
if (ErrorCode = RegOpenKeyEx(hRegistry, pKeyName, 0, KEY_QUERY_VALUE, &hRegistryKey))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
// query the value's type and size
|
|
if(ErrorCode = RegQueryValueEx(hRegistryKey, pValueName, NULL, &RegistryValueType, NULL,
|
|
&cbSize))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
// make sure the value is a string
|
|
if (RegistryValueType != REG_SZ)
|
|
{
|
|
ErrorCode = ERROR_INVALID_PARAMETER;
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// cbSize is the requested size of the buffer in bytes.
|
|
// allocate two more characters - one to make sure the
|
|
// cbSize / sizeof(TCHAR) is rounded up properly and one
|
|
// for a zero terminator to cover the case where the
|
|
// data is not properly zero terminated when written.
|
|
//
|
|
cchSize = cbSize / sizeof(TCHAR) + 2;
|
|
cbSize = cchSize * sizeof(TCHAR);
|
|
|
|
if (!(pString = (LPTSTR) GlobalAlloc(GMEM_FIXED, cbSize)))
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (ErrorCode = RegQueryValueEx(hRegistryKey, pValueName, NULL, &RegistryValueType,
|
|
(LPBYTE) pString, &cbSize))
|
|
{
|
|
ErrorCode = GetLastError();
|
|
goto CleanUp;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// RegQueryValueEx may not zero terminate the buffer if the
|
|
// data in the registry is not zero terminated. Make sure it
|
|
// is properly zero terminated.
|
|
//
|
|
pString[cchSize-1] = 0;
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
if (hRegistryKey)
|
|
{
|
|
RegCloseKey(hRegistryKey);
|
|
}
|
|
|
|
if (hRegistry)
|
|
{
|
|
RegCloseKey(hRegistry);
|
|
}
|
|
|
|
if (ErrorCode && pString)
|
|
{
|
|
GlobalFree(pString);
|
|
pString = NULL;
|
|
}
|
|
|
|
SetLastError (ErrorCode);
|
|
return pString;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetRegistrySubKeyCount returns the number of subkeys that the specified
|
|
// registry key contains. The registry can be on either a remote machine or
|
|
// the local machine.
|
|
//
|
|
// Parameter Description
|
|
// -----------------------------------------------------------------------------
|
|
// pServerName Name of server on which registry resides.
|
|
// hRegistryRoot Registry root (i.e. HKEY_LOCAL_MACHINE). See RegConnectRegistry
|
|
// for acceptable values.
|
|
// pKeyName Name of registry key.
|
|
//
|
|
// Returns:
|
|
// If successful, the function returns the number of subkeys and GetLastError()
|
|
// will return ERROR_SUCCESS. Otherwise, GetLastError() return the error code
|
|
// indicating the reason for the failure.
|
|
|
|
// Revision History:
|
|
// 10/23/95 <adamk> created.
|
|
//
|
|
BOOL
|
|
CComputerInfo::
|
|
GetRegistryKeyInfo(
|
|
LPCTSTR pServerName,
|
|
HKEY hRegistryRoot,
|
|
LPCTSTR pKeyName,
|
|
REGISTRY_KEY_INFO *pKeyInfo
|
|
)
|
|
{
|
|
DWORD ErrorCode = 0;
|
|
HKEY hRegistry = 0;
|
|
HKEY hRegistryKey = 0;
|
|
|
|
// connect to the registry of the specified machine
|
|
if (ErrorCode = RegConnectRegistry((LPTSTR) pServerName, hRegistryRoot, &hRegistry))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
// open the registry key
|
|
if (ErrorCode = RegOpenKeyEx(hRegistry, pKeyName, 0, KEY_QUERY_VALUE, &hRegistryKey))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
// get the key info
|
|
if (ErrorCode = RegQueryInfoKey(hRegistryKey, NULL, 0, 0, &pKeyInfo->NumSubKeys,
|
|
&pKeyInfo->MaxSubKeyLength, &pKeyInfo->MaxClassLength, &pKeyInfo->NumValues,
|
|
&pKeyInfo->MaxValueNameLength, &pKeyInfo->MaxValueDataLength,
|
|
&pKeyInfo->SecurityDescriptorLength, &pKeyInfo->LastWriteTime))
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
CleanUp:
|
|
|
|
if (hRegistryKey)
|
|
{
|
|
RegCloseKey(hRegistryKey);
|
|
}
|
|
|
|
if (hRegistry)
|
|
{
|
|
RegCloseKey(hRegistry);
|
|
}
|
|
|
|
if (ErrorCode)
|
|
{
|
|
SetLastError(ErrorCode);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|