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