|
|
/*++
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
|