]>
Commit | Line | Data |
---|---|---|
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 | ||
58 | IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage) | |
59 | CThirdPage::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 | ||
136 | exit: | |
137 | ||
138 | return; | |
7f0064bd A |
139 | } |
140 | ||
263eeeab A |
141 | |
142 | void | |
143 | CThirdPage::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 | |
157 | CThirdPage::~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 | // ---------------------------------------------------- | |
171 | void | |
4aea607d | 172 | CThirdPage::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 |
217 | void |
218 | CThirdPage::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 | ||
232 | void | |
283ee3ff | 233 | CThirdPage::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 | // -------------------------------------------------------- | |
300 | BOOL | |
301 | CThirdPage::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 | // -------------------------------------------------------- | |
315 | void | |
316 | CThirdPage::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 | ||
362 | OSStatus | |
363 | CThirdPage::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 | ||
540 | exit: | |
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 | // ------------------------------------------------------- | |
559 | OSStatus | |
560 | CThirdPage::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 | ||
676 | exit: | |
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 | // ------------------------------------------------------- | |
694 | OSStatus | |
695 | CThirdPage::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 | ||
811 | exit: | |
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 | // | |
824 | CString | |
825 | CThirdPage::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 | ||
864 | CString | |
865 | CThirdPage::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 | // | |
882 | CString | |
883 | CThirdPage::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 | 908 | OSStatus 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 | ||
1090 | Manufacturer* | |
1091 | CThirdPage::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 | ||
1124 | Model* | |
1125 | CThirdPage::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 | // | |
1173 | BOOL | |
4aea607d | 1174 | CThirdPage::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 | ||
1206 | exit: | |
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 | ||
1218 | OSStatus 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 |
1262 | void 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 | ||
1280 | BOOL | |
1281 | CThirdPage::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 | |
1350 | exit: | |
1351 | ||
1352 | return CPropertyPage::OnSetActive(); | |
1353 | } | |
1354 | ||
4aea607d A |
1355 | BOOL |
1356 | CThirdPage::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 | ||
1365 | exit: | |
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 | // | |
1375 | OSStatus | |
1376 | CThirdPage::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 |
1398 | BEGIN_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) | |
1403 | END_MESSAGE_MAP() | |
1404 | ||
7f0064bd A |
1405 | // CThirdPage message handlers |
1406 | void 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 | ||
1441 | void 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 | ||
1476 | exit: | |
1477 | ||
1478 | *pResult = 0; | |
1479 | } | |
1480 | ||
7f0064bd A |
1481 | void 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 | |
1494 | exit: | |
1495 | ||
1496 | return; | |
1497 | } | |
1498 | ||
1499 | void 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 | ||
1561 | exit: | |
1562 | ||
263eeeab | 1563 | FreeManufacturers( manufacturers ); |
7f0064bd A |
1564 | return; |
1565 | } | |
32bb7e43 A |
1566 | |
1567 | ||
1568 | void | |
1569 | CThirdPage::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 | } |