]> git.saurik.com Git - apple/mdnsresponder.git/blame - Clients/PrinterSetupWizard/ThirdPage.cpp
mDNSResponder-214.3.2.tar.gz
[apple/mdnsresponder.git] / Clients / PrinterSetupWizard / ThirdPage.cpp
CommitLineData
67c8f8a1
A
1/* -*- Mode: C; tab-width: 4 -*-
2 *
7f0064bd
A
3 * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
4 *
67c8f8a1
A
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
7f0064bd 8 *
67c8f8a1 9 * http://www.apache.org/licenses/LICENSE-2.0
7f0064bd 10 *
67c8f8a1
A
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
7f0064bd 15 * limitations under the License.
7f0064bd
A
16
17 Change History (most recent first):
18
19$Log: ThirdPage.cpp,v $
1a175162
A
20Revision 1.42 2009/07/07 22:04:55 herscher
21<rdar://problem/4176343> LOC Impact: Need custom text when selecting the wrong printer driver
22
32bb7e43
A
23Revision 1.41 2009/06/18 18:05:50 herscher
24<rdar://problem/4694554> Eliminate the first screen of Printer Wizard and maybe combine others ("I'm Feeling Lucky")
25
26Revision 1.40 2009/05/29 20:43:36 herscher
27<rdar://problem/6928136> Printer Wizard doesn't work correctly in Windows 7 64 bit
28
29Revision 1.39 2009/05/27 06:25:49 herscher
30<rdar://problem/4176334> Need error dialog when selecting bad INF file
31
32Revision 1.38 2009/05/27 04:59:57 herscher
33<rdar://problem/4517393> COMPATIBILITY WITH HP CLJ4700
34<rdar://problem/6142138> Compatibility with Samsung print driver files
35
67c8f8a1
A
36Revision 1.37 2007/06/08 06:30:26 herscher
37<rdar://problem/5257700> Fix uninitialized pointers when detecting generic PCL and PS drivers
38
39Revision 1.36 2007/06/06 20:39:10 cheshire
40<rdar://problem/5254377> Printer Setup Wizard started crashing in Bonjour104A8, after update to Visual Studio 2005
41
42Revision 1.35 2007/06/06 20:08:01 cheshire
43<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
44AutoScroll model list as well as manufacturer list
45
46Revision 1.34 2007/06/06 19:53:48 cheshire
47<rdar://problem/5187308> Move build train to Visual Studio 2005
48
49Revision 1.33 2007/04/20 22:58:10 herscher
50<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
51
52Revision 1.32 2007/04/13 23:42:20 herscher
53<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
54
55Revision 1.31 2007/04/13 21:38:46 herscher
56<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
57
58Revision 1.30 2007/04/13 20:23:40 herscher
59Fixed mistake in previous checkin that reverted license text for this file
60
61Revision 1.29 2007/04/13 18:10:24 herscher
62<rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
63
64Revision 1.28 2006/08/14 23:24:09 cheshire
65Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
66
4aea607d
A
67Revision 1.27 2005/10/05 21:41:45 herscher
68<rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS shared queue supports raw
69
70Revision 1.26 2005/07/11 20:17:15 shersche
7df24c4d 71<rdar://problem/4124524> UI fixes associated with CUPS printer workaround fix.
4aea607d
A
72
73Revision 1.25 2005/07/07 17:53:20 shersche
74Fix problems associated with the CUPS printer workaround fix.
75
76Revision 1.24 2005/06/30 18:02:54 shersche
77<rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
78
79Revision 1.23 2005/04/18 02:33:47 shersche
80<rdar://problem/4091216> Default printer option cannot be deselected
81
82Revision 1.22 2005/04/13 17:46:22 shersche
83<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
84
85Revision 1.21 2005/03/30 02:09:55 shersche
86Auto-resize the column width to account for differing fonts and font sizes
87
7cb34e5c
A
88Revision 1.20 2005/03/05 02:27:45 shersche
89<rdar://problem/4030388> Generic drivers don't do color
90
91Revision 1.19 2005/02/23 02:08:51 shersche
92<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".
93
94Revision 1.18 2005/02/15 07:02:51 shersche
95<rdar://problem/4003724> Display different UI text when generic printer drivers are selected
96
97Revision 1.17 2005/02/08 21:45:06 shersche
98<rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
99
100Revision 1.16 2005/02/08 18:56:03 shersche
101Fix generated IPP url so that it doesn't add "/printers" string
102
103Revision 1.15 2005/02/01 01:44:07 shersche
104Load 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.
105
283ee3ff
A
106Revision 1.14 2005/01/25 08:55:54 shersche
107<rdar://problem/3911084> Load icons at run-time from resource DLL
108Bug #: 3911084
109
110Revision 1.13 2005/01/06 08:15:45 shersche
111Append queue name to end of LPR port name, correctly build port name when queue name is absent
112
113Revision 1.12 2005/01/05 01:06:12 shersche
114<rdar://problem/3841218> Strip the first substring off the product key if an initial match can't be found with the whole product key.
115Bug #: 3841218
116
117Revision 1.11 2004/12/29 18:53:38 shersche
118<rdar://problem/3725106>
119<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
120Bug #: 3725106, 3737413
121
7f0064bd
A
122Revision 1.10 2004/10/11 22:55:34 shersche
123<rdar://problem/3827624> Use the IP port number when deriving the printer port name.
124Bug #: 3827624
125
126Revision 1.9 2004/06/27 23:08:00 shersche
127code cleanup, make sure EnumPrintDrivers returns non-zero value, ignore comments in inf files
128
129Revision 1.8 2004/06/27 08:06:45 shersche
130Parse [Strings] section of inf file
131
132Revision 1.7 2004/06/26 04:00:05 shersche
133fix warnings compiling in debug mode
134Submitted by: herscher
135
136Revision 1.6 2004/06/26 03:19:57 shersche
137clean up warning messages
138
139Submitted by: herscher
140
141Revision 1.5 2004/06/25 05:06:02 shersche
142Trim whitespace from key/value pairs when parsing inf files
143Submitted by: herscher
144
145Revision 1.4 2004/06/25 02:44:13 shersche
146Tweaked code to handle Xerox Phaser printer identification
147Submitted by: herscher
148
149Revision 1.3 2004/06/25 02:27:58 shersche
150Do a CListCtrl::FindItem() before calling CListCtrl::SetItemState().
151Submitted by: herscher
152
153Revision 1.2 2004/06/23 18:09:23 shersche
154Normalize tag names when parsing inf files.
155Submitted by: herscher
156
157Revision 1.1 2004/06/18 04:36:58 rpantos
158First checked in
7f0064bd
A
159*/
160
161#include "stdafx.h"
162#include "PrinterSetupWizardApp.h"
163#include "PrinterSetupWizardSheet.h"
164#include "ThirdPage.h"
7f0064bd
A
165#include <dns_sd.h>
166#include <tcpxcv.h>
167#include <winspool.h>
32bb7e43 168#include <setupapi.h>
7f0064bd
A
169
170// local variable is initialize but not referenced
171#pragma warning(disable:4189)
172
7f0064bd
A
173//
174// This is the printer description file that is shipped
67c8f8a1 175// with Windows XP and below
7f0064bd
A
176//
177#define kNTPrintFile L"inf\\ntprint.inf"
178
67c8f8a1
A
179//
180// Windows Vista ships with a set of prn*.inf files
181//
182#define kVistaPrintFiles L"inf\\prn*.inf"
183
7f0064bd
A
184//
185// These are pre-defined names for Generic manufacturer and model
186//
7cb34e5c
A
187#define kGenericManufacturer L"Generic"
188#define kGenericText L"Generic / Text Only"
189#define kGenericPostscript L"Generic / Postscript"
190#define kGenericPCL L"Generic / PCL"
191#define kPDLPostscriptKey L"application/postscript"
192#define kPDLPCLKey L"application/vnd.hp-pcl"
193#define kGenericPSColorDriver L"HP Color LaserJet 4550 PS"
194#define kGenericPSDriver L"HP LaserJet 4050 Series PS"
195#define kGenericPCLColorDriver L"HP Color LaserJet 4550 PCL"
196#define kGenericPCLDriver L"HP LaserJet 4050 Series PCL"
197
7f0064bd 198
7f0064bd
A
199// CThirdPage dialog
200
201IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage)
202CThirdPage::CThirdPage()
203 : CPropertyPage(CThirdPage::IDD),
67c8f8a1
A
204 m_manufacturerSelected( NULL ),
205 m_modelSelected( NULL ),
206 m_genericPostscript( NULL ),
207 m_genericPCL( NULL ),
283ee3ff
A
208 m_initialized(false),
209 m_printerImage( NULL )
7f0064bd 210{
7cb34e5c
A
211 static const int bufferSize = 32768;
212 TCHAR windowsDirectory[bufferSize];
213 CString header;
67c8f8a1
A
214 WIN32_FIND_DATA findFileData;
215 HANDLE findHandle;
216 CString prnFiles;
7cb34e5c
A
217 CString ntPrint;
218 OSStatus err;
219 BOOL ok;
220
7f0064bd
A
221 m_psp.dwFlags &= ~(PSP_HASHELP);
222 m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
223
224 m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_INSTALL_TITLE);
225 m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_INSTALL_SUBTITLE);
7cb34e5c
A
226
227 //
228 // load printers from ntprint.inf
229 //
230 ok = GetWindowsDirectory( windowsDirectory, bufferSize );
231 err = translate_errno( ok, errno_compat(), kUnknownErr );
232 require_noerr( err, exit );
233
67c8f8a1
A
234 //
235 // <rdar://problem/4826126>
236 //
237 // If there are no *prn.inf files, we'll assume that the information
238 // is in ntprint.inf
239 //
240 prnFiles.Format( L"%s\\%s", windowsDirectory, kVistaPrintFiles );
241 findHandle = FindFirstFile( prnFiles, &findFileData );
242
243 if ( findHandle != INVALID_HANDLE_VALUE )
244 {
245 CString absolute;
246
247 absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
248 err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
249 require_noerr( err, exit );
250
251 while ( FindNextFile( findHandle, &findFileData ) )
252 {
253 absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
254 err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
255 require_noerr( err, exit );
256 }
257
258 FindClose( findHandle );
259 }
260 else
261 {
262 ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
263 err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
264 require_noerr(err, exit);
265 }
7cb34e5c
A
266
267 //
268 // load printer drivers that have been installed on this machine
269 //
270 err = LoadPrintDriverDefs( m_manufacturers );
271 require_noerr(err, exit);
272
273 //
4aea607d 274 // load our own special generic printer defs
7cb34e5c
A
275 //
276 err = LoadGenericPrintDriverDefs( m_manufacturers );
277 require_noerr( err, exit );
278
279exit:
280
281 return;
7f0064bd
A
282}
283
7f0064bd
A
284CThirdPage::~CThirdPage()
285{
286 //
287 // clean up all the printer manufacturers
288 //
289 while (m_manufacturers.size())
290 {
291 Manufacturers::iterator iter = m_manufacturers.begin();
292
293 while (iter->second->models.size())
294 {
295 Models::iterator it = iter->second->models.begin();
296
297 Model * model = *it;
298
299 delete model;
300
301 iter->second->models.erase(it);
302 }
303
304 delete iter->second;
305
306 m_manufacturers.erase(iter);
307 }
308}
309
7f0064bd
A
310// ----------------------------------------------------
311// SelectMatch
312//
313// SelectMatch will do all the UI work associated with
314// selected a manufacturer and model of printer. It also
67c8f8a1 315// makes sure the printer object is update with the
7f0064bd
A
316// latest settings
317//
318// ----------------------------------------------------
319void
4aea607d 320CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model)
7f0064bd
A
321{
322 LVFINDINFO info;
323 int nIndex;
324
325 check( printer != NULL );
326 check( manufacturer != NULL );
327 check( model != NULL );
328
7f0064bd
A
329 //
330 // select the manufacturer
331 //
332 info.flags = LVFI_STRING;
333 info.psz = manufacturer->name;
334
335 nIndex = m_manufacturerListCtrl.FindItem(&info);
336
337 if (nIndex != -1)
338 {
339 m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
67c8f8a1
A
340 //
341 //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
342 //
343 AutoScroll(m_manufacturerListCtrl, nIndex);
7f0064bd
A
344 }
345
346 //
347 // select the model
348 //
349 info.flags = LVFI_STRING;
7cb34e5c 350 info.psz = model->displayName;
7f0064bd
A
351
352 nIndex = m_modelListCtrl.FindItem(&info);
353
354 if (nIndex != -1)
355 {
356 m_modelListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
67c8f8a1 357 AutoScroll( m_modelListCtrl, nIndex );
7f0064bd
A
358
359 m_modelListCtrl.SetFocus();
360 }
361
283ee3ff 362 CopyPrinterSettings( printer, service, manufacturer, model );
7f0064bd
A
363}
364
4aea607d
A
365void
366CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model)
367{
368 PopulateUI( manufacturers );
369
370 SelectMatch( printer, service, manufacturer, model );
371}
372
7f0064bd
A
373// --------------------------------------------------------
374// CopyPrinterSettings
375//
376// This function makes sure that the printer object has the
377// latest settings from the manufacturer and model objects
378// --------------------------------------------------------
379
380void
283ee3ff 381CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufacturer * manufacturer, Model * model )
7f0064bd
A
382{
383 printer->manufacturer = manufacturer->name;
7cb34e5c
A
384 printer->displayModelName = model->displayName;
385 printer->modelName = model->name;
7f0064bd
A
386 printer->driverInstalled = model->driverInstalled;
387 printer->infFileName = model->infFileName;
283ee3ff
A
388
389 if ( service->type == kPDLServiceType )
390 {
391 printer->portName.Format(L"IP_%s.%d", static_cast<LPCTSTR>(service->hostname), service->portNumber);
392 service->protocol = L"Raw";
393 }
394 else if ( service->type == kLPRServiceType )
395 {
396 Queue * q = service->queues.front();
397 check( q );
398
399 if ( q->name.GetLength() > 0 )
400 {
401 printer->portName.Format(L"LPR_%s.%d.%s", static_cast<LPCTSTR>(service->hostname), service->portNumber, static_cast<LPCTSTR>(q->name) );
402 }
403 else
404 {
405 printer->portName.Format(L"LPR_%s.%d", static_cast<LPCTSTR>(service->hostname), service->portNumber);
406 }
407
408 service->protocol = L"LPR";
409 }
410 else if ( service->type == kIPPServiceType )
411 {
412 Queue * q = service->queues.front();
413 check( q );
414
415 if ( q->name.GetLength() > 0 )
416 {
7cb34e5c 417 printer->portName.Format(L"http://%s:%d/%s", static_cast<LPCTSTR>(service->hostname), service->portNumber, static_cast<LPCTSTR>(q->name) );
283ee3ff
A
418 }
419 else
420 {
421 printer->portName.Format(L"http://%s:%d/", static_cast<LPCTSTR>(service->hostname), service->portNumber );
422 }
423
424 service->protocol = L"IPP";
425 }
7f0064bd
A
426}
427
67c8f8a1
A
428// --------------------------------------------------------
429// DefaultPrinterExists
430//
431// Checks to see if a default printer has been configured
432// on this machine
433// --------------------------------------------------------
434BOOL
435CThirdPage::DefaultPrinterExists()
436{
437 CPrintDialog dlg(FALSE);
438
439 dlg.m_pd.Flags |= PD_RETURNDEFAULT;
440
441 return dlg.GetDefaults();
442}
443
444// --------------------------------------------------------
445// AutoScroll
446//
447// Ensure selected item is in middle of list
448// --------------------------------------------------------
449void
450CThirdPage::AutoScroll( CListCtrl & list, int nIndex )
451{
452 //
453 //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
454 //
455
456 int top;
457 int count;
458
459 list.EnsureVisible( nIndex, FALSE );
460
461 top = list.GetTopIndex();
462 count = list.GetCountPerPage();
463
464 if ( ( nIndex == top ) || ( ( nIndex + 1 ) == ( top + count ) ) )
465 {
466 CRect rect;
467 int rows;
468
469 rows = ( count / 2 );
470
471 if ( nIndex == top )
472 {
473 list.GetItemRect(0, rect, LVIR_BOUNDS);
474 list.Scroll( CPoint( 0, rows * rect.Height() * -1 ) );
475 }
476 else
477 {
478 list.GetItemRect(0, rect, LVIR_BOUNDS);
479 list.Scroll( CPoint( 0, rows * rect.Height() ) );
480 }
481 }
482}
7f0064bd
A
483
484// ------------------------------------------------------
485// LoadPrintDriverDefsFromFile
486//
67c8f8a1 487// The only potentially opaque thing about this function is the
7f0064bd
A
488// checkForDuplicateModels flag. The problem here is that ntprint.inf
489// doesn't contain duplicate models, and it has hundreds of models
490// listed. You wouldn't check for duplicates there. But oftentimes,
491// loading different windows print driver files contain multiple
492// entries for the same printer. You don't want the UI to display
493// the same printer multiple times, so in that case, you would ask
494// this function to check for multiple models.
495
496OSStatus
497CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels )
498{
32bb7e43
A
499 HINF handle = INVALID_HANDLE_VALUE;
500 const TCHAR * section = TEXT( "Manufacturer" );
501 LONG sectionCount;
502 TCHAR line[ 1000 ];
503 CString klass;
504 INFCONTEXT manufacturerContext;
505 BOOL ok;
506 OSStatus err = 0;
507
508 // Make sure we can open the file
509 handle = SetupOpenInfFile( filename, NULL, INF_STYLE_WIN4, NULL );
510 translate_errno( handle != INVALID_HANDLE_VALUE, GetLastError(), kUnknownErr );
511 require_noerr( err, exit );
7f0064bd 512
32bb7e43
A
513 // Make sure it's a printer file
514 ok = SetupGetLineText( NULL, handle, TEXT( "Version" ), TEXT( "Class" ), line, sizeof( line ), NULL );
515 translate_errno( ok, GetLastError(), kUnknownErr );
7f0064bd 516 require_noerr( err, exit );
32bb7e43
A
517 klass = line;
518 require_action( klass == TEXT( "Printer" ), exit, err = kUnknownErr );
7f0064bd 519
32bb7e43
A
520 sectionCount = SetupGetLineCount( handle, section );
521 translate_errno( sectionCount != -1, GetLastError(), kUnknownErr );
522 require_noerr( err, exit );
7f0064bd 523
32bb7e43
A
524 memset( &manufacturerContext, 0, sizeof( manufacturerContext ) );
525
526 for ( LONG i = 0; i < sectionCount; i++ )
7f0064bd 527 {
32bb7e43
A
528 Manufacturers::iterator iter;
529 Manufacturer * manufacturer;
530 CString manufacturerName;
531 CString temp;
532 CStringList modelSectionNameDecl;
533 CString modelSectionName;
534 CString baseModelName;
535 CString model;
536 INFCONTEXT modelContext;
537 LONG modelCount;
538 POSITION p;
539
540 if ( i == 0 )
7f0064bd 541 {
32bb7e43
A
542 ok = SetupFindFirstLine( handle, section, NULL, &manufacturerContext );
543 err = translate_errno( ok, GetLastError(), kUnknownErr );
544 require_noerr( err, exit );
7f0064bd
A
545 }
546 else
547 {
32bb7e43
A
548 ok = SetupFindNextLine( &manufacturerContext, &manufacturerContext );
549 err = translate_errno( ok, GetLastError(), kUnknownErr );
550 require_noerr( err, exit );
7f0064bd 551 }
7f0064bd 552
32bb7e43
A
553 ok = SetupGetStringField( &manufacturerContext, 0, line, sizeof( line ), NULL );
554 err = translate_errno( ok, GetLastError(), kUnknownErr );
555 require_noerr( err, exit );
556 manufacturerName = line;
7f0064bd 557
32bb7e43
A
558 ok = SetupGetLineText( &manufacturerContext, handle, NULL, NULL, line, sizeof( line ), NULL );
559 err = translate_errno( ok, GetLastError(), kUnknownErr );
560 require_noerr( err, exit );
7f0064bd 561
32bb7e43
A
562 // Try to find some model section name that has entries. Explanation of int file structure
563 // can be found at:
7f0064bd 564 //
32bb7e43
A
565 // <http://msdn.microsoft.com/en-us/library/ms794359.aspx>
566 Split( line, ',', modelSectionNameDecl );
567
568 p = modelSectionNameDecl.GetHeadPosition();
569 modelSectionName = modelSectionNameDecl.GetNext( p );
570 modelCount = SetupGetLineCount( handle, modelSectionName );
571 baseModelName = modelSectionName;
572
573 while ( modelCount <= 0 && p )
7f0064bd 574 {
32bb7e43
A
575 CString targetOSVersion;
576
577 targetOSVersion = modelSectionNameDecl.GetNext( p );
578 modelSectionName = baseModelName + TEXT( "." ) + targetOSVersion;
579 modelCount = SetupGetLineCount( handle, modelSectionName );
7f0064bd
A
580 }
581
32bb7e43 582 if ( modelCount > 0 )
7f0064bd 583 {
32bb7e43 584 manufacturerName = NormalizeManufacturerName( manufacturerName );
7f0064bd 585
32bb7e43 586 iter = manufacturers.find( manufacturerName );
7f0064bd 587
32bb7e43 588 if ( iter != manufacturers.end() )
7f0064bd 589 {
32bb7e43
A
590 manufacturer = iter->second;
591 require_action( manufacturer, exit, err = kUnknownErr );
7f0064bd
A
592 }
593 else
594 {
32bb7e43 595 try
7f0064bd 596 {
32bb7e43 597 manufacturer = new Manufacturer;
7f0064bd 598 }
32bb7e43 599 catch (...)
7f0064bd 600 {
32bb7e43 601 manufacturer = NULL;
7f0064bd 602 }
7f0064bd 603
32bb7e43 604 require_action( manufacturer, exit, err = kNoMemoryErr );
7f0064bd 605
32bb7e43
A
606 manufacturer->name = manufacturerName;
607 manufacturers[ manufacturerName ] = manufacturer;
608 }
7f0064bd 609
32bb7e43 610 memset( &modelContext, 0, sizeof( modelContext ) );
67c8f8a1 611
32bb7e43
A
612 for ( LONG j = 0; j < modelCount; j++ )
613 {
614 CString modelName;
615 Model * model;
7f0064bd 616
32bb7e43
A
617 if ( j == 0 )
618 {
619 ok = SetupFindFirstLine( handle, modelSectionName, NULL, &modelContext );
620 err = translate_errno( ok, GetLastError(), kUnknownErr );
621 require_noerr( err, exit );
7f0064bd 622 }
32bb7e43 623 else
7f0064bd 624 {
32bb7e43
A
625 SetupFindNextLine( &modelContext, &modelContext );
626 err = translate_errno( ok, GetLastError(), kUnknownErr );
627 require_noerr( err, exit );
628 }
283ee3ff 629
32bb7e43
A
630 ok = SetupGetStringField( &modelContext, 0, line, sizeof( line ), NULL );
631 err = translate_errno( ok, GetLastError(), kUnknownErr );
632 require_noerr( err, exit );
283ee3ff 633
32bb7e43 634 modelName = line;
283ee3ff 635
32bb7e43
A
636 if (checkForDuplicateModels == true)
637 {
638 if ( MatchModel( manufacturer, ConvertToModelName( modelName ) ) != NULL )
67c8f8a1
A
639 {
640 continue;
641 }
32bb7e43 642 }
67c8f8a1 643
32bb7e43
A
644 //
645 // Stock Vista printer inf files embed guids in the model
646 // declarations for Epson printers. Let's ignore those.
647 //
648 if ( modelName.Find( TEXT( "{" ), 0 ) != -1 )
649 {
650 continue;
7f0064bd 651 }
7f0064bd 652
32bb7e43
A
653 try
654 {
655 model = new Model;
656 }
657 catch (...)
7f0064bd 658 {
32bb7e43 659 model = NULL;
7f0064bd 660 }
32bb7e43
A
661
662 require_action( model, exit, err = kNoMemoryErr );
663
664 model->infFileName = filename;
665 model->displayName = modelName;
666 model->name = modelName;
667 model->driverInstalled = false;
668
669 manufacturer->models.push_back(model);
7f0064bd
A
670 }
671 }
672 }
673
674exit:
675
32bb7e43
A
676 if ( handle != INVALID_HANDLE_VALUE )
677 {
678 SetupCloseInfFile( handle );
679 handle = NULL;
680 }
7f0064bd 681
32bb7e43 682 return err;
7f0064bd
A
683}
684
32bb7e43 685
7f0064bd
A
686// -------------------------------------------------------
687// LoadPrintDriverDefs
688//
689// This function is responsible for loading the print driver
690// definitions of all print drivers that have been installed
691// on this machine.
692// -------------------------------------------------------
693OSStatus
694CThirdPage::LoadPrintDriverDefs( Manufacturers & manufacturers )
695{
696 BYTE * buffer = NULL;
697 DWORD bytesReceived = 0;
698 DWORD numPrinters = 0;
699 OSStatus err = 0;
700 BOOL ok;
701
702 //
703 // like a lot of win32 calls, we call this first to get the
704 // size of the buffer we need.
705 //
706 EnumPrinterDrivers(NULL, L"all", 6, NULL, 0, &bytesReceived, &numPrinters);
707
708 if (bytesReceived > 0)
709 {
710 try
711 {
712 buffer = new BYTE[bytesReceived];
713 }
714 catch (...)
715 {
716 buffer = NULL;
717 }
718
719 require_action( buffer, exit, err = kNoMemoryErr );
720
721 //
722 // this call gets the real info
723 //
724 ok = EnumPrinterDrivers(NULL, L"all", 6, buffer, bytesReceived, &bytesReceived, &numPrinters);
725 err = translate_errno( ok, errno_compat(), kUnknownErr );
726 require_noerr( err, exit );
727
728 DRIVER_INFO_6 * info = (DRIVER_INFO_6*) buffer;
729
730 for (DWORD i = 0; i < numPrinters; i++)
731 {
732 Manufacturer * manufacturer;
733 Model * model;
734 CString name;
735
736 //
737 // skip over anything that doesn't have a manufacturer field. This
67c8f8a1 738 // fixes a bug that I noticed that occurred after I installed
7f0064bd
A
739 // ProComm. This program add a print driver with no manufacturer
740 // that screwed up this wizard.
741 //
742 if (info[i].pszMfgName == NULL)
743 {
744 continue;
745 }
746
747 //
748 // look for manufacturer
749 //
750 Manufacturers::iterator iter;
751
752 //
753 // save the name
754 //
755 name = NormalizeManufacturerName( info[i].pszMfgName );
756
757 iter = manufacturers.find(name);
758
759 if (iter != manufacturers.end())
760 {
761 manufacturer = iter->second;
762 }
763 else
764 {
765 try
766 {
767 manufacturer = new Manufacturer;
768 }
769 catch (...)
770 {
771 manufacturer = NULL;
772 }
773
774 require_action( manufacturer, exit, err = kNoMemoryErr );
775
776 manufacturer->name = name;
777
778 manufacturers[name] = manufacturer;
779 }
780
781 //
782 // now look to see if we have already seen this guy. this could
783 // happen if we have already installed printers that are described
784 // in ntprint.inf. the extant drivers will show up in EnumPrinterDrivers
785 // but we have already loaded their info
786 //
787 //
788 if ( MatchModel( manufacturer, ConvertToModelName( info[i].pName ) ) == NULL )
789 {
790 try
791 {
792 model = new Model;
793 }
794 catch (...)
795 {
796 model = NULL;
797 }
798
799 require_action( model, exit, err = kNoMemoryErr );
800
7cb34e5c 801 model->displayName = info[i].pName;
7f0064bd
A
802 model->name = info[i].pName;
803 model->driverInstalled = true;
804
805 manufacturer->models.push_back(model);
806 }
807 }
808 }
809
810exit:
811
812 if (buffer != NULL)
813 {
814 delete [] buffer;
815 }
816
817 return err;
818}
819
7cb34e5c
A
820// -------------------------------------------------------
821// LoadGenericPrintDriverDefs
822//
823// This function is responsible for loading polymorphic
824// generic print drivers defs. The UI will read
825// something like "Generic / Postscript" and we can map
826// that to any print driver we want.
827// -------------------------------------------------------
828OSStatus
829CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers )
830{
831 Manufacturer * manufacturer;
832 Model * model;
833 Manufacturers::iterator iter;
834 CString psDriverName;
835 CString pclDriverName;
836 OSStatus err = 0;
837
838 // <rdar://problem/4030388> Generic drivers don't do color
839
840 // First try and find our generic driver names
841
4aea607d 842 iter = m_manufacturers.find(L"HP");
67c8f8a1 843 require_action( iter != m_manufacturers.end(), exit, err = kUnknownErr );
7cb34e5c
A
844 manufacturer = iter->second;
845
67c8f8a1 846 // Look for Postscript
7cb34e5c
A
847
848 model = manufacturer->find( kGenericPSColorDriver );
849
850 if ( !model )
851 {
852 model = manufacturer->find( kGenericPSDriver );
853 }
854
855 if ( model )
856 {
857 psDriverName = model->name;
7cb34e5c
A
858 }
859
860 // Look for PCL
861
862 model = manufacturer->find( kGenericPCLColorDriver );
863
864 if ( !model )
865 {
866 model = manufacturer->find( kGenericPCLDriver );
867 }
868
869 if ( model )
870 {
67c8f8a1 871 pclDriverName = model->name;
7cb34e5c
A
872 }
873
874 // If we found either a generic PS driver, or a generic PCL driver,
875 // then add them to the list
876
877 if ( psDriverName.GetLength() || pclDriverName.GetLength() )
878 {
879 // Try and find generic manufacturer if there is one
880
881 iter = manufacturers.find(L"Generic");
882
883 if (iter != manufacturers.end())
884 {
885 manufacturer = iter->second;
886 }
887 else
888 {
889 try
890 {
891 manufacturer = new Manufacturer;
892 }
893 catch (...)
894 {
895 manufacturer = NULL;
896 }
897
898 require_action( manufacturer, exit, err = kNoMemoryErr );
899
900 manufacturer->name = "Generic";
901 manufacturers[manufacturer->name] = manufacturer;
902 }
903
904 if ( psDriverName.GetLength() > 0 )
905 {
906 try
907 {
908 m_genericPostscript = new Model;
909 }
910 catch (...)
911 {
912 m_genericPostscript = NULL;
913 }
914
915 require_action( m_genericPostscript, exit, err = kNoMemoryErr );
916
917 m_genericPostscript->displayName = kGenericPostscript;
918 m_genericPostscript->name = psDriverName;
919 m_genericPostscript->driverInstalled = false;
920
921 manufacturer->models.push_back( m_genericPostscript );
922 }
923
924 if ( pclDriverName.GetLength() > 0 )
925 {
926 try
927 {
928 m_genericPCL = new Model;
929 }
930 catch (...)
931 {
932 m_genericPCL = NULL;
933 }
934
935 require_action( m_genericPCL, exit, err = kNoMemoryErr );
936
937 m_genericPCL->displayName = kGenericPCL;
938 m_genericPCL->name = pclDriverName;
939 m_genericPCL->driverInstalled = false;
940
941 manufacturer->models.push_back( m_genericPCL );
942 }
943 }
944
945exit:
946
947 return err;
948}
949
7f0064bd
A
950// ------------------------------------------------------
951// ConvertToManufacturerName
952//
67c8f8a1 953// This function is responsible for tweaking the
7f0064bd
A
954// name so that subsequent string operations won't fail because
955// of capitalizations/different names for the same manufacturer
956// (i.e. Hewlett-Packard/HP/Hewlett Packard)
957//
958CString
959CThirdPage::ConvertToManufacturerName( const CString & name )
960{
961 //
962 // first we're going to convert all the characters to lower
963 // case
964 //
965 CString lower = name;
966 lower.MakeLower();
967
968 //
969 // now we're going to check to see if the string says "hewlett-packard",
970 // because sometimes they refer to themselves as "hewlett-packard", and
971 // sometimes they refer to themselves as "hp".
972 //
973 if ( lower == L"hewlett-packard")
974 {
975 lower = "hp";
976 }
977
978 //
979 // tweak for Xerox Phaser, which doesn't announce itself
980 // as a xerox
981 //
982 else if ( lower.Find( L"phaser", 0 ) != -1 )
983 {
984 lower = "xerox";
985 }
986
987 return lower;
988}
989
7f0064bd
A
990// ------------------------------------------------------
991// ConvertToModelName
992//
993// This function is responsible for ensuring that subsequent
994// string operations don't fail because of differing capitalization
995// schemes and the like
996// ------------------------------------------------------
997
998CString
999CThirdPage::ConvertToModelName( const CString & name )
1000{
1001 //
1002 // convert it to lowercase
1003 //
1004 CString lower = name;
1005 lower.MakeLower();
1006
1007 return lower;
1008}
1009
7f0064bd
A
1010// ------------------------------------------------------
1011// NormalizeManufacturerName
1012//
1013// This function is responsible for tweaking the manufacturer
1014// name so that there are no aliases for vendors
1015//
1016CString
1017CThirdPage::NormalizeManufacturerName( const CString & name )
1018{
1019 CString normalized = name;
1020
1021 //
1022 // now we're going to check to see if the string says "hewlett-packard",
1023 // because sometimes they refer to themselves as "hewlett-packard", and
1024 // sometimes they refer to themselves as "hp".
1025 //
1026 if ( normalized == L"Hewlett-Packard")
1027 {
1028 normalized = "HP";
1029 }
1030
1031 return normalized;
1032}
1033
7f0064bd
A
1034// -------------------------------------------------------
1035// MatchPrinter
1036//
1037// This function is responsible for matching a printer
1038// to a list of manufacturers and models. It calls
1039// MatchManufacturer and MatchModel in turn.
1040//
1041
4aea607d 1042OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * printer, Service * service, bool useCUPSWorkaround)
7f0064bd
A
1043{
1044 CString normalizedProductName;
7cb34e5c
A
1045 Manufacturer * manufacturer = NULL;
1046 Manufacturer * genericManufacturer = NULL;
1047 Model * model = NULL;
1048 Model * genericModel = NULL;
1049 bool found = false;
7f0064bd 1050 CString text;
7cb34e5c 1051 OSStatus err = kNoErr;
7f0064bd 1052
4aea607d
A
1053 check( printer );
1054 check( service );
1055
1056 Queue * q = service->SelectedQueue();
1057
1058 check( q );
1059
7f0064bd
A
1060 //
1061 // first look to see if we have a usb_MFG descriptor
1062 //
4aea607d 1063 if ( q->usb_MFG.GetLength() > 0)
7f0064bd 1064 {
4aea607d 1065 manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( q->usb_MFG ) );
7f0064bd
A
1066 }
1067
1068 if ( manufacturer == NULL )
1069 {
4aea607d
A
1070 q->product.Remove('(');
1071 q->product.Remove(')');
7f0064bd 1072
4aea607d 1073 manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( q->product ) );
7f0064bd
A
1074 }
1075
1076 //
1077 // if we found the manufacturer, then start looking for the model
1078 //
1079 if ( manufacturer != NULL )
1080 {
4aea607d 1081 if ( q->usb_MDL.GetLength() > 0 )
7f0064bd 1082 {
4aea607d 1083 model = MatchModel ( manufacturer, ConvertToModelName ( q->usb_MDL ) );
7f0064bd
A
1084 }
1085
4aea607d 1086 if ( ( model == NULL ) && ( q->product.GetLength() > 0 ) )
7f0064bd 1087 {
4aea607d
A
1088 q->product.Remove('(');
1089 q->product.Remove(')');
7f0064bd 1090
4aea607d 1091 model = MatchModel ( manufacturer, ConvertToModelName ( q->product ) );
7f0064bd
A
1092 }
1093
1094 if ( model != NULL )
1095 {
4aea607d
A
1096 // <rdar://problem/4124524> Offer Generic printers if printer advertises Postscript or PCL. Workaround
1097 // bug in OS X CUPS printer sharing by selecting Generic driver instead of matched printer.
1098
1099 bool hasGenericDriver = false;
1100
1101 if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
1102 {
1103 hasGenericDriver = true;
1104 }
1105
67c8f8a1 1106 // <rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS
4aea607d
A
1107 // shared queue supports raw
1108
1109 if ( q->pdl.Find( L"application/octet-stream" ) != -1 )
1110 {
1111 useCUPSWorkaround = false;
1112 }
1113
1114 if ( useCUPSWorkaround && printer->isSharedFromOSX && hasGenericDriver )
1115 {
67c8f8a1
A
1116 //
1117 // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
1118 //
1119 Manufacturers genericManufacturers;
1120
1121 LoadGenericPrintDriverDefs( genericManufacturers );
1122
1123 SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
4aea607d
A
1124 }
1125 else
1126 {
1127 SelectMatch(manufacturers, printer, service, manufacturer, model);
1128 }
1129
7f0064bd
A
1130 found = true;
1131 }
1132 }
1133
1134 //
1135 // display a message to the user based on whether we could match
1136 // this printer
1137 //
1138 if (found)
1139 {
1140 text.LoadString(IDS_PRINTER_MATCH_GOOD);
1a175162 1141 err = kNoErr;
7f0064bd 1142 }
4aea607d 1143 else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
67c8f8a1 1144 {
4aea607d 1145 if ( printer->isSharedFromOSX )
7cb34e5c 1146 {
67c8f8a1
A
1147 //
1148 // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
1149 //
1150 Manufacturers genericManufacturers;
1151
1152 LoadGenericPrintDriverDefs( genericManufacturers );
1153
1154 SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
1155
4aea607d 1156 text.LoadString(IDS_PRINTER_MATCH_GOOD);
7cb34e5c
A
1157 }
1158 else
1159 {
67c8f8a1 1160 SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel );
4aea607d 1161 text.LoadString(IDS_PRINTER_MATCH_MAYBE);
7cb34e5c 1162 }
1a175162
A
1163
1164 err = kNoErr;
7cb34e5c 1165 }
7f0064bd
A
1166 else
1167 {
1168 text.LoadString(IDS_PRINTER_MATCH_BAD);
1169
1170 //
1171 // if there was any crud in this list from before, get rid of it now
1172 //
1173 m_modelListCtrl.DeleteAllItems();
1174
1175 //
1176 // select the manufacturer if we found one
1177 //
1178 if (manufacturer != NULL)
1179 {
1180 LVFINDINFO info;
1181 int nIndex;
1182
1183 //
1184 // select the manufacturer
1185 //
1186 info.flags = LVFI_STRING;
1187 info.psz = manufacturer->name;
1188
1189 nIndex = m_manufacturerListCtrl.FindItem(&info);
1190
1191 if (nIndex != -1)
1192 {
1193 m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
67c8f8a1
A
1194
1195 //
1196 //<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
1197 //
1198 AutoScroll(m_manufacturerListCtrl, nIndex);
7f0064bd
A
1199 }
1200 }
1a175162
A
1201
1202 err = kUnknownErr;
7f0064bd
A
1203 }
1204
1205 m_printerSelectionText.SetWindowText(text);
1206
1207 return err;
1208}
1209
7f0064bd
A
1210// ------------------------------------------------------
1211// MatchManufacturer
1212//
1213// This function is responsible for finding a manufacturer
1214// object from a string name. It does a CString::Find, which
1215// is like strstr, so it doesn't have to do an exact match
1216//
1217// If it can't find a match, NULL is returned
1218// ------------------------------------------------------
1219
1220Manufacturer*
1221CThirdPage::MatchManufacturer( Manufacturers & manufacturers, const CString & name)
1222{
1223 Manufacturers::iterator iter;
1224
1225 for (iter = manufacturers.begin(); iter != manufacturers.end(); iter++)
1226 {
1227 //
1228 // we're going to convert all the manufacturer names to lower case,
1229 // so we match the name passed in.
1230 //
1231 CString lower = iter->second->name;
1232 lower.MakeLower();
1233
1234 //
1235 // now try and find the lowered string in the name passed in.
283ee3ff
A
1236 //
1237 if (name.Find(lower) != -1)
7f0064bd
A
1238 {
1239 return iter->second;
1240 }
1241 }
1242
1243 return NULL;
1244}
1245
7f0064bd
A
1246// -------------------------------------------------------
1247// MatchModel
1248//
1249// This function is responsible for matching a model from
1250// a name. It does a CString::Find(), which works like strstr,
1251// so it doesn't rely on doing an exact string match.
1252//
1253
1254Model*
1255CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name)
1256{
1257 Models::iterator iter;
1258
1259 iter = manufacturer->models.begin();
1260
1261 for (iter = manufacturer->models.begin(); iter != manufacturer->models.end(); iter++)
1262 {
1263 Model * model = *iter;
1264
1265 //
1266 // convert the model name to lower case
1267 //
1268 CString lowered = model->name;
1269 lowered.MakeLower();
1270
1271 if (lowered.Find( name ) != -1)
1272 {
1273 return model;
1274 }
283ee3ff
A
1275
1276 //
1277 // <rdar://problem/3841218>
1278 // try removing the first substring and search again
1279 //
1280
1281 if ( name.Find(' ') != -1 )
1282 {
1283 CString altered = name;
1284 altered.Delete( 0, altered.Find(' ') + 1 );
1285
1286 if ( lowered.Find( altered ) != -1 )
1287 {
1288 return model;
1289 }
1290 }
7f0064bd
A
1291 }
1292
1293 return NULL;
1294}
1295
7cb34e5c
A
1296// -------------------------------------------------------
1297// MatchGeneric
1298//
1299// This function will attempt to find a generic printer
1300// driver for a printer that we weren't able to match
1301// specifically
1302//
1303BOOL
4aea607d 1304CThirdPage::MatchGeneric( Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer ** manufacturer, Model ** model )
7cb34e5c
A
1305{
1306 CString pdl;
1307 BOOL ok = FALSE;
1308
1309 DEBUG_UNUSED( printer );
1310
4aea607d
A
1311 check( service );
1312
1313 Queue * q = service->SelectedQueue();
1314
1315 check( q );
1316
1317 Manufacturers::iterator iter = manufacturers.find( kGenericManufacturer );
1318 require_action_quiet( iter != manufacturers.end(), exit, ok = FALSE );
7cb34e5c
A
1319
1320 *manufacturer = iter->second;
1321
4aea607d 1322 pdl = q->pdl;
7cb34e5c
A
1323 pdl.MakeLower();
1324
67c8f8a1 1325 if ( m_genericPCL && ( pdl.Find( kPDLPCLKey ) != -1 ) )
7cb34e5c
A
1326 {
1327 *model = m_genericPCL;
1328 ok = TRUE;
1329 }
67c8f8a1 1330 else if ( m_genericPostscript && ( pdl.Find( kPDLPostscriptKey ) != -1 ) )
7cb34e5c
A
1331 {
1332 *model = m_genericPostscript;
1333 ok = TRUE;
1334 }
1335
1336exit:
1337
1338 return ok;
1339}
1340
7f0064bd
A
1341// -----------------------------------------------------------
1342// OnInitPage
1343//
1344// This function is responsible for doing initialization that
1345// only occurs once during a run of the wizard
1346//
1347
1348OSStatus CThirdPage::OnInitPage()
1349{
7cb34e5c
A
1350 CString header;
1351 CString ntPrint;
1352 OSStatus err = kNoErr;
1353
1354 // Load printer icon
283ee3ff 1355 check( m_printerImage == NULL );
7f0064bd 1356
67c8f8a1 1357 m_printerImage = (CStatic*) GetDlgItem( 1 ); // 1 == IDR_MANIFEST
283ee3ff
A
1358 check( m_printerImage );
1359
1360 if ( m_printerImage != NULL )
1361 {
1362 m_printerImage->SetIcon( LoadIcon( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_PRINTER ) ) );
1363 }
7f0064bd
A
1364
1365 //
1366 // The CTreeCtrl widget automatically sends a selection changed
1367 // message which initially we want to ignore, because the user
1368 // hasn't selected anything
1369 //
1370 // this flag gets reset in the message handler. Every subsequent
1371 // message gets handled.
1372 //
1373
1374 //
67c8f8a1 1375 // we have to make sure that we only do this once. Typically,
7f0064bd
A
1376 // we would do this in something like OnInitDialog, but we don't
1377 // have this in Wizards, because the window is a PropertySheet.
1378 // We're considered fully initialized when we receive the first
1379 // selection notice
1380 //
1381 header.LoadString(IDS_MANUFACTURER_HEADING);
4aea607d 1382 m_manufacturerListCtrl.InsertColumn(0, header, LVCFMT_LEFT, -1 );
7f0064bd
A
1383 m_manufacturerSelected = NULL;
1384
1385 header.LoadString(IDS_MODEL_HEADING);
4aea607d 1386 m_modelListCtrl.InsertColumn(0, header, LVCFMT_LEFT, -1 );
7f0064bd
A
1387 m_modelSelected = NULL;
1388
7f0064bd
A
1389 return (err);
1390}
1391
7f0064bd
A
1392void CThirdPage::DoDataExchange(CDataExchange* pDX)
1393{
1394 CPropertyPage::DoDataExchange(pDX);
1395 DDX_Control(pDX, IDC_PRINTER_MANUFACTURER, m_manufacturerListCtrl);
1396 DDX_Control(pDX, IDC_PRINTER_MODEL, m_modelListCtrl);
1397 DDX_Control(pDX, IDC_PRINTER_NAME, m_printerName);
1398 DDX_Control(pDX, IDC_DEFAULT_PRINTER, m_defaultPrinterCtrl);
7cb34e5c
A
1399 DDX_Control(pDX, IDC_PRINTER_SELECTION_TEXT, m_printerSelectionText);
1400
7f0064bd
A
1401}
1402
7f0064bd
A
1403// ----------------------------------------------------------
1404// OnSetActive
1405//
1406// This function is called by MFC after the window has been
1407// activated.
1408//
1409
1410BOOL
1411CThirdPage::OnSetActive()
1412{
1413 CPrinterSetupWizardSheet * psheet;
1414 Printer * printer;
283ee3ff 1415 Service * service;
7f0064bd
A
1416
1417 psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
1418 require_quiet( psheet, exit );
1419
4aea607d 1420 psheet->SetWizardButtons( PSWIZB_BACK );
7f0064bd
A
1421
1422 printer = psheet->GetSelectedPrinter();
1423 require_quiet( printer, exit );
1424
283ee3ff
A
1425 service = printer->services.front();
1426 require_quiet( service, exit );
1427
7f0064bd
A
1428 //
1429 // call OnInitPage once
1430 //
1431 if (!m_initialized)
1432 {
1433 OnInitPage();
1434 m_initialized = true;
1435 }
1436
67c8f8a1
A
1437 //
1438 // <rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
1439 //
1440 if ( DefaultPrinterExists() )
1441 {
1442 m_defaultPrinterCtrl.SetCheck( BST_UNCHECKED );
1443 printer->deflt = false;
1444 }
1445 else
1446 {
1447 m_defaultPrinterCtrl.SetCheck( BST_CHECKED );
1448 printer->deflt = true;
1449 }
1450
7f0064bd
A
1451 //
1452 // update the UI with the printer name
1453 //
1454 m_printerName.SetWindowText(printer->displayName);
1455
1456 //
1457 // populate the list controls with the manufacturers and models
1458 // from ntprint.inf
1459 //
1460 PopulateUI( m_manufacturers );
1461
1462 //
1463 // and try and match the printer
1464 //
4aea607d 1465
32bb7e43 1466 if ( psheet->GetLastPage() == psheet->GetPage(0) )
4aea607d
A
1467 {
1468 MatchPrinter( m_manufacturers, printer, service, true );
32bb7e43
A
1469
1470 if ( ( m_manufacturerSelected != NULL ) && ( m_modelSelected != NULL ) )
1471 {
1472 GetParent()->PostMessage(PSM_SETCURSEL, 2 );
1473 }
4aea607d
A
1474 }
1475 else
1476 {
1477 SelectMatch(printer, service, m_manufacturerSelected, m_modelSelected);
1478 }
7f0064bd
A
1479
1480exit:
1481
1482 return CPropertyPage::OnSetActive();
1483}
1484
4aea607d
A
1485BOOL
1486CThirdPage::OnKillActive()
1487{
1488 CPrinterSetupWizardSheet * psheet;
1489
1490 psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
67c8f8a1 1491 require_quiet( psheet, exit );
4aea607d
A
1492
1493 psheet->SetLastPage(this);
1494
1495exit:
1496
1497 return CPropertyPage::OnKillActive();
1498}
1499
7f0064bd
A
1500// -------------------------------------------------------
1501// PopulateUI
1502//
1503// This function is called to populate the list of manufacturers
1504//
1505OSStatus
1506CThirdPage::PopulateUI(Manufacturers & manufacturers)
1507{
1508 Manufacturers::iterator iter;
1509
1510 m_manufacturerListCtrl.DeleteAllItems();
1511
1512 for (iter = manufacturers.begin(); iter != manufacturers.end(); iter++)
1513 {
1514 int nIndex;
1515
1516 Manufacturer * manufacturer = iter->second;
1517
1518 nIndex = m_manufacturerListCtrl.InsertItem(0, manufacturer->name);
1519
1520 m_manufacturerListCtrl.SetItemData(nIndex, (DWORD_PTR) manufacturer);
4aea607d
A
1521
1522 m_manufacturerListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE_USEHEADER );
7f0064bd
A
1523 }
1524
1525 return 0;
1526}
1527
7f0064bd
A
1528BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage)
1529 ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MANUFACTURER, OnLvnItemchangedManufacturer)
1530 ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MODEL, OnLvnItemchangedPrinterModel)
1531 ON_BN_CLICKED(IDC_DEFAULT_PRINTER, OnBnClickedDefaultPrinter)
1532 ON_BN_CLICKED(IDC_HAVE_DISK, OnBnClickedHaveDisk)
1533END_MESSAGE_MAP()
1534
7f0064bd
A
1535// CThirdPage message handlers
1536void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult)
1537{
1538 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
1539
1540 POSITION p = m_manufacturerListCtrl.GetFirstSelectedItemPosition();
1541 int nSelected = m_manufacturerListCtrl.GetNextSelectedItem(p);
1542
1543 if (nSelected != -1)
1544 {
1545 m_manufacturerSelected = (Manufacturer*) m_manufacturerListCtrl.GetItemData(nSelected);
1546
1547 m_modelListCtrl.SetRedraw(FALSE);
1548
1549 m_modelListCtrl.DeleteAllItems();
1550 m_modelSelected = NULL;
1551
1552 Models::iterator iter;
1553
1554 for (iter = m_manufacturerSelected->models.begin(); iter != m_manufacturerSelected->models.end(); iter++)
1555 {
1556 Model * model = *iter;
1557
7cb34e5c 1558 int nItem = m_modelListCtrl.InsertItem( 0, model->displayName );
7f0064bd
A
1559
1560 m_modelListCtrl.SetItemData(nItem, (DWORD_PTR) model);
4aea607d
A
1561
1562 m_modelListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE_USEHEADER );
7f0064bd
A
1563 }
1564
1565 m_modelListCtrl.SetRedraw(TRUE);
1566 }
1567
1568 *pResult = 0;
1569}
1570
1571void CThirdPage::OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult)
1572{
1573 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
1574
1575 CPrinterSetupWizardSheet * psheet;
1576 Printer * printer;
283ee3ff 1577 Service * service;
7f0064bd
A
1578
1579 psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
1580 require_quiet( psheet, exit );
1581
1582 printer = psheet->GetSelectedPrinter();
1583 require_quiet( printer, exit );
1584
283ee3ff
A
1585 service = printer->services.front();
1586 require_quiet( service, exit );
1587
7f0064bd
A
1588 check ( m_manufacturerSelected );
1589
1590 POSITION p = m_modelListCtrl.GetFirstSelectedItemPosition();
1591 int nSelected = m_modelListCtrl.GetNextSelectedItem(p);
1592
1593 if (nSelected != -1)
1594 {
1595 m_modelSelected = (Model*) m_modelListCtrl.GetItemData(nSelected);
1596
283ee3ff 1597 CopyPrinterSettings( printer, service, m_manufacturerSelected, m_modelSelected );
7f0064bd
A
1598
1599 psheet->SetWizardButtons(PSWIZB_BACK|PSWIZB_NEXT);
1600 }
1601 else
1602 {
1603 psheet->SetWizardButtons(PSWIZB_BACK);
1604 }
1605
1606exit:
1607
1608 *pResult = 0;
1609}
1610
7f0064bd
A
1611void CThirdPage::OnBnClickedDefaultPrinter()
1612{
1613 CPrinterSetupWizardSheet * psheet;
1614 Printer * printer;
1615
1616 psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
1617 require_quiet( psheet, exit );
1618
1619 printer = psheet->GetSelectedPrinter();
1620 require_quiet( printer, exit );
1621
4aea607d 1622 printer->deflt = ( m_defaultPrinterCtrl.GetCheck() == BST_CHECKED ) ? true : false;
7f0064bd
A
1623
1624exit:
1625
1626 return;
1627}
1628
1629void CThirdPage::OnBnClickedHaveDisk()
1630{
1631 CPrinterSetupWizardSheet * psheet;
1632 Printer * printer;
283ee3ff 1633 Service * service;
4aea607d 1634 Manufacturers manufacturers;
7f0064bd
A
1635
1636 CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, L"Setup Information (*.inf)|*.inf||", this);
1637
1638 psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
1639 require_quiet( psheet, exit );
1640
1641 printer = psheet->GetSelectedPrinter();
1642 require_quiet( printer, exit );
1643
283ee3ff
A
1644 service = printer->services.front();
1645 require_quiet( service, exit );
1646
4aea607d 1647 for ( ;; )
7f0064bd 1648 {
4aea607d
A
1649 if ( dlg.DoModal() == IDOK )
1650 {
1651 CString filename = dlg.GetPathName();
7f0064bd 1652
4aea607d 1653 LoadPrintDriverDefsFromFile( manufacturers, filename, true );
7f0064bd 1654
4aea607d 1655 // Sanity check
7f0064bd 1656
4aea607d
A
1657 if ( manufacturers.size() > 0 )
1658 {
1659 PopulateUI( manufacturers );
1660
1a175162
A
1661 if ( MatchPrinter( manufacturers, printer, service, false ) != kNoErr )
1662 {
1663 CString errorMessage;
1664 CString errorCaption;
1665
1666 errorMessage.LoadString( IDS_NO_MATCH_INF_FILE );
1667 errorCaption.LoadString( IDS_NO_MATCH_INF_FILE_CAPTION );
1668
1669 MessageBox( errorMessage, errorCaption, MB_OK );
1670 }
4aea607d
A
1671
1672 break;
1673 }
32bb7e43
A
1674 else
1675 {
1676 CString errorMessage;
1677 CString errorCaption;
1678
1679 errorMessage.LoadString( IDS_BAD_INF_FILE );
1680 errorCaption.LoadString( IDS_BAD_INF_FILE_CAPTION );
1681
1682 MessageBox( errorMessage, errorCaption, MB_OK );
1683 }
4aea607d
A
1684 }
1685 else
1686 {
1687 break;
1688 }
7f0064bd
A
1689 }
1690
1691exit:
1692
1693 return;
1694}
32bb7e43
A
1695
1696
1697void
1698CThirdPage::Split( const CString & string, TCHAR ch, CStringList & components )
1699{
1700 CString temp;
1701 int n;
1702
1703 temp = string;
1704
1705 while ( ( n = temp.Find( ch ) ) != -1 )
1706 {
1707 components.AddTail( temp.Left( n ) );
1708 temp = temp.Right( temp.GetLength() - ( n + 1 ) );
1709 }
1710
1711 components.AddTail( temp );
1712}