1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include "PrinterSetupWizardApp.h"
20 #include "PrinterSetupWizardSheet.h"
21 #include "CommonServices.h"
22 #include "DebugServices.h"
23 #include "WinServices.h"
31 #pragma warning(disable:4702)
34 #if( !TARGET_OS_WINDOWS_CE )
40 #if defined( UNICODE ) || defined( _UNICODE )
41 # define GetEnv _wgetenv
43 # define GetEnv getenv
47 g_printerDriverFiles
[] = // Printer driver files
50 TEXT( "pscript.hlp" ),
51 TEXT( "pscript.ntf" ),
52 TEXT( "pscript5.dll" ),
54 TEXT( "cupsui6.dll" ),
61 #define WM_SOCKET_EVENT ( WM_USER + 0x100 )
62 #define WM_PROCESS_EVENT ( WM_USER + 0x101 )
69 return TRUE
; // 64-bit programs run only on Win64
71 typedef BOOL (WINAPI
*LPFN_ISWOW64PROCESS
)( HANDLE
, PBOOL
);
72 LPFN_ISWOW64PROCESS fnIsWow64Process
;
73 BOOL bIsWow64
= FALSE
;
75 fnIsWow64Process
= ( LPFN_ISWOW64PROCESS
) GetProcAddress( GetModuleHandle( TEXT( "kernel32" ) ), "IsWow64Process" );
77 if ( fnIsWow64Process
!= NULL
)
81 ok
= fnIsWow64Process( GetCurrentProcess(), &bIsWow64
);
94 // CPrinterSetupWizardSheet
95 CPrinterSetupWizardSheet
* CPrinterSetupWizardSheet::m_self
;
97 IMPLEMENT_DYNAMIC(CPrinterSetupWizardSheet
, CPropertySheet
)
98 CPrinterSetupWizardSheet::CPrinterSetupWizardSheet(UINT nIDCaption
, CWnd
* pParentWnd
, UINT iSelectPage
)
99 :CPropertySheet(nIDCaption
, pParentWnd
, iSelectPage
),
100 m_selectedPrinter(NULL
),
101 m_driverThreadExitCode( 0 ),
102 m_driverThreadFinished( false ),
103 m_pdlBrowser( NULL
),
104 m_ippBrowser( NULL
),
105 m_lprBrowser( NULL
),
108 m_arrow
= LoadCursor(0, IDC_ARROW
);
109 m_wait
= LoadCursor(0, IDC_APPSTARTING
);
119 CPrinterSetupWizardSheet::~CPrinterSetupWizardSheet()
123 while ( m_printers
.size() > 0 )
125 printer
= m_printers
.front();
126 m_printers
.pop_front();
135 // ------------------------------------------------------
136 // SetSelectedPrinter
138 // Manages setting a printer as the printer to install. Stops
139 // any pending resolves.
142 CPrinterSetupWizardSheet::SetSelectedPrinter(Printer
* printer
)
144 check( !printer
|| ( printer
!= m_selectedPrinter
) );
146 m_selectedPrinter
= printer
;
151 CPrinterSetupWizardSheet::LoadPrinterNames()
157 // rdar://problem/3701926 - Printer can't be installed twice
159 // First thing we want to do is make sure the printer isn't already installed.
160 // If the printer name is found, we'll try and rename it until we
161 // find a unique name
163 DWORD dwNeeded
= 0, dwNumPrinters
= 0;
165 BOOL ok
= EnumPrinters(PRINTER_ENUM_LOCAL
, NULL
, 4, NULL
, 0, &dwNeeded
, &dwNumPrinters
);
166 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
168 if ((err
== ERROR_INSUFFICIENT_BUFFER
) && (dwNeeded
> 0))
172 buffer
= new unsigned char[dwNeeded
];
179 require_action( buffer
, exit
, kNoMemoryErr
);
180 ok
= EnumPrinters(PRINTER_ENUM_LOCAL
, NULL
, 4, buffer
, dwNeeded
, &dwNeeded
, &dwNumPrinters
);
181 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
182 require_noerr( err
, exit
);
184 for (DWORD index
= 0; index
< dwNumPrinters
; index
++)
186 PRINTER_INFO_4
* lppi4
= (PRINTER_INFO_4
*) (buffer
+ index
* sizeof(PRINTER_INFO_4
));
188 m_printerNames
.push_back( lppi4
->pPrinterName
);
204 // ------------------------------------------------------
207 // Installs a printer with Windows.
209 // Note: this works one of two ways, depending on whether
210 // there are drivers already installed for this printer.
211 // If there are, then we can just create a port with XcvData,
212 // and then call AddPrinter. If not, we use the printui.dll
213 // to install the printer. Actually installing drivers that
214 // are not currently installed is painful, and it's much
215 // easier and less error prone to just let printui.dll do
216 // the hard work for us.
220 CPrinterSetupWizardSheet::InstallPrinter(Printer
* printer
)
224 Service
* service
= NULL
;
228 service
= printer
->services
.front();
231 if ( printer
->isCUPSPrinter
&& cupsLib
.IsInstalled() )
233 err
= InstallPrinterCUPS( printer
, service
, cupsLib
);
234 require_noerr( err
, exit
);
239 // if the driver isn't installed, then install it
242 if ( !printer
->driverInstalled
)
248 m_driverThreadFinished
= false;
253 hThread
= (HANDLE
) _beginthreadex_compat( NULL
, 0, InstallDriverThread
, printer
, 0, &threadID
);
254 err
= translate_errno( hThread
, (OSStatus
) GetLastError(), kUnknownErr
);
255 require_noerr_with_log( log
, "_beginthreadex_compat()", err
, exit
);
260 while (!m_driverThreadFinished
)
264 GetMessage( &msg
, m_hWnd
, 0, 0 );
265 TranslateMessage(&msg
);
266 DispatchMessage(&msg
);
270 // Wait until child process exits.
272 dwResult
= WaitForSingleObject( hThread
, INFINITE
);
273 err
= translate_errno( dwResult
== WAIT_OBJECT_0
, errno_compat(), err
= kUnknownErr
);
274 require_noerr_with_log( log
, "WaitForSingleObject()", err
, exit
);
277 // check the return value of thread
279 require_noerr_with_log( log
, "thread exit code", m_driverThreadExitCode
, exit
);
282 // now we know that the driver was successfully installed
284 printer
->driverInstalled
= true;
287 if ( service
->type
== kPDLServiceType
)
289 err
= InstallPrinterPort( printer
, service
, PROTOCOL_RAWTCP_TYPE
, log
);
290 require_noerr_with_log( log
, "InstallPrinterPort()", err
, exit
);
291 err
= InstallPrinterPDLAndLPR( printer
, service
, log
);
292 require_noerr_with_log( log
, "InstallPrinterPDLAndLPR()", err
, exit
);
294 else if ( service
->type
== kLPRServiceType
)
296 err
= InstallPrinterPort( printer
, service
, PROTOCOL_LPR_TYPE
, log
);
297 require_noerr_with_log( log
, "InstallPrinterPort()", err
, exit
);
298 err
= InstallPrinterPDLAndLPR( printer
, service
, log
);
299 require_noerr_with_log( log
, "InstallPrinterPDLAndLPR()", err
, exit
);
301 else if ( service
->type
== kIPPServiceType
)
303 // There's no need to install a printer port for IPP printers, because
304 // the call to AddPrinter() will do that for us.
306 err
= InstallPrinterIPP( printer
, service
, log
);
307 require_noerr_with_log( log
, "InstallPrinterIPP()", err
, exit
);
311 require_action_with_log( log
, ( service
->type
== kPDLServiceType
) || ( service
->type
== kLPRServiceType
) || ( service
->type
== kIPPServiceType
), exit
, err
= kUnknownErr
);
315 printer
->installed
= true;
318 // if the user specified a default printer, set it
322 ok
= SetDefaultPrinter( printer
->actualName
);
323 err
= translate_errno( ok
, errno_compat(), err
= kUnknownErr
);
324 require_noerr_with_log( log
, "SetDefaultPrinter()", err
, exit
);
334 CPrinterSetupWizardSheet::InstallPrinterPort( Printer
* printer
, Service
* service
, DWORD protocol
, Logger
& log
)
336 PRINTER_DEFAULTS printerDefaults
= { NULL
, NULL
, SERVER_ACCESS_ADMINISTER
};
337 PORT_DATA_1 portData
;
339 DWORD cbInputData
= 100;
340 PBYTE pOutputData
= NULL
;
341 DWORD cbOutputNeeded
= 0;
347 ZeroMemory(&portData
, sizeof(PORT_DATA_1
));
349 require_action_with_log( log
, wcslen(printer
->portName
) < sizeof_array(portData
.sztPortName
), exit
, err
= kSizeErr
);
350 wcscpy_s(portData
.sztPortName
, printer
->portName
);
352 q
= service
->queues
.front();
355 ok
= OpenPrinter(L
",XcvMonitor Standard TCP/IP Port", &hXcv
, &printerDefaults
);
356 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
357 require_noerr_with_log( log
, "OpenPrinter()", err
, exit
);
360 // BUGBUG: MSDN said this is not required, but my experience shows it is required
364 pOutputData
= new BYTE
[cbInputData
];
371 require_action_with_log( log
, pOutputData
, exit
, err
= kNoMemoryErr
);
373 portData
.dwPortNumber
= service
->portNumber
;
374 portData
.dwVersion
= 1;
375 portData
.dwDoubleSpool
= 1;
377 portData
.dwProtocol
= protocol
;
378 portData
.cbSize
= sizeof PORT_DATA_1
;
379 portData
.dwReserved
= 0L;
381 require_action_with_log( log
, wcslen(q
->name
) < sizeof_array(portData
.sztQueue
), exit
, err
= kSizeErr
);
382 wcscpy_s(portData
.sztQueue
, q
->name
);
384 require_action_with_log( log
, wcslen( service
->hostname
) < sizeof_array(portData
.sztHostAddress
), exit
, err
= kSizeErr
);
385 wcscpy_s( portData
.sztHostAddress
, service
->hostname
);
387 ok
= XcvData(hXcv
, L
"AddPort", (PBYTE
) &portData
, sizeof(PORT_DATA_1
), pOutputData
, cbInputData
, &cbOutputNeeded
, &dwStatus
);
388 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
389 require_noerr_with_log( log
, "XcvData()", err
, exit
);
398 if (pOutputData
!= NULL
)
400 delete [] pOutputData
;
408 CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer
* printer
, Service
* service
, Logger
& log
)
410 PRINTER_INFO_2 pInfo
;
411 HANDLE hPrinter
= NULL
;
415 check(printer
!= NULL
);
416 check(printer
->installed
== false);
418 q
= service
->queues
.front();
424 ZeroMemory(&pInfo
, sizeof(pInfo
));
426 pInfo
.pPrinterName
= printer
->actualName
.GetBuffer();
427 pInfo
.pServerName
= NULL
;
428 pInfo
.pShareName
= NULL
;
429 pInfo
.pPortName
= printer
->portName
.GetBuffer();
430 pInfo
.pDriverName
= printer
->modelName
.GetBuffer();
431 pInfo
.pComment
= printer
->displayModelName
.GetBuffer();
432 pInfo
.pLocation
= q
->location
.GetBuffer();
433 pInfo
.pDevMode
= NULL
;
434 pInfo
.pDevMode
= NULL
;
435 pInfo
.pSepFile
= L
"";
436 pInfo
.pPrintProcessor
= L
"winprint";
437 pInfo
.pDatatype
= L
"RAW";
438 pInfo
.pParameters
= L
"";
439 pInfo
.pSecurityDescriptor
= NULL
;
440 pInfo
.Attributes
= PRINTER_ATTRIBUTE_QUEUED
;
442 pInfo
.DefaultPriority
= 0;
446 hPrinter
= AddPrinter(NULL
, 2, (LPBYTE
) &pInfo
);
447 err
= translate_errno( hPrinter
, errno_compat(), kUnknownErr
);
448 require_noerr_with_log( log
, "AddPrinter()", err
, exit
);
452 if (hPrinter
!= NULL
)
454 ClosePrinter(hPrinter
);
462 CPrinterSetupWizardSheet::InstallPrinterIPP(Printer
* printer
, Service
* service
, Logger
& log
)
464 DEBUG_UNUSED( service
);
466 Queue
* q
= service
->SelectedQueue();
467 HANDLE hPrinter
= NULL
;
468 PRINTER_INFO_2 pInfo
;
476 ZeroMemory(&pInfo
, sizeof(PRINTER_INFO_2
));
478 pInfo
.pPrinterName
= printer
->actualName
.GetBuffer();
479 pInfo
.pPortName
= printer
->portName
.GetBuffer();
480 pInfo
.pDriverName
= printer
->modelName
.GetBuffer();
481 pInfo
.pPrintProcessor
= L
"winprint";
482 pInfo
.pLocation
= q
->location
.GetBuffer();
483 pInfo
.pComment
= printer
->displayModelName
.GetBuffer();
484 pInfo
.Attributes
= PRINTER_ATTRIBUTE_NETWORK
| PRINTER_ATTRIBUTE_LOCAL
;
486 hPrinter
= AddPrinter(NULL
, 2, (LPBYTE
)&pInfo
);
487 err
= translate_errno( hPrinter
, errno_compat(), kUnknownErr
);
488 require_noerr_with_log( log
, "AddPrinter()", err
, exit
);
492 if ( hPrinter
!= NULL
)
494 ClosePrinter(hPrinter
);
502 CPrinterSetupWizardSheet::InstallPrinterCUPS(Printer
* printer
, Service
* service
, CUPSLibrary
& cupsLib
)
504 OSStatus err
= kNoErr
;
508 check( cupsLib
.IsInstalled() );
510 err
= InstallPrinterCUPS( printer
, service
, cupsLib
, TEXT( "Windows NT x86" ) );
511 require_noerr( err
, exit
);
513 if ( Is64BitWindows() )
515 err
= InstallPrinterCUPS( printer
, service
, cupsLib
, TEXT( "Windows x64" ) );
516 require_noerr( err
, exit
);
526 CPrinterSetupWizardSheet::InstallPrinterCUPS(Printer
* printer
, Service
* service
, CUPSLibrary
& cupsLib
, TCHAR
* env
)
530 CString ppdfile
; // PPD file for printer drivers
531 TCHAR driverdir
[1024]; // Directory for driver files
532 DWORD needed
; // Bytes needed
533 DRIVER_INFO_3 driverinfo
; // Driver information
534 PRINTER_INFO_2 printerinfo
; // Printer information
535 HANDLE printerHandle
= NULL
; // Handle to printer
536 CString filename
; // Driver filename
537 CString dependentFiles
; // List of dependent files
538 CString portName
; // Port Name
539 int bytes
; // Bytes copied
540 TCHAR datadir
[ MAX_PATH
]; // Driver files location
541 CFile in
; // Input file
542 CFile out
; // Output file
543 void * http
; // Connection to server
544 char buffer
[4096]; // Copy/error buffer
546 char hostname
[ 1024 ];
548 char destANSI
[ 1024 ];
556 check( cupsLib
.IsInstalled() );
559 // What do we do here for multiple queues?
560 q
= service
->queues
.front();
561 require_action( q
!= NULL
, exit
, err
= kUnknownErr
);
563 num
= GetModuleFileName( NULL
, datadir
, MAX_PATH
);
564 err
= translate_errno( num
> 0, GetLastError(), kUnknownErr
);
565 require_noerr( err
, exit
);
566 ok
= PathRemoveFileSpec( datadir
);
567 require_action( ok
, exit
, err
= kUnknownErr
);
569 ok
= GetPrinterDriverDirectory(NULL
, env
, 1, ( LPBYTE
) driverdir
, sizeof( driverdir
), &needed
);
570 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
571 require_noerr( err
, exit
);
574 platform
= platform
.Right( 3 );
576 // Append the supported banner pages to the PPD file...
577 err
= StringObjectToUTF8String( service
->hostname
, hostname
, sizeof( hostname
) );
578 require_noerr( err
, exit
);
579 http
= cupsLib
.httpConnectEncrypt( hostname
, service
->portNumber
, cupsLib
.cupsEncryption() );
580 err
= translate_errno( http
!= NULL
, errno
, kUnknownErr
);
581 require_noerr( err
, exit
);
583 if ( ( service
->portNumber
== 443 ) || ( cupsLib
.cupsEncryption() >= HTTP_ENCRYPT_REQUIRED
) )
585 // This forces the use the https: URLs below...
586 cupsLib
.cupsSetEncryption( HTTP_ENCRYPT_ALWAYS
);
589 // Strip the leading "printers/" or "classes/" from the beginning
593 dest
.Replace( TEXT( "printers/" ), TEXT( "" ) );
594 dest
.Replace( TEXT( "classes/" ), TEXT( "" ) );
596 err
= StringObjectToUTF8String( dest
, destANSI
, sizeof( destANSI
) );
597 require_noerr( err
, exit
);
599 // Get the PPD file...
600 for ( i
= 0; i
< 10; i
++ )
602 char ppdfileANSI
[ 1024 ];
604 if ( cupsLib
.cupsAdminCreateWindowsPPD( http
, destANSI
, ppdfileANSI
, sizeof( ppdfileANSI
) ) )
606 err
= UTF8StringToStringObject( ppdfileANSI
, ppdfile
);
607 require_noerr( err
, exit
);
612 err
= translate_errno( i
< 10, errno
, kUnknownErr
);
613 require_noerr( err
, exit
);
615 // Copy the PPD file to the Windows driver directory...
616 filename
.Format( TEXT( "%s/%s.ppd" ), driverdir
, dest
);
618 ok
= in
.Open( ppdfile
, CFile::modeRead
| CFile::typeBinary
);
619 translate_errno( ok
, GetLastError(), kUnknownErr
);
620 require_noerr( err
, exit
);
622 ok
= out
.Open( filename
, CFile::modeCreate
| CFile::modeWrite
| CFile::typeBinary
);
623 translate_errno( ok
, GetLastError(), kUnknownErr
);
624 require_noerr( err
, exit
);
626 while ( ( bytes
= in
.Read( buffer
, sizeof(buffer
) ) ) > 0 )
628 out
.Write(buffer
, bytes
);
634 // Cleanup temp file...
635 CFile::Remove( ppdfile
);
637 // Copy the driver files to the driver directory...
638 for ( i
= 0; i
< ( sizeof( g_printerDriverFiles
) / sizeof( g_printerDriverFiles
[0] ) ); i
++ )
640 filename
.Format( TEXT( "%s/drivers/%s/%s" ), datadir
, platform
, g_printerDriverFiles
[i
]);
642 ok
= in
.Open(filename
, CFile::modeRead
| CFile::typeBinary
);
643 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
644 require_noerr( err
, exit
);
646 filename
.Format( TEXT( "%s/%s" ), driverdir
, g_printerDriverFiles
[i
] );
647 ok
= out
.Open(filename
, CFile::modeCreate
| CFile::modeWrite
| CFile::typeBinary
);
648 err
= translate_errno( ok
, errno
, kUnknownErr
);
650 while ( ( bytes
= in
.Read(buffer
, sizeof( buffer
) ) ) > 0 )
652 out
.Write( buffer
, bytes
);
659 // Do the Windows system calls needed to add the printer driver...
660 filename
.Format( TEXT( "%s.ppd" ), dest
);
661 dependentFiles
.Format( TEXT( "pscript5.dll%c" ) TEXT( "%s.ppd%c" ) TEXT( "ps5ui.dll%c" ) TEXT( "pscript.hlp%c" ) TEXT( "pscript.ntf%c" ) TEXT( "cups6.ini%c" ) TEXT( "cupsps6.dll%c" ) TEXT( "cupsui6.dll%c" ), 0, dest
, 0, 0, 0, 0, 0, 0, 0);
663 driverinfo
.cVersion
= 3;
664 driverinfo
.pName
= printer
->actualName
.GetBuffer();
665 driverinfo
.pEnvironment
= env
;
666 driverinfo
.pDriverPath
= TEXT( "pscript5.dll" );
667 driverinfo
.pDataFile
= filename
.GetBuffer();
668 driverinfo
.pConfigFile
= TEXT( "ps5ui.dll" );
669 driverinfo
.pHelpFile
= TEXT( "pscript.hlp" );
670 driverinfo
.pDependentFiles
= dependentFiles
.GetBuffer();
671 driverinfo
.pMonitorName
= NULL
;
672 driverinfo
.pDefaultDataType
= TEXT( "raw" );
674 ok
= AddPrinterDriverEx(NULL
, 3, (LPBYTE
) &driverinfo
, APD_COPY_ALL_FILES
);
675 err
= translate_errno( ok
, GetLastError(), kUnknownErr
);
676 require_noerr( err
, exit
);
678 // See if the printer has already been added?
679 if ( OpenPrinter( printer
->actualName
.GetBuffer(), &printerHandle
, NULL
) )
681 // Printer already exists, so we are done now...
685 // Add the printer using the HTTP/IPP port...
686 portName
.Format( TEXT( "%s://%s:%d/printers/%s" ), cupsLib
.cupsEncryption() == HTTP_ENCRYPT_ALWAYS
? TEXT( "https" ) : TEXT( "http" ), service
->hostname
.GetBuffer(), service
->portNumber
, dest
);
688 memset(&printerinfo
, 0, sizeof(printerinfo
));
689 printerinfo
.pPrinterName
= printer
->actualName
.GetBuffer();
690 printerinfo
.pPortName
= portName
.GetBuffer();
691 printerinfo
.pDriverName
= printer
->actualName
.GetBuffer();
692 printerinfo
.Attributes
= PRINTER_ATTRIBUTE_NETWORK
| PRINTER_ATTRIBUTE_LOCAL
;
693 printerinfo
.pComment
= q
->description
.GetBuffer();
694 printerinfo
.pLocation
= q
->location
.GetBuffer();
695 printerinfo
.pPrintProcessor
= TEXT( "winprint" );
697 printerHandle
= AddPrinter( NULL
, 2, (LPBYTE
) &printerinfo
);
698 err
= translate_errno( printerHandle
, GetLastError(), kUnknownErr
);
699 require_noerr( err
, exit
);
703 if ( printerHandle
!= NULL
)
705 ClosePrinter( printerHandle
);
706 printerHandle
= NULL
;
712 BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet
, CPropertySheet
)
713 ON_MESSAGE( WM_SOCKET_EVENT
, OnSocketEvent
)
714 ON_MESSAGE( WM_PROCESS_EVENT
, OnProcessEvent
)
720 // ------------------------------------------------------
723 // Traps when the user hits Finish
725 BOOL
CPrinterSetupWizardSheet::OnCommand(WPARAM wParam
, LPARAM lParam
)
728 // Check if this is OK
730 if (wParam
== ID_WIZFINISH
) // If OK is hit...
735 return CPropertySheet::OnCommand(wParam
, lParam
);
739 // ------------------------------------------------------
742 // Initializes this Dialog object.
744 BOOL
CPrinterSetupWizardSheet::OnInitDialog()
748 CPropertySheet::OnInitDialog();
751 require_noerr( err
, exit
);
759 if ( err
== kDNSServiceErr_Firewall
)
761 CString text
, caption
;
763 text
.LoadString( IDS_FIREWALL
);
764 caption
.LoadString( IDS_FIREWALL_CAPTION
);
766 MessageBox(text
, caption
, MB_OK
|MB_ICONEXCLAMATION
);
770 CString text
, caption
;
772 text
.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT
);
773 caption
.LoadString( IDS_ERROR_CAPTION
);
775 MessageBox(text
, caption
, MB_OK
|MB_ICONEXCLAMATION
);
785 // ------------------------------------------------------
788 // This is called when Windows wants to know what cursor
789 // to display. So we tell it.
792 CPrinterSetupWizardSheet::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
795 DEBUG_UNUSED(nHitTest
);
796 DEBUG_UNUSED(message
);
803 // ------------------------------------------------------
806 // This is not fully implemented yet.
810 CPrinterSetupWizardSheet::OnContextMenu(CWnd
* pWnd
, CPoint pos
)
821 // ------------------------------------------------------
824 // This is called when the user hits the "Finish" button
827 CPrinterSetupWizardSheet::OnOK()
832 check ( m_selectedPrinter
!= NULL
);
834 SetWizardButtons( PSWIZB_DISABLEDFINISH
);
836 window
= GetDlgItem( IDCANCEL
);
840 window
->EnableWindow( FALSE
);
843 m_pgFourth
.StartActivityIndicator();
845 err
= InstallPrinter( m_selectedPrinter
);
847 m_pgFourth
.StopActivityIndicator();
854 caption
.LoadString(IDS_INSTALL_ERROR_CAPTION
);
855 caption
.AppendFormat( TEXT( " (%d)" ), err
);
856 message
.LoadString(IDS_INSTALL_ERROR_MESSAGE
);
857 MessageBox(message
, caption
, MB_OK
|MB_ICONEXCLAMATION
);
864 // CPrinterSetupWizardSheet message handlers
866 void CPrinterSetupWizardSheet::Init(void)
868 AddPage(&m_pgSecond
);
870 AddPage(&m_pgFourth
);
872 m_psh
.dwFlags
&= (~PSH_HASHELP
);
874 m_psh
.dwFlags
|= PSH_WIZARD97
|PSH_WATERMARK
|PSH_HEADER
;
875 m_psh
.pszbmWatermark
= MAKEINTRESOURCE(IDB_WATERMARK
);
876 m_psh
.pszbmHeader
= MAKEINTRESOURCE(IDB_BANNER_ICON
);
878 m_psh
.hInstance
= GetNonLocalizedResources();
885 CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam
, LPARAM inLParam
)
887 if (WSAGETSELECTERROR(inLParam
) && !(HIWORD(inLParam
)))
889 dlog( kDebugLevelError
, "OnServiceEvent: window error\n" );
893 SOCKET sock
= (SOCKET
) inWParam
;
896 ServiceRefList::iterator begin
= m_serviceRefList
.begin();
897 ServiceRefList::iterator end
= m_serviceRefList
.end();
901 DNSServiceRef ref
= *begin
++;
905 if ((SOCKET
) DNSServiceRefSockFD(ref
) == sock
)
907 DNSServiceProcessResult(ref
);
918 CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam
, LPARAM inLParam
)
920 DEBUG_UNUSED(inLParam
);
922 m_driverThreadExitCode
= (DWORD
) inWParam
;
923 m_driverThreadFinished
= true;
930 CPrinterSetupWizardSheet::InstallDriverThread( LPVOID inParam
)
932 Printer
* printer
= (Printer
*) inParam
;
937 PROCESS_INFORMATION pi
;
944 // because we're calling endthreadex(), C++ objects won't be cleaned up
945 // correctly. we'll nest the CString 'command' inside a block so
946 // that it's destructor will be invoked.
951 ZeroMemory( &si
, sizeof(si
) );
953 ZeroMemory( &pi
, sizeof(pi
) );
955 command
.Format(L
"rundll32.exe printui.dll,PrintUIEntry /ia /m \"%s\" /f \"%s\"", (LPCTSTR
) printer
->modelName
, (LPCTSTR
) printer
->infFileName
);
957 ok
= CreateProcess(NULL
, command
.GetBuffer(), NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
958 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
959 require_noerr( err
, exit
);
961 dwResult
= WaitForSingleObject( pi
.hProcess
, INFINITE
);
962 translate_errno( dwResult
== WAIT_OBJECT_0
, errno_compat(), err
= kUnknownErr
);
963 require_noerr( err
, exit
);
965 ok
= GetExitCodeProcess( pi
.hProcess
, &exitCode
);
966 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
967 require_noerr( err
, exit
);
973 // Close process and thread handles.
977 CloseHandle( pi
.hProcess
);
982 CloseHandle( pi
.hThread
);
986 // alert the main thread
988 m_self
->PostMessage( WM_PROCESS_EVENT
, err
, exitCode
);
990 _endthreadex_compat( 0 );
997 CPrinterSetupWizardSheet::OnBrowse(
999 DNSServiceFlags inFlags
,
1000 uint32_t inInterfaceIndex
,
1001 DNSServiceErrorType inErrorCode
,
1002 const char * inName
,
1003 const char * inType
,
1004 const char * inDomain
,
1007 DEBUG_UNUSED(inRef
);
1009 CPrinterSetupWizardSheet
* self
;
1010 bool moreComing
= (bool) (inFlags
& kDNSServiceFlagsMoreComing
);
1011 CPropertyPage
* active
;
1012 Printer
* printer
= NULL
;
1013 Service
* service
= NULL
;
1014 OSStatus err
= kNoErr
;
1016 require_noerr( inErrorCode
, exit
);
1018 self
= reinterpret_cast <CPrinterSetupWizardSheet
*>( inContext
);
1019 require_quiet( self
, exit
);
1021 active
= self
->GetActivePage();
1022 require_quiet( active
, exit
);
1024 // Have we seen this printer before?
1026 printer
= self
->Lookup( inName
);
1030 service
= printer
->LookupService( inType
);
1033 if ( inFlags
& kDNSServiceFlagsAdd
)
1035 BOOL newPrinter
= FALSE
;
1039 printer
= self
->OnAddPrinter( inInterfaceIndex
, inName
, inType
, inDomain
, moreComing
);
1040 require_action( printer
, exit
, err
= kUnknownErr
);
1044 // If we're looking at the browse list on page 2, then we need to call
1045 // CPage2::OnAddPrinter() regardless of whether we've seen the printer
1046 // or not because the moreComing flag might have changed from a previous
1047 // call. If we only call CPage2::OnAddPrinter() when there's a new printer,
1048 // we might not correctly update our UI, so if we've seen the printer before,
1049 // call OnAddPrinter with a NULL parameter.
1051 if ( self
->GetActivePage() == &self
->m_pgSecond
)
1053 self
->m_pgSecond
.OnAddPrinter( newPrinter
? printer
: NULL
, moreComing
);
1058 err
= self
->OnAddService( printer
, inInterfaceIndex
, inName
, inType
, inDomain
);
1059 require_noerr( err
, exit
);
1070 err
= self
->OnRemoveService( service
);
1071 require_noerr( err
, exit
);
1073 if ( printer
->services
.size() == 0 )
1075 err
= self
->OnRemovePrinter( printer
, moreComing
);
1076 require_noerr( err
, exit
);
1087 CPrinterSetupWizardSheet::OnResolve(
1088 DNSServiceRef inRef
,
1089 DNSServiceFlags inFlags
,
1090 uint32_t inInterfaceIndex
,
1091 DNSServiceErrorType inErrorCode
,
1092 const char * inFullName
,
1093 const char * inHostName
,
1099 DEBUG_UNUSED(inFullName
);
1100 DEBUG_UNUSED(inInterfaceIndex
);
1101 DEBUG_UNUSED(inFlags
);
1102 DEBUG_UNUSED(inRef
);
1104 CPrinterSetupWizardSheet
* self
;
1110 require_noerr( inErrorCode
, exit
);
1112 service
= reinterpret_cast<Service
*>( inContext
);
1113 require_quiet( service
, exit
);
1115 check( service
->refs
!= 0 );
1117 self
= service
->printer
->window
;
1118 require_quiet( self
, exit
);
1120 err
= self
->StopOperation( service
->serviceRef
);
1121 require_noerr( err
, exit
);
1124 // hold on to the hostname...
1126 err
= UTF8StringToStringObject( inHostName
, service
->hostname
);
1127 require_noerr( err
, exit
);
1130 // <rdar://problem/3739200> remove the trailing dot on hostname
1132 idx
= service
->hostname
.ReverseFind('.');
1134 if ((idx
> 1) && ((service
->hostname
.GetLength() - 1) == idx
))
1136 service
->hostname
.Delete(idx
, 1);
1140 // hold on to the port
1142 service
->portNumber
= ntohs(inPort
);
1144 if ( service
->qtotal
== 1 )
1147 // create a new queue
1158 require_action( q
, exit
, err
= E_OUTOFMEMORY
);
1161 // parse the text record.
1164 err
= self
->ParseTextRecord( service
, q
, inTXTSize
, inTXT
);
1165 require_noerr( err
, exit
);
1167 service
->queues
.push_back( q
);
1170 // we've completely resolved this service
1173 self
->OnResolveService( service
);
1178 // if qtotal is more than 1, then we need to get additional
1179 // text records. if not, then this service is considered
1183 err
= DNSServiceQueryRecord(&service
->serviceRef
, 0, inInterfaceIndex
, inFullName
, kDNSServiceType_TXT
, kDNSServiceClass_IN
, OnQuery
, (void*) service
);
1184 require_noerr( err
, exit
);
1186 err
= self
->StartOperation( service
->serviceRef
);
1187 require_noerr( err
, exit
);
1197 CPrinterSetupWizardSheet::OnQuery(
1198 DNSServiceRef inRef
,
1199 DNSServiceFlags inFlags
,
1200 uint32_t inInterfaceIndex
,
1201 DNSServiceErrorType inErrorCode
,
1202 const char * inFullName
,
1206 const void * inRData
,
1210 DEBUG_UNUSED( inTTL
);
1211 DEBUG_UNUSED( inRRClass
);
1212 DEBUG_UNUSED( inRRType
);
1213 DEBUG_UNUSED( inFullName
);
1214 DEBUG_UNUSED( inInterfaceIndex
);
1215 DEBUG_UNUSED( inRef
);
1217 Service
* service
= NULL
;
1219 CPrinterSetupWizardSheet
* self
;
1220 OSStatus err
= kNoErr
;
1222 require_noerr( inErrorCode
, exit
);
1224 service
= reinterpret_cast<Service
*>( inContext
);
1225 require_quiet( service
, exit
);
1227 self
= service
->printer
->window
;
1228 require_quiet( self
, exit
);
1230 if ( ( inFlags
& kDNSServiceFlagsAdd
) && ( inRDLen
> 0 ) && ( inRData
!= NULL
) )
1232 const char * inTXT
= ( const char * ) inRData
;
1235 // create a new queue
1246 require_action( q
, exit
, err
= E_OUTOFMEMORY
);
1248 err
= service
->printer
->window
->ParseTextRecord( service
, q
, inRDLen
, inTXT
);
1249 require_noerr( err
, exit
);
1255 service
->queues
.push_back( q
);
1257 if ( service
->queues
.size() == service
->qtotal
)
1260 // else if moreComing is not set, then we're going
1261 // to assume that we're done
1264 self
->StopOperation( service
->serviceRef
);
1270 service
->queues
.sort( OrderQueueFunc
);
1273 // we've completely resolved this service
1276 self
->OnResolveService( service
);
1282 if ( err
&& service
&& ( service
->serviceRef
!= NULL
) )
1284 service
->printer
->window
->StopOperation( service
->serviceRef
);
1292 CPrinterSetupWizardSheet::OnAddPrinter(
1293 uint32_t inInterfaceIndex
,
1294 const char * inName
,
1295 const char * inType
,
1296 const char * inDomain
,
1299 Printer
* printer
= NULL
;
1300 DWORD printerNameCount
;
1303 DEBUG_UNUSED( inInterfaceIndex
);
1304 DEBUG_UNUSED( inType
);
1305 DEBUG_UNUSED( inDomain
);
1306 DEBUG_UNUSED( moreComing
);
1310 printer
= new Printer
;
1317 require_action( printer
, exit
, err
= E_OUTOFMEMORY
);
1319 printer
->window
= this;
1320 printer
->name
= inName
;
1322 err
= UTF8StringToStringObject(inName
, printer
->displayName
);
1324 printer
->actualName
= printer
->displayName
;
1325 printer
->installed
= false;
1326 printer
->deflt
= false;
1327 printer
->resolving
= 0;
1329 // Compare this name against printers that are already installed
1330 // to avoid name clashes. Rename as necessary
1331 // to come up with a unique name.
1333 printerNameCount
= 2;
1337 CPrinterSetupWizardSheet::PrinterNames::iterator it
;
1339 // <rdar://problem/4141221> Don't use find to do comparisons because we need to
1340 // do a case insensitive string comparison
1342 for ( it
= m_printerNames
.begin(); it
!= m_printerNames
.end(); it
++ )
1344 if ( (*it
).CompareNoCase( printer
->actualName
) == 0 )
1350 if (it
!= m_printerNames
.end())
1352 printer
->actualName
.Format(L
"%s (%d)", printer
->displayName
, printerNameCount
);
1362 m_printers
.push_back( printer
);
1371 CPrinterSetupWizardSheet::OnAddService(
1373 uint32_t inInterfaceIndex
,
1374 const char * inName
,
1375 const char * inType
,
1376 const char * inDomain
)
1378 Service
* service
= NULL
;
1379 OSStatus err
= kNoErr
;
1381 DEBUG_UNUSED( inName
);
1382 DEBUG_UNUSED( inDomain
);
1386 service
= new Service
;
1393 require_action( service
, exit
, err
= E_OUTOFMEMORY
);
1395 service
->printer
= printer
;
1396 service
->ifi
= inInterfaceIndex
;
1397 service
->type
= inType
;
1398 service
->domain
= inDomain
;
1399 service
->qtotal
= 1;
1401 service
->serviceRef
= NULL
;
1403 printer
->services
.push_back( service
);
1406 // if the printer is selected, then we'll want to start a
1407 // resolve on this guy
1410 if ( printer
== m_selectedPrinter
)
1412 StartResolve( service
);
1422 CPrinterSetupWizardSheet::OnRemovePrinter( Printer
* printer
, bool moreComing
)
1424 CPropertyPage
* active
= GetActivePage();
1425 OSStatus err
= kNoErr
;
1427 if ( active
== &m_pgSecond
)
1429 m_pgSecond
.OnRemovePrinter( printer
, moreComing
);
1432 m_printers
.remove( printer
);
1434 if ( m_selectedPrinter
== printer
)
1436 m_selectedPrinter
= NULL
;
1438 if ( ( active
== &m_pgThird
) || ( active
== &m_pgFourth
) )
1443 caption
.LoadString( IDS_ERROR_CAPTION
);
1444 message
.LoadString( IDS_PRINTER_UNAVAILABLE
);
1446 MessageBox(message
, caption
, MB_OK
|MB_ICONEXCLAMATION
);
1448 SetActivePage( &m_pgSecond
);
1459 CPrinterSetupWizardSheet::OnRemoveService( Service
* service
)
1461 OSStatus err
= kNoErr
;
1463 if ( service
&& ( --service
->refs
== 0 ) )
1465 if ( service
->serviceRef
!= NULL
)
1467 err
= StopResolve( service
);
1468 require_noerr( err
, exit
);
1471 service
->printer
->services
.remove( service
);
1483 CPrinterSetupWizardSheet::OnResolveService( Service
* service
)
1485 // Make sure that the active page is page 2
1487 require_quiet( GetActivePage() == &m_pgSecond
, exit
);
1489 if ( !--service
->printer
->resolving
)
1491 // sort the services now. we want the service that
1492 // has the highest priority queue to be first in
1495 service
->printer
->services
.sort( OrderServiceFunc
);
1497 // Now we can hit next
1499 SetWizardButtons( PSWIZB_BACK
|PSWIZB_NEXT
);
1505 // And tell page 2 about it
1507 m_pgSecond
.OnResolveService( service
);
1517 CPrinterSetupWizardSheet::StartBrowse()
1522 // setup the DNS-SD browsing
1524 err
= DNSServiceBrowse( &m_pdlBrowser
, 0, 0, kPDLServiceType
, NULL
, OnBrowse
, this );
1525 require_noerr( err
, exit
);
1527 err
= StartOperation( m_pdlBrowser
);
1528 require_noerr( err
, exit
);
1530 err
= DNSServiceBrowse( &m_lprBrowser
, 0, 0, kLPRServiceType
, NULL
, OnBrowse
, this );
1531 require_noerr( err
, exit
);
1533 err
= StartOperation( m_lprBrowser
);
1534 require_noerr( err
, exit
);
1536 err
= DNSServiceBrowse( &m_ippBrowser
, 0, 0, kIPPServiceType
, NULL
, OnBrowse
, this );
1537 require_noerr( err
, exit
);
1539 err
= StartOperation( m_ippBrowser
);
1540 require_noerr( err
, exit
);
1549 CPrinterSetupWizardSheet::StopBrowse()
1553 err
= StopOperation( m_pdlBrowser
);
1554 require_noerr( err
, exit
);
1556 err
= StopOperation( m_lprBrowser
);
1557 require_noerr( err
, exit
);
1559 err
= StopOperation( m_ippBrowser
);
1560 require_noerr( err
, exit
);
1562 while ( m_printers
.size() > 0 )
1564 Printer
* printer
= m_printers
.front();
1566 m_printers
.pop_front();
1568 if ( printer
->resolving
)
1570 StopResolve( printer
);
1583 CPrinterSetupWizardSheet::StartResolve( Printer
* printer
)
1585 OSStatus err
= kNoErr
;
1586 Services::iterator it
;
1590 for ( it
= printer
->services
.begin(); it
!= printer
->services
.end(); it
++ )
1592 if ( (*it
)->serviceRef
== NULL
)
1594 err
= StartResolve( *it
);
1595 require_noerr( err
, exit
);
1599 m_selectedPrinter
= printer
;
1608 CPrinterSetupWizardSheet::StartResolve( Service
* service
)
1610 OSStatus err
= kNoErr
;
1612 check( service
->serviceRef
== NULL
);
1615 // clean out any queues that were collected during a previous
1619 service
->EmptyQueues();
1622 // now start the new resolve
1625 err
= DNSServiceResolve( &service
->serviceRef
, 0, 0, service
->printer
->name
.c_str(), service
->type
.c_str(), service
->domain
.c_str(), (DNSServiceResolveReply
) OnResolve
, service
);
1626 require_noerr( err
, exit
);
1628 err
= StartOperation( service
->serviceRef
);
1629 require_noerr( err
, exit
);
1632 // If we're not currently resolving, then disable the next button
1633 // and set the cursor to hourglass
1636 if ( !service
->printer
->resolving
)
1638 SetWizardButtons( PSWIZB_BACK
);
1641 SetCursor(m_active
);
1644 service
->printer
->resolving
++;
1653 CPrinterSetupWizardSheet::StopResolve(Printer
* printer
)
1655 OSStatus err
= kNoErr
;
1659 Services::iterator it
;
1661 for ( it
= printer
->services
.begin(); it
!= printer
->services
.end(); it
++ )
1663 if ( (*it
)->serviceRef
)
1665 err
= StopResolve( *it
);
1666 require_noerr( err
, exit
);
1677 CPrinterSetupWizardSheet::StopResolve( Service
* service
)
1681 check( service
->serviceRef
);
1683 err
= StopOperation( service
->serviceRef
);
1684 require_noerr( err
, exit
);
1686 service
->printer
->resolving
--;
1695 CPrinterSetupWizardSheet::StartOperation( DNSServiceRef ref
)
1699 err
= WSAAsyncSelect((SOCKET
) DNSServiceRefSockFD(ref
), m_hWnd
, WM_SOCKET_EVENT
, FD_READ
|FD_CLOSE
);
1700 require_noerr( err
, exit
);
1702 m_serviceRefList
.push_back( ref
);
1711 CPrinterSetupWizardSheet::StopOperation( DNSServiceRef
& ref
)
1713 OSStatus err
= kNoErr
;
1717 m_serviceRefList
.remove( ref
);
1719 if ( IsWindow( m_hWnd
) )
1721 err
= WSAAsyncSelect((SOCKET
) DNSServiceRefSockFD( ref
), m_hWnd
, 0, 0 );
1722 require_noerr( err
, exit
);
1725 DNSServiceRefDeallocate( ref
);
1736 CPrinterSetupWizardSheet::ParseTextRecord( Service
* service
, Queue
* q
, uint16_t inTXTSize
, const char * inTXT
)
1741 // <rdar://problem/3946587> Use TXTRecord APIs declared in dns_sd.h
1743 bool qtotalDefined
= false;
1747 OSStatus err
= kNoErr
;
1749 // <rdar://problem/3987680> Default to queue "lp"
1753 // <rdar://problem/4003710> Default pdl key to be "application/postscript"
1755 q
->pdl
= L
"application/postscript";
1757 if ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "rp", &len
) ) != NULL
)
1759 // Stringize val ( doesn't have trailing '\0' yet )
1761 memcpy( buf
, val
, len
);
1764 err
= UTF8StringToStringObject( buf
, q
->name
);
1765 require_noerr( err
, exit
);
1768 if ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "pdl", &len
) ) != NULL
)
1770 // Stringize val ( doesn't have trailing '\0' yet )
1772 memcpy( buf
, val
, len
);
1775 err
= UTF8StringToStringObject( buf
, q
->pdl
);
1776 require_noerr( err
, exit
);
1779 if ( ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "usb_mfg", &len
) ) != NULL
) ||
1780 ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "usb_manufacturer", &len
) ) != NULL
) )
1782 // Stringize val ( doesn't have trailing '\0' yet )
1784 memcpy( buf
, val
, len
);
1787 err
= UTF8StringToStringObject( buf
, q
->usb_MFG
);
1788 require_noerr( err
, exit
);
1791 if ( ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "usb_mdl", &len
) ) != NULL
) ||
1792 ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "usb_model", &len
) ) != NULL
) )
1794 // Stringize val ( doesn't have trailing '\0' yet )
1796 memcpy( buf
, val
, len
);
1799 err
= UTF8StringToStringObject( buf
, q
->usb_MDL
);
1800 require_noerr( err
, exit
);
1803 if ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "ty", &len
) ) != NULL
)
1805 // Stringize val ( doesn't have trailing '\0' yet )
1807 memcpy( buf
, val
, len
);
1810 err
= UTF8StringToStringObject( buf
, q
->description
);
1811 require_noerr( err
, exit
);
1814 if ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "product", &len
) ) != NULL
)
1816 // Stringize val ( doesn't have trailing '\0' yet )
1818 memcpy( buf
, val
, len
);
1821 err
= UTF8StringToStringObject( buf
, q
->product
);
1822 require_noerr( err
, exit
);
1825 if ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "note", &len
) ) != NULL
)
1827 // Stringize val ( doesn't have trailing '\0' yet )
1829 memcpy( buf
, val
, len
);
1832 err
= UTF8StringToStringObject( buf
, q
->location
);
1833 require_noerr( err
, exit
);
1836 if ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "qtotal", &len
) ) != NULL
)
1838 // Stringize val ( doesn't have trailing '\0' yet )
1840 memcpy( buf
, val
, len
);
1843 service
->qtotal
= (unsigned short) atoi( buf
);
1844 qtotalDefined
= true;
1847 if ( ( val
= TXTRecordGetValuePtr( inTXTSize
, inTXT
, "priority", &len
) ) != NULL
)
1849 // Stringize val ( doesn't have trailing '\0' yet )
1851 memcpy( buf
, val
, len
);
1854 q
->priority
= atoi( buf
);
1857 // <rdar://problem/4124524> Was this printer discovered via OS X Printer Sharing?
1859 if ( TXTRecordContainsKey( inTXTSize
, inTXT
, "printer-state" ) || TXTRecordContainsKey( inTXTSize
, inTXT
, "printer-type" ) )
1861 service
->printer
->isCUPSPrinter
= true;
1866 // The following code is to fix a problem with older HP
1867 // printers that don't include "qtotal" in their text
1868 // record. We'll check to see if the q->name is "TEXT"
1869 // and if so, we're going to modify it to be "lp" so
1870 // that we don't use the wrong queue
1872 if ( !err
&& !qtotalDefined
&& ( q
->name
== L
"TEXT" ) )
1882 CPrinterSetupWizardSheet::Lookup(const char * inName
)
1886 Printer
* printer
= NULL
;
1887 Printers::iterator it
;
1889 for ( it
= m_printers
.begin(); it
!= m_printers
.end(); it
++ )
1891 if ( (*it
)->name
== inName
)
1903 CPrinterSetupWizardSheet::OrderServiceFunc( const Service
* a
, const Service
* b
)
1907 q1
= (a
->queues
.size() > 0) ? a
->queues
.front() : NULL
;
1909 q2
= (b
->queues
.size() > 0) ? b
->queues
.front() : NULL
;
1915 else if ( q1
&& !q2
)
1919 else if ( !q1
&& q2
)
1923 else if ( q1
->priority
< q2
->priority
)
1927 else if ( q1
->priority
> q2
->priority
)
1931 else if ( ( a
->type
== kPDLServiceType
) || ( ( a
->type
== kLPRServiceType
) && ( b
->type
== kIPPServiceType
) ) )
1943 CPrinterSetupWizardSheet::OrderQueueFunc( const Queue
* q1
, const Queue
* q2
)
1945 return ( q1
->priority
<= q2
->priority
) ? true : false;