Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1426 lines
36 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. print.c
  5. Abstract:
  6. This file implements basic printer functionality
  7. Author:
  8. Asaf Shaar (asafs) 28-Nov-1999
  9. Environment:
  10. User Mode
  11. --*/
  12. #include <windows.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <tchar.h>
  16. #include <WinSpool.h>
  17. #include <faxutil.h>
  18. #include <faxreg.h>
  19. #include <shlobj.h>
  20. /*++
  21. Routine Description:
  22. Wrapper function for EnumPrinters API
  23. Arguments:
  24. pServerName - Server name (NULL for current server)
  25. dwLevel - Specifies PRINTER_INFO level to be returned
  26. pcPrinters - Returns the number of printers found
  27. dwFlags - Specifies the type of printer objects to be enumerated
  28. level -
  29. pCount -
  30. Return Value:
  31. Pointer to an array of PRINTER_INFO_x structures
  32. NULL if there is an error
  33. --*/
  34. PVOID
  35. MyEnumPrinters(
  36. LPTSTR pServerName,
  37. DWORD dwLevel,
  38. PDWORD pcPrinters,
  39. DWORD dwFlags
  40. )
  41. {
  42. PBYTE pPrinterInfo = NULL;
  43. DWORD cb = 0;
  44. DWORD Error = ERROR_SUCCESS;
  45. if (!dwFlags)
  46. {
  47. dwFlags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
  48. }
  49. if (!EnumPrinters(dwFlags, pServerName, dwLevel, NULL, 0, &cb, pcPrinters))
  50. {
  51. Error = GetLastError();
  52. if ( Error == ERROR_INSUFFICIENT_BUFFER && (pPrinterInfo = (PBYTE) MemAlloc(cb)) != NULL)
  53. {
  54. if (EnumPrinters(dwFlags, pServerName, dwLevel, pPrinterInfo, cb, &cb, pcPrinters))
  55. {
  56. return pPrinterInfo;
  57. }
  58. Error = GetLastError();
  59. }
  60. }
  61. MemFree(pPrinterInfo);
  62. SetLastError(Error);
  63. return NULL;
  64. }
  65. /*++
  66. Routine Description:
  67. Returns the name of the first Fax printer on the local machine:
  68. for LOCAL fax printer use GetFirstLocalFaxPrinterName.
  69. for REMOTE fax printer use GetFirstRemoteFaxPrinterName.
  70. Arguments:
  71. OUT lptstrPrinterName - A buffer to hold the returned printer name.
  72. IN dwPrintNameInChars - The size of the buffer in characters (including the space for terminating null)
  73. Return Value:
  74. TRUE if the function succeeded and found a fax printer.
  75. FALSE if the function failed or did not find a fax printer.
  76. If a printer was not found then GetLastError() will report ERROR_PRINTER_NOT_FOUND.
  77. --*/
  78. BOOL
  79. GetFirstFaxPrinterName(
  80. OUT LPTSTR lptstrPrinterName,
  81. IN DWORD dwMaxLenInChars,
  82. IN DWORD dwFlag)
  83. {
  84. PPRINTER_INFO_2 pPrinterInfo = NULL;
  85. DWORD dwNumPrinters;
  86. DWORD dwPrinter;
  87. DWORD ec = ERROR_SUCCESS;
  88. DEBUG_FUNCTION_NAME(TEXT("GetFirstFaxPrinterName"));
  89. SetLastError (ERROR_SUCCESS);
  90. pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL,
  91. 2,
  92. &dwNumPrinters,
  93. dwFlag
  94. );
  95. if (!pPrinterInfo)
  96. {
  97. //
  98. // Either error on no printers
  99. //
  100. ec = GetLastError();
  101. if (ERROR_SUCCESS == ec)
  102. {
  103. //
  104. // Not an error - no printers
  105. //
  106. SetLastError (ERROR_PRINTER_NOT_FOUND);
  107. return FALSE;
  108. }
  109. DebugPrintEx(
  110. DEBUG_ERR,
  111. TEXT("MyEnumPrinters() failed (ec: %ld)"),
  112. ec);
  113. goto Error;
  114. }
  115. for (dwPrinter=0; dwPrinter < dwNumPrinters; dwPrinter++)
  116. {
  117. if (!_tcscmp(pPrinterInfo[dwPrinter].pDriverName,FAX_DRIVER_NAME))
  118. {
  119. memset(lptstrPrinterName,0,dwMaxLenInChars*sizeof(TCHAR));
  120. _tcsncpy(lptstrPrinterName,pPrinterInfo[dwPrinter].pPrinterName,dwMaxLenInChars-1);
  121. goto Exit;
  122. }
  123. }
  124. ec = ERROR_PRINTER_NOT_FOUND;
  125. goto Error;
  126. Error:
  127. Assert (ERROR_SUCCESS != ec);
  128. Exit:
  129. MemFree(pPrinterInfo);
  130. pPrinterInfo = NULL;
  131. if (ERROR_SUCCESS != ec)
  132. {
  133. SetLastError(ec);
  134. return FALSE;
  135. }
  136. return (ERROR_SUCCESS == ec);
  137. }
  138. BOOL
  139. GetFirstLocalFaxPrinterName(
  140. OUT LPTSTR lptstrPrinterName,
  141. IN DWORD dwMaxLenInChars)
  142. {
  143. return GetFirstFaxPrinterName(lptstrPrinterName,dwMaxLenInChars,PRINTER_ENUM_LOCAL);
  144. }
  145. BOOL
  146. GetFirstRemoteFaxPrinterName(
  147. OUT LPTSTR lptstrPrinterName,
  148. IN DWORD dwMaxLenInChars)
  149. {
  150. return GetFirstFaxPrinterName(lptstrPrinterName,dwMaxLenInChars,PRINTER_ENUM_CONNECTIONS);
  151. }
  152. //
  153. //
  154. // Function: GetPrinterInfo
  155. // Description: Returns a pointer to PRINTER_INFO_2 of the specified printer name.
  156. // If the printer was not found or there was an error than the function
  157. // return NULL. To get extended error information, call GetLastError().
  158. //
  159. // Remarks: The caller must release the allocated memory with MemFree()
  160. //
  161. // Args: LPTSTR lptstrPrinterName : The name of the printer.
  162. //
  163. // Author: AsafS
  164. PPRINTER_INFO_2
  165. GetFaxPrinterInfo(
  166. LPCTSTR lptstrPrinterName
  167. )
  168. {
  169. DEBUG_FUNCTION_NAME(TEXT("GetPrinterInfo"))
  170. DWORD ec = ERROR_SUCCESS;
  171. PPRINTER_INFO_2 pPrinterInfo = NULL;
  172. DWORD dwNeededSize = 0;
  173. BOOL result = FALSE;
  174. HANDLE hPrinter = NULL;
  175. if (!OpenPrinter(
  176. (LPTSTR) lptstrPrinterName,
  177. &hPrinter,
  178. NULL))
  179. {
  180. ec = GetLastError();
  181. DebugPrintEx(
  182. DEBUG_ERR,
  183. TEXT("A printer with %s name was not found (ec: %ld)."),
  184. lptstrPrinterName,
  185. GetLastError()
  186. );
  187. goto Exit;
  188. }
  189. result = GetPrinter(
  190. hPrinter,
  191. 2,
  192. NULL,
  193. 0,
  194. &dwNeededSize
  195. );
  196. if (!result)
  197. {
  198. if ( (ec = GetLastError()) != ERROR_INSUFFICIENT_BUFFER )
  199. {
  200. DebugPrintEx(
  201. DEBUG_ERR,
  202. TEXT("GetPrinter return an unexpected result or error (ec: %ld)."),
  203. ec
  204. );
  205. goto Exit;
  206. }
  207. }
  208. pPrinterInfo = (PPRINTER_INFO_2) MemAlloc(dwNeededSize);
  209. if (!pPrinterInfo)
  210. {
  211. ec = ERROR_NOT_ENOUGH_MEMORY;
  212. goto Exit;
  213. }
  214. result = GetPrinter(
  215. hPrinter,
  216. 2,
  217. (LPBYTE) pPrinterInfo,
  218. dwNeededSize,
  219. &dwNeededSize
  220. );
  221. if (!result)
  222. {
  223. ec = GetLastError();
  224. DebugPrintEx(
  225. DEBUG_ERR,
  226. TEXT("GetPrinter failed in second call (ec: %ld)."),
  227. ec
  228. );
  229. MemFree(pPrinterInfo);
  230. pPrinterInfo = NULL;
  231. goto Exit;
  232. }
  233. Exit:
  234. SetLastError(ec);
  235. if (hPrinter)
  236. {
  237. if (!ClosePrinter(hPrinter))
  238. {
  239. DebugPrintEx(
  240. DEBUG_ERR,
  241. TEXT("ClosePrinter failed with %ld"),
  242. GetLastError ()
  243. );
  244. }
  245. }
  246. return pPrinterInfo;
  247. } // GetFaxPrinterInfo
  248. ///////////////////////////////////////////////////////////////////////////////////////
  249. // Function:
  250. // IsPrinterFaxPrinter
  251. //
  252. // Purpose: determines whether the input printer name is a valid
  253. // fax printer by checking the driver name
  254. //
  255. // Params:
  256. // LPTSTR PrinterName - printer name to evaluate
  257. //
  258. // Return Value:
  259. // TRUE - printer is a valid fax printer
  260. // FALSE - otherwise
  261. //
  262. // Author:
  263. // Mooly Beery (MoolyB) 21-Aug-2001
  264. ///////////////////////////////////////////////////////////////////////////////////////
  265. BOOL IsPrinterFaxPrinter(LPTSTR PrinterName)
  266. {
  267. DWORD Rval = FALSE;
  268. LPPRINTER_INFO_2 lpPrinterInfo = NULL;
  269. DEBUG_FUNCTION_NAME(TEXT("IsPrinterFaxPrinter"))
  270. lpPrinterInfo = GetFaxPrinterInfo(PrinterName);
  271. if (lpPrinterInfo==NULL)
  272. {
  273. DebugPrintEx(DEBUG_ERR,_T("GetFaxPrinterInfo failed with %ld."),GetLastError());
  274. return FALSE;
  275. }
  276. if (_tcscmp( lpPrinterInfo->pDriverName, FAX_DRIVER_NAME ) == 0)
  277. {
  278. Rval = TRUE;
  279. }
  280. else
  281. {
  282. Rval = FALSE;
  283. }
  284. MemFree( lpPrinterInfo );
  285. return Rval;
  286. }
  287. DWORD
  288. IsLocalFaxPrinterInstalled(
  289. LPBOOL lpbLocalFaxPrinterInstalled
  290. )
  291. /*++
  292. Routine name : IsLocalFaxPrinterInstalled
  293. Routine description:
  294. Checks if a local fax printer is installed and not marked for deletion.
  295. Author:
  296. Eran Yariv (EranY), Jul, 2000
  297. Arguments:
  298. lpbLocalFaxPrinterInstalled [out] - Result flag
  299. Return Value:
  300. Standard Win32 error code
  301. --*/
  302. {
  303. TCHAR tszPrinterName[MAX_PATH * 3] = TEXT("\0");
  304. DWORD dwErr;
  305. PPRINTER_INFO_2 pi2 = NULL;
  306. DEBUG_FUNCTION_NAME(TEXT("IsLocalFaxPrinterInstalled"))
  307. if (!GetFirstLocalFaxPrinterName (tszPrinterName, sizeof (tszPrinterName) / sizeof (tszPrinterName[0])))
  308. {
  309. dwErr = GetLastError ();
  310. DebugPrintEx(
  311. DEBUG_ERR,
  312. TEXT("GetFirstLocalFaxPrinterName failed with %ld."),
  313. dwErr);
  314. if (ERROR_PRINTER_NOT_FOUND == dwErr)
  315. {
  316. //
  317. // Local fax printer is not installed
  318. //
  319. *lpbLocalFaxPrinterInstalled = FALSE;
  320. return ERROR_SUCCESS;
  321. }
  322. Assert (ERROR_SUCCESS != dwErr);
  323. return dwErr;
  324. }
  325. //
  326. // Local fax printer is installed
  327. // Let's see if it is PRINTER_STATUS_PENDING_DELETION.
  328. // If so, let's return FALSE because the printer will be gone soon.
  329. // If someone will call AddPrinter because we return FALSE, it's OK. See AddPrinter() remarks.
  330. //
  331. Assert (lstrlen (tszPrinterName));
  332. pi2 = GetFaxPrinterInfo (tszPrinterName);
  333. if (!pi2)
  334. {
  335. dwErr = GetLastError ();
  336. DebugPrintEx(
  337. DEBUG_ERR,
  338. TEXT("GetFaxPrinterInfo failed with %ld."),
  339. dwErr);
  340. //
  341. // Printer is installed but somehow I can't get it's info - weird
  342. //
  343. Assert (ERROR_SUCCESS != dwErr);
  344. return dwErr;
  345. }
  346. if ((pi2->Status) & PRINTER_STATUS_PENDING_DELETION)
  347. {
  348. //
  349. // Printer is there but is marked for deletion
  350. //
  351. DebugPrintEx(
  352. DEBUG_MSG,
  353. TEXT("Printer %s is installed but marked for deletion. Reported as non-existant"),
  354. tszPrinterName);
  355. *lpbLocalFaxPrinterInstalled = FALSE;
  356. }
  357. else
  358. {
  359. *lpbLocalFaxPrinterInstalled = TRUE;
  360. }
  361. MemFree (pi2);
  362. return ERROR_SUCCESS;
  363. } // IsLocalFaxPrinterInstalled
  364. DWORD
  365. IsLocalFaxPrinterShared (
  366. LPBOOL lpbShared
  367. )
  368. /*++
  369. Routine name : IsLocalFaxPrinterShared
  370. Routine description:
  371. Detects if the local fax printer is shared
  372. Author:
  373. Eran Yariv (EranY), Jul, 2000
  374. Arguments:
  375. lpbShared [out] - Sharing flag
  376. Return Value:
  377. Standard Win32 error code
  378. --*/
  379. {
  380. TCHAR tszPrinterName[MAX_PATH * 3];
  381. DWORD dwErr;
  382. PPRINTER_INFO_2 pInfo2;
  383. DEBUG_FUNCTION_NAME(TEXT("IsLocalFaxPrinterShared"))
  384. if (!GetFirstLocalFaxPrinterName (tszPrinterName, sizeof (tszPrinterName) / sizeof (tszPrinterName[0])))
  385. {
  386. dwErr = GetLastError ();
  387. if (ERROR_PRINTER_NOT_FOUND == dwErr)
  388. {
  389. //
  390. // Local fax printer is not installed
  391. //
  392. *lpbShared = FALSE;
  393. return ERROR_SUCCESS;
  394. }
  395. DebugPrintEx(
  396. DEBUG_ERR,
  397. TEXT("GetFirstLocalFaxPrinterName failed with %ld."),
  398. dwErr);
  399. return dwErr;
  400. }
  401. pInfo2 = GetFaxPrinterInfo (tszPrinterName);
  402. if (!pInfo2)
  403. {
  404. dwErr = GetLastError ();
  405. DebugPrintEx(
  406. DEBUG_ERR,
  407. TEXT("GetFaxPrinterInfo failed with %ld."),
  408. dwErr);
  409. return dwErr;
  410. }
  411. *lpbShared = ((pInfo2->Attributes) & PRINTER_ATTRIBUTE_SHARED) ? TRUE : FALSE;
  412. MemFree (pInfo2);
  413. return ERROR_SUCCESS;
  414. } // IsLocalFaxPrinterShared
  415. DWORD
  416. AddLocalFaxPrinter (
  417. LPCTSTR lpctstrPrinterName,
  418. LPCTSTR lpctstrPrinterDescription
  419. )
  420. /*++
  421. Routine name : AddLocalFaxPrinter
  422. Routine description:
  423. Adds a local fax printer
  424. Author:
  425. Eran Yariv (EranY), Jul, 2000
  426. Arguments:
  427. lpctstrPrinterName [in] - Printer name
  428. lpctstrPrinterDescription [in] - Printer comments (description)
  429. Return Value:
  430. Standard Win32 error code
  431. Remarks:
  432. This function should not be called if a local fax printer is installed.
  433. --*/
  434. {
  435. DWORD ec = ERROR_SUCCESS;
  436. HANDLE hPrinter = NULL;
  437. PRINTER_INFO_2 PrinterInfo2 = {0};
  438. BOOL bLocalPrinterInstalled;
  439. BOOL bIsFaxPrinterShared = FALSE;
  440. DWORD dwAttributes = PRINTER_ATTRIBUTE_LOCAL | PRINTER_ATTRIBUTE_FAX;
  441. LPCTSTR lpctstrShareName = NULL;
  442. DEBUG_FUNCTION_NAME(TEXT("AddLocalFaxPrinter"))
  443. ec = IsLocalFaxPrinterInstalled (&bLocalPrinterInstalled);
  444. if (ERROR_SUCCESS == ec && bLocalPrinterInstalled)
  445. {
  446. //
  447. // Local fax printer already installed
  448. //
  449. return ec;
  450. }
  451. //
  452. // Check if this is SKU supports fax sharing.
  453. // If it does not - do not share printer.
  454. //
  455. if (IsFaxShared())
  456. {
  457. // We can share the printer on this SKU. Let's check if Fax is
  458. // installed in Sharing enabled mode.
  459. HKEY hFaxKey = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_FAX_SETUP,FALSE,KEY_READ);
  460. if (hFaxKey)
  461. {
  462. if (GetRegistryDword(hFaxKey,REGVAL_IS_SHARED_FAX_PRINTER))
  463. {
  464. DebugPrintEx(DEBUG_MSG, TEXT("Fax is installed in a mode that enables sharing"));
  465. bIsFaxPrinterShared = TRUE;
  466. }
  467. else
  468. {
  469. DebugPrintEx(DEBUG_MSG, TEXT("Fax is installed in a mode that does not enable sharing"));
  470. }
  471. RegCloseKey(hFaxKey);
  472. }
  473. else
  474. {
  475. DebugPrintEx(DEBUG_WRN, TEXT("Failed to open REGKEY_FAX_SETUP, printer won't be shared (ec=%d)"),GetLastError());
  476. }
  477. }
  478. if (bIsFaxPrinterShared)
  479. {
  480. dwAttributes |= PRINTER_ATTRIBUTE_SHARED;
  481. lpctstrShareName = lpctstrPrinterName;
  482. }
  483. PrinterInfo2.pServerName = NULL;
  484. PrinterInfo2.pPrinterName = (LPTSTR) lpctstrPrinterName;
  485. PrinterInfo2.pPortName = FAX_MONITOR_PORT_NAME;
  486. PrinterInfo2.pDriverName = FAX_DRIVER_NAME;
  487. PrinterInfo2.pPrintProcessor = TEXT("WinPrint");
  488. PrinterInfo2.pDatatype = TEXT("RAW");
  489. PrinterInfo2.Attributes = dwAttributes;
  490. PrinterInfo2.pShareName = (LPTSTR) lpctstrShareName;
  491. PrinterInfo2.pComment = (LPTSTR) lpctstrPrinterDescription;
  492. hPrinter = AddPrinter(NULL,
  493. 2,
  494. (LPBYTE)&PrinterInfo2);
  495. if (hPrinter == NULL)
  496. {
  497. ec = GetLastError();
  498. DebugPrintEx(
  499. DEBUG_ERR,
  500. TEXT("AddPrinter failed with %ld."),
  501. ec);
  502. }
  503. else
  504. {
  505. if (IsFaxShared() && bIsFaxPrinterShared)
  506. {
  507. //
  508. // Publish the printer in the DS
  509. //
  510. PRINTER_INFO_7 pi7;
  511. pi7.pszObjectGUID = NULL;
  512. pi7.dwAction = DSPRINT_PUBLISH;
  513. if (!SetPrinter(hPrinter, // handle to printer object
  514. 7, // information level
  515. (LPBYTE)&pi7, // printer data buffer
  516. 0 // printer-state command
  517. ))
  518. {
  519. DebugPrintEx(DEBUG_ERR,TEXT("SetPrinter failed with %ld."),GetLastError());
  520. //
  521. // In any case we do not want to fail the whole setup just because we were
  522. // unable to publish the printer on the DS.
  523. // common error codes are:
  524. //
  525. // ERROR_IO_PENDING means SetPrinter is trying to publish the printer in the
  526. // background, we do not wait for it to succeed/fail.
  527. //
  528. // ERROR_DS_UNAVAILABLE means the DS is not accesible.
  529. //
  530. }
  531. }
  532. if (!ClosePrinter(hPrinter))
  533. {
  534. DebugPrintEx(
  535. DEBUG_ERR,
  536. TEXT("ClosePrinter failed with %ld."),
  537. GetLastError ());
  538. }
  539. hPrinter = NULL;
  540. RefreshPrintersAndFaxesFolder();
  541. }
  542. return ec;
  543. } // AddLocalFaxPrinter
  544. //*********************************************************************************
  545. //* Name: ParamTagsToString()
  546. //* Author: Ronen Barenboim
  547. //* Date: March 23, 1999
  548. //*********************************************************************************
  549. //* DESCRIPTION:
  550. //* Writes a collection of tag parameters and values in the format of a parameter
  551. //* string into a caller provided buffer.
  552. // Reports the size of the tagged string.
  553. //* PARAMETERS:
  554. //* lpTagMap
  555. //* A pointer to an array of FAX_TAG_MAP_ENTRY structures that contain the
  556. //* tag names and values.
  557. //* dwTagCount
  558. //* The number of entries in the tag map array.
  559. //* lpTargetBuf
  560. //* A pointer to a buffer where the tag value string will be placed.
  561. //* The size of this buffer must be big enough to hold the resulting string
  562. // including a terminating NULL char.
  563. //* If this parameter is NULL the function will not generate the tag value
  564. //* string and only report its size in *lpdwSize;
  565. //* lpdwSize
  566. //* A pointer to a DWORD that will accept the size of the resulting
  567. //* tagged string in BYTES. The size DOES NOT INCLUDE the terminating NULL char.
  568. //* RETURN VALUE:
  569. //* NONE
  570. //* REMARKS:
  571. //* The format of the resulting string is:
  572. //* Tag1Value1Tag2Value2....TagNValueN'\0'
  573. //*********************************************************************************
  574. void
  575. ParamTagsToString(
  576. FAX_TAG_MAP_ENTRY * lpTagMap,
  577. DWORD dwTagCount,
  578. LPTSTR lpTargetBuf,
  579. LPDWORD lpdwSize)
  580. {
  581. DWORD index;
  582. LPTSTR p;
  583. DWORD dwSize = 0;
  584. //
  585. // Calculate string size WITHOUT termianting NULL
  586. //
  587. for (index=0; index <dwTagCount; index++)
  588. {
  589. if (lpTagMap[index].lptstrValue && !IsEmptyString(lpTagMap[index].lptstrValue))
  590. {
  591. dwSize += _tcslen(lpTagMap[index].lptstrTagName)*sizeof(TCHAR) + _tcslen(lpTagMap[index].lptstrValue)*sizeof(TCHAR);
  592. }
  593. }
  594. if (lpTargetBuf)
  595. {
  596. //
  597. // Check that size of the Target Buffer is not smaller then the calculated size
  598. //
  599. Assert(dwSize <= *lpdwSize);
  600. //
  601. // Assemble fax job parameters into a single tagged string at the target buffer
  602. // there is a terminating NULL at the end of the string !!!
  603. //
  604. p=lpTargetBuf;
  605. for (index=0; index < dwTagCount; index++)
  606. {
  607. if (lpTagMap[index].lptstrValue && !IsEmptyString(lpTagMap[index].lptstrValue))
  608. {
  609. _tcscpy(p, lpTagMap[index].lptstrTagName);
  610. p += _tcslen(p); // The value string runs over the NULL char of the tag string
  611. _tcscpy(p, lpTagMap[index].lptstrValue);
  612. p += _tcslen(p);
  613. }
  614. }
  615. }
  616. //
  617. // Return the size of the string
  618. //
  619. *lpdwSize = dwSize;
  620. }
  621. HRESULT
  622. RefreshPrintersAndFaxesFolder ()
  623. /*++
  624. Routine name : RefreshPrintersAndFaxesFolder
  625. Routine description:
  626. Notifies the 'Printers and Faxes' shell folder to refresh itself
  627. Author:
  628. Eran Yariv (EranY), Mar, 2001
  629. Arguments:
  630. Return Value:
  631. Standard HRESULT
  632. --*/
  633. {
  634. HRESULT hr = E_FAIL;
  635. LPITEMIDLIST pidlPF = NULL;
  636. LPMALLOC pShellMalloc = NULL;
  637. DEBUG_FUNCTION_NAME(TEXT("RefreshPrintersAndFaxesFolder"));
  638. //
  639. // First obtail the shell alloctaor
  640. //
  641. hr = SHGetMalloc (&pShellMalloc);
  642. if (SUCCEEDED(hr))
  643. {
  644. //
  645. // Get the printer's folder PIDL
  646. //
  647. hr = SHGetSpecialFolderLocation(NULL, CSIDL_PRINTERS, &pidlPF);
  648. if (SUCCEEDED(hr))
  649. {
  650. //
  651. // Requets refresh
  652. //
  653. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_IDLIST | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, pidlPF, NULL);
  654. //
  655. // Release the returned PIDL by using the shell allocator
  656. //
  657. pShellMalloc->Free(pidlPF);
  658. }
  659. //
  660. // Release the shell allocator
  661. //
  662. pShellMalloc->Release();
  663. }
  664. return hr;
  665. } // RefreshPrintersAndFaxesFolder
  666. #ifdef UNICODE
  667. PPRINTER_NAMES
  668. CollectPrinterNames (
  669. LPDWORD lpdwNumPrinters,
  670. BOOL bFilterOutFaxPrinters
  671. )
  672. /*++
  673. Routine name : CollectPrinterNames
  674. Routine description:
  675. Creates a list of printer names for all visible local and remote printers
  676. Author:
  677. Eran Yariv (EranY), Apr, 2001
  678. Arguments:
  679. lpdwNumPrinters [out] - Number of elements in the list
  680. bFilterOutFaxPrinters [in] - If TRUE, fax printers are not returned in the list
  681. Return Value:
  682. Allocated list of printers names. If NULL, an error has occurred - check LastError.
  683. Use ReleasePrinterNames() to release allocated value.
  684. --*/
  685. {
  686. DWORD dwPrinter;
  687. DWORD dwNumPrinters;
  688. DWORD dwIndex = 0;
  689. BOOL bSuccess = FALSE;
  690. PPRINTER_INFO_2 pPrinterInfo = NULL;
  691. PPRINTER_NAMES pRes = NULL;
  692. DEBUG_FUNCTION_NAME(TEXT("ReleasePrinterNames"));
  693. SetLastError (ERROR_SUCCESS);
  694. pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL, // Local machine
  695. 2, // Level 2
  696. &dwNumPrinters, // [out] Number of printers found
  697. 0 // Both local and remote
  698. );
  699. if (!pPrinterInfo)
  700. {
  701. //
  702. // Either error on no printers
  703. //
  704. DWORD ec = GetLastError();
  705. if (ERROR_SUCCESS == ec)
  706. {
  707. //
  708. // Not an error - no printers
  709. //
  710. SetLastError (ERROR_PRINTER_NOT_FOUND);
  711. return NULL;
  712. }
  713. DebugPrintEx(
  714. DEBUG_ERR,
  715. TEXT("MyEnumPrinters() failed (ec: %ld)"),
  716. ec);
  717. return NULL;
  718. }
  719. Assert (dwNumPrinters > 0);
  720. if (bFilterOutFaxPrinters)
  721. {
  722. //
  723. // Counter number of printers w/out the fax printer(s)
  724. //
  725. DWORD dwNewPrintersCount = 0;
  726. for (dwPrinter = 0; dwPrinter < dwNumPrinters; dwPrinter++)
  727. {
  728. if (_tcscmp(pPrinterInfo[dwPrinter].pDriverName,FAX_DRIVER_NAME))
  729. {
  730. //
  731. // Not a fax printer
  732. //
  733. dwNewPrintersCount++;
  734. }
  735. }
  736. if (!dwNewPrintersCount)
  737. {
  738. //
  739. // Only fax printers - return NULL
  740. //
  741. SetLastError (ERROR_PRINTER_NOT_FOUND);
  742. goto exit;
  743. }
  744. *lpdwNumPrinters = dwNewPrintersCount;
  745. }
  746. else
  747. {
  748. *lpdwNumPrinters = dwNumPrinters;
  749. }
  750. pRes = (PPRINTER_NAMES)MemAlloc (sizeof (PRINTER_NAMES) * (*lpdwNumPrinters));
  751. if (!pRes)
  752. {
  753. goto exit;
  754. }
  755. memset (pRes, 0, sizeof (PRINTER_NAMES) * (*lpdwNumPrinters));
  756. for (dwPrinter = 0; dwPrinter < dwNumPrinters; dwPrinter++)
  757. {
  758. if (bFilterOutFaxPrinters && !_tcscmp(pPrinterInfo[dwPrinter].pDriverName,FAX_DRIVER_NAME))
  759. {
  760. //
  761. // This is a fax printer and filtering is on - skip it
  762. //
  763. continue;
  764. }
  765. pRes[dwIndex].lpcwstrDisplayName = StringDup (pPrinterInfo[dwPrinter].pPrinterName);
  766. if (!pRes[dwIndex].lpcwstrDisplayName)
  767. {
  768. goto exit;
  769. }
  770. if (pPrinterInfo[dwPrinter].pServerName)
  771. {
  772. //
  773. // Remote printer
  774. //
  775. WCHAR wszShare[MAX_PATH] = {0};
  776. //
  777. // Server name must begin with '\\'
  778. //
  779. Assert (lstrlen (pPrinterInfo[dwPrinter].pServerName) > 2)
  780. Assert ((TEXT('\\') == pPrinterInfo[dwPrinter].pServerName[0]) &&
  781. (TEXT('\\') == pPrinterInfo[dwPrinter].pServerName[1]));
  782. //
  783. // Share name cannot be NULL or empty string
  784. //
  785. Assert (pPrinterInfo[dwPrinter].pShareName && lstrlen(pPrinterInfo[dwPrinter].pShareName));
  786. //
  787. // Compose UNC path to print share
  788. //
  789. if (0 > _snwprintf (wszShare,
  790. ARR_SIZE(wszShare) -1,
  791. TEXT("%s\\%s"),
  792. pPrinterInfo[dwPrinter].pServerName,
  793. pPrinterInfo[dwPrinter].pShareName))
  794. {
  795. //
  796. // Buffer too small
  797. //
  798. SetLastError (ERROR_GEN_FAILURE);
  799. goto exit;
  800. }
  801. pRes[dwIndex].lpcwstrPath = StringDup (wszShare);
  802. }
  803. else
  804. {
  805. //
  806. // Local printer
  807. //
  808. pRes[dwIndex].lpcwstrPath = StringDup (pPrinterInfo[dwPrinter].pPrinterName);
  809. }
  810. if (!pRes[dwIndex].lpcwstrPath)
  811. {
  812. goto exit;
  813. }
  814. dwIndex++;
  815. }
  816. Assert (dwIndex == *lpdwNumPrinters);
  817. bSuccess = TRUE;
  818. exit:
  819. MemFree (pPrinterInfo);
  820. if (!bSuccess)
  821. {
  822. //
  823. // Free data and return NULL
  824. //
  825. if (pRes)
  826. {
  827. ReleasePrinterNames (pRes, *lpdwNumPrinters);
  828. pRes = NULL;
  829. }
  830. }
  831. return pRes;
  832. } // CollectPrinterNames
  833. VOID
  834. ReleasePrinterNames (
  835. PPRINTER_NAMES pNames,
  836. DWORD dwNumPrinters
  837. )
  838. /*++
  839. Routine name : ReleasePrinterNames
  840. Routine description:
  841. Releases the list of printer names returned by CollectPrinterNames().
  842. Author:
  843. Eran Yariv (EranY), Apr, 2001
  844. Arguments:
  845. pNames [in] - List of printer names
  846. dwNumPrinters [in] - Number of elements in the list
  847. Return Value:
  848. None.
  849. --*/
  850. {
  851. DWORD dw;
  852. DEBUG_FUNCTION_NAME(TEXT("ReleasePrinterNames"));
  853. if (!dwNumPrinters)
  854. {
  855. return;
  856. }
  857. Assert (pNames);
  858. for (dw = 0; dw < dwNumPrinters; dw++)
  859. {
  860. MemFree ((PVOID)(pNames[dw].lpcwstrDisplayName));
  861. pNames[dw].lpcwstrDisplayName = NULL;
  862. MemFree ((PVOID)(pNames[dw].lpcwstrPath));
  863. pNames[dw].lpcwstrPath = NULL;
  864. }
  865. MemFree ((PVOID)pNames);
  866. } // ReleasePrinterNames
  867. LPCWSTR
  868. FindPrinterNameFromPath (
  869. PPRINTER_NAMES pNames,
  870. DWORD dwNumPrinters,
  871. LPCWSTR lpcwstrPath
  872. )
  873. {
  874. DWORD dw;
  875. DEBUG_FUNCTION_NAME(TEXT("FindPrinterNameFromPath"));
  876. if (!pNames || !dwNumPrinters)
  877. {
  878. return NULL;
  879. }
  880. if (!lpcwstrPath)
  881. {
  882. return NULL;
  883. }
  884. for (dw = 0; dw < dwNumPrinters; dw++)
  885. {
  886. if (!lstrcmpi (pNames[dw].lpcwstrPath, lpcwstrPath))
  887. {
  888. return pNames[dw].lpcwstrDisplayName;
  889. }
  890. }
  891. return NULL;
  892. } // FindPrinterNameFromPath
  893. LPCWSTR
  894. FindPrinterPathFromName (
  895. PPRINTER_NAMES pNames,
  896. DWORD dwNumPrinters,
  897. LPCWSTR lpcwstrName
  898. )
  899. {
  900. DWORD dw;
  901. DEBUG_FUNCTION_NAME(TEXT("FindPrinterPathFromName"));
  902. if (!pNames || !dwNumPrinters)
  903. {
  904. return NULL;
  905. }
  906. if (!lpcwstrName)
  907. {
  908. return NULL;
  909. }
  910. for (dw = 0; dw < dwNumPrinters; dw++)
  911. {
  912. if (!lstrcmpi (pNames[dw].lpcwstrDisplayName, lpcwstrName))
  913. {
  914. return pNames[dw].lpcwstrPath;
  915. }
  916. }
  917. return NULL;
  918. } // FindPrinterPathFromName
  919. #endif // UNICODE
  920. BOOL
  921. VerifyPrinterIsOnline (
  922. LPCTSTR lpctstrPrinterName
  923. )
  924. /*++
  925. Routine name : VerifyPrinterIsOnline
  926. Routine description:
  927. Verifies a printer is online and shared
  928. Author:
  929. Eran Yariv (EranY), Apr, 2001
  930. Arguments:
  931. lpctstrPrinterName [in] - Printer name
  932. Return Value:
  933. TRUE if printer is online and shared, FALSE otherwise.
  934. --*/
  935. {
  936. HANDLE hPrinter = NULL;
  937. PRINTER_DEFAULTS pd = {0};
  938. DEBUG_FUNCTION_NAME(TEXT("VerifyPrinterIsOnline"));
  939. Assert (lpctstrPrinterName);
  940. //
  941. // According to Mark Lawrence (NT PRINT), only by opening the printer in admistrator mode, we actually hit the wire.
  942. //
  943. pd.DesiredAccess = PRINTER_ACCESS_ADMINISTER;
  944. if (!OpenPrinter ((LPTSTR)lpctstrPrinterName,
  945. &hPrinter,
  946. &pd))
  947. {
  948. DWORD dwRes = GetLastError ();
  949. if (ERROR_ACCESS_DENIED == dwRes)
  950. {
  951. //
  952. // Printer is there - we just can't admin it.
  953. //
  954. DebugPrintEx(
  955. DEBUG_MSG,
  956. TEXT("OpenPrinter(%s) failed with ERROR_ACCESS_DENIED - Printer is there - we just can't admin it"),
  957. lpctstrPrinterName);
  958. return TRUE;
  959. }
  960. if (ERROR_INVALID_PRINTER_NAME == dwRes)
  961. {
  962. //
  963. // Printer is deleted
  964. //
  965. DebugPrintEx(
  966. DEBUG_ERR,
  967. TEXT("OpenPrinter(%s) failed with ERROR_INVALID_PRINTER_NAME - Printer is deleted"),
  968. lpctstrPrinterName);
  969. return FALSE;
  970. }
  971. if (RPC_S_SERVER_UNAVAILABLE == dwRes)
  972. {
  973. //
  974. // Printer is not shared / server is unreachable
  975. //
  976. DebugPrintEx(
  977. DEBUG_ERR,
  978. TEXT("OpenPrinter(%s) failed with RPC_SERVER_UNAVAILABLE - Printer is not shared / server is unreachable"),
  979. lpctstrPrinterName);
  980. return FALSE;
  981. }
  982. else
  983. {
  984. //
  985. // Any other error - assume printer is not valid
  986. //
  987. DebugPrintEx(
  988. DEBUG_ERR,
  989. TEXT("OpenPrinter(%s) failed with %ld - assuming printer is not valid"),
  990. lpctstrPrinterName,
  991. dwRes);
  992. return FALSE;
  993. }
  994. }
  995. //
  996. // Printer succesfully opened - it's online
  997. //
  998. DebugPrintEx(
  999. DEBUG_MSG,
  1000. TEXT("OpenPrinter(%s) succeeded - Printer is there"),
  1001. lpctstrPrinterName);
  1002. ClosePrinter (hPrinter);
  1003. return TRUE;
  1004. } // VerifyPrinterIsOnline
  1005. VOID
  1006. FaxPrinterProperty(DWORD dwPage)
  1007. /*++
  1008. Routine name : FaxPrinterProperty
  1009. Routine description:
  1010. Opens fax printer properties sheet
  1011. Arguments:
  1012. dwPage [in] - Initial page number
  1013. Return Value:
  1014. none
  1015. --*/
  1016. {
  1017. HWND hWndFaxMon = NULL;
  1018. DEBUG_FUNCTION_NAME(TEXT("FaxPrinterProperty"));
  1019. hWndFaxMon = FindWindow(FAXSTAT_WINCLASS, NULL);
  1020. if (hWndFaxMon)
  1021. {
  1022. SetForegroundWindow(hWndFaxMon);
  1023. SendMessage(hWndFaxMon, WM_FAXSTAT_PRINTER_PROPERTY, dwPage, 0);
  1024. }
  1025. else
  1026. {
  1027. DebugPrintEx(DEBUG_ERR, TEXT("FindWindow(FAXSTAT_WINCLASS) failed with %d"), GetLastError());
  1028. }
  1029. } // FaxPrinterProperty
  1030. DWORD
  1031. SetLocalFaxPrinterSharing (
  1032. BOOL bShared
  1033. )
  1034. /*++
  1035. Routine name : SetLocalFaxPrinterSharing
  1036. Routine description:
  1037. Shares or un-shares the local fax printer
  1038. Author:
  1039. Eran Yariv (EranY), Jul, 2001
  1040. Arguments:
  1041. bShared [in] - Share the printer?
  1042. Return Value:
  1043. Standard Win32 error code
  1044. --*/
  1045. {
  1046. TCHAR tszFaxPrinterName[MAX_PATH *3];
  1047. HANDLE hPrinter = NULL;
  1048. BYTE aBuf[4096];
  1049. PRINTER_INFO_2 *pInfo = (PRINTER_INFO_2 *)aBuf;
  1050. PRINTER_DEFAULTS pd = {0};
  1051. DWORD dwRequiredSize;
  1052. DWORD dwRes = ERROR_SUCCESS;
  1053. DEBUG_FUNCTION_NAME(TEXT("SetLocalFaxPrinterSharing"));
  1054. if (!GetFirstLocalFaxPrinterName (tszFaxPrinterName, ARR_SIZE(tszFaxPrinterName)))
  1055. {
  1056. dwRes = GetLastError ();
  1057. DebugPrintEx(DEBUG_ERR, TEXT("GetFirstLocalFaxPrinterName failed with %d"), dwRes);
  1058. return dwRes;
  1059. }
  1060. pd.DesiredAccess = PRINTER_ALL_ACCESS;
  1061. if (!OpenPrinter (tszFaxPrinterName, &hPrinter, &pd))
  1062. {
  1063. dwRes = GetLastError ();
  1064. DebugPrintEx(DEBUG_ERR, TEXT("OpenPrinter failed with %d"), dwRes);
  1065. return dwRes;
  1066. }
  1067. if (!GetPrinter (hPrinter,
  1068. 2,
  1069. (LPBYTE)pInfo,
  1070. sizeof (aBuf),
  1071. &dwRequiredSize))
  1072. {
  1073. dwRes = GetLastError ();
  1074. if (ERROR_INSUFFICIENT_BUFFER != dwRes)
  1075. {
  1076. //
  1077. // Real error
  1078. //
  1079. DebugPrintEx(DEBUG_ERR, TEXT("GetPrinter failed with %d"), dwRes);
  1080. goto exit;
  1081. }
  1082. pInfo = (PRINTER_INFO_2 *)MemAlloc (dwRequiredSize);
  1083. if (!pInfo)
  1084. {
  1085. dwRes = GetLastError ();
  1086. DebugPrintEx(DEBUG_ERR, TEXT("Failed to allocate %d bytes"), dwRequiredSize);
  1087. goto exit;
  1088. }
  1089. if (!GetPrinter (hPrinter,
  1090. 2,
  1091. (LPBYTE)pInfo,
  1092. dwRequiredSize,
  1093. &dwRequiredSize))
  1094. {
  1095. dwRes = GetLastError ();
  1096. DebugPrintEx(DEBUG_ERR, TEXT("GetPrinter failed with %d"), dwRes);
  1097. goto exit;
  1098. }
  1099. }
  1100. dwRes = ERROR_SUCCESS;
  1101. if (bShared)
  1102. {
  1103. if (pInfo->Attributes & PRINTER_ATTRIBUTE_SHARED)
  1104. {
  1105. //
  1106. // Printer already shared
  1107. //
  1108. goto exit;
  1109. }
  1110. //
  1111. // Set the sharing bit
  1112. //
  1113. pInfo->Attributes |= PRINTER_ATTRIBUTE_SHARED;
  1114. }
  1115. else
  1116. {
  1117. if (!(pInfo->Attributes & PRINTER_ATTRIBUTE_SHARED))
  1118. {
  1119. //
  1120. // Printer already un-shared
  1121. //
  1122. goto exit;
  1123. }
  1124. //
  1125. // Clear the sharing bit
  1126. //
  1127. pInfo->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
  1128. }
  1129. if (!SetPrinter (hPrinter,
  1130. 2,
  1131. (LPBYTE)pInfo,
  1132. 0))
  1133. {
  1134. dwRes = GetLastError ();
  1135. DebugPrintEx(DEBUG_ERR, TEXT("SetPrinter failed with %d"), dwRes);
  1136. goto exit;
  1137. }
  1138. Assert (ERROR_SUCCESS == dwRes);
  1139. exit:
  1140. if (hPrinter)
  1141. {
  1142. ClosePrinter (hPrinter);
  1143. }
  1144. if ((LPBYTE)pInfo != aBuf)
  1145. {
  1146. MemFree (pInfo);
  1147. }
  1148. return dwRes;
  1149. } // SetLocalFaxPrinterSharing
  1150. DWORD
  1151. AddOrVerifyLocalFaxPrinter ()
  1152. /*++
  1153. Routine name : AddOrVerifyLocalFaxPrinter
  1154. Routine description:
  1155. This function verifies a local fax printer is installed.
  1156. If not installed, this function installs one.
  1157. Author:
  1158. Eran Yariv (EranY), June, 2002
  1159. Arguments:
  1160. None.
  1161. Return Value:
  1162. Standard Win32 error code
  1163. --*/
  1164. {
  1165. DWORD dwRes;
  1166. BOOL bLocalFaxPrinterInstalled;
  1167. BOOL bFaxInstalled;
  1168. DEBUG_FUNCTION_NAME(TEXT("AddOrVerifyLocalFaxPrinter"));
  1169. dwRes = IsFaxInstalled (&bFaxInstalled);
  1170. if (ERROR_SUCCESS != dwRes)
  1171. {
  1172. return dwRes;
  1173. }
  1174. if (!bFaxInstalled)
  1175. {
  1176. //
  1177. // The fax product (optional component) is not installed on the system.
  1178. // Bail out here
  1179. //
  1180. return ERROR_SUCCESS;
  1181. }
  1182. dwRes = IsLocalFaxPrinterInstalled(&bLocalFaxPrinterInstalled);
  1183. if (ERROR_SUCCESS != dwRes)
  1184. {
  1185. //
  1186. // Can't really tell if local fax printer is installed.
  1187. // Better install anyway, just to be on the safe side.
  1188. //
  1189. DebugPrintEx(
  1190. DEBUG_ERR,
  1191. TEXT("IsLocalFaxPrinterInstalled failed with %ld"),
  1192. dwRes);
  1193. bLocalFaxPrinterInstalled = FALSE;
  1194. }
  1195. if (bLocalFaxPrinterInstalled)
  1196. {
  1197. //
  1198. // Nothing more to do here
  1199. //
  1200. return ERROR_SUCCESS;
  1201. }
  1202. dwRes = AddLocalFaxPrinter (FAX_PRINTER_NAME, NULL);
  1203. if (ERROR_SUCCESS != dwRes)
  1204. {
  1205. DebugPrintEx(
  1206. DEBUG_ERR,
  1207. TEXT("AddLocalFaxPrinter failed with %ld"),
  1208. dwRes);
  1209. }
  1210. return dwRes;
  1211. } // AddOrVerifyLocalFaxPrinter