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.

1116 lines
34 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "printer.h"
  4. #include "copy.h"
  5. #include "ids.h"
  6. typedef struct
  7. {
  8. UINT uAction;
  9. LPTSTR lpBuf1;
  10. LPTSTR lpBuf2;
  11. } PRINTERS_RUNDLL_INFO, *LPPRI;
  12. // forward prototypes
  13. void Printer_OpenMe(LPCTSTR pName, LPCTSTR pServer, BOOL fModal);
  14. void Printers_ProcessCommand(HWND hwndStub, LPPRI lpPRI, BOOL fModal);
  15. TCHAR const c_szPrintersGetCommand_RunDLL[] = TEXT("SHELL32,PrintersGetCommand_RunDLL");
  16. //
  17. // if uAction IS NOT MSP_NEWDRIVER then:
  18. // installs a printer (uAction). If successful, notifies the shell and
  19. // returns a pidl to the printer. ILFree() is callers responsibility.
  20. // otherwise, if uAction IS MSP_NEWDRIVER then:
  21. // installs a printer driver (uAction). If successful, fills the new
  22. // driver's name into pszPrinter (ASSUMED >= MAXNAMELEN).
  23. // Always returns NULL.
  24. // if uAction is MSP_TESTPAGEPARTIALPROMPT then:
  25. // executes the test page code
  26. // Always returns NULL.
  27. //
  28. LPITEMIDLIST Printers_PrinterSetup(HWND hwnd, UINT uAction, LPTSTR pszPrinter, DWORD cchBufSize, LPCTSTR pszServer)
  29. {
  30. LPITEMIDLIST pidl = NULL;
  31. TCHAR szPrinter[MAXNAMELENBUFFER];
  32. DWORD cchBufLen;
  33. // HACK! This hack is related to BUG #272207
  34. // This function is called from Printers_DeletePrinter for
  35. // printer deletion and this case we should not check
  36. // for REST_NOPRINTERADD restriction. -LazarI
  37. if (MSP_NEWPRINTER == uAction ||
  38. MSP_NETPRINTER == uAction ||
  39. MSP_NEWPRINTER_MODELESS == uAction)
  40. {
  41. if (SHIsRestricted(hwnd, REST_NOPRINTERADD))
  42. {
  43. return NULL;
  44. }
  45. }
  46. cchBufLen = ARRAYSIZE(szPrinter);
  47. if (pszPrinter)
  48. StringCchCopy(szPrinter, ARRAYSIZE(szPrinter), pszPrinter);
  49. else
  50. szPrinter[0] = 0;
  51. // We don't have to worry about PrinterSetup failing due to the
  52. // output buffer being too small. It's the right size (MAXNAMELENBUFFER)
  53. if (bPrinterSetup(hwnd, LOWORD(uAction), cchBufLen, szPrinter, &cchBufLen, pszServer))
  54. {
  55. if (uAction == MSP_NEWDRIVER)
  56. {
  57. StringCchCopy(pszPrinter, cchBufSize, szPrinter);
  58. }
  59. else if (uAction == MSP_TESTPAGEPARTIALPROMPT)
  60. {
  61. // nothing to do for this case
  62. }
  63. else if (uAction == MSP_REMOVEPRINTER || uAction == MSP_NEWPRINTER_MODELESS || uAction == MSP_REMOVENETPRINTER)
  64. {
  65. // a bit ugly, but we need to pass back success for this case
  66. pidl = (LPITEMIDLIST)TRUE;
  67. }
  68. else
  69. {
  70. // do not validate the printer PIDL here because the validation mechanism in ParseDisplayName
  71. // is using the folder cache and since we just added it may still not be in the folder cache,
  72. // and we fail, although this a valid local printer/connection already.
  73. ParsePrinterNameEx(szPrinter, &pidl, TRUE, 0, 0);
  74. }
  75. }
  76. return pidl;
  77. }
  78. SHSTDAPI_(BOOL) SHInvokePrinterCommand(
  79. IN HWND hwnd,
  80. IN UINT uAction,
  81. IN LPCTSTR lpBuf1,
  82. IN LPCTSTR lpBuf2,
  83. IN BOOL fModal)
  84. {
  85. PRINTERS_RUNDLL_INFO PRI;
  86. PRI.uAction = uAction;
  87. PRI.lpBuf1 = (LPTSTR)lpBuf1;
  88. PRI.lpBuf2 = (LPTSTR)lpBuf2;
  89. Printers_ProcessCommand(hwnd, &PRI, fModal);
  90. return TRUE;
  91. }
  92. SHSTDAPI_(BOOL)
  93. SHInvokePrinterCommandA(
  94. IN HWND hwnd,
  95. IN UINT uAction,
  96. IN LPCSTR lpBuf1, OPTIONAL
  97. IN LPCSTR lpBuf2, OPTIONAL
  98. IN BOOL fModal)
  99. {
  100. WCHAR szBuf1[MAX_PATH];
  101. WCHAR szBuf2[MAX_PATH];
  102. BOOL bSuccess = TRUE;
  103. if (bSuccess && lpBuf1)
  104. {
  105. bSuccess = (MultiByteToWideChar(CP_ACP, 0, lpBuf1, -1, szBuf1, SIZECHARS(szBuf1)) > 0);
  106. lpBuf1 = bSuccess ? (LPCSTR)szBuf1 : NULL;
  107. }
  108. if (bSuccess && lpBuf2)
  109. {
  110. bSuccess = (MultiByteToWideChar(CP_ACP, 0, lpBuf2, -1, szBuf2, SIZECHARS(szBuf2)) > 0);
  111. lpBuf2 = bSuccess ? (LPCSTR)szBuf2 : NULL;
  112. }
  113. if (bSuccess)
  114. {
  115. bSuccess = SHInvokePrinterCommand(hwnd, uAction, (LPCWSTR)lpBuf1, (LPCWSTR)lpBuf2, fModal);
  116. }
  117. return bSuccess;
  118. }
  119. void WINAPI PrintersGetCommand_RunDLL_Common(HWND hwndStub, HINSTANCE hAppInstance, LPTSTR lpszCmdLine, int nCmdShow)
  120. {
  121. PRINTERS_RUNDLL_INFO PRI;
  122. UINT cchBuf1;
  123. UINT cchBuf2;
  124. LPTSTR lpComma;
  125. LPTSTR lpCommaNext;
  126. lpComma = StrChr(lpszCmdLine,TEXT(','));
  127. if (lpComma == NULL)
  128. {
  129. goto BadCmdLine;
  130. }
  131. *lpComma = TEXT('\0'); // Terminate it here
  132. PRI.uAction = StrToLong(lpszCmdLine);
  133. lpCommaNext = StrChr(lpComma+1,TEXT(','));
  134. if (lpCommaNext == NULL)
  135. {
  136. goto BadCmdLine;
  137. }
  138. *lpCommaNext = TEXT('\0'); // Terminate it here
  139. cchBuf1 = StrToLong(lpComma+1);
  140. lpComma = lpCommaNext;
  141. lpCommaNext = StrChr(lpComma+1,TEXT(','));
  142. if (lpCommaNext == NULL)
  143. {
  144. goto BadCmdLine;
  145. }
  146. *lpCommaNext = TEXT('\0'); // Terminate it here
  147. cchBuf2 = StrToLong(lpComma+1);
  148. lpComma = lpCommaNext;
  149. PRI.lpBuf1 = lpComma+1; // Just past the comma
  150. //
  151. // Make sure cchBuf1 & cchBuf2 are correct which means that the length
  152. // of the remainder of the string should be either equal to cchBuf1 if
  153. // cchBuf2 is equal to zero, OR equal to (cchBuf1 + cchBuf2 + 1) if
  154. // cchBuf2 is not equal to zero.
  155. //
  156. if (lstrlen(PRI.lpBuf1) != (int)(cchBuf1 + ((!!cchBuf2) * (cchBuf2 + 1))))
  157. {
  158. goto BadCmdLine;
  159. }
  160. *(PRI.lpBuf1+cchBuf1) = '\0';
  161. if (cchBuf2 == 0)
  162. {
  163. PRI.lpBuf2 = NULL;
  164. }
  165. else
  166. {
  167. PRI.lpBuf2 = PRI.lpBuf1+cchBuf1+1;
  168. }
  169. // Make this modal.
  170. Printers_ProcessCommand(hwndStub, &PRI, TRUE);
  171. return;
  172. BadCmdLine:
  173. DebugMsg(DM_ERROR, TEXT("pgc_rd: bad command line: %s"), lpszCmdLine);
  174. return;
  175. }
  176. void WINAPI PrintersGetCommand_RunDLL(HWND hwndStub, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
  177. {
  178. int iLen;
  179. HRESULT hrInit = SHOleInitialize(0);
  180. if (lpszCmdLine)
  181. {
  182. //
  183. // Call WideCharToMultiByte to properly calculate the destination buffer length.
  184. //
  185. iLen = MultiByteToWideChar(CP_ACP, 0, lpszCmdLine, -1, NULL, 0);
  186. //
  187. // MultiByteToWideChar returns zero if the conversion fails.
  188. //
  189. if (iLen > 0)
  190. {
  191. LPWSTR lpwszCmdLine = (LPWSTR)LocalAlloc(LPTR, iLen * sizeof(WCHAR));
  192. //
  193. // Check if LocalAlloc has succeeded.
  194. //
  195. if (lpwszCmdLine)
  196. {
  197. iLen = MultiByteToWideChar(CP_ACP, 0, lpszCmdLine, -1, lpwszCmdLine, iLen);
  198. //
  199. // MultiByteToWideChar returns zero if the conversion fails.
  200. //
  201. if (iLen > 0)
  202. {
  203. PrintersGetCommand_RunDLL_Common(hwndStub,
  204. hAppInstance,
  205. lpwszCmdLine,
  206. nCmdShow);
  207. }
  208. LocalFree(lpwszCmdLine);
  209. }
  210. }
  211. }
  212. SHOleUninitialize(hrInit);
  213. }
  214. void WINAPI PrintersGetCommand_RunDLLW(HWND hwndStub, HINSTANCE hAppInstance, LPWSTR lpwszCmdLine, int nCmdShow)
  215. {
  216. PrintersGetCommand_RunDLL_Common( hwndStub,
  217. hAppInstance,
  218. lpwszCmdLine,
  219. nCmdShow );
  220. }
  221. static void
  222. HandleOpenPrinter(HWND hwnd, LPCTSTR pszPrinter, BOOL fModal, BOOL bConnect)
  223. {
  224. BOOL bPrinterOK = FALSE;
  225. DWORD dwError = ERROR_SUCCESS;
  226. TCHAR szPrinter[MAXNAMELENBUFFER];
  227. HANDLE hPrinter = NULL;
  228. LPITEMIDLIST pidl = NULL;
  229. PRINTER_INFO_2 *pPrinter = NULL;
  230. // we need to open the printer and get the real printer name in case
  231. // the passed in printer name is a sharename
  232. lstrcpyn(szPrinter, pszPrinter, ARRAYSIZE(szPrinter));
  233. hPrinter = Printer_OpenPrinter(szPrinter);
  234. if (hPrinter)
  235. {
  236. pPrinter = (PRINTER_INFO_2 *)Printer_GetPrinterInfo(hPrinter, 2);
  237. if (pPrinter)
  238. {
  239. if (pPrinter->pPrinterName && pPrinter->pPrinterName[0])
  240. {
  241. // copy the real printer name
  242. bPrinterOK = TRUE;
  243. lstrcpyn(szPrinter, pPrinter->pPrinterName, ARRAYSIZE(szPrinter));
  244. }
  245. LocalFree((HLOCAL)pPrinter);
  246. }
  247. else
  248. {
  249. // save last error
  250. dwError = GetLastError();
  251. }
  252. Printer_ClosePrinter(hPrinter);
  253. }
  254. else
  255. {
  256. // save last error
  257. dwError = GetLastError();
  258. }
  259. if (bPrinterOK)
  260. {
  261. if (bConnect)
  262. {
  263. // if the printer is not installed then we'll silently install it
  264. // since this is what most users will expect.
  265. if (FAILED(ParsePrinterName(szPrinter, &pidl)))
  266. {
  267. // connect....
  268. pidl = Printers_PrinterSetup(hwnd, MSP_NETPRINTER, szPrinter, 0, NULL);
  269. if (pidl)
  270. {
  271. // get the real printer name from the printer's folder...
  272. SHGetNameAndFlags(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szPrinter, ARRAYSIZE(szPrinter), NULL);
  273. ILFree(pidl);
  274. }
  275. else
  276. {
  277. // failed to install the printer (it shows UI, so we shouldn't)
  278. bPrinterOK = FALSE;
  279. }
  280. }
  281. else
  282. {
  283. // the printer is already installed
  284. ILFree(pidl);
  285. }
  286. }
  287. if (bPrinterOK)
  288. {
  289. Printer_OpenMe(szPrinter, NULL, fModal);
  290. }
  291. }
  292. else
  293. {
  294. // something else failed -- show up an error message
  295. ShowErrorMessageSC(NULL, NULL, hwnd, NULL, NULL, MB_OK|MB_ICONEXCLAMATION, dwError);
  296. }
  297. }
  298. /********************************************************************
  299. lpPRI structure description based on uAction.
  300. uAction lpBuf1 lpBuf2
  301. OPEN, printer, server
  302. PROPERTIES, printer, SheetName
  303. NETINSTALL, printer,
  304. NETINSTALLLINK, printer, target directory to create link
  305. OPENNETPRN, printer,
  306. TESTPAGE printer
  307. ********************************************************************/
  308. void Printers_ProcessCommand(HWND hwndStub, LPPRI lpPRI, BOOL fModal)
  309. {
  310. switch (lpPRI->uAction)
  311. {
  312. case PRINTACTION_OPEN:
  313. if (!lstrcmpi(lpPRI->lpBuf1, c_szNewObject))
  314. {
  315. Printers_PrinterSetup(hwndStub, MSP_NEWPRINTER_MODELESS,
  316. lpPRI->lpBuf1, 0, lpPRI->lpBuf2);
  317. }
  318. else
  319. {
  320. HandleOpenPrinter(hwndStub, lpPRI->lpBuf1, fModal, FALSE);
  321. }
  322. break;
  323. case PRINTACTION_SERVERPROPERTIES:
  324. {
  325. LPCTSTR pszServer = (LPTSTR)(lpPRI->lpBuf1);
  326. // we should never get called with c_szNewObject
  327. ASSERT(lstrcmpi(lpPRI->lpBuf1, c_szNewObject));
  328. vServerPropPages(hwndStub, pszServer, SW_SHOWNORMAL, 0);
  329. break;
  330. }
  331. case PRINTACTION_DOCUMENTDEFAULTS:
  332. {
  333. // we should never get called with c_szNewObject
  334. ASSERT(lstrcmpi(lpPRI->lpBuf1, c_szNewObject));
  335. vDocumentDefaults(hwndStub, lpPRI->lpBuf1, SW_SHOWNORMAL, (LPARAM)(lpPRI->lpBuf2));
  336. break;
  337. }
  338. case PRINTACTION_PROPERTIES:
  339. {
  340. // we should never get called with c_szNewObject
  341. ASSERT(lstrcmpi(lpPRI->lpBuf1, c_szNewObject));
  342. vPrinterPropPages(hwndStub, lpPRI->lpBuf1, SW_SHOWNORMAL, (LPARAM)(lpPRI->lpBuf2));
  343. break;
  344. }
  345. case PRINTACTION_NETINSTALLLINK:
  346. case PRINTACTION_NETINSTALL:
  347. {
  348. LPITEMIDLIST pidl = Printers_PrinterSetup(hwndStub, MSP_NETPRINTER, lpPRI->lpBuf1, 0, NULL);
  349. if (pidl)
  350. {
  351. if (lpPRI->uAction == PRINTACTION_NETINSTALLLINK)
  352. {
  353. IDataObject *pdtobj;
  354. if (SUCCEEDED(SHGetUIObjectFromFullPIDL(pidl, NULL, IID_PPV_ARG(IDataObject, &pdtobj))))
  355. {
  356. SHCreateLinks(hwndStub, lpPRI->lpBuf2, pdtobj, SHCL_USETEMPLATE, NULL);
  357. pdtobj->lpVtbl->Release(pdtobj);
  358. }
  359. }
  360. ILFree(pidl);
  361. }
  362. break;
  363. }
  364. case PRINTACTION_OPENNETPRN:
  365. {
  366. HandleOpenPrinter(hwndStub, lpPRI->lpBuf1, fModal, TRUE);
  367. break;
  368. } // case PRINTACTION_OPENNETPRN
  369. case PRINTACTION_TESTPAGE:
  370. Printers_PrinterSetup(hwndStub, MSP_TESTPAGEPARTIALPROMPT,
  371. lpPRI->lpBuf1, 0, NULL);
  372. break;
  373. default:
  374. DebugMsg(TF_WARNING, TEXT("PrintersGetCommand_RunDLL() received unrecognized uAction %d"), lpPRI->uAction);
  375. break;
  376. }
  377. }
  378. void Printer_OpenMe(LPCTSTR pName, LPCTSTR pServer, BOOL fModal)
  379. {
  380. BOOL fOpened = FALSE;
  381. HKEY hkeyPrn;
  382. TCHAR buf[50+MAXNAMELEN];
  383. StringCchPrintf(buf, ARRAYSIZE(buf), TEXT("Printers\\%s"), pName);
  384. if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, buf, &hkeyPrn))
  385. {
  386. SHELLEXECUTEINFO sei =
  387. {
  388. SIZEOF(SHELLEXECUTEINFO),
  389. SEE_MASK_CLASSKEY | SEE_MASK_FLAG_NO_UI, // fMask
  390. NULL, // hwnd - queue view should not be modal on the printer's folder, make it top level
  391. NULL, // lpVerb
  392. pName, // lpFile
  393. NULL, // lpParameters
  394. NULL, // lpDirectory
  395. SW_SHOWNORMAL, // nShow
  396. NULL, // hInstApp
  397. NULL, // lpIDList
  398. NULL, // lpClass
  399. hkeyPrn, // hkeyClass
  400. 0, // dwHotKey
  401. NULL // hIcon
  402. };
  403. fOpened = ShellExecuteEx(&sei);
  404. RegCloseKey(hkeyPrn);
  405. }
  406. if (!fOpened)
  407. {
  408. vQueueCreate(NULL, pName, SW_SHOWNORMAL, (LPARAM)fModal);
  409. }
  410. }
  411. //
  412. // Arguments:
  413. // pidl -- (absolute) pidl to the object of interest
  414. //
  415. // Return '"""<Printer Name>""" """<Driver Name>""" """<Path>"""' if success,
  416. // NULL if failure
  417. //
  418. // We need """ because shlexec strips the outer quotes and converts "" to "
  419. //
  420. UINT Printer_GetPrinterInfoFromPidl(LPCITEMIDLIST pidl, LPTSTR *plpParms)
  421. {
  422. LPTSTR lpBuffer = NULL;
  423. UINT uErr = ERROR_NOT_ENOUGH_MEMORY;
  424. HANDLE hPrinter;
  425. TCHAR szPrinter[MAXNAMELENBUFFER];
  426. SHGetNameAndFlags(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szPrinter, ARRAYSIZE(szPrinter), NULL);
  427. hPrinter = Printer_OpenPrinter(szPrinter);
  428. if (NULL == hPrinter)
  429. {
  430. // fallback to the full name in case this was as \\server\share
  431. // printer drop target
  432. SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPrinter, ARRAYSIZE(szPrinter), NULL);
  433. hPrinter = Printer_OpenPrinter(szPrinter);
  434. }
  435. if (hPrinter)
  436. {
  437. PRINTER_INFO_5 *pPrinter;
  438. pPrinter = Printer_GetPrinterInfo(hPrinter, 5);
  439. if (pPrinter)
  440. {
  441. DRIVER_INFO_2 *pPrinterDriver;
  442. pPrinterDriver = Printer_GetPrinterDriver(hPrinter, 2);
  443. if (pPrinterDriver)
  444. {
  445. LPTSTR lpDriverName = PathFindFileName(pPrinterDriver->pDriverPath);
  446. DWORD cchBufSize = 2+lstrlen(szPrinter)+1+
  447. 2+lstrlen(lpDriverName)+1+
  448. 2+lstrlen(pPrinter->pPortName)+1;
  449. lpBuffer = (void*)LocalAlloc(LPTR, cchBufSize * SIZEOF(TCHAR));
  450. if (lpBuffer)
  451. {
  452. StringCchPrintf(lpBuffer, cchBufSize, TEXT("\"%s\" \"%s\" \"%s\""),
  453. szPrinter, lpDriverName, pPrinter->pPortName);
  454. uErr = ERROR_SUCCESS;
  455. }
  456. LocalFree((HLOCAL)pPrinterDriver);
  457. }
  458. LocalFree((HLOCAL)pPrinter);
  459. }
  460. Printer_ClosePrinter(hPrinter);
  461. }
  462. else
  463. {
  464. // HACK: special case this error return in calling function,
  465. // as we need a special error message
  466. uErr = ERROR_SUCCESS;
  467. }
  468. *plpParms = lpBuffer;
  469. return(uErr);
  470. }
  471. //
  472. // Arguments:
  473. // hwndParent -- Specifies the parent window.
  474. // szFilePath -- The file to printed.
  475. //
  476. void Printer_PrintFile(HWND hWnd, LPCTSTR pszFilePath, LPCITEMIDLIST pidl)
  477. {
  478. UINT uErr;
  479. LPTSTR lpParms = NULL;
  480. BOOL bTryPrintVerb = TRUE;
  481. BOOL bShowError = FALSE;
  482. LPITEMIDLIST pidlFull = NULL;
  483. SHELLEXECUTEINFO ExecInfo = {0};
  484. uErr = Printer_GetPrinterInfoFromPidl(pidl, &lpParms);
  485. if (uErr != ERROR_SUCCESS)
  486. {
  487. bShowError = TRUE;
  488. }
  489. if (!bShowError && !lpParms)
  490. {
  491. // If you rename a printer and then try to use a link to that
  492. // printer, we hit this case. Also, if you get a link to a printer
  493. // on another computer, we'll likely hit this case.
  494. ShellMessageBox(HINST_THISDLL, hWnd,
  495. MAKEINTRESOURCE(IDS_CANTPRINT),
  496. MAKEINTRESOURCE(IDS_PRINTERS),
  497. MB_OK|MB_ICONEXCLAMATION);
  498. return;
  499. }
  500. //
  501. // Get the context menu for the file
  502. //
  503. pidlFull = ILCreateFromPath( pszFilePath );
  504. if (!bShowError && pidlFull)
  505. {
  506. //
  507. // Try the "printto" verb first...
  508. //
  509. ExecInfo.cbSize = sizeof(ExecInfo);
  510. ExecInfo.fMask = SEE_MASK_UNICODE | SEE_MASK_INVOKEIDLIST |
  511. SEE_MASK_IDLIST | SEE_MASK_FLAG_NO_UI;
  512. ExecInfo.hwnd = hWnd;
  513. ExecInfo.lpVerb = c_szPrintTo;
  514. ExecInfo.lpParameters = lpParms;
  515. ExecInfo.nShow = SW_SHOWNORMAL;
  516. ExecInfo.lpIDList = pidlFull;
  517. if (!ShellExecuteEx( &ExecInfo ))
  518. {
  519. //
  520. // Since we can't print specifying the printer name (i.e., printto),
  521. // our next option is to print to the default printer. However,
  522. // that might not be the printer the user dragged the files onto
  523. // so check here and let the user set the desired printer to be
  524. // the default if they want...
  525. //
  526. TCHAR szPrinter[MAXNAMELENBUFFER];
  527. SHGetNameAndFlags(pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, szPrinter, ARRAYSIZE(szPrinter), NULL);
  528. if (!IsDefaultPrinter(szPrinter, 0))
  529. {
  530. //
  531. // this isn't the default printer, ask first
  532. //
  533. if (IDYES==ShellMessageBox(
  534. HINST_THISDLL, GetTopLevelAncestor(hWnd),
  535. MAKEINTRESOURCE(IDS_CHANGEDEFAULTPRINTER),
  536. MAKEINTRESOURCE(IDS_PRINTERS),
  537. MB_YESNO|MB_ICONEXCLAMATION))
  538. {
  539. Printer_SetAsDefault(szPrinter);
  540. }
  541. else
  542. {
  543. bTryPrintVerb = FALSE;
  544. }
  545. }
  546. if (bTryPrintVerb)
  547. {
  548. //
  549. // Try the "print" verb
  550. //
  551. ExecInfo.lpVerb = c_szPrint;
  552. if (!ShellExecuteEx( &ExecInfo ))
  553. {
  554. uErr = GetLastError();
  555. bShowError = TRUE;
  556. }
  557. }
  558. }
  559. ILFree(pidlFull);
  560. }
  561. if (lpParms)
  562. LocalFree((HLOCAL)lpParms);
  563. if (bShowError)
  564. {
  565. ShellMessageBox(HINST_THISDLL, hWnd,
  566. MAKEINTRESOURCE(IDS_ERRORPRINTING),
  567. MAKEINTRESOURCE(IDS_PRINTERS),
  568. MB_OK|MB_ICONEXCLAMATION);
  569. }
  570. }
  571. BOOL Printer_ModifyPrinter(LPCTSTR lpszPrinterName, DWORD dwCommand)
  572. {
  573. HANDLE hPrinter = Printer_OpenPrinterAdmin(lpszPrinterName);
  574. BOOL fRet = FALSE;
  575. if (hPrinter)
  576. {
  577. fRet = SetPrinter(hPrinter, 0, NULL, dwCommand);
  578. Printer_ClosePrinter(hPrinter);
  579. }
  580. return fRet;
  581. }
  582. BOOL IsAvoidAutoDefaultPrinter(LPCTSTR pszPrinter);
  583. // this will find the first printer (if any) and set it as the default
  584. // and inform the user
  585. void Printers_ChooseNewDefault(HWND hwnd)
  586. {
  587. PRINTER_INFO_4 *pPrinters = NULL;
  588. DWORD iPrinter, dwNumPrinters = Printers_EnumPrinters(NULL,
  589. PRINTER_ENUM_LOCAL | PRINTER_ENUM_FAVORITE,
  590. 4,
  591. &pPrinters);
  592. if (dwNumPrinters)
  593. {
  594. if (pPrinters)
  595. {
  596. for (iPrinter = 0 ; iPrinter < dwNumPrinters ; iPrinter++)
  597. {
  598. if (!IsAvoidAutoDefaultPrinter(pPrinters[iPrinter].pPrinterName))
  599. break;
  600. }
  601. if (iPrinter == dwNumPrinters)
  602. {
  603. dwNumPrinters = 0;
  604. }
  605. else
  606. {
  607. Printer_SetAsDefault(pPrinters[iPrinter].pPrinterName);
  608. }
  609. }
  610. else
  611. {
  612. dwNumPrinters = 0;
  613. }
  614. }
  615. // Inform user
  616. if (dwNumPrinters)
  617. {
  618. ShellMessageBox(HINST_THISDLL,
  619. hwnd,
  620. MAKEINTRESOURCE(IDS_DELNEWDEFAULT),
  621. MAKEINTRESOURCE(IDS_PRINTERS),
  622. MB_OK,
  623. pPrinters[iPrinter].pPrinterName);
  624. }
  625. else
  626. {
  627. Printer_SetAsDefault(NULL); // clear the default printer
  628. ShellMessageBox(HINST_THISDLL, hwnd, MAKEINTRESOURCE(IDS_DELNODEFAULT),
  629. MAKEINTRESOURCE(IDS_PRINTERS), MB_OK);
  630. }
  631. if (pPrinters)
  632. LocalFree((HLOCAL)pPrinters);
  633. }
  634. BOOL Printer_SetAsDefault(LPCTSTR lpszPrinterName)
  635. {
  636. TCHAR szDefaultPrinterString[MAX_PATH * 2];
  637. TCHAR szBuffer[MAX_PATH * 2];
  638. if (lpszPrinterName)
  639. {
  640. // Not the default, set it.
  641. if( !GetProfileString( TEXT( "Devices" ), lpszPrinterName, TEXT( "" ), szBuffer, ARRAYSIZE( szBuffer )))
  642. {
  643. return FALSE;
  644. }
  645. StringCchCopy(szDefaultPrinterString, ARRAYSIZE(szDefaultPrinterString), lpszPrinterName);
  646. StringCchCat(szDefaultPrinterString, ARRAYSIZE(szDefaultPrinterString), TEXT( "," ));
  647. StringCchCat(szDefaultPrinterString, ARRAYSIZE(szDefaultPrinterString), szBuffer );
  648. //
  649. // Use the new string for Windows.Device.
  650. //
  651. lpszPrinterName = szDefaultPrinterString;
  652. }
  653. if (!WriteProfileString( TEXT( "Windows" ), TEXT( "Device" ), lpszPrinterName ))
  654. {
  655. return FALSE;
  656. }
  657. // Tell the world and make everyone flash.
  658. SendNotifyMessage( HWND_BROADCAST, WM_WININICHANGE, 0, (LPARAM)TEXT( "Windows" ));
  659. return TRUE;
  660. }
  661. void *Printer_EnumProps(HANDLE hPrinter, DWORD dwLevel, DWORD *lpdwNum,
  662. ENUMPROP lpfnEnum, void *lpData)
  663. {
  664. DWORD dwSize, dwNeeded;
  665. LPBYTE pEnum;
  666. dwSize = 0;
  667. SetLastError(0);
  668. lpfnEnum(lpData, hPrinter, dwLevel, NULL, 0, &dwSize, lpdwNum);
  669. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  670. {
  671. pEnum = NULL;
  672. goto Error1;
  673. }
  674. ASSERT(dwSize < 0x100000L);
  675. pEnum = (void*)LocalAlloc(LPTR, dwSize);
  676. TryAgain:
  677. if (!pEnum)
  678. {
  679. goto Error1;
  680. }
  681. SetLastError(0);
  682. if (!lpfnEnum(lpData, hPrinter, dwLevel, pEnum, dwSize, &dwNeeded, lpdwNum))
  683. {
  684. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  685. {
  686. LPBYTE pTmp;
  687. dwSize = dwNeeded;
  688. pTmp = (void*)LocalReAlloc((HLOCAL)pEnum, dwSize,
  689. LMEM_MOVEABLE|LMEM_ZEROINIT);
  690. if (pTmp)
  691. {
  692. pEnum = pTmp;
  693. goto TryAgain;
  694. }
  695. }
  696. LocalFree((HLOCAL)pEnum);
  697. pEnum = NULL;
  698. }
  699. Error1:
  700. return pEnum;
  701. }
  702. BOOL Printers_EnumPrintersCB(void *lpData, HANDLE hPrinter, DWORD dwLevel,
  703. LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
  704. {
  705. return EnumPrinters(PtrToUlong(lpData), (LPTSTR)hPrinter, dwLevel,
  706. pEnum, dwSize, lpdwNeeded, lpdwNum);
  707. }
  708. DWORD Printers_EnumPrinters(LPCTSTR pszServer, DWORD dwType, DWORD dwLevel, void **ppPrinters)
  709. {
  710. DWORD dwNum = 0L;
  711. //
  712. // If the server is szNULL, pass in NULL, since EnumPrinters expects
  713. // this for the local server.
  714. //
  715. if (pszServer && !pszServer[0])
  716. {
  717. pszServer = NULL;
  718. }
  719. *ppPrinters = Printer_EnumProps((HANDLE)pszServer, dwLevel, &dwNum, Printers_EnumPrintersCB, ULongToPtr(dwType));
  720. if (*ppPrinters==NULL)
  721. {
  722. dwNum = 0;
  723. }
  724. return dwNum;
  725. }
  726. BOOL Printers_FolderEnumPrintersCB(void *lpData, HANDLE hFolder, DWORD dwLevel,
  727. LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
  728. {
  729. return bFolderEnumPrinters(hFolder, (PFOLDER_PRINTER_DATA)pEnum,
  730. dwSize, lpdwNeeded, lpdwNum);
  731. }
  732. DWORD Printers_FolderEnumPrinters(HANDLE hFolder, void **ppPrinters)
  733. {
  734. DWORD dwNum = 0L;
  735. *ppPrinters = Printer_EnumProps(hFolder, 0, &dwNum,
  736. Printers_FolderEnumPrintersCB,
  737. NULL);
  738. if (*ppPrinters==NULL)
  739. {
  740. dwNum=0;
  741. }
  742. return dwNum;
  743. }
  744. BOOL Printers_FolderGetPrinterCB(void *lpData, HANDLE hFolder, DWORD dwLevel,
  745. LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
  746. {
  747. return bFolderGetPrinter(hFolder, (LPCTSTR)lpData, (PFOLDER_PRINTER_DATA)pEnum, dwSize, lpdwNeeded);
  748. }
  749. void *Printer_FolderGetPrinter(HANDLE hFolder, LPCTSTR pszPrinter)
  750. {
  751. return Printer_EnumProps(hFolder, 0, NULL, Printers_FolderGetPrinterCB, (LPVOID)pszPrinter);
  752. }
  753. BOOL Printers_GetPrinterDriverCB(void *lpData, HANDLE hPrinter, DWORD dwLevel,
  754. LPBYTE pEnum, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
  755. {
  756. return GetPrinterDriver(hPrinter, NULL, dwLevel, pEnum, dwSize, lpdwNeeded);
  757. }
  758. void *Printer_GetPrinterDriver(HANDLE hPrinter, DWORD dwLevel)
  759. {
  760. return Printer_EnumProps(hPrinter, dwLevel, NULL, Printers_GetPrinterDriverCB, NULL);
  761. }
  762. ////////////////////////////////////////////////////////////////////////////////
  763. // code moved from prcache.c
  764. //
  765. HANDLE Printer_OpenPrinterAdmin(LPCTSTR lpszPrinterName)
  766. {
  767. HANDLE hPrinter = NULL;
  768. PRINTER_DEFAULTS PrinterDefaults;
  769. PrinterDefaults.pDatatype = NULL;
  770. PrinterDefaults.pDevMode = NULL;
  771. PrinterDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
  772. // PRINTER_READ ? READ_CONTROL
  773. if (!OpenPrinter((LPTSTR)lpszPrinterName, &hPrinter, &PrinterDefaults))
  774. {
  775. hPrinter = NULL; // OpenPrinter may trash hPrinter
  776. }
  777. return(hPrinter);
  778. }
  779. HANDLE Printer_OpenPrinter(LPCTSTR lpszPrinterName)
  780. {
  781. HANDLE hPrinter = NULL;
  782. if (!OpenPrinter((LPTSTR)lpszPrinterName, &hPrinter, NULL))
  783. {
  784. hPrinter = NULL; // OpenPrinter may trash hPrinter
  785. }
  786. return(hPrinter);
  787. }
  788. VOID Printer_ClosePrinter(HANDLE hPrinter)
  789. {
  790. ClosePrinter(hPrinter);
  791. }
  792. BOOL Printers_DeletePrinter(HWND hWnd, LPCTSTR pszFullPrinter, DWORD dwAttributes, LPCTSTR pszServer, BOOL bQuietMode)
  793. {
  794. DWORD dwCommand = MSP_REMOVEPRINTER;
  795. if (SHIsRestricted(hWnd, REST_NOPRINTERDELETE))
  796. return FALSE;
  797. if ((dwAttributes & PRINTER_ATTRIBUTE_NETWORK) && !(dwAttributes & PRINTER_ATTRIBUTE_LOCAL))
  798. {
  799. //
  800. // If it's not local, then it must be a remote connection. Note
  801. // that we can't just check for PRINTER_ATTRIBUTE_NETWORK because
  802. // NT's spooler has 'masq' printers that are local printers
  803. // that masquarade as network printers. Even though they
  804. // are created by connecting to a printer, the have both LOCAL
  805. // and NETWORK bits set.
  806. //
  807. dwCommand = MSP_REMOVENETPRINTER;
  808. }
  809. //
  810. // Don't show the confirmation dialog box if in quiet mode
  811. //
  812. if (!bQuietMode)
  813. {
  814. if (pszServer && pszServer[0])
  815. {
  816. //
  817. // It's a printer on the remote server. (Skip \\ prefix on server.)
  818. //
  819. if (ShellMessageBox(HINST_THISDLL, hWnd,
  820. MAKEINTRESOURCE(IDS_SUREDELETEREMOTE),
  821. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION,
  822. pszFullPrinter, SkipServerSlashes(pszServer)) != IDYES)
  823. {
  824. return FALSE;
  825. }
  826. }
  827. else if (dwAttributes & PRINTER_ATTRIBUTE_NETWORK)
  828. {
  829. TCHAR szScratch[MAXNAMELENBUFFER];
  830. LPTSTR pszPrinter, pszServer;
  831. Printer_SplitFullName(szScratch, ARRAYSIZE(szScratch), pszFullPrinter, &pszServer, &pszPrinter);
  832. if (pszServer && *pszServer)
  833. {
  834. //
  835. // It's a printer connection.
  836. //
  837. if (ShellMessageBox(HINST_THISDLL, hWnd,
  838. MAKEINTRESOURCE(IDS_SUREDELETECONNECTION),
  839. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION,
  840. pszPrinter, SkipServerSlashes(pszServer)) != IDYES)
  841. {
  842. return FALSE;
  843. }
  844. }
  845. else
  846. {
  847. //
  848. // It's a printer connection with a printer name that
  849. // does not have a server name prefix i.e. \\server\printer. This
  850. // is true for the http connected printer, which have printer names
  851. // of the form http://server/printer on NT these printers are
  852. // 'masq' printers. A 'masq' printer is a printer which
  853. // is a local printer acting as network connection.
  854. //
  855. if (ShellMessageBox(HINST_THISDLL, hWnd,
  856. MAKEINTRESOURCE(IDS_SUREDELETECONNECTIONNOSERVERNAME),
  857. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION,
  858. pszPrinter) != IDYES)
  859. {
  860. return FALSE;
  861. }
  862. }
  863. }
  864. else
  865. //
  866. // Neither a remote printer nor a local connection. The final
  867. // upcoming else clause is a local printer.
  868. //
  869. if (ShellMessageBox(HINST_THISDLL, hWnd, MAKEINTRESOURCE(IDS_SUREDELETE),
  870. MAKEINTRESOURCE(IDS_PRINTERS), MB_YESNO|MB_ICONQUESTION, pszFullPrinter)
  871. != IDYES)
  872. {
  873. return FALSE;
  874. }
  875. }
  876. if (CallPrinterCopyHooks(hWnd, PO_DELETE, 0, pszFullPrinter, 0, NULL, 0)
  877. != IDYES)
  878. {
  879. return FALSE;
  880. }
  881. //
  882. // Cast away const. Safe since Printers_PrinterSetup only modifies
  883. // pszPrinter if dwCommand is MSP_NEWDRIVER.
  884. //
  885. return BOOLFROMPTR(Printers_PrinterSetup(hWnd, dwCommand,
  886. (LPTSTR)pszFullPrinter, 0, pszServer));
  887. }
  888. BOOL Printer_GPI2CB(LPVOID lpData, HANDLE hPrinter, DWORD dwLevel,
  889. LPBYTE pBuf, DWORD dwSize, DWORD *lpdwNeeded, DWORD *lpdwNum)
  890. {
  891. return GetPrinter(hPrinter, dwLevel, pBuf, dwSize, lpdwNeeded);
  892. }
  893. //
  894. // Old NT printers don't support the level 5. So we try for the 2 after 5.
  895. // Win96 WILL PROBABLY WANT TO DO THIS TOO!
  896. //
  897. LPPRINTER_INFO_5 Printer_MakePrinterInfo5( HANDLE hPrinter )
  898. {
  899. LPPRINTER_INFO_5 pPI5 = NULL;
  900. DWORD cbPI5 = 0;
  901. DWORD cbName = 0;
  902. DWORD cbPort = 0;
  903. LPPRINTER_INFO_2 pPI2 = Printer_EnumProps(hPrinter, 2, NULL, Printer_GPI2CB, (LPVOID)0);
  904. if (!pPI2)
  905. return NULL;
  906. cbName = (lstrlen(pPI2->pPrinterName)+1) * SIZEOF(TCHAR);
  907. cbPI5 = SIZEOF(PRINTER_INFO_5) + cbName;
  908. //
  909. // Port name may not be supported (e.g., downlevel machines).
  910. //
  911. if (pPI2->pPortName)
  912. {
  913. cbPort = (lstrlen(pPI2->pPortName)+1) * SIZEOF(TCHAR);
  914. cbPI5 += cbPort;
  915. }
  916. pPI5 = (LPPRINTER_INFO_5)LocalAlloc(LPTR, cbPI5);
  917. if (pPI5)
  918. {
  919. ASSERT(pPI5->pPrinterName==NULL); // These should be null for the
  920. ASSERT(pPI5->pPortName==NULL); // no names case
  921. if (pPI2->pPrinterName)
  922. {
  923. pPI5->pPrinterName = (LPTSTR)(pPI5+1);
  924. //
  925. // Use byte-size here.
  926. //
  927. StringCbCopy(pPI5->pPrinterName, cbName, pPI2->pPrinterName);
  928. }
  929. if (pPI2->pPortName)
  930. {
  931. pPI5->pPortName = (LPTSTR)((LPBYTE)(pPI5+1) + cbName);
  932. //
  933. // User byte-size here.
  934. //
  935. StringCbCopy(pPI5->pPortName, cbPort, pPI2->pPortName);
  936. }
  937. pPI5->Attributes = pPI2->Attributes;
  938. pPI5->DeviceNotSelectedTimeout = 0;
  939. pPI5->TransmissionRetryTimeout = 0;
  940. }
  941. LocalFree(pPI2);
  942. return(pPI5);
  943. }
  944. LPVOID Printer_GetPrinterInfo(HANDLE hPrinter, DWORD dwLevel)
  945. {
  946. LPVOID pPrinter = Printer_EnumProps(hPrinter, dwLevel, NULL, Printer_GPI2CB, (LPVOID)0);
  947. //
  948. // Old NT printers don't support the level 5. So we try for the 2 after 5.
  949. // Win96 WILL PROBABLY WANT TO DO THIS TOO!
  950. //
  951. if (!pPrinter && dwLevel == 5)
  952. return(Printer_MakePrinterInfo5(hPrinter));
  953. return pPrinter;
  954. }
  955. LPVOID Printer_GetPrinterInfoStr(LPCTSTR lpszPrinterName, DWORD dwLevel)
  956. {
  957. LPPRINTER_INFO_2 pPI2 = NULL;
  958. HANDLE hPrinter = Printer_OpenPrinter(lpszPrinterName);
  959. if (hPrinter)
  960. {
  961. pPI2 = Printer_GetPrinterInfo(hPrinter, dwLevel);
  962. Printer_ClosePrinter(hPrinter);
  963. }
  964. return pPI2;
  965. }