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.
835 lines
29 KiB
835 lines
29 KiB
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corporation, 1999 - 1999 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
cluster.cpp
|
|
handles starting/stopping cluster resources
|
|
|
|
FILE HISTORY:
|
|
|
|
*/
|
|
|
|
//define USE_CCLUSPROPLIST // tells Clushead.h to compile for the CClusPropList class
|
|
//include "clushead.h" // the Sample Include Header
|
|
|
|
#include "stdafx.h"
|
|
#include "cluster.h"
|
|
#include "objplus.h"
|
|
#include "ipaddres.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
DynamicDLL g_ClusDLL( _T("CLUSAPI.DLL"), g_apchClusFunctionNames );
|
|
DynamicDLL g_ResUtilsDLL( _T("RESUTILS.DLL"), g_apchResUtilsFunctionNames );
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ControlClusterService()
|
|
//
|
|
// Finds the cluster name using the following procedure:
|
|
// 1. Opens a handle to the local cluster (using NULL cluster name).
|
|
// 1. Enumerates the resources in the cluster.
|
|
// 2. Checks each resource to see if it is the core
|
|
// Network Name resource.
|
|
// 5. Finds the cluster name by retrieving the private properties
|
|
// of the core Network Name resource.
|
|
// 6. Online/Offline the service
|
|
//
|
|
// Arguments: ServiceName, start/stop flag
|
|
//
|
|
// Return value: Error code
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
ControlClusterService(LPCTSTR pszComputer, LPCTSTR pszResourceType, LPCTSTR pszServiceDesc, BOOL fStart)
|
|
{
|
|
HCLUSTER hCluster = NULL; // cluster handle
|
|
HCLUSENUM hClusEnum = NULL; // enumeration handle
|
|
HRESOURCE hRes = NULL; // resource handle
|
|
|
|
DWORD dwError = ERROR_SUCCESS; // captures return values
|
|
DWORD dwIndex = 0; // enumeration index; incremented to loop through all resources
|
|
DWORD dwResFlags = 0; // describes the flags set for a resource
|
|
DWORD dwEnumType = CLUSTER_ENUM_RESOURCE; // bitmask describing the cluster object(s) to enumerate
|
|
|
|
DWORD cchResNameSize = 0; // actual size (count of characters) of lpszResName
|
|
DWORD cchResNameAlloc = MAX_NAME_SIZE; // allocated size of lpszResName; MAX_NAME_SIZE = 256 (defined in clushead.h)
|
|
|
|
LPWSTR lpszResName = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // enumerated resource name
|
|
LPWSTR lpszResType = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // the resource type of the current resource name
|
|
|
|
BOOL bDoLoop = TRUE; // loop exit condition
|
|
int iResult = 0; // for return values
|
|
|
|
if ( !g_ClusDLL.LoadFunctionPointers() )
|
|
return dwError;
|
|
|
|
//
|
|
// Open a cluster handle.
|
|
// The NULL cluster name opens a handle to the local cluster.
|
|
//
|
|
hCluster = ((OPENCLUSTER) g_ClusDLL[CLUS_OPEN_CLUSTER])( pszComputer );
|
|
if (hCluster == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
Trace1("OpenCluster failed %d!", dwError );
|
|
goto ExitFunc;
|
|
}
|
|
|
|
//
|
|
// Open an enumeration handle
|
|
//
|
|
hClusEnum = ((CLUSTEROPENENUM) g_ClusDLL[CLUS_CLUSTER_OPEN_ENUM])( hCluster, dwEnumType );
|
|
if (hClusEnum == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
Trace1( "ClusterOpenEnum failed %d", dwError );
|
|
goto ExitFunc;
|
|
}
|
|
|
|
//
|
|
// Enumeration loop
|
|
//
|
|
while( bDoLoop == TRUE )
|
|
{
|
|
//
|
|
// Reset the name size for each iteration
|
|
//
|
|
cchResNameSize = cchResNameAlloc;
|
|
|
|
//
|
|
// Enumerate resource #<dwIndex>
|
|
//
|
|
dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum,
|
|
dwIndex,
|
|
&dwEnumType,
|
|
lpszResName,
|
|
&cchResNameSize );
|
|
//
|
|
// If the lpszResName buffer was too small, reallocate
|
|
// according to the size returned by cchResNameSize
|
|
//
|
|
if ( dwError == ERROR_MORE_DATA )
|
|
{
|
|
LocalFree( lpszResName );
|
|
|
|
cchResNameAlloc = cchResNameSize;
|
|
|
|
lpszResName = (LPWSTR) LocalAlloc( LPTR, cchResNameAlloc );
|
|
|
|
dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum,
|
|
dwIndex,
|
|
&dwEnumType,
|
|
lpszResName,
|
|
&cchResNameSize );
|
|
}
|
|
|
|
//
|
|
// Exit loop on any non-success.
|
|
// Includes ERROR_NO_MORE_ITEMS (no more objects to enumerate)
|
|
//
|
|
if ( dwError != ERROR_SUCCESS )
|
|
break;
|
|
|
|
//
|
|
// Open resource handle
|
|
//
|
|
hRes = ((OPENCLUSTERRESOURCE) g_ClusDLL[CLUS_OPEN_CLUSTER_RESOURCE])( hCluster, lpszResName );
|
|
|
|
if (hRes == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
Trace1 ( "OpenClusterResource failed %d", dwError);
|
|
goto ExitFunc;
|
|
}
|
|
|
|
//
|
|
// Get the resource type.
|
|
//
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
|
|
NULL,
|
|
0,
|
|
lpszResType,
|
|
cchResNameAlloc,
|
|
&cchResNameSize);
|
|
|
|
//
|
|
// Reallocation routine if lpszResType is too small
|
|
//
|
|
if ( dwError == ERROR_MORE_DATA )
|
|
{
|
|
LocalFree( lpszResType );
|
|
|
|
cchResNameAlloc = cchResNameSize;
|
|
|
|
lpszResType = (LPWSTR) LocalAlloc( LPTR, cchResNameAlloc );
|
|
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
|
|
NULL,
|
|
0,
|
|
lpszResType,
|
|
cchResNameAlloc,
|
|
&cchResNameSize);
|
|
}
|
|
|
|
if ( dwError != ERROR_SUCCESS )
|
|
break;
|
|
|
|
if ( lstrcmpi( lpszResType, pszResourceType ) == 0 )
|
|
{
|
|
//
|
|
// do the online/offline stuff here
|
|
//
|
|
if (fStart)
|
|
{
|
|
dwError = StartResource(pszComputer, hRes, pszServiceDesc);
|
|
}
|
|
else
|
|
{
|
|
dwError = StopResource(pszComputer, hRes, pszServiceDesc);
|
|
}
|
|
|
|
bDoLoop = FALSE;
|
|
}
|
|
|
|
((CLOSECLUSTERRESOURCE) g_ClusDLL[CLUS_CLOSE_CLUSTER_RESOURCE])( hRes );
|
|
|
|
dwIndex++; // increment the enumeration index
|
|
|
|
|
|
} // end Enumeration Loop
|
|
|
|
|
|
ExitFunc:
|
|
|
|
if ( hClusEnum != NULL )
|
|
((CLUSTERCLOSEENUM) g_ClusDLL[CLUS_CLUSTER_CLOSE_ENUM])( hClusEnum );
|
|
|
|
if ( hCluster != NULL )
|
|
((CLOSECLUSTER) g_ClusDLL[CLUS_CLOSE_CLUSTER])( hCluster );
|
|
|
|
LocalFree( lpszResName );
|
|
LocalFree( lpszResType );
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FIsComputerInRunningCluster()
|
|
//
|
|
// Determines if the given machine is in a running cluster
|
|
//
|
|
// Arguments: Computer Name
|
|
//
|
|
// Return value: Error code
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
FIsComputerInRunningCluster(LPCTSTR pszComputer)
|
|
{
|
|
DWORD dwClusterState = 0;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
BOOL fInRunningCluster = FALSE;
|
|
|
|
if ( !g_ClusDLL.LoadFunctionPointers() )
|
|
return dwError;
|
|
|
|
dwError = ((GETNODECLUSTERSTATE) g_ClusDLL[CLUS_GET_NODE_CLUSTER_STATE])( pszComputer, &dwClusterState );
|
|
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
if (dwClusterState == ClusterStateRunning)
|
|
fInRunningCluster = TRUE;
|
|
}
|
|
|
|
return fInRunningCluster;
|
|
}
|
|
|
|
|
|
DWORD
|
|
StartResource(LPCTSTR pszComputer, HRESOURCE hResource, LPCTSTR pszServiceDesc)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if ( !g_ClusDLL.LoadFunctionPointers() )
|
|
return dwError;
|
|
|
|
dwError = ((ONLINECLUSTERRESOURCE) g_ClusDLL[CLUS_ONLINE_CLUSTER_RESOURCE])( hResource );
|
|
|
|
if ( dwError == ERROR_IO_PENDING )
|
|
{
|
|
//
|
|
// Put up the dialog with the funky spinning thing to
|
|
// let the user know that something is happening
|
|
//
|
|
CServiceCtrlDlg dlgServiceCtrl(hResource, pszComputer, pszServiceDesc, TRUE);
|
|
|
|
dlgServiceCtrl.DoModal();
|
|
dwError = dlgServiceCtrl.m_dwErr;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
DWORD
|
|
StopResource(LPCTSTR pszComputer, HRESOURCE hResource, LPCTSTR pszServiceDesc)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if ( !g_ClusDLL.LoadFunctionPointers() )
|
|
return dwError;
|
|
|
|
dwError = ((OFFLINECLUSTERRESOURCE) g_ClusDLL[CLUS_OFFLINE_CLUSTER_RESOURCE])( hResource );
|
|
|
|
if ( dwError == ERROR_IO_PENDING )
|
|
{
|
|
//
|
|
// Put up the dialog with the funky spinning thing to
|
|
// let the user know that something is happening
|
|
//
|
|
CServiceCtrlDlg dlgServiceCtrl(hResource, pszComputer, pszServiceDesc, FALSE);
|
|
|
|
dlgServiceCtrl.DoModal();
|
|
dwError = dlgServiceCtrl.m_dwErr;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetClusterResourceIp()
|
|
//
|
|
// Finds the cluster name using the following procedure:
|
|
// 1. Opens a handle to the local cluster (using NULL cluster name).
|
|
// 1. Enumerates the resources in the cluster.
|
|
// 2. Checks each resource to see if it is the core
|
|
// Network Name resource.
|
|
// 5. Finds the cluster name by retrieving the private properties
|
|
// of the core Network Name resource.
|
|
//
|
|
// Arguments: ServiceName
|
|
//
|
|
// Return value: Error code
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
DWORD
|
|
GetClusterResourceIp(LPCTSTR pszComputer, LPCTSTR pszResourceType, CString & strAddress)
|
|
{
|
|
HCLUSTER hCluster = NULL; // cluster handle
|
|
HCLUSENUM hClusEnum = NULL; // enumeration handle
|
|
HRESOURCE hRes = NULL; // resource handle
|
|
HRESOURCE hResIp = NULL; // resource handle
|
|
|
|
DWORD dwError = ERROR_SUCCESS; // captures return values
|
|
DWORD dwIndex = 0; // enumeration index; incremented to loop through all resources
|
|
DWORD dwResFlags = 0; // describes the flags set for a resource
|
|
DWORD dwEnumType = CLUSTER_ENUM_RESOURCE; // bitmask describing the cluster object(s) to enumerate
|
|
|
|
DWORD cchResNameSize = 0; // actual size (count of characters) of lpszResName
|
|
DWORD cchResNameAlloc = MAX_NAME_SIZE; // allocated size of lpszResName; MAX_NAME_SIZE = 256 (defined in clushead.h)
|
|
|
|
LPWSTR lpszResName = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // enumerated resource name
|
|
LPWSTR lpszResType = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE); // the resource type of the current resource name
|
|
|
|
BOOL bDoLoop = TRUE; // loop exit condition
|
|
|
|
HKEY hkeyProvider = NULL;
|
|
HRESENUM hResEnum = NULL;
|
|
int ienum;
|
|
LPWSTR pwszName = NULL;
|
|
DWORD cchName;
|
|
DWORD cchmacName;
|
|
DWORD dwRetType;
|
|
LPWSTR lpszResIpType = NULL;
|
|
|
|
strAddress.Empty();
|
|
|
|
if ( !g_ClusDLL.LoadFunctionPointers() )
|
|
return dwError;
|
|
|
|
//
|
|
// Open a cluster handle.
|
|
// The NULL cluster name opens a handle to the local cluster.
|
|
//
|
|
hCluster = ((OPENCLUSTER) g_ClusDLL[CLUS_OPEN_CLUSTER])( pszComputer );
|
|
if (hCluster == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
Trace1("OpenCluster failed %d!", dwError );
|
|
goto ExitFunc;
|
|
}
|
|
|
|
//
|
|
// Open an enumeration handle
|
|
//
|
|
hClusEnum = ((CLUSTEROPENENUM) g_ClusDLL[CLUS_CLUSTER_OPEN_ENUM])( hCluster, dwEnumType );
|
|
if (hClusEnum == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
Trace1( "ClusterOpenEnum failed %d", dwError );
|
|
goto ExitFunc;
|
|
}
|
|
|
|
//
|
|
// Enumeration loop
|
|
//
|
|
while( bDoLoop == TRUE )
|
|
{
|
|
//
|
|
// Reset the name size for each iteration
|
|
//
|
|
cchResNameSize = cchResNameAlloc;
|
|
|
|
//
|
|
// Enumerate resource #<dwIndex>
|
|
//
|
|
dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum,
|
|
dwIndex,
|
|
&dwEnumType,
|
|
lpszResName,
|
|
&cchResNameSize );
|
|
//
|
|
// If the lpszResName buffer was too small, reallocate
|
|
// according to the size returned by cchResNameSize
|
|
//
|
|
if ( dwError == ERROR_MORE_DATA )
|
|
{
|
|
LocalFree( lpszResName );
|
|
|
|
cchResNameAlloc = cchResNameSize;
|
|
|
|
lpszResName = (LPWSTR) LocalAlloc( LPTR, cchResNameAlloc );
|
|
|
|
dwError = ((CLUSTERENUM) g_ClusDLL[CLUS_CLUSTER_ENUM])( hClusEnum,
|
|
dwIndex,
|
|
&dwEnumType,
|
|
lpszResName,
|
|
&cchResNameSize );
|
|
}
|
|
|
|
//
|
|
// Exit loop on any non-success.
|
|
// Includes ERROR_NO_MORE_ITEMS (no more objects to enumerate)
|
|
//
|
|
if ( dwError != ERROR_SUCCESS )
|
|
break;
|
|
|
|
//
|
|
// Open resource handle
|
|
//
|
|
hRes = ((OPENCLUSTERRESOURCE) g_ClusDLL[CLUS_OPEN_CLUSTER_RESOURCE])( hCluster, lpszResName );
|
|
|
|
if (hRes == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
Trace1 ( "OpenClusterResource failed %d", dwError);
|
|
goto ExitFunc;
|
|
}
|
|
|
|
dwError = GetResourceType(hRes, &lpszResType, cchResNameAlloc, &cchResNameSize);
|
|
|
|
if ( dwError != ERROR_SUCCESS )
|
|
break;
|
|
|
|
if ( lstrcmpi( lpszResType, pszResourceType ) == 0 )
|
|
{
|
|
// found the right resource, enum dependencies and find the IP
|
|
hResEnum = ((CLUSTERRESOURCEOPENENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_OPEN_ENUM])( hRes,
|
|
CLUSTER_RESOURCE_ENUM_DEPENDS);
|
|
|
|
if (hResEnum)
|
|
{
|
|
// Allocate a name buffer.
|
|
cchmacName = 128;
|
|
pwszName = new WCHAR[cchmacName];
|
|
|
|
// Loop through the enumeration and add each dependent resource to the list.
|
|
for (ienum = 0 ; ; ienum++)
|
|
{
|
|
// Get the next item in the enumeration.
|
|
cchName = cchmacName;
|
|
|
|
dwError = ((CLUSTERRESOURCEENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_ENUM])( hResEnum,
|
|
ienum,
|
|
&dwRetType,
|
|
pwszName,
|
|
&cchName);
|
|
if (dwError == ERROR_MORE_DATA)
|
|
{
|
|
delete [] pwszName;
|
|
cchmacName = ++cchName;
|
|
pwszName = new WCHAR[cchmacName];
|
|
dwError = ((CLUSTERRESOURCEENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_ENUM])( hResEnum,
|
|
ienum,
|
|
&dwRetType,
|
|
pwszName,
|
|
&cchName);
|
|
} // if: name buffer was too small
|
|
|
|
if (dwError == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ASSERT(dwRetType == CLUSTER_RESOURCE_ENUM_DEPENDS);
|
|
|
|
//
|
|
// Open resource handle
|
|
//
|
|
hResIp = ((OPENCLUSTERRESOURCE) g_ClusDLL[CLUS_OPEN_CLUSTER_RESOURCE])( hCluster, pwszName );
|
|
if (hResIp == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
Trace1 ( "OpenClusterResource failed %d", dwError);
|
|
break;
|
|
}
|
|
|
|
lpszResIpType = (LPWSTR)LocalAlloc(LPTR, MAX_NAME_SIZE);
|
|
|
|
dwError = GetResourceType(hResIp, &lpszResIpType, MAX_NAME_SIZE, NULL);
|
|
|
|
if ( dwError != ERROR_SUCCESS )
|
|
break;
|
|
|
|
if ( lstrcmpiW( lpszResIpType, _T("IP Address") ) == 0 )
|
|
{
|
|
GetResourceIpAddress(hResIp, strAddress);
|
|
bDoLoop = FALSE;
|
|
} // if: IP Address resource found
|
|
|
|
((CLOSECLUSTERRESOURCE) g_ClusDLL[CLUS_CLOSE_CLUSTER_RESOURCE])( hResIp );
|
|
|
|
LocalFree( lpszResIpType );
|
|
|
|
hResIp = NULL;
|
|
lpszResIpType = NULL;
|
|
|
|
if (!strAddress.IsEmpty())
|
|
break; // found it
|
|
|
|
} // for: each dependency
|
|
|
|
delete [] pwszName;
|
|
dwError = ((CLUSTERRESOURCECLOSEENUM) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CLOSE_ENUM])( hResEnum );
|
|
}
|
|
|
|
}
|
|
|
|
((CLOSECLUSTERRESOURCE) g_ClusDLL[CLUS_CLOSE_CLUSTER_RESOURCE])( hRes );
|
|
|
|
dwIndex++; // increment the enumeration index
|
|
|
|
|
|
} // end Enumeration Loop
|
|
|
|
|
|
ExitFunc:
|
|
|
|
if ( hClusEnum != NULL )
|
|
((CLUSTERCLOSEENUM) g_ClusDLL[CLUS_CLUSTER_CLOSE_ENUM])( hClusEnum );
|
|
|
|
if ( hCluster != NULL )
|
|
((CLOSECLUSTER) g_ClusDLL[CLUS_CLOSE_CLUSTER])( hCluster );
|
|
|
|
LocalFree( lpszResName );
|
|
LocalFree( lpszResType );
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
DWORD
|
|
GetResourceType(HRESOURCE hRes, LPWSTR * ppszName, DWORD dwBufSizeIn, DWORD * pdwBufSizeOut)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
DWORD cchResNameSize = dwBufSizeIn;
|
|
DWORD cchResNameSizeNeeded = 0;
|
|
//
|
|
// Figure out how big a buffer we need.
|
|
//
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
|
|
NULL,
|
|
0,
|
|
*ppszName,
|
|
cchResNameSize,
|
|
&cchResNameSizeNeeded);
|
|
|
|
//
|
|
// Reallocation routine if lpszResType is too small
|
|
//
|
|
if ( dwError == ERROR_MORE_DATA )
|
|
{
|
|
cchResNameSize = cchResNameSizeNeeded;
|
|
|
|
LocalFree(*ppszName);
|
|
|
|
*ppszName = (LPWSTR) LocalAlloc( LPTR, cchResNameSize );
|
|
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
|
|
NULL,
|
|
0,
|
|
*ppszName,
|
|
cchResNameSize,
|
|
&cchResNameSizeNeeded);
|
|
}
|
|
|
|
if (pdwBufSizeOut)
|
|
*pdwBufSizeOut = cchResNameSizeNeeded;
|
|
|
|
return dwError;
|
|
}
|
|
|
|
DWORD
|
|
GetResourceIpAddress(HRESOURCE hRes, CString & strAddress)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
DWORD cbProps;
|
|
PVOID pvProps = NULL;
|
|
LPWSTR pszIPAddress = NULL;
|
|
|
|
// Loop to avoid goto's.
|
|
do
|
|
{
|
|
//
|
|
// Get the size of the private properties from the resource.
|
|
//
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&cbProps);
|
|
|
|
if ( (dwError != ERROR_SUCCESS) ||
|
|
(cbProps == 0) )
|
|
{
|
|
if ( dwError == ERROR_SUCCESS )
|
|
{
|
|
dwError = ERROR_INVALID_DATA;
|
|
} // if: no properties available
|
|
|
|
break;
|
|
|
|
} // if: error getting size of properties or no properties available
|
|
|
|
//
|
|
// Allocate the property buffer.
|
|
//
|
|
pvProps = LocalAlloc( LMEM_FIXED, cbProps );
|
|
if ( pvProps == NULL )
|
|
{
|
|
dwError = GetLastError();
|
|
break;
|
|
} // if: error allocating memory
|
|
|
|
//
|
|
// Get the private properties from the resource.
|
|
//
|
|
dwError = ((CLUSTERRESOURCECONTROL) g_ClusDLL[CLUS_CLUSTER_RESOURCE_CONTROL])( hRes,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES,
|
|
NULL,
|
|
0,
|
|
pvProps,
|
|
cbProps,
|
|
&cbProps);
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
} // if: error getting private properties
|
|
|
|
//
|
|
// Find the Address property.
|
|
//
|
|
dwError = FindSzProp(pvProps, cbProps, L"Address", &pszIPAddress);
|
|
|
|
if ( dwError != ERROR_SUCCESS )
|
|
{
|
|
break;
|
|
} // if: error finding the Address property
|
|
|
|
} while ( 0 );
|
|
|
|
//
|
|
// Cleanup.
|
|
//
|
|
|
|
strAddress = pszIPAddress;
|
|
|
|
LocalFree( pvProps );
|
|
|
|
return dwError;
|
|
}
|
|
|
|
DWORD FindSzProp
|
|
(
|
|
LPVOID pvProps,
|
|
DWORD cbProps,
|
|
LPCWSTR pszTarget,
|
|
LPWSTR * ppszOut
|
|
)
|
|
{
|
|
|
|
BOOL DoLoop = TRUE; // loop exit condition
|
|
BOOL Found = FALSE; // tests whether property has been found
|
|
DWORD dwError = ERROR_SUCCESS; // for return values
|
|
|
|
DWORD cbOffset = 0; // offset to next entry in the value list
|
|
DWORD cbPosition = 0; // tracks the advance through the value list buffer
|
|
|
|
CLUSPROP_BUFFER_HELPER ListEntry; // to parse the list
|
|
|
|
//
|
|
// Set the pb member to the start of the list
|
|
//
|
|
ListEntry.pb = (BYTE *) pvProps;
|
|
|
|
//
|
|
// Main loop:
|
|
// 1. Check syntax of current list entry
|
|
// 2. If it is a property name, check that we have the right property.
|
|
// 3. If it is a binary value, check that we found the right name.
|
|
// 4. Advance the position counter and test vs. size of list.
|
|
//
|
|
do
|
|
{
|
|
switch( *ListEntry.pdw ) // check the syntax of the entry
|
|
{
|
|
case CLUSPROP_SYNTAX_NAME:
|
|
//
|
|
// If this is the Security property, flag Found as TRUE.
|
|
// The next pass through the loop should yield the Security value.
|
|
//
|
|
if ( lstrcmpi( ListEntry.pName->sz, pszTarget ) == 0 )
|
|
{
|
|
Trace0( "Found name.\n" );
|
|
Found = TRUE;
|
|
}
|
|
else
|
|
{
|
|
Found = FALSE;
|
|
}
|
|
//
|
|
// Calculate offset to next entry. Note the use of ALIGN_CLUSPROP
|
|
//
|
|
cbOffset = sizeof( *ListEntry.pName ) + ALIGN_CLUSPROP( ListEntry.pName->cbLength );
|
|
break;
|
|
case CLUSPROP_SYNTAX_LIST_VALUE_DWORD:
|
|
cbOffset = sizeof( *ListEntry.pDwordValue ); // ALIGN_CLUSPROP not used; value is already DWORD-aligned
|
|
break;
|
|
case CLUSPROP_SYNTAX_LIST_VALUE_SZ:
|
|
if ( Found == TRUE)
|
|
{
|
|
if (ppszOut)
|
|
{
|
|
*ppszOut = ListEntry.pStringValue->sz;
|
|
}
|
|
|
|
DoLoop = FALSE;
|
|
}
|
|
else
|
|
{
|
|
Trace0( "Found something else.\n" );
|
|
cbOffset = sizeof( *ListEntry.pStringValue ) + ALIGN_CLUSPROP( ListEntry.pStringValue->cbLength );
|
|
}
|
|
break;
|
|
case CLUSPROP_SYNTAX_LIST_VALUE_BINARY: // this is what we're looking for
|
|
cbOffset = sizeof( *ListEntry.pBinaryValue ) + ALIGN_CLUSPROP( ListEntry.pBinaryValue->cbLength );
|
|
break;
|
|
case CLUSPROP_SYNTAX_ENDMARK:
|
|
default:
|
|
cbOffset = sizeof( DWORD );
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Verify that the offset to the next entry is
|
|
// within the value list buffer, then advance
|
|
// the CLUSPROP_BUFFER_HELPER pointer.
|
|
//
|
|
cbPosition += cbOffset;
|
|
if ( cbPosition > cbProps )
|
|
break;
|
|
ListEntry.pb += cbOffset;
|
|
|
|
} while ( DoLoop );
|
|
|
|
if (Found)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
DWORD GetClusterInfo(
|
|
LPCTSTR pszClusIp,
|
|
CString &strClusName,
|
|
DWORD * pdwClusIp)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
HCLUSTER hCluster;
|
|
CIpAddress ipClus(pszClusIp);
|
|
|
|
strClusName.Empty();
|
|
*pdwClusIp = (LONG)ipClus;
|
|
|
|
hCluster = ((OPENCLUSTER) g_ClusDLL[CLUS_OPEN_CLUSTER])(pszClusIp);
|
|
if (hCluster == NULL)
|
|
{
|
|
dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
DWORD dwClusNameLen;
|
|
|
|
dwClusNameLen = 0;
|
|
dwErr = ((GETCLUSTERINFORMATION) g_ClusDLL[CLUS_GET_CLUSTER_INFORMATION])(
|
|
hCluster,
|
|
NULL,
|
|
&dwClusNameLen,
|
|
NULL);
|
|
if (dwClusNameLen > 0)
|
|
{
|
|
LPTSTR pClusName;
|
|
|
|
dwClusNameLen++;
|
|
pClusName = strClusName.GetBuffer((dwClusNameLen)*sizeof(WCHAR));
|
|
dwErr = ((GETCLUSTERINFORMATION) g_ClusDLL[CLUS_GET_CLUSTER_INFORMATION])(
|
|
hCluster,
|
|
pClusName,
|
|
&dwClusNameLen,
|
|
NULL);
|
|
strClusName.ReleaseBuffer();
|
|
}
|
|
|
|
((CLOSECLUSTER) g_ClusDLL[CLUS_CLOSE_CLUSTER])(hCluster);
|
|
}
|
|
|
|
return dwErr;
|
|
}
|