* 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: ThirdPage.cpp,v $
-Revision 1.37 2007/06/08 06:30:26 herscher
-<rdar://problem/5257700> Fix uninitialized pointers when detecting generic PCL and PS drivers
-
-Revision 1.36 2007/06/06 20:39:10 cheshire
-<rdar://problem/5254377> Printer Setup Wizard started crashing in Bonjour104A8, after update to Visual Studio 2005
-
-Revision 1.35 2007/06/06 20:08:01 cheshire
-<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
-AutoScroll model list as well as manufacturer list
-
-Revision 1.34 2007/06/06 19:53:48 cheshire
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.33 2007/04/20 22:58:10 herscher
-<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
-
-Revision 1.32 2007/04/13 23:42:20 herscher
-<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
-
-Revision 1.31 2007/04/13 21:38:46 herscher
-<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
-
-Revision 1.30 2007/04/13 20:23:40 herscher
-Fixed mistake in previous checkin that reverted license text for this file
-
-Revision 1.29 2007/04/13 18:10:24 herscher
-<rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
-
-Revision 1.28 2006/08/14 23:24:09 cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.27 2005/10/05 21:41:45 herscher
-<rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS shared queue supports raw
-
-Revision 1.26 2005/07/11 20:17:15 shersche
-<rdar://problem/4124524> UI fixes associated with CUPS printer workaround fix.
-
-Revision 1.25 2005/07/07 17:53:20 shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.24 2005/06/30 18:02:54 shersche
-<rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
-
-Revision 1.23 2005/04/18 02:33:47 shersche
-<rdar://problem/4091216> Default printer option cannot be deselected
-
-Revision 1.22 2005/04/13 17:46:22 shersche
-<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
-
-Revision 1.21 2005/03/30 02:09:55 shersche
-Auto-resize the column width to account for differing fonts and font sizes
-
-Revision 1.20 2005/03/05 02:27:45 shersche
-<rdar://problem/4030388> Generic drivers don't do color
-
-Revision 1.19 2005/02/23 02:08:51 shersche
-<rdar://problem/4012275> 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
-<rdar://problem/4003724> Display different UI text when generic printer drivers are selected
-
-Revision 1.17 2005/02/08 21:45:06 shersche
-<rdar://problem/3947490> 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
-<rdar://problem/3911084> 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
-<rdar://problem/3841218> 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
-<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.10 2004/10/11 22:55:34 shersche
-<rdar://problem/3827624> 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 <dns_sd.h>
-#include <tcpxcv.h>
#include <winspool.h>
+#include <setupapi.h>
// local variable is initialize but not referenced
#pragma warning(disable:4189)
#define kGenericPCLColorDriver L"HP Color LaserJet 4550 PCL"
#define kGenericPCLDriver L"HP LaserJet 4050 Series PCL"
-//
-// states for parsing ntprint.inf
-//
-enum PrinterParsingState
-{
- Looking,
- ParsingManufacturers,
- ParsingModels,
- ParsingStrings
-};
// CThirdPage dialog
return;
}
-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
//
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;
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 ) );
+ }
+ }
}
// --------------------------------------------------------
// ------------------------------------------------------
// 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
// checkForDuplicateModels flag. The problem here is that ntprint.inf
// doesn't contain duplicate models, and it has hundreds of models
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<CString, CString> 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)
- {
- continue;
- }
-
- //
- // check for tag
- //
- else 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 )
{
- //
- // 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))
- {
- //
- // check for comment
+ // Try to find some model section name that has entries. Explanation of int file structure
+ // can be found at:
//
- if (s.Find(';') == 0)
+ // <http://msdn.microsoft.com/en-us/library/ms794359.aspx>
+ 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
{
- CString name;
- int curPos;
-
- //
- // remove the leading and trailing delimiters
- //
- s.Remove('[');
- s.Remove(']');
-
- //
- // <rdar://problem/4826126>
- //
- // Ignore decorations in model declarations
- //
- curPos = 0;
- name = s.Tokenize( L".", curPos );
-
- //
- // check to see if this is a printer entry
- //
- iter = manufacturers.find( name );
-
- 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();
-
- //
- // why is there no consistency in inf files?
- //
- if (val.GetLength() == 0)
- {
- val = key;
- }
+ require_action( manufacturer, exit, err = kNoMemoryErr );
- //
- // fix the manufacturer name if necessary
- //
- curPos = 0;
- val = val.Tokenize(L",", curPos);
+ manufacturer->name = manufacturerName;
+ manufacturers[ manufacturerName ] = manufacturer;
+ }
- for ( ;; )
- {
- CString decoration;
-
- decoration = val.Tokenize( L",", curPos );
-
- if ( decoration.GetLength() > 0 )
- {
- manufacturer->decorations.push_back( decoration );
- }
- else
- {
- break;
- }
- }
+ 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;
- }
- }
-
- //
- // Stock Vista printer inf files embed guids in the model
- // declarations for Epson printers. Let's ignore those.
- //
- if ( name.Find( L"{", 0 ) != -1 )
+ if (checkForDuplicateModels == true)
+ {
+ if ( MatchModel( manufacturer, ConvertToModelName( modelName ) ) != NULL )
{
continue;
}
+ }
- try
- {
- model = new Model;
- }
- catch (...)
- {
- model = NULL;
- }
-
- 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;
}
+
// -------------------------------------------------------
// LoadPrintDriverDefs
//
useCUPSWorkaround = false;
}
- if ( useCUPSWorkaround && printer->isSharedFromOSX && hasGenericDriver )
+ if ( useCUPSWorkaround && printer->isCUPSPrinter && hasGenericDriver )
{
//
// <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
LoadGenericPrintDriverDefs( genericManufacturers );
SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
+
+ FreeManufacturers( genericManufacturers );
}
else
{
if (found)
{
text.LoadString(IDS_PRINTER_MATCH_GOOD);
+ err = kNoErr;
}
else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
{
- if ( printer->isSharedFromOSX )
+ if ( printer->isCUPSPrinter )
{
//
// <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
text.LoadString(IDS_PRINTER_MATCH_GOOD);
+
+ FreeManufacturers( genericManufacturers );
}
else
{
SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel );
text.LoadString(IDS_PRINTER_MATCH_MAYBE);
}
+
+ err = kNoErr;
}
else
{
AutoScroll(m_manufacturerListCtrl, nIndex);
}
}
+
+ err = kUnknownErr;
}
m_printerSelectionText.SetWindowText(text);
// and try and match the printer
//
- if ( psheet->GetLastPage() == psheet->GetPage(1) )
+ 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
{
{
PopulateUI( manufacturers );
- MatchPrinter( manufacturers, printer, service, false );
+ 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
{
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 );
+}