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.

1849 lines
44 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. splsvc.c
  6. Abstract:
  7. Resource DLL for Spooler
  8. Author:
  9. Albert Ting (albertt) 17-Sept-1996
  10. Based on resdll\genapp
  11. Revision History:
  12. --*/
  13. #include "precomp.hxx"
  14. #pragma hdrstop
  15. #include "splsvc.hxx"
  16. #include "spooler.hxx"
  17. #include "clusinfo.hxx"
  18. #include "clusrtl.h"
  19. MODULE_DEBUG_INIT( DBG_ERROR|DBG_WARN|DBG_TRACE, DBG_ERROR );
  20. #define MAX_SPOOLER 60
  21. #define MAX_GROUP_NAME_LENGTH 120
  22. #define SPOOLER_TERMINATE // Kill the spooler on terminate if pending offline.
  23. #define SplSvcLogEvent ClusResLogEvent
  24. #define SplSvcSetResourceStatus ClusResSetResourceStatus
  25. #define NET_NAME_RESOURCE_NAME CLUS_RESTYPE_NAME_NETNAME
  26. #define PARAM_NAME__DEFAULTSPOOLDIRECTORY CLUSREG_NAME_PRTSPOOL_DEFAULT_SPOOL_DIR
  27. #define PARAM_NAME__JOBCOMPLETIONTIMEOUT CLUSREG_NAME_PRTSPOOL_TIMEOUT
  28. #define KEY_NAME__DEFAULTSPOOLDIRECTORY L"Printers"
  29. #define KEY_NAME__JOBCOMPLETIONTIMEOUT NULL
  30. #define PARAM_MIN__JOBCOMPLETIONTIMEOUT 0
  31. #define PARAM_MAX__JOBCOMPLETIONTIMEOUT ((DWORD) -1)
  32. #define PARAM_DEFAULT_JOBCOMPLETIONTIMEOUT 160
  33. typedef struct _SPOOLER_PARAMS {
  34. LPWSTR DefaultSpoolDirectory;
  35. DWORD JobCompletionTimeout;
  36. } SPOOLER_PARAMS, *PSPOOLER_PARAMS;
  37. //
  38. // Properties
  39. //
  40. RESUTIL_PROPERTY_ITEM
  41. SplSvcResourcePrivateProperties[] = {
  42. { PARAM_NAME__DEFAULTSPOOLDIRECTORY, KEY_NAME__DEFAULTSPOOLDIRECTORY, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(SPOOLER_PARAMS,DefaultSpoolDirectory) },
  43. { PARAM_NAME__JOBCOMPLETIONTIMEOUT, KEY_NAME__JOBCOMPLETIONTIMEOUT, CLUSPROP_FORMAT_DWORD, PARAM_DEFAULT_JOBCOMPLETIONTIMEOUT, PARAM_MIN__JOBCOMPLETIONTIMEOUT, PARAM_MAX__JOBCOMPLETIONTIMEOUT, 0, FIELD_OFFSET(SPOOLER_PARAMS,JobCompletionTimeout) },
  44. { 0 }
  45. };
  46. //
  47. // Lock to protect the ProcessInfo table
  48. //
  49. CRITICAL_SECTION gProcessLock;
  50. //
  51. // Global count of spooler resource instances.
  52. //
  53. UINT gcSpoolerInfo;
  54. extern CLRES_FUNCTION_TABLE SplSvcFunctionTable;
  55. #define PSPOOLERINFO_FROM_RESID(resid) ((PSPOOLER_INFORMATION)resid)
  56. #define RESID_FROM_SPOOLERINFO(pSpoolerInfo) ((RESID)pSpoolerInfo)
  57. //
  58. // Forward prototypes.
  59. //
  60. #ifdef __cplusplus
  61. extern "C"
  62. #endif
  63. BOOLEAN
  64. WINAPI
  65. SplSvcDllEntryPoint(
  66. IN HINSTANCE DllHandle,
  67. IN DWORD Reason,
  68. IN LPVOID Reserved
  69. );
  70. RESID
  71. WINAPI
  72. SplSvcOpen(
  73. IN LPCWSTR ResourceName,
  74. IN HKEY ResourceKey,
  75. IN RESOURCE_HANDLE ResourceHandle
  76. );
  77. VOID
  78. WINAPI
  79. SplSvcClose(
  80. IN RESID Resid
  81. );
  82. DWORD
  83. WINAPI
  84. SplSvcOnline(
  85. IN RESID Resid,
  86. IN OUT PHANDLE EventHandle
  87. );
  88. DWORD
  89. WINAPI
  90. SplSvcOffline(
  91. IN RESID Resid
  92. );
  93. VOID
  94. WINAPI
  95. SplSvcTerminate(
  96. IN RESID Resource
  97. );
  98. BOOL
  99. WINAPI
  100. SplSvcIsAlive(
  101. IN RESID Resource
  102. );
  103. BOOL
  104. WINAPI
  105. SplSvcLooksAlive(
  106. IN RESID Resource
  107. );
  108. DWORD
  109. SplSvcGetPrivateResProperties(
  110. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  111. OUT PVOID OutBuffer,
  112. IN DWORD OutBufferSize,
  113. OUT LPDWORD BytesReturned
  114. );
  115. DWORD
  116. SplSvcValidatePrivateResProperties(
  117. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  118. IN PVOID InBuffer,
  119. IN DWORD InBufferSize,
  120. OUT PSPOOLER_PARAMS Params
  121. );
  122. DWORD
  123. SplSvcSetPrivateResProperties(
  124. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  125. IN PVOID InBuffer,
  126. IN DWORD InBufferSize
  127. );
  128. PSPOOLER_INFORMATION
  129. pNewSpoolerInfo(
  130. LPCTSTR pszResource,
  131. RESOURCE_HANDLE ResourceHandle,
  132. PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  133. PLOG_EVENT_ROUTINE LogEvent
  134. )
  135. {
  136. PSPOOLER_INFORMATION pSpoolerInfo = NULL;
  137. LPTSTR pszResourceNew = NULL;
  138. pSpoolerInfo = (PSPOOLER_INFORMATION)LocalAlloc(
  139. LPTR,
  140. sizeof( SPOOLER_INFORMATION ));
  141. if( !pSpoolerInfo ){
  142. goto Fail;
  143. }
  144. pszResourceNew = (LPTSTR)LocalAlloc(
  145. LMEM_FIXED,
  146. ( lstrlen( pszResource ) + 1 )
  147. * sizeof( TCHAR ));
  148. if( !pszResourceNew ){
  149. goto Fail;
  150. }
  151. lstrcpy( pszResourceNew, pszResource );
  152. pSpoolerInfo->pfnLogEvent = LogEvent;
  153. pSpoolerInfo->ResourceHandle = ResourceHandle;
  154. pSpoolerInfo->pfnSetResourceStatus = SetResourceStatus;
  155. pSpoolerInfo->pszResource = pszResourceNew;
  156. pSpoolerInfo->pszName = NULL;
  157. pSpoolerInfo->pszAddress = NULL;
  158. return pSpoolerInfo;
  159. Fail:
  160. if( pszResourceNew ){
  161. LocalFree( (HLOCAL)pszResourceNew );
  162. }
  163. if( pSpoolerInfo ){
  164. LocalFree( (HLOCAL)pSpoolerInfo );
  165. }
  166. return NULL;
  167. }
  168. VOID
  169. vDeleteSpoolerInfo(
  170. PSPOOLER_INFORMATION pSpoolerInfo
  171. )
  172. {
  173. if( !pSpoolerInfo ){
  174. return;
  175. }
  176. SPLASSERT( !pSpoolerInfo->cRef );
  177. //
  178. // Shut down everything.
  179. //
  180. if( pSpoolerInfo->pszName ){
  181. LocalFree( (HLOCAL)pSpoolerInfo->pszName );
  182. }
  183. if( pSpoolerInfo->pszAddress ){
  184. LocalFree( (HLOCAL)pSpoolerInfo->pszAddress );
  185. }
  186. if( pSpoolerInfo->pszResource ){
  187. LocalFree( (HLOCAL)pSpoolerInfo->pszResource );
  188. }
  189. LocalFree( (HLOCAL)pSpoolerInfo );
  190. }
  191. BOOL
  192. Init(
  193. VOID
  194. )
  195. {
  196. InitializeCriticalSection( &gProcessLock );
  197. return bSplLibInit();
  198. }
  199. BOOLEAN
  200. WINAPI
  201. SplSvcDllEntryPoint(
  202. IN HINSTANCE DllHandle,
  203. IN DWORD Reason,
  204. IN LPVOID Reserved
  205. )
  206. {
  207. UNREFERENCED_PARAMETER(DllHandle);
  208. UNREFERENCED_PARAMETER(Reserved);
  209. switch( Reason ) {
  210. case DLL_PROCESS_ATTACH:
  211. if( !Init() ){
  212. DBGMSG( DBG_ERROR, ( "DllEntryPoint: failed to init\n" ));
  213. return FALSE;
  214. }
  215. break;
  216. case DLL_PROCESS_DETACH:
  217. break;
  218. default:
  219. break;
  220. }
  221. return TRUE;
  222. }
  223. /********************************************************************
  224. Required exports and function table entries used by clustering.
  225. ********************************************************************/
  226. /********************************************************************
  227. Resource DLL functions.
  228. ********************************************************************/
  229. BOOL
  230. bSplRegCopyTree(
  231. IN HKEY hClusterKey,
  232. IN HKEY hLocalKey
  233. )
  234. /*++
  235. Routine Description:
  236. Recursives copies every key and value from under hLocalKey to hClusterKey
  237. Arguments:
  238. hClusterKey - handle to the cluster registry (destination)
  239. hLocalKey - handle to the local registry (source)
  240. Return Value:
  241. TRUE - success
  242. FALSE - failure
  243. --*/
  244. {
  245. BOOL bStatus = FALSE;
  246. DWORD dwError, dwIndex, cbValueName, cbData, cbKeyName, dwType;
  247. DWORD cbMaxSubKeyLen, cbMaxValueNameLen, cValues, cSubKeys, cbMaxValueLen;
  248. LPBYTE lpValueName = NULL, lpData = NULL, lpKeyName = NULL;
  249. HKEY hLocalSubKey = NULL, hClusterSubKey = NULL;
  250. //
  251. // Retrieve the max buffer sizes required for the copy
  252. //
  253. dwError = RegQueryInfoKey( hLocalKey, NULL, NULL, NULL, &cSubKeys,
  254. &cbMaxSubKeyLen, NULL, &cValues,
  255. &cbMaxValueNameLen, &cbMaxValueLen,
  256. NULL, NULL );
  257. if( dwError ){
  258. SetLastError( dwError );
  259. goto CleanUp;
  260. }
  261. //
  262. // Add for the terminating NULL character
  263. //
  264. ++cbMaxSubKeyLen;
  265. ++cbMaxValueNameLen;
  266. //
  267. // Allocate the buffers
  268. //
  269. lpValueName = (LPBYTE) LocalAlloc( LMEM_FIXED, cbMaxValueNameLen * sizeof(WCHAR) );
  270. lpData = (LPBYTE) LocalAlloc( LMEM_FIXED, cbMaxValueLen );
  271. lpKeyName = (LPBYTE) LocalAlloc( LMEM_FIXED, cbMaxSubKeyLen * sizeof(WCHAR) );
  272. if( !lpValueName || !lpData || !lpKeyName){
  273. goto CleanUp;
  274. }
  275. //
  276. // Copy all the values in the current key
  277. //
  278. for (dwIndex = 0; dwIndex < cValues; ++ dwIndex) {
  279. cbValueName = cbMaxValueNameLen;
  280. cbData = cbMaxValueLen;
  281. //
  282. // Retrieve the value name and the data
  283. //
  284. dwError = RegEnumValue( hLocalKey, dwIndex, (LPWSTR) lpValueName, &cbValueName,
  285. NULL, &dwType, lpData, &cbData );
  286. if( dwError ){
  287. SetLastError( dwError );
  288. goto CleanUp;
  289. }
  290. //
  291. // Set the value in the cluster registry
  292. //
  293. dwError = ClusterRegSetValue( hClusterKey, (LPWSTR) lpValueName, dwType,
  294. lpData, cbData );
  295. if( dwError ){
  296. SetLastError( dwError );
  297. goto CleanUp;
  298. }
  299. }
  300. //
  301. // Recursively copies all the subkeys
  302. //
  303. for (dwIndex = 0; dwIndex < cSubKeys; ++ dwIndex) {
  304. cbKeyName = cbMaxSubKeyLen;
  305. //
  306. // Retrieve the key name
  307. //
  308. dwError = RegEnumKeyEx( hLocalKey, dwIndex, (LPWSTR) lpKeyName, &cbKeyName,
  309. NULL, NULL, NULL, NULL );
  310. if( dwError ){
  311. SetLastError( dwError );
  312. goto CleanUp;
  313. }
  314. //
  315. // Open local subkey
  316. //
  317. if( dwError = RegOpenKeyEx( hLocalKey, (LPWSTR) lpKeyName, 0,
  318. KEY_READ, &hLocalSubKey ) ){
  319. SetLastError( dwError );
  320. goto CleanUp;
  321. }
  322. //
  323. // Create the cluster subkey
  324. //
  325. if(( dwError = ClusterRegOpenKey( hClusterKey, (LPWSTR) lpKeyName,
  326. KEY_READ|KEY_WRITE,
  327. &hClusterSubKey)) == ERROR_FILE_NOT_FOUND )
  328. {
  329. if( dwError = ClusterRegCreateKey( hClusterKey, (LPWSTR) lpKeyName,
  330. 0,KEY_READ|KEY_WRITE,
  331. NULL, &hClusterSubKey, NULL ) )
  332. {
  333. SetLastError( dwError );
  334. goto CleanUp;
  335. }
  336. }
  337. //
  338. // Copy the subkey tree
  339. //
  340. if( !bSplRegCopyTree( hClusterSubKey, hLocalSubKey ) ){
  341. goto CleanUp;
  342. }
  343. //
  344. // Close the registry handle
  345. //
  346. RegCloseKey( hLocalSubKey );
  347. ClusterRegCloseKey( hClusterSubKey );
  348. hLocalSubKey = NULL;
  349. hClusterSubKey = NULL;
  350. }
  351. bStatus = TRUE;
  352. CleanUp:
  353. if( lpValueName ){
  354. LocalFree( lpValueName );
  355. }
  356. if( lpData ){
  357. LocalFree( lpData );
  358. }
  359. if( lpKeyName ){
  360. LocalFree( lpKeyName );
  361. }
  362. if( hLocalSubKey ){
  363. RegCloseKey( hLocalSubKey );
  364. }
  365. if( hClusterSubKey ){
  366. ClusterRegCloseKey( hClusterSubKey );
  367. }
  368. return bStatus;
  369. }
  370. BOOL
  371. bUpdateRegPort(
  372. IN HKEY hClusterKey,
  373. OUT LPBOOL pbRegUpdated
  374. )
  375. /*++
  376. Routine Description:
  377. Moves Port data from the local to the cluster registry
  378. Arguments:
  379. hClusterKey - handle to the cluster registry
  380. pbRegUpdated - flag to indicate if the registry was updated
  381. Return Value:
  382. TRUE - success
  383. FALSE - failure
  384. --*/
  385. {
  386. BOOL bStatus = FALSE;
  387. DWORD dwError, dwType, dwValue, dwSize;
  388. HKEY hLocalLPR = NULL, hClusterLPR = NULL;
  389. WCHAR szLocalLPRKey[] = L"System\\CurrentControlSet\\Control\\Print\\Monitors\\LPR Port";
  390. WCHAR szClusterLPRKey[] = L"Monitors\\LPR Port";
  391. WCHAR szSplVersion[] = L"Spooler Version";
  392. //
  393. // Initialize the bRegUpdate flag
  394. //
  395. *pbRegUpdated = FALSE;
  396. //
  397. // Check if ports have been migrated already
  398. //
  399. dwSize = sizeof(DWORD);
  400. if( dwError = ClusterRegQueryValue( hClusterKey, szSplVersion, &dwType,
  401. (LPBYTE) &dwValue, &dwSize ) ){
  402. if( dwError != ERROR_FILE_NOT_FOUND ){
  403. SetLastError( dwError );
  404. return FALSE;
  405. }
  406. } else {
  407. if( dwValue == 1 ){
  408. return TRUE;
  409. }
  410. }
  411. //
  412. // Open the local LPR Port key, if any
  413. //
  414. if( dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE, szLocalLPRKey, 0,
  415. KEY_READ, &hLocalLPR ) ){
  416. //
  417. // LPR Port key was not found
  418. //
  419. if( dwError == ERROR_FILE_NOT_FOUND ){
  420. bStatus = TRUE;
  421. } else {
  422. SetLastError( dwError );
  423. }
  424. goto CleanUp;
  425. }
  426. //
  427. // Create the LPR Port key on the cluster registry
  428. //
  429. if(( dwError = ClusterRegOpenKey( hClusterKey, szClusterLPRKey,
  430. KEY_READ|KEY_WRITE,
  431. &hClusterLPR ) ) == ERROR_FILE_NOT_FOUND)
  432. {
  433. if( dwError = ClusterRegCreateKey( hClusterKey, szClusterLPRKey,
  434. 0,KEY_READ|KEY_WRITE,
  435. NULL, &hClusterLPR, NULL ) )
  436. {
  437. SetLastError( dwError );
  438. goto CleanUp;
  439. }
  440. }
  441. else if ( dwError )
  442. {
  443. SetLastError( dwError );
  444. goto CleanUp;
  445. }
  446. bStatus = bSplRegCopyTree( hClusterLPR, hLocalLPR );
  447. if( bStatus ){
  448. //
  449. // Create a value in the cluster to avoid repeated copying of the port data
  450. //
  451. dwValue = 1;
  452. dwSize = sizeof(dwValue);
  453. ClusterRegSetValue( hClusterKey, szSplVersion, REG_DWORD,
  454. (LPBYTE) &dwValue, dwSize );
  455. *pbRegUpdated = TRUE;
  456. }
  457. CleanUp:
  458. if( hLocalLPR ){
  459. RegCloseKey( hLocalLPR );
  460. }
  461. if( hClusterLPR ){
  462. ClusterRegCloseKey( hClusterLPR );
  463. }
  464. return bStatus;
  465. }
  466. RESID
  467. WINAPI
  468. SplSvcOpen(
  469. IN LPCWSTR ResourceName,
  470. IN HKEY ResourceKey,
  471. IN RESOURCE_HANDLE ResourceHandle
  472. )
  473. /*++
  474. Routine Description:
  475. Opens the spooler resource. This will start the spooler
  476. service if necessary.
  477. Arguments:
  478. ResourceName - supplies the resource name
  479. ResourceKey - supplies a handle to the resource's cluster registry key
  480. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  481. is called.
  482. Return Value:
  483. RESID of created resource
  484. Zero on failure
  485. --*/
  486. {
  487. PSPOOLER_INFORMATION pSpoolerInfo = NULL;
  488. BOOL bTooMany = FALSE, bRegUpdated;
  489. HKEY parametersKey = NULL;
  490. DWORD status;
  491. HCLUSTER hCluster;
  492. UNREFERENCED_PARAMETER(ResourceKey);
  493. vEnterSem();
  494. DBGMSG( DBG_WARN, ( ">>> Open: called\n" ));
  495. if( gcSpoolerInfo == MAX_SPOOLER ){
  496. bTooMany = TRUE;
  497. status = ERROR_ALLOTTED_SPACE_EXCEEDED;
  498. goto FailLeave;
  499. }
  500. //
  501. // Open the Parameters key for this resource.
  502. //
  503. status = ClusterRegOpenKey( ResourceKey,
  504. CLUSREG_KEYNAME_PARAMETERS,
  505. KEY_READ,
  506. &parametersKey );
  507. if ( status != ERROR_SUCCESS || parametersKey == NULL ) {
  508. (SplSvcLogEvent)(
  509. ResourceHandle,
  510. LOG_ERROR,
  511. L"Unable to open parameters key for resource '%1!ws!'. Error: %2!u!.\n",
  512. ResourceName,
  513. status );
  514. goto FailLeave;
  515. }
  516. //
  517. // Move the ports data from local to cluster registry
  518. //
  519. if( !bUpdateRegPort( parametersKey, &bRegUpdated ) ){
  520. (SplSvcLogEvent)(
  521. ResourceHandle,
  522. LOG_WARNING,
  523. L"LPR Port settings could not be moved to cluster registry.\n" );
  524. DBGMSG( DBG_WARN, ( "Port settings could not be moved to cluster registry" ));
  525. }
  526. //
  527. // Find a free index in the process info table for this new app.
  528. //
  529. pSpoolerInfo = pNewSpoolerInfo( ResourceName,
  530. ResourceHandle,
  531. SplSvcSetResourceStatus,
  532. SplSvcLogEvent );
  533. if( !pSpoolerInfo ){
  534. status = ERROR_ALLOTTED_SPACE_EXCEEDED;
  535. goto FailLeave;
  536. }
  537. //
  538. // Save the name of the resource.
  539. //
  540. hCluster = OpenCluster( NULL );
  541. if ( !hCluster ) {
  542. status = GetLastError();
  543. goto FailLeave;
  544. }
  545. pSpoolerInfo->hResource = OpenClusterResource( hCluster,
  546. ResourceName );
  547. status = GetLastError();
  548. CloseCluster( hCluster );
  549. if ( pSpoolerInfo->hResource == NULL ) {
  550. goto FailLeave;
  551. }
  552. pSpoolerInfo->eState = kOpen;
  553. pSpoolerInfo->ParametersKey = parametersKey;
  554. vAddRef( pSpoolerInfo );
  555. ++gcSpoolerInfo;
  556. vLeaveSem();
  557. DBGMSG( DBG_WARN,
  558. ( "Open: return %x\n", RESID_FROM_SPOOLERINFO( pSpoolerInfo )));
  559. return RESID_FROM_SPOOLERINFO(pSpoolerInfo);
  560. FailLeave:
  561. vLeaveSem();
  562. if( bTooMany ){
  563. (SplSvcLogEvent)(
  564. ResourceHandle,
  565. LOG_ERROR,
  566. L"Too many spoolers.\n" );
  567. DBGMSG( DBG_WARN, ( "SplSvcOpen: Too many spoolers.\n" ));
  568. } else {
  569. (SplSvcLogEvent)(
  570. ResourceHandle,
  571. LOG_ERROR,
  572. L"Failed to create new spooler. Error: %1!u!.\n",
  573. GetLastError() );
  574. DBGMSG( DBG_ERROR, ( "SplSvcOpen: Unable to create spooler %d\n",
  575. GetLastError()));
  576. }
  577. if ( parametersKey != NULL ) {
  578. ClusterRegCloseKey( parametersKey );
  579. }
  580. if ( pSpoolerInfo && (pSpoolerInfo->hResource != NULL) ) {
  581. CloseClusterResource( pSpoolerInfo->hResource );
  582. }
  583. vDeleteSpoolerInfo( pSpoolerInfo );
  584. SetLastError( status );
  585. return (RESID)0;
  586. }
  587. VOID
  588. WINAPI
  589. SplSvcClose(
  590. IN RESID Resid
  591. )
  592. /*++
  593. Routine Description:
  594. Close down the open spooler resource ID. Note that we'll leave
  595. the spooler running, since it always should be running.
  596. Arguments:
  597. Resource - supplies resource id to be closed
  598. Return Value:
  599. --*/
  600. {
  601. PSPOOLER_INFORMATION pSpoolerInfo;
  602. DBGMSG( DBG_WARN, ( ">>> Close: called %x\n", Resid ));
  603. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  604. //
  605. // If resource is still online, terminate it.
  606. //
  607. if( pSpoolerInfo->eState == kOnline ){
  608. SplSvcTerminate( Resid );
  609. }
  610. vEnterSem();
  611. --gcSpoolerInfo;
  612. pSpoolerInfo->eState = kClose;
  613. vLeaveSem();
  614. if (pSpoolerInfo->hResource != NULL ) {
  615. CloseClusterResource( pSpoolerInfo->hResource );
  616. }
  617. if (pSpoolerInfo->ParametersKey != NULL ) {
  618. ClusterRegCloseKey( pSpoolerInfo->ParametersKey );
  619. }
  620. vDecRef( pSpoolerInfo );
  621. }
  622. DWORD
  623. WINAPI
  624. SplSvcOnline(
  625. IN RESID Resid,
  626. IN OUT PHANDLE EventHandle
  627. )
  628. /*++
  629. Routine Description:
  630. Online the spooler resource.
  631. This always completes asynchronously with ERROR_IO_PENDING.
  632. Arguments:
  633. Resource - supplies resource id to be brought online
  634. EventHandle - supplies a pointer to a handle to signal on error.
  635. Return Value:
  636. In success case, this returns ERROR_IO_PENDING, else win32
  637. error code.
  638. --*/
  639. {
  640. BOOL bStatus;
  641. DWORD Status = ERROR_IO_PENDING;
  642. PSPOOLER_INFORMATION pSpoolerInfo;
  643. UNREFERENCED_PARAMETER( EventHandle );
  644. DBGMSG( DBG_WARN, ( ">>> Online: called %x\n", Resid ));
  645. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  646. //
  647. // Rpc to the spooler to initiate Online.
  648. //
  649. bStatus = SpoolerOnline( pSpoolerInfo );
  650. if( !bStatus ){
  651. Status = GetLastError();
  652. SPLASSERT( Status );
  653. (pSpoolerInfo->pfnLogEvent)(
  654. pSpoolerInfo->ResourceHandle,
  655. LOG_ERROR,
  656. L"Unable to online spooler resource. Error: %1!u!.\n",
  657. Status );
  658. DBGMSG( DBG_ERROR, ( "SplSvcOnline: Unable to online spooler\n" ));
  659. }
  660. return Status;
  661. }
  662. DWORD
  663. WINAPI
  664. SplSvcOffline(
  665. IN RESID Resid
  666. )
  667. /*++
  668. Routine Description:
  669. Offline the spooler resource.
  670. Arguments:
  671. Resid - supplies the resource to be taken offline
  672. Return Value:
  673. In success case, this returns ERROR_IO_PENDING, else win32
  674. error code.
  675. --*/
  676. {
  677. PSPOOLER_INFORMATION pSpoolerInfo;
  678. DBGMSG( DBG_WARN, ( ">>> Offline: called %x\n", Resid ));
  679. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  680. vEnterSem();
  681. pSpoolerInfo->ClusterResourceState = ClusterResourceOffline;
  682. vLeaveSem();
  683. return(SpoolerOffline(pSpoolerInfo));
  684. }
  685. VOID
  686. WINAPI
  687. SplSvcTerminate(
  688. IN RESID Resid
  689. )
  690. /*++
  691. Routine Description:
  692. Terminate and restart the spooler--no waiting.
  693. Arguments:
  694. Resid - supplies resource id to be terminated
  695. Return Value:
  696. --*/
  697. {
  698. PSPOOLER_INFORMATION pSpoolerInfo;
  699. DBGMSG( DBG_WARN, ( ">>> Terminate: called %x\n", Resid ));
  700. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  701. vEnterSem();
  702. pSpoolerInfo->ClusterResourceState = ClusterResourceFailed;
  703. vLeaveSem();
  704. SpoolerTerminate(pSpoolerInfo);
  705. return;
  706. }
  707. BOOL
  708. WINAPI
  709. SplSvcIsAlive(
  710. IN RESID Resid
  711. )
  712. /*++
  713. Routine Description:
  714. IsAlive routine for Generice Applications resource.
  715. Arguments:
  716. Resource - supplies the resource id to be polled.
  717. Return Value:
  718. TRUE - Resource is alive and well
  719. FALSE - Resource is toast.
  720. --*/
  721. {
  722. PSPOOLER_INFORMATION pSpoolerInfo;
  723. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  724. return SpoolerIsAlive( pSpoolerInfo );
  725. }
  726. BOOL
  727. WINAPI
  728. SplSvcLooksAlive(
  729. IN RESID Resid
  730. )
  731. /*++
  732. Routine Description:
  733. LooksAlive routine for Generic Applications resource.
  734. Arguments:
  735. Resource - supplies the resource id to be polled.
  736. Return Value:
  737. TRUE - Resource looks like it is alive and well
  738. FALSE - Resource looks like it is toast.
  739. --*/
  740. {
  741. PSPOOLER_INFORMATION pSpoolerInfo;
  742. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( Resid );
  743. return SpoolerLooksAlive( pSpoolerInfo );
  744. }
  745. DWORD
  746. SplSvcGetRequiredDependencies(
  747. OUT PVOID OutBuffer,
  748. IN DWORD OutBufferSize,
  749. OUT LPDWORD BytesReturned
  750. )
  751. /*++
  752. Routine Description:
  753. Processes the CLCTL_GET_REQUIRED_DEPENDENCIES control function
  754. for resources of type Print Spooler.
  755. Arguments:
  756. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  757. OutBufferSize - Supplies the size, in bytes, of the available space
  758. pointed to by OutBuffer.
  759. BytesReturned - Returns the number of bytes of OutBuffer actually
  760. filled in by the resource. If OutBuffer is too small, BytesReturned
  761. contains the total number of bytes for the operation to succeed.
  762. Return Value:
  763. ERROR_SUCCESS - The function completed successfully.
  764. ERROR_MORE_DATA - The output buffer is too small to return the data.
  765. BytesReturned contains the required size.
  766. Win32 error code - The function failed.
  767. --*/
  768. {
  769. typedef struct DEP_DATA {
  770. CLUSPROP_RESOURCE_CLASS storageEntry;
  771. CLUSPROP_SZ_DECLARE( netnameEntry, sizeof(NET_NAME_RESOURCE_NAME) / sizeof(WCHAR) );
  772. CLUSPROP_SYNTAX endmark;
  773. } DEP_DATA, *PDEP_DATA;
  774. PDEP_DATA pdepdata = (PDEP_DATA)OutBuffer;
  775. DWORD status;
  776. *BytesReturned = sizeof(DEP_DATA);
  777. if ( OutBufferSize < sizeof(DEP_DATA) ) {
  778. if ( OutBuffer == NULL ) {
  779. status = ERROR_SUCCESS;
  780. } else {
  781. status = ERROR_MORE_DATA;
  782. }
  783. } else {
  784. ZeroMemory( pdepdata, sizeof(DEP_DATA) );
  785. pdepdata->storageEntry.Syntax.dw = CLUSPROP_SYNTAX_RESCLASS;
  786. pdepdata->storageEntry.cbLength = sizeof(DWORD);
  787. pdepdata->storageEntry.rc = CLUS_RESCLASS_STORAGE;
  788. pdepdata->netnameEntry.Syntax.dw = CLUSPROP_SYNTAX_NAME;
  789. pdepdata->netnameEntry.cbLength = sizeof(NET_NAME_RESOURCE_NAME);
  790. lstrcpyW( pdepdata->netnameEntry.sz, NET_NAME_RESOURCE_NAME );
  791. pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
  792. status = ERROR_SUCCESS;
  793. }
  794. return status;
  795. } // SplSvcGetRequiredDependencies
  796. DWORD
  797. SplSvcResourceControl(
  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 Print Spooler 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. PSPOOLER_INFORMATION pSpoolerInfo;
  833. DWORD required;
  834. LPWSTR pszResourceNew;
  835. pSpoolerInfo = PSPOOLERINFO_FROM_RESID( ResourceId );
  836. switch ( ControlCode ) {
  837. case CLUSCTL_RESOURCE_UNKNOWN:
  838. *BytesReturned = 0;
  839. status = ERROR_SUCCESS;
  840. break;
  841. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  842. status = ResUtilGetPropertyFormats( SplSvcResourcePrivateProperties,
  843. OutBuffer,
  844. OutBufferSize,
  845. BytesReturned,
  846. &required );
  847. if ( status == ERROR_MORE_DATA ) {
  848. *BytesReturned = required;
  849. }
  850. break;
  851. case CLUSCTL_RESOURCE_SET_NAME:
  852. pszResourceNew = (LPWSTR)LocalAlloc(
  853. LMEM_FIXED,
  854. ( lstrlenW( (LPWSTR)InBuffer ) + 1 )
  855. * sizeof( WCHAR ));
  856. if ( pszResourceNew ) {
  857. LocalFree( (HLOCAL)pSpoolerInfo->pszResource );
  858. lstrcpyW( pszResourceNew, (LPWSTR)InBuffer );
  859. pSpoolerInfo->pszResource = (LPTSTR)pszResourceNew;
  860. status = ERROR_SUCCESS;
  861. } else {
  862. status = GetLastError();
  863. }
  864. break;
  865. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  866. status = SplSvcGetRequiredDependencies( OutBuffer,
  867. OutBufferSize,
  868. BytesReturned
  869. );
  870. break;
  871. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  872. status = ResUtilEnumProperties( SplSvcResourcePrivateProperties,
  873. (LPWSTR) OutBuffer,
  874. OutBufferSize,
  875. BytesReturned,
  876. &required );
  877. if ( status == ERROR_MORE_DATA ) {
  878. *BytesReturned = required;
  879. }
  880. break;
  881. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  882. status = SplSvcGetPrivateResProperties( pSpoolerInfo,
  883. OutBuffer,
  884. OutBufferSize,
  885. BytesReturned );
  886. break;
  887. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  888. status = SplSvcValidatePrivateResProperties( pSpoolerInfo,
  889. InBuffer,
  890. InBufferSize,
  891. NULL );
  892. break;
  893. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  894. status = SplSvcSetPrivateResProperties( pSpoolerInfo,
  895. InBuffer,
  896. InBufferSize );
  897. break;
  898. case CLUSCTL_RESOURCE_CLUSTER_VERSION_CHANGED:
  899. {
  900. LPWSTR pszResourceGuid = NULL;
  901. //
  902. // Retreive the guid of the spooler resource
  903. //
  904. if ((status = GetIDFromName(pSpoolerInfo->hResource,
  905. &pszResourceGuid)) == ERROR_SUCCESS)
  906. {
  907. status = SpoolerWriteClusterUpgradedKey(pszResourceGuid);
  908. LocalFree(pszResourceGuid);
  909. }
  910. }
  911. break;
  912. case CLUSCTL_RESOURCE_DELETE:
  913. SpoolerCleanDriverDirectory(pSpoolerInfo->ParametersKey);
  914. //
  915. // Let the res mon do the rest of the job for us
  916. //
  917. status = ERROR_INVALID_FUNCTION;
  918. break;
  919. default:
  920. status = ERROR_INVALID_FUNCTION;
  921. break;
  922. }
  923. return(status);
  924. } // SplSvcResourceControl
  925. DWORD
  926. SplSvcResourceTypeControl(
  927. IN LPCWSTR ResourceTypeName,
  928. IN DWORD ControlCode,
  929. IN PVOID InBuffer,
  930. IN DWORD InBufferSize,
  931. OUT PVOID OutBuffer,
  932. IN DWORD OutBufferSize,
  933. OUT LPDWORD BytesReturned
  934. )
  935. /*++
  936. Routine Description:
  937. ResourceTypeControl routine for Print Spooler resources.
  938. Perform the control request specified by ControlCode.
  939. Arguments:
  940. ResourceTypeName - Supplies the name of the resource type.
  941. ControlCode - Supplies the control code that defines the action
  942. to be performed.
  943. InBuffer - Supplies a pointer to a buffer containing input data.
  944. InBufferSize - Supplies the size, in bytes, of the data pointed
  945. to by InBuffer.
  946. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  947. OutBufferSize - Supplies the size, in bytes, of the available space
  948. pointed to by OutBuffer.
  949. BytesReturned - Returns the number of bytes of OutBuffer actually
  950. filled in by the resource. If OutBuffer is too small, BytesReturned
  951. contains the total number of bytes for the operation to succeed.
  952. Return Value:
  953. ERROR_SUCCESS - The function completed successfully.
  954. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  955. In some cases, this allows the cluster software to perform the work.
  956. Win32 error code - The function failed.
  957. --*/
  958. {
  959. DWORD status;
  960. DWORD required;
  961. switch ( ControlCode ) {
  962. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  963. *BytesReturned = 0;
  964. status = ERROR_SUCCESS;
  965. break;
  966. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  967. status = ResUtilGetPropertyFormats( SplSvcResourcePrivateProperties,
  968. OutBuffer,
  969. OutBufferSize,
  970. BytesReturned,
  971. &required );
  972. if ( status == ERROR_MORE_DATA ) {
  973. *BytesReturned = required;
  974. }
  975. break;
  976. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  977. status = SplSvcGetRequiredDependencies( OutBuffer,
  978. OutBufferSize,
  979. BytesReturned
  980. );
  981. break;
  982. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  983. status = ResUtilEnumProperties( SplSvcResourcePrivateProperties,
  984. (LPWSTR) OutBuffer,
  985. OutBufferSize,
  986. BytesReturned,
  987. &required );
  988. if ( status == ERROR_MORE_DATA ) {
  989. *BytesReturned = required;
  990. }
  991. break;
  992. default:
  993. status = ERROR_INVALID_FUNCTION;
  994. break;
  995. }
  996. return(status);
  997. } // SplSvcResourceTypeControl
  998. DWORD
  999. SplSvcGetPrivateResProperties(
  1000. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  1001. OUT PVOID OutBuffer,
  1002. IN DWORD OutBufferSize,
  1003. OUT LPDWORD BytesReturned
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control
  1008. function for resources of type Print Spooler.
  1009. Arguments:
  1010. ResourceEntry - Supplies the resource entry on which to operate.
  1011. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1012. OutBufferSize - Supplies the size, in bytes, of the available space
  1013. pointed to by OutBuffer.
  1014. BytesReturned - Returns the number of bytes of OutBuffer actually
  1015. filled in by the resource. If OutBuffer is too small, BytesReturned
  1016. contains the total number of bytes for the operation to succeed.
  1017. Return Value:
  1018. ERROR_SUCCESS - The function completed successfully.
  1019. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1020. Win32 error code - The function failed.
  1021. --*/
  1022. {
  1023. DWORD status;
  1024. DWORD required;
  1025. *BytesReturned = 0;
  1026. //
  1027. // Clear the output buffer
  1028. //
  1029. ZeroMemory( OutBuffer, OutBufferSize );
  1030. //
  1031. // Get the common properties.
  1032. //
  1033. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1034. SplSvcResourcePrivateProperties,
  1035. OutBuffer,
  1036. OutBufferSize,
  1037. BytesReturned,
  1038. &required );
  1039. if ( *BytesReturned == 0 ) {
  1040. *BytesReturned = required;
  1041. }
  1042. return(status);
  1043. } // SplSvcGetPrivateResProperties
  1044. DWORD
  1045. SplSvcValidateUniqueProperties(
  1046. IN HRESOURCE hSelf,
  1047. IN HRESOURCE hResource,
  1048. IN PVOID GroupName
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Callback function to validate that a resources properties are unique.
  1053. For the SplSvc resource we must ensure that only one print spooler
  1054. resource exists in a group.
  1055. We will never be called for the resource we are creating, only for
  1056. other resources of the same type.
  1057. Arguments:
  1058. hSelf - A handle to the original resource.
  1059. hResource - A handle to a resource of the same Type. Check against this
  1060. to make sure the new properties do not conflict.
  1061. lpszGroupName - The name of the Group the creating resource is in.
  1062. Return Value:
  1063. ERROR_SUCCESS - The function completed successfully, only one print
  1064. spooler in the given group.
  1065. ERROR_OBJECT_ALREADY_EXISTS - The name is not unique (i.e., already have
  1066. a print spooler in that group).
  1067. A Win32 error code on other failure.
  1068. --*/
  1069. {
  1070. WCHAR groupName[MAX_GROUP_NAME_LENGTH + 1];
  1071. DWORD groupNameSize = MAX_GROUP_NAME_LENGTH * sizeof(WCHAR);
  1072. CLUSTER_RESOURCE_STATE resourceState;
  1073. LPWSTR lpszGroupName = (LPWSTR)GroupName;
  1074. UNREFERENCED_PARAMETER(hSelf);
  1075. groupName[0] = L'\0';
  1076. resourceState = GetClusterResourceState( hResource,
  1077. NULL,
  1078. 0,
  1079. groupName,
  1080. &groupNameSize );
  1081. if ( !*groupName ) {
  1082. return(GetLastError());
  1083. }
  1084. if ( lstrcmpiW( lpszGroupName, groupName ) == 0 ) {
  1085. return(ERROR_OBJECT_ALREADY_EXISTS);
  1086. }
  1087. return( ERROR_SUCCESS );
  1088. } // SplSvcValidateUniqueProperties
  1089. DWORD
  1090. SplSvcValidatePrivateResProperties(
  1091. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  1092. IN PVOID InBuffer,
  1093. IN DWORD InBufferSize,
  1094. OUT PSPOOLER_PARAMS Params
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1099. function for resources of type Print Spooler.
  1100. Arguments:
  1101. ResourceEntry - Supplies the resource entry on which to operate.
  1102. InBuffer - Supplies a pointer to a buffer containing input data.
  1103. InBufferSize - Supplies the size, in bytes, of the data pointed
  1104. to by InBuffer.
  1105. Params - Supplies the parameter block to fill in.
  1106. Return Value:
  1107. ERROR_SUCCESS - The function completed successfully.
  1108. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1109. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1110. Win32 error code - The function failed.
  1111. --*/
  1112. {
  1113. DWORD status;
  1114. SPOOLER_PARAMS currentProps;
  1115. SPOOLER_PARAMS newProps;
  1116. PSPOOLER_PARAMS pParams = NULL;
  1117. WCHAR groupName[MAX_GROUP_NAME_LENGTH + 1];
  1118. DWORD groupNameSize = MAX_GROUP_NAME_LENGTH * sizeof(WCHAR);
  1119. CLUSTER_RESOURCE_STATE resourceState;
  1120. LPWSTR nameOfPropInError;
  1121. //
  1122. // Check if there is input data.
  1123. //
  1124. if ( (InBuffer == NULL) ||
  1125. (InBufferSize < sizeof(DWORD)) ) {
  1126. return(ERROR_INVALID_DATA);
  1127. }
  1128. //
  1129. // Capture the current set of private properties from the registry.
  1130. //
  1131. ZeroMemory( &currentProps, sizeof(currentProps) );
  1132. status = ResUtilGetPropertiesToParameterBlock(
  1133. ResourceEntry->ParametersKey,
  1134. SplSvcResourcePrivateProperties,
  1135. (LPBYTE) &currentProps,
  1136. FALSE, /*CheckForRequiredProperties*/
  1137. &nameOfPropInError
  1138. );
  1139. if ( status != ERROR_SUCCESS ) {
  1140. (SplSvcLogEvent)(
  1141. ResourceEntry->ResourceHandle,
  1142. LOG_ERROR,
  1143. L"Unable to read the '%1' property. Error: %2!u!.\n",
  1144. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  1145. status );
  1146. goto FnExit;
  1147. }
  1148. //
  1149. // Duplicate the resource parameter block.
  1150. //
  1151. if ( Params == NULL ) {
  1152. pParams = &newProps;
  1153. } else {
  1154. pParams = Params;
  1155. }
  1156. ZeroMemory( pParams, sizeof(SPOOLER_PARAMS) );
  1157. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1158. (LPBYTE) &currentProps,
  1159. SplSvcResourcePrivateProperties );
  1160. if ( status != ERROR_SUCCESS ) {
  1161. return(status);
  1162. }
  1163. //
  1164. // Parse and validate the properties.
  1165. //
  1166. status = ResUtilVerifyPropertyTable( SplSvcResourcePrivateProperties,
  1167. NULL,
  1168. TRUE, // Allow unknowns
  1169. InBuffer,
  1170. InBufferSize,
  1171. (LPBYTE) pParams );
  1172. if ( status == ERROR_SUCCESS ) {
  1173. //
  1174. // Validate the Default Spool Directory
  1175. //
  1176. if ( pParams->DefaultSpoolDirectory &&
  1177. !ResUtilIsPathValid( pParams->DefaultSpoolDirectory ) ) {
  1178. status = ERROR_INVALID_PARAMETER;
  1179. goto FnExit;
  1180. }
  1181. //
  1182. // Make sure there is only one print spooler in this group.
  1183. //
  1184. resourceState = GetClusterResourceState( ResourceEntry->hResource,
  1185. NULL,
  1186. 0,
  1187. groupName,
  1188. &groupNameSize );
  1189. if ( !*groupName ) {
  1190. status = GetLastError();
  1191. goto FnExit;
  1192. }
  1193. status = ResUtilEnumResources(ResourceEntry->hResource,
  1194. CLUS_RESTYPE_NAME_PRTSPLR,
  1195. SplSvcValidateUniqueProperties,
  1196. (PVOID)groupName);
  1197. if (status != ERROR_SUCCESS) {
  1198. goto FnExit;
  1199. }
  1200. }
  1201. FnExit:
  1202. //
  1203. // Cleanup our parameter block.
  1204. //
  1205. if ( ( (status != ERROR_SUCCESS)
  1206. && (pParams != NULL) )
  1207. || ( pParams == &newProps )
  1208. ) {
  1209. ResUtilFreeParameterBlock( (LPBYTE) pParams,
  1210. (LPBYTE) &currentProps,
  1211. SplSvcResourcePrivateProperties );
  1212. }
  1213. ResUtilFreeParameterBlock(
  1214. (LPBYTE) &currentProps,
  1215. NULL,
  1216. SplSvcResourcePrivateProperties
  1217. );
  1218. return(status);
  1219. } // SplSvcValidatePrivateResProperties
  1220. DWORD
  1221. SplSvcSetPrivateResProperties(
  1222. IN OUT PSPOOLER_INFORMATION ResourceEntry,
  1223. IN PVOID InBuffer,
  1224. IN DWORD InBufferSize
  1225. )
  1226. /*++
  1227. Routine Description:
  1228. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1229. for resources of type Print Spooler.
  1230. Arguments:
  1231. ResourceEntry - Supplies the resource entry on which to operate.
  1232. InBuffer - Supplies a pointer to a buffer containing input data.
  1233. InBufferSize - Supplies the size, in bytes, of the data pointed
  1234. to by InBuffer.
  1235. Return Value:
  1236. ERROR_SUCCESS - The function completed successfully.
  1237. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1238. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1239. Win32 error code - The function failed.
  1240. --*/
  1241. {
  1242. DWORD status;
  1243. // SPOOLER_PARAMS params;
  1244. //
  1245. // Parse the properties so they can be validated together.
  1246. // This routine does individual property validation.
  1247. //
  1248. status = SplSvcValidatePrivateResProperties( ResourceEntry,
  1249. InBuffer,
  1250. InBufferSize,
  1251. NULL /*&params*/ );
  1252. if ( status != ERROR_SUCCESS ) {
  1253. return(status);
  1254. }
  1255. //
  1256. // Save the parameter values.
  1257. //
  1258. status = ResUtilSetPropertyTable( ResourceEntry->ParametersKey,
  1259. SplSvcResourcePrivateProperties,
  1260. NULL,
  1261. TRUE, // Allow unknowns
  1262. InBuffer,
  1263. InBufferSize,
  1264. NULL );
  1265. // status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1266. // SplSvcResourcePrivateProperties,
  1267. // NULL,
  1268. // (LPBYTE) &params,
  1269. // InBuffer,
  1270. // InBufferSize,
  1271. // (LPBYTE) &ResourceEntry->Params );
  1272. // ResUtilFreeParameterBlock( (LPBYTE) &params,
  1273. // (LPBYTE) &ResourceEntry->Params,
  1274. // SplSvcResourcePrivateProperties );
  1275. //
  1276. // If the resource is online, return a non-success status.
  1277. //
  1278. if (status == ERROR_SUCCESS) {
  1279. if ( (ResourceEntry->eState == kOnline) ||
  1280. (ResourceEntry->eState == kOnlinePending) ) {
  1281. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1282. } else {
  1283. status = ERROR_SUCCESS;
  1284. }
  1285. }
  1286. return(status);
  1287. } // SplSvcSetPrivateResProperties
  1288. /********************************************************************
  1289. Utility functions
  1290. ********************************************************************/
  1291. VOID
  1292. vEnterSem(
  1293. VOID
  1294. )
  1295. {
  1296. EnterCriticalSection( &gProcessLock );
  1297. }
  1298. VOID
  1299. vLeaveSem(
  1300. VOID
  1301. )
  1302. {
  1303. LeaveCriticalSection( &gProcessLock );
  1304. }
  1305. VOID
  1306. vAddRef(
  1307. PSPOOLER_INFORMATION pSpoolerInfo
  1308. )
  1309. {
  1310. vEnterSem();
  1311. ++pSpoolerInfo->cRef;
  1312. vLeaveSem();
  1313. }
  1314. VOID
  1315. vDecRef(
  1316. PSPOOLER_INFORMATION pSpoolerInfo
  1317. )
  1318. {
  1319. UINT uRef;
  1320. SPLASSERT( pSpoolerInfo->cRef );
  1321. vEnterSem();
  1322. uRef = --pSpoolerInfo->cRef;
  1323. vLeaveSem();
  1324. if( !uRef ){
  1325. vDeleteSpoolerInfo( pSpoolerInfo );
  1326. }
  1327. }
  1328. //***********************************************************
  1329. //
  1330. // Define Function Table
  1331. //
  1332. //***********************************************************
  1333. CLRES_V1_FUNCTION_TABLE( SplSvcFunctionTable,
  1334. CLRES_VERSION_V1_00,
  1335. SplSvc,
  1336. NULL,
  1337. NULL,
  1338. SplSvcResourceControl,
  1339. SplSvcResourceTypeControl );