X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/blobdiff_plain/619ee211a2d1cd19533acb8c109cb34a602cbd46..2682e09e0dbe18ba42fd4707b09a89e8c34f697c:/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp index e912716..47e5f91 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp @@ -13,130 +13,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - - Change History (most recent first): - -$Log: PrinterSetupWizardSheet.cpp,v $ -Revision 1.35 2006/08/14 23:24:09 cheshire -Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0 - -Revision 1.34 2005/10/05 17:32:51 herscher - Use a case insensitive compare operation to check whether a printer with the same name has already been installed. - -Revision 1.33 2005/07/11 20:17:15 shersche - UI fixes associated with CUPS printer workaround fix. - -Revision 1.32 2005/07/07 17:53:20 shersche -Fix problems associated with the CUPS printer workaround fix. - -Revision 1.31 2005/06/30 18:02:54 shersche - Workaround for Mac OS X Printer Sharing bug - -Revision 1.30 2005/04/13 17:46:22 shersche - Generic PCL not selected when printers advertise multiple text records - -Revision 1.29 2005/02/14 20:48:37 shersche - Default pdl key to "application/postscript" - -Revision 1.28 2005/02/14 20:37:53 shersche - Populate comment field with the model name that users see in the wizard UI. - -Revision 1.27 2005/02/09 05:04:03 shersche - Use TXTRecordGetValuePtr() API in ParseTextRecord - -Revision 1.26 2005/02/08 21:45:06 shersche - Default to Generic PostScript or PCL if unable to match driver - -Revision 1.25 2005/02/08 18:54:17 shersche - Default queue name is "lp" when rp key is not specified. - -Revision 1.24 2005/02/01 02:15:55 shersche - Use TXTRecord parsing APIs in ParseTextRecord - -Revision 1.23 2005/01/31 23:54:30 shersche - Start browsing when printer wizard starts. Move browsing logic from CSecondPage object to CPrinterSetupWizardSheet object. - -Revision 1.22 2005/01/25 18:49:43 shersche -Get icon resources from resource DLL - -Revision 1.21 2005/01/10 01:09:32 shersche -Use the "note" key to populate pLocation field when setting up printer - -Revision 1.20 2005/01/03 19:05:01 shersche -Store pointer to instance of wizard sheet so that print driver install thread sends a window message to the correct window - -Revision 1.19 2004/12/31 07:23:53 shersche -Don't modify the button setting in SetSelectedPrinter() - -Revision 1.18 2004/12/29 18:53:38 shersche - - Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase. -Bug #: 3725106, 3737413 - -Revision 1.17 2004/10/12 18:02:53 shersche - Escape '/', '@', '"' characters in printui command. -Bug #: 3764873 - -Revision 1.16 2004/09/13 21:27:22 shersche - Pass the moreComing flag to OnAddPrinter and OnRemovePrinter callbacks -Bug #: 3796483 - -Revision 1.15 2004/09/11 05:59:06 shersche - Fix code that generates unique printer names based on currently installed printers -Bug #: 3785766 - -Revision 1.14 2004/09/02 01:57:58 cheshire - Fix incorrect testing of MoreComing flag - -Revision 1.13 2004/07/26 21:06:29 shersche - Removing trailing '.' in hostname -Bug #: 3739200 - -Revision 1.12 2004/07/13 21:24:23 rpantos -Fix for . - -Revision 1.11 2004/06/28 00:51:47 shersche -Move call to EnumPrinters out of browse callback into standalone function - -Revision 1.10 2004/06/27 23:06:47 shersche -code cleanup, make sure EnumPrinters returns non-zero value - -Revision 1.9 2004/06/27 15:49:31 shersche -clean up some cruft in the printer browsing code - -Revision 1.8 2004/06/27 08:04:51 shersche -copy selected printer to prevent printer being deleted out from under - -Revision 1.7 2004/06/26 23:27:12 shersche -support for installing multiple printers of the same name - -Revision 1.6 2004/06/26 21:22:39 shersche -handle spaces in file names - -Revision 1.5 2004/06/26 03:19:57 shersche -clean up warning messages - -Submitted by: herscher - -Revision 1.4 2004/06/25 02:26:52 shersche -Normalize key fields in text record entries -Submitted by: herscher - -Revision 1.3 2004/06/24 20:12:07 shersche -Clean up source code -Submitted by: herscher - -Revision 1.2 2004/06/23 17:58:21 shersche - eliminated memory leaks on exit - installation of a printer that is already installed results in a no-op -Bug #: 3701837, 3701926 -Submitted by: herscher - -Revision 1.1 2004/06/18 04:36:57 rpantos -First checked in - - -*/ + */ #include "stdafx.h" #include "PrinterSetupWizardApp.h" @@ -145,9 +22,10 @@ First checked in #include "DebugServices.h" #include "WinServices.h" #include "About.h" +#include "tcpxcv.h" #include -#include #include +#include // unreachable code #pragma warning(disable:4702) @@ -158,12 +36,61 @@ First checked in # include #endif + +#if defined( UNICODE ) || defined( _UNICODE ) +# define GetEnv _wgetenv +#else +# define GetEnv getenv +#endif + +static TCHAR* +g_printerDriverFiles[] = // Printer driver files +{ + TEXT( "ps5ui.dll" ), + TEXT( "pscript.hlp" ), + TEXT( "pscript.ntf" ), + TEXT( "pscript5.dll" ), + TEXT( "cups6.ini" ), + TEXT( "cupsui6.dll" ), + TEXT( "cupsps6.dll" ) +}; + + // Private Messages #define WM_SOCKET_EVENT ( WM_USER + 0x100 ) #define WM_PROCESS_EVENT ( WM_USER + 0x101 ) +static BOOL +Is64BitWindows() +{ +#if defined(_WIN64) + return TRUE; // 64-bit programs run only on Win64 +#else + typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)( HANDLE, PBOOL ); + LPFN_ISWOW64PROCESS fnIsWow64Process; + BOOL bIsWow64 = FALSE; + + fnIsWow64Process = ( LPFN_ISWOW64PROCESS ) GetProcAddress( GetModuleHandle( TEXT( "kernel32" ) ), "IsWow64Process" ); + + if ( fnIsWow64Process != NULL ) + { + BOOL ok; + + ok = fnIsWow64Process( GetCurrentProcess(), &bIsWow64 ); + + if ( !ok ) + { + bIsWow64 = FALSE; + } + } + + return bIsWow64; +#endif +} + + // CPrinterSetupWizardSheet CPrinterSetupWizardSheet * CPrinterSetupWizardSheet::m_self; @@ -279,7 +206,7 @@ exit: // // Installs a printer with Windows. // -// NOTE: this works one of two ways, depending on whether +// Note: this works one of two ways, depending on whether // there are drivers already installed for this printer. // If there are, then we can just create a port with XcvData, // and then call AddPrinter. If not, we use the printui.dll @@ -292,81 +219,97 @@ exit: OSStatus CPrinterSetupWizardSheet::InstallPrinter(Printer * printer) { - Service * service; + Logger log; + CUPSLibrary cupsLib; + Service * service = NULL; BOOL ok; - OSStatus err; + OSStatus err = 0; service = printer->services.front(); check( service ); - // - // if the driver isn't installed, then install it - // - - if ( !printer->driverInstalled ) + if ( printer->isCUPSPrinter && cupsLib.IsInstalled() ) { - DWORD dwResult; - HANDLE hThread; - unsigned threadID; - - m_driverThreadFinished = false; - - // - // create the thread - // - hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID ); - err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr ); + err = InstallPrinterCUPS( printer, service, cupsLib ); require_noerr( err, exit ); - + } + else + { // - // go modal + // if the driver isn't installed, then install it // - while (!m_driverThreadFinished) + + if ( !printer->driverInstalled ) { - MSG msg; - - GetMessage( &msg, m_hWnd, 0, 0 ); - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - // - // Wait until child process exits. - // - dwResult = WaitForSingleObject( hThread, INFINITE ); - err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr ); - require_noerr( err, exit ); + DWORD dwResult; + HANDLE hThread; + unsigned threadID; - // - // check the return value of thread - // - require_noerr( m_driverThreadExitCode, exit ); + m_driverThreadFinished = false; + + // + // create the thread + // + hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID ); + err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr ); + require_noerr_with_log( log, "_beginthreadex_compat()", err, exit ); + + // + // go modal + // + while (!m_driverThreadFinished) + { + MSG msg; + + GetMessage( &msg, m_hWnd, 0, 0 ); + TranslateMessage(&msg); + DispatchMessage(&msg); + } - // - // now we know that the driver was successfully installed - // - printer->driverInstalled = true; - } + // + // Wait until child process exits. + // + dwResult = WaitForSingleObject( hThread, INFINITE ); + err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr ); + require_noerr_with_log( log, "WaitForSingleObject()", err, exit ); - if ( service->type == kPDLServiceType ) - { - err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE ); - require_noerr( err, exit ); - } - else if ( service->type == kLPRServiceType ) - { - err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE ); - require_noerr( err, exit ); - } - else if ( service->type == kIPPServiceType ) - { - err = InstallPrinterIPP( printer, service ); - require_noerr( err, exit ); - } - else - { - err = kUnknownErr; - require_noerr( err, exit ); + // + // check the return value of thread + // + require_noerr_with_log( log, "thread exit code", m_driverThreadExitCode, exit ); + + // + // now we know that the driver was successfully installed + // + printer->driverInstalled = true; + } + + if ( service->type == kPDLServiceType ) + { + err = InstallPrinterPort( printer, service, PROTOCOL_RAWTCP_TYPE, log ); + require_noerr_with_log( log, "InstallPrinterPort()", err, exit ); + err = InstallPrinterPDLAndLPR( printer, service, log ); + require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit ); + } + else if ( service->type == kLPRServiceType ) + { + err = InstallPrinterPort( printer, service, PROTOCOL_LPR_TYPE, log ); + require_noerr_with_log( log, "InstallPrinterPort()", err, exit ); + err = InstallPrinterPDLAndLPR( printer, service, log ); + require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit ); + } + else if ( service->type == kIPPServiceType ) + { + // There's no need to install a printer port for IPP printers, because + // the call to AddPrinter() will do that for us. + + err = InstallPrinterIPP( printer, service, log ); + require_noerr_with_log( log, "InstallPrinterIPP()", err, exit ); + } + else + { + require_action_with_log( log, ( service->type == kPDLServiceType ) || ( service->type == kLPRServiceType ) || ( service->type == kIPPServiceType ), exit, err = kUnknownErr ); + } } printer->installed = true; @@ -378,7 +321,7 @@ CPrinterSetupWizardSheet::InstallPrinter(Printer * printer) { ok = SetDefaultPrinter( printer->actualName ); err = translate_errno( ok, errno_compat(), err = kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "SetDefaultPrinter()", err, exit ); } exit: @@ -388,30 +331,30 @@ exit: OSStatus -CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol ) +CPrinterSetupWizardSheet::InstallPrinterPort( Printer * printer, Service * service, DWORD protocol, Logger & log ) { PRINTER_DEFAULTS printerDefaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER }; + PORT_DATA_1 portData; DWORD dwStatus; DWORD cbInputData = 100; PBYTE pOutputData = NULL; DWORD cbOutputNeeded = 0; - PORT_DATA_1 portData; - PRINTER_INFO_2 pInfo; HANDLE hXcv = NULL; - HANDLE hPrinter = NULL; Queue * q; BOOL ok; OSStatus err; - check(printer != NULL); - check(printer->installed == false); + ZeroMemory(&portData, sizeof(PORT_DATA_1)); + + require_action_with_log( log, wcslen(printer->portName) < sizeof_array(portData.sztPortName), exit, err = kSizeErr ); + wcscpy_s(portData.sztPortName, printer->portName); q = service->queues.front(); check( q ); ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults); err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "OpenPrinter()", err, exit ); // // BUGBUG: MSDN said this is not required, but my experience shows it is required @@ -425,28 +368,55 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s pOutputData = NULL; } - require_action( pOutputData, exit, err = kNoMemoryErr ); - - // - // setup the port - // - ZeroMemory(&portData, sizeof(PORT_DATA_1)); - wcscpy(portData.sztPortName, printer->portName); + require_action_with_log( log, pOutputData, exit, err = kNoMemoryErr ); portData.dwPortNumber = service->portNumber; portData.dwVersion = 1; + portData.dwDoubleSpool = 1; portData.dwProtocol = protocol; portData.cbSize = sizeof PORT_DATA_1; portData.dwReserved = 0L; - - wcscpy(portData.sztQueue, q->name); - wcscpy(portData.sztIPAddress, service->hostname); - wcscpy(portData.sztHostAddress, service->hostname); + + require_action_with_log( log, wcslen(q->name) < sizeof_array(portData.sztQueue), exit, err = kSizeErr ); + wcscpy_s(portData.sztQueue, q->name); + + require_action_with_log( log, wcslen( service->hostname ) < sizeof_array(portData.sztHostAddress), exit, err = kSizeErr ); + wcscpy_s( portData.sztHostAddress, service->hostname ); ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData, &cbOutputNeeded, &dwStatus); err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "XcvData()", err, exit ); + +exit: + + if (hXcv != NULL) + { + ClosePrinter(hXcv); + } + + if (pOutputData != NULL) + { + delete [] pOutputData; + } + + return err; +} + + +OSStatus +CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, Logger & log ) +{ + PRINTER_INFO_2 pInfo; + HANDLE hPrinter = NULL; + Queue * q; + OSStatus err; + + check(printer != NULL); + check(printer->installed == false); + + q = service->queues.front(); + check( q ); // // add the printer @@ -475,7 +445,7 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo); err = translate_errno( hPrinter, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "AddPrinter()", err, exit ); exit: @@ -484,22 +454,12 @@ exit: ClosePrinter(hPrinter); } - if (hXcv != NULL) - { - ClosePrinter(hXcv); - } - - if (pOutputData != NULL) - { - delete [] pOutputData; - } - return err; } OSStatus -CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service) +CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service, Logger & log) { DEBUG_UNUSED( service ); @@ -525,7 +485,7 @@ CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pInfo); err = translate_errno( hPrinter, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); + require_noerr_with_log( log, "AddPrinter()", err, exit ); exit: @@ -538,6 +498,217 @@ exit: } +OSStatus +CPrinterSetupWizardSheet::InstallPrinterCUPS(Printer * printer, Service * service, CUPSLibrary & cupsLib ) +{ + OSStatus err = kNoErr; + + check( printer ); + check( service ); + check( cupsLib.IsInstalled() ); + + err = InstallPrinterCUPS( printer, service, cupsLib, TEXT( "Windows NT x86" ) ); + require_noerr( err, exit ); + + if ( Is64BitWindows() ) + { + err = InstallPrinterCUPS( printer, service, cupsLib, TEXT( "Windows x64" ) ); + require_noerr( err, exit ); + } + +exit: + + return err; +} + + +OSStatus +CPrinterSetupWizardSheet::InstallPrinterCUPS(Printer * printer, Service * service, CUPSLibrary & cupsLib, TCHAR * env ) +{ + + Queue * q; + CString ppdfile; // PPD file for printer drivers + TCHAR driverdir[1024]; // Directory for driver files + DWORD needed; // Bytes needed + DRIVER_INFO_3 driverinfo; // Driver information + PRINTER_INFO_2 printerinfo; // Printer information + HANDLE printerHandle = NULL; // Handle to printer + CString filename; // Driver filename + CString dependentFiles; // List of dependent files + CString portName; // Port Name + int bytes; // Bytes copied + TCHAR datadir[ MAX_PATH ]; // Driver files location + CFile in; // Input file + CFile out; // Output file + void * http; // Connection to server + char buffer[4096]; // Copy/error buffer + CString platform; + char hostname[ 1024 ]; + CString dest; + char destANSI[ 1024 ]; + int i; + DWORD num; + OSStatus err = 0; + BOOL ok; + + check( printer ); + check( service ); + check( cupsLib.IsInstalled() ); + check( env ); + + // What do we do here for multiple queues? + q = service->queues.front(); + require_action( q != NULL, exit, err = kUnknownErr ); + + num = GetModuleFileName( NULL, datadir, MAX_PATH ); + err = translate_errno( num > 0, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + ok = PathRemoveFileSpec( datadir ); + require_action( ok, exit, err = kUnknownErr ); + + ok = GetPrinterDriverDirectory(NULL, env, 1, ( LPBYTE ) driverdir, sizeof( driverdir ), &needed ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + platform = env; + platform = platform.Right( 3 ); + + // Append the supported banner pages to the PPD file... + err = StringObjectToUTF8String( service->hostname, hostname, sizeof( hostname ) ); + require_noerr( err, exit ); + http = cupsLib.httpConnectEncrypt( hostname, service->portNumber, cupsLib.cupsEncryption() ); + err = translate_errno( http != NULL, errno, kUnknownErr ); + require_noerr( err, exit ); + + if ( ( service->portNumber == 443 ) || ( cupsLib.cupsEncryption() >= HTTP_ENCRYPT_REQUIRED ) ) + { + // This forces the use the https: URLs below... + cupsLib.cupsSetEncryption( HTTP_ENCRYPT_ALWAYS ); + } + + // Strip the leading "printers/" or "classes/" from the beginning + // of the name + + dest = q->name; + dest.Replace( TEXT( "printers/" ), TEXT( "" ) ); + dest.Replace( TEXT( "classes/" ), TEXT( "" ) ); + + err = StringObjectToUTF8String( dest, destANSI, sizeof( destANSI ) ); + require_noerr( err, exit ); + + // Get the PPD file... + for ( i = 0; i < 10; i++ ) + { + char ppdfileANSI[ 1024 ]; + + if ( cupsLib.cupsAdminCreateWindowsPPD( http, destANSI, ppdfileANSI, sizeof( ppdfileANSI ) ) ) + { + err = UTF8StringToStringObject( ppdfileANSI, ppdfile ); + require_noerr( err, exit ); + break; + } + } + + err = translate_errno( i < 10, errno, kUnknownErr ); + require_noerr( err, exit ); + + // Copy the PPD file to the Windows driver directory... + filename.Format( TEXT( "%s/%s.ppd" ), driverdir, dest ); + + ok = in.Open( ppdfile, CFile::modeRead | CFile::typeBinary ); + translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + ok = out.Open( filename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary ); + translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + while ( ( bytes = in.Read( buffer, sizeof(buffer) ) ) > 0 ) + { + out.Write(buffer, bytes ); + } + + in.Close(); + out.Close(); + + // Cleanup temp file... + CFile::Remove( ppdfile ); + + // Copy the driver files to the driver directory... + for ( i = 0; i < ( sizeof( g_printerDriverFiles ) / sizeof( g_printerDriverFiles[0] ) ); i++ ) + { + filename.Format( TEXT( "%s/drivers/%s/%s" ), datadir, platform, g_printerDriverFiles[i]); + + ok = in.Open(filename, CFile::modeRead | CFile::typeBinary ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + filename.Format( TEXT( "%s/%s" ), driverdir, g_printerDriverFiles[i] ); + ok = out.Open(filename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary ); + err = translate_errno( ok, errno, kUnknownErr ); + + while ( ( bytes = in.Read(buffer, sizeof( buffer ) ) ) > 0 ) + { + out.Write( buffer, bytes ); + } + + in.Close(); + out.Close(); + } + + // Do the Windows system calls needed to add the printer driver... + filename.Format( TEXT( "%s.ppd" ), dest); + 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); + + driverinfo.cVersion = 3; + driverinfo.pName = printer->actualName.GetBuffer(); + driverinfo.pEnvironment = env; + driverinfo.pDriverPath = TEXT( "pscript5.dll" ); + driverinfo.pDataFile = filename.GetBuffer(); + driverinfo.pConfigFile = TEXT( "ps5ui.dll" ); + driverinfo.pHelpFile = TEXT( "pscript.hlp" ); + driverinfo.pDependentFiles = dependentFiles.GetBuffer(); + driverinfo.pMonitorName = NULL; + driverinfo.pDefaultDataType = TEXT( "raw" ); + + ok = AddPrinterDriverEx(NULL, 3, (LPBYTE) &driverinfo, APD_COPY_ALL_FILES ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + + // See if the printer has already been added? + if ( OpenPrinter( printer->actualName.GetBuffer(), &printerHandle, NULL ) ) + { + // Printer already exists, so we are done now... + goto exit; + } + + // Add the printer using the HTTP/IPP port... + portName.Format( TEXT( "%s://%s:%d/printers/%s" ), cupsLib.cupsEncryption() == HTTP_ENCRYPT_ALWAYS ? TEXT( "https" ) : TEXT( "http" ), service->hostname.GetBuffer(), service->portNumber, dest ); + + memset(&printerinfo, 0, sizeof(printerinfo)); + printerinfo.pPrinterName = printer->actualName.GetBuffer(); + printerinfo.pPortName = portName.GetBuffer(); + printerinfo.pDriverName = printer->actualName.GetBuffer(); + printerinfo.Attributes = PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL; + printerinfo.pComment = q->description.GetBuffer(); + printerinfo.pLocation = q->location.GetBuffer(); + printerinfo.pPrintProcessor = TEXT( "winprint" ); + + printerHandle = AddPrinter( NULL, 2, (LPBYTE) &printerinfo ); + err = translate_errno( printerHandle, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + +exit: + + if ( printerHandle != NULL ) + { + ClosePrinter( printerHandle ); + printerHandle = NULL; + } + + return err; +} + BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet, CPropertySheet) ON_MESSAGE( WM_SOCKET_EVENT, OnSocketEvent ) ON_MESSAGE( WM_PROCESS_EVENT, OnProcessEvent ) @@ -573,7 +744,7 @@ BOOL CPrinterSetupWizardSheet::OnCommand(WPARAM wParam, LPARAM lParam) BOOL CPrinterSetupWizardSheet::OnInitDialog() { OSStatus err; - + CPropertySheet::OnInitDialog(); err = StartBrowse(); @@ -596,12 +767,14 @@ exit: } else { - CPrinterSetupWizardSheet::WizardException exc; - - exc.text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT ); - exc.caption.LoadString( IDS_ERROR_CAPTION ); - - throw(exc); + CString text, caption; + + text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT ); + caption.LoadString( IDS_ERROR_CAPTION ); + + MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION); + + _exit( 0 ); } } @@ -653,18 +826,34 @@ CPrinterSetupWizardSheet::OnContextMenu(CWnd * pWnd, CPoint pos) void CPrinterSetupWizardSheet::OnOK() { + CWnd * window; + OSStatus err; + check ( m_selectedPrinter != NULL ); SetWizardButtons( PSWIZB_DISABLEDFINISH ); - if ( InstallPrinter( m_selectedPrinter ) != kNoErr ) + window = GetDlgItem( IDCANCEL ); + + if ( window ) + { + window->EnableWindow( FALSE ); + } + + m_pgFourth.StartActivityIndicator(); + + err = InstallPrinter( m_selectedPrinter ); + + m_pgFourth.StopActivityIndicator(); + + if ( err != kNoErr ) { CString caption; CString message; caption.LoadString(IDS_INSTALL_ERROR_CAPTION); + caption.AppendFormat( TEXT( " (%d)" ), err ); message.LoadString(IDS_INSTALL_ERROR_MESSAGE); - MessageBox(message, caption, MB_OK|MB_ICONEXCLAMATION); } @@ -676,7 +865,6 @@ CPrinterSetupWizardSheet::OnOK() void CPrinterSetupWizardSheet::Init(void) { - AddPage(&m_pgFirst); AddPage(&m_pgSecond); AddPage(&m_pgThird); AddPage(&m_pgFourth); @@ -693,7 +881,7 @@ void CPrinterSetupWizardSheet::Init(void) } -LONG +LRESULT CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam) { if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam))) @@ -726,7 +914,7 @@ CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam) } -LONG +LRESULT CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam) { DEBUG_UNUSED(inLParam); @@ -826,7 +1014,7 @@ CPrinterSetupWizardSheet::OnBrowse( OSStatus err = kNoErr; require_noerr( inErrorCode, exit ); - + self = reinterpret_cast ( inContext ); require_quiet( self, exit ); @@ -844,12 +1032,25 @@ CPrinterSetupWizardSheet::OnBrowse( if ( inFlags & kDNSServiceFlagsAdd ) { - if (printer == NULL) - { - // If not, then create a new one + BOOL newPrinter = FALSE; + if ( !printer ) + { printer = self->OnAddPrinter( inInterfaceIndex, inName, inType, inDomain, moreComing ); require_action( printer, exit, err = kUnknownErr ); + newPrinter = TRUE; + } + + // If we're looking at the browse list on page 2, then we need to call + // CPage2::OnAddPrinter() regardless of whether we've seen the printer + // or not because the moreComing flag might have changed from a previous + // call. If we only call CPage2::OnAddPrinter() when there's a new printer, + // we might not correctly update our UI, so if we've seen the printer before, + // call OnAddPrinter with a NULL parameter. + + if ( self->GetActivePage() == &self->m_pgSecond ) + { + self->m_pgSecond.OnAddPrinter( newPrinter ? printer : NULL, moreComing ); } if ( !service ) @@ -1102,6 +1303,7 @@ CPrinterSetupWizardSheet::OnAddPrinter( DEBUG_UNUSED( inInterfaceIndex ); DEBUG_UNUSED( inType ); DEBUG_UNUSED( inDomain ); + DEBUG_UNUSED( moreComing ); try { @@ -1159,11 +1361,6 @@ CPrinterSetupWizardSheet::OnAddPrinter( m_printers.push_back( printer ); - if ( GetActivePage() == &m_pgSecond ) - { - m_pgSecond.OnAddPrinter( printer, moreComing ); - } - exit: return printer; @@ -1661,7 +1858,7 @@ CPrinterSetupWizardSheet::ParseTextRecord( Service * service, Queue * q, uint16_ if ( TXTRecordContainsKey( inTXTSize, inTXT, "printer-state" ) || TXTRecordContainsKey( inTXTSize, inTXT, "printer-type" ) ) { - service->printer->isSharedFromOSX = true; + service->printer->isCUPSPrinter = true; } exit: