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.

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