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.

1018 lines
21 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. Change.c
  6. Abstract:
  7. Handles the wait for printer change new code.
  8. FindFirstPrinterChangeNotification
  9. FindNextPrinterChangeNotification
  10. FindClosePrinterChangeNotification
  11. Author:
  12. Albert Ting (AlbertT) 20-Jan-94
  13. Environment:
  14. User Mode -Win32
  15. Revision History:
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. #include "client.h"
  20. #include <change.h>
  21. #include <ntfytab.h>
  22. //
  23. // Globals
  24. //
  25. PNOTIFY pNotifyHead;
  26. extern DWORD ClientHandleCount;
  27. INT
  28. UnicodeToAnsiString(
  29. LPWSTR pUnicode,
  30. LPSTR pAnsi,
  31. DWORD StringLength);
  32. VOID
  33. CopyAnsiDevModeFromUnicodeDevMode(
  34. LPDEVMODEA pANSIDevMode,
  35. LPDEVMODEW pUnicodeDevMode);
  36. //
  37. // Prototypes:
  38. //
  39. PNOTIFY
  40. WPCWaitAdd(
  41. PSPOOL pSpool);
  42. VOID
  43. WPCWaitDelete(
  44. PNOTIFY pNotify);
  45. DWORD
  46. WPCSimulateThreadProc(PVOID pvParm);
  47. HANDLE
  48. FindFirstPrinterChangeNotificationWorker(
  49. HANDLE hPrinter,
  50. DWORD fdwFilter,
  51. DWORD fdwOptions,
  52. PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions
  53. )
  54. /*++
  55. Routine Description:
  56. The FindFirstChangeNotification function creates a change notification
  57. handle and sets up initial change notification filter conditions. A
  58. wait on a notification handle succeeds when a change matching
  59. the filter conditions occurs in the specified directory or subtree.
  60. Arguments:
  61. hPrinter - Handle to a printer the user wishes to watch.
  62. fdwFlags - Specifies the filter conditions that satisfy a change
  63. notification wait. This parameter can be one or more of the
  64. following values:
  65. Value Meaning
  66. PRINTER_CHANGE_PRINTER Notify changes to a printer.
  67. PRINTER_CHANGE_JOB Notify changes to a job.
  68. PRINTER_CHANGE_FORM Notify changes to a form.
  69. PRINTER_CHANGE_PORT Notify changes to a port.
  70. PRINTER_CHANGE_PRINT_PROCESSOR Notify changes to a print processor.
  71. PRINTER_CHANGE_PRINTER_DRIVER Notify changes to a printer driver.
  72. fdwOptions - Specifies options to FFPCN.
  73. PRINTER_NOTIFY_OPTION_SIM_FFPCN Trying to simulate a FFPCN using a WPC
  74. PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE Simulation of FFPCN active
  75. PRINTER_NOTIFY_OPTION_SIM_FFPCN_CLOSE Waiting thread must close pSpool
  76. PRINTER_NOTIFY_OPTION_SIM_WPC Trying to simulate a WPC using a FFPCN
  77. Return Value:
  78. Not -1 - Returns a find first handle
  79. that can be used in a subsequent call to FindNextFile or FindClose.
  80. -1 - The operation failed. Extended error status is available
  81. using GetLastError.
  82. --*/
  83. {
  84. PSPOOL pSpool = (PSPOOL)hPrinter;
  85. DWORD dwError;
  86. PNOTIFY pNotify;
  87. HANDLE hEvent = INVALID_HANDLE_VALUE;
  88. //
  89. // Nothing to watch.
  90. //
  91. if (!fdwFilter && !pPrinterNotifyOptions) {
  92. SetLastError(ERROR_INVALID_PARAMETER);
  93. return INVALID_HANDLE_VALUE;
  94. }
  95. vEnterSem();
  96. if (eProtectHandle( hPrinter, FALSE )) {
  97. vLeaveSem();
  98. return INVALID_HANDLE_VALUE;
  99. }
  100. //
  101. // First check if we are already waiting.
  102. //
  103. // This is broken if we are daytona client->528 server and
  104. // the app does a FFPCN, FCPCN, FFPCN on the same printer,
  105. // and the WPC hasn't returned yet. We really can't fix this
  106. // because there's no way to interrupt the WPC.
  107. //
  108. // The only thing we can do is check if it's simulating and waiting
  109. // to close. If so, then we can reuse it.
  110. //
  111. if (pSpool->pNotify) {
  112. if ((pSpool->pNotify->fdwOptions & PRINTER_NOTIFY_OPTION_SIM_FFPCN_CLOSE) &&
  113. (fdwFilter == pSpool->pNotify->fdwFlags)) {
  114. //
  115. // No longer closing, since we are using it.
  116. //
  117. pSpool->pNotify->fdwOptions &= ~PRINTER_NOTIFY_OPTION_SIM_FFPCN_CLOSE;
  118. hEvent = pSpool->pNotify->hEvent;
  119. goto Done;
  120. }
  121. SetLastError(ERROR_ALREADY_WAITING);
  122. goto Done;
  123. }
  124. //
  125. // Create and add our pSpool to the linked list of wait requests.
  126. //
  127. pNotify = WPCWaitAdd(pSpool);
  128. if (!pNotify) {
  129. goto Done;
  130. }
  131. vLeaveSem();
  132. pNotify->fdwOptions = fdwOptions;
  133. pNotify->fdwFlags = fdwFilter;
  134. RpcTryExcept {
  135. if (dwError = RpcClientFindFirstPrinterChangeNotification(
  136. pSpool->hPrinter,
  137. fdwFilter,
  138. fdwOptions,
  139. GetCurrentProcessId(),
  140. (PRPC_V2_NOTIFY_OPTIONS)pPrinterNotifyOptions,
  141. (LPDWORD)&pNotify->hEvent)) {
  142. hEvent = INVALID_HANDLE_VALUE;
  143. } else {
  144. hEvent = pNotify->hEvent;
  145. }
  146. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  147. dwError = TranslateExceptionCode(RpcExceptionCode());
  148. hEvent = INVALID_HANDLE_VALUE;
  149. } RpcEndExcept
  150. vEnterSem();
  151. //
  152. // If we encounter a 528 server, then we need to simulate the
  153. // FFPCN using a WPC. If the client originally wanted a WPC anyway,
  154. // then fail out and let the client thread do the blocking.
  155. //
  156. if (dwError == RPC_S_PROCNUM_OUT_OF_RANGE &&
  157. !(fdwOptions & PRINTER_NOTIFY_OPTION_SIM_WPC)) {
  158. DWORD dwIDThread;
  159. HANDLE hThread;
  160. //
  161. // If pPrinterNotifyOptions is set, we can't handle it.
  162. // just fail.
  163. //
  164. if (pPrinterNotifyOptions) {
  165. WPCWaitDelete(pNotify);
  166. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  167. hEvent = INVALID_HANDLE_VALUE;
  168. goto Done;
  169. }
  170. hEvent = pNotify->hEvent = CreateEvent(NULL,
  171. TRUE,
  172. FALSE,
  173. NULL);
  174. if( !hEvent ){
  175. hEvent = INVALID_HANDLE_VALUE;
  176. } else {
  177. //
  178. // We're simulating a FFPCN using WPC now.
  179. //
  180. pNotify->fdwOptions |= PRINTER_NOTIFY_OPTION_SIM_FFPCN |
  181. PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE;
  182. //
  183. // Also mark that we failed trying to use FFPCN so we never
  184. // try again on this handle.
  185. //
  186. pSpool->fdwFlags |= SPOOL_FLAG_FFPCN_FAILED;
  187. hThread = CreateThread(NULL,
  188. INITIAL_STACK_COMMIT,
  189. WPCSimulateThreadProc,
  190. pNotify,
  191. 0,
  192. &dwIDThread);
  193. if (hThread) {
  194. CloseHandle(hThread);
  195. } else {
  196. CloseHandle(hEvent);
  197. hEvent = INVALID_HANDLE_VALUE;
  198. dwError = GetLastError();
  199. pNotify->fdwOptions &= ~PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE;
  200. }
  201. }
  202. }
  203. //
  204. // On error case, remove us from the list of waiting handles
  205. //
  206. if( hEvent == INVALID_HANDLE_VALUE ){
  207. WPCWaitDelete(pNotify);
  208. SetLastError(dwError);
  209. }
  210. Done:
  211. vUnprotectHandle( hPrinter );
  212. vLeaveSem();
  213. return hEvent;
  214. }
  215. HANDLE WINAPI
  216. FindFirstPrinterChangeNotification(
  217. HANDLE hPrinter,
  218. DWORD fdwFilter,
  219. DWORD fdwOptions,
  220. PPRINTER_NOTIFY_OPTIONS pPrinterNotifyOptions)
  221. {
  222. if (fdwOptions) {
  223. SetLastError(ERROR_INVALID_PARAMETER);
  224. return INVALID_HANDLE_VALUE;
  225. }
  226. return FindFirstPrinterChangeNotificationWorker(hPrinter,
  227. fdwFilter,
  228. fdwOptions,
  229. pPrinterNotifyOptions);
  230. }
  231. BOOL WINAPI
  232. FindNextPrinterChangeNotification(
  233. HANDLE hChange,
  234. LPDWORD pdwChange,
  235. LPVOID pPrinterNotifyOptions,
  236. LPVOID* ppInfo)
  237. {
  238. BOOL bReturnValue;
  239. DWORD dwError;
  240. HANDLE hPrinter;
  241. PSPOOL pSpool;
  242. PNOTIFY pNotify;
  243. PVOID pvIgnore;
  244. DWORD dwIgnore;
  245. DWORD fdwFlags;
  246. if (!pdwChange) {
  247. pdwChange = &dwIgnore;
  248. }
  249. if (ppInfo) {
  250. *ppInfo = NULL;
  251. fdwFlags = PRINTER_NOTIFY_NEXT_INFO;
  252. } else {
  253. ppInfo = &pvIgnore;
  254. fdwFlags = 0;
  255. }
  256. vEnterSem();
  257. pNotify = WPCWaitFind(hChange);
  258. //
  259. // Either the handle is bad, or it doesn't have a wait or we have
  260. //
  261. if (!pNotify || !pNotify->pSpool || pNotify->bHandleInvalid) {
  262. SetLastError(ERROR_INVALID_HANDLE);
  263. goto FailExitWaitList;
  264. }
  265. pSpool = pNotify->pSpool;
  266. hPrinter = pSpool->hPrinter;
  267. //
  268. // If we are simulating FFPCN using WPC, we must use the thread.
  269. //
  270. if (pNotify->fdwOptions & PRINTER_NOTIFY_OPTION_SIM_FFPCN) {
  271. HANDLE hThread;
  272. DWORD dwIDThread;
  273. ResetEvent(pNotify->hEvent);
  274. //
  275. // Get the last return status. Client should not call FNCPN
  276. // until the WPC sets the event, so this value should be
  277. // initialized.
  278. //
  279. *pdwChange = pNotify->dwReturn;
  280. //
  281. // If the thread is active anyway, then don't try to create another
  282. // Best we can do at this point.
  283. //
  284. if (pNotify->fdwOptions & PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE) {
  285. vLeaveSem();
  286. return TRUE;
  287. }
  288. //
  289. // We're simulating a FFPCN using WPC now.
  290. //
  291. pNotify->fdwOptions |= PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE;
  292. hThread = CreateThread(NULL,
  293. INITIAL_STACK_COMMIT,
  294. WPCSimulateThreadProc,
  295. pNotify,
  296. 0,
  297. &dwIDThread);
  298. if (hThread) {
  299. CloseHandle(hThread);
  300. vLeaveSem();
  301. return TRUE;
  302. }
  303. pNotify->fdwOptions &= ~PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE;
  304. goto FailExitWaitList;
  305. }
  306. vLeaveSem();
  307. RpcTryExcept {
  308. if (dwError = RpcFindNextPrinterChangeNotification(
  309. hPrinter,
  310. fdwFlags,
  311. pdwChange,
  312. (PRPC_V2_NOTIFY_OPTIONS)pPrinterNotifyOptions,
  313. (PRPC_V2_NOTIFY_INFO*)ppInfo)) {
  314. SetLastError(dwError);
  315. bReturnValue = FALSE;
  316. } else {
  317. bReturnValue = TRUE;
  318. }
  319. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  320. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  321. bReturnValue = FALSE;
  322. } RpcEndExcept
  323. //
  324. // Thunk from W to A if necessary.
  325. //
  326. if (pSpool->Status & SPOOL_STATUS_ANSI &&
  327. bReturnValue &&
  328. fdwFlags & PRINTER_NOTIFY_NEXT_INFO &&
  329. *ppInfo) {
  330. DWORD i;
  331. PPRINTER_NOTIFY_INFO_DATA pData;
  332. for(pData = (*(PPRINTER_NOTIFY_INFO*)ppInfo)->aData,
  333. i=(*(PPRINTER_NOTIFY_INFO*)ppInfo)->Count;
  334. i;
  335. pData++, i--) {
  336. switch ((BYTE)pData->Reserved) {
  337. case TABLE_STRING:
  338. UnicodeToAnsiString(
  339. pData->NotifyData.Data.pBuf,
  340. pData->NotifyData.Data.pBuf,
  341. (pData->NotifyData.Data.cbBuf/sizeof(WCHAR)) -1);
  342. break;
  343. case TABLE_DEVMODE:
  344. if (pData->NotifyData.Data.cbBuf) {
  345. CopyAnsiDevModeFromUnicodeDevMode(
  346. pData->NotifyData.Data.pBuf,
  347. pData->NotifyData.Data.pBuf);
  348. }
  349. break;
  350. }
  351. }
  352. }
  353. return bReturnValue;
  354. FailExitWaitList:
  355. vLeaveSem();
  356. return FALSE;
  357. }
  358. BOOL WINAPI
  359. FindClosePrinterChangeNotification(
  360. HANDLE hChange)
  361. {
  362. PNOTIFY pNotify;
  363. HANDLE hPrinterRPC = NULL;
  364. DWORD dwError;
  365. vEnterSem();
  366. pNotify = WPCWaitFind(hChange);
  367. if (!pNotify) {
  368. SetLastError(ERROR_INVALID_HANDLE);
  369. vLeaveSem();
  370. return FALSE;
  371. }
  372. if (pNotify->pSpool)
  373. hPrinterRPC = pNotify->pSpool->hPrinter;
  374. dwError = FindClosePrinterChangeNotificationWorker(pNotify,
  375. hPrinterRPC,
  376. FALSE);
  377. vLeaveSem();
  378. if (dwError) {
  379. SetLastError(dwError);
  380. return FALSE;
  381. }
  382. return TRUE;
  383. }
  384. DWORD
  385. FindClosePrinterChangeNotificationWorker(
  386. IN PNOTIFY pNotify,
  387. IN HANDLE hPrinterRPC,
  388. IN BOOL bRevalidate
  389. )
  390. /*++
  391. Routine Description:
  392. Does the actual FindClose work.
  393. Arguments:
  394. pNotify - notification to close
  395. hPrinterRPC - handle to printer to close
  396. bRevalidate - If this is TRUE, we were called to revalidate the handle
  397. rather than close it.
  398. Return Value:
  399. TRUE - success
  400. FALSE - fail
  401. Note: assume in critical section
  402. --*/
  403. {
  404. DWORD dwError;
  405. PSPOOL pSpool;
  406. if (!pNotify) {
  407. return ERROR_INVALID_HANDLE;
  408. }
  409. //
  410. // Detach the pNotify and pSpool objects completely. Only if we are not
  411. // revalidating.
  412. //
  413. pSpool = pNotify->pSpool;
  414. if (!bRevalidate) {
  415. if (pSpool) {
  416. pSpool->pNotify = NULL;
  417. pSpool->fdwFlags = 0;
  418. }
  419. pNotify->pSpool = NULL;
  420. }
  421. //
  422. // If we are simulating a FFPCN with a WPC, then let the WPC thread
  423. // free up the data structure or clean it up if the thread is done.
  424. //
  425. if (pNotify->fdwOptions & PRINTER_NOTIFY_OPTION_SIM_FFPCN) {
  426. if (pNotify->fdwOptions & PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE) {
  427. pNotify->fdwOptions |= PRINTER_NOTIFY_OPTION_SIM_FFPCN_CLOSE;
  428. } else {
  429. //
  430. // The thread has exited, so we need to do the cleanup.
  431. // Set the event to release any waiting threads. Since the caller
  432. // does not necessarily know how to handle the failure on
  433. // WaitForMultipleObjects,
  434. //
  435. SetEvent(pNotify->hEvent);
  436. if (!bRevalidate) {
  437. CloseHandle(pNotify->hEvent);
  438. WPCWaitDelete(pNotify);
  439. } else {
  440. pNotify->bHandleInvalid = TRUE;
  441. }
  442. }
  443. return ERROR_SUCCESS;
  444. }
  445. SetEvent(pNotify->hEvent);
  446. //
  447. // If we are not revalidating, we can close the handle for real, otherwise
  448. // we just want to set the handle to invalid.
  449. //
  450. if (!bRevalidate) {
  451. CloseHandle(pNotify->hEvent);
  452. WPCWaitDelete(pNotify);
  453. } else {
  454. pNotify->bHandleInvalid = TRUE;
  455. }
  456. if (!hPrinterRPC)
  457. return ERROR_SUCCESS;
  458. vLeaveSem();
  459. RpcTryExcept {
  460. dwError = RpcFindClosePrinterChangeNotification(hPrinterRPC);
  461. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  462. dwError = TranslateExceptionCode(RpcExceptionCode());
  463. } RpcEndExcept
  464. vEnterSem();
  465. return dwError;
  466. }
  467. //
  468. // WPC Wait structures
  469. // Currently implemented as a linked list
  470. //
  471. PNOTIFY
  472. WPCWaitAdd(
  473. PSPOOL pSpool)
  474. /*++
  475. Routine Description:
  476. Allocates a wait structure on the client side, which allows the
  477. user program to refer to events only.
  478. Arguments:
  479. pSpool - object to add to list
  480. Return Value:
  481. NOTE: Asssumes already in critical section
  482. --*/
  483. {
  484. PNOTIFY pNotify;
  485. pNotify = AllocSplMem(sizeof(NOTIFY));
  486. if (!pNotify)
  487. return NULL;
  488. pNotify->pSpool = pSpool;
  489. pSpool->pNotify = pNotify;
  490. pNotify->pNext = pNotifyHead;
  491. pNotifyHead = pNotify;
  492. return pNotify;
  493. }
  494. VOID
  495. WPCWaitDelete(
  496. PNOTIFY pNotify)
  497. /*++
  498. Routine Description:
  499. Find wait structure based on hEvent.
  500. Arguments:
  501. pNotify - delete it
  502. Return Value:
  503. VOID
  504. NOTE: Asssumes already in critical section
  505. --*/
  506. {
  507. PNOTIFY pNotifyTmp;
  508. if (!pNotify)
  509. return;
  510. //
  511. // Check head case first
  512. //
  513. if (pNotifyHead == pNotify) {
  514. pNotifyHead = pNotify->pNext;
  515. } else {
  516. //
  517. // Scan list to delete
  518. //
  519. for(pNotifyTmp = pNotifyHead;
  520. pNotifyTmp;
  521. pNotifyTmp = pNotifyTmp->pNext) {
  522. if (pNotify == pNotifyTmp->pNext) {
  523. pNotifyTmp->pNext = pNotify->pNext;
  524. break;
  525. }
  526. }
  527. //
  528. // If not found, return without freeing
  529. //
  530. if (!pNotifyTmp)
  531. return;
  532. }
  533. //
  534. // Remove link from pSpool to us... but only if we've found
  535. // ourselves on the linked list (could have been removed by
  536. // ClosePrinter in a different thread).
  537. //
  538. if (pNotify->pSpool) {
  539. pNotify->pSpool->pNotify = NULL;
  540. }
  541. FreeSplMem(pNotify);
  542. return;
  543. }
  544. PNOTIFY
  545. WPCWaitFind(
  546. HANDLE hFind)
  547. /*++
  548. Routine Description:
  549. Find wait structure based on hEvent.
  550. Arguments:
  551. hFind - Handle to event returned from FindFirstPrinterChangeNotification
  552. or hPrinter
  553. Return Value:
  554. pWait pointer, or NULL if not found
  555. NOTE: assumes already in critical section
  556. --*/
  557. {
  558. PNOTIFY pNotify;
  559. for(pNotify = pNotifyHead; pNotify; pNotify=pNotify->pNext) {
  560. if (hFind == pNotify->hEvent) {
  561. return pNotify;
  562. }
  563. }
  564. return NULL;
  565. }
  566. DWORD
  567. WPCSimulateThreadProc(
  568. PVOID pvParm)
  569. /*++
  570. Routine Description:
  571. This thread simulates the FFPCN when daytona apps run on daytona
  572. clients connected to 528 servers.
  573. Arguments:
  574. pvParm - pSpool
  575. Return Value:
  576. VOID
  577. Note:
  578. --*/
  579. {
  580. PNOTIFY pNotify = (PNOTIFY)pvParm;
  581. pNotify->dwReturn = WaitForPrinterChange(pNotify->pSpool,
  582. pNotify->fdwFlags);
  583. vEnterSem();
  584. pNotify->fdwOptions &= ~PRINTER_NOTIFY_OPTION_SIM_FFPCN_ACTIVE;
  585. //
  586. // !! POLICY !!
  587. //
  588. // How do we handle timeouts?
  589. //
  590. SetEvent(pNotify->hEvent);
  591. if (pNotify->fdwOptions & PRINTER_NOTIFY_OPTION_SIM_FFPCN_CLOSE) {
  592. CloseHandle(pNotify->hEvent);
  593. WPCWaitDelete(pNotify);
  594. }
  595. vLeaveSem();
  596. //
  597. // We are no longer active; the FindClose must clean up for us.
  598. //
  599. return 0;
  600. }
  601. DWORD
  602. WaitForPrinterChange(
  603. HANDLE hPrinter,
  604. DWORD Flags
  605. )
  606. {
  607. DWORD ReturnValue;
  608. PSPOOL pSpool = (PSPOOL)hPrinter;
  609. HANDLE hEvent;
  610. DWORD rc;
  611. if( eProtectHandle( hPrinter, FALSE )){
  612. return(FALSE);
  613. }
  614. //
  615. // Try using FFPCN first, if we haven't failed on this printer before.
  616. //
  617. if (!(pSpool->fdwFlags & SPOOL_FLAG_FFPCN_FAILED)) {
  618. if (pSpool->fdwFlags & SPOOL_FLAG_LAZY_CLOSE) {
  619. vEnterSem();
  620. if (pSpool->pNotify)
  621. hEvent = pSpool->pNotify->hEvent;
  622. vLeaveSem();
  623. } else {
  624. hEvent = FindFirstPrinterChangeNotificationWorker(
  625. hPrinter,
  626. Flags,
  627. PRINTER_NOTIFY_OPTION_SIM_WPC,
  628. NULL);
  629. }
  630. if (hEvent != INVALID_HANDLE_VALUE) {
  631. //
  632. // Found notification, now wait for it.
  633. //
  634. rc = WaitForSingleObject(hEvent, PRINTER_CHANGE_TIMEOUT_VALUE);
  635. switch (rc) {
  636. case WAIT_TIMEOUT:
  637. ReturnValue = PRINTER_CHANGE_TIMEOUT;
  638. break;
  639. case WAIT_OBJECT_0:
  640. if (!FindNextPrinterChangeNotification(
  641. hEvent,
  642. &ReturnValue,
  643. 0,
  644. NULL)) {
  645. ReturnValue = 0;
  646. DBGMSG(DBG_WARNING,
  647. ("QueryPrinterChange failed %d\n",
  648. GetLastError()));
  649. }
  650. break;
  651. default:
  652. ReturnValue = 0;
  653. break;
  654. }
  655. //
  656. // !! Policy !!
  657. //
  658. // Do we want to close it? The app might just reopen it.
  659. // If we leave it open, it will get cleaned-up at ClosePrinter
  660. // time. We would need an api to clear out pending events.
  661. //
  662. pSpool->fdwFlags |= SPOOL_FLAG_LAZY_CLOSE;
  663. goto Done;
  664. }
  665. //
  666. // FFPCN failed. Only if entry not found (511 client) do
  667. // we try old WPC. Otherwise return here.
  668. //
  669. if (GetLastError() != RPC_S_PROCNUM_OUT_OF_RANGE) {
  670. ReturnValue = 0;
  671. goto Done;
  672. }
  673. pSpool->fdwFlags |= SPOOL_FLAG_FFPCN_FAILED;
  674. }
  675. RpcTryExcept {
  676. if (ReturnValue = RpcWaitForPrinterChange(
  677. pSpool->hPrinter,
  678. Flags,
  679. &Flags)) {
  680. SetLastError(ReturnValue);
  681. ReturnValue = 0;
  682. } else
  683. ReturnValue = Flags;
  684. } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) {
  685. SetLastError(TranslateExceptionCode(RpcExceptionCode()));
  686. ReturnValue = 0;
  687. } RpcEndExcept
  688. Done:
  689. vUnprotectHandle( pSpool );
  690. return ReturnValue;
  691. }
  692. BOOL WINAPI
  693. FreePrinterNotifyInfo(
  694. PPRINTER_NOTIFY_INFO pInfo)
  695. {
  696. DWORD i;
  697. PPRINTER_NOTIFY_INFO_DATA pData;
  698. if (!pInfo) {
  699. SetLastError(ERROR_INVALID_PARAMETER);
  700. return FALSE;
  701. }
  702. for(pData = pInfo->aData, i=pInfo->Count;
  703. i;
  704. pData++, i--) {
  705. if ((BYTE)pData->Reserved != TABLE_DWORD &&
  706. pData->NotifyData.Data.pBuf) {
  707. midl_user_free(pData->NotifyData.Data.pBuf);
  708. }
  709. }
  710. midl_user_free(pInfo);
  711. return TRUE;
  712. }