2025-04-27 07:49:33 -04:00

1022 lines
22 KiB
C++

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
metakey.cpp
Abstract:
A class to help manipulate metabase keys.
Author:
Magnus Hedlund (MagnusH) --
Revision History:
--*/
#include "stdafx.h"
#include "metakey.h"
#include <stdio.h>
#define _WIN32_WINNT 0x0400
#include <objbase.h>
#define MD_DEFAULT_TIMEOUT 5000
static BOOL IsValidIntegerSubKey ( LPCWSTR wszSubKey );
//$-------------------------------------------------------------------
//
// CreateMetabaseObject
//
// Description:
//
// Creates an instance of the metabase object on the given
// machine and initializes it.
//
// Parameters:
//
// wszMachine - The machine to create the metabase on.
// ppMetabase - Returns the resulting metabase pointer.
//
// Returns:
//
// Error code from CoCreateInstance or the metabase routines.
//
//--------------------------------------------------------------------
HRESULT CreateMetabaseObject ( LPCWSTR wszMachine, IMSAdminBase ** ppMetabaseResult )
{
TraceFunctEnter ( "CreateMetabaseObject" );
// Check parameters:
_ASSERT ( ppMetabaseResult != NULL );
_ASSERT ( IS_VALID_OUT_PARAM ( ppMetabaseResult ) );
if ( ppMetabaseResult == NULL ) {
FatalTrace ( 0, "Bad Return Pointer" );
TraceFunctLeave ();
return E_POINTER;
}
// Variables:
HRESULT hr = NOERROR;
CComPtr<IMSAdminBase> pMetabase;
MULTI_QI mqi[1];
COSERVERINFO coserver;
// Zero the out parameter:
*ppMetabaseResult = NULL;
// QI for IID_IMSAdminBase:
mqi[0].pIID = &IID_IMSAdminBase;
mqi[0].pItf = NULL;
mqi[0].hr = 0;
// Which remote server to talk to:
coserver.dwReserved1 = 0;
coserver.dwReserved2 = 0;
coserver.pwszName = const_cast<LPWSTR> (wszMachine);
coserver.pAuthInfo = NULL;
// Create the object:
hr = CoCreateInstanceEx (
CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
wszMachine ? &coserver : NULL,
1,
mqi );
if ( FAILED(hr) ) {
ErrorTraceX ( 0, "CoCreate(metabase) failed %x", hr );
goto Exit;
}
if ( FAILED(mqi[0].hr) ) {
hr = mqi[0].hr;
ErrorTraceX ( 0, "QI(metabase) failed %x", hr );
goto Exit;
}
// Get the interface pointer:
pMetabase = (IMSAdminBase *) mqi[0].pItf;
mqi[0].pItf->Release ();
// Return the interface pointer:
_ASSERT ( pMetabase );
*ppMetabaseResult = pMetabase;
pMetabase->AddRef();
Exit:
TraceFunctLeave ();
return hr;
// pMetabase will be released automatically.
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::CMetabaseKey
//
// Description:
//
// Initializes the CMetabaseKey
//
// Parameters:
//
// pMetabase - a pointer to the metabase object.
//
//--------------------------------------------------------------------
CMetabaseKey::CMetabaseKey ( IMSAdminBase * pMetabase )
{
_ASSERT ( pMetabase );
m_pMetabase = pMetabase;
m_hKey = NULL;
m_cChildren = 0;
m_cIntegerChildren = 0;
m_indexCursor = 0;
m_dwMaxIntegerChild = 0;
pMetabase->AddRef ();
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::~CMetabaseKey
//
// Description:
//
// Destroys the metabase key
//
//--------------------------------------------------------------------
CMetabaseKey::~CMetabaseKey ( )
{
Close ();
if ( m_pMetabase ) {
m_pMetabase->Release ();
}
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::Open
//
// Description:
//
// Opens a key and associates that key with this object.
//
// Parameters:
//
// hParentKey - the already open key to use a base.
// szPath - path of the key to open
// dwPermissions - READ or WRITE access.
//
// Returns:
//
// see IMSAdminBase::OpenKey
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::Open ( METADATA_HANDLE hParentKey, IN LPCWSTR szPath, DWORD dwPermissions )
{
TraceFunctEnter ( "CMetabaseKey::Open" );
HRESULT hr = NOERROR;
Close ();
hr = m_pMetabase->OpenKey (
hParentKey,
szPath,
dwPermissions,
MD_DEFAULT_TIMEOUT,
&m_hKey
);
if ( FAILED(hr) ) {
ErrorTraceX ( (LPARAM) this, "Failed to open key %s: %x", szPath, hr );
goto Exit;
}
Exit:
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::Attach
//
// Description:
//
// Attaches this object to an already opened metabase key.
//
// Parameters:
//
// hKey - the opened metabase key
//
//--------------------------------------------------------------------
void CMetabaseKey::Attach ( METADATA_HANDLE hKey )
{
Close ();
_ASSERT ( hKey != NULL );
m_hKey = hKey;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::Detach
//
// Description:
//
// Detaches the metabase key from this object and returns it
//
// Returns:
//
// The key handle that this object is holding.
//
//--------------------------------------------------------------------
METADATA_HANDLE CMetabaseKey::Detach ( )
{
METADATA_HANDLE hKeyResult;
hKeyResult = m_hKey;
m_hKey = NULL;
return hKeyResult;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::Close
//
// Description:
//
// Closes the key that this object has open.
//
//--------------------------------------------------------------------
void CMetabaseKey::Close ( )
{
TraceFunctEnter ( "CMetabaseKey::Close" );
HRESULT hr;
if ( m_hKey ) {
hr = m_pMetabase->CloseKey ( m_hKey );
_ASSERT ( SUCCEEDED(hr) );
m_hKey = NULL;
}
TraceFunctLeave ();
}
void CMetabaseKey::GetLastChangeTime ( FILETIME * pftGMT, LPCWSTR wszPath )
{
_ASSERT ( m_hKey );
_ASSERT ( IS_VALID_OUT_PARAM ( pftGMT ) );
HRESULT hr;
hr = m_pMetabase->GetLastChangeTime ( m_hKey, wszPath, pftGMT, FALSE );
_ASSERT ( SUCCEEDED(hr) );
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::Save
//
// Description:
//
// Saves the changes.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::Save ( )
{
TraceFunctEnter ( "CMetabaseKey::Save" );
HRESULT hr;
hr = m_pMetabase->SaveData ( );
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::GetChildCount
//
// Description:
//
// Returns the number of subkeys of the current metabase key.
//
// Parameters:
//
// pcChildren - resulting number of subkeys.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::GetChildCount ( OUT DWORD * pcChildren )
{
_ASSERT ( m_hKey != NULL );
if ( m_cChildren != 0 ) {
*pcChildren = m_cChildren;
return NOERROR;
}
HRESULT hr;
hr = CountSubkeys (
NULL,
&m_cChildren,
&m_cIntegerChildren,
NULL,
&m_dwMaxIntegerChild
);
*pcChildren = m_cChildren;
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::GetIntegerChildCount
//
// Description:
//
// Returns the number of integer subkeys of the current key.
//
// Parameters:
//
// pcIntegerChildren - the number of integer subkeys of the currently
// opened key.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::GetIntegerChildCount ( OUT DWORD * pcIntegerChildren )
{
_ASSERT ( m_hKey != NULL );
if ( m_cChildren != 0 ) {
*pcIntegerChildren = m_cIntegerChildren;
return NOERROR;
}
HRESULT hr;
hr = CountSubkeys (
NULL,
&m_cChildren,
&m_cIntegerChildren,
NULL,
&m_dwMaxIntegerChild
);
*pcIntegerChildren = m_cIntegerChildren;
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::GetCustomChildCount
//
// Description:
//
// Returns the number of subkeys of the current metabase key
// for which fpIsCustomKey returns true.
//
// Parameters:
//
// pcCustomChildren - resulting number of subkeys.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::GetCustomChildCount (
KEY_TEST_FUNCTION fpIsCustomKey,
OUT DWORD * pcCustomChildren
)
{
_ASSERT ( m_hKey != NULL );
_ASSERT ( fpIsCustomKey );
_ASSERT ( IS_VALID_OUT_PARAM ( pcCustomChildren ) );
HRESULT hr;
hr = CountSubkeys (
fpIsCustomKey,
&m_cChildren,
&m_cIntegerChildren,
pcCustomChildren,
&m_dwMaxIntegerChild
);
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::BeginChildEnumeration
//
// Description:
//
// Sets up the object to enumerate subkeys.
// Call before calling NextChild or NextIntegerChild.
//
//--------------------------------------------------------------------
void CMetabaseKey::BeginChildEnumeration ( )
{
TraceFunctEnter ( "CMetabaseKey::BeginChildEnumeration" );
_ASSERT ( m_hKey != NULL );
HRESULT hr;
m_indexCursor = 0;
StateTrace ( (LPARAM) this, "Changing to Read Permission" );
hr = m_pMetabase->ChangePermissions ( m_hKey, 1, METADATA_PERMISSION_READ );
_ASSERT ( SUCCEEDED(hr) );
if ( FAILED (hr) ) {
ErrorTraceX ( (LPARAM) this, "Failed to change permissions to read: %x", hr );
}
TraceFunctLeave ();
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::NextChild
//
// Description:
//
// Returns the name of the next subkey.
// Call BeginChildEnumeration before calling NextChild
//
// Parameters:
//
// szChildKey - the resulting key name
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::NextChild ( OUT LPWSTR wszChildKey )
{
TraceFunctEnter ( "CMetabaseKey::NextChild" );
_ASSERT ( IS_VALID_OUT_PARAM ( wszChildKey ) );
_ASSERT ( m_hKey != NULL );
HRESULT hr;
*wszChildKey = NULL;
// Use the m_indexCursor to enumerated the next child:
hr = m_pMetabase->EnumKeys ( m_hKey, _T(""), wszChildKey, m_indexCursor );
if ( FAILED (hr) ) {
ErrorTraceX ( (LPARAM) this, "Failed to get next child: %x", hr );
goto Exit;
}
m_indexCursor++;
Exit:
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::NextIntegerChild
//
// Description:
//
// Returns the name of the next integer subkey.
// Call BeginChildEnumeration before calling NextIntegerChild
//
// Parameters:
//
// pdwID - the integer value of the subkey.
// szIntegerChildKey - the subkey name string.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::NextIntegerChild ( OUT DWORD * pdwID, OUT LPWSTR wszIntegerChildKey )
{
TraceFunctEnter ( "CMetabaseKey::NextChild" );
_ASSERT ( IS_VALID_OUT_PARAM ( pdwID ) );
_ASSERT ( IS_VALID_OUT_PARAM ( wszIntegerChildKey ) );
_ASSERT ( m_hKey != NULL );
_ASSERT ( m_indexCursor < m_cIntegerChildren );
HRESULT hr;
BOOL fFoundInteger;
*pdwID = 0;
*wszIntegerChildKey = NULL;
for ( fFoundInteger = FALSE; !fFoundInteger; ) {
// Use the m_indexCursor to enumerated the next child:
hr = m_pMetabase->EnumKeys ( m_hKey, _T(""), wszIntegerChildKey, m_indexCursor );
if ( FAILED (hr) ) {
goto Exit;
}
if ( IsValidIntegerSubKey ( wszIntegerChildKey ) ) {
fFoundInteger = TRUE;
*pdwID = _wtoi ( wszIntegerChildKey );
}
m_indexCursor++;
}
Exit:
// This means that you called NextIntegerChild more times than
// was possible:
_ASSERT ( HRESULTTOWIN32 ( hr ) != ERROR_NO_MORE_ITEMS );
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::NextCustomChild
//
// Description:
//
// Returns the name of the next subkey for which fpIsCustomKey
// returns true.
// Call BeginChildEnumeration before calling NextCustomChild
//
// Parameters:
//
// fpIsCustomKey - function that returns true if a given key
// should be returned.
// szChildKey - the resulting key name
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::NextCustomChild (
KEY_TEST_FUNCTION fpIsCustomKey,
OUT LPWSTR wszChildKey
)
{
TraceFunctEnter ( "CMetabaseKey::NextCustomChild" );
_ASSERT ( fpIsCustomKey );
_ASSERT ( IS_VALID_OUT_PARAM ( wszChildKey ) );
_ASSERT ( m_hKey != NULL );
_ASSERT ( m_indexCursor < m_cChildren );
HRESULT hr;
BOOL fFoundCustomKey;
*wszChildKey = NULL;
for ( fFoundCustomKey = FALSE; !fFoundCustomKey; ) {
// Use the m_indexCursor to enumerated the next child:
hr = m_pMetabase->EnumKeys ( m_hKey, _T(""), wszChildKey, m_indexCursor );
if ( FAILED (hr) ) {
goto Exit;
}
if ( fpIsCustomKey ( wszChildKey ) ) {
fFoundCustomKey = TRUE;
}
m_indexCursor++;
}
Exit:
// This means that you called NextCustomChild more times than
// was possible:
_ASSERT ( HRESULTTOWIN32 ( hr ) != ERROR_NO_MORE_ITEMS );
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::CreateChild
//
// Description:
//
// Creates the given path under the currently opened key.
// Changes the current key to write permission.
// Note: Does not call SaveData.
//
// Parameters:
//
// szChildPath - name of the subkey to create.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::CreateChild ( IN LPWSTR wszChildPath )
{
TraceFunctEnter ( "CMetabaseKey::CreateChild" );
_ASSERT ( wszChildPath );
_ASSERT ( m_hKey != NULL );
HRESULT hr;
StateTrace ( (LPARAM) this, "Changing to Write Permission" );
hr = m_pMetabase->ChangePermissions ( m_hKey, MD_DEFAULT_TIMEOUT, METADATA_PERMISSION_WRITE );
if ( FAILED(hr) ) {
goto Exit;
}
hr = m_pMetabase->AddKey ( m_hKey, wszChildPath );
if ( FAILED (hr) ) {
goto Exit;
}
/*
// !!!magnush - Should we save the data now?
hr = m_pMetabase->SaveData ();
if ( FAILED (hr) ) {
goto Exit;
}
*/
m_cChildren++;
if ( IsValidIntegerSubKey ( wszChildPath ) ) {
m_cIntegerChildren++;
}
Exit:
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::DestroyChild
//
// Description:
//
// Deletes the given subkey
// Changes the current key to write permission.
// Note: Does not call SaveData
//
// Parameters:
//
// szChildPath - the name of the subkey to delete.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::DestroyChild ( IN LPWSTR wszChildPath )
{
TraceFunctEnter ( "CMetabaseKey::DestroyChild" );
_ASSERT ( wszChildPath );
_ASSERT ( m_hKey != NULL );
HRESULT hr;
StateTrace ( (LPARAM) this, "Changing to Write Permission" );
hr = m_pMetabase->ChangePermissions ( m_hKey, MD_DEFAULT_TIMEOUT, METADATA_PERMISSION_WRITE );
if ( FAILED(hr) ) {
goto Exit;
}
hr = m_pMetabase->DeleteKey ( m_hKey, wszChildPath );
if ( FAILED (hr) ) {
goto Exit;
}
/*
// !!!magnush - Should we save the data now?
hr = m_pMetabase->SaveData ();
if ( FAILED (hr) ) {
goto Exit;
}
*/
m_cChildren--;
if ( IsValidIntegerSubKey ( wszChildPath ) ) {
m_cIntegerChildren--;
}
Exit:
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::CreateIntegerChild
//
// Description:
//
// Creates an integer subkey of the currently open key.
// This key will be 1 + the highest integer subkey.
//
// Parameters:
//
// pdwID - the resulting integer value.
// szChildPath - the resulting subkey path.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::CreateIntegerChild ( OUT DWORD * pdwID, OUT LPWSTR wszChildPath )
{
TraceFunctEnter ( "CMetabaseKEy::CreateIntegerChild" );
_ASSERT ( IS_VALID_OUT_PARAM ( pdwID ) );
_ASSERT ( IS_VALID_OUT_PARAM ( wszChildPath ) );
_ASSERT ( m_hKey != NULL );
HRESULT hr = NOERROR;
DWORD dwId;
*pdwID = 0;
*wszChildPath = NULL;
for ( dwId = 1; dwId != 0; dwId++ ) {
//
// Keep trying to add an instance key until it works:
//
wsprintf ( wszChildPath, _T("%d"), dwId );
hr = CreateChild ( wszChildPath );
if ( SUCCEEDED(hr) ) {
// We created the child, so lets get out of here.
break;
}
else if ( HRESULTTOWIN32 ( hr ) == ERROR_ALREADY_EXISTS ) {
// Child already exists, try the next one.
continue;
}
else {
// Real error: report it and bail.
ErrorTrace ( (LPARAM) this, "Error %d adding %s\n", HRESULTTOWIN32(hr), wszChildPath );
goto Exit;
}
}
if ( dwId == 0 ) {
hr = E_FAIL;
goto Exit;
}
_ASSERT ( SUCCEEDED(hr) );
if ( dwId > m_dwMaxIntegerChild ) {
m_dwMaxIntegerChild = dwId;
}
*pdwID = dwId;
Exit:
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::DestroyIntegerChild
//
// Description:
//
// Deletes the given integer subkey.
//
// Parameters:
//
// i - the subkey to delete
//
// Returns:
//
// metabase error code
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::DestroyIntegerChild ( IN DWORD i )
{
TraceFunctEnter ( "CMetabaseKey::DestroyIntegerChild" );
_ASSERT ( i != 0 );
_ASSERT ( m_hKey != NULL );
WCHAR wszChild [ METADATA_MAX_NAME_LEN ];
HRESULT hr;
wsprintf ( wszChild, _T("%d"), i );
hr = DestroyChild ( wszChild );
TraceFunctLeave ();
return hr;
}
//$-------------------------------------------------------------------
//
// CMetabaseKey::CountSubKeys
//
// Description:
//
// Returns the number of subkeys and integer subkeys of the
// current metabase key.
// Changes the key to read permission.
//
// Parameters:
//
// fpIsCustomKey - Function that takes a key and returns true
// if that key should be included in the custom child count.
// pcSubKeys - number of subkeys.
// pcIntegerSubKeys - number of integer subkeys.
// pcCustomChildren - the number of keys for which fpIsCustomKey
// returns true.
// pdwMaxIntegerSubkey - the highest integer subkey value.
//
// Returns:
//
// metabase error code.
//
//--------------------------------------------------------------------
HRESULT CMetabaseKey::CountSubkeys (
KEY_TEST_FUNCTION fpIsCustomKey,
OUT DWORD * pcSubKeys,
OUT DWORD * pcIntegerSubKeys,
OUT DWORD * pcCustomSubKeys,
OUT DWORD * pdwMaxIntegerSubKey
)
{
TraceFunctEnter ( "CMetabaseKey::CountSubKeys" );
_ASSERT ( pcSubKeys );
_ASSERT ( IS_VALID_OUT_PARAM ( pcSubKeys ) );
_ASSERT ( pcIntegerSubKeys );
_ASSERT ( IS_VALID_OUT_PARAM ( pcIntegerSubKeys ) );
// _ASSERT ( pcCustomSubKeys );
// _ASSERT ( IS_VALID_OUT_PARAM ( pcCustomSubKeys ) );
_ASSERT ( m_hKey != NULL );
// Zero the out parameter:
*pcSubKeys = 0;
*pcIntegerSubKeys = 0;
*pdwMaxIntegerSubKey = 0;
if ( pcCustomSubKeys ) {
*pcCustomSubKeys = 0;
}
HRESULT hr = NOERROR;
DWORD cItems = 0;
DWORD cIntegerItems = 0;
DWORD cCustomItems = 0;
DWORD dwMaxIntegerSubKey = 0;
WCHAR wszName [ METADATA_MAX_NAME_LEN ];
DWORD i = 0;
StateTrace ( (LPARAM) this, "Changing to Read Permission" );
hr = m_pMetabase->ChangePermissions ( m_hKey, 1, METADATA_PERMISSION_READ );
_ASSERT ( SUCCEEDED(hr) );
if ( FAILED (hr) ) {
ErrorTraceX ( (LPARAM) this, "Failed to change permissions to read: %x", hr );
goto Exit;
}
// Because I can't do a count here, I have to assume that the error means
// there are no more items:
for ( cItems = 0, cIntegerItems = 0, cCustomItems = 0, i = 0;
/* Don't know how long it will last */;
i++ ) {
hr = m_pMetabase->EnumKeys ( m_hKey, _T(""), wszName, i );
if ( HRESULTTOWIN32 ( hr ) == ERROR_NO_MORE_ITEMS ) {
// This is expected, end the loop:
hr = NOERROR;
break;
}
if ( FAILED (hr) ) {
// Unexpected error case.
ErrorTraceX ( 0, "Failed to enum object %d : %x", i, hr );
goto Exit;
}
cItems++;
if ( IsValidIntegerSubKey ( wszName ) ) {
DWORD dwSubkey;
cIntegerItems++;
dwSubkey = _wtoi ( wszName );
if ( dwSubkey > dwMaxIntegerSubKey ) {
dwMaxIntegerSubKey = dwSubkey;
}
}
else {
// Don't count this one:
ErrorTrace ( 0, "Bad subkey number: %d", i );
}
if ( fpIsCustomKey && fpIsCustomKey ( wszName ) ) {
cCustomItems++;
}
_ASSERT ( i < 0xf000000 ); // Infinite loop
}
// Now we have the count of items in cItems.
*pcSubKeys = cItems;
*pcIntegerSubKeys = cIntegerItems;
*pdwMaxIntegerSubKey = dwMaxIntegerSubKey;
if ( pcCustomSubKeys ) {
*pcCustomSubKeys = cCustomItems;
}
Exit:
TraceFunctLeave ();
return hr;
}
BOOL IsValidIntegerSubKey ( LPCWSTR wszSubKey )
{
TraceQuietEnter ( "IsValidIntegerSubKey" );
WCHAR wszIntegerKey [ METADATA_MAX_NAME_LEN ];
DWORD dwItemValue;
dwItemValue = _wtoi ( wszSubKey );
wsprintf ( wszIntegerKey, _T("%d"), dwItemValue );
// If the key is nonzero AND
// The key is just the itoa value of the number:
if ( dwItemValue != 0 &&
lstrcmp ( wszIntegerKey, wszSubKey ) == 0 ) {
return TRUE;
}
else {
return FALSE;
}
}