2 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: ThirdPage.cpp,v $
26 Revision 1.14 2005/01/25 08:55:54 shersche
27 <rdar://problem/3911084> Load icons at run-time from resource DLL
30 Revision 1.13 2005/01/06 08:15:45 shersche
31 Append queue name to end of LPR port name, correctly build port name when queue name is absent
33 Revision 1.12 2005/01/05 01:06:12 shersche
34 <rdar://problem/3841218> Strip the first substring off the product key if an initial match can't be found with the whole product key.
37 Revision 1.11 2004/12/29 18:53:38 shersche
38 <rdar://problem/3725106>
39 <rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
40 Bug #: 3725106, 3737413
42 Revision 1.10 2004/10/11 22:55:34 shersche
43 <rdar://problem/3827624> Use the IP port number when deriving the printer port name.
46 Revision 1.9 2004/06/27 23:08:00 shersche
47 code cleanup, make sure EnumPrintDrivers returns non-zero value, ignore comments in inf files
49 Revision 1.8 2004/06/27 08:06:45 shersche
50 Parse [Strings] section of inf file
52 Revision 1.7 2004/06/26 04:00:05 shersche
53 fix warnings compiling in debug mode
54 Submitted by: herscher
56 Revision 1.6 2004/06/26 03:19:57 shersche
57 clean up warning messages
59 Submitted by: herscher
61 Revision 1.5 2004/06/25 05:06:02 shersche
62 Trim whitespace from key/value pairs when parsing inf files
63 Submitted by: herscher
65 Revision 1.4 2004/06/25 02:44:13 shersche
66 Tweaked code to handle Xerox Phaser printer identification
67 Submitted by: herscher
69 Revision 1.3 2004/06/25 02:27:58 shersche
70 Do a CListCtrl::FindItem() before calling CListCtrl::SetItemState().
71 Submitted by: herscher
73 Revision 1.2 2004/06/23 18:09:23 shersche
74 Normalize tag names when parsing inf files.
75 Submitted by: herscher
77 Revision 1.1 2004/06/18 04:36:58 rpantos
84 #include "PrinterSetupWizardApp.h"
85 #include "PrinterSetupWizardSheet.h"
86 #include "ThirdPage.h"
87 #include "StdioFileEx.h"
92 // local variable is initialize but not referenced
93 #pragma warning(disable:4189)
97 // This is the printer description file that is shipped
100 #define kNTPrintFile L"inf\\ntprint.inf"
103 // These are pre-defined names for Generic manufacturer and model
105 #define kGenericManufacturer L"Generic"
106 #define kGenericModel L"Generic / Text Only"
109 // states for parsing ntprint.inf
111 enum PrinterParsingState
114 ParsingManufacturers
,
122 IMPLEMENT_DYNAMIC(CThirdPage
, CPropertyPage
)
123 CThirdPage::CThirdPage()
124 : CPropertyPage(CThirdPage::IDD
),
125 m_initialized(false),
126 m_printerImage( NULL
)
128 m_psp
.dwFlags
&= ~(PSP_HASHELP
);
129 m_psp
.dwFlags
|= PSP_DEFAULT
|PSP_USEHEADERTITLE
|PSP_USEHEADERSUBTITLE
;
131 m_psp
.pszHeaderTitle
= MAKEINTRESOURCE(IDS_INSTALL_TITLE
);
132 m_psp
.pszHeaderSubTitle
= MAKEINTRESOURCE(IDS_INSTALL_SUBTITLE
);
136 CThirdPage::~CThirdPage()
139 // clean up all the printer manufacturers
141 while (m_manufacturers
.size())
143 Manufacturers::iterator iter
= m_manufacturers
.begin();
145 while (iter
->second
->models
.size())
147 Models::iterator it
= iter
->second
->models
.begin();
153 iter
->second
->models
.erase(it
);
158 m_manufacturers
.erase(iter
);
163 // ----------------------------------------------------
166 // SelectMatch will do all the UI work associated with
167 // selected a manufacturer and model of printer. It also
168 // makes sure the printer object is update with the
171 // ----------------------------------------------------
173 CThirdPage::SelectMatch(Printer
* printer
, Service
* service
, Manufacturer
* manufacturer
, Model
* model
)
178 check( printer
!= NULL
);
179 check( manufacturer
!= NULL
);
180 check( model
!= NULL
);
182 Manufacturers manufacturers
;
183 manufacturers
[manufacturer
->name
] = manufacturer
;
185 PopulateUI( manufacturers
);
188 // select the manufacturer
190 info
.flags
= LVFI_STRING
;
191 info
.psz
= manufacturer
->name
;
193 nIndex
= m_manufacturerListCtrl
.FindItem(&info
);
197 m_manufacturerListCtrl
.SetItemState(nIndex
, LVIS_SELECTED
, LVIS_SELECTED
);
198 m_manufacturerListCtrl
.EnsureVisible(nIndex
, FALSE
);
204 info
.flags
= LVFI_STRING
;
205 info
.psz
= model
->name
;
207 nIndex
= m_modelListCtrl
.FindItem(&info
);
211 m_modelListCtrl
.SetItemState(nIndex
, LVIS_SELECTED
, LVIS_SELECTED
);
212 m_modelListCtrl
.EnsureVisible(nIndex
, FALSE
);
214 m_modelListCtrl
.SetFocus();
217 CopyPrinterSettings( printer
, service
, manufacturer
, model
);
221 // --------------------------------------------------------
222 // CopyPrinterSettings
224 // This function makes sure that the printer object has the
225 // latest settings from the manufacturer and model objects
226 // --------------------------------------------------------
229 CThirdPage::CopyPrinterSettings( Printer
* printer
, Service
* service
, Manufacturer
* manufacturer
, Model
* model
)
231 printer
->manufacturer
= manufacturer
->name
;
232 printer
->model
= model
->name
;
233 printer
->driverInstalled
= model
->driverInstalled
;
234 printer
->infFileName
= model
->infFileName
;
236 if ( service
->type
== kPDLServiceType
)
238 printer
->portName
.Format(L
"IP_%s.%d", static_cast<LPCTSTR
>(service
->hostname
), service
->portNumber
);
239 service
->protocol
= L
"Raw";
241 else if ( service
->type
== kLPRServiceType
)
243 Queue
* q
= service
->queues
.front();
246 if ( q
->name
.GetLength() > 0 )
248 printer
->portName
.Format(L
"LPR_%s.%d.%s", static_cast<LPCTSTR
>(service
->hostname
), service
->portNumber
, static_cast<LPCTSTR
>(q
->name
) );
252 printer
->portName
.Format(L
"LPR_%s.%d", static_cast<LPCTSTR
>(service
->hostname
), service
->portNumber
);
255 service
->protocol
= L
"LPR";
257 else if ( service
->type
== kIPPServiceType
)
259 Queue
* q
= service
->queues
.front();
262 if ( q
->name
.GetLength() > 0 )
264 printer
->portName
.Format(L
"http://%s:%d/printers/%s", static_cast<LPCTSTR
>(service
->hostname
), service
->portNumber
, static_cast<LPCTSTR
>(q
->name
) );
268 printer
->portName
.Format(L
"http://%s:%d/", static_cast<LPCTSTR
>(service
->hostname
), service
->portNumber
);
271 service
->protocol
= L
"IPP";
276 // ------------------------------------------------------
277 // LoadPrintDriverDefsFromFile
279 // This function does all the heavy lifting in parsing inf
280 // files. It is called to parse both ntprint.inf, and driver
281 // files that might be shipped on a printer's installation
284 // The inf file is not totally parsed. I only want to determine
285 // the manufacturer and models that are involved. I leave it
286 // to printui.dll to actually copy the driver files to the
289 // I was aiming to parse as little as I could so as not to
290 // duplicate the parsing code that is contained in Windows. There
291 // are no public APIs for parsing inf files.
293 // That part of the inf file that we're interested in has a fairly
294 // easy format. Tags are strings that are enclosed in brackets.
295 // We are only interested in [MANUFACTURERS] and models.
297 // The only potentially opaque thing about this function is the
298 // checkForDuplicateModels flag. The problem here is that ntprint.inf
299 // doesn't contain duplicate models, and it has hundreds of models
300 // listed. You wouldn't check for duplicates there. But oftentimes,
301 // loading different windows print driver files contain multiple
302 // entries for the same printer. You don't want the UI to display
303 // the same printer multiple times, so in that case, you would ask
304 // this function to check for multiple models.
307 CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers
& manufacturers
, const CString
& filename
, bool checkForDuplicateModels
)
309 PrinterParsingState state
= Looking
;
310 Manufacturers::iterator iter
= manufacturers
.end();
312 CFileException feError
;
317 typedef std::map
<CString
, CString
> StringMap
;
321 ok
= file
.Open( filename
, CFile::modeRead
|CFile::typeText
, &feError
);
322 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
323 require_noerr( err
, exit
);
325 check ( state
== Looking
);
326 check ( iter
== manufacturers
.end() );
329 // first, parse the file looking for string sections
331 while (file
.ReadString(s
))
336 if (s
.Find(';') == 0)
344 else if (s
.Find('[') == 0)
347 // handle any capitalization issues here
353 if (tag
== L
"[strings]")
355 state
= ParsingStrings
;
370 if (s
.GetLength() > 0)
372 CString key
= s
.Tokenize(L
"=",curPos
);
373 CString val
= s
.Tokenize(L
"=",curPos
);
376 // get rid of all delimiters
394 ok
= file
.Open( filename
, CFile::modeRead
|CFile::typeText
, &feError
);
395 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
396 require_noerr( err
, exit
);
400 check ( iter
== manufacturers
.end() );
402 while (file
.ReadString(s
))
407 if (s
.Find(';') == 0)
415 else if (s
.Find('[') == 0)
418 // handle any capitalization issues here
424 if (tag
== L
"[manufacturer]")
426 state
= ParsingManufacturers
;
430 // remove the leading and trailing delimiters
435 // check to see if this is a printer entry
437 iter
= manufacturers
.find(s
);
439 if (iter
!= manufacturers
.end())
441 state
= ParsingModels
;
450 // only look at this if the line isn't empty, or
451 // if it isn't a comment
453 else if ((s
.GetLength() > 0) && (s
.Find(';') != 0))
458 // if we're parsing manufacturers, then we will parse
459 // an entry of the form key=val, where key is a delimited
460 // string specifying a manufacturer name, and val is
461 // a tag that is used later in the file. the key is
462 // delimited by either '"' (quotes) or '%' (percent sign).
464 // the tag is used further down the file when models are
465 // declared. this allows multiple manufacturers to exist
466 // in a single inf file.
468 case ParsingManufacturers
:
470 Manufacturer
* manufacturer
;
473 CString key
= s
.Tokenize(L
"=",curPos
);
474 CString val
= s
.Tokenize(L
"=",curPos
);
478 manufacturer
= new Manufacturer
;
485 require_action( manufacturer
, exit
, err
= kNoMemoryErr
);
488 // if it's a variable, look it up
490 if (key
.Find('%') == 0)
492 StringMap::iterator it
;
496 it
= strings
.find(key
);
498 if (it
!= strings
.end())
512 // why is there no consistency in inf files?
514 if (val
.GetLength() == 0)
520 // fix the manufacturer name if necessary
523 val
= val
.Tokenize(L
",", curPos
);
525 manufacturer
->name
= NormalizeManufacturerName( key
);
526 manufacturer
->tag
= val
;
528 manufacturers
[val
] = manufacturer
;
534 check( iter
!= manufacturers
.end() );
539 CString name
= s
.Tokenize(L
"=",curPos
);
540 CString description
= s
.Tokenize(L
"=",curPos
);
542 if (name
.Find('%') == 0)
544 StringMap::iterator it
;
548 it
= strings
.find(name
);
550 if (it
!= strings
.end())
564 // If true, see if we've seen this guy before
566 if (checkForDuplicateModels
== true)
568 if ( MatchModel( iter
->second
, ConvertToModelName( name
) ) != NULL
)
583 require_action( model
, exit
, err
= kNoMemoryErr
);
585 model
->infFileName
= filename
;
587 model
->driverInstalled
= false;
589 iter
->second
->models
.push_back(model
);
595 // pay no attention if we are in any other state
610 // -------------------------------------------------------
611 // LoadPrintDriverDefs
613 // This function is responsible for loading the print driver
614 // definitions of all print drivers that have been installed
616 // -------------------------------------------------------
618 CThirdPage::LoadPrintDriverDefs( Manufacturers
& manufacturers
)
620 BYTE
* buffer
= NULL
;
621 DWORD bytesReceived
= 0;
622 DWORD numPrinters
= 0;
627 // like a lot of win32 calls, we call this first to get the
628 // size of the buffer we need.
630 EnumPrinterDrivers(NULL
, L
"all", 6, NULL
, 0, &bytesReceived
, &numPrinters
);
632 if (bytesReceived
> 0)
636 buffer
= new BYTE
[bytesReceived
];
643 require_action( buffer
, exit
, err
= kNoMemoryErr
);
646 // this call gets the real info
648 ok
= EnumPrinterDrivers(NULL
, L
"all", 6, buffer
, bytesReceived
, &bytesReceived
, &numPrinters
);
649 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
650 require_noerr( err
, exit
);
652 DRIVER_INFO_6
* info
= (DRIVER_INFO_6
*) buffer
;
654 for (DWORD i
= 0; i
< numPrinters
; i
++)
656 Manufacturer
* manufacturer
;
661 // skip over anything that doesn't have a manufacturer field. This
662 // fixes a bug that I noticed that occurred after I installed
663 // ProComm. This program add a print driver with no manufacturer
664 // that screwed up this wizard.
666 if (info
[i
].pszMfgName
== NULL
)
672 // look for manufacturer
674 Manufacturers::iterator iter
;
679 name
= NormalizeManufacturerName( info
[i
].pszMfgName
);
681 iter
= manufacturers
.find(name
);
683 if (iter
!= manufacturers
.end())
685 manufacturer
= iter
->second
;
691 manufacturer
= new Manufacturer
;
698 require_action( manufacturer
, exit
, err
= kNoMemoryErr
);
700 manufacturer
->name
= name
;
702 manufacturers
[name
] = manufacturer
;
706 // now look to see if we have already seen this guy. this could
707 // happen if we have already installed printers that are described
708 // in ntprint.inf. the extant drivers will show up in EnumPrinterDrivers
709 // but we have already loaded their info
712 if ( MatchModel( manufacturer
, ConvertToModelName( info
[i
].pName
) ) == NULL
)
723 require_action( model
, exit
, err
= kNoMemoryErr
);
725 model
->name
= info
[i
].pName
;
726 model
->driverInstalled
= true;
728 manufacturer
->models
.push_back(model
);
744 // ------------------------------------------------------
745 // ConvertToManufacturerName
747 // This function is responsible for tweaking the
748 // name so that subsequent string operations won't fail because
749 // of capitalizations/different names for the same manufacturer
750 // (i.e. Hewlett-Packard/HP/Hewlett Packard)
753 CThirdPage::ConvertToManufacturerName( const CString
& name
)
756 // first we're going to convert all the characters to lower
759 CString lower
= name
;
763 // now we're going to check to see if the string says "hewlett-packard",
764 // because sometimes they refer to themselves as "hewlett-packard", and
765 // sometimes they refer to themselves as "hp".
767 if ( lower
== L
"hewlett-packard")
773 // tweak for Xerox Phaser, which doesn't announce itself
776 else if ( lower
.Find( L
"phaser", 0 ) != -1 )
785 // ------------------------------------------------------
786 // ConvertToModelName
788 // This function is responsible for ensuring that subsequent
789 // string operations don't fail because of differing capitalization
790 // schemes and the like
791 // ------------------------------------------------------
794 CThirdPage::ConvertToModelName( const CString
& name
)
797 // convert it to lowercase
799 CString lower
= name
;
806 // ------------------------------------------------------
807 // NormalizeManufacturerName
809 // This function is responsible for tweaking the manufacturer
810 // name so that there are no aliases for vendors
813 CThirdPage::NormalizeManufacturerName( const CString
& name
)
815 CString normalized
= name
;
818 // now we're going to check to see if the string says "hewlett-packard",
819 // because sometimes they refer to themselves as "hewlett-packard", and
820 // sometimes they refer to themselves as "hp".
822 if ( normalized
== L
"Hewlett-Packard")
831 // -------------------------------------------------------
834 // This function is responsible for matching a printer
835 // to a list of manufacturers and models. It calls
836 // MatchManufacturer and MatchModel in turn.
839 OSStatus
CThirdPage::MatchPrinter(Manufacturers
& manufacturers
, Printer
* printer
, Service
* service
)
841 CString normalizedProductName
;
842 Manufacturer
* manufacturer
= NULL
;
843 Model
* model
= NULL
;
846 OSStatus err
= kNoErr
;
849 // first look to see if we have a usb_MFG descriptor
851 if (service
->usb_MFG
.GetLength() > 0)
853 manufacturer
= MatchManufacturer( manufacturers
, ConvertToManufacturerName ( service
->usb_MFG
) );
856 if ( manufacturer
== NULL
)
858 service
->product
.Remove('(');
859 service
->product
.Remove(')');
861 manufacturer
= MatchManufacturer( manufacturers
, ConvertToManufacturerName ( service
->product
) );
865 // if we found the manufacturer, then start looking for the model
867 if ( manufacturer
!= NULL
)
869 if (service
->usb_MDL
.GetLength() > 0)
871 model
= MatchModel ( manufacturer
, ConvertToModelName ( service
->usb_MDL
) );
876 service
->product
.Remove('(');
877 service
->product
.Remove(')');
879 model
= MatchModel ( manufacturer
, ConvertToModelName ( service
->product
) );
884 SelectMatch(printer
, service
, manufacturer
, model
);
890 // display a message to the user based on whether we could match
895 text
.LoadString(IDS_PRINTER_MATCH_GOOD
);
899 text
.LoadString(IDS_PRINTER_MATCH_BAD
);
902 // if there was any crud in this list from before, get rid of it now
904 m_modelListCtrl
.DeleteAllItems();
907 // select the manufacturer if we found one
909 if (manufacturer
!= NULL
)
915 // select the manufacturer
917 info
.flags
= LVFI_STRING
;
918 info
.psz
= manufacturer
->name
;
920 nIndex
= m_manufacturerListCtrl
.FindItem(&info
);
924 m_manufacturerListCtrl
.SetItemState(nIndex
, LVIS_SELECTED
, LVIS_SELECTED
);
925 m_manufacturerListCtrl
.EnsureVisible(nIndex
, FALSE
);
930 m_printerSelectionText
.SetWindowText(text
);
936 // ------------------------------------------------------
939 // This function is responsible for finding a manufacturer
940 // object from a string name. It does a CString::Find, which
941 // is like strstr, so it doesn't have to do an exact match
943 // If it can't find a match, NULL is returned
944 // ------------------------------------------------------
947 CThirdPage::MatchManufacturer( Manufacturers
& manufacturers
, const CString
& name
)
949 Manufacturers::iterator iter
;
951 for (iter
= manufacturers
.begin(); iter
!= manufacturers
.end(); iter
++)
954 // we're going to convert all the manufacturer names to lower case,
955 // so we match the name passed in.
957 CString lower
= iter
->second
->name
;
961 // now try and find the lowered string in the name passed in.
963 if (name
.Find(lower
) != -1)
973 // -------------------------------------------------------
976 // This function is responsible for matching a model from
977 // a name. It does a CString::Find(), which works like strstr,
978 // so it doesn't rely on doing an exact string match.
982 CThirdPage::MatchModel(Manufacturer
* manufacturer
, const CString
& name
)
984 Models::iterator iter
;
986 iter
= manufacturer
->models
.begin();
988 for (iter
= manufacturer
->models
.begin(); iter
!= manufacturer
->models
.end(); iter
++)
990 Model
* model
= *iter
;
993 // convert the model name to lower case
995 CString lowered
= model
->name
;
998 if (lowered
.Find( name
) != -1)
1004 // <rdar://problem/3841218>
1005 // try removing the first substring and search again
1008 if ( name
.Find(' ') != -1 )
1010 CString altered
= name
;
1011 altered
.Delete( 0, altered
.Find(' ') + 1 );
1013 if ( lowered
.Find( altered
) != -1 )
1025 // -----------------------------------------------------------
1028 // This function is responsible for doing initialization that
1029 // only occurs once during a run of the wizard
1032 OSStatus
CThirdPage::OnInitPage()
1034 static const int bufferSize
= 32768;
1035 TCHAR windowsDirectory
[bufferSize
];
1041 // Load printer icon
1043 check( m_printerImage
== NULL
);
1045 m_printerImage
= (CStatic
*) GetDlgItem( IDR_MANIFEST
);
1046 check( m_printerImage
);
1048 if ( m_printerImage
!= NULL
)
1050 m_printerImage
->SetIcon( LoadIcon( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_PRINTER
) ) );
1054 // The CTreeCtrl widget automatically sends a selection changed
1055 // message which initially we want to ignore, because the user
1056 // hasn't selected anything
1058 // this flag gets reset in the message handler. Every subsequent
1059 // message gets handled.
1063 // we have to make sure that we only do this once. Typically,
1064 // we would do this in something like OnInitDialog, but we don't
1065 // have this in Wizards, because the window is a PropertySheet.
1066 // We're considered fully initialized when we receive the first
1069 header
.LoadString(IDS_MANUFACTURER_HEADING
);
1070 m_manufacturerListCtrl
.InsertColumn(0, header
, LVCFMT_LEFT
, 138);
1071 m_manufacturerSelected
= NULL
;
1073 header
.LoadString(IDS_MODEL_HEADING
);
1074 m_modelListCtrl
.InsertColumn(0, header
, LVCFMT_LEFT
, 247);
1075 m_modelSelected
= NULL
;
1078 // load printers from ntprint.inf
1080 ok
= GetWindowsDirectory( windowsDirectory
, bufferSize
);
1081 err
= translate_errno( ok
, errno_compat(), kUnknownErr
);
1082 require_noerr( err
, exit
);
1084 ntPrint
.Format(L
"%s\\%s", windowsDirectory
, kNTPrintFile
);
1085 err
= LoadPrintDriverDefsFromFile( m_manufacturers
, ntPrint
, false );
1086 require_noerr(err
, exit
);
1089 // load printer drivers that have been installed on this machine
1091 err
= LoadPrintDriverDefs( m_manufacturers
);
1092 require_noerr(err
, exit
);
1100 void CThirdPage::DoDataExchange(CDataExchange
* pDX
)
1102 CPropertyPage::DoDataExchange(pDX
);
1103 DDX_Control(pDX
, IDC_PRINTER_MANUFACTURER
, m_manufacturerListCtrl
);
1104 DDX_Control(pDX
, IDC_PRINTER_MODEL
, m_modelListCtrl
);
1105 DDX_Control(pDX
, IDC_PRINTER_NAME
, m_printerName
);
1106 DDX_Control(pDX
, IDC_DEFAULT_PRINTER
, m_defaultPrinterCtrl
);
1107 DDX_Control(pDX
, IDC_PRINTER_SELECTION_TEXT
, m_printerSelectionText
);
1111 // ----------------------------------------------------------
1114 // This function is called by MFC after the window has been
1119 CThirdPage::OnSetActive()
1121 CPrinterSetupWizardSheet
* psheet
;
1125 psheet
= reinterpret_cast<CPrinterSetupWizardSheet
*>(GetParent());
1126 require_quiet( psheet
, exit
);
1128 if ((m_manufacturerListCtrl
.GetFirstSelectedItemPosition() != NULL
) &&
1129 (m_modelListCtrl
.GetFirstSelectedItemPosition() != NULL
))
1131 psheet
->SetWizardButtons( PSWIZB_BACK
|PSWIZB_NEXT
);
1135 psheet
->SetWizardButtons( PSWIZB_BACK
);
1138 printer
= psheet
->GetSelectedPrinter();
1139 require_quiet( printer
, exit
);
1141 service
= printer
->services
.front();
1142 require_quiet( service
, exit
);
1145 // call OnInitPage once
1150 m_initialized
= true;
1154 // update the UI with the printer name
1156 m_printerName
.SetWindowText(printer
->displayName
);
1159 // populate the list controls with the manufacturers and models
1162 PopulateUI( m_manufacturers
);
1165 // and try and match the printer
1167 MatchPrinter( m_manufacturers
, printer
, service
);
1171 return CPropertyPage::OnSetActive();
1175 // -------------------------------------------------------
1178 // This function is called to populate the list of manufacturers
1181 CThirdPage::PopulateUI(Manufacturers
& manufacturers
)
1183 Manufacturers::iterator iter
;
1185 m_manufacturerListCtrl
.DeleteAllItems();
1187 for (iter
= manufacturers
.begin(); iter
!= manufacturers
.end(); iter
++)
1191 Manufacturer
* manufacturer
= iter
->second
;
1193 nIndex
= m_manufacturerListCtrl
.InsertItem(0, manufacturer
->name
);
1195 m_manufacturerListCtrl
.SetItemData(nIndex
, (DWORD_PTR
) manufacturer
);
1202 BEGIN_MESSAGE_MAP(CThirdPage
, CPropertyPage
)
1203 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_PRINTER_MANUFACTURER
, OnLvnItemchangedManufacturer
)
1204 ON_NOTIFY(LVN_ITEMCHANGED
, IDC_PRINTER_MODEL
, OnLvnItemchangedPrinterModel
)
1205 ON_BN_CLICKED(IDC_DEFAULT_PRINTER
, OnBnClickedDefaultPrinter
)
1206 ON_BN_CLICKED(IDC_HAVE_DISK
, OnBnClickedHaveDisk
)
1210 // CThirdPage message handlers
1211 void CThirdPage::OnLvnItemchangedManufacturer(NMHDR
*pNMHDR
, LRESULT
*pResult
)
1213 LPNMLISTVIEW pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
1215 POSITION p
= m_manufacturerListCtrl
.GetFirstSelectedItemPosition();
1216 int nSelected
= m_manufacturerListCtrl
.GetNextSelectedItem(p
);
1218 if (nSelected
!= -1)
1220 m_manufacturerSelected
= (Manufacturer
*) m_manufacturerListCtrl
.GetItemData(nSelected
);
1222 m_modelListCtrl
.SetRedraw(FALSE
);
1224 m_modelListCtrl
.DeleteAllItems();
1225 m_modelSelected
= NULL
;
1227 Models::iterator iter
;
1229 for (iter
= m_manufacturerSelected
->models
.begin(); iter
!= m_manufacturerSelected
->models
.end(); iter
++)
1231 Model
* model
= *iter
;
1233 int nItem
= m_modelListCtrl
.InsertItem(0, model
->name
);
1235 m_modelListCtrl
.SetItemData(nItem
, (DWORD_PTR
) model
);
1238 m_modelListCtrl
.SetRedraw(TRUE
);
1244 void CThirdPage::OnLvnItemchangedPrinterModel(NMHDR
*pNMHDR
, LRESULT
*pResult
)
1246 LPNMLISTVIEW pNMLV
= reinterpret_cast<LPNMLISTVIEW
>(pNMHDR
);
1248 CPrinterSetupWizardSheet
* psheet
;
1252 psheet
= reinterpret_cast<CPrinterSetupWizardSheet
*>(GetParent());
1253 require_quiet( psheet
, exit
);
1255 printer
= psheet
->GetSelectedPrinter();
1256 require_quiet( printer
, exit
);
1258 service
= printer
->services
.front();
1259 require_quiet( service
, exit
);
1261 check ( m_manufacturerSelected
);
1263 POSITION p
= m_modelListCtrl
.GetFirstSelectedItemPosition();
1264 int nSelected
= m_modelListCtrl
.GetNextSelectedItem(p
);
1266 if (nSelected
!= -1)
1268 m_modelSelected
= (Model
*) m_modelListCtrl
.GetItemData(nSelected
);
1270 CopyPrinterSettings( printer
, service
, m_manufacturerSelected
, m_modelSelected
);
1272 psheet
->SetWizardButtons(PSWIZB_BACK
|PSWIZB_NEXT
);
1276 psheet
->SetWizardButtons(PSWIZB_BACK
);
1285 void CThirdPage::OnBnClickedDefaultPrinter()
1287 CPrinterSetupWizardSheet
* psheet
;
1290 psheet
= reinterpret_cast<CPrinterSetupWizardSheet
*>(GetParent());
1291 require_quiet( psheet
, exit
);
1293 printer
= psheet
->GetSelectedPrinter();
1294 require_quiet( printer
, exit
);
1296 printer
->deflt
= m_defaultPrinterCtrl
.GetState() ? true : false;
1303 void CThirdPage::OnBnClickedHaveDisk()
1305 CPrinterSetupWizardSheet
* psheet
;
1309 CFileDialog
dlg(TRUE
, NULL
, NULL
, OFN_HIDEREADONLY
|OFN_FILEMUSTEXIST
, L
"Setup Information (*.inf)|*.inf||", this);
1311 psheet
= reinterpret_cast<CPrinterSetupWizardSheet
*>(GetParent());
1312 require_quiet( psheet
, exit
);
1314 printer
= psheet
->GetSelectedPrinter();
1315 require_quiet( printer
, exit
);
1317 service
= printer
->services
.front();
1318 require_quiet( service
, exit
);
1320 if ( dlg
.DoModal() == IDOK
)
1322 Manufacturers manufacturers
;
1323 CString filename
= dlg
.GetPathName();
1325 LoadPrintDriverDefsFromFile( manufacturers
, filename
, true );
1327 PopulateUI( manufacturers
);
1329 MatchPrinter( manufacturers
, printer
, service
);