435 lines
9.1 KiB
C++
435 lines
9.1 KiB
C++
/*++
|
||
|
||
Copyright (c) 1992-1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
iisutil.c
|
||
|
||
Abstract:
|
||
|
||
IIS Resource utility routine DLL
|
||
|
||
Author:
|
||
|
||
Pete Benoit (v-pbenoi) 12-SEP-1996
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#define UNICODE 1
|
||
|
||
extern "C" {
|
||
#include "clusres.h"
|
||
#include "wtypes.h"
|
||
} // extern "C"
|
||
|
||
DWORD
|
||
WINAPI
|
||
ResUtilGetSzProperty(
|
||
OUT LPWSTR * OutValue,
|
||
IN const PCLUSPROP_SZ ValueStruct,
|
||
IN LPCWSTR OldValue,
|
||
OUT LPBYTE * PropBuffer,
|
||
OUT LPDWORD PropBufferSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets a string property from a property list and advances the pointers.
|
||
|
||
Arguments:
|
||
|
||
OutValue - Supplies the address of a pointer in which to return a
|
||
pointer to the string in the property list.
|
||
|
||
ValueStruct - Supplies the string value from the property list.
|
||
|
||
OldValue - Supplies the previous value for this property.
|
||
|
||
PropBuffer - Supplies the address of the pointer to the property list
|
||
buffer which will be advanced to the beginning of the next property.
|
||
|
||
PropBufferSize - Supplies a pointer to the buffer size which will be
|
||
decremented to account for this property.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The operation completed successfully.
|
||
|
||
ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
|
||
|
||
Win32 error code - The operation failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD dataSize;
|
||
|
||
//
|
||
// Make sure the buffer is big enough and
|
||
// the value is formatted correctly.
|
||
//
|
||
dataSize = sizeof(*ValueStruct) + ALIGN_CLUSPROP( ValueStruct->cbLength );
|
||
if ( (*PropBufferSize < dataSize) ||
|
||
(ValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_SZ) ) {
|
||
return(ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// If the value changed, point to the new value.
|
||
//
|
||
if ( (OldValue == NULL) ||
|
||
(lstrcmpW( ValueStruct->sz, OldValue ) != 0) ) {
|
||
*OutValue = ValueStruct->sz;
|
||
}
|
||
//
|
||
// Decrement remaining buffer size and move to the next property.
|
||
//
|
||
*PropBufferSize -= dataSize;
|
||
*PropBuffer += dataSize;
|
||
|
||
return(ERROR_SUCCESS);
|
||
|
||
} // ResUtilGetSzProperty
|
||
|
||
|
||
DWORD
|
||
ResUtilSetSzProperty(
|
||
IN HKEY RegistryKey,
|
||
IN LPCWSTR PropName,
|
||
IN LPCWSTR NewValue,
|
||
IN OUT PWSTR * OutValue
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets a REG_SZ property in a pointer, deallocating a previous value
|
||
if necessary, and sets the value in the cluster database.
|
||
|
||
Arguments:
|
||
|
||
RegistryKey - Supplies the cluster key where the property is stored.
|
||
|
||
PropName - Supplies the name of the value.
|
||
|
||
NewValue - Supplies the new string value.
|
||
|
||
OutValue - Supplies pointer to the string pointer in which to set
|
||
the property.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The operation completed successfully.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
|
||
|
||
Win32 error code - The operation failed.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
DWORD dataSize;
|
||
PWSTR allocedValue;
|
||
|
||
//
|
||
// Allocate memory for the new value string.
|
||
//
|
||
dataSize = (lstrlenW( NewValue ) + 1) * sizeof(WCHAR);
|
||
allocedValue = (PWSTR)LocalAlloc( LMEM_FIXED, dataSize );
|
||
if ( allocedValue == NULL ) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
|
||
//
|
||
// Set the property in the cluster database.
|
||
//
|
||
// _ASSERTE( ClusterKey != NULL );
|
||
// _ASSERTE( PropName != NULL );
|
||
status = ClusterRegSetValue( RegistryKey,
|
||
PropName,
|
||
REG_SZ,
|
||
(CONST BYTE*)NewValue,
|
||
dataSize );
|
||
if ( status != ERROR_SUCCESS ) {
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Copy the new value to the output buffer.
|
||
//
|
||
lstrcpyW( allocedValue, NewValue );
|
||
|
||
// Set the new value in the output string pointer.
|
||
if ( *OutValue != NULL ) {
|
||
LocalFree( *OutValue );
|
||
}
|
||
*OutValue = allocedValue;
|
||
|
||
return(ERROR_SUCCESS);
|
||
|
||
} // ResUtilSetSzProperty
|
||
|
||
|
||
//
|
||
// Worker thread routines
|
||
//
|
||
extern CRITICAL_SECTION ClusResWorkerLock;
|
||
|
||
typedef struct _WORK_CONTEXT {
|
||
PCLUS_WORKER Worker;
|
||
PVOID lpParameter;
|
||
PWORKER_START_ROUTINE lpStartRoutine;
|
||
} WORK_CONTEXT, *PWORK_CONTEXT;
|
||
|
||
DWORD
|
||
WINAPI
|
||
ClusWorkerStart(
|
||
IN PWORK_CONTEXT pContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Wrapper routine for cluster resource worker startup
|
||
|
||
Arguments:
|
||
|
||
Context - Supplies the context block. This will be freed.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Status;
|
||
WORK_CONTEXT Context;
|
||
|
||
//
|
||
// Capture our parameters and free the work context.
|
||
//
|
||
Context = *pContext;
|
||
LocalFree(pContext);
|
||
|
||
//
|
||
// Call the worker routine
|
||
//
|
||
Status = (Context.lpStartRoutine)(Context.Worker, Context.lpParameter);
|
||
|
||
//
|
||
// Synchronize and clean up properly.
|
||
//
|
||
EnterCriticalSection(&ClusResWorkerLock);
|
||
if (!Context.Worker->Terminate) {
|
||
CloseHandle(Context.Worker->hThread);
|
||
Context.Worker->hThread = NULL;
|
||
}
|
||
Context.Worker->Terminate = TRUE;
|
||
LeaveCriticalSection(&ClusResWorkerLock);
|
||
|
||
return(Status);
|
||
|
||
} // ClusWorkerStart
|
||
|
||
|
||
DWORD
|
||
ClusWorkerCreate(
|
||
OUT PCLUS_WORKER Worker,
|
||
IN PWORKER_START_ROUTINE lpStartAddress,
|
||
IN PVOID lpParameter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Common wrapper for resource DLL worker threads. Provides
|
||
"clean" terminate semantics
|
||
|
||
Arguments:
|
||
|
||
Worker - Returns an initialized worker structure
|
||
|
||
lpStartAddress - Supplies the worker thread routine
|
||
|
||
lpParameter - Supplies the parameter to be passed to the
|
||
worker thread routine
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
PWORK_CONTEXT Context;
|
||
DWORD ThreadId;
|
||
DWORD Status;
|
||
|
||
Context = (PWORK_CONTEXT)LocalAlloc(LMEM_FIXED, sizeof(WORK_CONTEXT));
|
||
if (Context == NULL) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
Context->Worker = Worker;
|
||
Context->lpParameter = lpParameter;
|
||
Context->lpStartRoutine = lpStartAddress;
|
||
|
||
Worker->Terminate = FALSE;
|
||
Worker->hThread = CreateThread(NULL,
|
||
0,
|
||
(LPTHREAD_START_ROUTINE)ClusWorkerStart,
|
||
Context,
|
||
0,
|
||
&ThreadId);
|
||
if (Worker->hThread == NULL) {
|
||
Status = GetLastError();
|
||
LocalFree(Context);
|
||
return(Status);
|
||
}
|
||
return(ERROR_SUCCESS);
|
||
|
||
} // ClusWorkerCreate
|
||
|
||
|
||
|
||
BOOL
|
||
ClusWorkerCheckTerminate(
|
||
IN PCLUS_WORKER Worker
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks to see if the specified Worker thread should exit ASAP.
|
||
|
||
Arguments:
|
||
|
||
Worker - Supplies the worker
|
||
|
||
Return Value:
|
||
|
||
TRUE if the thread should exit.
|
||
|
||
FALSE otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
return(Worker->Terminate);
|
||
|
||
} // ClusWorkerCheckTerminate
|
||
|
||
|
||
|
||
VOID
|
||
ClusWorkerTerminate(
|
||
IN PCLUS_WORKER Worker
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks to see if the specified Worker thread should exit ASAP.
|
||
|
||
Arguments:
|
||
|
||
Worker - Supplies the worker
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// N.B. There is a race condition here if multiple threads
|
||
// call this routine on the same worker. The first one
|
||
// through will set Terminate. The second one will see
|
||
// that Terminate is set and return immediately without
|
||
// waiting for the Worker to exit. Not really any nice
|
||
// way to fix this without adding another synchronization
|
||
// object.
|
||
//
|
||
|
||
if ((Worker->hThread == NULL) ||
|
||
(Worker->Terminate)) {
|
||
return;
|
||
}
|
||
EnterCriticalSection(&ClusResWorkerLock);
|
||
if (!Worker->Terminate) {
|
||
Worker->Terminate = TRUE;
|
||
LeaveCriticalSection(&ClusResWorkerLock);
|
||
WaitForSingleObject(Worker->hThread, INFINITE);
|
||
CloseHandle(Worker->hThread);
|
||
Worker->hThread = NULL;
|
||
} else {
|
||
LeaveCriticalSection(&ClusResWorkerLock);
|
||
}
|
||
return;
|
||
|
||
} // ClusWorkerTerminate
|
||
|
||
|
||
|
||
VOID
|
||
ClusWorkerTerminateEx(
|
||
IN PCLUS_WORKER Worker,
|
||
IN DWORD Timeout
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Checks to see if the specified Worker thread should exit and waits a
|
||
short time before killing the thread.
|
||
|
||
Arguments:
|
||
|
||
Worker - Supplies the worker
|
||
|
||
Timeout - Supplies the timeout period in ms.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// N.B. There is a race condition here if multiple threads
|
||
// call this routine on the same worker. The first one
|
||
// through will set Terminate. The second one will see
|
||
// that Terminate is set and return immediately without
|
||
// waiting for the Worker to exit. Not really any nice
|
||
// way to fix this without adding another synchronization
|
||
// object.
|
||
//
|
||
|
||
if ((Worker->hThread == NULL) ||
|
||
(Worker->Terminate)) {
|
||
return;
|
||
}
|
||
EnterCriticalSection(&ClusResWorkerLock);
|
||
if (!Worker->Terminate) {
|
||
Worker->Terminate = TRUE;
|
||
LeaveCriticalSection(&ClusResWorkerLock);
|
||
WaitForSingleObject(Worker->hThread, Timeout);
|
||
CloseHandle(Worker->hThread);
|
||
Worker->hThread = NULL;
|
||
} else {
|
||
LeaveCriticalSection(&ClusResWorkerLock);
|
||
}
|
||
return;
|
||
|
||
} // ClusWorkerTerminate
|
||
|