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