Source code of Windows XP (NT5)
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.

434 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 1992-1996 Microsoft Corporation
  3. Module Name:
  4. iisutil.c
  5. Abstract:
  6. IIS Resource utility routine DLL
  7. Author:
  8. Pete Benoit (v-pbenoi) 12-SEP-1996
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. extern "C" {
  13. #include "clusres.h"
  14. #include "wtypes.h"
  15. } // extern "C"
  16. DWORD
  17. WINAPI
  18. ResUtilGetSzProperty(
  19. OUT LPWSTR * OutValue,
  20. IN const PCLUSPROP_SZ ValueStruct,
  21. IN LPCWSTR OldValue,
  22. OUT LPBYTE * PropBuffer,
  23. OUT LPDWORD PropBufferSize
  24. )
  25. /*++
  26. Routine Description:
  27. Gets a string property from a property list and advances the pointers.
  28. Arguments:
  29. OutValue - Supplies the address of a pointer in which to return a
  30. pointer to the string in the property list.
  31. ValueStruct - Supplies the string value from the property list.
  32. OldValue - Supplies the previous value for this property.
  33. PropBuffer - Supplies the address of the pointer to the property list
  34. buffer which will be advanced to the beginning of the next property.
  35. PropBufferSize - Supplies a pointer to the buffer size which will be
  36. decremented to account for this property.
  37. Return Value:
  38. ERROR_SUCCESS - The operation completed successfully.
  39. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  40. Win32 error code - The operation failed.
  41. --*/
  42. {
  43. DWORD dataSize;
  44. //
  45. // Make sure the buffer is big enough and
  46. // the value is formatted correctly.
  47. //
  48. dataSize = sizeof(*ValueStruct) + ALIGN_CLUSPROP( ValueStruct->cbLength );
  49. if ( (*PropBufferSize < dataSize) ||
  50. (ValueStruct->Syntax.wFormat != CLUSPROP_FORMAT_SZ) ) {
  51. return(ERROR_INVALID_PARAMETER);
  52. }
  53. //
  54. // If the value changed, point to the new value.
  55. //
  56. if ( (OldValue == NULL) ||
  57. (lstrcmpW( ValueStruct->sz, OldValue ) != 0) ) {
  58. *OutValue = ValueStruct->sz;
  59. }
  60. //
  61. // Decrement remaining buffer size and move to the next property.
  62. //
  63. *PropBufferSize -= dataSize;
  64. *PropBuffer += dataSize;
  65. return(ERROR_SUCCESS);
  66. } // ResUtilGetSzProperty
  67. DWORD
  68. ResUtilSetSzProperty(
  69. IN HKEY RegistryKey,
  70. IN LPCWSTR PropName,
  71. IN LPCWSTR NewValue,
  72. IN OUT PWSTR * OutValue
  73. )
  74. /*++
  75. Routine Description:
  76. Sets a REG_SZ property in a pointer, deallocating a previous value
  77. if necessary, and sets the value in the cluster database.
  78. Arguments:
  79. RegistryKey - Supplies the cluster key where the property is stored.
  80. PropName - Supplies the name of the value.
  81. NewValue - Supplies the new string value.
  82. OutValue - Supplies pointer to the string pointer in which to set
  83. the property.
  84. Return Value:
  85. ERROR_SUCCESS - The operation completed successfully.
  86. ERROR_NOT_ENOUGH_MEMORY - An error occurred attempting to allocate memory.
  87. Win32 error code - The operation failed.
  88. --*/
  89. {
  90. DWORD status;
  91. DWORD dataSize;
  92. PWSTR allocedValue;
  93. //
  94. // Allocate memory for the new value string.
  95. //
  96. dataSize = (lstrlenW( NewValue ) + 1) * sizeof(WCHAR);
  97. allocedValue = (PWSTR)LocalAlloc( LMEM_FIXED, dataSize );
  98. if ( allocedValue == NULL ) {
  99. return(ERROR_NOT_ENOUGH_MEMORY);
  100. }
  101. //
  102. // Set the property in the cluster database.
  103. //
  104. // _ASSERTE( ClusterKey != NULL );
  105. // _ASSERTE( PropName != NULL );
  106. status = ClusterRegSetValue( RegistryKey,
  107. PropName,
  108. REG_SZ,
  109. (CONST BYTE*)NewValue,
  110. dataSize );
  111. if ( status != ERROR_SUCCESS ) {
  112. return(status);
  113. }
  114. //
  115. // Copy the new value to the output buffer.
  116. //
  117. lstrcpyW( allocedValue, NewValue );
  118. // Set the new value in the output string pointer.
  119. if ( *OutValue != NULL ) {
  120. LocalFree( *OutValue );
  121. }
  122. *OutValue = allocedValue;
  123. return(ERROR_SUCCESS);
  124. } // ResUtilSetSzProperty
  125. //
  126. // Worker thread routines
  127. //
  128. extern CRITICAL_SECTION ClusResWorkerLock;
  129. typedef struct _WORK_CONTEXT {
  130. PCLUS_WORKER Worker;
  131. PVOID lpParameter;
  132. PWORKER_START_ROUTINE lpStartRoutine;
  133. } WORK_CONTEXT, *PWORK_CONTEXT;
  134. DWORD
  135. WINAPI
  136. ClusWorkerStart(
  137. IN PWORK_CONTEXT pContext
  138. )
  139. /*++
  140. Routine Description:
  141. Wrapper routine for cluster resource worker startup
  142. Arguments:
  143. Context - Supplies the context block. This will be freed.
  144. Return Value:
  145. ERROR_SUCCESS
  146. --*/
  147. {
  148. DWORD Status;
  149. WORK_CONTEXT Context;
  150. //
  151. // Capture our parameters and free the work context.
  152. //
  153. Context = *pContext;
  154. LocalFree(pContext);
  155. //
  156. // Call the worker routine
  157. //
  158. Status = (Context.lpStartRoutine)(Context.Worker, Context.lpParameter);
  159. //
  160. // Synchronize and clean up properly.
  161. //
  162. EnterCriticalSection(&ClusResWorkerLock);
  163. if (!Context.Worker->Terminate) {
  164. CloseHandle(Context.Worker->hThread);
  165. Context.Worker->hThread = NULL;
  166. }
  167. Context.Worker->Terminate = TRUE;
  168. LeaveCriticalSection(&ClusResWorkerLock);
  169. return(Status);
  170. } // ClusWorkerStart
  171. DWORD
  172. ClusWorkerCreate(
  173. OUT PCLUS_WORKER Worker,
  174. IN PWORKER_START_ROUTINE lpStartAddress,
  175. IN PVOID lpParameter
  176. )
  177. /*++
  178. Routine Description:
  179. Common wrapper for resource DLL worker threads. Provides
  180. "clean" terminate semantics
  181. Arguments:
  182. Worker - Returns an initialized worker structure
  183. lpStartAddress - Supplies the worker thread routine
  184. lpParameter - Supplies the parameter to be passed to the
  185. worker thread routine
  186. Return Value:
  187. ERROR_SUCCESS if successful
  188. Win32 error code otherwise
  189. --*/
  190. {
  191. PWORK_CONTEXT Context;
  192. DWORD ThreadId;
  193. DWORD Status;
  194. Context = (PWORK_CONTEXT)LocalAlloc(LMEM_FIXED, sizeof(WORK_CONTEXT));
  195. if (Context == NULL) {
  196. return(ERROR_NOT_ENOUGH_MEMORY);
  197. }
  198. Context->Worker = Worker;
  199. Context->lpParameter = lpParameter;
  200. Context->lpStartRoutine = lpStartAddress;
  201. Worker->Terminate = FALSE;
  202. Worker->hThread = CreateThread(NULL,
  203. 0,
  204. (LPTHREAD_START_ROUTINE)ClusWorkerStart,
  205. Context,
  206. 0,
  207. &ThreadId);
  208. if (Worker->hThread == NULL) {
  209. Status = GetLastError();
  210. LocalFree(Context);
  211. return(Status);
  212. }
  213. return(ERROR_SUCCESS);
  214. } // ClusWorkerCreate
  215. BOOL
  216. ClusWorkerCheckTerminate(
  217. IN PCLUS_WORKER Worker
  218. )
  219. /*++
  220. Routine Description:
  221. Checks to see if the specified Worker thread should exit ASAP.
  222. Arguments:
  223. Worker - Supplies the worker
  224. Return Value:
  225. TRUE if the thread should exit.
  226. FALSE otherwise
  227. --*/
  228. {
  229. return(Worker->Terminate);
  230. } // ClusWorkerCheckTerminate
  231. VOID
  232. ClusWorkerTerminate(
  233. IN PCLUS_WORKER Worker
  234. )
  235. /*++
  236. Routine Description:
  237. Checks to see if the specified Worker thread should exit ASAP.
  238. Arguments:
  239. Worker - Supplies the worker
  240. Return Value:
  241. None.
  242. --*/
  243. {
  244. //
  245. // N.B. There is a race condition here if multiple threads
  246. // call this routine on the same worker. The first one
  247. // through will set Terminate. The second one will see
  248. // that Terminate is set and return immediately without
  249. // waiting for the Worker to exit. Not really any nice
  250. // way to fix this without adding another synchronization
  251. // object.
  252. //
  253. if ((Worker->hThread == NULL) ||
  254. (Worker->Terminate)) {
  255. return;
  256. }
  257. EnterCriticalSection(&ClusResWorkerLock);
  258. if (!Worker->Terminate) {
  259. Worker->Terminate = TRUE;
  260. LeaveCriticalSection(&ClusResWorkerLock);
  261. WaitForSingleObject(Worker->hThread, INFINITE);
  262. CloseHandle(Worker->hThread);
  263. Worker->hThread = NULL;
  264. } else {
  265. LeaveCriticalSection(&ClusResWorkerLock);
  266. }
  267. return;
  268. } // ClusWorkerTerminate
  269. VOID
  270. ClusWorkerTerminateEx(
  271. IN PCLUS_WORKER Worker,
  272. IN DWORD Timeout
  273. )
  274. /*++
  275. Routine Description:
  276. Checks to see if the specified Worker thread should exit and waits a
  277. short time before killing the thread.
  278. Arguments:
  279. Worker - Supplies the worker
  280. Timeout - Supplies the timeout period in ms.
  281. Return Value:
  282. None.
  283. --*/
  284. {
  285. //
  286. // N.B. There is a race condition here if multiple threads
  287. // call this routine on the same worker. The first one
  288. // through will set Terminate. The second one will see
  289. // that Terminate is set and return immediately without
  290. // waiting for the Worker to exit. Not really any nice
  291. // way to fix this without adding another synchronization
  292. // object.
  293. //
  294. if ((Worker->hThread == NULL) ||
  295. (Worker->Terminate)) {
  296. return;
  297. }
  298. EnterCriticalSection(&ClusResWorkerLock);
  299. if (!Worker->Terminate) {
  300. Worker->Terminate = TRUE;
  301. LeaveCriticalSection(&ClusResWorkerLock);
  302. WaitForSingleObject(Worker->hThread, Timeout);
  303. CloseHandle(Worker->hThread);
  304. Worker->hThread = NULL;
  305. } else {
  306. LeaveCriticalSection(&ClusResWorkerLock);
  307. }
  308. return;
  309. } // ClusWorkerTerminate