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.

5229 lines
147 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. All rights reserved
  4. Module Name:
  5. browse.cxx
  6. Abstract:
  7. Handles the browse dialog for printer connections.
  8. Author:
  9. Created by AndrewBe on 1 Dec 1992
  10. Steve Kiraly (SteveKi) 1 May 1998
  11. Environment:
  12. User Mode Win32
  13. Revision History:
  14. 1 May 1998 moved from winspool.drv to printui.dll
  15. --*/
  16. #include "precomp.hxx"
  17. #pragma hdrstop
  18. #include "result.hxx"
  19. #include "asyncdlg.hxx"
  20. #include "addprn.hxx"
  21. #include "browse.hxx"
  22. #include "persist.hxx"
  23. #define SECURITY_WIN32
  24. #include <wincred.h>
  25. #include <wincrui.h>
  26. //
  27. // Global variables used only in this file.
  28. //
  29. static HDC hdcBitmap = NULL;
  30. static HBITMAP hbmBitmap = NULL;
  31. static HBITMAP hbmDefault = NULL;
  32. static HANDLE hRes = NULL;
  33. static DWORD SysColorHighlight = 0;
  34. static DWORD SysColorWindow = 0;
  35. static INT iBackground = 0;
  36. static INT iBackgroundSel = 0;
  37. static INT iButtonFace = 0;
  38. static INT iButtonShadow = 0;
  39. static BOOL ColorIndicesInitialised = FALSE;
  40. /*++
  41. ConnectTo objects
  42. In the ConnectTo dialog, we initially call EnumPrinters with Flags == 0.
  43. This returns an array of top-level objects represented by a PrinterInfo
  44. structure, e.g:
  45. LanMan Windows NT
  46. Banyan
  47. etc...
  48. We create a chain of ConnectTo objects, each of which points to a PrinterInfo
  49. structure. Initially, pSubObject is NULL.
  50. The Flags field in the PrinterInfo structure indicates whether we can enumerate
  51. on the object. If so, this is indicated to the user through the display of
  52. an appropriate icon in the list box.
  53. If the user clicks on such an enumerable object, we call
  54. EnumPrinters( PRINTER_ENUM_NAME, pName, ... ), which returns a further buffer
  55. of PrinterInfo structures. These may represent servers on the network,
  56. which may in turn be enumerated on to give the names of printers.
  57. Each time an object is enumerated on, we create a new array of ConnectTo objects
  58. which pSubObject points to:
  59. pPrinterInfo[n] pPrinterInfo[n+1]
  60. +-----------------+ +-----------------+
  61. | FLAG_ENUMERABLE | | FLAG_ENUMERABLE |
  62. | <description> | | <description> |
  63. | "LanMan NT" | .... | "Banyan" |
  64. | "local network" | | "other network" |
  65. +-----------------+ +-----------------+
  66. A A
  67. | |
  68. +--------------+ | +--------------+ |
  69. | pPrinterInfo |--+ | pPrinterInfo |--+
  70. +--------------+ ..... +--------------+
  71. +--| pSubObject | | (NULL) |
  72. | +--------------+ +--------------+
  73. | | sizeof(Inf)*2| | 0 |
  74. | +--------------+ +--------------+
  75. |
  76. | =======================================================================
  77. |
  78. | pPrinterInfo[n+m] pPrinterInfo[n+m+1]
  79. | +-----------------+ +-----------------+
  80. | | FLAG_ENUMERABLE | | FLAG_ENUMERABLE |
  81. | | "LanMan Server" | | "LanMan Server" |
  82. | | "Server A" | .... | "Server B" |
  83. | | "daft comment" | | "other comment" |
  84. | +-----------------+ +-----------------+
  85. | A A
  86. | | |
  87. | +--------------+ | +--------------+ |
  88. +->| pPrinterInfo |--+ | pPrinterInfo |--+
  89. +--------------+ +--------------+
  90. +--| pSubObject | | (NULL) |
  91. | +--------------+ ..... +--------------+
  92. | | sizeof(Inf)*2| | 0 |
  93. | +--------------+ +--------------+
  94. |
  95. | =======================================================================
  96. |
  97. | pPrinterInfo[n+m+k] pPrinterInfo[n+m+k+1]
  98. | +-----------------+ +-----------------+
  99. | | 0 | | 0 |
  100. | | "HP Laserjet" | | "Epson" |
  101. | | "Fave Printer" | .... | "Epson Printer" |
  102. | | "good quality" | | "Epson thingy" |
  103. | +-----------------+ +-----------------+
  104. | A A
  105. | | |
  106. | +--------------+ | +--------------+ |
  107. +->| pPrinterInfo |--+ | pPrinterInfo |--+
  108. +--------------+ +--------------+
  109. | (NULL) | | (NULL) |
  110. +--------------+ ..... +--------------+
  111. | 0 | | 0 |
  112. +--------------+ +--------------+
  113. In the list box, the name of each object is displayed, with icon and indentation
  114. to indicate enumerations possible. The simple example above would look like this:
  115. +----------------------+-+
  116. | - LanMan NT |A|
  117. | * Fave Printer + +
  118. | * Epson Printer | |
  119. | + Banyan | |
  120. | | |
  121. | + +
  122. | |V|
  123. +----------------------+-+
  124. --*/
  125. /* ConnectToPrinterDlg
  126. *
  127. * Initializes bitmaps, fonts and cursors the first time it is invoked,
  128. * then calls the ConnectTo dialog.
  129. *
  130. * Parameters:
  131. *
  132. * hwnd - Owner window handle
  133. *
  134. * Returns:
  135. *
  136. * The handle of the printer connected to,
  137. * NULL if no printer was selected or an error occurred.
  138. *
  139. * Author: andrewbe, August 1992
  140. */
  141. HANDLE
  142. WINAPI
  143. ConnectToPrinterDlg(
  144. HWND hwnd,
  145. DWORD Flags
  146. )
  147. {
  148. PBROWSE_DLG_DATA pBrowseDlgData = new BROWSE_DLG_DATA;
  149. HANDLE hPrinter = NULL;
  150. if( pBrowseDlgData )
  151. {
  152. pBrowseDlgData->vIncRef();
  153. if( pBrowseDlgData->bValid() )
  154. {
  155. pBrowseDlgData->hwndParent = hwnd;
  156. pBrowseDlgData->Flags = Flags;
  157. //
  158. // Make sure COM is initialized first.
  159. //
  160. COleComInitializer com;
  161. //
  162. // Show up the dialog box now.
  163. //
  164. INT_PTR iResult = DialogBoxParam( ghInst,
  165. MAKEINTRESOURCE(DLG_CONNECTTO),
  166. hwnd,
  167. (DLGPROC)ConnectToDlg,
  168. (LPARAM)pBrowseDlgData );
  169. if( iResult == IDOK )
  170. {
  171. hPrinter = pBrowseDlgData->hPrinter;
  172. }
  173. }
  174. pBrowseDlgData->cDecRef();
  175. }
  176. return hPrinter;
  177. }
  178. UINT CALLBACK PropSheetPageCallBack(
  179. IN HWND hwnd,
  180. IN UINT uMsg,
  181. IN LPPROPSHEETPAGE ppsp
  182. )
  183. /*++
  184. Routine Description:
  185. This function gets called when the property sheet
  186. returned from ConnectToPrinterPropertyPage() gets
  187. created/released
  188. Arguments:
  189. hwnd - reserved; must be NULL
  190. uMsg - PSPCB_CREATE - when the page gets created
  191. (return TRUE to allow page creation)
  192. PSPCB_RELEASE - when the page is being destroyed
  193. (return value is ignored)
  194. ppsp - Address of a PROPSHEETPAGE structure that defines
  195. the page being created or destroyed.
  196. Return Value:
  197. Depends on the message - see above.
  198. --*/
  199. {
  200. UINT uReturn = TRUE;
  201. switch( uMsg )
  202. {
  203. case PSPCB_CREATE:
  204. {
  205. //
  206. // Just allow page creation. Do nothing
  207. // but return TRUE
  208. //
  209. }
  210. break;
  211. case PSPCB_RELEASE:
  212. {
  213. //
  214. // We must unhook the UI from the page here
  215. //
  216. PBROWSE_DLG_DATA pBrowseDlgData = reinterpret_cast<PBROWSE_DLG_DATA>( ppsp->lParam );
  217. pBrowseDlgData->cDecRef( );
  218. }
  219. break;
  220. default:
  221. {
  222. //
  223. // This message is not processed.
  224. //
  225. uReturn = FALSE;
  226. }
  227. break;
  228. }
  229. return uReturn;
  230. }
  231. /*
  232. *
  233. */
  234. HRESULT
  235. ConnectToPrinterPropertyPage(
  236. OUT HPROPSHEETPAGE *phPsp,
  237. OUT UINT *puPageID,
  238. IN IPageSwitch *pPageSwitchController
  239. )
  240. /*++
  241. Routine Description:
  242. Creates a property page, which is identical to the
  243. ConnectToPrinterDlg dialog box
  244. Arguments:
  245. phpsp - Pointer to handle of property sheet page created
  246. ppageID - The resource identifier of the created page
  247. nNextPageID - Page ID to switch if next is pressed
  248. nPrevPageID - Page ID to switch if prev is pressed
  249. Return Value:
  250. S_OK - if everything is fine
  251. E_FAIL (or other error code) if something goes wrong
  252. --*/
  253. {
  254. //
  255. // Assume success
  256. //
  257. HRESULT hResult = S_OK;
  258. //
  259. // Create the dialog data structure
  260. //
  261. PBROWSE_DLG_DATA pBrowseDlgData = NULL;
  262. pBrowseDlgData = new BROWSE_DLG_DATA;
  263. if( pBrowseDlgData )
  264. {
  265. pBrowseDlgData->bInPropertyPage = TRUE;
  266. pBrowseDlgData->pPageSwitchController = pPageSwitchController;
  267. pBrowseDlgData->vIncRef( );
  268. if( pBrowseDlgData->bValid() )
  269. {
  270. //
  271. // Create a property page and return a handle to it.
  272. //
  273. PROPSHEETPAGE psp = {0};
  274. psp.dwSize = sizeof( psp );
  275. psp.hInstance = ghInst;
  276. psp.pfnDlgProc = reinterpret_cast<DLGPROC>( ConnectToPropertyPage );
  277. psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE | PSP_USECALLBACK;
  278. psp.pfnCallback = PropSheetPageCallBack;
  279. //
  280. // Set the title and subtitle.
  281. //
  282. TStatusB bStatus;
  283. TString strTitle;
  284. TString strSubTitle;
  285. bStatus DBGCHK = strTitle.bLoadString( ghInst, IDS_WIZ_BROWSE_TITLE );
  286. bStatus DBGCHK = strSubTitle.bLoadString( ghInst, IDS_WIZ_BROWSE_SUBTITLE );
  287. psp.pszHeaderTitle = strTitle;
  288. psp.pszHeaderSubTitle = strSubTitle;
  289. psp.pszTemplate = MAKEINTRESOURCE( DLG_WIZ_BROWSE );
  290. psp.lParam = reinterpret_cast<LPARAM>( pBrowseDlgData );
  291. //
  292. // Create the property page handle
  293. //
  294. *phPsp = CreatePropertySheetPage( &psp );
  295. if( NULL == *phPsp )
  296. {
  297. bStatus DBGCHK = FALSE;
  298. hResult = E_FAIL;
  299. }
  300. else
  301. {
  302. //
  303. // Everything looks fine - so return the page ID
  304. //
  305. *puPageID = DLG_WIZ_BROWSE;
  306. }
  307. }
  308. else
  309. {
  310. //
  311. // An error occured ...
  312. //
  313. hResult = E_FAIL;
  314. }
  315. }
  316. else
  317. {
  318. //
  319. // Memory allocation failure
  320. //
  321. hResult = E_OUTOFMEMORY;
  322. }
  323. //
  324. // Check if something failed to prevent
  325. // leaking the BROWSE_DLG_DATA structure
  326. //
  327. if( FAILED( hResult ) )
  328. {
  329. if( pBrowseDlgData )
  330. {
  331. pBrowseDlgData->cDecRef();
  332. }
  333. }
  334. return hResult;
  335. }
  336. /*
  337. *
  338. */
  339. LRESULT
  340. WINAPI
  341. ConnectToPropertyPage(
  342. HWND hWnd,
  343. UINT uMsg,
  344. WPARAM wParam,
  345. LPARAM lParam
  346. )
  347. /*++
  348. Routine Description:
  349. The window proc for the ConnectToPrinter property page.
  350. Just cracks the lParam to point to PBROWSE_DLG_DATA
  351. structure and pass the control to the ConnectTo proc.
  352. Arguments:
  353. Standard window procedure parameters -
  354. see WindowProc for more details
  355. Return Value:
  356. --*/
  357. {
  358. BOOL bProcessed = TRUE;
  359. //
  360. // Message processing switch
  361. //
  362. switch( uMsg )
  363. {
  364. case WM_INITDIALOG:
  365. {
  366. //
  367. // Crack the lParam parameter, so we could leverage
  368. // the original ConnectToDlg dialog proc for initialization
  369. //
  370. lParam = ( (LPPROPSHEETPAGE )lParam )->lParam;
  371. //
  372. // Impersonate message is not processed
  373. //
  374. bProcessed = FALSE;
  375. }
  376. break;
  377. case WM_DESTROY:
  378. {
  379. //
  380. // Just send a message to the background thread to terminate
  381. // and unhook from the data.
  382. //
  383. ConnectToDestroy( hWnd );
  384. SET_BROWSE_DLG_DATA( hWnd, static_cast<PBROWSE_DLG_DATA>(NULL) );
  385. }
  386. break;
  387. case WM_NOTIFY:
  388. {
  389. //
  390. // Assume we didn't process the message until
  391. // otherwise happened
  392. //
  393. bProcessed = FALSE;
  394. PBROWSE_DLG_DATA pBrowseDlgData = GET_BROWSE_DLG_DATA( hWnd );
  395. SPLASSERT( pBrowseDlgData );
  396. //
  397. // Check if we are in a property page
  398. //
  399. if( pBrowseDlgData->bInPropertyPage )
  400. {
  401. LPNMHDR pnmh = (LPNMHDR)lParam;
  402. switch( pnmh->code )
  403. {
  404. case PSN_WIZBACK:
  405. {
  406. bProcessed = PropertyPageWizardBack( hWnd );
  407. }
  408. break;
  409. case PSN_WIZNEXT:
  410. {
  411. bProcessed = ConnectToOK( hWnd, TRUE );
  412. }
  413. break;
  414. case PSN_QUERYCANCEL:
  415. {
  416. bProcessed = ConnectToCancel( hWnd );
  417. }
  418. break;
  419. }
  420. }
  421. }
  422. break;
  423. default:
  424. {
  425. //
  426. // Pass the message for standard
  427. // processing to ConnectToDlg( ... )
  428. //
  429. bProcessed = FALSE;
  430. }
  431. break;
  432. }
  433. if( !bProcessed )
  434. {
  435. //
  436. // Transfer the control to the ConnectToDlg( ... ) proc
  437. //
  438. bProcessed = (BOOL)ConnectToDlg( hWnd, uMsg, wParam, lParam );
  439. }
  440. return bProcessed;
  441. }
  442. /*
  443. *
  444. */
  445. BOOL
  446. PropertyPageWizardBack( HWND hWnd )
  447. /*++
  448. Routine Description:
  449. This function moves the property sheet wizard
  450. by one page back
  451. Arguments:
  452. hWnd - handle to the property page
  453. Return Value:
  454. TRUE - if the message is processed
  455. FALSE - otherwise
  456. --*/
  457. {
  458. PBROWSE_DLG_DATA pBrowseDlgData = GET_BROWSE_DLG_DATA( hWnd );
  459. SPLASSERT( pBrowseDlgData );
  460. BOOL bProcessed = TRUE;
  461. //
  462. // Check if there is page switch controller provided
  463. //
  464. if( pBrowseDlgData->pPageSwitchController )
  465. {
  466. UINT uPrevPage;
  467. HRESULT hr = pBrowseDlgData->pPageSwitchController->GetPrevPageID( &uPrevPage );
  468. //
  469. // if S_OK == hr then just go to the provided
  470. // prev page (no problem)
  471. //
  472. if( S_OK == hr )
  473. {
  474. SetWindowLong( hWnd, DWLP_MSGRESULT, uPrevPage );
  475. }
  476. else
  477. {
  478. //
  479. // Don't switch the page - or per client request
  480. // or in case of an error
  481. //
  482. SetWindowLong( hWnd, DWLP_MSGRESULT, -1 );
  483. }
  484. }
  485. else
  486. {
  487. //
  488. // There is no page switch controller provided -
  489. // just go to the natural prev page ...
  490. //
  491. SetWindowLong( hWnd, DWLP_MSGRESULT, 0 );
  492. }
  493. return bProcessed;
  494. }
  495. /*
  496. *
  497. */
  498. BOOL SetDevMode( HANDLE hPrinter )
  499. {
  500. PPRINTER_INFO_2 pPrinter = NULL;
  501. DWORD cbPrinter = 0;
  502. LONG cbDevMode;
  503. PDEVMODE pNewDevMode;
  504. BOOL Success = FALSE;
  505. //
  506. // Gather the information.
  507. //
  508. if( VDataRefresh::bGetPrinter( hPrinter,
  509. 2,
  510. (PVOID*)&pPrinter,
  511. &cbPrinter ) )
  512. {
  513. cbDevMode = DocumentProperties(NULL,
  514. hPrinter,
  515. pPrinter->pPrinterName,
  516. NULL,
  517. pPrinter->pDevMode,
  518. 0);
  519. if (cbDevMode > 0)
  520. {
  521. if (pNewDevMode = (PDEVMODE)AllocSplMem(cbDevMode))
  522. {
  523. if (DocumentProperties(NULL,
  524. hPrinter,
  525. pPrinter->pPrinterName,
  526. pNewDevMode,
  527. pPrinter->pDevMode,
  528. DM_COPY) == IDOK)
  529. {
  530. pPrinter->pDevMode = pNewDevMode;
  531. if( SetPrinter( hPrinter, 2, (LPBYTE)pPrinter, 0 ) )
  532. Success = TRUE;
  533. }
  534. FreeSplMem(pNewDevMode);
  535. pPrinter->pDevMode = NULL;
  536. }
  537. }
  538. FreeMem( pPrinter );
  539. }
  540. else
  541. {
  542. DBGMSG( DBG_WARN, ( "GetPrinter failed: Error %d\n", GetLastError( ) ) );
  543. }
  544. return Success;
  545. }
  546. /////////////////////////////////////////////////////////////////////////////
  547. //
  548. // ConnectToDlg
  549. //
  550. // This is the window procedure manages the ConnectTo dialog which allows
  551. // for the selection and creation of a new printer for use by the system.
  552. //
  553. // TO DO:
  554. // error checking for spooler api calls
  555. // IDOK - creating/saving new Printer settings
  556. // Limit text on editbox input fields ???
  557. // Implement
  558. // case IDD_AP_HELP
  559. //
  560. //
  561. //
  562. /////////////////////////////////////////////////////////////////////////////
  563. LRESULT
  564. WINAPI
  565. ConnectToDlg(
  566. HWND hWnd,
  567. UINT usMsg,
  568. WPARAM wParam,
  569. LPARAM lParam
  570. )
  571. {
  572. PBROWSE_DLG_DATA pBrowseDlgData = NULL;
  573. switch (usMsg)
  574. {
  575. case WM_INITDIALOG:
  576. return ConnectToInitDialog( hWnd, (PBROWSE_DLG_DATA)lParam );
  577. case WM_DRAWITEM:
  578. if( ConnectToDrawItem( hWnd, (LPDRAWITEMSTRUCT)lParam ) )
  579. return TRUE;
  580. break;
  581. case WM_CHARTOITEM:
  582. //
  583. // If the key entered is space, well will not do the search;
  584. // instead, we send a fake double click message to the list
  585. // box to expand/collaps the selected item.
  586. //
  587. if( LOWORD( wParam ) == VK_SPACE )
  588. {
  589. HWND hListbox = NULL;
  590. if( hListbox = GetDlgItem( hWnd, IDD_BROWSE_SELECT_LB ))
  591. {
  592. SendMessage( hWnd,
  593. WM_COMMAND,
  594. MAKEWPARAM(GetDlgCtrlID(hListbox), LBN_DBLCLK),
  595. (LPARAM)hListbox );
  596. }
  597. return -1;
  598. }
  599. else
  600. {
  601. return ConnectToCharToItem( hWnd, LOWORD( wParam ) );
  602. }
  603. case WM_VKEYTOITEM:
  604. switch (LOWORD(wParam))
  605. {
  606. case VK_RETURN:
  607. ConnectToSelectLbDblClk( hWnd, (HWND)lParam );
  608. /* fall through ... */
  609. default:
  610. return -1;
  611. }
  612. case WM_DESTROY:
  613. ConnectToDestroy( hWnd );
  614. return 0;
  615. case WM_COMMAND:
  616. switch (LOWORD(wParam))
  617. {
  618. case IDD_BROWSE_SELECT_LB:
  619. switch (HIWORD(wParam))
  620. {
  621. case LBN_SELCHANGE:
  622. ConnectToSelectLbSelChange( hWnd );
  623. break;
  624. case LBN_DBLCLK:
  625. ConnectToSelectLbDblClk( hWnd, (HWND)lParam );
  626. break;
  627. }
  628. break;
  629. case IDOK:
  630. return ConnectToOK( hWnd, FALSE );
  631. case IDCANCEL:
  632. return ConnectToCancel( hWnd );
  633. case IDD_BROWSE_DEFAULTEXPAND:
  634. {
  635. //
  636. // Imediately save the checkbox state in the registry
  637. //
  638. return SetRegShowLogonDomainFlag( (BOOL )SendDlgItemMessage(hWnd,IDD_BROWSE_DEFAULTEXPAND, BM_GETCHECK, 0, 0L) );
  639. }
  640. }
  641. break;
  642. case WM_MOUSEMOVE:
  643. ConnectToMouseMove( hWnd, (LONG)LOWORD( lParam ), (LONG)HIWORD( lParam ) );
  644. break;
  645. case WM_SETCURSOR:
  646. return ConnectToSetCursor( hWnd );
  647. case WM_ENUM_OBJECTS_COMPLETE:
  648. pBrowseDlgData = (PBROWSE_DLG_DATA)lParam;
  649. ConnectToEnumObjectsComplete( hWnd,
  650. (PCONNECTTO_OBJECT)pBrowseDlgData->wParam );
  651. break;
  652. case WM_GET_PRINTER_COMPLETE:
  653. pBrowseDlgData = (PBROWSE_DLG_DATA)lParam;
  654. ConnectToGetPrinterComplete( hWnd,
  655. (LPTSTR)pBrowseDlgData->wParam,
  656. (PPRINTER_INFO_2)pBrowseDlgData->lParam,
  657. NO_ERROR );
  658. break;
  659. case WM_GET_PRINTER_ERROR:
  660. pBrowseDlgData = (PBROWSE_DLG_DATA)lParam;
  661. ConnectToGetPrinterComplete( hWnd,
  662. (LPTSTR)pBrowseDlgData->wParam,
  663. NULL,
  664. (DWORD)pBrowseDlgData->lParam );
  665. break;
  666. case WM_HELP:
  667. case WM_CONTEXTMENU:
  668. PrintUIHelp( usMsg, hWnd, wParam, lParam );
  669. break;
  670. }
  671. return FALSE;
  672. }
  673. /*
  674. *
  675. */
  676. BOOL ConnectToInitDialog( HWND hWnd, PBROWSE_DLG_DATA pBrowseDlgData )
  677. {
  678. //
  679. // Start the initial browse request.
  680. //
  681. DBGMSG( DBG_TRACE, ( "Sending initial browse request\n" ) );
  682. if( !pBrowseDlgData->bInitializeBrowseThread( hWnd ) )
  683. {
  684. iMessage( hWnd,
  685. IDS_CONNECTTOPRINTER,
  686. IDS_COULDNOTSTARTBROWSETHREAD,
  687. MB_OK | MB_ICONSTOP,
  688. kMsgNone,
  689. NULL );
  690. if( pBrowseDlgData->bInPropertyPage )
  691. {
  692. PropSheet_PressButton( GetParent( hWnd ), PSBTN_CANCEL );
  693. }
  694. else
  695. {
  696. EndDialog( hWnd, IDCANCEL );
  697. }
  698. return FALSE;
  699. }
  700. //
  701. // Set up the initial UI.
  702. //
  703. SET_BROWSE_DLG_DATA( hWnd, pBrowseDlgData );
  704. SendDlgItemMessage(hWnd, IDD_BROWSE_PRINTER, EM_LIMITTEXT, kPrinterBufMax-1, 0L );
  705. if( pBrowseDlgData->Status & BROWSE_STATUS_INITIAL )
  706. {
  707. SETLISTCOUNT(hWnd, 1);
  708. DISABLE_LIST(hWnd);
  709. if( !pBrowseDlgData->bInPropertyPage )
  710. {
  711. //
  712. // When we are in a property page this checkbox
  713. // will not exist at all.
  714. //
  715. SendDlgItemMessage( hWnd, IDD_BROWSE_DEFAULTEXPAND, BM_SETCHECK, 1, 0L );
  716. }
  717. }
  718. /* Set focus initially to the Printer entry field;
  719. * when enumeration is complete (if we're enumerating)
  720. * we'll set it to the list:
  721. */
  722. SetFocus( GetDlgItem( hWnd, IDD_BROWSE_PRINTER ) );
  723. //
  724. // Enable autocomplete for the printer share/name edit box
  725. //
  726. ShellServices::InitPrintersAutoComplete(GetDlgItem(hWnd, IDD_BROWSE_PRINTER));
  727. return FALSE; /* FALSE == don't set default keyboard focus */
  728. }
  729. /*
  730. *
  731. */
  732. BOOL ConnectToDrawItem( HWND hwnd, LPDRAWITEMSTRUCT pdis )
  733. {
  734. PBROWSE_DLG_DATA pBrowseDlgData;
  735. PCONNECTTO_OBJECT pConnectToData;
  736. PCONNECTTO_OBJECT pConnectToObject;
  737. TCHAR Working[255]; /* String to display when we're expanding initially */
  738. DWORD ObjectsFound = 0;
  739. DWORD Depth = 0;
  740. RECT LineRect;
  741. BOOL Selected;
  742. int xIcon; // Coordinates of icon
  743. int yIcon; // in the resource bitmap
  744. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hwnd) ) )
  745. return FALSE;
  746. pConnectToData = GET_CONNECTTO_DATA(hwnd);
  747. if( !pConnectToData || ( pdis->itemID == (UINT)-1 ) )
  748. return FALSE;
  749. /* If this is the first item when we're expanding,
  750. * put "Working..." in the list box:
  751. */
  752. if( ( pBrowseDlgData->Status & BROWSE_STATUS_INITIAL ) && pdis->itemID == 0 )
  753. {
  754. LoadString( ghInst, IDS_WORKING, Working,
  755. COUNTOF(Working));
  756. pdis->rcItem.left += 3;
  757. DrawLine( pdis->hDC, &pdis->rcItem, Working, FALSE );
  758. return TRUE;
  759. }
  760. LineRect = pdis->rcItem;
  761. Selected = ( pdis->itemState & ODS_SELECTED );
  762. pConnectToObject = GetConnectToObject( pConnectToData->pSubObject,
  763. pConnectToData->cSubObjects,
  764. pdis->itemID,
  765. NULL,
  766. &ObjectsFound,
  767. &Depth );
  768. if( pConnectToObject )
  769. {
  770. DWORD Flags;
  771. //
  772. // If the object is not a container and it is a provider do not
  773. // display this provider, because there is nothing underneath it
  774. // we should not show it.
  775. //
  776. if( pConnectToObject->pPrinterInfo->Flags & PRINTER_ENUM_HIDE )
  777. {
  778. return FALSE;
  779. }
  780. if (Selected) {
  781. SetBkColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHT) );
  782. SetTextColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT) );
  783. } else {
  784. SetBkColor(pdis->hDC, GetSysColor(COLOR_WINDOW) );
  785. SetTextColor(pdis->hDC, GetSysColor(COLOR_WINDOWTEXT) );
  786. }
  787. /* Draw the indentation:
  788. */
  789. LineRect.right = ( LineRect.left + ( Depth * STATUS_BITMAP_SPACE / 4 ) );
  790. DrawLine( pdis->hDC, &LineRect, TEXT(""), Selected );
  791. LineRect.left = LineRect.right;
  792. /* We need to handle 8 different types of icon here:
  793. */
  794. Flags = pConnectToObject->pPrinterInfo->Flags;
  795. /* Find out the x-coordinate of the icon we need
  796. * to display in the listbox:
  797. */
  798. switch( Flags & PRINTER_ENUM_ICONMASK )
  799. {
  800. case PRINTER_ENUM_ICON1:
  801. xIcon = ( STATUS_BITMAP_WIDTH * 0 );
  802. break;
  803. case PRINTER_ENUM_ICON2:
  804. xIcon = ( STATUS_BITMAP_WIDTH * 1 );
  805. break;
  806. case PRINTER_ENUM_ICON3:
  807. xIcon = ( STATUS_BITMAP_WIDTH * 2 );
  808. break;
  809. case PRINTER_ENUM_ICON4:
  810. xIcon = ( STATUS_BITMAP_WIDTH * 3 );
  811. break;
  812. case PRINTER_ENUM_ICON5:
  813. xIcon = ( STATUS_BITMAP_WIDTH * 4 );
  814. break;
  815. case PRINTER_ENUM_ICON6:
  816. xIcon = ( STATUS_BITMAP_WIDTH * 5 );
  817. break;
  818. case PRINTER_ENUM_ICON7:
  819. xIcon = ( STATUS_BITMAP_WIDTH * 6 );
  820. break;
  821. case PRINTER_ENUM_ICON8:
  822. default:
  823. xIcon = ( STATUS_BITMAP_WIDTH * 7 );
  824. break;
  825. }
  826. /* If there are enumerated subobjects, pick the appropriate icon:
  827. */
  828. if( pConnectToObject->pSubObject )
  829. yIcon = BM_IND_CONNECTTO_DOMEXPAND;
  830. else
  831. yIcon = BM_IND_CONNECTTO_DOMPLUS;
  832. /* Ensure that the highlight will extend right across:
  833. */
  834. LineRect.right = pdis->rcItem.right;
  835. DisplayStatusIcon( pdis->hDC, &LineRect, xIcon, yIcon, Selected );
  836. if( pConnectToObject->pPrinterInfo->Flags & PRINTER_ENUM_CONTAINER )
  837. {
  838. /* Draw the description as is for containers:
  839. */
  840. DrawLine( pdis->hDC, &LineRect,
  841. pConnectToObject->pPrinterInfo->pDescription,
  842. Selected );
  843. }
  844. else
  845. {
  846. /* ... but insert tabs for the printers:
  847. */
  848. DrawLineWithTabs( pdis->hDC, &LineRect,
  849. pConnectToObject->pPrinterInfo->pDescription,
  850. Selected );
  851. }
  852. }
  853. if( Selected && ( pdis->itemState & ODS_FOCUS ) )
  854. DrawFocusRect( pdis->hDC, &pdis->rcItem );
  855. return TRUE;
  856. }
  857. /* Need to define LBS_WANTKEYBOARDINPUT for this to work
  858. *
  859. */
  860. LONG ConnectToCharToItem( HWND hWnd, WORD Key )
  861. {
  862. PBROWSE_DLG_DATA pBrowseDlgData;
  863. PCONNECTTO_OBJECT pConnectToData;
  864. PCONNECTTO_OBJECT pConnectToObject;
  865. LONG_PTR CurSel;
  866. LONG_PTR i;
  867. LONG_PTR ListCount;
  868. DWORD ObjectsFound;
  869. DWORD Depth;
  870. BOOL Found = FALSE;
  871. TCHAR Char[2];
  872. CurSel = SendDlgItemMessage(hWnd, IDD_BROWSE_SELECT_LB, LB_GETCURSEL, 0, 0L );
  873. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  874. return FALSE;
  875. ENTER_CRITICAL( pBrowseDlgData );
  876. pConnectToData = GET_CONNECTTO_DATA(hWnd);
  877. if( pConnectToData )
  878. {
  879. /* Ensure character is upper case:
  880. */
  881. Char[0] = (TCHAR)Key;
  882. Char[1] = (TCHAR)0;
  883. CharUpper( Char );
  884. ListCount = SendDlgItemMessage( hWnd, IDD_BROWSE_SELECT_LB, LB_GETCOUNT, 0, 0 );
  885. i = ( CurSel + 1 );
  886. while( !Found && ( i < ListCount ) )
  887. {
  888. ObjectsFound = 0;
  889. Depth = 0;
  890. pConnectToObject = GetConnectToObject( pConnectToData->pSubObject,
  891. pConnectToData->cSubObjects,
  892. (DWORD)i,
  893. NULL,
  894. &ObjectsFound,
  895. &Depth );
  896. if( pConnectToObject
  897. &&( *pConnectToObject->pPrinterInfo->pDescription == *Char ) )
  898. Found = TRUE;
  899. else
  900. i++;
  901. }
  902. if( !Found )
  903. i = 0;
  904. while( !Found && ( i < CurSel ) )
  905. {
  906. ObjectsFound = 0;
  907. Depth = 0;
  908. pConnectToObject = GetConnectToObject( pConnectToData->pSubObject,
  909. pConnectToData->cSubObjects,
  910. (DWORD)i,
  911. NULL,
  912. &ObjectsFound,
  913. &Depth );
  914. if( pConnectToObject
  915. &&( *pConnectToObject->pPrinterInfo->pDescription == *Char ) )
  916. Found = TRUE;
  917. else
  918. i++;
  919. }
  920. }
  921. LEAVE_CRITICAL( pBrowseDlgData );
  922. if( Found )
  923. return (LONG)i;
  924. else
  925. return -1;
  926. }
  927. /*
  928. *
  929. */
  930. VOID ConnectToMouseMove( HWND hWnd, LONG x, LONG y )
  931. {
  932. PBROWSE_DLG_DATA pBrowseDlgData;
  933. POINT pt;
  934. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  935. return;
  936. if( GetCursor() != pBrowseDlgData->hcursorArrow && GetCursor() != pBrowseDlgData->hcursorWait )
  937. {
  938. return;
  939. }
  940. if( pBrowseDlgData->Status & BROWSE_STATUS_EXPAND )
  941. {
  942. pt.x = x;
  943. pt.y = y;
  944. if( ChildWindowFromPoint( hWnd, pt ) == GetDlgItem( hWnd, IDD_BROWSE_SELECT_LB ) )
  945. {
  946. SetCursor( pBrowseDlgData->hcursorWait );
  947. }
  948. else
  949. SetCursor( pBrowseDlgData->hcursorArrow );
  950. }
  951. else
  952. SetCursor( pBrowseDlgData->hcursorArrow );
  953. }
  954. /* Return TRUE if we want control of the cursor.
  955. * This will be the case if we're over the browse list and
  956. * currently expanding the list.
  957. */
  958. BOOL ConnectToSetCursor( HWND hWnd )
  959. {
  960. PBROWSE_DLG_DATA pBrowseDlgData;
  961. POINT pt;
  962. BOOL rc = FALSE;
  963. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  964. return rc;
  965. if( pBrowseDlgData->Status & BROWSE_STATUS_EXPAND )
  966. {
  967. if( !GetCursorPos( &pt ) )
  968. {
  969. DBGMSG( DBG_WARN, ( "GetCursorPos failed in ConnectToSetCursor: Error %d\n", GetLastError( ) ) );
  970. }
  971. ScreenToClient( hWnd, &pt );
  972. if( ChildWindowFromPoint( hWnd, pt ) == GetDlgItem( hWnd, IDD_BROWSE_SELECT_LB ) )
  973. rc = TRUE;
  974. }
  975. return rc;
  976. }
  977. /*
  978. *
  979. */
  980. VOID SetCursorShape( HWND hWnd )
  981. {
  982. POINT CursorPos;
  983. if( !GetCursorPos( &CursorPos ) )
  984. {
  985. DBGMSG( DBG_WARN, ( "GetCursorPos failed in SetCursorShape: Error %d\n", GetLastError( ) ) );
  986. }
  987. ScreenToClient( hWnd, &CursorPos );
  988. ConnectToMouseMove( hWnd, CursorPos.x, CursorPos.y );
  989. }
  990. /*
  991. *
  992. */
  993. VOID ConnectToEnumObjectsComplete(
  994. HWND hWnd,
  995. PCONNECTTO_OBJECT pConnectToObject )
  996. {
  997. PBROWSE_DLG_DATA pBrowseDlgData;
  998. PCONNECTTO_OBJECT pDefaultExpand;
  999. DWORD Index;
  1000. TCHAR PrinterName[10];
  1001. DWORD ObjectsAdded;
  1002. DWORD dwExtent;
  1003. INT iLevel;
  1004. PCONNECTTO_OBJECT pConnectToData;
  1005. DWORD Depth = 0;
  1006. DWORD DepthExtent = 0;
  1007. DWORD ObjectsFound = 0;
  1008. HDC hDC;
  1009. LPTSTR pszLine;
  1010. LPTSTR pszPrevLine;
  1011. SIZE size;
  1012. DWORD dwCurExtent;
  1013. PCONNECTTO_OBJECT pConnectToObjectChild;
  1014. DBGMSG( DBG_TRACE, ( "EnumObjectsComplete\n" ) );
  1015. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  1016. return;
  1017. ObjectsAdded = pConnectToObject->cSubObjects;
  1018. //
  1019. // Before entering critical section, calculated extents
  1020. //
  1021. hDC = GetDC(NULL);
  1022. if (hDC)
  1023. {
  1024. pConnectToData = GET_CONNECTTO_DATA(hWnd);
  1025. if (pConnectToData)
  1026. {
  1027. dwExtent = pBrowseDlgData->dwExtent;
  1028. GetConnectToObject(pConnectToData->pSubObject,
  1029. pConnectToData->cSubObjects,
  1030. 0,
  1031. pConnectToObject,
  1032. &ObjectsFound,
  1033. &Depth);
  1034. DepthExtent = (Depth + 2) * STATUS_BITMAP_SPACE / 4 +
  1035. STATUS_BITMAP_SPACE;
  1036. for (Index = 0, pConnectToObjectChild = pConnectToObject->pSubObject;
  1037. Index < ObjectsAdded;
  1038. Index++, pConnectToObjectChild++)
  1039. {
  1040. pszLine = pConnectToObjectChild->pPrinterInfo->pDescription;
  1041. for (iLevel = 0; pszLine;) {
  1042. pszPrevLine = pszLine;
  1043. pszLine = _tcschr(pszLine, TEXT(','));
  1044. if (pszLine) {
  1045. iLevel++;
  1046. pszLine++;
  1047. }
  1048. }
  1049. if (GetTextExtentPoint32(hDC,
  1050. pszPrevLine,
  1051. _tcslen(pszPrevLine),
  1052. &size))
  1053. {
  1054. dwCurExtent = size.cx +
  1055. iLevel * (COLUMN_WIDTH + COLUMN_SEPARATOR_WIDTH) +
  1056. DepthExtent;
  1057. dwExtent = dwExtent > dwCurExtent ? dwExtent : dwCurExtent;
  1058. }
  1059. }
  1060. if (pBrowseDlgData->dwExtent != dwExtent)
  1061. {
  1062. SendDlgItemMessage(hWnd,
  1063. IDD_BROWSE_SELECT_LB,
  1064. LB_SETHORIZONTALEXTENT,
  1065. dwExtent,
  1066. 0L);
  1067. pBrowseDlgData->dwExtent = dwExtent;
  1068. }
  1069. }
  1070. ReleaseDC(NULL, hDC);
  1071. }
  1072. ENTER_CRITICAL( pBrowseDlgData );
  1073. if( pBrowseDlgData->Status & BROWSE_STATUS_INITIAL )
  1074. {
  1075. pBrowseDlgData->cExpandObjects += ObjectsAdded;
  1076. pDefaultExpand = GetDefaultExpand( pConnectToObject->pSubObject,
  1077. pConnectToObject->cSubObjects,
  1078. &Index );
  1079. if( pDefaultExpand )
  1080. {
  1081. DBGMSG( DBG_TRACE, ( "Expanding next level @08%x\n", pDefaultExpand ) );
  1082. pBrowseDlgData->ExpandSelection += ( Index + 1 );
  1083. SEND_BROWSE_THREAD_REQUEST( pBrowseDlgData,
  1084. BROWSE_THREAD_ENUM_OBJECTS,
  1085. pDefaultExpand->pPrinterInfo->pName,
  1086. pDefaultExpand );
  1087. }
  1088. else
  1089. {
  1090. DBGMSG( DBG_TRACE, ( "No more levels to expand: Count = %d; Selection = %d\n",
  1091. pBrowseDlgData->cExpandObjects,
  1092. pBrowseDlgData->ExpandSelection ) );
  1093. /* Put the selection on the name of the last enumerated node,
  1094. * not the first printer under that node:
  1095. */
  1096. pBrowseDlgData->ExpandSelection--;
  1097. SendDlgItemMessage( hWnd, IDD_BROWSE_SELECT_LB, WM_SETREDRAW, 0, 0L );
  1098. SETLISTCOUNT( hWnd, pBrowseDlgData->cExpandObjects );
  1099. SETLISTSEL( hWnd, pBrowseDlgData->ExpandSelection );
  1100. SendDlgItemMessage( hWnd, IDD_BROWSE_SELECT_LB, LB_SETTOPINDEX,
  1101. pBrowseDlgData->ExpandSelection, 0 );
  1102. SendDlgItemMessage( hWnd, IDD_BROWSE_SELECT_LB, WM_SETREDRAW, 1, 0L );
  1103. ENABLE_LIST( hWnd );
  1104. SetCursorShape( hWnd );
  1105. /* If the user hasn't typed into the printer name field,
  1106. * set the focus to the list:
  1107. */
  1108. if( !GetDlgItemText( hWnd, IDD_BROWSE_PRINTER,
  1109. PrinterName, COUNTOF(PrinterName) ) )
  1110. {
  1111. //
  1112. // Check if the window is visible or not.
  1113. // This is a workaround for the case when we are in a property page
  1114. // where the property page may not be visible at
  1115. // this moment and we didn't want the current control
  1116. // to lose the focus because the background thread has finished
  1117. // its job.
  1118. //
  1119. if( IsWindowVisible(hWnd) )
  1120. {
  1121. SetFocus( GetDlgItem( hWnd, IDD_BROWSE_SELECT_LB ) );
  1122. }
  1123. }
  1124. pBrowseDlgData->Status &= ~BROWSE_STATUS_INITIAL;
  1125. pBrowseDlgData->Status &= ~BROWSE_STATUS_EXPAND;
  1126. }
  1127. }
  1128. else
  1129. {
  1130. UpdateList( hWnd, (INT)pConnectToObject->cSubObjects );
  1131. if( GETLISTSEL( hWnd ) == LB_ERR )
  1132. SETLISTSEL( hWnd, 0 );
  1133. ENABLE_LIST( hWnd );
  1134. pBrowseDlgData->Status &= ~BROWSE_STATUS_EXPAND;
  1135. SetCursor( pBrowseDlgData->hcursorArrow );
  1136. //
  1137. // If no one has focus, set it to the list box.
  1138. // (Common case: double click on machine, listbox
  1139. // is disabled, updated, enabled)
  1140. //
  1141. if ( !GetFocus() )
  1142. SetFocus( GetDlgItem( hWnd, IDD_BROWSE_SELECT_LB ) );
  1143. }
  1144. LEAVE_CRITICAL( pBrowseDlgData );
  1145. }
  1146. VOID ConnectToGetPrinterComplete(
  1147. HWND hWnd,
  1148. LPTSTR pPrinterName,
  1149. PPRINTER_INFO_2 pPrinter,
  1150. DWORD Error )
  1151. {
  1152. PBROWSE_DLG_DATA pBrowseDlgData;
  1153. PCONNECTTO_OBJECT pConnectToData;
  1154. PCONNECTTO_OBJECT pConnectToObject;
  1155. LONG_PTR i;
  1156. DWORD ObjectsFound = 0;
  1157. DWORD Depth = 0;
  1158. DBGMSG( DBG_TRACE, ( "GetPrinterComplete\n" ) );
  1159. i = GETLISTSEL(hWnd);
  1160. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  1161. return;
  1162. pConnectToData = GET_CONNECTTO_DATA(hWnd);
  1163. ENTER_CRITICAL( pBrowseDlgData );
  1164. if( pConnectToData )
  1165. {
  1166. pConnectToObject = GetConnectToObject( pConnectToData->pSubObject,
  1167. pConnectToData->cSubObjects,
  1168. (DWORD)i,
  1169. NULL,
  1170. &ObjectsFound,
  1171. &Depth );
  1172. if( !pConnectToObject || !pPrinterName ||
  1173. !pConnectToObject->pPrinterInfo->pName ||
  1174. _tcscmp( pConnectToObject->pPrinterInfo->pName, pPrinterName ) ) {
  1175. pPrinter = NULL;
  1176. }
  1177. }
  1178. UpdateError( hWnd, Error );
  1179. if( Error == NO_ERROR )
  1180. SetInfoFields( hWnd, pPrinter );
  1181. LEAVE_CRITICAL( pBrowseDlgData );
  1182. }
  1183. VOID ConnectToDestroy( HWND hWnd )
  1184. {
  1185. PBROWSE_DLG_DATA pBrowseDlgData;
  1186. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  1187. return;
  1188. DBGMSG( DBG_TRACE, ( "Terminating browse thread\n" ) );
  1189. ENTER_CRITICAL( pBrowseDlgData );
  1190. DBGMSG( DBG_TRACE, ( "Entered critical section\n" ) );
  1191. SEND_BROWSE_THREAD_REQUEST( pBrowseDlgData,
  1192. BROWSE_THREAD_TERMINATE,
  1193. NULL, NULL );
  1194. DBGMSG( DBG_TRACE, ( "Sent BROWSE_THREAD_TERMINATE\n" ) );
  1195. LEAVE_CRITICAL( pBrowseDlgData );
  1196. DBGMSG( DBG_TRACE, ( "Left critical section\n" ) );
  1197. FreeBitmaps( );
  1198. }
  1199. /*
  1200. *
  1201. */
  1202. VOID ConnectToSelectLbSelChange( HWND hWnd )
  1203. {
  1204. PBROWSE_DLG_DATA pBrowseDlgData;
  1205. PCONNECTTO_OBJECT pConnectToData;
  1206. PCONNECTTO_OBJECT pConnectToObject;
  1207. LONG_PTR i;
  1208. DWORD ObjectsFound = 0;
  1209. DWORD Depth = 0;
  1210. i = GETLISTSEL(hWnd);
  1211. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  1212. return;
  1213. pConnectToData = GET_CONNECTTO_DATA(hWnd);
  1214. ENTER_CRITICAL( pBrowseDlgData );
  1215. SetInfoFields( hWnd, NULL );
  1216. if( pConnectToData )
  1217. {
  1218. pConnectToObject = GetConnectToObject( pConnectToData->pSubObject,
  1219. pConnectToData->cSubObjects,
  1220. (DWORD)i,
  1221. NULL,
  1222. &ObjectsFound,
  1223. &Depth );
  1224. if( pConnectToObject )
  1225. {
  1226. DBGMSG( DBG_TRACE, ( "Selection: " TSTR "\n", pConnectToObject->pPrinterInfo->pName ) );
  1227. if( !( pConnectToObject->pPrinterInfo->Flags & PRINTER_ENUM_CONTAINER ) )
  1228. {
  1229. SetDlgItemText(hWnd, IDD_BROWSE_PRINTER,
  1230. pConnectToObject->pPrinterInfo->pName);
  1231. SEND_BROWSE_THREAD_REQUEST( pBrowseDlgData,
  1232. BROWSE_THREAD_GET_PRINTER,
  1233. pConnectToObject->pPrinterInfo->pName,
  1234. pConnectToObject );
  1235. }
  1236. else
  1237. {
  1238. SetDlgItemText(hWnd, IDD_BROWSE_PRINTER, TEXT(""));
  1239. }
  1240. }
  1241. }
  1242. LEAVE_CRITICAL( pBrowseDlgData );
  1243. }
  1244. /*
  1245. *
  1246. */
  1247. VOID ConnectToSelectLbDblClk( HWND hwnd, HWND hwndListbox )
  1248. {
  1249. PBROWSE_DLG_DATA pBrowseDlgData;
  1250. PCONNECTTO_OBJECT pConnectToData;
  1251. PCONNECTTO_OBJECT pConnectToObject;
  1252. LONG_PTR CurSel;
  1253. DWORD ObjectsFound = 0;
  1254. DWORD Depth = 0;
  1255. CurSel = SendMessage(hwndListbox, LB_GETCURSEL, 0, 0L );
  1256. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA( hwnd ) ) )
  1257. return;
  1258. ENTER_CRITICAL( pBrowseDlgData );
  1259. pConnectToData = GET_CONNECTTO_DATA(hwnd);
  1260. if( pConnectToData )
  1261. {
  1262. pConnectToObject = GetConnectToObject( pConnectToData->pSubObject,
  1263. pConnectToData->cSubObjects,
  1264. (DWORD)CurSel,
  1265. NULL,
  1266. &ObjectsFound,
  1267. &Depth );
  1268. if( pConnectToObject )
  1269. {
  1270. /* If this object is a container, and has not yet been enumerated,
  1271. * call EnumPrinters on this node. If the node has already been
  1272. * expanded, close the subtree:
  1273. */
  1274. if( pConnectToObject->pPrinterInfo->Flags & PRINTER_ENUM_CONTAINER )
  1275. ToggleExpandConnectToObject( hwnd, pConnectToObject );
  1276. else
  1277. {
  1278. //
  1279. // Check if we are in a property page force the
  1280. // wizard to advance to the next page - not only
  1281. // to create the printer connection
  1282. //
  1283. if( pBrowseDlgData->bInPropertyPage )
  1284. {
  1285. PropSheet_PressButton( GetParent( hwnd ), PSBTN_NEXT );
  1286. }
  1287. else
  1288. {
  1289. ConnectToOK( hwnd, TRUE );
  1290. }
  1291. }
  1292. }
  1293. }
  1294. LEAVE_CRITICAL( pBrowseDlgData );
  1295. }
  1296. BOOL
  1297. ConnectToOK(
  1298. HWND hWnd,
  1299. BOOL ForceClose
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. We have a remote printer name, try and form the connection. We
  1304. may need to create a local printer (the masq case) if the print
  1305. providor doesn't support AddPrinterConnection.
  1306. Arguments:
  1307. Return Value:
  1308. --*/
  1309. {
  1310. PBROWSE_DLG_DATA pBrowseDlgData;
  1311. TCHAR szPrinter[kPrinterBufMax];
  1312. LPPRINTER_INFO_1 pPrinter=NULL;
  1313. LPTSTR pListName=NULL; // The name selected in the list
  1314. LPTSTR pConnectToName=NULL; // The name we try to connect to
  1315. DWORD ObjectsFound = 0;
  1316. DWORD Depth = 0;
  1317. BOOL bAdded;
  1318. BOOL bStatus = FALSE;
  1319. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hWnd) ) )
  1320. return FALSE;
  1321. SetCursor( pBrowseDlgData->hcursorWait );
  1322. //
  1323. // Fake a double-click if the focus is on the list box:
  1324. //
  1325. if( !ForceClose &&
  1326. ( GetFocus( ) == GetDlgItem( hWnd, IDD_BROWSE_SELECT_LB ) ) ) {
  1327. SendMessage( hWnd, WM_COMMAND,
  1328. MAKEWPARAM( IDD_BROWSE_SELECT_LB, LBN_DBLCLK ),
  1329. (LPARAM)GetDlgItem( hWnd, IDD_BROWSE_SELECT_LB ) );
  1330. return 0;
  1331. }
  1332. //
  1333. // Get the name from the edit box:
  1334. //
  1335. if( !GetDlgItemText(hWnd, IDD_BROWSE_PRINTER, szPrinter, COUNTOF(szPrinter)) )
  1336. {
  1337. //
  1338. // Check if we are in a property page -
  1339. // to prevent closing
  1340. //
  1341. BOOL bResult = TRUE;
  1342. if( pBrowseDlgData->bInPropertyPage )
  1343. {
  1344. //
  1345. // Display a messge to the user and prevent
  1346. // advancing to the next page
  1347. //
  1348. iMessage( hWnd,
  1349. IDS_ERR_ADD_PRINTER_TITLE,
  1350. IDS_ERR_MISSING_PRINTER_NAME,
  1351. MB_OK|MB_ICONHAND,
  1352. kMsgNone,
  1353. NULL );
  1354. SetWindowLong( hWnd, DWLP_MSGRESULT, -1 );
  1355. }
  1356. else
  1357. {
  1358. //
  1359. // This is the dialog case -
  1360. // just close the dialog
  1361. //
  1362. bResult = ConnectToCancel( hWnd );
  1363. }
  1364. return bResult;
  1365. }
  1366. //
  1367. // Printer names cannot have trailing white spaces.
  1368. //
  1369. vStripTrailWhiteSpace( szPrinter );
  1370. //
  1371. // Add the printer connection, also displaying progress UI.
  1372. //
  1373. pBrowseDlgData->hPrinter = AddPrinterConnectionUI( hWnd,
  1374. szPrinter,
  1375. &bAdded );
  1376. //
  1377. // Check if the printer connection has been sucessfully
  1378. // created/added - this covers also the case if the printer
  1379. // connection already exist (so we don't add new connection)
  1380. //
  1381. if( pBrowseDlgData->hPrinter )
  1382. bStatus = HandleSuccessfulPrinterConnection( hWnd, pBrowseDlgData );
  1383. return bStatus;
  1384. }
  1385. BOOL
  1386. HandleSuccessfulPrinterConnection(
  1387. HWND hWnd,
  1388. PBROWSE_DLG_DATA pBrowseDlgData
  1389. )
  1390. /*++
  1391. Routine Description:
  1392. Handles the situation when successful printer
  1393. connection has been established
  1394. Arguments:
  1395. hWnd - Handle to the dialog/property page
  1396. pBrowseDlgData - The already extracted dialog data
  1397. Return Value:
  1398. TRUE - the message is proccessed fine
  1399. FALSE - an error occured
  1400. --*/
  1401. {
  1402. SPLASSERT( pBrowseDlgData );
  1403. //
  1404. // Assume success
  1405. //
  1406. BOOL bStatus = TRUE;
  1407. //
  1408. // Check if we are in a property page ...
  1409. //
  1410. if( pBrowseDlgData->bInPropertyPage )
  1411. {
  1412. if( pBrowseDlgData->pPageSwitchController )
  1413. {
  1414. //
  1415. // Extract the printer information
  1416. //
  1417. TString strPrinterName, strLocation, strComment, strShareName;
  1418. bStatus = PrintUIGetPrinterInformation( pBrowseDlgData->hPrinter, &strPrinterName, &strLocation, &strComment, &strShareName );
  1419. if( bStatus )
  1420. {
  1421. //
  1422. // Notify the client for the extracted printer information
  1423. //
  1424. pBrowseDlgData->pPageSwitchController->SetPrinterInfo( strPrinterName, strLocation, strComment, strShareName );
  1425. }
  1426. }
  1427. //
  1428. // Prevent the user from leaking the printer handle
  1429. // when going to the next page
  1430. //
  1431. ClosePrinter( pBrowseDlgData->hPrinter );
  1432. pBrowseDlgData->hPrinter = NULL;
  1433. }
  1434. //
  1435. // Perform the actual message processing here
  1436. //
  1437. if( bStatus )
  1438. {
  1439. //
  1440. // Check if we are in a propery page
  1441. //
  1442. if( pBrowseDlgData->bInPropertyPage )
  1443. {
  1444. //
  1445. // Is there a page switch controller provided
  1446. //
  1447. if( pBrowseDlgData->pPageSwitchController )
  1448. {
  1449. UINT uNextPage;
  1450. HRESULT hr = pBrowseDlgData->pPageSwitchController->GetNextPageID( &uNextPage );
  1451. //
  1452. // if S_OK == hr then go to the next page provided
  1453. //
  1454. if( S_OK == hr )
  1455. {
  1456. SetWindowLong( hWnd, DWLP_MSGRESULT, uNextPage );
  1457. }
  1458. else
  1459. {
  1460. //
  1461. // Disable advancing to the next page here
  1462. // per client request (S_FALSE) or in case
  1463. // of an error
  1464. //
  1465. SetWindowLong( hWnd, DWLP_MSGRESULT, -1 );
  1466. }
  1467. }
  1468. else
  1469. {
  1470. //
  1471. // There is no page switch controller provided -
  1472. // just go to the natural next page in the wizard
  1473. //
  1474. SetWindowLong( hWnd, DWLP_MSGRESULT, 0 );
  1475. }
  1476. }
  1477. else
  1478. {
  1479. //
  1480. // This is the dialog case ...
  1481. // just close the dialog
  1482. //
  1483. EndDialog( hWnd, IDOK );
  1484. }
  1485. }
  1486. return bStatus;
  1487. }
  1488. /////////////////////////////////////////////////////////
  1489. // CredUI prototypes
  1490. typedef
  1491. CREDUIAPI
  1492. DWORD
  1493. (WINAPI *PFN_CredUIPromptForCredentialsW)(
  1494. PCREDUI_INFOW pUiInfo,
  1495. PCWSTR pszTargetName,
  1496. PCtxtHandle pContext,
  1497. DWORD dwAuthError,
  1498. PWSTR pszUserName,
  1499. ULONG ulUserNameMaxChars,
  1500. PWSTR pszPassword,
  1501. ULONG ulPasswordMaxChars,
  1502. BOOL *save,
  1503. DWORD dwFlags
  1504. );
  1505. typedef
  1506. CREDUIAPI
  1507. void
  1508. (WINAPI *PFN_CredUIConfirmCredentialsW)(
  1509. PCWSTR pszTargetName,
  1510. BOOL bConfirm
  1511. );
  1512. /////////////////////////////////////////////////////////
  1513. // CCredUILoader
  1514. class CCredUILoader: public CDllLoader
  1515. {
  1516. public:
  1517. CCredUILoader():
  1518. CDllLoader(TEXT("credui.dll")),
  1519. m_pfnCredUIPromptForCredentials(NULL),
  1520. m_pfnCredUIConfirmCredentials(NULL)
  1521. {
  1522. if (CDllLoader::operator BOOL())
  1523. {
  1524. // if the DLL is loaded then do GetProcAddress to the functions we care about
  1525. m_pfnCredUIPromptForCredentials =
  1526. (PFN_CredUIPromptForCredentialsW )GetProcAddress("CredUIPromptForCredentialsW");
  1527. m_pfnCredUIConfirmCredentials =
  1528. (PFN_CredUIConfirmCredentialsW)GetProcAddress("CredUIConfirmCredentialsW");
  1529. }
  1530. }
  1531. operator BOOL () const
  1532. {
  1533. return
  1534. ((CDllLoader::operator BOOL()) &&
  1535. m_pfnCredUIPromptForCredentials &&
  1536. m_pfnCredUIConfirmCredentials);
  1537. }
  1538. PFN_CredUIPromptForCredentialsW m_pfnCredUIPromptForCredentials;
  1539. PFN_CredUIConfirmCredentialsW m_pfnCredUIConfirmCredentials;
  1540. };
  1541. /////////////////////////////////////////////////////////
  1542. // OpenPrinter_CredUI
  1543. inline static BOOL
  1544. IsRPC_SMB(LPTSTR pszPrinter)
  1545. {
  1546. // should have 2 leading slashes
  1547. return (
  1548. lstrlen(pszPrinter) > 2 &&
  1549. TEXT('\\') == pszPrinter[0] &&
  1550. TEXT('\\') == pszPrinter[1]);
  1551. }
  1552. static BOOL
  1553. OpenPrinter_CredUI(HWND hwnd, LPTSTR pszPrinter, LPHANDLE phPrinter, LPPRINTER_DEFAULTS pDefault)
  1554. {
  1555. ASSERT(phPrinter);
  1556. BOOL bRet = FALSE;
  1557. // open the printer to see if we have access to it.
  1558. bRet = OpenPrinter(pszPrinter, phPrinter, pDefault);
  1559. DWORD dwError = GetLastError();
  1560. if (IsRPC_SMB(pszPrinter) && (!bRet && ERROR_ACCESS_DENIED == dwError))
  1561. {
  1562. // OpenPrinter failed because of insufficient permissions.
  1563. // in this case we should call credui to obtain credentials.
  1564. // then we should call WNetAddConnection2. WNetAddConnection2
  1565. // can fail with ERROR_SESSION_CREDENTIAL_CONFLICT if there
  1566. // is existing set of credentials which are in conflict with
  1567. // ours in which case we should offer the user to overwrite
  1568. // the credentials or it can fail with any aother error in the
  1569. // case where pszPrinter is not a share name. in this case we
  1570. // should try \\server\ipc$ to auth the RPC chanell over named
  1571. // pipes and apply the same rules. if WNetAddConnection2 succeeds
  1572. // we make another OpenPrinter attempt and if the credentials
  1573. // are still not sufficient we inform the user and ask if he
  1574. // wants to enter new credentials.
  1575. TCHAR szBuffer[PRINTER_MAX_PATH];
  1576. LPCTSTR pszServerName = NULL, pszPrinterName = NULL;
  1577. // split the full qualified printer name into its components
  1578. HRESULT hr = PrinterSplitFullName(pszPrinter, szBuffer, ARRAYSIZE(szBuffer),
  1579. &pszServerName, &pszPrinterName);
  1580. if (NULL == pszServerName || 0 == pszServerName[0])
  1581. {
  1582. // this is the case where the user passed a server name (like: '\\servername')
  1583. // in this case PrinterSplitFullName succeeds and returns the server name in
  1584. // pszPrinterName.
  1585. pszServerName = pszPrinterName;
  1586. }
  1587. if (SUCCEEDED(hr))
  1588. {
  1589. // load credui.dll
  1590. CCredUILoader credUI;
  1591. if (credUI)
  1592. {
  1593. // in case we need to connect through \\server\ipc$
  1594. BOOL bAskForCredentials = TRUE;
  1595. BOOL bTriedDownlevel = FALSE;
  1596. BOOL bSavePassword = TRUE;
  1597. BOOL bMustConfirmCredentials = FALSE;
  1598. TString strShareIPC;
  1599. if (strShareIPC.bFormat(TEXT("%s\\ipc$"), pszServerName))
  1600. {
  1601. // the server name without slashes
  1602. LPCTSTR pszServer = pszServerName + 2;
  1603. // credui
  1604. DWORD dwCreduiFlags = CREDUI_FLAGS_EXPECT_CONFIRMATION |
  1605. CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX |
  1606. CREDUI_FLAGS_SERVER_CREDENTIAL;
  1607. CREDUI_INFO credUIInfo = { sizeof(CREDUI_INFO), hwnd, NULL, NULL, NULL };
  1608. WCHAR szUserName[CREDUI_MAX_USERNAME_LENGTH + 1];
  1609. WCHAR szPassword[CREDUI_MAX_PASSWORD_LENGTH + 1];
  1610. szUserName[0] = 0;
  1611. szPassword[0] = 0;
  1612. // NETRESOURCE passed to WNetAddConnection2
  1613. NETRESOURCE nr;
  1614. ZeroMemory(&nr, sizeof(nr));
  1615. nr.dwScope = RESOURCE_GLOBALNET;
  1616. nr.dwType = RESOURCETYPE_ANY;
  1617. nr.lpRemoteName = const_cast<LPTSTR>(static_cast<LPCTSTR>(strShareIPC));
  1618. for (;;)
  1619. {
  1620. // try to obtain credentials from cred UI. since
  1621. // we pass in buffers for the username and password
  1622. // credui will *NOT* persist the credentials until
  1623. // we confirm they are fine by calling
  1624. // CredUIConfirmCredentials
  1625. if (bAskForCredentials)
  1626. {
  1627. if (bMustConfirmCredentials)
  1628. {
  1629. // if bMustConfirmCredentials is TRUE and we're here this
  1630. // means the credentials are fake and we need to call
  1631. // CredUIConfirmCredentials(FALSE) to prevent leaking memory.
  1632. credUI.m_pfnCredUIConfirmCredentials(pszServer, FALSE);
  1633. bMustConfirmCredentials = FALSE;
  1634. }
  1635. // ask the user for credentails....
  1636. dwError = credUI.m_pfnCredUIPromptForCredentials(
  1637. &credUIInfo, // PCREDUI_INFOW pUiInfo,
  1638. pszServer, // PCWSTR pszTargetName,
  1639. NULL, // PCtxtHandle pContext,
  1640. dwError, // DWORD dwAuthError,
  1641. szUserName, // PWSTR pszUserName,
  1642. ARRAYSIZE(szUserName), // ULONG ulUserNameMaxChars,
  1643. szPassword, // PWSTR pszPassword,
  1644. ARRAYSIZE(szPassword), // ULONG ulPasswordMaxChars,
  1645. &bSavePassword, // BOOL *save,
  1646. dwCreduiFlags // DWORD dwFlags
  1647. );
  1648. // any further attemts should not ask for credentials unless
  1649. // we explicitly say so!
  1650. bMustConfirmCredentials = TRUE;
  1651. bAskForCredentials = FALSE;
  1652. }
  1653. else
  1654. {
  1655. // assume sucecss if we don't have to ask for credentials
  1656. dwError = ERROR_SUCCESS;
  1657. }
  1658. if (dwError == ERROR_SUCCESS)
  1659. {
  1660. // try the remote name directly assuming it is a printer share
  1661. dwError = WNetAddConnection2(&nr, szPassword, szUserName, 0);
  1662. // handle the possible cases:
  1663. //
  1664. // 1. ERROR_SUCCESS -- the success case. in this case we make another
  1665. // OpenPrinter attempt and in the case the credentials are not yet
  1666. // suffucient we should offer the user to enter new credentials.
  1667. //
  1668. // 2. ERROR_SESSION_CREDENTIAL_CONFLICT -- there is an existing
  1669. // connection with different set of credentials. offer the user
  1670. // to overwrite the credentials with the new ones.
  1671. // this may break some running applications, which rely on the
  1672. // existing connection but we'll leave that up to the user (to decide).
  1673. //
  1674. // 3. [any other error] -- nr.lpRemoteName is not a valid net resource.
  1675. // try using the \\server\ipc$ if not tried already. if tried then
  1676. // just fail silently and propagate the error
  1677. if (ERROR_SUCCESS == dwError)
  1678. {
  1679. // WNetAddConnection2 has succeeded -- let's make
  1680. // another OpenPrinter attempt
  1681. bRet = OpenPrinter(pszPrinter, phPrinter, pDefault);
  1682. dwError = GetLastError();
  1683. if (!bRet && ERROR_ACCESS_DENIED == dwError)
  1684. {
  1685. // got access denied again -- inform the user
  1686. // that the supplied credentials are not sufficient
  1687. // and ask if he wants to try different credentials
  1688. if (IDYES == iMessage(hwnd, IDS_CONNECTTOPRINTER,
  1689. IDS_CREDUI_QUESTION_INSUFFICIENT_CREDENTIALS,
  1690. MB_YESNO|MB_ICONEXCLAMATION, kMsgNone, NULL))
  1691. {
  1692. // delete the connection (force) and try again
  1693. dwError = WNetCancelConnection2(nr.lpRemoteName,
  1694. CONNECT_UPDATE_PROFILE, TRUE);
  1695. if (ERROR_SUCCESS == dwError)
  1696. {
  1697. // the connection was deleted successfuly -- try again
  1698. // asking the user for *new* credentials...
  1699. bAskForCredentials = TRUE;
  1700. continue;
  1701. }
  1702. else
  1703. {
  1704. // WNetCancelConnection2 failed -- this could be
  1705. // because of lack of permissions or something else
  1706. // show UI and cancel the whole operation...
  1707. iMessage(hwnd, IDS_CONNECTTOPRINTER, IDS_CREDUI_CANNOT_DELETE_CREDENTIALS,
  1708. MB_OK|MB_ICONSTOP, dwError, NULL);
  1709. }
  1710. }
  1711. // if we are here cancel the whole operation
  1712. dwError = ERROR_CANCELLED;
  1713. }
  1714. if (bRet && bMustConfirmCredentials)
  1715. {
  1716. // we successfully opened the printer -- we need to
  1717. // confirm the credentials, so they can be saved.
  1718. credUI.m_pfnCredUIConfirmCredentials(pszServer, TRUE);
  1719. bMustConfirmCredentials = FALSE;
  1720. }
  1721. }
  1722. else if (ERROR_SESSION_CREDENTIAL_CONFLICT == dwError)
  1723. {
  1724. // there is a credentials conflict -- ask the user
  1725. // if he wants to force and overwrite the existing
  1726. // credentials -- this may break some running
  1727. // applications but the message box will warn about that.
  1728. if (IDYES == iMessage(hwnd, IDS_CONNECTTOPRINTER,
  1729. IDS_CREDUI_QUESTION_OWERWRITE_CREDENTIALS,
  1730. MB_YESNO|MB_ICONEXCLAMATION, kMsgNone, NULL))
  1731. {
  1732. // delete the connection (force) and try again
  1733. dwError = WNetCancelConnection2(nr.lpRemoteName,
  1734. CONNECT_UPDATE_PROFILE, TRUE);
  1735. if (ERROR_SUCCESS == dwError)
  1736. {
  1737. // the previous connection was deleted successfuly --
  1738. // try again now.
  1739. continue;
  1740. }
  1741. else
  1742. {
  1743. // WNetCancelConnection2 failed -- this could be
  1744. // because of lack of permissions or something else
  1745. // show UI and cancel the whole operation...
  1746. iMessage(hwnd, IDS_CONNECTTOPRINTER,
  1747. IDS_CREDUI_CANNOT_DELETE_CREDENTIALS,
  1748. MB_OK |MB_ICONSTOP, dwError, NULL);
  1749. }
  1750. }
  1751. // if we are here cancel the whole operation
  1752. dwError = ERROR_CANCELLED;
  1753. }
  1754. else if (!bTriedDownlevel)
  1755. {
  1756. // something else failed. in this case we assume that
  1757. // teh remote machine is downlevel server (not NT) and
  1758. // the passed in name is a print share name
  1759. nr.dwType = RESOURCETYPE_PRINT;
  1760. nr.lpRemoteName = pszPrinter;
  1761. bTriedDownlevel = TRUE;
  1762. // let's try again now
  1763. continue;
  1764. }
  1765. }
  1766. if (bMustConfirmCredentials)
  1767. {
  1768. // if bMustConfirmCredentials is TRUE and we're here this
  1769. // means the credentials are fake and we need to call
  1770. // CredUIConfirmCredentials(FALSE) to prevent leaking memory.
  1771. credUI.m_pfnCredUIConfirmCredentials(pszServer, FALSE);
  1772. bMustConfirmCredentials = FALSE;
  1773. }
  1774. // exit the infinite loop here...
  1775. break;
  1776. }
  1777. }
  1778. else
  1779. {
  1780. // the only possible reason bFormat can fail
  1781. dwError = ERROR_OUTOFMEMORY;
  1782. }
  1783. }
  1784. else
  1785. {
  1786. // just preserve the last error
  1787. dwError = GetLastError();
  1788. }
  1789. }
  1790. else
  1791. {
  1792. // convert to Win32 error (if possible)
  1793. dwError = SCODE_CODE(GetScode(hr));
  1794. }
  1795. }
  1796. if (bRet)
  1797. {
  1798. // make sure the last error is correct
  1799. dwError = ERROR_SUCCESS;
  1800. }
  1801. else
  1802. {
  1803. // just in case OpenPrinter has trashed
  1804. // the handle (unlikely, but...)
  1805. *phPrinter = NULL;
  1806. }
  1807. // make sure the last error is set!
  1808. SetLastError(dwError);
  1809. return bRet;
  1810. }
  1811. HANDLE
  1812. AddPrinterConnectionUI(
  1813. HWND hwnd,
  1814. LPCTSTR pszPrinterIn,
  1815. PBOOL pbAdded
  1816. )
  1817. /*++
  1818. Routine Description:
  1819. Add a printer connection with UI. See AddPrinterConnectionUIQuery.
  1820. Arguments:
  1821. hwd - Parent window.
  1822. pszPrinter - Printer to add.
  1823. pbAdded - Indicates whether pszPrinter was added. FALSE = printer
  1824. already existed in some form.
  1825. Return Value:
  1826. HANDLE - hPrinter from pszPrinter.
  1827. --*/
  1828. {
  1829. HANDLE hPrinter = NULL;
  1830. HANDLE hServer;
  1831. TString strPrinter;
  1832. PRINTER_DEFAULTS PrinterDefaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER };
  1833. DWORD dwPrinterAttributes = 0;
  1834. BOOL bNetConnectionAdded = FALSE;
  1835. BOOL bUserDenied = FALSE;
  1836. BOOL bMasq = FALSE;
  1837. BOOL bUnavailableDriver;
  1838. DWORD dwError;
  1839. LPWSTR pszArchLocal = NULL;
  1840. LPWSTR pszArchRemote = NULL;
  1841. LPTSTR pszDriverNew = NULL;
  1842. LPTSTR pszDriver = NULL;
  1843. LPTSTR pszPrinter = (LPTSTR)pszPrinterIn;
  1844. LPTSTR pszPrinterName = NULL;
  1845. *pbAdded = FALSE;
  1846. if( !OpenPrinter_CredUI(hwnd, pszPrinter, &hPrinter, NULL) ){
  1847. DBGMSG( DBG_WARN, ( "OpenPrinter( "TSTR" ) failed: Error = %d\n", pszPrinter, GetLastError( ) ) );
  1848. if (GetLastError() != ERROR_CANCELLED){
  1849. ReportFailure( hwnd,
  1850. IDS_CONNECTTOPRINTER,
  1851. IDS_COULDNOTCONNECTTOPRINTER );
  1852. }
  1853. goto Fail;
  1854. }
  1855. if( !PrinterExists( hPrinter, &dwPrinterAttributes, &pszDriver, &pszPrinterName )){
  1856. DBGMSG( DBG_WARN, ( "Attempt to connect to a non-existent printer.\n" ) );
  1857. //
  1858. // Check for an http*:// prefix.
  1859. //
  1860. if( GetLastError () == ERROR_ACCESS_DENIED &&
  1861. (!_tcsnicmp( pszPrinterIn, gszHttpPrefix0, _tcslen(gszHttpPrefix0)) ||
  1862. !_tcsnicmp( pszPrinterIn, gszHttpPrefix1, _tcslen(gszHttpPrefix1)))) {
  1863. // This is an HTTP printer, we need to give user another chance to enter
  1864. // a different username and password
  1865. if (!ConfigurePort( NULL, hwnd, (LPTSTR) pszPrinterIn)) {
  1866. ReportFailure( hwnd,
  1867. IDS_CONNECTTOPRINTER,
  1868. IDS_COULDNOTCONNECTTOPRINTER );
  1869. goto Fail;
  1870. } else {
  1871. //
  1872. // Retry GetPrinter
  1873. //
  1874. if( !PrinterExists( hPrinter, &dwPrinterAttributes, &pszDriver, &pszPrinterName )){
  1875. DBGMSG( DBG_WARN, ( "2nd Attempt to connect to a non-existent printer.\n" ) );
  1876. goto Fail;
  1877. }
  1878. }
  1879. }
  1880. else {
  1881. ReportFailure( hwnd,
  1882. IDS_CONNECTTOPRINTER,
  1883. IDS_COULDNOTCONNECTTOPRINTER );
  1884. goto Fail;
  1885. }
  1886. }
  1887. if( dwPrinterAttributes & PRINTER_ATTRIBUTE_LOCAL ){
  1888. //
  1889. // This means the printer is a local pseudo-connection
  1890. // probably created when the user tried to connect
  1891. // on a previous occasion.
  1892. //
  1893. goto Done;
  1894. }
  1895. if (AddPrinterConnectionAndPrompt(hwnd, pszPrinter, &bUserDenied, &strPrinter)) {
  1896. //
  1897. // This could be refused by the user,
  1898. //
  1899. if (bUserDenied) {
  1900. goto Fail;
  1901. }
  1902. else {
  1903. goto Done;
  1904. }
  1905. }
  1906. dwError = GetLastError();
  1907. //
  1908. // If this is a KM block issue, display the KM block message and
  1909. // go to Fail
  1910. //
  1911. if( dwError == ERROR_KM_DRIVER_BLOCKED ||
  1912. dwError == ERROR_PRINTER_DRIVER_BLOCKED )
  1913. {
  1914. ReportFailure( hwnd,
  1915. IDS_CONNECTTOPRINTER,
  1916. IDS_COULDNOTCONNECTTOPRINTER );
  1917. goto Fail;
  1918. }
  1919. if (dwError == ERROR_ACCESS_DISABLED_BY_POLICY)
  1920. {
  1921. DisplayMessageFromOtherResourceDll(hwnd,
  1922. IDS_CONNECTTOPRINTER,
  1923. L"xpsp1res.dll",
  1924. IDS_TEXT_POINTANDPRINT_POLICY_PRINTUI_DLL,
  1925. MB_OK | MB_ICONERROR);
  1926. goto Fail;
  1927. }
  1928. bUnavailableDriver = ( dwError == ERROR_UNKNOWN_PRINTER_DRIVER );
  1929. //
  1930. // We failed to add the printer connection. This may occur if
  1931. //
  1932. // 1. This is a mini-print provider, or
  1933. // 2. The driver is not installed on the client or server.
  1934. //
  1935. // In both cases, we need to install the driver locally, so check
  1936. // if we have admin privleges.
  1937. //
  1938. // If the driver was already installed, then AddPrinterConnection
  1939. // would have succeeded. If it wasn't installed, then we need
  1940. // admin privilege to install it, or create the local printer
  1941. // in the masq case, so it's ok to check for admin access here.
  1942. //
  1943. if( !OpenPrinter( NULL, &hServer, &PrinterDefaults )){
  1944. if( GetLastError() == ERROR_ACCESS_DENIED ){
  1945. iMessage( hwnd,
  1946. IDS_CONNECTTOPRINTER,
  1947. IDS_INSUFFPRIV_CREATEPRINTER,
  1948. MB_OK | MB_ICONINFORMATION,
  1949. kMsgNone,
  1950. NULL );
  1951. } else {
  1952. iMessage( hwnd,
  1953. IDS_CONNECTTOPRINTER,
  1954. IDS_CANNOTOPENPRINTER,
  1955. MB_OK | MB_ICONSTOP,
  1956. kMsgNone,
  1957. NULL );
  1958. }
  1959. goto Fail;
  1960. }
  1961. else
  1962. {
  1963. pszArchLocal = GetArch(hServer);
  1964. }
  1965. ClosePrinter( hServer );
  1966. {
  1967. //
  1968. // Create this special scope
  1969. // for SplSetupData var
  1970. //
  1971. SPLSETUP_DATA SplSetupData;
  1972. if( !SplSetupData.bValid )
  1973. {
  1974. DBGMSG( DBG_ERROR, ("AddPrinterConnectionUI: can't initialize SplSetupData -- error %d\n", GetLastError() ) );
  1975. goto Fail;
  1976. }
  1977. //
  1978. // If we have the driver name, we don't need to prompt for it.
  1979. // We may still have true or false connections.
  1980. //
  1981. if( pszDriver && pszDriver[0] ){
  1982. //
  1983. // Check if the reason we failed is because the driver
  1984. // isn't available on the client or server.
  1985. //
  1986. if( bUnavailableDriver ){
  1987. BOOL bSamePlatform = TRUE;
  1988. DWORD dwNeeded = 0;
  1989. LPPRINTER_INFO_2 pPrinterInfo2 = NULL;
  1990. if( pszArchLocal )
  1991. {
  1992. if( !GetPrinter( hPrinter, 2, NULL, 0, &dwNeeded ) &&
  1993. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  1994. NULL != ( pPrinterInfo2 = ( LPPRINTER_INFO_2 ) AllocMem( dwNeeded ) ) &&
  1995. GetPrinter( hPrinter, 2, ( LPBYTE ) pPrinterInfo2, dwNeeded, &dwNeeded ) )
  1996. {
  1997. PRINTER_DEFAULTS PrinterDef = { NULL, NULL, SERVER_READ };
  1998. if( OpenPrinter( pPrinterInfo2->pServerName, &hServer, &PrinterDef ) )
  1999. {
  2000. pszArchRemote = GetArch(hServer);
  2001. if( pszArchRemote )
  2002. {
  2003. bSamePlatform = ( lstrcmpi( pszArchRemote, pszArchLocal ) == 0 );
  2004. }
  2005. }
  2006. ClosePrinter( hServer );
  2007. }
  2008. if( pPrinterInfo2 )
  2009. {
  2010. FreeMem( pPrinterInfo2 );
  2011. }
  2012. }
  2013. //
  2014. // Add the driver.
  2015. //
  2016. if( !AddKnownDriver( &SplSetupData, hwnd, pszDriver, bSamePlatform )){
  2017. //
  2018. // Handles Error UI.
  2019. //
  2020. SplSetupData.ReportErrorMessage( hwnd );
  2021. goto Fail;
  2022. }
  2023. //
  2024. // The only problem was that the driver was not installed, then
  2025. // install the driver and try the AddPrinterConnection again.
  2026. //
  2027. if( !PrintUIAddPrinterConnection( pszPrinter, &strPrinter )){
  2028. ReportFailure( hwnd,
  2029. IDS_CONNECTTOPRINTER,
  2030. IDS_COULDNOTCONNECTTOPRINTER );
  2031. goto Fail;
  2032. }
  2033. } else {
  2034. //
  2035. // We failed, but not becuase the driver is unavailable.
  2036. // It's very likely we have a mini-provider, so
  2037. // create the masq case: we have a local printer that
  2038. // pretends it's network printer. Of course, it's not
  2039. // per-user anymore...
  2040. //
  2041. // Note that our driver may already be installed.
  2042. //
  2043. //
  2044. // The current hPrinter is a handle to the remote printer.
  2045. // We want a handle to the local masq printer instead.
  2046. //
  2047. ClosePrinter( hPrinter );
  2048. bMasq = TRUE;
  2049. hPrinter = CreateLocalPrinter( pszPrinterName,
  2050. pszDriver,
  2051. pszPrinter,
  2052. bMasq,
  2053. NULL );
  2054. if( !hPrinter ){
  2055. //
  2056. // If we failed because we didn't have the driver,
  2057. // then let the user select it and we'll install again.
  2058. //
  2059. dwError = GetLastError();
  2060. if( dwError == ERROR_UNKNOWN_PRINTER_DRIVER ){
  2061. //
  2062. // Add the driver, but don't prompt user if the printer
  2063. // to add is an http printer - just install from local resources.
  2064. // Also, don't prompt the user if we were asked not not show UI
  2065. // in the first place (obviously).
  2066. //
  2067. BOOL bPromptUser = _tcsnicmp( pszPrinter, gszHttpPrefix0, _tcslen(gszHttpPrefix0) ) &&
  2068. _tcsnicmp( pszPrinter, gszHttpPrefix1, _tcslen(gszHttpPrefix1) );
  2069. if( !AddDriver( &SplSetupData,
  2070. hwnd,
  2071. pszDriver,
  2072. bPromptUser,
  2073. &pszDriverNew ) ){
  2074. //
  2075. // Handles Error UI.
  2076. //
  2077. SplSetupData.ReportErrorMessage( hwnd );
  2078. goto Fail;
  2079. }
  2080. hPrinter = CreateLocalPrinter( pszPrinterName,
  2081. pszDriverNew,
  2082. pszPrinter,
  2083. bMasq,
  2084. NULL );
  2085. }
  2086. if( !hPrinter ){
  2087. ReportFailure( hwnd,
  2088. IDS_CONNECTTOPRINTER,
  2089. IDS_COULDNOTCONNECTTOPRINTER );
  2090. goto Fail;
  2091. }
  2092. }
  2093. }
  2094. } else {
  2095. //
  2096. // The driver is not known; we need to prompt the user for it.
  2097. //
  2098. bMasq = TRUE;
  2099. FreeSplStr( pszDriver );
  2100. pszDriver = NULL;
  2101. if( !AddDriver( &SplSetupData,
  2102. hwnd,
  2103. NULL,
  2104. TRUE,
  2105. &pszDriverNew )){
  2106. //
  2107. // Handles Error UI.
  2108. //
  2109. SplSetupData.ReportErrorMessage( hwnd );
  2110. goto Fail;
  2111. }
  2112. //
  2113. // Create the masq case: we have a local printer that
  2114. // pretends it's network printer. Of course, it's not
  2115. // per-user anymore...
  2116. //
  2117. // Close the current handle since it refers to the remote printer,
  2118. // and we want a handle to the local masq printer.
  2119. //
  2120. ClosePrinter( hPrinter );
  2121. hPrinter = CreateLocalPrinter(pszPrinterName,
  2122. pszDriverNew,
  2123. pszPrinter,
  2124. bMasq,
  2125. NULL);
  2126. if( !hPrinter ){
  2127. ReportFailure( hwnd,
  2128. IDS_CONNECTTOPRINTER,
  2129. IDS_COULDNOTCONNECTTOPRINTER );
  2130. goto Fail;
  2131. }
  2132. }
  2133. if(hPrinter && SplSetupData.bDriverAdded){
  2134. //
  2135. // Let the class installer know we have just
  2136. // added a local printer drivers.
  2137. //
  2138. SplSetupData.pfnProcessPrinterAdded(SplSetupData.hDevInfo,
  2139. SplSetupData.pSetupLocalData,
  2140. pszPrinter,
  2141. hwnd);
  2142. }
  2143. }
  2144. Done:
  2145. if( bMasq ){
  2146. SetDevMode( hPrinter );
  2147. }
  2148. *pbAdded = TRUE;
  2149. //
  2150. // If the handle is valid and the connected printer name is not empty
  2151. // and it is not equal to the original name then reopen the printer handle
  2152. // using the actual printer name. This is necessary for callers to have
  2153. // a handle to the printer that was opened with the real printer name.
  2154. //
  2155. if( hPrinter && !strPrinter.bEmpty() && _tcsicmp( strPrinter, pszPrinter ) )
  2156. {
  2157. HANDLE hNewPrinter = NULL;
  2158. if( OpenPrinter( const_cast<LPTSTR>( static_cast<LPCTSTR>( strPrinter ) ), &hNewPrinter, NULL ) )
  2159. {
  2160. ClosePrinter( hPrinter );
  2161. hPrinter = hNewPrinter;
  2162. }
  2163. }
  2164. Fail:
  2165. if( pszArchLocal )
  2166. {
  2167. FreeMem( pszArchLocal );
  2168. }
  2169. if( pszArchRemote )
  2170. {
  2171. FreeMem( pszArchRemote );
  2172. }
  2173. if( !*pbAdded ){
  2174. if( hPrinter ){
  2175. ClosePrinter( hPrinter );
  2176. hPrinter = NULL;
  2177. }
  2178. }
  2179. //
  2180. // Free strings.
  2181. //
  2182. FreeSplStr(pszDriver);
  2183. FreeSplStr(pszDriverNew);
  2184. FreeSplStr(pszPrinterName);
  2185. return hPrinter;
  2186. }
  2187. /*++
  2188. Routine Name:
  2189. AddPrinterConnectionAndPrompt
  2190. Routine Description:
  2191. This checks to see whether the provider supports opening just the server name
  2192. (which implies that it is the win32spl provider),
  2193. Arguments:
  2194. hWnd - The window handle
  2195. pszPrinterName - The name of the printer to which we are adding the connection.
  2196. pbUserDenied - If TRUE, the user decided not to connect to the given printer.
  2197. pstrNewName - The new, possibly shortened, name of the printer.
  2198. Return Value:
  2199. BOOL - If TRUE, the connection was added or the user refused the connection.
  2200. --*/
  2201. BOOL
  2202. AddPrinterConnectionAndPrompt(
  2203. IN HWND hWnd,
  2204. IN PCWSTR pszPrinterName,
  2205. OUT BOOL *pbUserDenied,
  2206. OUT TString *pstrNewName
  2207. )
  2208. {
  2209. TStatusB bRet;
  2210. TString strServerName;
  2211. TString strServerUNC;
  2212. BOOL bOnDomain = FALSE;
  2213. HANDLE hServer = NULL;
  2214. if (!hWnd || !pszPrinterName || !pbUserDenied || !pstrNewName)
  2215. {
  2216. SetLastError(ERROR_INVALID_PARAMETER);
  2217. bRet DBGCHK = FALSE;
  2218. }
  2219. else
  2220. {
  2221. bRet DBGNOCHK = TRUE;
  2222. }
  2223. //
  2224. // Are we on a Domain?
  2225. //
  2226. if (bRet)
  2227. {
  2228. bRet DBGCHK = AreWeOnADomain(&bOnDomain);
  2229. }
  2230. if (bRet && !bOnDomain)
  2231. {
  2232. //
  2233. // Let's check if this is a remote NT server. For this we need the server
  2234. // part of the queue name.
  2235. //
  2236. if (pszPrinterName[0] == L'\\' && pszPrinterName[1] == L'\\')
  2237. {
  2238. bRet DBGCHK = strServerName.bUpdate(&pszPrinterName[2]);
  2239. }
  2240. else
  2241. {
  2242. SetLastError(ERROR_INVALID_PRINTER_NAME);
  2243. bRet DBGCHK = FALSE;
  2244. }
  2245. if (bRet)
  2246. {
  2247. PWSTR pszSlash = const_cast<PWSTR>(wcschr(strServerName, L'\\'));
  2248. if (pszSlash)
  2249. {
  2250. *pszSlash = L'\0';
  2251. }
  2252. else
  2253. {
  2254. SetLastError(ERROR_INVALID_PRINTER_NAME);
  2255. bRet DBGCHK = FALSE;
  2256. }
  2257. }
  2258. //
  2259. // OK, we have the server name part, lets get a UNC name.
  2260. //
  2261. if (bRet)
  2262. {
  2263. bRet DBGCHK = strServerUNC.bFormat(L"\\\\%s", static_cast<PCWSTR>(strServerName));
  2264. }
  2265. //
  2266. // Bit of a hack here, if we can open the server name, then this implies we
  2267. // are talking to an NT Server.
  2268. //
  2269. if (bRet)
  2270. {
  2271. bRet DBGCHK = OpenPrinter(const_cast<PWSTR>(static_cast<PCWSTR>(strServerUNC)), &hServer, NULL);
  2272. }
  2273. if (bRet)
  2274. {
  2275. int Result = DisplayMessageFromOtherResourceDll(hWnd,
  2276. IDS_CONNECTTOPRINTER,
  2277. L"xpsp1res.dll",
  2278. IDS_TEXT_POINTANDPRINT_WARNING_PRINTUI_DLL,
  2279. MB_YESNO | MB_ICONWARNING,
  2280. static_cast<PCWSTR>(strServerName));
  2281. bRet DBGNOCHK = Result == IDYES || Result == IDNO;
  2282. *pbUserDenied = Result == IDNO;
  2283. }
  2284. }
  2285. //
  2286. // If we are on a domain, then the user did not deny us the connection (
  2287. // although, we didn't ask).
  2288. //
  2289. if (bRet && bOnDomain)
  2290. {
  2291. *pbUserDenied = FALSE;
  2292. }
  2293. if (bRet && !*pbUserDenied)
  2294. {
  2295. bRet DBGCHK = PrintUIAddPrinterConnection(pszPrinterName, pstrNewName);
  2296. }
  2297. if (hServer)
  2298. {
  2299. ClosePrinter(hServer);
  2300. }
  2301. return bRet;
  2302. }
  2303. HANDLE
  2304. AddPrinterConnectionNoUI(
  2305. LPCTSTR pszPrinterIn,
  2306. PBOOL pbAdded
  2307. )
  2308. /*++
  2309. Routine Description:
  2310. Add a printer connection silently, this routine will never show UI to the user.
  2311. Since the installation doesn't show UI, we can't make a normal RPC printer
  2312. connection to the remote side since this will refresh the printer driver from
  2313. the remote server. So we create a local printer with a redirected port rather.
  2314. Arguments:
  2315. pszPrinter - Printer to add.
  2316. pbAdded - Indicates whether pszPrinter was added.
  2317. Return Value:
  2318. HANDLE - hPrinter from pszPrinter.
  2319. --*/
  2320. {
  2321. HANDLE hPrinter = NULL;
  2322. BOOL bAdded = FALSE;
  2323. HANDLE hServer = NULL;
  2324. PORT_INFO_1 *pPorts = NULL;
  2325. PRINTER_DEFAULTS Defaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER };
  2326. DWORD cbPorts = 0;
  2327. DWORD cPorts = 0;
  2328. TStatusB bContinue;
  2329. if (!pszPrinterIn || !pbAdded)
  2330. {
  2331. SetLastError(ERROR_INVALID_PARAMETER);
  2332. bContinue DBGCHK = FALSE;
  2333. }
  2334. //
  2335. // First, does the user have local administrator rights on this machine?
  2336. //
  2337. if (bContinue)
  2338. {
  2339. bContinue DBGCHK = OpenPrinter(NULL, &hServer, &Defaults);
  2340. }
  2341. //
  2342. // Get all the port names of the local machine. If this port already exists,
  2343. // we just try and open the printer.
  2344. //
  2345. if (bContinue)
  2346. {
  2347. bContinue DBGCHK = VDataRefresh::bEnumPorts(NULL, 1, reinterpret_cast<VOID **>(&pPorts), &cbPorts, &cPorts);
  2348. }
  2349. //
  2350. // Check to see if a port with the same name that we are already adding
  2351. // exists.
  2352. //
  2353. for(UINT i = 0; bContinue && i < cPorts; i++)
  2354. {
  2355. //
  2356. // The port names match.
  2357. //
  2358. if (!_tcsicmp(pPorts[i].pName, pszPrinterIn))
  2359. {
  2360. //
  2361. // Open the printer and return this is the handle. If it can't
  2362. // open, this is considered a failure, but we don't add the
  2363. // printer.
  2364. //
  2365. (VOID)OpenPrinter(const_cast<PWSTR>(pszPrinterIn), &hPrinter, NULL);
  2366. bContinue DBGNOCHK = FALSE;
  2367. SetLastError(ERROR_ALREADY_EXISTS);
  2368. }
  2369. }
  2370. //
  2371. // The port name does not exist yet. Create the redirected or Masq printer.
  2372. //
  2373. if (bContinue)
  2374. {
  2375. hPrinter = CreateRedirectedPrinter(pszPrinterIn);
  2376. bAdded = hPrinter != NULL;
  2377. }
  2378. //
  2379. // Cleanup any resources used.
  2380. //
  2381. FreeMem(pPorts);
  2382. if (hServer)
  2383. {
  2384. ClosePrinter(hServer);
  2385. }
  2386. if (pbAdded)
  2387. {
  2388. *pbAdded = bAdded;
  2389. }
  2390. return hPrinter;
  2391. }
  2392. /*++
  2393. Routine Name:
  2394. CreateRedirectedPrinter
  2395. Routine Description:
  2396. Create either a local printer with a redirected port to Windows NT or a
  2397. masq printer to a 9x box.
  2398. Arguments:
  2399. pszPrinter - Printer to add.
  2400. Return Value:
  2401. HANDLE - hPrinter from pszPrinter.
  2402. --*/
  2403. HANDLE
  2404. CreateRedirectedPrinter(
  2405. IN PCWSTR pszPrinterIn
  2406. )
  2407. {
  2408. HANDLE hNewPrinter = NULL;
  2409. HANDLE hPrinter = NULL;
  2410. PRINTER_INFO_2 *pPrinterInfo = NULL;
  2411. DWORD cbBuffer = 0;
  2412. BOOL bWinNT = FALSE;
  2413. PWSTR pszPrinterName = NULL;
  2414. PWSTR pszMappedDriver = NULL;
  2415. BOOL bDriverMapped = FALSE;
  2416. BOOL bPortAdded = FALSE;
  2417. DWORD dwLastError = ERROR_SUCCESS;
  2418. TStatusB bSucceeded;
  2419. {
  2420. SPLSETUP_DATA SplSetupData;
  2421. bSucceeded DBGCHK = SplSetupData.bValid;
  2422. if (!bSucceeded)
  2423. {
  2424. DBGMSG(DBG_ERROR, ("CreateRedirectedPrinter: can't initialize SplSetupData -- error %d\n", GetLastError()));
  2425. }
  2426. if (bSucceeded)
  2427. {
  2428. bSucceeded DBGCHK = OpenPrinter(const_cast<PWSTR>(pszPrinterIn), &hPrinter, NULL);
  2429. }
  2430. //
  2431. // Get the printer info for the remote printer. From this we can determine
  2432. // the required driver and we can get the devmode for applying to the printer
  2433. // later.
  2434. //
  2435. if (bSucceeded)
  2436. {
  2437. bSucceeded DBGCHK = VDataRefresh::bGetPrinter(hPrinter,
  2438. 2,
  2439. reinterpret_cast<VOID **>(&pPrinterInfo),
  2440. &cbBuffer);
  2441. }
  2442. //
  2443. // We need the driver name, or we can't add the local printer.
  2444. //
  2445. if (bSucceeded)
  2446. {
  2447. bSucceeded DBGNOCHK = pPrinterInfo->pDriverName && *pPrinterInfo->pDriverName;
  2448. if (!bSucceeded)
  2449. {
  2450. SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
  2451. }
  2452. }
  2453. if (bSucceeded)
  2454. {
  2455. //
  2456. // If we are being asked to make a connection to ourselves, the server
  2457. // name we retrieve from the spooler will be NULL. Since unlike
  2458. // AddPrinterConnection this will result in a printer in the desktop,
  2459. // kill this attempt now.
  2460. //
  2461. if (pPrinterInfo->pServerName && *pPrinterInfo->pServerName)
  2462. {
  2463. //
  2464. // Determine whether we are talking to a Win9X or an NT server.
  2465. //
  2466. if (bSucceeded)
  2467. {
  2468. HRESULT hr = IsNTServer(pPrinterInfo->pServerName);
  2469. if (hr == S_OK)
  2470. {
  2471. bWinNT = TRUE;
  2472. }
  2473. else if (FAILED(hr))
  2474. {
  2475. SetLastError(HRESULT_CODE(hr));
  2476. bSucceeded DBGCHK = FALSE;
  2477. }
  2478. }
  2479. //
  2480. // If we are talking to an NT server, then create a name rather like a
  2481. // connection name for the printer and create a local port to represent
  2482. // it.
  2483. //
  2484. if (bSucceeded)
  2485. {
  2486. if (bWinNT)
  2487. {
  2488. bSucceeded DBGCHK = BuildNTPrinterName(pPrinterInfo, &pszPrinterName);
  2489. }
  2490. else
  2491. {
  2492. BuildMasqPrinterName(pPrinterInfo, &pszPrinterName);
  2493. bSucceeded DBGCHK = pszPrinterName != NULL;
  2494. }
  2495. }
  2496. //
  2497. // Check to see whether we have a mapping for the printer driver.
  2498. //
  2499. if (bSucceeded)
  2500. {
  2501. bSucceeded DBGCHK = SplSetupData.pfnFindMappedDriver(bWinNT,
  2502. pPrinterInfo->pDriverName,
  2503. &pszMappedDriver,
  2504. &bDriverMapped);
  2505. }
  2506. //
  2507. // If we are talking to an NT Server, create the local redirected port.
  2508. //
  2509. if (bSucceeded && bWinNT)
  2510. {
  2511. bSucceeded DBGCHK = CreateLocalPort(pszPrinterIn);
  2512. bPortAdded = bSucceeded;
  2513. }
  2514. //
  2515. // Try to Create the local printer.
  2516. //
  2517. if (bSucceeded)
  2518. {
  2519. hNewPrinter = CreateLocalPrinter(pszPrinterName,
  2520. pszMappedDriver,
  2521. pszPrinterIn,
  2522. !bWinNT,
  2523. pPrinterInfo->pDevMode);
  2524. bSucceeded DBGCHK = hNewPrinter != NULL;
  2525. //
  2526. // We couldn't create the local printer because the driver wasn't there.
  2527. // Or, somehow a version 2 driver was put on the machine, and the
  2528. // corresponding V3 driver isn't there. In this case, try to add the
  2529. // driver ourselves.
  2530. //
  2531. if (!bSucceeded &&
  2532. (GetLastError() == ERROR_UNKNOWN_PRINTER_DRIVER ||
  2533. GetLastError() == ERROR_KM_DRIVER_BLOCKED))
  2534. {
  2535. //
  2536. // Add the in-box printer driver silently.
  2537. //
  2538. DWORD Status = SplSetupData.pfnInstallInboxDriverSilently(pszMappedDriver);
  2539. if (Status != ERROR_SUCCESS)
  2540. {
  2541. SetLastError(Status);
  2542. bSucceeded DBGCHK = FALSE;
  2543. }
  2544. else
  2545. {
  2546. bSucceeded DBGCHK = TRUE;
  2547. }
  2548. if (bSucceeded)
  2549. {
  2550. hNewPrinter = CreateLocalPrinter(pszPrinterName,
  2551. pszMappedDriver,
  2552. pszPrinterIn,
  2553. !bWinNT,
  2554. pPrinterInfo->pDevMode);
  2555. bSucceeded DBGCHK = hNewPrinter != NULL;
  2556. }
  2557. }
  2558. }
  2559. }
  2560. }
  2561. //
  2562. // If we added the port, but failed to add the printer, delete the port.
  2563. //
  2564. if (!bSucceeded && bPortAdded)
  2565. {
  2566. DeletePort(NULL, NULL, const_cast<PWSTR>(pszPrinterIn));
  2567. }
  2568. //
  2569. // The SplSetupData class overwrites the last error when it is
  2570. // destructed. So, save the last error here,
  2571. //
  2572. dwLastError = GetLastError();
  2573. //
  2574. // Clean up all of our local resources.
  2575. //
  2576. if (hPrinter)
  2577. {
  2578. ClosePrinter(hPrinter);
  2579. }
  2580. FreeMem(pPrinterInfo);
  2581. FreeSplStr(pszPrinterName);
  2582. if (pszMappedDriver)
  2583. {
  2584. (VOID)SplSetupData.pfnFreeMem(pszMappedDriver);
  2585. }
  2586. }
  2587. SetLastError(dwLastError);
  2588. return hNewPrinter;
  2589. }
  2590. /*++
  2591. Routine Name:
  2592. GetArch
  2593. Routine Description:
  2594. Return the architecture of the given server.
  2595. Arguments:
  2596. hServer - The server whose architecture to retrieve,
  2597. Return Value:
  2598. An allocated string with the architecture.
  2599. --*/
  2600. LPWSTR
  2601. GetArch(
  2602. HANDLE hServer
  2603. )
  2604. {
  2605. LPWSTR pszRetArch = NULL;
  2606. WCHAR szArch[kStrMax] = {0};
  2607. DWORD dwNeeded = 0;
  2608. if( ERROR_SUCCESS == GetPrinterData( hServer,
  2609. SPLREG_ARCHITECTURE,
  2610. NULL,
  2611. (PBYTE)szArch,
  2612. sizeof( szArch ),
  2613. &dwNeeded ) )
  2614. {
  2615. if( NULL != ( pszRetArch = (LPWSTR)AllocMem(dwNeeded*sizeof(*szArch)) ) )
  2616. {
  2617. lstrcpyn( pszRetArch, szArch, dwNeeded );
  2618. }
  2619. }
  2620. return pszRetArch;
  2621. }
  2622. /* BuildMasqPrinterName
  2623. *
  2624. * generates a proper printer name for masq printers
  2625. */
  2626. VOID
  2627. BuildMasqPrinterName(
  2628. IN PPRINTER_INFO_2 pPrinter,
  2629. OUT PWSTR *ppszPrinterName
  2630. )
  2631. {
  2632. ASSERT(pPrinter);
  2633. ASSERT(ppszPrinterName);
  2634. // if this is an http printer, we need to take the server name (http://server) from pPrinter->pPortName
  2635. // if this is downlevel printer then the pPrinter->pPortName is NULL
  2636. TCHAR *p = NULL;
  2637. if( pPrinter->pPortName )
  2638. {
  2639. // check if the server is http://server
  2640. if( !p && !_tcsnicmp(pPrinter->pPortName, gszHttpPrefix0, _tcslen(gszHttpPrefix0)) )
  2641. {
  2642. p = pPrinter->pPortName + _tcslen(gszHttpPrefix0);
  2643. }
  2644. // check if the server is https://server
  2645. if( !p && !_tcsnicmp(pPrinter->pPortName, gszHttpPrefix1, _tcslen(gszHttpPrefix1)) )
  2646. {
  2647. p = pPrinter->pPortName + _tcslen(gszHttpPrefix1);
  2648. }
  2649. }
  2650. if( p )
  2651. {
  2652. // this is http printer, we need to build the name in the following format
  2653. // \\http://server\printer
  2654. LPCTSTR pszServer;
  2655. LPCTSTR pszPrinter;
  2656. TCHAR szScratch[kPrinterBufMax];
  2657. // split the full printer name into its components.
  2658. vPrinterSplitFullName(szScratch, pPrinter->pPrinterName, &pszServer, &pszPrinter);
  2659. // go to the end of the server name & terminate p
  2660. for( ; *p && *p != _T('/'); p++ ) { } *p = 0;
  2661. // now pPrinter->pPortName now should be "http://server" or "https://server"
  2662. pszServer = pPrinter->pPortName;
  2663. if( pszServer && *pszServer )
  2664. {
  2665. // build the masq printer name here (i.e. "\\http://server\printer")
  2666. TString strPrinterName;
  2667. if( strPrinterName.bFormat(_T("\\\\%s\\%s"), pszServer, pszPrinter) )
  2668. {
  2669. *ppszPrinterName = AllocSplStr(strPrinterName);
  2670. }
  2671. }
  2672. }
  2673. else
  2674. {
  2675. // the friendly name is the same as pPrinter->pPrinterName
  2676. *ppszPrinterName = AllocSplStr(pPrinter->pPrinterName);
  2677. }
  2678. }
  2679. /* PrinterExists
  2680. *
  2681. * check if the printer exists & return some of its
  2682. * attributes/data.
  2683. */
  2684. BOOL
  2685. PrinterExists(
  2686. HANDLE hPrinter,
  2687. PDWORD pAttributes,
  2688. LPTSTR *ppszDriver,
  2689. LPTSTR *ppszPrinterName
  2690. )
  2691. {
  2692. BOOL bReturn = FALSE;
  2693. DWORD cb = 0;
  2694. CAutoPtrSpl<PRINTER_INFO_2> spPI2;
  2695. ASSERT(ppszDriver);
  2696. ASSERT(ppszPrinterName);
  2697. *ppszDriver = NULL;
  2698. *ppszPrinterName = NULL;
  2699. bReturn = VDataRefresh::bGetPrinter(hPrinter, 2, spPI2.GetPPV(), &cb);
  2700. if( bReturn )
  2701. {
  2702. // return the driver & attributes
  2703. *pAttributes = spPI2->Attributes;
  2704. *ppszDriver = AllocSplStr(spPI2->pDriverName);
  2705. // generate a friendly name - i.e.
  2706. // "printer or server" or "printer on http://server"
  2707. BuildMasqPrinterName(spPI2, ppszPrinterName);
  2708. }
  2709. else
  2710. {
  2711. // this is a bit of a hack:
  2712. //
  2713. // OpenPrinter returns a valid handle if the name of a server is passed in.
  2714. // we need to call GetPrinter with that handle to check that it's a printer.
  2715. // if this call fails, the error will have been set to ERROR_INVALID_HANDLE,
  2716. // whereas it really should be ERROR_INVALID_PRINTER_NAME.
  2717. if( ERROR_INVALID_HANDLE == GetLastError() )
  2718. {
  2719. SetLastError( ERROR_INVALID_PRINTER_NAME );
  2720. }
  2721. }
  2722. return bReturn;
  2723. }
  2724. /*++
  2725. Routine Name:
  2726. BuildNTPrinterName
  2727. Routine Description:
  2728. This builds the name of the NT printer, if the name is \\Foo\Bar, we will
  2729. call it Auto Foo on Bar. This will be the real printer name to ensure that the
  2730. UI does not confuse it with a printer connection which causes problems in
  2731. the shell folder.
  2732. Arguments:
  2733. pPrinter - The printer info for the printer
  2734. ppszPrinterName - The returned
  2735. Return Value:
  2736. An allocated string with the architecture.
  2737. --*/
  2738. BOOL
  2739. BuildNTPrinterName(
  2740. IN PRINTER_INFO_2 *pPrinter,
  2741. OUT PWSTR *ppszPrinterName
  2742. )
  2743. {
  2744. PCWSTR pszPrinterName = NULL;
  2745. PCWSTR pszServerName = NULL;
  2746. WCHAR szScratch[kPrinterBufMax];
  2747. TString strNtConnectName;
  2748. TStatusB bRet;
  2749. if (!pPrinter || !pPrinter->pPrinterName || !ppszPrinterName)
  2750. {
  2751. SetLastError(ERROR_INVALID_PARAMETER);
  2752. bRet DBGCHK = FALSE;
  2753. }
  2754. else
  2755. {
  2756. bRet DBGCHK = TRUE;
  2757. }
  2758. //
  2759. // Split the printer name into a server name and printer name. Then we will
  2760. // load the resource and format the message string.
  2761. //
  2762. if (bRet)
  2763. {
  2764. vPrinterSplitFullName(szScratch, pPrinter->pPrinterName, &pszServerName, &pszPrinterName);
  2765. //
  2766. // Strip the leading \\ from the server name.
  2767. //
  2768. if(pszServerName[0] == L'\\' && pszServerName[1] == L'\\')
  2769. {
  2770. pszServerName = pszServerName + 2;
  2771. }
  2772. bRet DBGCHK = bConstructMessageString(ghInst, strNtConnectName, IDS_DSPTEMPLATE_NETCRAWLER, pszPrinterName, pszServerName);
  2773. }
  2774. //
  2775. // If this succeeds, allocate a copy a string back. We do this so the caller
  2776. // can free the string just as it does with BuildMasqPrinterName.
  2777. //
  2778. if (bRet)
  2779. {
  2780. *ppszPrinterName = AllocSplStr(strNtConnectName);
  2781. bRet DBGCHK = *ppszPrinterName != NULL;
  2782. }
  2783. return bRet;
  2784. }
  2785. /* CreateLocalPrinter
  2786. *
  2787. * creates a local masq printer with the specified
  2788. * name, driver & port.
  2789. */
  2790. HANDLE
  2791. CreateLocalPrinter(
  2792. IN LPCTSTR pPrinterName,
  2793. IN LPCTSTR pDriverName,
  2794. IN LPCTSTR pPortName,
  2795. IN BOOL bMasqPrinter,
  2796. IN DEVMODE *pDevMode OPTIONAL
  2797. )
  2798. {
  2799. // make sure the name is unique
  2800. TCHAR szPrinterName[kPrinterBufMax];
  2801. if( NewFriendlyName(NULL, pPrinterName, szPrinterName) )
  2802. {
  2803. pPrinterName = szPrinterName;
  2804. }
  2805. // set the printer info fields to actually create the masq printer.
  2806. PRINTER_INFO_2 pi2 = {0};
  2807. pi2.pPrinterName = const_cast<PTSTR>(pPrinterName);
  2808. pi2.pDriverName = const_cast<PTSTR>(pDriverName);
  2809. pi2.pPortName = const_cast<PTSTR>(pPortName);
  2810. pi2.pPrintProcessor = (LPTSTR)gszDefaultPrintProcessor;
  2811. pi2.pDevMode = pDevMode;
  2812. pi2.Attributes = PRINTER_ATTRIBUTE_LOCAL;
  2813. if (bMasqPrinter)
  2814. {
  2815. pi2.Attributes |= PRINTER_ATTRIBUTE_NETWORK;
  2816. }
  2817. // ask the spooler to create a masq printer for us
  2818. // (i.e. attributes should be local + network).
  2819. return AddPrinter(NULL, 2, (LPBYTE)&pi2 );
  2820. }
  2821. /*
  2822. *
  2823. */
  2824. BOOL ConnectToCancel( HWND hWnd )
  2825. {
  2826. PBROWSE_DLG_DATA pBrowseDlgData = GET_BROWSE_DLG_DATA( hWnd );
  2827. SPLASSERT( pBrowseDlgData );
  2828. //
  2829. // Check if we are in property page
  2830. //
  2831. if( pBrowseDlgData->bInPropertyPage )
  2832. {
  2833. BOOL bEnableClose = TRUE;
  2834. //
  2835. // Check if there is page switch controller provided
  2836. //
  2837. if( pBrowseDlgData->pPageSwitchController )
  2838. {
  2839. if( S_OK == pBrowseDlgData->pPageSwitchController->QueryCancel( ) )
  2840. {
  2841. //
  2842. // We must prevent closing in this case
  2843. //
  2844. bEnableClose = FALSE;
  2845. }
  2846. }
  2847. if( bEnableClose )
  2848. {
  2849. //
  2850. // Allow closing operation
  2851. //
  2852. SetWindowLong( hWnd, DWLP_MSGRESULT, FALSE );
  2853. }
  2854. else
  2855. {
  2856. //
  2857. // Prevent closing operation
  2858. //
  2859. SetWindowLong( hWnd, DWLP_MSGRESULT, TRUE );
  2860. }
  2861. }
  2862. else
  2863. {
  2864. //
  2865. // We are in dialog box -
  2866. // Just close dialog with IDCANCEL
  2867. //
  2868. EndDialog( hWnd, IDCANCEL );
  2869. }
  2870. //
  2871. // Always processing this message
  2872. //
  2873. return TRUE;
  2874. }
  2875. /* GetConnectToObject
  2876. *
  2877. * Does a recursive search down the ConnectTo object tree to find the Nth
  2878. * object, where Index == N.
  2879. * On the top-level call, *pObjectsFound must be initialised to zero,
  2880. * and this value is incremented each time an object in the tree is encountered.
  2881. * On any given level, if *pObjectsFound equals the index being sought,
  2882. * then a pointer to the corresponding ConnectTo object is returned.
  2883. * If the index hasn't yet been reached, the function is called recursively
  2884. * on any subobjects.
  2885. *
  2886. * Arguments:
  2887. *
  2888. * pFirstConnectToObject - Pointer to the first ConnectTo object
  2889. * in the array of objects at a given level.
  2890. *
  2891. * cThisLevelObjects - The number of objects in the array at this level.
  2892. *
  2893. * Index - Which object is requested. E.g. if the top item in the printers
  2894. * list box is being drawn, this will be 0.
  2895. *
  2896. * pObjectsFound - A pointer to the number of objects encountered so far in
  2897. * the search. This must be initialised to zero by the top-level caller.
  2898. *
  2899. * pDepth - A pointer to the depth of the object found in the search.
  2900. * This value is zero-based and must be initialised to zero
  2901. * by the top-level caller.
  2902. *
  2903. * Return:
  2904. *
  2905. * A pointer to the CONNECTTO_OBJECT if found, otherwise NULL.
  2906. *
  2907. *
  2908. * Author: andrewbe July 1992
  2909. *
  2910. *
  2911. */
  2912. PCONNECTTO_OBJECT GetConnectToObject(
  2913. IN PCONNECTTO_OBJECT pFirstConnectToObject,
  2914. IN DWORD cThisLevelObjects,
  2915. IN DWORD Index,
  2916. IN PCONNECTTO_OBJECT pFindObject,
  2917. OUT PDWORD pObjectsFound,
  2918. OUT PDWORD pDepth )
  2919. {
  2920. PCONNECTTO_OBJECT pConnectToObject = NULL;
  2921. DWORD i = 0;
  2922. while( !pConnectToObject && ( i < cThisLevelObjects ) )
  2923. {
  2924. if (&pFirstConnectToObject[i] == pFindObject ||
  2925. (!pFindObject && *pObjectsFound == Index))
  2926. {
  2927. pConnectToObject = &pFirstConnectToObject[i];
  2928. }
  2929. /* Make a recursive call on any objects which have subobjects:
  2930. */
  2931. else if( pFirstConnectToObject[i].pSubObject )
  2932. {
  2933. (*pObjectsFound)++; // Add the current object to the total count
  2934. pConnectToObject = GetConnectToObject(
  2935. pFirstConnectToObject[i].pSubObject,
  2936. pFirstConnectToObject[i].cSubObjects,
  2937. Index,
  2938. pFindObject,
  2939. pObjectsFound,
  2940. pDepth );
  2941. if( pConnectToObject )
  2942. (*pDepth)++;
  2943. }
  2944. else
  2945. (*pObjectsFound)++; // Add the current object to the total count
  2946. i++; // Increment to the next object at this level
  2947. }
  2948. return pConnectToObject;
  2949. }
  2950. /* GetDefaultExpand
  2951. *
  2952. * Searches one level of enumerated objects to find the first one with the
  2953. * PRINTER_ENUM_EXPAND flag set.
  2954. * This flag should have been set by the spooler to guide us to the user's
  2955. * logon domain, so we can show the printers in that domain straight away.
  2956. * The user can disable this behaviour by unchecking the box in the ConnectTo
  2957. * dialog. If this has been done, this function will return NULL immediately.
  2958. *
  2959. * Arguments:
  2960. *
  2961. * pFirstConnectToObject - Pointer to the first ConnectTo object
  2962. * in the array of objects at a given level.
  2963. *
  2964. * cThisLevelObjects - The number of objects in the array at this level.
  2965. *
  2966. * pIndex - A pointer to a DWORD which will receive the index of the
  2967. * object found in the array.
  2968. *
  2969. * Return:
  2970. *
  2971. * A pointer to the CONNECTTO_OBJECT if found, otherwise NULL.
  2972. *
  2973. *
  2974. * Author: andrewbe December 1992 (based on GetConnectToObject)
  2975. *
  2976. *
  2977. */
  2978. PCONNECTTO_OBJECT GetDefaultExpand(
  2979. IN PCONNECTTO_OBJECT pFirstConnectToObject,
  2980. IN DWORD cThisLevelObjects,
  2981. OUT PDWORD pIndex )
  2982. {
  2983. PCONNECTTO_OBJECT pDefaultExpand = NULL;
  2984. DWORD i = 0;
  2985. while( !pDefaultExpand && ( i < cThisLevelObjects ) )
  2986. {
  2987. if( pFirstConnectToObject[i].pPrinterInfo->Flags & PRINTER_ENUM_EXPAND )
  2988. pDefaultExpand = &pFirstConnectToObject[i];
  2989. else
  2990. i++; // Increment to the next object at this level
  2991. }
  2992. *pIndex = i;
  2993. return pDefaultExpand;
  2994. }
  2995. /* FreeConnectToObjects
  2996. *
  2997. * Frees the array of objects on the current level, after making a recursive
  2998. * call on any subobjects of members of the array.
  2999. *
  3000. * Arguments:
  3001. *
  3002. * pFirstConnectToObject - Pointer to the first ConnectTo object in the array
  3003. * of objects at a given level.
  3004. *
  3005. * cThisLevelObjects - The number of objects in the array at this level.
  3006. *
  3007. * cbThisLevelObjects - The size of the the array at this level.
  3008. *
  3009. * Return:
  3010. *
  3011. * The number of objects actually removed, regardless of errors.
  3012. *
  3013. *
  3014. * Author: andrewbe July 1992
  3015. */
  3016. DWORD FreeConnectToObjects(
  3017. IN PCONNECTTO_OBJECT pFirstConnectToObject,
  3018. IN DWORD cThisLevelObjects,
  3019. IN DWORD cbPrinterInfo )
  3020. {
  3021. DWORD i;
  3022. DWORD SubObjectsFreed = 0;
  3023. if( ( cThisLevelObjects > 0 ) && pFirstConnectToObject->pPrinterInfo )
  3024. FreeSplMem( pFirstConnectToObject->pPrinterInfo );
  3025. for( i = 0; i < cThisLevelObjects; i++ )
  3026. {
  3027. /* Make a recursive call on any objects which have subobjects:
  3028. */
  3029. if( pFirstConnectToObject[i].pSubObject )
  3030. {
  3031. SubObjectsFreed = FreeConnectToObjects(
  3032. pFirstConnectToObject[i].pSubObject,
  3033. pFirstConnectToObject[i].cSubObjects,
  3034. pFirstConnectToObject[i].cbPrinterInfo );
  3035. }
  3036. }
  3037. if( cThisLevelObjects > 0 )
  3038. FreeSplMem( pFirstConnectToObject );
  3039. return ( SubObjectsFreed + cThisLevelObjects );
  3040. }
  3041. /* ToggleExpandConnectToObject
  3042. *
  3043. * Expands or collapses the node accordingly.
  3044. *
  3045. * Arguments:
  3046. *
  3047. * hwndListbox - Handle of the listbox containing the printer info.
  3048. *
  3049. * pConnectToObject - The node to be expanded or collapsed.
  3050. * If it has already been expanded, collapse it, otherwise expand it.
  3051. *
  3052. * Return:
  3053. *
  3054. * TRUE if no error occurred.
  3055. *
  3056. */
  3057. BOOL ToggleExpandConnectToObject(
  3058. HWND hwnd,
  3059. PCONNECTTO_OBJECT pConnectToObject )
  3060. {
  3061. PBROWSE_DLG_DATA pBrowseDlgData;
  3062. DWORD ObjectsRemoved = 0;
  3063. if( !( pBrowseDlgData = GET_BROWSE_DLG_DATA(hwnd) ) )
  3064. return FALSE;
  3065. ASSERT( pBrowseDlgData->csLock.bInside() );
  3066. if( pConnectToObject->pSubObject )
  3067. {
  3068. ObjectsRemoved = FreeConnectToObjects(
  3069. &pConnectToObject->pSubObject[0],
  3070. pConnectToObject->cSubObjects,
  3071. pConnectToObject->cbPrinterInfo );
  3072. pConnectToObject->pSubObject = NULL;
  3073. pConnectToObject->cSubObjects = 0;
  3074. pConnectToObject->cbPrinterInfo = 0;
  3075. UpdateList( hwnd, ( - (INT)ObjectsRemoved ) );
  3076. SetCursor( pBrowseDlgData->hcursorArrow );
  3077. }
  3078. else
  3079. {
  3080. pBrowseDlgData->Status |= BROWSE_STATUS_EXPAND;
  3081. SetCursorShape( hwnd );
  3082. DISABLE_LIST(hwnd);
  3083. SEND_BROWSE_THREAD_REQUEST( pBrowseDlgData,
  3084. BROWSE_THREAD_ENUM_OBJECTS,
  3085. pConnectToObject->pPrinterInfo->pName,
  3086. pConnectToObject );
  3087. }
  3088. return TRUE;
  3089. }
  3090. BOOL UpdateList(
  3091. HWND hwnd,
  3092. INT Increment )
  3093. {
  3094. HWND hwndListbox;
  3095. LONG_PTR CurSel;
  3096. LONG_PTR OldCount;
  3097. DWORD ObjectsRemoved = 0;
  3098. LONG_PTR NewObjectsOutOfView;
  3099. ULONG_PTR TopIndex;
  3100. ULONG_PTR BottomIndex;
  3101. RECT CurrentSelectionRect;
  3102. RECT ListboxRect;
  3103. DWORD Error = 0;
  3104. ASSERT( GET_BROWSE_DLG_DATA(hwnd)->csLock.bInside() );
  3105. hwndListbox = GetDlgItem( hwnd, IDD_BROWSE_SELECT_LB );
  3106. CurSel = SendMessage( hwndListbox, LB_GETCURSEL, 0, 0L );
  3107. SendMessage( hwndListbox, WM_SETREDRAW, 0, 0L );
  3108. TopIndex = SendMessage( hwndListbox, LB_GETTOPINDEX, 0, 0 );
  3109. OldCount = SendMessage( hwndListbox, LB_GETCOUNT, 0, 0 );
  3110. DBGMSG( DBG_TRACE, ( "Setting list count to %d\n", OldCount + Increment ) );
  3111. SendMessage( hwndListbox, LB_SETCOUNT, OldCount + Increment, 0 );
  3112. if( Increment > 0 )
  3113. {
  3114. GetClientRect( hwndListbox, &ListboxRect );
  3115. BottomIndex = ( TopIndex +
  3116. ( ListboxRect.bottom / STATUS_BITMAP_HEIGHT ) - 1 );
  3117. NewObjectsOutOfView = ( CurSel + Increment - BottomIndex );
  3118. if( NewObjectsOutOfView > 0 )
  3119. {
  3120. TopIndex = min( CurSel, (LONG_PTR) ( TopIndex + NewObjectsOutOfView ) );
  3121. }
  3122. }
  3123. SendMessage( hwndListbox, LB_SETCURSEL, CurSel, 0L );
  3124. SendMessage( hwndListbox, LB_SETTOPINDEX, TopIndex, 0 );
  3125. SendMessage( hwndListbox, WM_SETREDRAW, 1, 0L );
  3126. SendMessage( hwndListbox, LB_GETITEMRECT, CurSel,
  3127. (LPARAM)&CurrentSelectionRect );
  3128. InvalidateRect( hwndListbox, NULL, FALSE );
  3129. return TRUE;
  3130. }
  3131. /* GetPrinterStatusString
  3132. *
  3133. * Loads the resource string corresponding to the supplied status code.
  3134. *
  3135. * andrewbe wrote it - April 1992
  3136. */
  3137. int GetPrinterStatusString( DWORD Status, LPTSTR string )
  3138. {
  3139. int stringID = -1;
  3140. if( Status & PRINTER_STATUS_ERROR )
  3141. stringID = IDS_ERROR;
  3142. else
  3143. if( Status & PRINTER_STATUS_PAUSED )
  3144. stringID = IDS_PAUSED;
  3145. else
  3146. if( Status & PRINTER_STATUS_PENDING_DELETION )
  3147. stringID = IDS_PENDING_DELETION;
  3148. else
  3149. stringID = IDS_READY;
  3150. if( stringID != -1 )
  3151. {
  3152. return LoadString( ghInst, stringID, string, MAX_PATH );
  3153. }
  3154. return FALSE;
  3155. }
  3156. /////////////////////////////////////////////////////////////////////////////
  3157. //
  3158. // SetInfoFields
  3159. //
  3160. // This routine sets the Printer Information and selected printer textbox
  3161. // fields to the currently selected item in the Select Printer listbox.
  3162. //
  3163. // TO DO:
  3164. // error checking for win api calls
  3165. // get strings from resource file
  3166. //
  3167. //
  3168. /////////////////////////////////////////////////////////////////////////////
  3169. BOOL SetInfoFields (
  3170. HWND hWnd,
  3171. LPPRINTER_INFO_2 pPrinter
  3172. )
  3173. {
  3174. TCHAR PrinterStatus[MAX_PATH];
  3175. BOOL BufferAllocated = FALSE;
  3176. ASSERT( GET_BROWSE_DLG_DATA(hWnd)->csLock.bInside() );
  3177. if( !pPrinter )
  3178. {
  3179. SetDlgItemText(hWnd, IDD_BROWSE_DESCRIPTION, TEXT(""));
  3180. SetDlgItemText(hWnd, IDD_BROWSE_STATUS, TEXT(""));
  3181. SetDlgItemText(hWnd, IDD_BROWSE_DOCUMENTS, TEXT(""));
  3182. }
  3183. else
  3184. {
  3185. SetDlgItemText(hWnd, IDD_BROWSE_PRINTER, pPrinter->pPrinterName);
  3186. SetDlgItemText(hWnd, IDD_BROWSE_DESCRIPTION, pPrinter->pComment); // !!!???
  3187. if(GetPrinterStatusString(pPrinter->Status, PrinterStatus))
  3188. SetDlgItemText(hWnd, IDD_BROWSE_STATUS, PrinterStatus);
  3189. else
  3190. SetDlgItemText(hWnd, IDD_BROWSE_STATUS, TEXT(""));
  3191. SetDlgItemInt(hWnd, IDD_BROWSE_DOCUMENTS, (UINT)pPrinter->cJobs, FALSE);
  3192. }
  3193. return TRUE;
  3194. }
  3195. /* --- Function: DrawLine() -------------------------------------------------
  3196. *
  3197. */
  3198. void
  3199. DrawLine(
  3200. HDC hDC,
  3201. LPRECT pRect,
  3202. LPTSTR pStr,
  3203. BOOL bInvert
  3204. )
  3205. {
  3206. ExtTextOut(hDC, pRect->left, pRect->top, ETO_OPAQUE, (CONST RECT *)pRect,
  3207. pStr, _tcslen(pStr), NULL);
  3208. }
  3209. /* DrawLineWithTabs
  3210. *
  3211. * Accepts a zero-terminated buffer containing strings delimited by commas
  3212. * in the following format: <string> [,<string>[,<string> ... ]]
  3213. * where <string> may be zero characters in length,
  3214. * e.g.:
  3215. * \\ntprint\LASER,HP Laserjet Series II,,other stuff
  3216. *
  3217. * It takes a copy of the string, and converts any commas into NULLs,
  3218. * ensuring that the new buffer has a double NULL termination,
  3219. * then steps through calling DrawLine on each NULL-terminated substring.
  3220. */
  3221. void
  3222. DrawLineWithTabs(
  3223. HDC hDC,
  3224. LPRECT pRect,
  3225. LPTSTR pStr,
  3226. BOOL bInvert
  3227. )
  3228. {
  3229. DWORD ColumnWidth = COLUMN_WIDTH; // Arbitrary column width for now
  3230. RECT ColumnRect;
  3231. TCHAR *pBuffer;
  3232. TCHAR *pBufferEnd;
  3233. TCHAR OutputBuffer[OUTPUT_BUFFER_LENGTH+2]; // Allow for double null terminator
  3234. DWORD StringLength; // Number of TCHARs in string;
  3235. DWORD BytesToCopy; // Number of BYTEs in OutputBuffer;
  3236. DWORD BufferLength; // NUMBER of TCHARs in OutputBuffer;
  3237. #ifdef _HYDRA_
  3238. SIZE StrSize;
  3239. DWORD ColSize, StrWidth;
  3240. #endif
  3241. /* Make a copy of the input string so we can mess with it
  3242. * without any worries.
  3243. * Just in case it's longer than our buffer, copy no more than
  3244. * buffer length:
  3245. */
  3246. StringLength = _tcslen( pStr );
  3247. BytesToCopy = min( ( StringLength * sizeof( TCHAR ) ), OUTPUT_BUFFER_LENGTH );
  3248. memcpy( OutputBuffer, pStr, BytesToCopy );
  3249. BufferLength = ( BytesToCopy / sizeof( TCHAR ) );
  3250. pBufferEnd = &OutputBuffer[BufferLength];
  3251. OutputBuffer[BufferLength] = (TCHAR)0; // Ensure double
  3252. OutputBuffer[BufferLength+1] = (TCHAR)0; // null terminated
  3253. /* Convert commas to nulls:
  3254. */
  3255. pBuffer = OutputBuffer;
  3256. while( *pBuffer )
  3257. {
  3258. if( *pBuffer == (TCHAR)',' )
  3259. *pBuffer = (TCHAR)0;
  3260. pBuffer++;
  3261. }
  3262. CopyRect( &ColumnRect, (CONST RECT *)pRect );
  3263. /* Tokenise the buffer delimited by commas:
  3264. */
  3265. pBuffer = OutputBuffer;
  3266. while( pBuffer < pBufferEnd )
  3267. {
  3268. #ifdef _HYDRA_
  3269. // For long strings, expand the column size. This prevents
  3270. // columns from aligning. But that is better than the alternatives
  3271. // which are to truncate the text or to make super wide columns
  3272. // that force the user to scroll.
  3273. ColSize = ColumnWidth;
  3274. if (GetTextExtentPoint32(hDC, pBuffer, _tcslen(pBuffer),
  3275. &StrSize) != 0)
  3276. {
  3277. StrWidth = (DWORD) StrSize.cx;
  3278. while (ColSize < StrWidth && ColSize < 8 * ColumnWidth)
  3279. ColSize += ColumnWidth / 2;
  3280. }
  3281. ColumnRect.right = ColumnRect.left + ColSize;
  3282. #else
  3283. ColumnRect.right = ( ColumnRect.left + ColumnWidth );
  3284. #endif
  3285. DrawLine( hDC, &ColumnRect, pBuffer, bInvert );
  3286. ColumnRect.left = ColumnRect.right;
  3287. /* Draw a column separator:
  3288. */
  3289. ColumnRect.right = ( ColumnRect.left + COLUMN_SEPARATOR_WIDTH );
  3290. DrawLine( hDC, &ColumnRect, TEXT(""), bInvert );
  3291. ColumnRect.left = ColumnRect.right;
  3292. /* Find and step over the next null:
  3293. */
  3294. while( *pBuffer++ )
  3295. ;
  3296. }
  3297. ColumnRect.right = pRect->right;
  3298. DrawLine( hDC, &ColumnRect, TEXT(""), bInvert );
  3299. }
  3300. /* DisplayStatusIcon
  3301. *
  3302. * andrewbe - May 1992
  3303. */
  3304. BOOL DisplayStatusIcon( HDC hdc, PRECT prect, int xBase, int yBase, BOOL Highlight )
  3305. {
  3306. BOOL OK;
  3307. int right;
  3308. right = prect->right;
  3309. if( ( SysColorWindow != GetSysColor(COLOR_WINDOW))
  3310. ||( SysColorHighlight != GetSysColor(COLOR_HIGHLIGHT)))
  3311. FixupBitmapColours( );
  3312. OK = BitBlt( hdc, prect->left + STATUS_BITMAP_MARGIN,
  3313. prect->top,
  3314. STATUS_BITMAP_WIDTH,
  3315. STATUS_BITMAP_HEIGHT,
  3316. hdcBitmap,
  3317. xBase,
  3318. Highlight ? ( yBase + STATUS_BITMAP_HEIGHT ) : yBase,
  3319. SRCCOPY );
  3320. if( OK )
  3321. {
  3322. /* Draw around it so we don't get a flashing effect on the highlight line:
  3323. */
  3324. prect->right = ( prect->left + STATUS_BITMAP_MARGIN );
  3325. DrawLine( hdc, prect, TEXT(""), Highlight );
  3326. prect->left += STATUS_BITMAP_MARGIN + STATUS_BITMAP_WIDTH;
  3327. prect->right = prect->left + STATUS_BITMAP_MARGIN;
  3328. DrawLine( hdc, prect, TEXT(""), Highlight );
  3329. prect->left += STATUS_BITMAP_MARGIN;
  3330. }
  3331. else
  3332. {
  3333. prect->right = STATUS_BITMAP_SPACE;
  3334. DrawLine( hdc, prect, TEXT(""), Highlight );
  3335. prect->left += STATUS_BITMAP_SPACE;
  3336. }
  3337. /* Restore the right coordinate (left has now been updated to the new position):
  3338. */
  3339. prect->right = right;
  3340. return OK;
  3341. }
  3342. /////////////////////////////////////////////////////////////////////////////
  3343. //
  3344. // LoadBitmaps
  3345. //
  3346. // this routine loads DIB bitmaps, and "fixes up" their color tables
  3347. // so that we get the desired result for the device we are on.
  3348. //
  3349. // this routine requires:
  3350. // the DIB is a 16 color DIB authored with the standard windows colors
  3351. // bright green (00 FF 00) is converted to the background color!
  3352. // bright magenta (FF 00 FF) is converted to the background color!
  3353. // light grey (C0 C0 C0) is replaced with the button face color
  3354. // dark grey (80 80 80) is replaced with the button shadow color
  3355. //
  3356. // this means you can't have any of these colors in your bitmap
  3357. //
  3358. /////////////////////////////////////////////////////////////////////////////
  3359. DWORD FlipColor(DWORD rgb)
  3360. {
  3361. return RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb));
  3362. }
  3363. BOOL LoadBitmaps()
  3364. {
  3365. HDC hdc;
  3366. HANDLE h;
  3367. DWORD FAR *pColorTable;
  3368. LPBYTE lpBits;
  3369. LPBITMAPINFOHEADER lpBitmapInfo;
  3370. int i;
  3371. UINT cbBitmapSize;
  3372. LPBITMAPINFOHEADER lpBitmapData;
  3373. h = FindResource(ghInst, MAKEINTRESOURCE(IDB_BROWSE), RT_BITMAP);
  3374. if( !h )
  3375. return FALSE;
  3376. hRes = LoadResource(ghInst, (HRSRC)h);
  3377. if( !hRes )
  3378. return FALSE;
  3379. /* Lock the bitmap and get a pointer to the color table. */
  3380. lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
  3381. if (!lpBitmapInfo)
  3382. return FALSE;
  3383. cbBitmapSize = SizeofResource(ghInst, (HRSRC)h);
  3384. if (!(lpBitmapData = (LPBITMAPINFOHEADER)LocalAlloc(LMEM_FIXED, cbBitmapSize))) {
  3385. FreeResource( hRes );
  3386. return FALSE;
  3387. }
  3388. CopyMemory((PBYTE)lpBitmapData, (PBYTE)lpBitmapInfo, cbBitmapSize);
  3389. pColorTable = (DWORD FAR *)((LPBYTE)(lpBitmapData) + lpBitmapData->biSize);
  3390. /* Search for the Solid Blue entry and replace it with the current
  3391. * background RGB.
  3392. */
  3393. if( !ColorIndicesInitialised )
  3394. {
  3395. for( i = 0; i < 16; i++ )
  3396. {
  3397. switch( pColorTable[i] )
  3398. {
  3399. case BACKGROUND:
  3400. iBackground = i;
  3401. break;
  3402. case BACKGROUNDSEL:
  3403. iBackgroundSel = i;
  3404. break;
  3405. case BUTTONFACE:
  3406. iButtonFace = i;
  3407. break;
  3408. case BUTTONSHADOW:
  3409. iButtonShadow = i;
  3410. break;
  3411. }
  3412. }
  3413. ColorIndicesInitialised = TRUE;
  3414. }
  3415. pColorTable[iBackground] = FlipColor(GetSysColor(COLOR_WINDOW));
  3416. pColorTable[iBackgroundSel] = FlipColor(GetSysColor(COLOR_HIGHLIGHT));
  3417. pColorTable[iButtonFace] = FlipColor(GetSysColor(COLOR_BTNFACE));
  3418. pColorTable[iButtonShadow] = FlipColor(GetSysColor(COLOR_BTNSHADOW));
  3419. UnlockResource(hRes);
  3420. /* First skip over the header structure */
  3421. lpBits = (LPBYTE)(lpBitmapData + 1);
  3422. /* Skip the color table entries, if any */
  3423. lpBits += (1 << (lpBitmapData->biBitCount)) * sizeof(RGBQUAD);
  3424. /* Create a color bitmap compatible with the display device */
  3425. BOOL bResult = FALSE;
  3426. hdc = GetDC(NULL);
  3427. if( hdc && (hdcBitmap = CreateCompatibleDC(hdc)) )
  3428. {
  3429. if (hbmBitmap = CreateDIBitmap (hdc, lpBitmapData, (DWORD)CBM_INIT,
  3430. lpBits, (LPBITMAPINFO)lpBitmapData, DIB_RGB_COLORS))
  3431. {
  3432. hbmDefault = (HBITMAP)SelectObject(hdcBitmap, hbmBitmap);
  3433. bResult = TRUE;
  3434. }
  3435. }
  3436. if( hdc )
  3437. {
  3438. ReleaseDC(NULL, hdc);
  3439. }
  3440. GlobalUnlock(hRes);
  3441. FreeResource(hRes);
  3442. LocalFree(lpBitmapData);
  3443. return bResult;
  3444. }
  3445. /* I'm sure there's a better way to do this.
  3446. * We should be able to modify the colour palette,
  3447. * but I haven't managed to make it work...
  3448. */
  3449. BOOL FixupBitmapColours( )
  3450. {
  3451. FreeBitmaps( );
  3452. LoadBitmaps( );
  3453. return TRUE;
  3454. }
  3455. INT APIENTRY GetHeightFromPointsString(DWORD Points)
  3456. {
  3457. HDC hdc;
  3458. INT height = Points;
  3459. hdc = GetDC(NULL);
  3460. if( hdc )
  3461. {
  3462. height = MulDiv( -(LONG)(Points), GetDeviceCaps(hdc, LOGPIXELSY), 72 );
  3463. ReleaseDC(NULL, hdc);
  3464. }
  3465. return height;
  3466. }
  3467. VOID FreeBitmaps( )
  3468. {
  3469. SelectObject( hdcBitmap, hbmDefault );
  3470. DeleteObject( hbmBitmap );
  3471. DeleteDC( hdcBitmap );
  3472. }
  3473. /* GetRegShowLogonDomainFlag
  3474. *
  3475. * Checks to see whether the current user has disabled the ShowLogonDomain
  3476. * flag to stop the default domain being expanded.
  3477. *
  3478. * If the flag is not there or an error occurs, defaults to TRUE.
  3479. *
  3480. */
  3481. BOOL GetRegShowLogonDomainFlag( )
  3482. {
  3483. TStatusB bStatus;
  3484. BOOL bShowLogonDomain = FALSE;
  3485. //
  3486. // Read the show logon domain flag from the registry.
  3487. //
  3488. TPersist Persist( gszRegPrinters, TPersist::kOpen|TPersist::kRead );
  3489. bStatus DBGCHK = VALID_OBJ( Persist );
  3490. if( bStatus )
  3491. {
  3492. bStatus DBGCHK = Persist.bRead( gszShowLogonDomain, bShowLogonDomain );
  3493. }
  3494. return bShowLogonDomain;
  3495. }
  3496. /* SetRegShowLogonDomainFlag
  3497. *
  3498. *
  3499. */
  3500. BOOL SetRegShowLogonDomainFlag( BOOL bShowLogonDomain )
  3501. {
  3502. TStatusB bStatus;
  3503. //
  3504. // Write the show logon domain flag to the registry.
  3505. //
  3506. TPersist Persist( gszRegPrinters, TPersist::kCreate|TPersist::kWrite );
  3507. bStatus DBGCHK = VALID_OBJ( Persist );
  3508. if( bStatus )
  3509. {
  3510. bStatus DBGCHK = Persist.bWrite( gszShowLogonDomain, bShowLogonDomain );
  3511. }
  3512. return bStatus;
  3513. }
  3514. /* Strip out carriage return and linefeed characters,
  3515. * and convert them to spaces:
  3516. */
  3517. VOID RemoveCrLf( LPTSTR pString )
  3518. {
  3519. while( *pString )
  3520. {
  3521. if( ( 0x0d == *pString ) || ( 0x0a == *pString ) )
  3522. *pString = ' ';
  3523. pString++;
  3524. }
  3525. }
  3526. VOID UpdateError( HWND hwnd, DWORD Error )
  3527. {
  3528. TCHAR ErrorTitle[20] = TEXT("");
  3529. TCHAR ErrorText[1048];
  3530. LPTSTR pErrorString;
  3531. if( Error == NO_ERROR )
  3532. {
  3533. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DESCRIPTION_TX ), SW_SHOW );
  3534. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DESCRIPTION ), SW_SHOW );
  3535. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_STATUS_TX ), SW_SHOW );
  3536. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_STATUS ), SW_SHOW );
  3537. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DOCUMENTS_TX ), SW_SHOW );
  3538. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DOCUMENTS ), SW_SHOW );
  3539. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_ERROR ), SW_HIDE );
  3540. SetDlgItemText(hwnd, IDD_BROWSE_ERROR, TEXT(""));
  3541. }
  3542. else
  3543. {
  3544. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DESCRIPTION_TX ), SW_HIDE );
  3545. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DESCRIPTION ), SW_HIDE );
  3546. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_STATUS_TX ), SW_HIDE );
  3547. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_STATUS ), SW_HIDE );
  3548. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DOCUMENTS_TX ), SW_HIDE );
  3549. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_DOCUMENTS ), SW_HIDE );
  3550. ShowWindow( GetDlgItem( hwnd, IDD_BROWSE_ERROR ), SW_SHOW );
  3551. if( !*ErrorTitle )
  3552. LoadString( ghInst, IDS_ERROR, ErrorTitle, COUNTOF(ErrorTitle));
  3553. if( *ErrorTitle )
  3554. {
  3555. TString strErrorString;
  3556. TResult Result( Error );
  3557. Result.bGetErrorString( strErrorString );
  3558. pErrorString = (LPTSTR)(LPCTSTR)strErrorString;
  3559. if( pErrorString )
  3560. {
  3561. RemoveCrLf( pErrorString );
  3562. _stprintf( ErrorText,
  3563. TEXT("%s: %s"),
  3564. ErrorTitle,
  3565. pErrorString );
  3566. SetDlgItemText(hwnd, IDD_BROWSE_ERROR, ErrorText);
  3567. }
  3568. }
  3569. }
  3570. }
  3571. /*++
  3572. Routine Name:
  3573. SPLSETUP_DATA
  3574. Routine Description:
  3575. Constructor/Destructor
  3576. Arguments:
  3577. Return Value:
  3578. --*/
  3579. SPLSETUP_DATA::
  3580. SPLSETUP_DATA(
  3581. VOID
  3582. ) : hModule(NULL),
  3583. hDevInfo(INVALID_HANDLE_VALUE),
  3584. pSetupLocalData(NULL),
  3585. pfnCreatePrinterDeviceInfoList(NULL),
  3586. pfnDestroyPrinterDeviceInfoList(NULL),
  3587. pfnSelectDriver(NULL),
  3588. pfnGetSelectedDriverInfo(NULL),
  3589. pfnDestroySelectedDriverInfo(NULL),
  3590. pfnInstallPrinterDriver(NULL),
  3591. pfnThisPlatform(NULL),
  3592. pfnDriverInfoFromName(NULL),
  3593. pfnGetPathToSearch(NULL),
  3594. pfnBuildDriversFromPath(NULL),
  3595. pfnIsDriverInstalled(NULL),
  3596. pfnGetLocalDataField(NULL),
  3597. pfnFreeDrvField(NULL),
  3598. pfnProcessPrinterAdded(NULL),
  3599. pfnFindMappedDriver(NULL),
  3600. pfnInstallInboxDriverSilently(NULL),
  3601. pfnFreeMem(NULL),
  3602. bValid(FALSE),
  3603. bDriverAdded(FALSE),
  3604. dwLastError(ERROR_SUCCESS)
  3605. {
  3606. if ( (hModule = LoadLibrary(TEXT("ntprint.dll"))) &&
  3607. (pfnCreatePrinterDeviceInfoList
  3608. = (pfPSetupCreatePrinterDeviceInfoList)GetProcAddress(hModule, "PSetupCreatePrinterDeviceInfoList")) &&
  3609. (pfnDestroyPrinterDeviceInfoList
  3610. = (pfPSetupDestroyPrinterDeviceInfoList)GetProcAddress(hModule, "PSetupDestroyPrinterDeviceInfoList")) &&
  3611. (pfnSelectDriver
  3612. = (pfPSetupSelectDriver)GetProcAddress(hModule, "PSetupSelectDriver")) &&
  3613. (pfnGetSelectedDriverInfo
  3614. = (pfPSetupGetSelectedDriverInfo)GetProcAddress(hModule, "PSetupGetSelectedDriverInfo")) &&
  3615. (pfnDestroySelectedDriverInfo
  3616. = (pfPSetupDestroySelectedDriverInfo)GetProcAddress(hModule, "PSetupDestroySelectedDriverInfo")) &&
  3617. (pfnInstallPrinterDriver
  3618. = (pfPSetupInstallPrinterDriver)GetProcAddress(hModule, "PSetupInstallPrinterDriver")) &&
  3619. (pfnThisPlatform
  3620. = (pfPSetupThisPlatform)GetProcAddress(hModule, "PSetupThisPlatform")) &&
  3621. (pfnDriverInfoFromName
  3622. = (pfPSetupDriverInfoFromName)GetProcAddress(hModule, "PSetupDriverInfoFromName")) &&
  3623. (pfnGetPathToSearch
  3624. = (pfPSetupGetPathToSearch)GetProcAddress(hModule, "PSetupGetPathToSearch")) &&
  3625. (pfnBuildDriversFromPath
  3626. = (pfPSetupBuildDriversFromPath)GetProcAddress(hModule, "PSetupBuildDriversFromPath")) &&
  3627. (pfnIsDriverInstalled
  3628. = (pfPSetupIsDriverInstalled)GetProcAddress(hModule, "PSetupIsDriverInstalled")) &&
  3629. (pfnGetLocalDataField
  3630. = (pfPSetupGetLocalDataField)GetProcAddress(hModule, "PSetupGetLocalDataField")) &&
  3631. (pfnFreeDrvField
  3632. = (pfPSetupFreeDrvField)GetProcAddress(hModule, "PSetupFreeDrvField")) &&
  3633. (pfnProcessPrinterAdded
  3634. = (pfPSetupProcessPrinterAdded)GetProcAddress(hModule, "PSetupProcessPrinterAdded")) &&
  3635. (pfnFindMappedDriver
  3636. = (pfPSetupFindMappedDriver)GetProcAddress(hModule, "PSetupFindMappedDriver")) &&
  3637. (pfnInstallInboxDriverSilently
  3638. = (pfPSetupInstallInboxDriverSilently)GetProcAddress(hModule, "PSetupInstallInboxDriverSilently")) &&
  3639. (pfnFreeMem
  3640. = (pfPSetupFreeMem)GetProcAddress(hModule, "PSetupFreeMem"))
  3641. )
  3642. {
  3643. bValid = TRUE;
  3644. }
  3645. }
  3646. SPLSETUP_DATA::
  3647. ~SPLSETUP_DATA(
  3648. VOID
  3649. )
  3650. {
  3651. //
  3652. // Free up the alocated resources.
  3653. //
  3654. FreeDriverInfo( );
  3655. if( hModule )
  3656. {
  3657. FreeLibrary( hModule );
  3658. }
  3659. }
  3660. VOID
  3661. SPLSETUP_DATA::
  3662. FreeDriverInfo(
  3663. VOID
  3664. )
  3665. {
  3666. if( hDevInfo != INVALID_HANDLE_VALUE )
  3667. {
  3668. pfnDestroyPrinterDeviceInfoList( hDevInfo );
  3669. hDevInfo = INVALID_HANDLE_VALUE;
  3670. }
  3671. if( pSetupLocalData )
  3672. {
  3673. pfnDestroySelectedDriverInfo( pSetupLocalData );
  3674. pSetupLocalData = NULL;
  3675. }
  3676. }
  3677. BOOL
  3678. SPLSETUP_DATA::
  3679. LoadDriverInfo(
  3680. IN HWND hwnd,
  3681. IN LPWSTR pszDriver
  3682. )
  3683. {
  3684. FreeDriverInfo( );
  3685. //
  3686. // Put up the Model/Manf dialog and install the printer driver selected
  3687. // by the user
  3688. //
  3689. hDevInfo = pfnCreatePrinterDeviceInfoList( hwnd );
  3690. if ( hDevInfo == INVALID_HANDLE_VALUE )
  3691. {
  3692. return FALSE;
  3693. }
  3694. //
  3695. // If we know the driver name we will see if it is found in the infs on
  3696. // the system
  3697. //
  3698. if( pszDriver )
  3699. {
  3700. pSetupLocalData = pfnDriverInfoFromName( hDevInfo, pszDriver );
  3701. }
  3702. //
  3703. // If we do not know the driver name or if the driver is not found in
  3704. // the infs we will prompt and let the user select a driver
  3705. //
  3706. if( !pSetupLocalData )
  3707. {
  3708. if( !pfnSelectDriver( hDevInfo ) )
  3709. {
  3710. return FALSE;
  3711. }
  3712. pSetupLocalData = pfnGetSelectedDriverInfo( hDevInfo );
  3713. if( !pSetupLocalData )
  3714. {
  3715. return FALSE;
  3716. }
  3717. }
  3718. return TRUE;
  3719. }
  3720. BOOL
  3721. SPLSETUP_DATA::
  3722. LoadKnownDriverInfo(
  3723. IN HWND hwnd,
  3724. IN LPWSTR pszDriver
  3725. )
  3726. {
  3727. TString strFormat;
  3728. TString strTitle;
  3729. TCHAR szInfDir[MAX_PATH];
  3730. FreeDriverInfo( );
  3731. hDevInfo = pfnCreatePrinterDeviceInfoList( hwnd );
  3732. if( hDevInfo == INVALID_HANDLE_VALUE )
  3733. {
  3734. return FALSE;
  3735. }
  3736. pSetupLocalData = pfnDriverInfoFromName( hDevInfo, pszDriver );
  3737. if( !pSetupLocalData )
  3738. {
  3739. if( !strFormat.bLoadString( ghInst, IDS_PROMPTFORINF ) ||
  3740. !strTitle.bFormat( strFormat, pszDriver ) )
  3741. {
  3742. return FALSE;
  3743. }
  3744. szInfDir[0] = TEXT('\0');
  3745. if( pfnGetPathToSearch( hwnd, strTitle, NULL, TEXT("*.INF"), FALSE, szInfDir ) &&
  3746. pfnBuildDriversFromPath(hDevInfo, szInfDir, FALSE) )
  3747. {
  3748. pSetupLocalData = pfnDriverInfoFromName( hDevInfo, pszDriver );
  3749. }
  3750. }
  3751. if( !pSetupLocalData )
  3752. {
  3753. return FALSE;
  3754. }
  3755. return TRUE;
  3756. }
  3757. VOID
  3758. SPLSETUP_DATA::
  3759. ReportErrorMessage(
  3760. IN HWND hwnd
  3761. )
  3762. {
  3763. if( dwLastError != ERROR_SUCCESS )
  3764. {
  3765. switch( dwLastError )
  3766. {
  3767. case ERROR_UNKNOWN_PRINTER_DRIVER:
  3768. {
  3769. iMessage( hwnd,
  3770. IDS_INSTALLDRIVER,
  3771. IDS_ERROR_UNKNOWN_DRIVER,
  3772. MB_OK | MB_ICONSTOP,
  3773. kMsgNone,
  3774. NULL );
  3775. }
  3776. break;
  3777. case ERROR_CANCELLED:
  3778. // do nothing
  3779. break;
  3780. default:
  3781. {
  3782. iMessage( hwnd,
  3783. IDS_INSTALLDRIVER,
  3784. IDS_ERRORRUNNINGSPLSETUP,
  3785. MB_OK | MB_ICONSTOP,
  3786. dwLastError,
  3787. NULL );
  3788. }
  3789. break;
  3790. }
  3791. }
  3792. }
  3793. inline static BOOL
  3794. IsNULLDriver(LPWSTR pszDriver)
  3795. {
  3796. // the spooler is setting the driver name to "NULL" for downlevel
  3797. // print servers, so applications don't crash. pretty weird, but
  3798. // that's how it is.
  3799. return (
  3800. NULL == pszDriver ||
  3801. 0 == pszDriver[0] ||
  3802. 0 == lstrcmpi(pszDriver, TEXT("NULL"))
  3803. );
  3804. }
  3805. BOOL
  3806. AddDriver(
  3807. IN SPLSETUP_DATA *pSplSetupData,
  3808. IN HWND hwnd,
  3809. IN LPWSTR pszDriver,
  3810. IN BOOL bPromptUser,
  3811. OUT LPWSTR *ppszDriverOut
  3812. )
  3813. /*++
  3814. Routine Description:
  3815. Verifies the user wants to install a driver, then puts up UI to
  3816. select the driver (pre-selects based on pszDriver), then invokes
  3817. install code.
  3818. Arguments:
  3819. pSplSetupData - The setup data used for the driver installation from
  3820. ntprint.dll.
  3821. hwnd - Parent window.
  3822. pszDriver - The driver from the remote printer provider (if known).
  3823. bPromptUser - If TRUE, the user should be prompted before installation.
  3824. ppszDriverOut - Driver selected by user, must be freed by callee
  3825. when this call succeeds.
  3826. Return Value:
  3827. TRUE = success, FALSE = FAILURE.
  3828. Notes:
  3829. Doesn't allow third party infs.
  3830. --*/
  3831. {
  3832. BOOL bRet = FALSE;
  3833. DRIVER_FIELD DrvField;
  3834. // Put up a message box to confirm that the user wants
  3835. // to install a driver locally:
  3836. //
  3837. if (bPromptUser)
  3838. {
  3839. if( iMessage( hwnd,
  3840. IDS_CONNECTTOPRINTER,
  3841. IsNULLDriver(pszDriver) ? IDS_CONFIRMINSTALLDRIVER : IDS_CONFIRMINSTALLKNOWNDRIVER,
  3842. MB_OKCANCEL | MB_ICONEXCLAMATION,
  3843. kMsgNone,
  3844. NULL,
  3845. pszDriver ) != IDOK )
  3846. {
  3847. return FALSE;
  3848. }
  3849. }
  3850. DrvField.Index = DRIVER_NAME;
  3851. DrvField.pszDriverName = NULL;
  3852. SPLASSERT( pSplSetupData );
  3853. if ( pSplSetupData->LoadDriverInfo( hwnd, pszDriver ) &&
  3854. pSplSetupData->pfnGetLocalDataField(
  3855. pSplSetupData->pSetupLocalData,
  3856. pSplSetupData->pfnThisPlatform(),
  3857. &DrvField) &&
  3858. (pSplSetupData->pfnIsDriverInstalled(NULL,
  3859. DrvField.pszDriverName,
  3860. pSplSetupData->pfnThisPlatform(),
  3861. KERNEL_MODE_DRIVER_VERSION) ||
  3862. ERROR_SUCCESS == (pSplSetupData->dwLastError = pSplSetupData->pfnInstallPrinterDriver(
  3863. pSplSetupData->hDevInfo,
  3864. pSplSetupData->pSetupLocalData,
  3865. NULL,
  3866. pSplSetupData->pfnThisPlatform(),
  3867. SPOOLER_VERSION,
  3868. NULL,
  3869. hwnd,
  3870. NULL,
  3871. NULL,
  3872. 0,
  3873. APD_COPY_NEW_FILES,
  3874. NULL))) )
  3875. {
  3876. pSplSetupData->bDriverAdded = TRUE;
  3877. *ppszDriverOut = AllocSplStr( DrvField.pszDriverName );
  3878. if ( *ppszDriverOut )
  3879. {
  3880. // success here
  3881. bRet = TRUE;
  3882. }
  3883. }
  3884. if( DrvField.pszDriverName )
  3885. {
  3886. pSplSetupData->pfnFreeDrvField(&DrvField);
  3887. }
  3888. if( !bRet && ERROR_SUCCESS == pSplSetupData->dwLastError )
  3889. {
  3890. pSplSetupData->dwLastError = GetLastError();
  3891. //
  3892. // If ntprint.dll fails, but doesn't set the last error then
  3893. // we will set a bizarre last error here, so the UI will end
  3894. // up displaying a generic error message instead of silence.
  3895. //
  3896. if( ERROR_SUCCESS == pSplSetupData->dwLastError )
  3897. {
  3898. pSplSetupData->dwLastError = ERROR_INVALID_FUNCTION;
  3899. }
  3900. }
  3901. return bRet;
  3902. }
  3903. BOOL
  3904. AddKnownDriver(
  3905. IN SPLSETUP_DATA *pSplSetupData,
  3906. IN HWND hwnd,
  3907. IN LPWSTR pszDriver,
  3908. IN BOOL bSamePlatform
  3909. )
  3910. /*++
  3911. Routine Description:
  3912. Adds a known driver. Doesn't prompt for printer name or driver
  3913. selection; calls setup directly.
  3914. Arguments:
  3915. hwnd - Parent hwnd.
  3916. pszDriver - Driver to install.
  3917. Return Value:
  3918. TRUE = success, FALSE = failure.
  3919. --*/
  3920. {
  3921. ASSERT(pSplSetupData);
  3922. BOOL bRet = FALSE;
  3923. //
  3924. // Put up a message box to confirm that the user wants
  3925. // to install a driver locally:
  3926. //
  3927. if (iMessage(hwnd,
  3928. IDS_CONNECTTOPRINTER,
  3929. IDS_CONFIRMINSTALLKNOWNDRIVER,
  3930. MB_OKCANCEL | MB_ICONEXCLAMATION,
  3931. kMsgNone,
  3932. NULL,
  3933. pszDriver) != IDOK)
  3934. {
  3935. return FALSE;
  3936. }
  3937. // don't offer replacement inbox driver in the AddPrinterConnection case
  3938. DWORD dwInstallFlags = DRVINST_DONT_OFFER_REPLACEMENT;
  3939. if( pSplSetupData->LoadKnownDriverInfo( hwnd, pszDriver ) )
  3940. {
  3941. pSplSetupData->dwLastError = pSplSetupData->pfnInstallPrinterDriver(
  3942. pSplSetupData->hDevInfo,
  3943. pSplSetupData->pSetupLocalData,
  3944. NULL,
  3945. pSplSetupData->pfnThisPlatform(),
  3946. SPOOLER_VERSION,
  3947. NULL,
  3948. hwnd,
  3949. NULL,
  3950. NULL,
  3951. dwInstallFlags,
  3952. APD_COPY_NEW_FILES,
  3953. NULL );
  3954. if ( ERROR_SUCCESS == pSplSetupData->dwLastError )
  3955. {
  3956. pSplSetupData->bDriverAdded = TRUE;
  3957. bRet = TRUE;
  3958. }
  3959. }
  3960. if( !bRet && ERROR_SUCCESS == pSplSetupData->dwLastError )
  3961. {
  3962. pSplSetupData->dwLastError = GetLastError();
  3963. //
  3964. // If ntprint.dll fails, but doesn't set the last error then
  3965. // we will set a bizarre last error here, so the UI will end
  3966. // up displaying a generic error message instead of silence.
  3967. //
  3968. if( ERROR_SUCCESS == pSplSetupData->dwLastError )
  3969. {
  3970. pSplSetupData->dwLastError = ERROR_INVALID_FUNCTION;
  3971. }
  3972. }
  3973. return bRet;
  3974. }
  3975. /*++
  3976. Routine Name:
  3977. IsNTServer
  3978. Routine Description:
  3979. Returns whether the given server is a windows nt server or not.
  3980. Arguments:
  3981. pszServerName -
  3982. Return Value:
  3983. An HRESULT - S_OK - It is an NT server.
  3984. S_FALSE - It is not an NT server.
  3985. E_X - There was an error.
  3986. --*/
  3987. HRESULT
  3988. IsNTServer(
  3989. IN PCWSTR pszServerName
  3990. )
  3991. {
  3992. HANDLE hServer = NULL;
  3993. PRINTER_DEFAULTS PrinterDef = { NULL, NULL, SERVER_READ };
  3994. TStatusH hRetval;
  3995. //
  3996. // If we can open the remote server, then this is an NT box.
  3997. //
  3998. hRetval DBGCHK = OpenPrinter(const_cast<PWSTR>(pszServerName), &hServer, &PrinterDef) ? S_OK : CreateHRFromWin32();
  3999. if (hServer)
  4000. {
  4001. ClosePrinter(hServer);
  4002. }
  4003. return SUCCEEDED(hRetval) ? S_OK : S_FALSE;
  4004. }
  4005. /*++
  4006. Routine Name:
  4007. CreateLocalPort
  4008. Routine Description:
  4009. This creates a local port of the given name by communicating with the
  4010. local monitor.
  4011. Arguments:
  4012. pszPortName - The port name to add.
  4013. Return Value:
  4014. TRUE - Success, FALSE - Failure.
  4015. --*/
  4016. BOOL
  4017. CreateLocalPort(
  4018. IN PCWSTR pszPortName
  4019. )
  4020. {
  4021. HANDLE hXcv = NULL;
  4022. PRINTER_DEFAULTS Defaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER };
  4023. TStatusB bRet;
  4024. if (pszPortName == NULL)
  4025. {
  4026. SetLastError(ERROR_INVALID_PARAMETER);
  4027. bRet DBGCHK = FALSE;
  4028. }
  4029. //
  4030. // Open a Xcv handle to the local monitor.
  4031. //
  4032. if (bRet)
  4033. {
  4034. bRet DBGCHK = OpenPrinter(const_cast<PWSTR>(gszXvcLocalMonitor), &hXcv, &Defaults);
  4035. }
  4036. //
  4037. // Ask it to add a port for us.
  4038. //
  4039. if (bRet)
  4040. {
  4041. DWORD cbOutputNeeded = 0;
  4042. DWORD Status = ERROR_SUCCESS;
  4043. bRet DBGCHK = XcvData(hXcv,
  4044. gszAddPort,
  4045. reinterpret_cast<BYTE *>(const_cast<PWSTR>(pszPortName)),
  4046. (wcslen(pszPortName) + 1) * sizeof(WCHAR),
  4047. NULL,
  4048. 0,
  4049. &cbOutputNeeded,
  4050. &Status);
  4051. if (bRet)
  4052. {
  4053. //
  4054. // If it succeeded, or the port already exists, we are OK.
  4055. //
  4056. if (Status != ERROR_SUCCESS && Status != ERROR_ALREADY_EXISTS)
  4057. {
  4058. SetLastError(Status);
  4059. bRet DBGCHK = FALSE;
  4060. }
  4061. }
  4062. }
  4063. if (hXcv)
  4064. {
  4065. ClosePrinter(hXcv);
  4066. }
  4067. return bRet;
  4068. }
  4069. LPVOID
  4070. AllocSplMem(
  4071. DWORD cb
  4072. )
  4073. {
  4074. LPVOID pReturn = AllocMem( cb );
  4075. if( pReturn )
  4076. {
  4077. memset( pReturn, 0, cb );
  4078. }
  4079. return pReturn;
  4080. }
  4081. BOOL
  4082. FreeSplMem(
  4083. LPVOID pMem
  4084. )
  4085. {
  4086. FreeMem( pMem );
  4087. return TRUE;
  4088. }
  4089. LPVOID
  4090. ReallocSplMem(
  4091. LPVOID pOldMem,
  4092. DWORD cbOld,
  4093. DWORD cbNew
  4094. )
  4095. {
  4096. LPVOID pNewMem = AllocSplMem( cbNew );
  4097. if (pOldMem && pNewMem)
  4098. {
  4099. if (cbOld)
  4100. {
  4101. memcpy(pNewMem, pOldMem, min(cbNew, cbOld));
  4102. }
  4103. FreeSplMem(pOldMem);
  4104. }
  4105. return pNewMem;
  4106. }
  4107. LPTSTR
  4108. AllocSplStr(
  4109. LPCTSTR pStr
  4110. )
  4111. {
  4112. LPTSTR pMem = NULL;
  4113. if( pStr )
  4114. {
  4115. pMem = (LPTSTR)AllocSplMem( _tcslen(pStr) * sizeof(TCHAR) + sizeof(TCHAR) );
  4116. if( pMem )
  4117. {
  4118. _tcscpy( pMem, pStr );
  4119. }
  4120. }
  4121. return pMem;
  4122. }
  4123. BOOL
  4124. FreeSplStr(
  4125. LPTSTR pStr
  4126. )
  4127. {
  4128. FreeSplMem( pStr );
  4129. return TRUE;
  4130. }
  4131. static MSG_HLPMAP MsgHelpTable [] =
  4132. {
  4133. { ERROR_KM_DRIVER_BLOCKED, IDS_NULLSTR, gszHelpTroubleShooterURL},
  4134. { 0, 0, 0}
  4135. };
  4136. DWORD
  4137. ReportFailure(
  4138. HWND hwndParent,
  4139. DWORD idTitle,
  4140. DWORD idDefaultError
  4141. )
  4142. {
  4143. DWORD dwLastError = GetLastError();
  4144. if( dwLastError == ERROR_KM_DRIVER_BLOCKED )
  4145. {
  4146. iMessageEx ( hwndParent,
  4147. idTitle,
  4148. IDS_COULDNOTCONNECTTOPRINTER_BLOCKED_HELP,
  4149. MB_OK | MB_ICONSTOP,
  4150. dwLastError,
  4151. NULL,
  4152. dwLastError,
  4153. MsgHelpTable);
  4154. }
  4155. else
  4156. {
  4157. iMessageEx( hwndParent,
  4158. idTitle,
  4159. idDefaultError,
  4160. MB_OK | MB_ICONSTOP,
  4161. dwLastError,
  4162. NULL,
  4163. bGoodLastError(dwLastError) ? -1 : idDefaultError,
  4164. NULL );
  4165. }
  4166. return dwLastError;
  4167. }
  4168. BROWSE_DLG_DATA::
  4169. BROWSE_DLG_DATA(
  4170. VOID
  4171. ) : hPrinter( NULL ),
  4172. Request( NULL ),
  4173. RequestComplete( NULL ),
  4174. pConnectToData( NULL ),
  4175. Status( 0 ),
  4176. cExpandObjects( 0 ),
  4177. ExpandSelection( NULL ),
  4178. dwExtent( 0 ),
  4179. pEnumerateName( NULL ),
  4180. pEnumerateObject( NULL ),
  4181. Message( 0 ),
  4182. wParam( 0 ),
  4183. lParam( 0 ),
  4184. pPrinterInfo( NULL ),
  4185. cbPrinterInfo( 0 ),
  4186. hwndDialog( NULL ),
  4187. _bValid( FALSE ),
  4188. pPageSwitchController( NULL ),
  4189. bInPropertyPage( FALSE )
  4190. {
  4191. DBGMSG( DBG_TRACE, ( "BROWSE_DLG_DATA::ctor\n") );\
  4192. hcursorArrow = LoadCursor(NULL, IDC_ARROW);
  4193. hcursorWait = LoadCursor(NULL, IDC_WAIT);
  4194. //
  4195. // Leave _bValid = FALSE if cursors are *not* loaded properly
  4196. //
  4197. if( hcursorArrow && hcursorWait )
  4198. {
  4199. _bValid = MRefCom::bValid();
  4200. }
  4201. }
  4202. BROWSE_DLG_DATA::
  4203. ~BROWSE_DLG_DATA(
  4204. VOID
  4205. )
  4206. {
  4207. DBGMSG( DBG_TRACE, ( "BROWSE_DLG_DATA::dtor\n") );
  4208. if( pPrinterInfo )
  4209. FreeSplMem( pPrinterInfo );
  4210. if (pConnectToData)
  4211. FreeSplMem(pConnectToData);
  4212. if (RequestComplete)
  4213. CloseHandle(RequestComplete);
  4214. if (Request)
  4215. CloseHandle(Request);
  4216. }
  4217. VOID
  4218. BROWSE_DLG_DATA::
  4219. vRefZeroed(
  4220. VOID
  4221. )
  4222. {
  4223. delete this;
  4224. }
  4225. BOOL
  4226. BROWSE_DLG_DATA::
  4227. bValid(
  4228. VOID
  4229. )
  4230. {
  4231. return _bValid;
  4232. }
  4233. BOOL
  4234. BROWSE_DLG_DATA::
  4235. bInitializeBrowseThread(
  4236. HWND hWnd
  4237. )
  4238. {
  4239. if( !LoadBitmaps() )
  4240. {
  4241. DBGMSG( DBG_WARN, ( "Bitmaps are not loaded properly" ) );
  4242. return FALSE;
  4243. }
  4244. DWORD ThreadId;
  4245. HANDLE hThread;
  4246. //
  4247. // !! WARNING !!
  4248. // Assumes ->Request, ->RequestComplete, ->pConnectToData zero initialized!
  4249. //
  4250. Request = CreateEvent( NULL,
  4251. EVENT_RESET_AUTOMATIC,
  4252. EVENT_INITIAL_STATE_NOT_SIGNALED,
  4253. NULL );
  4254. RequestComplete = CreateEvent( NULL,
  4255. EVENT_RESET_AUTOMATIC,
  4256. EVENT_INITIAL_STATE_NOT_SIGNALED,
  4257. NULL );
  4258. if( !RequestComplete || !Request )
  4259. {
  4260. DBGMSG( DBG_WARN, ( "CreateEvent failed: Error %d\n", GetLastError( ) ) );
  4261. return FALSE;
  4262. }
  4263. if( !( pConnectToData = (PCONNECTTO_OBJECT)AllocSplMem( sizeof( CONNECTTO_OBJECT ) ) ) )
  4264. {
  4265. return FALSE;
  4266. }
  4267. vIncRef();
  4268. hThread = TSafeThread::Create( NULL,
  4269. 0,
  4270. (LPTHREAD_START_ROUTINE)BrowseThread,
  4271. this,
  4272. 0,
  4273. &ThreadId );
  4274. if( !hThread )
  4275. {
  4276. DBGMSG( DBG_WARN, ( "CreateThread of BrowseThread failed: Error %d\n", GetLastError( ) ) );
  4277. cDecRef();
  4278. return FALSE;
  4279. }
  4280. CloseHandle( hThread );
  4281. if( bInPropertyPage || GetRegShowLogonDomainFlag( ) )
  4282. Status |= BROWSE_STATUS_INITIAL | BROWSE_STATUS_EXPAND;
  4283. ENTER_CRITICAL( this );
  4284. SEND_BROWSE_THREAD_REQUEST( this,
  4285. BROWSE_THREAD_ENUM_OBJECTS,
  4286. NULL,
  4287. pConnectToData );
  4288. LEAVE_CRITICAL( this );
  4289. hwndDialog = hWnd;
  4290. SetCursorShape( hwndDialog );
  4291. return TRUE;
  4292. }