X-Git-Url: https://git.saurik.com/apple/mdnsresponder.git/blobdiff_plain/052924568ac81d9637dc4ae07e9de2887b7dc50c..2682e09e0dbe18ba42fd4707b09a89e8c34f697c:/Clients/PrinterSetupWizard/ThirdPage.cpp?ds=sidebyside diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp index acd8d3c..6caf55c 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.cpp +++ b/Clients/PrinterSetupWizard/ThirdPage.cpp @@ -1,122 +1,43 @@ -/* +/* -*- 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: ThirdPage.cpp,v $ -Revision 1.20 2005/03/05 02:27:45 shersche - Generic drivers don't do color - -Revision 1.19 2005/02/23 02:08:51 shersche - If we can't match the manufacturer, and select a generic printer, then show all the manufacturers in the manufacturer pane, not just "Generic". - -Revision 1.18 2005/02/15 07:02:51 shersche - Display different UI text when generic printer drivers are selected - -Revision 1.17 2005/02/08 21:45:06 shersche - Default to Generic PostScript or PCL if unable to match driver - -Revision 1.16 2005/02/08 18:56:03 shersche -Fix generated IPP url so that it doesn't add "/printers" string - -Revision 1.15 2005/02/01 01:44:07 shersche -Load ntprint.inf at startup. This will cause the wizard to take a second or two longer to come up, but will eliminate the pause when auto-selecting the print drivers. - -Revision 1.14 2005/01/25 08:55:54 shersche - Load icons at run-time from resource DLL -Bug #: 3911084 - -Revision 1.13 2005/01/06 08:15:45 shersche -Append queue name to end of LPR port name, correctly build port name when queue name is absent - -Revision 1.12 2005/01/05 01:06:12 shersche - Strip the first substring off the product key if an initial match can't be found with the whole product key. -Bug #: 3841218 - -Revision 1.11 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.10 2004/10/11 22:55:34 shersche - Use the IP port number when deriving the printer port name. -Bug #: 3827624 - -Revision 1.9 2004/06/27 23:08:00 shersche -code cleanup, make sure EnumPrintDrivers returns non-zero value, ignore comments in inf files - -Revision 1.8 2004/06/27 08:06:45 shersche -Parse [Strings] section of inf file - -Revision 1.7 2004/06/26 04:00:05 shersche -fix warnings compiling in debug mode -Submitted by: herscher - -Revision 1.6 2004/06/26 03:19:57 shersche -clean up warning messages - -Submitted by: herscher - -Revision 1.5 2004/06/25 05:06:02 shersche -Trim whitespace from key/value pairs when parsing inf files -Submitted by: herscher - -Revision 1.4 2004/06/25 02:44:13 shersche -Tweaked code to handle Xerox Phaser printer identification -Submitted by: herscher - -Revision 1.3 2004/06/25 02:27:58 shersche -Do a CListCtrl::FindItem() before calling CListCtrl::SetItemState(). -Submitted by: herscher - -Revision 1.2 2004/06/23 18:09:23 shersche -Normalize tag names when parsing inf files. -Submitted by: herscher - -Revision 1.1 2004/06/18 04:36:58 rpantos -First checked in - - -*/ + */ #include "stdafx.h" #include "PrinterSetupWizardApp.h" #include "PrinterSetupWizardSheet.h" #include "ThirdPage.h" -#include "StdioFileEx.h" +#include "tcpxcv.h" #include -#include #include +#include // local variable is initialize but not referenced #pragma warning(disable:4189) - // // This is the printer description file that is shipped -// with Windows +// with Windows XP and below // #define kNTPrintFile L"inf\\ntprint.inf" +// +// Windows Vista ships with a set of prn*.inf files +// +#define kVistaPrintFiles L"inf\\prn*.inf" + // // These are pre-defined names for Generic manufacturer and model // @@ -132,29 +53,24 @@ First checked in #define kGenericPCLDriver L"HP LaserJet 4050 Series PCL" -// -// states for parsing ntprint.inf -// -enum PrinterParsingState -{ - Looking, - ParsingManufacturers, - ParsingModels, - ParsingStrings -}; - - // CThirdPage dialog IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage) CThirdPage::CThirdPage() : CPropertyPage(CThirdPage::IDD), + m_manufacturerSelected( NULL ), + m_modelSelected( NULL ), + m_genericPostscript( NULL ), + m_genericPCL( NULL ), m_initialized(false), m_printerImage( NULL ) { static const int bufferSize = 32768; TCHAR windowsDirectory[bufferSize]; CString header; + WIN32_FIND_DATA findFileData; + HANDLE findHandle; + CString prnFiles; CString ntPrint; OSStatus err; BOOL ok; @@ -172,9 +88,38 @@ CThirdPage::CThirdPage() err = translate_errno( ok, errno_compat(), kUnknownErr ); require_noerr( err, exit ); - ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile); - err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false ); - require_noerr(err, exit); + // + // + // + // If there are no *prn.inf files, we'll assume that the information + // is in ntprint.inf + // + prnFiles.Format( L"%s\\%s", windowsDirectory, kVistaPrintFiles ); + findHandle = FindFirstFile( prnFiles, &findFileData ); + + if ( findHandle != INVALID_HANDLE_VALUE ) + { + CString absolute; + + absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName ); + err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false ); + require_noerr( err, exit ); + + while ( FindNextFile( findHandle, &findFileData ) ) + { + absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName ); + err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false ); + require_noerr( err, exit ); + } + + FindClose( findHandle ); + } + else + { + ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile); + err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false ); + require_noerr(err, exit); + } // // load printer drivers that have been installed on this machine @@ -183,7 +128,7 @@ CThirdPage::CThirdPage() require_noerr(err, exit); // - // and lastly load our own special generic printer defs + // load our own special generic printer defs // err = LoadGenericPrintDriverDefs( m_manufacturers ); require_noerr( err, exit ); @@ -194,44 +139,37 @@ exit: } -CThirdPage::~CThirdPage() +void +CThirdPage::FreeManufacturers( Manufacturers & manufacturers ) { - // - // clean up all the printer manufacturers - // - while (m_manufacturers.size()) + for ( Manufacturers::iterator it = manufacturers.begin(); it != manufacturers.end(); it++ ) { - Manufacturers::iterator iter = m_manufacturers.begin(); - - while (iter->second->models.size()) + for ( Models::iterator it2 = it->second->models.begin(); it2 != it->second->models.end(); it2++ ) { - Models::iterator it = iter->second->models.begin(); - - Model * model = *it; - - delete model; - - iter->second->models.erase(it); + delete *it2; } - delete iter->second; - - m_manufacturers.erase(iter); + delete it->second; } } +CThirdPage::~CThirdPage() +{ + FreeManufacturers( m_manufacturers ); +} + // ---------------------------------------------------- // SelectMatch // // SelectMatch will do all the UI work associated with // selected a manufacturer and model of printer. It also -// makes sure the printer object is update with the +// makes sure the printer object is update with the // latest settings // // ---------------------------------------------------- void -CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturers & manufacturers, Manufacturer * manufacturer, Model * model) +CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model) { LVFINDINFO info; int nIndex; @@ -240,8 +178,6 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturers & ma check( manufacturer != NULL ); check( model != NULL ); - PopulateUI( manufacturers ); - // // select the manufacturer // @@ -253,7 +189,10 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturers & ma if (nIndex != -1) { m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED); - m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE); + // + // mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + // + AutoScroll(m_manufacturerListCtrl, nIndex); } // @@ -267,7 +206,7 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturers & ma if (nIndex != -1) { m_modelListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED); - m_modelListCtrl.EnsureVisible(nIndex, FALSE); + AutoScroll( m_modelListCtrl, nIndex ); m_modelListCtrl.SetFocus(); } @@ -275,6 +214,13 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturers & ma CopyPrinterSettings( printer, service, manufacturer, model ); } +void +CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model) +{ + PopulateUI( manufacturers ); + + SelectMatch( printer, service, manufacturer, model ); +} // -------------------------------------------------------- // CopyPrinterSettings @@ -286,6 +232,8 @@ CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturers & ma void CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufacturer * manufacturer, Model * model ) { + DWORD portNameLen; + printer->manufacturer = manufacturer->name; printer->displayModelName = model->displayName; printer->modelName = model->name; @@ -329,31 +277,80 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu service->protocol = L"IPP"; } + + // If it's not an IPP printr, truncate the portName so that it's valid + + if ( service->type != kIPPServiceType ) + { + portNameLen = printer->portName.GetLength() + 1; + + if ( portNameLen > MAX_PORTNAME_LEN ) + { + printer->portName.Delete( MAX_PORTNAME_LEN - 1, ( portNameLen - MAX_PORTNAME_LEN ) ); + } + } } +// -------------------------------------------------------- +// DefaultPrinterExists +// +// Checks to see if a default printer has been configured +// on this machine +// -------------------------------------------------------- +BOOL +CThirdPage::DefaultPrinterExists() +{ + CPrintDialog dlg(FALSE); + + dlg.m_pd.Flags |= PD_RETURNDEFAULT; + + return dlg.GetDefaults(); +} + +// -------------------------------------------------------- +// AutoScroll +// +// Ensure selected item is in middle of list +// -------------------------------------------------------- +void +CThirdPage::AutoScroll( CListCtrl & list, int nIndex ) +{ + // + // mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + // + + int top; + int count; + + list.EnsureVisible( nIndex, FALSE ); + + top = list.GetTopIndex(); + count = list.GetCountPerPage(); + + if ( ( nIndex == top ) || ( ( nIndex + 1 ) == ( top + count ) ) ) + { + CRect rect; + int rows; + + rows = ( count / 2 ); + + if ( nIndex == top ) + { + list.GetItemRect(0, rect, LVIR_BOUNDS); + list.Scroll( CPoint( 0, rows * rect.Height() * -1 ) ); + } + else + { + list.GetItemRect(0, rect, LVIR_BOUNDS); + list.Scroll( CPoint( 0, rows * rect.Height() ) ); + } + } +} // ------------------------------------------------------ // LoadPrintDriverDefsFromFile // -// This function does all the heavy lifting in parsing inf -// files. It is called to parse both ntprint.inf, and driver -// files that might be shipped on a printer's installation -// disk -// -// The inf file is not totally parsed. I only want to determine -// the manufacturer and models that are involved. I leave it -// to printui.dll to actually copy the driver files to the -// right places. -// -// I was aiming to parse as little as I could so as not to -// duplicate the parsing code that is contained in Windows. There -// are no public APIs for parsing inf files. -// -// That part of the inf file that we're interested in has a fairly -// easy format. Tags are strings that are enclosed in brackets. -// We are only interested in [MANUFACTURERS] and models. -// -// The only potentially opaque thing about this function is the +// The only potentially opaque thing about this function is the // checkForDuplicateModels flag. The problem here is that ntprint.inf // doesn't contain duplicate models, and it has hundreds of models // listed. You wouldn't check for duplicates there. But oftentimes, @@ -365,305 +362,190 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu OSStatus CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels ) { - PrinterParsingState state = Looking; - Manufacturers::iterator iter = manufacturers.end(); - CStdioFileEx file; - CFileException feError; - CString s; - OSStatus err; - BOOL ok; - - typedef std::map StringMap; + HINF handle = INVALID_HANDLE_VALUE; + const TCHAR * section = TEXT( "Manufacturer" ); + LONG sectionCount; + TCHAR line[ 1000 ]; + CString klass; + INFCONTEXT manufacturerContext; + BOOL ok; + OSStatus err = 0; + + // Make sure we can open the file + handle = SetupOpenInfFile( filename, NULL, INF_STYLE_WIN4, NULL ); + translate_errno( handle != INVALID_HANDLE_VALUE, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - StringMap strings; - - ok = file.Open( filename, CFile::modeRead|CFile::typeText, &feError); - err = translate_errno( ok, errno_compat(), kUnknownErr ); + // Make sure it's a printer file + ok = SetupGetLineText( NULL, handle, TEXT( "Version" ), TEXT( "Class" ), line, sizeof( line ), NULL ); + translate_errno( ok, GetLastError(), kUnknownErr ); require_noerr( err, exit ); + klass = line; + require_action( klass == TEXT( "Printer" ), exit, err = kUnknownErr ); - check ( state == Looking ); - check ( iter == manufacturers.end() ); + sectionCount = SetupGetLineCount( handle, section ); + translate_errno( sectionCount != -1, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - // - // first, parse the file looking for string sections - // - while (file.ReadString(s)) + memset( &manufacturerContext, 0, sizeof( manufacturerContext ) ); + + for ( LONG i = 0; i < sectionCount; i++ ) { - // - // check for comment - // - if (s.Find(';') == 0) + Manufacturers::iterator iter; + Manufacturer * manufacturer; + CString manufacturerName; + CString temp; + CStringList modelSectionNameDecl; + CString modelSectionName; + CString baseModelName; + CString model; + INFCONTEXT modelContext; + LONG modelCount; + POSITION p; + + if ( i == 0 ) { - continue; - } - - // - // check for tag - // - else if (s.Find('[') == 0) - { - // - // handle any capitalization issues here - // - CString tag = s; - - tag.MakeLower(); - - if (tag == L"[strings]") - { - state = ParsingStrings; - } - else - { - state = Looking; - } + ok = SetupFindFirstLine( handle, section, NULL, &manufacturerContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } else { - switch (state) - { - case ParsingStrings: - { - int curPos = 0; - - if (s.GetLength() > 0) - { - CString key = s.Tokenize(L"=",curPos); - CString val = s.Tokenize(L"=",curPos); - - // - // get rid of all delimiters - // - key.Trim(); - val.Remove('"'); - - // - // and store it - // - strings[key] = val; - } - } - break; - } + ok = SetupFindNextLine( &manufacturerContext, &manufacturerContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } - } - - file.Close(); - ok = file.Open( filename, CFile::modeRead|CFile::typeText, &feError); - err = translate_errno( ok, errno_compat(), kUnknownErr ); - require_noerr( err, exit ); - - state = Looking; + ok = SetupGetStringField( &manufacturerContext, 0, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + manufacturerName = line; - check ( iter == manufacturers.end() ); + ok = SetupGetLineText( &manufacturerContext, handle, NULL, NULL, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - while (file.ReadString(s)) - { + // Try to find some model section name that has entries. Explanation of int file structure + // can be found at: // - // check for comment - // - if (s.Find(';') == 0) + // + Split( line, ',', modelSectionNameDecl ); + + p = modelSectionNameDecl.GetHeadPosition(); + modelSectionName = modelSectionNameDecl.GetNext( p ); + modelCount = SetupGetLineCount( handle, modelSectionName ); + baseModelName = modelSectionName; + + while ( modelCount <= 0 && p ) { - continue; + CString targetOSVersion; + + targetOSVersion = modelSectionNameDecl.GetNext( p ); + modelSectionName = baseModelName + TEXT( "." ) + targetOSVersion; + modelCount = SetupGetLineCount( handle, modelSectionName ); } - // - // check for tag - // - else if (s.Find('[') == 0) + if ( modelCount > 0 ) { - // - // handle any capitalization issues here - // - CString tag = s; + manufacturerName = NormalizeManufacturerName( manufacturerName ); - tag.MakeLower(); + iter = manufacturers.find( manufacturerName ); - if (tag == L"[manufacturer]") + if ( iter != manufacturers.end() ) { - state = ParsingManufacturers; + manufacturer = iter->second; + require_action( manufacturer, exit, err = kUnknownErr ); } else { - // remove the leading and trailing delimiters - // - s.Remove('['); - s.Remove(']'); - - // check to see if this is a printer entry - // - iter = manufacturers.find(s); - - if (iter != manufacturers.end()) + try { - state = ParsingModels; + manufacturer = new Manufacturer; } - else + catch (...) { - state = Looking; + manufacturer = NULL; } - } - } - // - // only look at this if the line isn't empty, or - // if it isn't a comment - // - else if ((s.GetLength() > 0) && (s.Find(';') != 0)) - { - switch (state) - { - // - // if we're parsing manufacturers, then we will parse - // an entry of the form key=val, where key is a delimited - // string specifying a manufacturer name, and val is - // a tag that is used later in the file. the key is - // delimited by either '"' (quotes) or '%' (percent sign). - // - // the tag is used further down the file when models are - // declared. this allows multiple manufacturers to exist - // in a single inf file. - // - case ParsingManufacturers: - { - Manufacturer * manufacturer; - int curPos = 0; - - CString key = s.Tokenize(L"=",curPos); - CString val = s.Tokenize(L"=",curPos); - - try - { - manufacturer = new Manufacturer; - } - catch (...) - { - manufacturer = NULL; - } - - require_action( manufacturer, exit, err = kNoMemoryErr ); - - // - // if it's a variable, look it up - // - if (key.Find('%') == 0) - { - StringMap::iterator it; - - key.Remove('%'); - - it = strings.find(key); - if (it != strings.end()) - { - key = it->second; - } - } - else - { - key.Remove('"'); - } - - val.TrimLeft(); - val.TrimRight(); + require_action( manufacturer, exit, err = kNoMemoryErr ); - // - // why is there no consistency in inf files? - // - if (val.GetLength() == 0) - { - val = key; - } + manufacturer->name = manufacturerName; + manufacturers[ manufacturerName ] = manufacturer; + } - // - // fix the manufacturer name if necessary - // - curPos = 0; - val = val.Tokenize(L",", curPos); + memset( &modelContext, 0, sizeof( modelContext ) ); - manufacturer->name = NormalizeManufacturerName( key ); - manufacturer->tag = val; + for ( LONG j = 0; j < modelCount; j++ ) + { + CString modelName; + Model * model; - manufacturers[val] = manufacturer; + if ( j == 0 ) + { + ok = SetupFindFirstLine( handle, modelSectionName, NULL, &modelContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); } - break; - - case ParsingModels: + else { - check( iter != manufacturers.end() ); - - Model * model; - int curPos = 0; - - CString name = s.Tokenize(L"=",curPos); - CString description = s.Tokenize(L"=",curPos); - - if (name.Find('%') == 0) - { - StringMap::iterator it; - - name.Remove('%'); + SetupFindNextLine( &modelContext, &modelContext ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); + } - it = strings.find(name); + ok = SetupGetStringField( &modelContext, 0, line, sizeof( line ), NULL ); + err = translate_errno( ok, GetLastError(), kUnknownErr ); + require_noerr( err, exit ); - if (it != strings.end()) - { - name = it->second; - } - } - else - { - name.Remove('"'); - } + modelName = line; - name.Trim(); - description.Trim(); - - // - // If true, see if we've seen this guy before - // - if (checkForDuplicateModels == true) - { - if ( MatchModel( iter->second, ConvertToModelName( name ) ) != NULL ) - { - continue; - } - } - - try - { - model = new Model; - } - catch (...) + if (checkForDuplicateModels == true) + { + if ( MatchModel( manufacturer, ConvertToModelName( modelName ) ) != NULL ) { - model = NULL; + continue; } + } - require_action( model, exit, err = kNoMemoryErr ); - - model->infFileName = filename; - model->displayName = name; - model->name = name; - model->driverInstalled = false; - - iter->second->models.push_back(model); + // + // Stock Vista printer inf files embed guids in the model + // declarations for Epson printers. Let's ignore those. + // + if ( modelName.Find( TEXT( "{" ), 0 ) != -1 ) + { + continue; } - break; - default: + try { - // pay no attention if we are in any other state + model = new Model; } - break; + catch (...) + { + model = NULL; + } + + require_action( model, exit, err = kNoMemoryErr ); + + model->infFileName = filename; + model->displayName = modelName; + model->name = modelName; + model->driverInstalled = false; + + manufacturer->models.push_back(model); } } } exit: - file.Close(); + if ( handle != INVALID_HANDLE_VALUE ) + { + SetupCloseInfFile( handle ); + handle = NULL; + } - return (err); + return err; } @@ -719,7 +601,7 @@ CThirdPage::LoadPrintDriverDefs( Manufacturers & manufacturers ) // // skip over anything that doesn't have a manufacturer field. This - // fixes a bug that I noticed that occurred after I installed + // fixes a bug that I noticed that occurred after I installed // ProComm. This program add a print driver with no manufacturer // that screwed up this wizard. // @@ -801,7 +683,6 @@ exit: return err; } - // ------------------------------------------------------- // LoadGenericPrintDriverDefs // @@ -824,11 +705,11 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers ) // First try and find our generic driver names - iter = manufacturers.find(L"HP"); - require_action( iter != manufacturers.end(), exit, err = kUnknownErr ); + iter = m_manufacturers.find(L"HP"); + require_action( iter != m_manufacturers.end(), exit, err = kUnknownErr ); manufacturer = iter->second; - // Look for Postscript + // Look for Postscript model = manufacturer->find( kGenericPSColorDriver ); @@ -840,7 +721,6 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers ) if ( model ) { psDriverName = model->name; - } // Look for PCL @@ -854,7 +734,7 @@ CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers ) if ( model ) { - pclDriverName = model->name; + pclDriverName = model->name; } // If we found either a generic PS driver, or a generic PCL driver, @@ -936,7 +816,7 @@ exit: // ------------------------------------------------------ // ConvertToManufacturerName // -// This function is responsible for tweaking the +// This function is responsible for tweaking the // name so that subsequent string operations won't fail because // of capitalizations/different names for the same manufacturer // (i.e. Hewlett-Packard/HP/Hewlett Packard) @@ -973,7 +853,6 @@ CThirdPage::ConvertToManufacturerName( const CString & name ) return lower; } - // ------------------------------------------------------ // ConvertToModelName // @@ -994,7 +873,6 @@ CThirdPage::ConvertToModelName( const CString & name ) return lower; } - // ------------------------------------------------------ // NormalizeManufacturerName // @@ -1019,7 +897,6 @@ CThirdPage::NormalizeManufacturerName( const CString & name ) return normalized; } - // ------------------------------------------------------- // MatchPrinter // @@ -1028,7 +905,7 @@ CThirdPage::NormalizeManufacturerName( const CString & name ) // MatchManufacturer and MatchModel in turn. // -OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * printer, Service * service) +OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * printer, Service * service, bool useCUPSWorkaround) { CString normalizedProductName; Manufacturer * manufacturer = NULL; @@ -1039,20 +916,27 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print CString text; OSStatus err = kNoErr; + check( printer ); + check( service ); + + Queue * q = service->SelectedQueue(); + + check( q ); + // // first look to see if we have a usb_MFG descriptor // - if (service->usb_MFG.GetLength() > 0) + if ( q->usb_MFG.GetLength() > 0) { - manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( service->usb_MFG ) ); + manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( q->usb_MFG ) ); } if ( manufacturer == NULL ) { - service->product.Remove('('); - service->product.Remove(')'); + q->product.Remove('('); + q->product.Remove(')'); - manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( service->product ) ); + manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( q->product ) ); } // @@ -1060,25 +944,57 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print // if ( manufacturer != NULL ) { - if (service->usb_MDL.GetLength() > 0) + if ( q->usb_MDL.GetLength() > 0 ) { - model = MatchModel ( manufacturer, ConvertToModelName ( service->usb_MDL ) ); + model = MatchModel ( manufacturer, ConvertToModelName ( q->usb_MDL ) ); } - if ( ( model == NULL ) && ( service->product.GetLength() > 0 ) ) + if ( ( model == NULL ) && ( q->product.GetLength() > 0 ) ) { - service->product.Remove('('); - service->product.Remove(')'); + q->product.Remove('('); + q->product.Remove(')'); - model = MatchModel ( manufacturer, ConvertToModelName ( service->product ) ); + model = MatchModel ( manufacturer, ConvertToModelName ( q->product ) ); } if ( model != NULL ) { - Manufacturers manufacturers; - - manufacturers[manufacturer->name] = manufacturer; - SelectMatch(printer, service, manufacturers, manufacturer, model); + // Offer Generic printers if printer advertises Postscript or PCL. Workaround + // bug in OS X CUPS printer sharing by selecting Generic driver instead of matched printer. + + bool hasGenericDriver = false; + + if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) ) + { + hasGenericDriver = true; + } + + // Use "application/octet-stream" to determine if CUPS + // shared queue supports raw + + if ( q->pdl.Find( L"application/octet-stream" ) != -1 ) + { + useCUPSWorkaround = false; + } + + if ( useCUPSWorkaround && printer->isCUPSPrinter && hasGenericDriver ) + { + // + // mDNS: Don't allow user to choose non-working driver + // + Manufacturers genericManufacturers; + + LoadGenericPrintDriverDefs( genericManufacturers ); + + SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel ); + + FreeManufacturers( genericManufacturers ); + } + else + { + SelectMatch(manufacturers, printer, service, manufacturer, model); + } + found = true; } } @@ -1090,27 +1006,32 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print if (found) { text.LoadString(IDS_PRINTER_MATCH_GOOD); + err = kNoErr; } - else if ( MatchGeneric( printer, service, &genericManufacturer, &genericModel ) ) + else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) ) { - Manufacturers * pManufacturers; - Manufacturers manufacturers; - - text.LoadString(IDS_PRINTER_MATCH_MAYBE); - - if ( manufacturer ) + if ( printer->isCUPSPrinter ) { - manufacturers[genericManufacturer->name] = genericManufacturer; - manufacturers[manufacturer->name] = manufacturer; + // + // mDNS: Don't allow user to choose non-working driver + // + Manufacturers genericManufacturers; - pManufacturers = &manufacturers; + LoadGenericPrintDriverDefs( genericManufacturers ); + + SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel ); + + text.LoadString(IDS_PRINTER_MATCH_GOOD); + + FreeManufacturers( genericManufacturers ); } else { - pManufacturers = &m_manufacturers; + SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel ); + text.LoadString(IDS_PRINTER_MATCH_MAYBE); } - SelectMatch( printer, service, *pManufacturers, genericManufacturer, genericModel ); + err = kNoErr; } else { @@ -1140,9 +1061,15 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print if (nIndex != -1) { m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED); - m_manufacturerListCtrl.EnsureVisible(nIndex, FALSE); + + // + // mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle + // + AutoScroll(m_manufacturerListCtrl, nIndex); } } + + err = kUnknownErr; } m_printerSelectionText.SetWindowText(text); @@ -1150,7 +1077,6 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print return err; } - // ------------------------------------------------------ // MatchManufacturer // @@ -1187,7 +1113,6 @@ CThirdPage::MatchManufacturer( Manufacturers & manufacturers, const CString & na return NULL; } - // ------------------------------------------------------- // MatchModel // @@ -1238,7 +1163,6 @@ CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name) return NULL; } - // ------------------------------------------------------- // MatchGeneric // @@ -1247,27 +1171,33 @@ CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name) // specifically // BOOL -CThirdPage::MatchGeneric( Printer * printer, Service * service, Manufacturer ** manufacturer, Model ** model ) +CThirdPage::MatchGeneric( Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer ** manufacturer, Model ** model ) { CString pdl; BOOL ok = FALSE; DEBUG_UNUSED( printer ); - Manufacturers::iterator iter = m_manufacturers.find( kGenericManufacturer ); - require_action_quiet( iter != m_manufacturers.end(), exit, ok = FALSE ); + check( service ); + + Queue * q = service->SelectedQueue(); + + check( q ); + + Manufacturers::iterator iter = manufacturers.find( kGenericManufacturer ); + require_action_quiet( iter != manufacturers.end(), exit, ok = FALSE ); *manufacturer = iter->second; - pdl = service->pdl; + pdl = q->pdl; pdl.MakeLower(); - if ( pdl.Find( kPDLPCLKey ) != -1 ) + if ( m_genericPCL && ( pdl.Find( kPDLPCLKey ) != -1 ) ) { *model = m_genericPCL; ok = TRUE; } - else if ( pdl.Find( kPDLPostscriptKey ) != -1 ) + else if ( m_genericPostscript && ( pdl.Find( kPDLPostscriptKey ) != -1 ) ) { *model = m_genericPostscript; ok = TRUE; @@ -1278,7 +1208,6 @@ exit: return ok; } - // ----------------------------------------------------------- // OnInitPage // @@ -1293,12 +1222,9 @@ OSStatus CThirdPage::OnInitPage() OSStatus err = kNoErr; // Load printer icon - - - check( m_printerImage == NULL ); - m_printerImage = (CStatic*) GetDlgItem( IDR_MANIFEST ); + m_printerImage = (CStatic*) GetDlgItem( 1 ); // 1 == IDR_MANIFEST check( m_printerImage ); if ( m_printerImage != NULL ) @@ -1316,24 +1242,23 @@ OSStatus CThirdPage::OnInitPage() // // - // we have to make sure that we only do this once. Typically, + // we have to make sure that we only do this once. Typically, // we would do this in something like OnInitDialog, but we don't // have this in Wizards, because the window is a PropertySheet. // We're considered fully initialized when we receive the first // selection notice // header.LoadString(IDS_MANUFACTURER_HEADING); - m_manufacturerListCtrl.InsertColumn(0, header, LVCFMT_LEFT, 138); + m_manufacturerListCtrl.InsertColumn(0, header, LVCFMT_LEFT, -1 ); m_manufacturerSelected = NULL; header.LoadString(IDS_MODEL_HEADING); - m_modelListCtrl.InsertColumn(0, header, LVCFMT_LEFT, 247); + m_modelListCtrl.InsertColumn(0, header, LVCFMT_LEFT, -1 ); m_modelSelected = NULL; return (err); } - void CThirdPage::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); @@ -1345,7 +1270,6 @@ void CThirdPage::DoDataExchange(CDataExchange* pDX) } - // ---------------------------------------------------------- // OnSetActive // @@ -1363,15 +1287,7 @@ CThirdPage::OnSetActive() psheet = reinterpret_cast(GetParent()); require_quiet( psheet, exit ); - if ((m_manufacturerListCtrl.GetFirstSelectedItemPosition() != NULL) && - (m_modelListCtrl.GetFirstSelectedItemPosition() != NULL)) - { - psheet->SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT ); - } - else - { - psheet->SetWizardButtons( PSWIZB_BACK ); - } + psheet->SetWizardButtons( PSWIZB_BACK ); printer = psheet->GetSelectedPrinter(); require_quiet( printer, exit ); @@ -1388,6 +1304,20 @@ CThirdPage::OnSetActive() m_initialized = true; } + // + // mDNS: Printers added using Bonjour should be set as the default printer. + // + if ( DefaultPrinterExists() ) + { + m_defaultPrinterCtrl.SetCheck( BST_UNCHECKED ); + printer->deflt = false; + } + else + { + m_defaultPrinterCtrl.SetCheck( BST_CHECKED ); + printer->deflt = true; + } + // // update the UI with the printer name // @@ -1402,13 +1332,40 @@ CThirdPage::OnSetActive() // // and try and match the printer // - MatchPrinter( m_manufacturers, printer, service ); + + if ( psheet->GetLastPage() == psheet->GetPage(0) ) + { + MatchPrinter( m_manufacturers, printer, service, true ); + + if ( ( m_manufacturerSelected != NULL ) && ( m_modelSelected != NULL ) ) + { + GetParent()->PostMessage(PSM_SETCURSEL, 2 ); + } + } + else + { + SelectMatch(printer, service, m_manufacturerSelected, m_modelSelected); + } exit: return CPropertyPage::OnSetActive(); } +BOOL +CThirdPage::OnKillActive() +{ + CPrinterSetupWizardSheet * psheet; + + psheet = reinterpret_cast(GetParent()); + require_quiet( psheet, exit ); + + psheet->SetLastPage(this); + +exit: + + return CPropertyPage::OnKillActive(); +} // ------------------------------------------------------- // PopulateUI @@ -1431,12 +1388,13 @@ CThirdPage::PopulateUI(Manufacturers & manufacturers) nIndex = m_manufacturerListCtrl.InsertItem(0, manufacturer->name); m_manufacturerListCtrl.SetItemData(nIndex, (DWORD_PTR) manufacturer); + + m_manufacturerListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE_USEHEADER ); } return 0; } - BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage) ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MANUFACTURER, OnLvnItemchangedManufacturer) ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MODEL, OnLvnItemchangedPrinterModel) @@ -1444,7 +1402,6 @@ BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage) ON_BN_CLICKED(IDC_HAVE_DISK, OnBnClickedHaveDisk) END_MESSAGE_MAP() - // CThirdPage message handlers void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult) { @@ -1471,6 +1428,8 @@ void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult) int nItem = m_modelListCtrl.InsertItem( 0, model->displayName ); m_modelListCtrl.SetItemData(nItem, (DWORD_PTR) model); + + m_modelListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE_USEHEADER ); } m_modelListCtrl.SetRedraw(TRUE); @@ -1519,7 +1478,6 @@ exit: *pResult = 0; } - void CThirdPage::OnBnClickedDefaultPrinter() { CPrinterSetupWizardSheet * psheet; @@ -1531,7 +1489,7 @@ void CThirdPage::OnBnClickedDefaultPrinter() printer = psheet->GetSelectedPrinter(); require_quiet( printer, exit ); - printer->deflt = m_defaultPrinterCtrl.GetState() ? true : false; + printer->deflt = ( m_defaultPrinterCtrl.GetCheck() == BST_CHECKED ) ? true : false; exit: @@ -1543,6 +1501,7 @@ void CThirdPage::OnBnClickedHaveDisk() CPrinterSetupWizardSheet * psheet; Printer * printer; Service * service; + Manufacturers manufacturers; CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, L"Setup Information (*.inf)|*.inf||", this); @@ -1555,19 +1514,70 @@ void CThirdPage::OnBnClickedHaveDisk() service = printer->services.front(); require_quiet( service, exit ); - if ( dlg.DoModal() == IDOK ) + for ( ;; ) { - Manufacturers manufacturers; - CString filename = dlg.GetPathName(); + if ( dlg.DoModal() == IDOK ) + { + CString filename = dlg.GetPathName(); - LoadPrintDriverDefsFromFile( manufacturers, filename, true ); + LoadPrintDriverDefsFromFile( manufacturers, filename, true ); - PopulateUI( manufacturers ); + // Sanity check - MatchPrinter( manufacturers, printer, service ); + if ( manufacturers.size() > 0 ) + { + PopulateUI( manufacturers ); + + if ( MatchPrinter( manufacturers, printer, service, false ) != kNoErr ) + { + CString errorMessage; + CString errorCaption; + + errorMessage.LoadString( IDS_NO_MATCH_INF_FILE ); + errorCaption.LoadString( IDS_NO_MATCH_INF_FILE_CAPTION ); + + MessageBox( errorMessage, errorCaption, MB_OK ); + } + + break; + } + else + { + CString errorMessage; + CString errorCaption; + + errorMessage.LoadString( IDS_BAD_INF_FILE ); + errorCaption.LoadString( IDS_BAD_INF_FILE_CAPTION ); + + MessageBox( errorMessage, errorCaption, MB_OK ); + } + } + else + { + break; + } } exit: + FreeManufacturers( manufacturers ); return; } + + +void +CThirdPage::Split( const CString & string, TCHAR ch, CStringList & components ) +{ + CString temp; + int n; + + temp = string; + + while ( ( n = temp.Find( ch ) ) != -1 ) + { + components.AddTail( temp.Left( n ) ); + temp = temp.Right( temp.GetLength() - ( n + 1 ) ); + } + + components.AddTail( temp ); +}