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.

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