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.

664 lines
16 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. All rights reserved.
  4. Module Name:
  5. addprn.cxx
  6. Abstract:
  7. Add Printer Connection UI
  8. Author:
  9. Steve Kiraly (SteveKi) 10-Feb-1997
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. #include "asyncdlg.hxx"
  15. #include "addprn.hxx"
  16. #include "browse.hxx"
  17. /*++
  18. Name:
  19. PrintUIGetPrinterInformation
  20. Routine Description:
  21. This function gets the information from a connected network printer,
  22. which includes:
  23. 1. The real printer name
  24. 2. The printer comment
  25. 3. The printer location
  26. 4. The printer share name
  27. Arguments:
  28. hPrinter - Handle to a valid printer conenction
  29. pstrPrinterName - Where to place the real printer name
  30. pstrComment - Where to place the comment
  31. pstrLocation - Where to place the location
  32. pstrShareName - Where to place the share name
  33. Return Value:
  34. TRUE the information is extracted.
  35. FALSE if an error occurred.
  36. --*/
  37. BOOL
  38. PrintUIGetPrinterInformation(
  39. IN HANDLE hPrinter,
  40. IN TString *pstrPrinterName,
  41. IN TString *pstrComment,
  42. IN TString *pstrLocation,
  43. IN TString *pstrShareName
  44. )
  45. {
  46. TStatusB bStatus;
  47. bStatus DBGNOCHK = FALSE;
  48. //
  49. // If the printer connection is ok
  50. // name string pointer.
  51. //
  52. if( hPrinter )
  53. {
  54. PPRINTER_INFO_2 pInfo2 = NULL;
  55. DWORD cbInfo2 = 0;
  56. //
  57. // Get the current printer info 2.
  58. //
  59. bStatus DBGCHK = VDataRefresh::bGetPrinter( hPrinter, 2, (PVOID*)&pInfo2, &cbInfo2 );
  60. if( bStatus )
  61. {
  62. if( pstrPrinterName )
  63. bStatus DBGCHK = pstrPrinterName->bUpdate( pInfo2->pPrinterName );
  64. if( pstrLocation )
  65. bStatus DBGCHK = pstrLocation->bUpdate( pInfo2->pLocation );
  66. if( pstrComment )
  67. bStatus DBGCHK = pstrComment->bUpdate( pInfo2->pComment );
  68. if( pstrShareName )
  69. bStatus DBGCHK = pstrShareName->bUpdate( pInfo2->pShareName );
  70. }
  71. //
  72. // Release the printer info 2 structure.
  73. //
  74. FreeMem( pInfo2 );
  75. }
  76. return bStatus;
  77. }
  78. /*++
  79. Name:
  80. PrintUIAddPrinterConnectionUIEx
  81. Routine Description:
  82. This function adds a printer connection on this machine
  83. to the specified printer. This routine will return the real
  84. printer name if the connection is established. Note a printer
  85. connection can be added using the share name, thus this routine
  86. will build the connection and then convert the share name to
  87. the real printer name.
  88. Arguments:
  89. hWnd - Parent window for any error UI.
  90. pszPrinter - Printer name (e.g., "\\test\My HP LaserJet IIISi").
  91. pstrPrinterName - Where to place the real printer name
  92. This is used when a user connects using a share name
  93. but the caller needs the real printer name to set
  94. the default printer. This parameter can be NULL if the
  95. real printer name is not needed.
  96. pstrComment - Where to place the comment
  97. pstrLocation - Where to place the location
  98. pstrShareName - Where to place the share name
  99. Return Value:
  100. TRUE the printer connection was added. FALSE if an error occurred.
  101. --*/
  102. BOOL
  103. PrintUIAddPrinterConnectionUIEx(
  104. IN HWND hwnd,
  105. IN LPCTSTR pszPrinter,
  106. IN TString *pstrPrinterName,
  107. IN TString *pstrComment,
  108. IN TString *pstrLocation,
  109. IN TString *pstrShareName
  110. )
  111. {
  112. DBGMSG( DBG_TRACE, ( "PrintUIAddPrinterConnectionUI\n" ) );
  113. DBGMSG( DBG_TRACE, ( "PrintUIAddPrinterConnectionUI pszPrinter " TSTR "\n", DBGSTR( pszPrinter ) ) );
  114. SPLASSERT( pszPrinter );
  115. BOOL bReturn = FALSE;
  116. BOOL bDummy = FALSE;
  117. HANDLE hPrinter = NULL;
  118. //
  119. // Currently just call the add printer connection UI
  120. //
  121. hPrinter = AddPrinterConnectionUI( hwnd, pszPrinter, &bDummy );
  122. //
  123. // If the connection was built and the called passed a valid printer
  124. // name string pointer. If we cannot fetch the real printer name
  125. // we do not fail this call.
  126. //
  127. if( hPrinter )
  128. {
  129. //
  130. // Extract the printer information
  131. //
  132. PrintUIGetPrinterInformation( hPrinter, pstrPrinterName, pstrComment, pstrLocation, pstrShareName );
  133. //
  134. // Release the printer handle.
  135. //
  136. ClosePrinter( hPrinter );
  137. bReturn = TRUE;
  138. }
  139. return bReturn;
  140. }
  141. /*++
  142. Name:
  143. PrintUIAddPrinterConnectionUI
  144. Routine Description:
  145. This function adds a printer connection on this machine
  146. to the specified printer. This function will bring up the
  147. up progress UI while the printer connection is being added.
  148. Arguments:
  149. hWnd - Parent window for progress UI.
  150. pszPrinter - Printer name (e.g., "\\test\My HP LaserJet IIISi").
  151. bShowConnectionUI - TRUE show connection UI, FALSE do not show connection UI.
  152. Return Value:
  153. TRUE the printer connection was added. FALSE if progress UI was canceled or
  154. the printer connection could not be added.
  155. Note:
  156. The last error is set on failure if the dialog was canceled.
  157. --*/
  158. BOOL
  159. PrintUIAddPrinterConnectionUI(
  160. IN HWND hwnd,
  161. IN LPCTSTR pszPrinter,
  162. IN BOOL bShowConnectionUI
  163. )
  164. {
  165. //
  166. // Assume failure.
  167. //
  168. BOOL bReturn = FALSE;
  169. //
  170. // Allocate the add printer connection data.
  171. //
  172. auto_ptr<TAddPrinterConnectionData> pInfo = new TAddPrinterConnectionData;
  173. //
  174. // If add printer connection data was returned.
  175. //
  176. if( pInfo.get() )
  177. {
  178. pInfo->_strPrinter.bUpdate( pszPrinter );
  179. pInfo->_bShowConnectionUI = bShowConnectionUI;
  180. //
  181. // Create the asynchrnous dialog.
  182. //
  183. TAsyncDlg *pDlg = new TAsyncDlg( hwnd, pInfo.get(), DLG_ASYNC );
  184. if( pDlg )
  185. {
  186. //
  187. // Aquire the refrence lock this will increment the refrence count
  188. // of the async dialog. The refrence lock will then be decremented
  189. // when the reflock fall out of scope.
  190. //
  191. TRefLock<TAsyncDlg> pAsyncDlg( pDlg );
  192. //
  193. // Create the dialog title.
  194. //
  195. TString strTitle;
  196. TCHAR szText[kStrMax+kPrinterBufMax];
  197. UINT nSize = COUNTOF( szText );
  198. strTitle.bLoadString( ghInst, IDS_CONNECTING_TO_PRINTER );
  199. ConstructPrinterFriendlyName( pszPrinter, szText, &nSize );
  200. strTitle.bCat( szText );
  201. //
  202. // Set the dialog title.
  203. //
  204. pDlg->vSetTitle( strTitle );
  205. //
  206. // Display the dialog.
  207. //
  208. INT iRetval = pDlg->bDoModal();
  209. //
  210. // If the dialog exited normally,
  211. // The use did not cancel the dialog then set the return
  212. // value.
  213. //
  214. if( iRetval == IDOK )
  215. {
  216. bReturn = pInfo.get()->_ReturnValue;
  217. }
  218. //
  219. // If the user cancel the dialog set the last error.
  220. //
  221. if( iRetval == IDCANCEL )
  222. {
  223. SetLastError( ERROR_CANCELLED );
  224. }
  225. //
  226. // Release the pinfo stucture to the Asynchronous dialog class.
  227. //
  228. pInfo.release();
  229. }
  230. }
  231. return bReturn;
  232. }
  233. /*++
  234. Name:
  235. PrintUIAddPrinterConnection
  236. Routine Description:
  237. This routine is very similar to the AddPrinterConnection in the clien
  238. side of spooler, however if the users current domain is the same
  239. as the domain name in the printer name then the short printer name is
  240. used. If this routine returns success then the printer new printer
  241. name is returned in pstrConnection.
  242. Arguments:
  243. pszConnection - pointer to full printer connection name (UNC name)
  244. pstrConnection - optional pointer to string object where to return
  245. the new printer name if it was shortened.
  246. Return Value:
  247. TRUE success, FALSE error occurred.
  248. --*/
  249. BOOL
  250. PrintUIAddPrinterConnection(
  251. IN LPCTSTR pszConnection,
  252. IN TString *pstrConnection OPTIONAL
  253. )
  254. {
  255. SPLASSERT( pszConnection );
  256. TStatusB bStatus;
  257. TString strConnection;
  258. //
  259. // Do a quick check to see if the printer name has a minimal potential
  260. // of containing a domain name.
  261. //
  262. if( _tcschr( pszConnection, _T('.') ) )
  263. {
  264. TString strDomainName;
  265. //
  266. // Get the current users domain name, we do not fail if the domain
  267. // name cannot be fetched, just add the connection. Maybe we are not
  268. // logged on to a domain.
  269. //
  270. bStatus DBGCHK = GetDomainName( strDomainName );
  271. //
  272. // Convert the printer domain name to a short name.
  273. //
  274. bStatus DBGCHK = ConvertDomainNameToShortName( pszConnection, strDomainName, strConnection );
  275. //
  276. // Get a pointer to the printer name, the name may have been shortened.
  277. //
  278. if( bStatus )
  279. {
  280. pszConnection = strConnection;
  281. }
  282. }
  283. //
  284. // Display a debug message see what the printer name really is.
  285. //
  286. DBGMSG( DBG_TRACE, ("PrintUIAddPrinterConnection " TSTR "\n", pszConnection ) );
  287. //
  288. // Add the printer connection.
  289. //
  290. bStatus DBGCHK = AddPrinterConnection( const_cast<LPTSTR>( pszConnection ) );
  291. if( bStatus && pstrConnection )
  292. {
  293. //
  294. // Copy back the printer name if a string object pointer was provided.
  295. //
  296. bStatus DBGCHK = pstrConnection->bUpdate( pszConnection );
  297. //
  298. // We were unable to make a copy of the connection string,
  299. // remove the printer connection and fail the call. This
  300. // should never happen.
  301. //
  302. SPLASSERT( bStatus );
  303. if( !bStatus )
  304. {
  305. (VOID)DeletePrinterConnection( const_cast<LPTSTR>( pszConnection ) );
  306. }
  307. }
  308. return bStatus;
  309. }
  310. /*++
  311. Name:
  312. ConvertDomainNameToShortName
  313. Routine Description:
  314. Give a fully qualified DNS printer name convert it to a short name
  315. if the domain part of the printer name is identical to the domain
  316. name of the user is currently logged on to. Example:
  317. \\server1.dns.microsoft.com\test dns.microsoft.com resultant printer
  318. name \\server1\test.
  319. Arguments:
  320. pszPrinter - pointer to fully qualified DNS printer name.
  321. pszDomain - pointer to the users domain name.
  322. strShort - refrence to string where to return the short printer name.
  323. Return Value:
  324. TRUE short name returned, FALSE error occurred.
  325. --*/
  326. BOOL
  327. ConvertDomainNameToShortName(
  328. IN LPCTSTR pszPrinter,
  329. IN LPCTSTR pszDomain,
  330. IN OUT TString &strShort
  331. )
  332. {
  333. SPLASSERT( pszPrinter );
  334. SPLASSERT( pszDomain );
  335. TStatusB bStatus;
  336. //
  337. // If a valid domain and unc printer name were provided then continue
  338. // checking for a domain name match.
  339. //
  340. bStatus DBGNOCHK = pszDomain && *pszDomain && pszPrinter && *(pszPrinter+0) == _T('\\') && *(pszPrinter+1) == _T('\\');
  341. if( bStatus )
  342. {
  343. //
  344. // Assume failure, until we actually build a short name.
  345. //
  346. bStatus DBGNOCHK = FALSE;
  347. //
  348. // Find the first '.' this will be the start of the domain name if
  349. // present. The domain name is from the first . to the first \
  350. //
  351. LPTSTR pszShort = _tcschr( pszPrinter, _T('.') );
  352. if( pszShort )
  353. {
  354. //
  355. // Allocate a printer name buffer, I simplify the is case by just allocating
  356. // a buffer large enought for the printer name. I know the name will potentialy
  357. // smaller, but it not worth figuring out how much smaller.
  358. //
  359. LPTSTR pszBuffer = (LPTSTR)AllocMem( (_tcslen( pszPrinter ) + 1) * sizeof(TCHAR) );
  360. if( pszBuffer )
  361. {
  362. LPTSTR p = pszShort+1;
  363. LPTSTR d = pszBuffer;
  364. //
  365. // Copy the domain name from the full printer name to the allocated buffer.
  366. //
  367. while( *p && *p != _T('\\') )
  368. {
  369. *d++ = *p++;
  370. }
  371. //
  372. // Null terminate the destination buffere.
  373. //
  374. *d = 0;
  375. //
  376. // Check if the domain name in the printer name match the provided domain name.
  377. //
  378. if( !_tcsicmp( pszBuffer, pszDomain ) )
  379. {
  380. //
  381. // Build the short printer name less the domain name.
  382. //
  383. memmove( pszBuffer, pszPrinter, sizeof(TCHAR) * (size_t)(pszShort-pszPrinter) );
  384. _tcscpy( pszBuffer+(pszShort-pszPrinter), p );
  385. //
  386. // Copy back the short printer name to the provided string object.
  387. //
  388. bStatus DBGCHK = strShort.bUpdate( pszBuffer );
  389. }
  390. //
  391. // Release the temp printer name buffer.
  392. //
  393. FreeMem( pszBuffer );
  394. }
  395. }
  396. }
  397. return bStatus;
  398. }
  399. /********************************************************************
  400. Add Printer Connection class
  401. ********************************************************************/
  402. /*++
  403. Name:
  404. TAddPrinterConnectionData
  405. Routine Description:
  406. This function is the derived add printer connection data class
  407. constructure that is used to pass data to an asynchronous worker
  408. thread. The worker thread is call after the progress UI is displayed.
  409. Arguments:
  410. None
  411. Return Value:
  412. Nothing.
  413. --*/
  414. TAddPrinterConnectionData::
  415. TAddPrinterConnectionData(
  416. VOID
  417. ) : _bShowConnectionUI( TRUE )
  418. {
  419. DBGMSG( DBG_TRACE, ( "TAddPrinterConnectionData::ctor\n" ) );
  420. }
  421. /*++
  422. Name:
  423. ~TAddPrinterConnectionData
  424. Routine Description:
  425. Destructor.
  426. Arguments:
  427. None
  428. Return Value:
  429. Nothing.
  430. Note:
  431. The last error is not set on failure.
  432. --*/
  433. TAddPrinterConnectionData::
  434. ~TAddPrinterConnectionData(
  435. VOID
  436. )
  437. {
  438. DBGMSG( DBG_TRACE, ( "TAddPrinterConnectionData::dtor\n" ) );
  439. }
  440. /*++
  441. Name:
  442. bAsyncWork
  443. Routine Description:
  444. This routine is the worker thread call back routine. It is called after the
  445. progress UI has been started and is currently being displayed. Because this
  446. function is a virtual within the TAsyncData class any specific data needed
  447. by this routine must be fully contained within the derived class. This routine
  448. accepts on argument a pointer to the progress dialog pointer. If needed this
  449. pointer should be used to stop the progress UI if any UI must be displayed.
  450. The hwnd of the progress UI should be used as the parent of any windows
  451. this routine may need to created.
  452. Arguments:
  453. Pointer to TAsyncDlg class.
  454. Return Value:
  455. TRUE function completed successfully, FALSE error occurred.
  456. --*/
  457. BOOL
  458. TAddPrinterConnectionData::
  459. bAsyncWork(
  460. IN TAsyncDlg *pDlg
  461. )
  462. {
  463. //
  464. // Print some debugging information.
  465. //
  466. DBGMSG( DBG_TRACE, ( "pszPrinter " TSTR "\n", DBGSTR( (LPCTSTR)_strPrinter ) ) );
  467. //
  468. // Currently just call the add printer connection UI in winspool.drv
  469. //
  470. if( _bShowConnectionUI )
  471. {
  472. BOOL bDummy = FALSE;
  473. //
  474. // Call add printer connection UI, note the add printer connection UI sill
  475. // will display UI if an error occurred or if the driver was needed in the
  476. // masq printer case.
  477. //
  478. HANDLE hHandle = AddPrinterConnectionUI( pDlg->_hDlg, _strPrinter, &bDummy );
  479. //
  480. // Handle is not needed, just release it if a valid handle was returned.
  481. //
  482. if( hHandle )
  483. {
  484. ClosePrinter( hHandle );
  485. _ReturnValue = TRUE;
  486. }
  487. else
  488. {
  489. _ReturnValue = FALSE;
  490. }
  491. }
  492. else
  493. {
  494. //
  495. // Add printer connection will just try and make an RPC connection to the printer
  496. // this call will not handle the masq printer case.
  497. //
  498. _ReturnValue = PrintUIAddPrinterConnection( _strPrinter, NULL );
  499. }
  500. return TRUE;
  501. }