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