-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_LICENSE_HEADER_START@
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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.
- *
- * @APPLE_LICENSE_HEADER_END@
-
- Change History (most recent first):
-
-$Log: PrinterSetupWizardSheet.cpp,v $
-Revision 1.30 2005/04/13 17:46:22 shersche
-<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
-
-Revision 1.29 2005/02/14 20:48:37 shersche
-<rdar://problem/4003710> Default pdl key to "application/postscript"
-
-Revision 1.28 2005/02/14 20:37:53 shersche
-<rdar://problem/4003944> Populate comment field with the model name that users see in the wizard UI.
-
-Revision 1.27 2005/02/09 05:04:03 shersche
-<rdar://problem/3946587> Use TXTRecordGetValuePtr() API in ParseTextRecord
-
-Revision 1.26 2005/02/08 21:45:06 shersche
-<rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
-
-Revision 1.25 2005/02/08 18:54:17 shersche
-<rdar://problem/3987680> Default queue name is "lp" when rp key is not specified.
-
-Revision 1.24 2005/02/01 02:15:55 shersche
-<rdar://problem/3946587> Use TXTRecord parsing APIs in ParseTextRecord
-
-Revision 1.23 2005/01/31 23:54:30 shersche
-<rdar://problem/3947508> 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
-<rdar://problem/3725106>
-<rdar://problem/3737413> 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
-<rdar://problem/3764873> Escape '/', '@', '"' characters in printui command.
-Bug #: 3764873
-
-Revision 1.16 2004/09/13 21:27:22 shersche
-<rdar://problem/3796483> Pass the moreComing flag to OnAddPrinter and OnRemovePrinter callbacks
-Bug #: 3796483
-
-Revision 1.15 2004/09/11 05:59:06 shersche
-<rdar://problem/3785766> Fix code that generates unique printer names based on currently installed printers
-Bug #: 3785766
-
-Revision 1.14 2004/09/02 01:57:58 cheshire
-<rdar://problem/3783611> Fix incorrect testing of MoreComing flag
-
-Revision 1.13 2004/07/26 21:06:29 shersche
-<rdar://problem/3739200> Removing trailing '.' in hostname
-Bug #: 3739200
-
-Revision 1.12 2004/07/13 21:24:23 rpantos
-Fix for <rdar://problem/3701120>.
-
-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
-<rdar://problem/3701837> eliminated memory leaks on exit
-<rdar://problem/3701926> 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"
#include "DebugServices.h"
#include "WinServices.h"
#include "About.h"
+#include "tcpxcv.h"
#include <winspool.h>
-#include <tcpxcv.h>
#include <string>
+#include <shlwapi.h>
// unreachable code
#pragma warning(disable:4702)
# include <process.h>
#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;
m_driverThreadFinished( false ),
m_pdlBrowser( NULL ),
m_ippBrowser( NULL ),
- m_lprBrowser( NULL )
+ m_lprBrowser( NULL ),
+ m_lastPage( NULL )
{
m_arrow = LoadCursor(0, IDC_ARROW);
m_wait = LoadCursor(0, IDC_APPSTARTING);
{
PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));
- m_printerNames[lppi4->pPrinterName] = lppi4->pPrinterName;
+ m_printerNames.push_back( lppi4->pPrinterName );
}
}
//
// 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
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;
{
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:
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
//
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
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:
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 );
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:
}
+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 )
BOOL CPrinterSetupWizardSheet::OnInitDialog()
{
OSStatus err;
-
+
CPropertySheet::OnInitDialog();
err = StartBrowse();
}
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 );
}
}
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);
}
void CPrinterSetupWizardSheet::Init(void)
{
- AddPage(&m_pgFirst);
AddPage(&m_pgSecond);
AddPage(&m_pgThird);
AddPage(&m_pgFourth);
}
-LONG
+LRESULT
CPrinterSetupWizardSheet::OnSocketEvent(WPARAM inWParam, LPARAM inLParam)
{
if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
}
-LONG
+LRESULT
CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam)
{
DEBUG_UNUSED(inLParam);
OSStatus err = kNoErr;
require_noerr( inErrorCode, exit );
-
+
self = reinterpret_cast <CPrinterSetupWizardSheet*>( inContext );
require_quiet( self, exit );
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 )
DEBUG_UNUSED( inInterfaceIndex );
DEBUG_UNUSED( inType );
DEBUG_UNUSED( inDomain );
+ DEBUG_UNUSED( moreComing );
try
{
for (;;)
{
- CPrinterSetupWizardSheet::PrinterNameMap::iterator it;
+ CPrinterSetupWizardSheet::PrinterNames::iterator it;
+
+ // <rdar://problem/4141221> Don't use find to do comparisons because we need to
+ // do a case insensitive string comparison
- it = m_printerNames.find(printer->actualName);
+ for ( it = m_printerNames.begin(); it != m_printerNames.end(); it++ )
+ {
+ if ( (*it).CompareNoCase( printer->actualName ) == 0 )
+ {
+ break;
+ }
+ }
if (it != m_printerNames.end())
{
m_printers.push_back( printer );
- if ( GetActivePage() == &m_pgSecond )
- {
- m_pgSecond.OnAddPrinter( printer, moreComing );
- }
-
exit:
return printer;
{
// Make sure that the active page is page 2
- check( GetActivePage() == &m_pgSecond );
+ require_quiet( GetActivePage() == &m_pgSecond, exit );
if ( !--service->printer->resolving )
{
m_pgSecond.OnResolveService( service );
}
+
+exit:
+
+ return;
}
q->priority = atoi( buf );
}
+ // <rdar://problem/4124524> Was this printer discovered via OS X Printer Sharing?
+
+ if ( TXTRecordContainsKey( inTXTSize, inTXT, "printer-state" ) || TXTRecordContainsKey( inTXTSize, inTXT, "printer-type" ) )
+ {
+ service->printer->isCUPSPrinter = true;
+ }
+
exit:
// The following code is to fix a problem with older HP