windows-nt/Source/XPSP1/NT/base/cluster/resmon/resmon.c

1038 lines
29 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995-1997 Microsoft Corporation
Module Name:
resmon.c
Abstract:
Startup and initialization portion of the Cluster Resource Monitor
Author:
John Vert (jvert) 30-Nov-1995
Revision History:
Sivaprasad Padisetty (sivapad) 06-18-1997 Added the COM support
--*/
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "resmonp.h"
#include "stdio.h"
#include "stdlib.h"
#include "clusverp.h"
#ifdef COMRES
#include "comres_i.c"
#endif
#define RESMON_MODULE RESMON_MODULE_RESMON
//
// Global data
//
CRITICAL_SECTION RmpListLock;
LOCK_INFO RmpListPPrevPrevLock;
LOCK_INFO RmpListPrevPrevLock;
LOCK_INFO RmpListPrevLock;
LOCK_INFO RmpListLastLock;
LOCK_INFO RmpListLastUnlock;
LOCK_INFO RmpListPrevUnlock;
LOCK_INFO RmpListPrevPrevUnlock;
LOCK_INFO RmpListPPrevPrevUnlock;
CRITICAL_SECTION RmpMonitorStateLock;
PMONITOR_STATE RmpSharedState = NULL;
HANDLE RmpInitEvent = NULL;
HANDLE RmpFileMapping = NULL;
HANDLE RmpClusterProcess = NULL;
HKEY RmpResourcesKey = NULL;
HKEY RmpResTypesKey = NULL;
HCLUSTER RmpHCluster = NULL;
HANDLE RmpWaitArray[MAX_THREADS];
HANDLE RmpRewaitEvent = NULL;
DWORD RmpNumberOfThreads = 0;
BOOL RmpDebugger = FALSE;
BOOL RmpCrashed = FALSE;
LPTOP_LEVEL_EXCEPTION_FILTER lpfnOriginalExceptionFilter = NULL;
PWCHAR RmonStates[] = {
L"", // Initializing
L"", // Idle
L"Starting",
L"Initializing",
L"Online",
L"Offline",
L"Shutdown",
L"Deleteing",
L"IsAlivePoll",
L"LooksAlivePoll",
L"Arbitrate",
L"Release"
L"ResourceControl",
L"ResourceTypeControl",
0 };
//
// Prototypes local to this module
//
DWORD
RmpInitialize(
VOID
);
VOID
RmpCleanup(
VOID
);
VOID
RmpParseArgs(
int argc,
wchar_t *argv[],
OUT LPDWORD pClussvcProcessId,
OUT HANDLE* pClussvcFileMapping,
OUT HANDLE* pClussvcInitEvent,
OUT LPWSTR* pDebuggerCommand
);
LONG
RmpExceptionFilter(
IN PEXCEPTION_POINTERS ExceptionInfo
)
/*++
Routine Description:
Top level exception handler for the resource monitor process.
Currently this just exits immediately and assumes that the
cluster service will notice and clean up the mess.
Arguments:
ExceptionInfo - Supplies the exception information
Return Value:
None.
--*/
{
DWORD code = 0;
if ( !RmpCrashed ) {
RmpCrashed = TRUE;
code = ExceptionInfo->ExceptionRecord->ExceptionCode;
ClRtlLogPrint( LOG_CRITICAL, "[RM] Exception. Code = 0x%1!lx!, Address = 0x%2!lx!\n",
ExceptionInfo->ExceptionRecord->ExceptionCode,
ExceptionInfo->ExceptionRecord->ExceptionAddress);
ClRtlLogPrint( LOG_CRITICAL, "[RM] Exception parameters: %1!lx!, %2!lx!, %3!lx!, %4!lx!\n",
ExceptionInfo->ExceptionRecord->ExceptionInformation[0],
ExceptionInfo->ExceptionRecord->ExceptionInformation[1],
ExceptionInfo->ExceptionRecord->ExceptionInformation[2],
ExceptionInfo->ExceptionRecord->ExceptionInformation[3]);
CL_LOGFAILURE(ExceptionInfo->ExceptionRecord->ExceptionCode);
if (lpfnOriginalExceptionFilter)
lpfnOriginalExceptionFilter(ExceptionInfo);
}
//
// Dump an exception report
//
GenerateExceptionReport(ExceptionInfo);
//
// Try to dump the resource and the resource state
//
try {
PRESOURCE resource;
DWORD state = 0;
resource = (PRESOURCE)RmpSharedState->ActiveResource;
if ( state <= RmonResourceTypeControl ) {
state =RmpSharedState->State;
}
ClRtlLogPrint( LOG_CRITICAL, "[RM] Active Resource = %1!08LX!\n",
resource );
ClRtlLogPrint( LOG_CRITICAL, "[RM] Resource State is %1!u!, \"%2!ws!\"\n",
RmpSharedState->State,
RmonStates[RmpSharedState->State] );
if ( resource ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Resource name is %1!ws!\n",
resource->ResourceName );
ClRtlLogPrint( LOG_CRITICAL, "[RM] Resource type is %1!ws!\n",
resource->ResourceType );
}
} except ( EXCEPTION_EXECUTE_HANDLER ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Exception %1!08LX! while dumping state for resource!\n",
GetExceptionCode());
}
if ( code == 0xC0000194 ) {
DumpCriticalSection( (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[0] );
}
if ( IsDebuggerPresent()) {
return(EXCEPTION_CONTINUE_SEARCH);
} else {
#if !CLUSTER_BETA
// terminate only when product ships
TerminateProcess( GetCurrentProcess(),
ExceptionInfo->ExceptionRecord->ExceptionCode );
#endif
return(EXCEPTION_CONTINUE_SEARCH);
}
}
int _cdecl
wmain (argc, argv)
int argc;
wchar_t *argv[];
{
PVOID EventList;
DWORD Status;
HANDLE ResourceId;
CLUSTER_RESOURCE_STATE ResourceState;
WCHAR rpcEndpoint[80];
HKEY ClusterKey;
BOOL Inited = FALSE;
BOOL comInited = FALSE;
BOOL bSuccess;
HANDLE ClussvcFileMapping, ClussvcInitEvent;
DWORD ClussvcProcessId;
LPWSTR debuggerCommand = NULL;
//
// Initialize the Cluster Rtl routines.
//
if ( (Status = ClRtlInitialize( FALSE, NULL )) != ERROR_SUCCESS ) {
ClRtlLogPrint(LOG_CRITICAL,
"[RM] Failed to initialize Cluster RTL, error %1!u!.\n",
Status);
goto init_failure;
}
ClRtlInitWmi(NULL);
Inited = TRUE;
//
// Parse the input arguments.
//
RmpParseArgs(argc, argv,
&ClussvcProcessId,
&ClussvcFileMapping,
&ClussvcInitEvent,
&debuggerCommand);
if ((ClussvcInitEvent == NULL) ||
(ClussvcFileMapping == NULL) ||
(ClussvcProcessId == 0)) {
//
// All of these arguments are required.
//
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to parse required parameter.\n");
Status = ERROR_INVALID_PARAMETER;
goto init_failure;
}
//
// We do not want to create resmon process with InheritHandles flag.
// So resmon parameters got changed. We no longer pass handles valid in
// the context of resmon.
//
//
// First, convert ProcessId into ProcessHandle
//
RmpClusterProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE, // Don't inherit
ClussvcProcessId);
if (RmpClusterProcess == NULL) {
Status = GetLastError();
ClRtlLogPrint( LOG_CRITICAL, "[RM] OpenProcess for %1!x! process failed, error %2!u!.\n",
RmpClusterProcess, Status);
goto init_failure;
}
//
// Now Dup the handles from ClusSvc to Resmon
//
bSuccess = DuplicateHandle(
RmpClusterProcess, // Source Process
ClussvcInitEvent, // Source Handle
GetCurrentProcess(),// Target Process
&RmpInitEvent, // Target Handle
0, // DUPLICATE_SAME_ACCESS
FALSE, // Don't inherit
DUPLICATE_SAME_ACCESS);
if (!bSuccess) {
Status = GetLastError();
ClRtlLogPrint( LOG_CRITICAL, "[RM] Dup InitEvent handle %1!x! failed, error %2!u!.\n",
ClussvcInitEvent, Status);
goto init_failure;
}
bSuccess = DuplicateHandle(
RmpClusterProcess, // Source Process
ClussvcFileMapping, // Source Handle
GetCurrentProcess(),// Target Process
&RmpFileMapping, // Target Handle
0, // DUPLICATE_SAME_ACCESS
FALSE, // Don't inherit
DUPLICATE_SAME_ACCESS);
if (!bSuccess) {
Status = GetLastError();
ClRtlLogPrint( LOG_CRITICAL, "[RM] Dup FileMapping handle %1!x! failed, error %2!u!.\n",
ClussvcFileMapping, Status);
goto init_failure;
}
if ( debuggerCommand ) {
//
// if -d was specified, then check if the optional command arg was
// specified. If not, wait for a debugger to be attached
// external. Otherwise, append the PID to the passed command and call
// CreateProcess on it.
//
if ( *debuggerCommand == UNICODE_NULL ) {
while ( !IsDebuggerPresent()) {
Sleep( 1000 );
}
} else {
STARTUPINFOW startupInfo;
PROCESS_INFORMATION processInfo;
DWORD cmdLength;
PWCHAR dbgCmdLine;
cmdLength = wcslen( debuggerCommand );
dbgCmdLine = LocalAlloc( LMEM_FIXED, ( cmdLength + 24 ) * sizeof( WCHAR ));
if ( dbgCmdLine != NULL ) {
wsprintfW(dbgCmdLine, L"%ws -p %d", debuggerCommand, GetCurrentProcessId());
ClRtlLogPrint(LOG_NOISE, "[RM] Starting debugger process: %1!ws!\n", dbgCmdLine );
//
// Attempt to attach debugger to us
//
ZeroMemory(&startupInfo, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
bSuccess = CreateProcessW(NULL,
dbgCmdLine,
NULL,
NULL,
FALSE, // Inherit handles
DETACHED_PROCESS, // so ctrl-c won't kill it
NULL,
NULL,
&startupInfo,
&processInfo);
if (!bSuccess) {
Status = GetLastError();
ClRtlLogPrint(LOG_UNUSUAL,
"[RM] Failed to create debugger process, error %1!u!.\n",
Status);
}
CloseHandle(processInfo.hThread); // don't need these
CloseHandle(processInfo.hProcess);
LocalFree( dbgCmdLine );
} else {
ClRtlLogPrint(LOG_UNUSUAL,
"[RM] Failed to alloc memory for debugger command line, error %1!u!.\n",
GetLastError());
}
}
}
//
// init COM for netname
//
Status = CoInitializeEx( NULL, COINIT_DISABLE_OLE1DDE | COINIT_MULTITHREADED );
if ( !SUCCEEDED( Status )) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Couldn't init COM %1!08X!\n", Status );
goto init_failure;
}
comInited = TRUE;
ClRtlLogPrint( LOG_NOISE, "[RM] Main: Initializing.\r\n");
//
// Initialize the resource monitor.
//
Status = RmpInitialize();
if ( Status != ERROR_SUCCESS ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to initialize, error %1!u!.\n",
Status);
goto init_failure;
}
RmpSharedState = MapViewOfFile(RmpFileMapping,
FILE_MAP_WRITE,
0,
0,
0);
if (RmpSharedState == NULL) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to init shared state, error %1!u!.\n",
Status = GetLastError());
goto init_failure;
}
CloseHandle(RmpFileMapping);
RmpFileMapping = NULL;
GetSystemTimeAsFileTime((PFILETIME)&RmpSharedState->LastUpdate);
RmpSharedState->State = RmonInitializing;
RmpSharedState->ActiveResource = NULL;
if ( RmpSharedState->ResmonStop ) {
// If ResmonStop is set to TRUE, then a debugger should be attached
RmpDebugger = TRUE;
}
//
// Connect to local cluster and open Resources key.
//
RmpHCluster = OpenCluster(NULL);
if (RmpHCluster == NULL) {
Status = GetLastError();
ClRtlLogPrint( LOG_CRITICAL, "[RM] Error opening cluster, error %1!u!.\n",
Status);
goto init_failure;
}
ClusterKey = GetClusterKey(RmpHCluster, KEY_READ);
if (ClusterKey == NULL) {
Status = GetLastError();
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to open the cluster key, error %1!u!.\n",
Status);
goto init_failure;
}
Status = ClusterRegOpenKey(ClusterKey,
CLUSREG_KEYNAME_RESOURCES,
KEY_READ,
&RmpResourcesKey);
if (Status != ERROR_SUCCESS) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to open Resources cluster registry key, error %1!u!.\n",
Status);
goto init_failure;
}
Status = ClusterRegOpenKey(ClusterKey,
CLUSREG_KEYNAME_RESOURCE_TYPES,
KEY_READ,
&RmpResTypesKey);
if (Status != ERROR_SUCCESS) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to open ResourceTypes cluster registry key, error %1!u!.\n",
Status);
goto init_failure;
}
//
// The Wait Count identifies the number of events the main thread will
// wait for. This is the notification event, the Cluster Service Process
// plus each event list thread. We start at 2 because the first two entries
// are fixed - for the notification event and the Cluster Service process.
//
RmpNumberOfThreads = 2;
//
// Create an event to be signaled whenever we add a new thread.
//
RmpRewaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if ( RmpRewaitEvent == NULL ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to create rewait event, error %1!u!.\n",
Status = GetLastError());
goto init_failure;
}
//
// Create the first event list, and start a polling thread.
//
EventList = RmpCreateEventList();
if (EventList == NULL) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to create event list, error %1!u!.\n",
Status = GetLastError());
goto init_failure;
}
//
// Start RPC Server
//
wsprintfW( rpcEndpoint, L"resrcmon%d", GetCurrentProcessId());
Status = RpcServerUseProtseqEpW(L"ncalrpc",
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
rpcEndpoint,
NULL);
if (Status != RPC_S_OK) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to initialize RPC interface, error %1!u!.\n",
Status);
goto init_failure;
}
Status = RpcServerRegisterIf(s_resmon_v2_0_s_ifspec,
NULL,
NULL);
if (Status != RPC_S_OK) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to register RPC interface, error %1!u!.\n",
Status);
goto init_failure;
}
Status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
if (Status != RPC_S_OK) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to set RPC server listening, error %1!u!.\n",
Status);
goto init_failure;
}
//
// Set our unhandled exception filter so that if anything horrible
// goes wrong, we can exit immediately.
//
lpfnOriginalExceptionFilter = SetUnhandledExceptionFilter(RmpExceptionFilter);
//
// Set the event to indicate that our initialization is complete.
// This event is passed on the command line.
//
if (!SetEvent(RmpInitEvent)) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] Failed to signal cluster service event, error %1!u!.\n",
Status = GetLastError());
goto init_failure;
}
CloseHandle(RmpInitEvent);
//
// ResmonStop is initialized to TRUE by ClusSvc, we will wait for
// ClusSvc to signal when it is done attaching a debugger by waiting
// until ResmonStop is set to FALSE.
//
while ( RmpSharedState->ResmonStop ) {
Sleep(100);
}
//
// Boost our priority. Non-fatal if this fails.
//
if ( !SetPriorityClass( GetCurrentProcess(),
HIGH_PRIORITY_CLASS ) ) {
ClRtlLogPrint( LOG_UNUSUAL, "[RM] Failed to set priority class, error %1!u!.\n",
GetLastError() );
}
//
// Wait for shutdown. Either the cluster service terminating or
// the poller thread terminating will initiate a shutdown.
//
RmpWaitArray[0] = RmpRewaitEvent;
RmpWaitArray[1] = RmpClusterProcess;
//
// If we are notified a new thread is added, then just re-wait.
// N.B. RmpNumberOfThreads is really the number of threads, plus the
// two fixed wait events (the change notification and the Cluster Service).
//
do {
Status = WaitForMultipleObjects(RmpNumberOfThreads,
RmpWaitArray,
FALSE,
INFINITE);
} while ( (Status == WAIT_OBJECT_0) && (RmpShutdown == FALSE) );
ClRtlLogPrint( LOG_UNUSUAL, "[RM] Going away, Status = %1!u!, Shutdown = %2!u!.\n",
Status, RmpShutdown);
RmpShutdown = TRUE;
CloseHandle( RmpRewaitEvent );
//
// Initiate RM shutdown.
//
s_RmShutdownProcess(NULL);
//
// Clean up any resources left lying around by the cluster service.
//
RmpRundownResources();
//
// Shutdown RPC Server
//
RpcMgmtStopServerListening(NULL);
RpcServerUnregisterIf(NULL, NULL, TRUE);
CoUninitialize () ;
return(0);
init_failure:
if ( RmpInitEvent != NULL ) {
CloseHandle( RmpInitEvent );
}
if ( RmpFileMapping != NULL ) {
CloseHandle( RmpFileMapping );
}
if ( RmpClusterProcess != NULL ) {
CloseHandle( RmpClusterProcess );
}
if ( RmpResTypesKey != NULL ) {
ClusterRegCloseKey( RmpResTypesKey );
}
if ( RmpResourcesKey != NULL ) {
ClusterRegCloseKey( RmpResourcesKey );
}
if ( RmpHCluster != NULL ) {
CloseCluster( RmpHCluster );
}
if ( RmpRewaitEvent != NULL ) {
CloseHandle( RmpRewaitEvent );
}
if ( comInited )
CoUninitialize();
if ( Inited )
CL_LOGFAILURE(Status);
return(Status);
} // main
VOID
RmpParseArgs(
int argc,
wchar_t *argv[],
OUT LPDWORD pClussvcProcessId,
OUT HANDLE* pClussvcFileMapping,
OUT HANDLE* pClussvcInitEvent,
OUT LPWSTR* pDebuggerCommand
)
/*++
Routine Description:
Parses the command line passed to the resource monitor
Required options:
-e EVENT supplies Event handle to be signalled when
initialization is complete
-m FILEMAPPING supplies file mapping handle to be
used for shared monitor state.
-p PROCESSID supplies process id of the cluster
service so resmon can detect failure of the
cluster service and shutdown cleanly.
-d [DEBUGGERCMD] - wait for or attach a debugger during startup
Additional options:
none
Arguments:
argc - supplies number of arguments
argv - supplies actual arguments
Return Value:
None.
--*/
{
int i;
wchar_t *p;
for (i=1; i<argc; i++) {
p=argv[i];
if ((*p == '-') ||
(*p == '/')) {
++p;
switch (toupper(*p)) {
case 'E':
if (i+1 < argc) {
*pClussvcInitEvent = LongToHandle(_wtoi(argv[++i]));
} else {
goto BadCommandLine;
}
break;
case 'M':
if (i+1 < argc) {
*pClussvcFileMapping = LongToHandle(_wtoi(argv[++i]));
} else {
goto BadCommandLine;
}
break;
case 'P':
if (i+1 < argc) {
*pClussvcProcessId = (DWORD)_wtoi(argv[++i]);
} else {
goto BadCommandLine;
}
break;
case 'D':
//
// use the empty (but not NULL) string to indicate that
// resmon should wait for a debugger to be attached.
//
if (i+1 < argc) {
if ( *argv[i+1] != UNICODE_NULL && *argv[i+1] != L'-' ) {
*pDebuggerCommand = argv[++i];
} else {
*pDebuggerCommand = L"";
}
} else {
*pDebuggerCommand = L"";
}
break;
default:
goto BadCommandLine;
}
}
}
return;
BadCommandLine:
ClusterLogEvent0(LOG_CRITICAL,
LOG_CURRENT_MODULE,
__FILE__,
__LINE__,
RMON_INVALID_COMMAND_LINE,
0,
NULL);
ExitProcess(0);
} // RmpParseArgs
DWORD
RmpInitialize(
VOID
)
/*++
Routine Description:
Initialize all resources needed by the resource monitor.
Arguments:
None.
Returns:
ERROR_SUCCESS if successful.
Win32 error code on failure.
--*/
{
//
// Initialize global data
//
InitializeCriticalSection(&RmpListLock);
InitializeCriticalSection(&RmpMonitorStateLock);
InitializeListHead(&RmpEventListHead);
ClRtlInitializeQueue(&RmpNotifyQueue);
return(ERROR_SUCCESS);
} // RmpInitialize
VOID
RmpCleanup(
VOID
)
/*++
Routine Description:
Cleanup all resources created during init.
Arguments:
None.
Returns:
None.
--*/
{
} // RmpCleanup
DWORD RmpLoadResType(
IN LPCWSTR lpszResourceTypeName,
IN LPCWSTR lpszDllName,
OUT PRESDLL_FNINFO pResDllFnInfo,
#ifdef COMRES
OUT PRESDLL_INTERFACES pResDllInterfaces,
#endif
OUT LPDWORD pdwCharacteristics
)
{
DWORD retry;
DWORD dwStatus = ERROR_SUCCESS;
HINSTANCE hDll = NULL;
PSTARTUP_ROUTINE pfnStartup;
PCLRES_FUNCTION_TABLE pFnTable = NULL;
LPWSTR pszDllName = (LPWSTR) lpszDllName;
pResDllFnInfo->hDll = NULL;
pResDllFnInfo->pResFnTable = NULL;
#ifdef COMRES
pResDllInterfaces->pClusterResource = NULL;
pResDllInterfaces->pClusterQuorumResource = NULL;
pResDllInterfaces->pClusterResControl = NULL;
#endif
// Expand any environment variables included in the DLL path name.
if ( wcschr( lpszDllName, L'%' ) != NULL ) {
pszDllName = ClRtlExpandEnvironmentStrings( lpszDllName );
if ( pszDllName == NULL ) {
dwStatus = GetLastError();
ClRtlLogPrint( LOG_UNUSUAL, "[RM] ResTypeControl: Error expanding environment strings in '%1!ls!, error %2!u!.\n",
lpszDllName,
dwStatus);
goto FnExit;
}
}
// Load the dll... we can't assume we have the DLL loaded!
hDll = LoadLibraryW(pszDllName);
if ( hDll == NULL )
{
dwStatus = GetLastError();
ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Error loading resource DLL '%1!ls!, error %2!u!.\n",
pszDllName,
dwStatus);
#ifdef COMRES
dwStatus = RmpLoadComResType(lpszDllName, pResDllInterfaces,
pdwCharacteristics);
#endif
goto FnExit;
}
//
// Invoke debugger if one is specified.
//
if ( RmpDebugger ) {
//
// Wait for debugger to come online.
//
retry = 100;
while ( retry-- &&
!IsDebuggerPresent() ) {
Sleep(100);
}
OutputDebugStringA("[RM] ResourceTypeControl: Just loaded resource DLL ");
OutputDebugStringW(lpszDllName);
OutputDebugStringA("\n");
DebugBreak();
}
// Get the startup routine
pfnStartup = (PSTARTUP_ROUTINE)GetProcAddress( hDll,
STARTUP_ROUTINE );
if ( pfnStartup == NULL ) {
dwStatus = GetLastError();
ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Error getting startup routine, status %1!u!.\n",
dwStatus);
goto FnExit;
}
// Get the function table
RmpSetMonitorState(RmonStartingResource, NULL);
try {
dwStatus = (pfnStartup)( lpszResourceTypeName,
CLRES_VERSION_V1_00,
CLRES_VERSION_V1_00,
RmpSetResourceStatus,
RmpLogEvent,
&pFnTable );
} except (EXCEPTION_EXECUTE_HANDLER) {
dwStatus = GetExceptionCode();
}
RmpSetMonitorState(RmonIdle, NULL);
if ( dwStatus != ERROR_SUCCESS ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Startup call failed, error %1!u!.\n",
dwStatus);
goto FnExit;
}
if ( pFnTable == NULL ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Startup function table is NULL!\n");
dwStatus = ERROR_INVALID_DATA;
goto FnExit;
}
if ( pFnTable->Version != CLRES_VERSION_V1_00 ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Incorrect function table version!\n");
dwStatus = ERROR_INVALID_DATA;
goto FnExit;
}
if ( pFnTable->TableSize != CLRES_V1_FUNCTION_SIZE ) {
ClRtlLogPrint( LOG_CRITICAL, "[RM] ResTypeControl: Incorrect function table size!\n");
dwStatus = ERROR_INVALID_DATA;
goto FnExit;
}
if ( (pFnTable->V1Functions.Arbitrate != NULL) &&
(pFnTable->V1Functions.Release != NULL) && pdwCharacteristics) {
*pdwCharacteristics = CLUS_CHAR_QUORUM;
}
FnExit:
if (dwStatus != ERROR_SUCCESS)
{
if (hDll) FreeLibrary(hDll);
if (pFnTable) LocalFree(pFnTable);
}
else
{
pResDllFnInfo->hDll = hDll;
pResDllFnInfo->pResFnTable = pFnTable;
}
if ( pszDllName != lpszDllName )
{
LocalFree( pszDllName );
}
return(dwStatus);
} //*** RmpLoadResType()
#ifdef COMRES
DWORD RmpLoadComResType(
IN LPCWSTR lpszDllName,
OUT PRESDLL_INTERFACES pResDllInterfaces,
OUT LPDWORD pdwCharacteristics)
{
IClusterResource *pClusterResource = NULL ;
IClusterQuorumResource *pClusterQuorumResource = NULL;
IClusterResControl *pClusterResControl = NULL;
HRESULT hr ;
CLSID clsid ;
DWORD Error ;
pResDllInterfaces->pClusterResource = NULL;
pResDllInterfaces->pClusterQuorumResource = NULL;
pResDllInterfaces->pClusterResControl = NULL;
hr = CLSIDFromProgID(lpszDllName, &clsid) ;
if (FAILED (hr))
{
ClRtlLogPrint( LOG_UNUSUAL, "[RM] Error converting CLSIDFromProgID Prog ID %1!ws!, error %2!u!.\n",
lpszDllName, hr);
goto FnExit ;
}
if ((hr = CoCreateInstance (&clsid, NULL, CLSCTX_ALL, &IID_IClusterResource, (LPVOID *) &pClusterResource)) != S_OK)
goto FnExit ;
//not a mandatory interface
hr = IClusterResource_QueryInterface (pClusterResource, &IID_IClusterQuorumResource, (LPVOID *) &pClusterQuorumResource) ;
if (SUCCEEDED(hr))
{
if (pdwCharacteristics)
*pdwCharacteristics = CLUS_CHAR_QUORUM;
IClusterQuorumResource_Release (pClusterQuorumResource) ;
}
//not a mandatory interface
hr = IClusterResource_QueryInterface (
pClusterResource,
&IID_IClusterResControl,
(LPVOID *) &pClusterResControl
) ;
if (SUCCEEDED(hr))
{
*pdwCharacteristics = CLUS_CHAR_QUORUM;
IClusterQuorumResource_Release (pClusterResControl) ;
}
hr = S_OK;
FnExit:
if (hr != S_OK)
{
if (pClusterResource)
IClusterResource_Release (pClusterResource) ;
if (pClusterQuorumResource)
IClusterQuorumResource_Release (pClusterQuorumResource) ;
if (pClusterResControl)
IClusterResControl_Release (pClusterResControl) ;
}
else
{
pResDllInterfaces->pClusterResource = pClusterResource;
pResDllInterfaces->pClusterQuorumResource = pClusterQuorumResource;
pResDllInterfaces->pClusterResControl = pClusterResControl;
}
return(hr);
}
#endif //enf of #ifdef COMRES