Leaked source code of windows server 2003
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.

1769 lines
47 KiB

  1. /*++
  2. Copyright (c) 1992-1998 Microsoft Corporation
  3. Module Name:
  4. genapp.c
  5. Abstract:
  6. Resource DLL for Generic Applications.
  7. Author:
  8. Rod Gamache (rodga) 8-Jan-1996
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "clusres.h"
  13. #include "clusrtl.h"
  14. #include "userenv.h"
  15. #define LOG_CURRENT_MODULE LOG_MODULE_GENAPP
  16. #define DBG_PRINT printf
  17. #define PARAM_NAME__COMMANDLINE CLUSREG_NAME_GENAPP_COMMAND_LINE
  18. #define PARAM_NAME__CURRENTDIRECTORY CLUSREG_NAME_GENAPP_CURRENT_DIRECTORY
  19. #define PARAM_NAME__USENETWORKNAME CLUSREG_NAME_GENAPP_USE_NETWORK_NAME
  20. #define PARAM_NAME__INTERACTWITHDESKTOP CLUSREG_NAME_GENAPP_INTERACT_WITH_DESKTOP
  21. #define PARAM_MIN__USENETWORKNAME 0
  22. #define PARAM_MAX__USENETWORKNAME 1
  23. #define PARAM_DEFAULT__USENETWORKNAME 0
  24. #define PARAM_MIN__INTERACTWITHDESKTOP 0
  25. #define PARAM_MAX__INTERACTWITHDESKTOP 1
  26. #define PARAM_DEFAULT__INTERACTWITHDESKTOP 0
  27. typedef struct _GENAPP_PARAMS {
  28. PWSTR CommandLine;
  29. PWSTR CurrentDirectory;
  30. DWORD UseNetworkName;
  31. DWORD InteractWithDesktop;
  32. } GENAPP_PARAMS, *PGENAPP_PARAMS;
  33. typedef struct _GENAPP_RESOURCE {
  34. GENAPP_PARAMS Params;
  35. HRESOURCE hResource;
  36. HANDLE hProcess;
  37. DWORD ProcessId;
  38. HKEY ResourceKey;
  39. HKEY ParametersKey;
  40. RESOURCE_HANDLE ResourceHandle;
  41. CLUS_WORKER PendingThread;
  42. BOOL Online;
  43. BOOL SentCloseMessage;
  44. } GENAPP_RESOURCE, *PGENAPP_RESOURCE;
  45. //
  46. // Global Data
  47. //
  48. RESUTIL_PROPERTY_ITEM
  49. GenAppResourcePrivateProperties[] = {
  50. { PARAM_NAME__COMMANDLINE, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(GENAPP_PARAMS,CommandLine) },
  51. { PARAM_NAME__CURRENTDIRECTORY, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(GENAPP_PARAMS,CurrentDirectory) },
  52. { PARAM_NAME__INTERACTWITHDESKTOP, NULL, CLUSPROP_FORMAT_DWORD, PARAM_DEFAULT__INTERACTWITHDESKTOP, PARAM_MIN__INTERACTWITHDESKTOP, PARAM_MAX__INTERACTWITHDESKTOP, 0, FIELD_OFFSET(GENAPP_PARAMS,InteractWithDesktop) },
  53. { PARAM_NAME__USENETWORKNAME, NULL, CLUSPROP_FORMAT_DWORD, PARAM_DEFAULT__USENETWORKNAME, PARAM_MIN__USENETWORKNAME, PARAM_MAX__USENETWORKNAME, 0, FIELD_OFFSET(GENAPP_PARAMS,UseNetworkName) },
  54. { 0 }
  55. };
  56. //
  57. // critsec to synchronize calling of SetProcessWindowStation in ClRtl routine
  58. //
  59. CRITICAL_SECTION GenAppWinsta0Lock;
  60. // Event Logging routine
  61. #define g_LogEvent ClusResLogEvent
  62. #define g_SetResourceStatus ClusResSetResourceStatus
  63. // Forward reference to our RESAPI function table.
  64. extern CLRES_FUNCTION_TABLE GenAppFunctionTable;
  65. //
  66. // Forward routines
  67. //
  68. BOOLEAN
  69. VerifyApp(
  70. IN RESID ResourceId,
  71. IN BOOLEAN IsAliveFlag
  72. );
  73. BOOL
  74. FindOurWindow(
  75. HWND WindowHandle,
  76. LPARAM OurProcessId
  77. );
  78. DWORD
  79. GenAppGetPrivateResProperties(
  80. IN OUT PGENAPP_RESOURCE ResourceEntry,
  81. OUT PVOID OutBuffer,
  82. IN DWORD OutBufferSize,
  83. OUT LPDWORD BytesReturned
  84. );
  85. DWORD
  86. GenAppValidatePrivateResProperties(
  87. IN OUT PGENAPP_RESOURCE ResourceEntry,
  88. IN PVOID InBuffer,
  89. IN DWORD InBufferSize,
  90. OUT PGENAPP_PARAMS Params
  91. );
  92. DWORD
  93. GenAppSetPrivateResProperties(
  94. IN OUT PGENAPP_RESOURCE ResourceEntry,
  95. IN PVOID InBuffer,
  96. IN DWORD InBufferSize
  97. );
  98. DWORD
  99. GenAppGetPids(
  100. IN OUT PGENAPP_RESOURCE ResourceEntry,
  101. OUT PVOID OutBuffer,
  102. IN DWORD OutBufferSize,
  103. OUT LPDWORD BytesReturned
  104. );
  105. //
  106. // end of forward declarations
  107. //
  108. BOOL
  109. GenAppInit(
  110. VOID
  111. )
  112. {
  113. BOOL success;
  114. DWORD spinCount;
  115. //
  116. // set spinCount so system pre-allocates the event for critical
  117. // sections. use the same spin count that the heap mgr uses as doc'ed in
  118. // MSDN
  119. //
  120. spinCount = 0x80000000 | 4000;
  121. success = InitializeCriticalSectionAndSpinCount(&GenAppWinsta0Lock,
  122. spinCount);
  123. return success;
  124. }
  125. VOID
  126. GenAppUninit(
  127. VOID
  128. )
  129. {
  130. DeleteCriticalSection( &GenAppWinsta0Lock );
  131. }
  132. BOOLEAN
  133. WINAPI
  134. GenAppDllEntryPoint(
  135. IN HINSTANCE DllHandle,
  136. IN DWORD Reason,
  137. IN LPVOID Reserved
  138. )
  139. {
  140. switch( Reason ) {
  141. case DLL_PROCESS_ATTACH:
  142. if ( !GenAppInit() ) {
  143. return(FALSE);
  144. }
  145. break;
  146. case DLL_PROCESS_DETACH:
  147. GenAppUninit();
  148. break;
  149. default:
  150. break;
  151. }
  152. return(TRUE);
  153. } // GenAppDllEntryPoint
  154. RESID
  155. WINAPI
  156. GenAppOpen(
  157. IN LPCWSTR ResourceName,
  158. IN HKEY ResourceKey,
  159. IN RESOURCE_HANDLE ResourceHandle
  160. )
  161. /*++
  162. Routine Description:
  163. Open routine for generic application resource.
  164. Arguments:
  165. ResourceName - supplies the resource name
  166. ResourceKey - supplies a handle to the resource's cluster registry key
  167. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  168. is called.
  169. Return Value:
  170. RESID of created resource
  171. Zero on failure
  172. --*/
  173. {
  174. RESID appResid = 0;
  175. DWORD errorCode;
  176. HKEY parametersKey = NULL;
  177. HKEY resKey = NULL;
  178. PGENAPP_RESOURCE resourceEntry = NULL;
  179. DWORD paramNameMaxSize = 0;
  180. HCLUSTER hCluster;
  181. //
  182. // Get registry parameters for this resource.
  183. //
  184. errorCode = ClusterRegOpenKey( ResourceKey,
  185. CLUSREG_KEYNAME_PARAMETERS,
  186. KEY_READ,
  187. &parametersKey );
  188. if ( errorCode != NO_ERROR ) {
  189. (g_LogEvent)(ResourceHandle,
  190. LOG_ERROR,
  191. L"Unable to open parameters key. Error: %1!u!.\n",
  192. errorCode );
  193. goto error_exit;
  194. }
  195. //
  196. // Get a handle to our resource key so that we can get our name later
  197. // if we need to log an event.
  198. //
  199. errorCode = ClusterRegOpenKey( ResourceKey,
  200. L"",
  201. KEY_READ,
  202. &resKey);
  203. if (errorCode != ERROR_SUCCESS) {
  204. (g_LogEvent)(ResourceHandle,
  205. LOG_ERROR,
  206. L"Unable to open resource key. Error: %1!u!.\n",
  207. errorCode );
  208. goto error_exit;
  209. }
  210. resourceEntry = LocalAlloc( LMEM_FIXED, sizeof(GENAPP_RESOURCE) );
  211. if ( resourceEntry == NULL ) {
  212. (g_LogEvent)(
  213. ResourceHandle,
  214. LOG_ERROR,
  215. L"Failed to allocate a process info structure.\n" );
  216. errorCode = ERROR_NOT_ENOUGH_MEMORY;
  217. goto error_exit;
  218. }
  219. ZeroMemory( resourceEntry, sizeof(GENAPP_RESOURCE) );
  220. resourceEntry->ResourceHandle = ResourceHandle;
  221. resourceEntry->ResourceKey = resKey;
  222. resourceEntry->ParametersKey = parametersKey;
  223. hCluster = OpenCluster(NULL);
  224. if (hCluster == NULL) {
  225. errorCode = GetLastError();
  226. (g_LogEvent)(ResourceHandle,
  227. LOG_ERROR,
  228. L"Failed to open cluster, error %1!u!.\n",
  229. errorCode);
  230. goto error_exit;
  231. }
  232. resourceEntry->hResource = OpenClusterResource( hCluster, ResourceName );
  233. errorCode = GetLastError();
  234. CloseCluster(hCluster);
  235. if (resourceEntry->hResource == NULL) {
  236. (g_LogEvent)(
  237. ResourceHandle,
  238. LOG_ERROR,
  239. L"Failed to open resource, error %1!u!.\n",
  240. errorCode
  241. );
  242. goto error_exit;
  243. }
  244. appResid = (RESID)resourceEntry;
  245. error_exit:
  246. if ( appResid == NULL) {
  247. if (parametersKey != NULL) {
  248. ClusterRegCloseKey( parametersKey );
  249. }
  250. if (resKey != NULL) {
  251. ClusterRegCloseKey( resKey );
  252. }
  253. }
  254. if ( (appResid == 0) && (resourceEntry != NULL) ) {
  255. LocalFree( resourceEntry );
  256. }
  257. if ( errorCode != ERROR_SUCCESS ) {
  258. SetLastError( errorCode );
  259. }
  260. return(appResid);
  261. } // GenAppOpen
  262. DWORD
  263. WINAPI
  264. GenAppOnlineWorker(
  265. IN PCLUS_WORKER Worker,
  266. IN PGENAPP_RESOURCE ResourceEntry
  267. )
  268. /*++
  269. Routine Description:
  270. Does the work of bringing a genapp resource online.
  271. Arguments:
  272. Worker - Supplies the worker structure
  273. ResourceEntry - A pointer to the GenApp block for this resource.
  274. Returns:
  275. ERROR_SUCCESS if successful.
  276. Win32 error code on failure.
  277. --*/
  278. {
  279. RESOURCE_STATUS resourceStatus;
  280. DWORD status = ERROR_SUCCESS;
  281. STARTUPINFO StartupInfo;
  282. PROCESS_INFORMATION Process;
  283. LPWSTR nameOfPropInError;
  284. LPWSTR expandedDir = NULL;
  285. LPWSTR expandedCommand = NULL;
  286. // Create Process parameters
  287. LPVOID Environment = NULL;
  288. LPVOID OldEnvironment;
  289. ResUtilInitializeResourceStatus( &resourceStatus );
  290. resourceStatus.ResourceState = ClusterResourceFailed;
  291. //resourceStatus.WaitHint = 0;
  292. resourceStatus.CheckPoint = 1;
  293. //
  294. // Read our parameters.
  295. //
  296. status = ResUtilGetPropertiesToParameterBlock( ResourceEntry->ParametersKey,
  297. GenAppResourcePrivateProperties,
  298. (LPBYTE) &ResourceEntry->Params,
  299. TRUE, // CheckForRequiredProperties
  300. &nameOfPropInError );
  301. if ( status != ERROR_SUCCESS ) {
  302. (g_LogEvent)(
  303. ResourceEntry->ResourceHandle,
  304. LOG_ERROR,
  305. L"Unable to read the '%1' property. Error: %2!u!.\n",
  306. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  307. status );
  308. goto error_exit;
  309. }
  310. if ( ResourceEntry->Params.UseNetworkName ) {
  311. //
  312. // Create the new environment with the simulated net name.
  313. //
  314. Environment = ResUtilGetEnvironmentWithNetName( ResourceEntry->hResource );
  315. } else {
  316. HANDLE processToken;
  317. //
  318. // get the current process token. If it fails, we revert to using just the
  319. // system environment area
  320. //
  321. OpenProcessToken( GetCurrentProcess(), MAXIMUM_ALLOWED, &processToken );
  322. //
  323. // Clone the current environment, picking up any changes that might have
  324. // been made after resmon started
  325. //
  326. CreateEnvironmentBlock(&Environment, processToken, FALSE );
  327. if ( processToken != NULL ) {
  328. CloseHandle( processToken );
  329. }
  330. }
  331. ZeroMemory( &StartupInfo, sizeof(StartupInfo) );
  332. StartupInfo.cb = sizeof(StartupInfo);
  333. //StartupInfo.lpTitle = NULL;
  334. //StartupInfo.lpDesktop = NULL;
  335. StartupInfo.wShowWindow = SW_HIDE;
  336. StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  337. if ( ResourceEntry->Params.InteractWithDesktop ) {
  338. //
  339. // don't blindly hang waiting for the lock to become available.
  340. //
  341. while ( !TryEnterCriticalSection( &GenAppWinsta0Lock )) {
  342. if ( ClusWorkerCheckTerminate( Worker )) {
  343. (g_LogEvent)(ResourceEntry->ResourceHandle,
  344. LOG_WARNING,
  345. L"Aborting online due to worker thread terminate request. lock currently "
  346. L"owned by thread %1!u!.\n",
  347. GenAppWinsta0Lock.OwningThread );
  348. goto error_exit;
  349. }
  350. Sleep( 1000 );
  351. }
  352. status = ClRtlAddClusterServiceAccountToWinsta0DACL();
  353. LeaveCriticalSection( &GenAppWinsta0Lock );
  354. if ( status != ERROR_SUCCESS ) {
  355. (g_LogEvent)(ResourceEntry->ResourceHandle,
  356. LOG_ERROR,
  357. L"Unable to set DACL on interactive window station and its desktop. Error: %1!u!.\n",
  358. status );
  359. goto error_exit;
  360. }
  361. StartupInfo.lpDesktop = L"WinSta0\\Default";
  362. StartupInfo.wShowWindow = SW_SHOW;
  363. }
  364. //
  365. // Expand the current directory parameter
  366. //
  367. if ( ResourceEntry->Params.CurrentDirectory ) {
  368. expandedDir = ResUtilExpandEnvironmentStrings( ResourceEntry->Params.CurrentDirectory );
  369. if ( expandedDir == NULL ) {
  370. status = GetLastError();
  371. (g_LogEvent)(ResourceEntry->ResourceHandle,
  372. LOG_ERROR,
  373. L"Error expanding the current directory, %1!ls!. Error: %2!u!.\n",
  374. ResourceEntry->Params.CurrentDirectory,
  375. status );
  376. goto error_exit;
  377. }
  378. }
  379. //
  380. // Expand the command line parameter
  381. //
  382. if ( ResourceEntry->Params.CommandLine ) {
  383. expandedCommand = ResUtilExpandEnvironmentStrings( ResourceEntry->Params.CommandLine );
  384. if ( expandedCommand == NULL ) {
  385. status = GetLastError();
  386. (g_LogEvent)(ResourceEntry->ResourceHandle,
  387. LOG_ERROR,
  388. L"Error expanding the command line, %1!ls!. Error: %2!u!.\n",
  389. ResourceEntry->Params.CommandLine,
  390. status );
  391. goto error_exit;
  392. }
  393. }
  394. if ( !CreateProcess( NULL,
  395. expandedCommand,
  396. NULL,
  397. NULL,
  398. FALSE,
  399. CREATE_UNICODE_ENVIRONMENT,
  400. Environment,
  401. expandedDir,
  402. &StartupInfo,
  403. &Process ) )
  404. {
  405. status = GetLastError();
  406. ClusResLogSystemEventByKeyData(ResourceEntry->ResourceKey,
  407. LOG_CRITICAL,
  408. RES_GENAPP_CREATE_FAILED,
  409. sizeof(status),
  410. &status);
  411. (g_LogEvent)(ResourceEntry->ResourceHandle,
  412. LOG_ERROR,
  413. L"Failed to create process. Error: %1!u!.\n",
  414. status );
  415. goto error_exit;
  416. }
  417. //
  418. // Save the handle to the process
  419. //
  420. ResourceEntry->hProcess = Process.hProcess;
  421. ResourceEntry->ProcessId = Process.dwProcessId;
  422. CloseHandle( Process.hThread );
  423. ResourceEntry->Online = TRUE;
  424. //
  425. // When the process fails EventHandle will be signaled.
  426. // Because of this no polling is necessary.
  427. //
  428. resourceStatus.EventHandle = ResourceEntry->hProcess;
  429. resourceStatus.ResourceState = ClusterResourceOnline;
  430. error_exit:
  431. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  432. &resourceStatus );
  433. if ( resourceStatus.ResourceState == ClusterResourceOnline ) {
  434. ResourceEntry->Online = TRUE;
  435. } else {
  436. ResourceEntry->Online = FALSE;
  437. }
  438. if ( expandedDir != NULL ) {
  439. LocalFree( expandedDir );
  440. }
  441. if ( expandedCommand != NULL ) {
  442. LocalFree( expandedCommand );
  443. }
  444. if (Environment != NULL) {
  445. RtlDestroyEnvironment(Environment);
  446. }
  447. return(status);
  448. } // GenAppOnlineWorker
  449. DWORD
  450. WINAPI
  451. GenAppOnline(
  452. IN RESID ResourceId,
  453. IN OUT PHANDLE EventHandle
  454. )
  455. /*++
  456. Routine Description:
  457. Online routine for Generic Application resource.
  458. Arguments:
  459. ResourceId - Supplies resource id to be brought online
  460. EventHandle - Supplies a pointer to a handle to signal on error.
  461. Return Value:
  462. ERROR_SUCCESS if successful.
  463. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  464. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  465. acquire 'ownership'.
  466. Win32 error code if other failure.
  467. --*/
  468. {
  469. PGENAPP_RESOURCE resourceEntry;
  470. DWORD status = ERROR_SUCCESS;
  471. resourceEntry = (PGENAPP_RESOURCE)ResourceId;
  472. if ( resourceEntry == NULL ) {
  473. #if DBG
  474. OutputDebugStringA( "GenApp: Online request for a nonexistent resource\n" );
  475. #endif
  476. return(ERROR_RESOURCE_NOT_FOUND);
  477. }
  478. if ( resourceEntry->hProcess != NULL ) {
  479. (g_LogEvent)(
  480. resourceEntry->ResourceHandle,
  481. LOG_ERROR,
  482. L"Online request and process handle is not NULL!\n" );
  483. return(ERROR_NOT_READY);
  484. }
  485. ClusWorkerTerminate( &resourceEntry->PendingThread );
  486. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  487. GenAppOnlineWorker,
  488. resourceEntry );
  489. if ( status == ERROR_SUCCESS ) {
  490. status = ERROR_IO_PENDING;
  491. }
  492. return(status);
  493. } // GenAppOnline
  494. VOID
  495. WINAPI
  496. GenAppTerminate(
  497. IN RESID ResourceId
  498. )
  499. /*++
  500. Routine Description:
  501. Terminate entry point for the Generic Application resource.
  502. Arguments:
  503. ResourceId - Supplies resource id to be terminated
  504. Return Value:
  505. None.
  506. --*/
  507. {
  508. PGENAPP_RESOURCE pResource;
  509. DWORD errorCode;
  510. pResource = ( PGENAPP_RESOURCE ) ResourceId;
  511. //
  512. // synchronize with any existing pending operation
  513. //
  514. ClusWorkerTerminate( &pResource->PendingThread );
  515. if ( pResource->hProcess != NULL ) {
  516. if ( !TerminateProcess( pResource->hProcess, 1 ) ) {
  517. errorCode = GetLastError();
  518. if ( errorCode != ERROR_ACCESS_DENIED ) {
  519. (g_LogEvent)(pResource->ResourceHandle,
  520. LOG_ERROR,
  521. L"Failed to terminate Process ID %1!u!. Error: %2!u!.\n",
  522. pResource->ProcessId,
  523. errorCode );
  524. }
  525. }
  526. pResource->ProcessId = 0;
  527. CloseHandle( pResource->hProcess );
  528. pResource->hProcess = NULL;
  529. pResource->Online = FALSE;
  530. }
  531. } // GenAppTerminate
  532. DWORD
  533. WINAPI
  534. GenAppOfflineWorker(
  535. IN PCLUS_WORKER Worker,
  536. IN PGENAPP_RESOURCE ResourceEntry
  537. )
  538. /*++
  539. Routine Description:
  540. Real worker routine for offlining a Generic Application resource.
  541. Arguments:
  542. Worker - Supplies the worker structure
  543. Context - A pointer to the GenApp block for this resource.
  544. Return Value:
  545. None.
  546. --*/
  547. {
  548. DWORD errorCode = ERROR_SUCCESS;
  549. BOOL switchedDesktop = FALSE;
  550. HDESK previousDesktop = NULL;
  551. HDESK inputDesktop;
  552. HDESK desktopHandle = NULL;
  553. BOOL success;
  554. BOOL callTerminateProc = TRUE;
  555. HWINSTA winsta0 = NULL;
  556. HWINSTA previousWinsta;
  557. DWORD logLevel = LOG_INFORMATION;
  558. RESOURCE_STATUS resourceStatus;
  559. //
  560. // init resource status structure
  561. //
  562. ResUtilInitializeResourceStatus( &resourceStatus );
  563. resourceStatus.ResourceState = ClusterResourceFailed;
  564. resourceStatus.CheckPoint = 1;
  565. //
  566. // get a handle to the appropriate desktop so we enum the correct window
  567. // set.
  568. //
  569. if ( ResourceEntry->Params.InteractWithDesktop ) {
  570. //
  571. // periodically check to see if we should terminate
  572. //
  573. while ( !TryEnterCriticalSection( &GenAppWinsta0Lock )) {
  574. if ( ClusWorkerCheckTerminate( Worker )) {
  575. (g_LogEvent)(ResourceEntry->ResourceHandle,
  576. LOG_WARNING,
  577. L"Aborting offline while trying to acquire desktop lock. lock currently "
  578. L"owned by thread %1!u!.\n",
  579. GenAppWinsta0Lock.OwningThread );
  580. goto error_exit;
  581. }
  582. Sleep( 500 );
  583. }
  584. winsta0 = OpenWindowStation( L"winsta0", FALSE, GENERIC_ALL );
  585. if ( winsta0 != NULL ) {
  586. previousWinsta = GetProcessWindowStation();
  587. if ( previousWinsta != NULL ) {
  588. success = SetProcessWindowStation( winsta0 );
  589. if ( success ) {
  590. //
  591. // if we have window station access, we should have desktop as well
  592. //
  593. desktopHandle = OpenInputDesktop( 0, FALSE, GENERIC_ALL );
  594. if ( desktopHandle != NULL ) {
  595. switchedDesktop = TRUE;
  596. }
  597. }
  598. }
  599. }
  600. if ( !switchedDesktop ) {
  601. errorCode = GetLastError();
  602. (g_LogEvent)(ResourceEntry->ResourceHandle,
  603. LOG_ERROR,
  604. L"Unable to switch to interactive desktop for process %1!u!, status %2!u!.\n",
  605. ResourceEntry->ProcessId,
  606. errorCode );
  607. LeaveCriticalSection( &GenAppWinsta0Lock );
  608. if ( winsta0 != NULL ) {
  609. CloseWindowStation( winsta0 );
  610. }
  611. }
  612. } else {
  613. //
  614. // get handle to service controller's desktop
  615. //
  616. desktopHandle = GetThreadDesktop( GetCurrentThreadId() );
  617. }
  618. ResourceEntry->SentCloseMessage = FALSE;
  619. #if DBG
  620. (g_LogEvent)(ResourceEntry->ResourceHandle,
  621. LOG_INFORMATION,
  622. L"Looking for window with PID %1!u!.\n",
  623. ResourceEntry->ProcessId );
  624. #endif
  625. //
  626. // find our window. If found, we'll post a WM_CLOSE and set
  627. // SentCloseMessage. It's possible, under heavy load conditions with rapid
  628. // resource state transition, that the primary top level window associated
  629. // with the process has not been created when the offline request is
  630. // made. We'll send WM_CLOSE to the ones we find and hope that it shuts
  631. // down the process. If no windows are found, we just terminate the
  632. // process.
  633. //
  634. do {
  635. if ( desktopHandle ) {
  636. EnumDesktopWindows( desktopHandle, FindOurWindow, (LPARAM)ResourceEntry );
  637. }
  638. if ( ResourceEntry->SentCloseMessage ) {
  639. //
  640. // we found a toplevel window. wait on the process handle until the
  641. // handle is signalled or a pending timeout has occurred
  642. //
  643. (g_LogEvent)(ResourceEntry->ResourceHandle,
  644. LOG_INFORMATION,
  645. L"Sent WM_CLOSE to process %1!u! - waiting for process to terminate.\n",
  646. ResourceEntry->ProcessId);
  647. errorCode = WaitForSingleObject( ResourceEntry->hProcess, 1000 );
  648. if ( errorCode == WAIT_OBJECT_0 ) {
  649. callTerminateProc = FALSE;
  650. break;
  651. } else {
  652. if ( ClusWorkerCheckTerminate( Worker )) {
  653. (g_LogEvent)(ResourceEntry->ResourceHandle,
  654. LOG_WARNING,
  655. L"Aborting offline while waiting for process to terminate.\n");
  656. logLevel = LOG_WARNING;
  657. break;
  658. }
  659. }
  660. } else {
  661. (g_LogEvent)(ResourceEntry->ResourceHandle,
  662. LOG_INFORMATION,
  663. L"No windows detected for process %1!u!\n",
  664. ResourceEntry->ProcessId);
  665. break;
  666. }
  667. } while ( TRUE );
  668. if ( switchedDesktop ) {
  669. SetProcessWindowStation( previousWinsta );
  670. CloseDesktop( desktopHandle );
  671. CloseWindowStation( winsta0 );
  672. LeaveCriticalSection( &GenAppWinsta0Lock );
  673. }
  674. if ( callTerminateProc ) {
  675. (g_LogEvent)(ResourceEntry->ResourceHandle,
  676. logLevel,
  677. L"Terminating process %1!u!\n",
  678. ResourceEntry->ProcessId);
  679. if ( !TerminateProcess( ResourceEntry->hProcess, 1 ) ) {
  680. errorCode = GetLastError();
  681. if ( errorCode != ERROR_ACCESS_DENIED ) {
  682. (g_LogEvent)(
  683. ResourceEntry->ResourceHandle,
  684. LOG_ERROR,
  685. L"Failed to terminate Process ID %1!u!. Error: %2!u!.\n",
  686. ResourceEntry->ProcessId,
  687. errorCode );
  688. }
  689. }
  690. }
  691. ResourceEntry->ProcessId = 0;
  692. CloseHandle( ResourceEntry->hProcess );
  693. ResourceEntry->hProcess = NULL;
  694. ResourceEntry->Online = FALSE;
  695. resourceStatus.ResourceState = ClusterResourceOffline;
  696. error_exit:
  697. (g_SetResourceStatus)( ResourceEntry->ResourceHandle,
  698. &resourceStatus );
  699. return ERROR_SUCCESS;
  700. } // GenAppOfflineThread
  701. DWORD
  702. WINAPI
  703. GenAppOffline(
  704. IN RESID ResourceId
  705. )
  706. /*++
  707. Routine Description:
  708. Offline routine for Generic Application resource.
  709. Arguments:
  710. ResourceId - Supplies the resource to be taken offline
  711. Return Value:
  712. ERROR_SUCCESS - always successful.
  713. --*/
  714. {
  715. PGENAPP_RESOURCE resourceEntry;
  716. DWORD status = ERROR_SUCCESS;
  717. resourceEntry = (PGENAPP_RESOURCE)ResourceId;
  718. if ( resourceEntry == NULL ) {
  719. #if DBG
  720. OutputDebugStringA( "GenApp: Offline request for a nonexistent resource\n" );
  721. #endif
  722. return(ERROR_RESOURCE_NOT_FOUND);
  723. }
  724. if ( resourceEntry->hProcess == NULL ) {
  725. (g_LogEvent)(
  726. resourceEntry->ResourceHandle,
  727. LOG_ERROR,
  728. L"Offline request and process handle is NULL!\n" );
  729. return(ERROR_NOT_READY);
  730. }
  731. ClusWorkerTerminate( &resourceEntry->PendingThread );
  732. status = ClusWorkerCreate( &resourceEntry->PendingThread,
  733. GenAppOfflineWorker,
  734. resourceEntry );
  735. if ( status == ERROR_SUCCESS ) {
  736. status = ERROR_IO_PENDING;
  737. }
  738. return(status);
  739. } // GenAppOffline
  740. BOOL
  741. WINAPI
  742. GenAppIsAlive(
  743. IN RESID ResourceId
  744. )
  745. /*++
  746. Routine Description:
  747. IsAlive routine for Generice Applications resource.
  748. Arguments:
  749. ResourceId - Supplies the resource id to be polled.
  750. Return Value:
  751. TRUE - Resource is alive and well
  752. FALSE - Resource is toast.
  753. --*/
  754. {
  755. return VerifyApp( ResourceId, TRUE );
  756. } // GenAppIsAlive
  757. BOOLEAN
  758. VerifyApp(
  759. IN RESID ResourceId,
  760. IN BOOLEAN IsAliveFlag
  761. )
  762. /*++
  763. Routine Description:
  764. Verify that a Generic Applications resource is running
  765. Arguments:
  766. ResourceId - Supplies the resource id to be polled.
  767. IsAliveFlag - TRUE if called from IsAlive, otherwise called from LooksAlive.
  768. Return Value:
  769. TRUE - Resource is alive and well
  770. FALSE - Resource is toast.
  771. --*/
  772. {
  773. return TRUE;
  774. } // VerifyApp
  775. BOOL
  776. WINAPI
  777. GenAppLooksAlive(
  778. IN RESID ResourceId
  779. )
  780. /*++
  781. Routine Description:
  782. LooksAlive routine for Generic Applications resource.
  783. Arguments:
  784. ResourceId - Supplies the resource id to be polled.
  785. Return Value:
  786. TRUE - Resource looks like it is alive and well
  787. FALSE - Resource looks like it is toast.
  788. --*/
  789. {
  790. return VerifyApp( ResourceId, FALSE );
  791. } // GenAppLooksAlive
  792. VOID
  793. WINAPI
  794. GenAppClose(
  795. IN RESID ResourceId
  796. )
  797. /*++
  798. Routine Description:
  799. Close routine for Generic Applications resource.
  800. Arguments:
  801. ResourceId - Supplies resource id to be closed
  802. Return Value:
  803. None.
  804. --*/
  805. {
  806. PGENAPP_RESOURCE resourceEntry;
  807. DWORD errorCode;
  808. resourceEntry = (PGENAPP_RESOURCE)ResourceId;
  809. if ( resourceEntry == NULL ) {
  810. #if DBG
  811. OutputDebugStringA( "GenApp: Close request for a nonexistent resource\n" );
  812. #endif
  813. return;
  814. }
  815. ClusterRegCloseKey( resourceEntry->ParametersKey );
  816. ClusterRegCloseKey( resourceEntry->ResourceKey );
  817. CloseClusterResource( resourceEntry->hResource );
  818. LocalFree( resourceEntry->Params.CommandLine );
  819. LocalFree( resourceEntry->Params.CurrentDirectory );
  820. LocalFree( resourceEntry );
  821. } // GenAppClose
  822. DWORD
  823. GenAppResourceControl(
  824. IN RESID ResourceId,
  825. IN DWORD ControlCode,
  826. IN PVOID InBuffer,
  827. IN DWORD InBufferSize,
  828. OUT PVOID OutBuffer,
  829. IN DWORD OutBufferSize,
  830. OUT LPDWORD BytesReturned
  831. )
  832. /*++
  833. Routine Description:
  834. ResourceControl routine for Generic Application resources.
  835. Perform the control request specified by ControlCode on the specified
  836. resource.
  837. Arguments:
  838. ResourceId - Supplies the resource id for the specific resource.
  839. ControlCode - Supplies the control code that defines the action
  840. to be performed.
  841. InBuffer - Supplies a pointer to a buffer containing input data.
  842. InBufferSize - Supplies the size, in bytes, of the data pointed
  843. to by InBuffer.
  844. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  845. OutBufferSize - Supplies the size, in bytes, of the available space
  846. pointed to by OutBuffer.
  847. BytesReturned - Returns the number of bytes of OutBuffer actually
  848. filled in by the resource. If OutBuffer is too small, BytesReturned
  849. contains the total number of bytes for the operation to succeed.
  850. Return Value:
  851. ERROR_SUCCESS - The function completed successfully.
  852. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  853. In some cases, this allows the cluster software to perform the work.
  854. Win32 error code - The function failed.
  855. --*/
  856. {
  857. DWORD status;
  858. PGENAPP_RESOURCE resourceEntry;
  859. DWORD required;
  860. resourceEntry = (PGENAPP_RESOURCE)ResourceId;
  861. if ( resourceEntry == NULL ) {
  862. #if DBG
  863. OutputDebugStringA( "GenApp: ResourceControl request for a nonexistent resource\n" );
  864. #endif
  865. return(FALSE);
  866. }
  867. switch ( ControlCode ) {
  868. case CLUSCTL_RESOURCE_UNKNOWN:
  869. *BytesReturned = 0;
  870. status = ERROR_SUCCESS;
  871. break;
  872. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  873. status = ResUtilGetPropertyFormats( GenAppResourcePrivateProperties,
  874. OutBuffer,
  875. OutBufferSize,
  876. BytesReturned,
  877. &required );
  878. if ( status == ERROR_MORE_DATA ) {
  879. *BytesReturned = required;
  880. }
  881. break;
  882. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  883. status = ResUtilEnumProperties( GenAppResourcePrivateProperties,
  884. OutBuffer,
  885. OutBufferSize,
  886. BytesReturned,
  887. &required );
  888. if ( status == ERROR_MORE_DATA ) {
  889. *BytesReturned = required;
  890. }
  891. break;
  892. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  893. status = GenAppGetPrivateResProperties( resourceEntry,
  894. OutBuffer,
  895. OutBufferSize,
  896. BytesReturned );
  897. break;
  898. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  899. status = GenAppValidatePrivateResProperties( resourceEntry,
  900. InBuffer,
  901. InBufferSize,
  902. NULL );
  903. break;
  904. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  905. status = GenAppSetPrivateResProperties( resourceEntry,
  906. InBuffer,
  907. InBufferSize );
  908. break;
  909. case CLUSCTL_RESOURCE_GET_LOADBAL_PROCESS_LIST:
  910. status = GenAppGetPids( resourceEntry,
  911. OutBuffer,
  912. OutBufferSize,
  913. BytesReturned );
  914. break;
  915. default:
  916. status = ERROR_INVALID_FUNCTION;
  917. break;
  918. }
  919. return(status);
  920. } // GenAppResourceControl
  921. DWORD
  922. GenAppResourceTypeControl(
  923. IN LPCWSTR ResourceTypeName,
  924. IN DWORD ControlCode,
  925. IN PVOID InBuffer,
  926. IN DWORD InBufferSize,
  927. OUT PVOID OutBuffer,
  928. IN DWORD OutBufferSize,
  929. OUT LPDWORD BytesReturned
  930. )
  931. /*++
  932. Routine Description:
  933. ResourceTypeControl routine for Generic Application resources.
  934. Perform the control request specified by ControlCode for this resource type.
  935. Arguments:
  936. ResourceTypeName - Supplies the resource type name.
  937. ControlCode - Supplies the control code that defines the action
  938. to be performed.
  939. InBuffer - Supplies a pointer to a buffer containing input data.
  940. InBufferSize - Supplies the size, in bytes, of the data pointed
  941. to by InBuffer.
  942. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  943. OutBufferSize - Supplies the size, in bytes, of the available space
  944. pointed to by OutBuffer.
  945. BytesReturned - Returns the number of bytes of OutBuffer actually
  946. filled in by the resource. If OutBuffer is too small, BytesReturned
  947. contains the total number of bytes for the operation to succeed.
  948. Return Value:
  949. ERROR_SUCCESS - The function completed successfully.
  950. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  951. In some cases, this allows the cluster software to perform the work.
  952. Win32 error code - The function failed.
  953. --*/
  954. {
  955. DWORD status;
  956. DWORD required;
  957. switch ( ControlCode ) {
  958. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  959. *BytesReturned = 0;
  960. status = ERROR_SUCCESS;
  961. break;
  962. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  963. status = ResUtilGetPropertyFormats( GenAppResourcePrivateProperties,
  964. OutBuffer,
  965. OutBufferSize,
  966. BytesReturned,
  967. &required );
  968. if ( status == ERROR_MORE_DATA ) {
  969. *BytesReturned = required;
  970. }
  971. break;
  972. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  973. status = ResUtilEnumProperties( GenAppResourcePrivateProperties,
  974. OutBuffer,
  975. OutBufferSize,
  976. BytesReturned,
  977. &required );
  978. if ( status == ERROR_MORE_DATA ) {
  979. *BytesReturned = required;
  980. }
  981. break;
  982. default:
  983. status = ERROR_INVALID_FUNCTION;
  984. break;
  985. }
  986. return(status);
  987. } // GenAppResourceTypeControl
  988. DWORD
  989. GenAppGetPrivateResProperties(
  990. IN OUT PGENAPP_RESOURCE ResourceEntry,
  991. OUT PVOID OutBuffer,
  992. IN DWORD OutBufferSize,
  993. OUT LPDWORD BytesReturned
  994. )
  995. /*++
  996. Routine Description:
  997. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  998. for resources of type GenApp.
  999. Arguments:
  1000. ResourceEntry - Supplies the resource entry on which to operate.
  1001. OutBuffer - Returns the output data.
  1002. OutBufferSize - Supplies the size, in bytes, of the data pointed
  1003. to by OutBuffer.
  1004. BytesReturned - The number of bytes returned in OutBuffer.
  1005. Return Value:
  1006. ERROR_SUCCESS - The function completed successfully.
  1007. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1008. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1009. Win32 error code - The function failed.
  1010. --*/
  1011. {
  1012. DWORD status;
  1013. DWORD required;
  1014. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1015. GenAppResourcePrivateProperties,
  1016. OutBuffer,
  1017. OutBufferSize,
  1018. BytesReturned,
  1019. &required );
  1020. if ( status == ERROR_MORE_DATA ) {
  1021. *BytesReturned = required;
  1022. }
  1023. return(status);
  1024. } // GenAppGetPrivateResProperties
  1025. DWORD
  1026. GenAppValidatePrivateResProperties(
  1027. IN OUT PGENAPP_RESOURCE ResourceEntry,
  1028. IN PVOID InBuffer,
  1029. IN DWORD InBufferSize,
  1030. OUT PGENAPP_PARAMS Params
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1035. function for resources of type Generic Application.
  1036. Arguments:
  1037. ResourceEntry - Supplies the resource entry on which to operate.
  1038. InBuffer - Supplies a pointer to a buffer containing input data.
  1039. InBufferSize - Supplies the size, in bytes, of the data pointed
  1040. to by InBuffer.
  1041. Params - Supplies the parameter block to fill in.
  1042. Return Value:
  1043. ERROR_SUCCESS - The function completed successfully.
  1044. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1045. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1046. ERROR_DEPENDENCY_NOT_FOUND - Trying to set UseNetworkName when there
  1047. is no dependency on a Network Name resource.
  1048. Win32 error code - The function failed.
  1049. --*/
  1050. {
  1051. DWORD status;
  1052. GENAPP_PARAMS currentProps;
  1053. GENAPP_PARAMS newProps;
  1054. PGENAPP_PARAMS pParams = NULL;
  1055. BOOL hResDependency;
  1056. LPWSTR nameOfPropInError;
  1057. WCHAR netnameBuffer[ MAX_PATH + 1 ];
  1058. DWORD netnameBufferSize = sizeof( netnameBuffer ) / sizeof( WCHAR );
  1059. //
  1060. // Check if there is input data.
  1061. //
  1062. if ( (InBuffer == NULL) ||
  1063. (InBufferSize < sizeof(DWORD)) ) {
  1064. return(ERROR_INVALID_DATA);
  1065. }
  1066. //
  1067. // Retrieve the current set of private properties from the
  1068. // cluster database.
  1069. //
  1070. ZeroMemory( &currentProps, sizeof(currentProps) );
  1071. status = ResUtilGetPropertiesToParameterBlock(
  1072. ResourceEntry->ParametersKey,
  1073. GenAppResourcePrivateProperties,
  1074. (LPBYTE) &currentProps,
  1075. FALSE, /*CheckForRequiredProperties*/
  1076. &nameOfPropInError
  1077. );
  1078. if ( status != ERROR_SUCCESS ) {
  1079. (g_LogEvent)(
  1080. ResourceEntry->ResourceHandle,
  1081. LOG_ERROR,
  1082. L"Unable to read the '%1' property. Error: %2!u!.\n",
  1083. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  1084. status );
  1085. goto FnExit;
  1086. }
  1087. //
  1088. // Duplicate the resource parameter block.
  1089. //
  1090. if ( Params == NULL ) {
  1091. pParams = &newProps;
  1092. } else {
  1093. pParams = Params;
  1094. }
  1095. ZeroMemory( pParams, sizeof(GENAPP_PARAMS) );
  1096. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1097. (LPBYTE) &currentProps,
  1098. GenAppResourcePrivateProperties );
  1099. if ( status != ERROR_SUCCESS ) {
  1100. return(status);
  1101. }
  1102. //
  1103. // Parse and validate the properties.
  1104. //
  1105. status = ResUtilVerifyPropertyTable( GenAppResourcePrivateProperties,
  1106. NULL,
  1107. TRUE, // Allow unknowns
  1108. InBuffer,
  1109. InBufferSize,
  1110. (LPBYTE) pParams );
  1111. if ( status == ERROR_SUCCESS ) {
  1112. //
  1113. // Validate the CurrentDirectory
  1114. //
  1115. if ( pParams->CurrentDirectory &&
  1116. !ResUtilIsPathValid( pParams->CurrentDirectory ) ) {
  1117. status = ERROR_INVALID_PARAMETER;
  1118. goto FnExit;
  1119. }
  1120. //
  1121. // If the resource should use the network name as the computer
  1122. // name, make sure there is a dependency on a Network Name
  1123. // resource.
  1124. //
  1125. if ( pParams->UseNetworkName ) {
  1126. hResDependency = GetClusterResourceNetworkName(ResourceEntry->hResource,
  1127. netnameBuffer,
  1128. &netnameBufferSize);
  1129. if ( !hResDependency ) {
  1130. status = ERROR_DEPENDENCY_NOT_FOUND;
  1131. }
  1132. }
  1133. }
  1134. FnExit:
  1135. //
  1136. // Cleanup our parameter block.
  1137. //
  1138. if ( ( (status != ERROR_SUCCESS)
  1139. && (pParams != NULL)
  1140. )
  1141. || ( pParams == &newProps )
  1142. )
  1143. {
  1144. ResUtilFreeParameterBlock( (LPBYTE) pParams,
  1145. (LPBYTE) &currentProps,
  1146. GenAppResourcePrivateProperties );
  1147. }
  1148. ResUtilFreeParameterBlock(
  1149. (LPBYTE) &currentProps,
  1150. NULL,
  1151. GenAppResourcePrivateProperties
  1152. );
  1153. return(status);
  1154. } // GenAppValidatePrivateResProperties
  1155. DWORD
  1156. GenAppSetPrivateResProperties(
  1157. IN OUT PGENAPP_RESOURCE ResourceEntry,
  1158. IN PVOID InBuffer,
  1159. IN DWORD InBufferSize
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1164. for resources of type Generic Application.
  1165. Arguments:
  1166. ResourceEntry - Supplies the resource entry on which to operate.
  1167. InBuffer - Supplies a pointer to a buffer containing input data.
  1168. InBufferSize - Supplies the size, in bytes, of the data pointed
  1169. to by InBuffer.
  1170. Return Value:
  1171. ERROR_SUCCESS - The function completed successfully.
  1172. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1173. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1174. Win32 error code - The function failed.
  1175. --*/
  1176. {
  1177. DWORD status;
  1178. GENAPP_PARAMS params;
  1179. ZeroMemory( &params, sizeof(GENAPP_PARAMS) );
  1180. //
  1181. // Parse and validate the properties.
  1182. //
  1183. status = GenAppValidatePrivateResProperties( ResourceEntry,
  1184. InBuffer,
  1185. InBufferSize,
  1186. &params );
  1187. if ( status != ERROR_SUCCESS ) {
  1188. return(status);
  1189. }
  1190. //
  1191. // Save the parameter values.
  1192. //
  1193. status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1194. GenAppResourcePrivateProperties,
  1195. NULL,
  1196. (LPBYTE) &params,
  1197. InBuffer,
  1198. InBufferSize,
  1199. (LPBYTE) &ResourceEntry->Params );
  1200. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1201. (LPBYTE) &ResourceEntry->Params,
  1202. GenAppResourcePrivateProperties );
  1203. //
  1204. // If the resource is online, return a non-success status.
  1205. //
  1206. if (status == ERROR_SUCCESS) {
  1207. if ( ResourceEntry->Online ) {
  1208. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1209. } else {
  1210. status = ERROR_SUCCESS;
  1211. }
  1212. }
  1213. return status;
  1214. } // GenAppSetPrivateResProperties
  1215. DWORD
  1216. GenAppGetPids(
  1217. IN OUT PGENAPP_RESOURCE ResourceEntry,
  1218. OUT PVOID OutBuffer,
  1219. IN DWORD OutBufferSize,
  1220. OUT LPDWORD BytesReturned
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Get array of PIDs (as DWORDS) to return for load balancing purposes.
  1225. Arguments:
  1226. ResourceEntry - Supplies the resource entry on which to operate.
  1227. OutBuffer - Supplies a pointer to a buffer for output data.
  1228. OutBufferSize - Supplies the size, in bytes, of the buffer pointed
  1229. to by OutBuffer.
  1230. BytesReturned - The number of bytes returned in OutBuffer.
  1231. Return Value:
  1232. ERROR_SUCCESS if successful.
  1233. A Win32 error code on failure.
  1234. --*/
  1235. {
  1236. CLUSPROP_BUFFER_HELPER props;
  1237. props.pb = OutBuffer;
  1238. *BytesReturned = sizeof(*props.pdw);
  1239. if ( OutBufferSize < sizeof(*props.pdw) ) {
  1240. return(ERROR_MORE_DATA);
  1241. }
  1242. *(props.pdw) = ResourceEntry->ProcessId;
  1243. return(ERROR_SUCCESS);
  1244. } // GenAppGetPids
  1245. BOOL
  1246. FindOurWindow(
  1247. HWND WindowHandle,
  1248. LPARAM Resource
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. Find our window handle in the midst of all of this confusion.
  1253. Arguments:
  1254. WindowHandle - a handle to the current window being enumerated.
  1255. Resource - pointer to resource's context block
  1256. Return Value:
  1257. TRUE - if we should continue enumeration.
  1258. FALSE - if we should not continue enumeration.
  1259. --*/
  1260. {
  1261. DWORD windowPid;
  1262. BOOL success;
  1263. PGENAPP_RESOURCE resource = (PGENAPP_RESOURCE)Resource;
  1264. GetWindowThreadProcessId( WindowHandle, &windowPid );
  1265. if ( windowPid == resource->ProcessId ) {
  1266. success = PostMessage(WindowHandle, WM_CLOSE, 0, 0);
  1267. if ( success ) {
  1268. #if DBG
  1269. if ( !resource->SentCloseMessage ) {
  1270. (g_LogEvent)(resource->ResourceHandle,
  1271. LOG_ERROR,
  1272. L"Posting WM_CLOSE message on HWND %2!08X! for process %1!u!\n",
  1273. resource->ProcessId,
  1274. WindowHandle);
  1275. } else {
  1276. (g_LogEvent)(resource->ResourceHandle,
  1277. LOG_ERROR,
  1278. L"Posting WM_CLOSE message on addt'l HWND %2!08X! for process %1!u!\n",
  1279. resource->ProcessId,
  1280. WindowHandle);
  1281. }
  1282. #endif
  1283. resource->SentCloseMessage = TRUE;
  1284. }
  1285. else {
  1286. (g_LogEvent)(resource->ResourceHandle,
  1287. LOG_ERROR,
  1288. L"Posting of WM_CLOSE message to window for process %1!u! failed - status %2!u!\n",
  1289. resource->ProcessId,
  1290. GetLastError());
  1291. }
  1292. }
  1293. //
  1294. // continue to enum since a process can have more than one top level window
  1295. //
  1296. return TRUE;
  1297. } // FindOurWindow
  1298. //***********************************************************
  1299. //
  1300. // Define Function Table
  1301. //
  1302. //***********************************************************
  1303. CLRES_V1_FUNCTION_TABLE( GenAppFunctionTable, // Name
  1304. CLRES_VERSION_V1_00, // Version
  1305. GenApp, // Prefix
  1306. NULL, // Arbitrate
  1307. NULL, // Release
  1308. GenAppResourceControl,// ResControl
  1309. GenAppResourceTypeControl ); // ResTypeControl