mirror of
https://git.rtems.org/rtems-libbsd/
synced 2025-06-12 04:33:36 +08:00

The sources can be obtained via: http://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-544.tar.gz
1584 lines
38 KiB
C++
1584 lines
38 KiB
C++
/* -*- Mode: C; tab-width: 4 -*-
|
|
*
|
|
* Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "PrinterSetupWizardApp.h"
|
|
#include "PrinterSetupWizardSheet.h"
|
|
#include "ThirdPage.h"
|
|
#include "tcpxcv.h"
|
|
#include <dns_sd.h>
|
|
#include <winspool.h>
|
|
#include <setupapi.h>
|
|
|
|
// local variable is initialize but not referenced
|
|
#pragma warning(disable:4189)
|
|
|
|
//
|
|
// This is the printer description file that is shipped
|
|
// with Windows XP and below
|
|
//
|
|
#define kNTPrintFile L"inf\\ntprint.inf"
|
|
|
|
//
|
|
// Windows Vista ships with a set of prn*.inf files
|
|
//
|
|
#define kVistaPrintFiles L"inf\\prn*.inf"
|
|
|
|
//
|
|
// These are pre-defined names for Generic manufacturer and model
|
|
//
|
|
#define kGenericManufacturer L"Generic"
|
|
#define kGenericText L"Generic / Text Only"
|
|
#define kGenericPostscript L"Generic / Postscript"
|
|
#define kGenericPCL L"Generic / PCL"
|
|
#define kPDLPostscriptKey L"application/postscript"
|
|
#define kPDLPCLKey L"application/vnd.hp-pcl"
|
|
#define kGenericPSColorDriver L"HP Color LaserJet 4550 PS"
|
|
#define kGenericPSDriver L"HP LaserJet 4050 Series PS"
|
|
#define kGenericPCLColorDriver L"HP Color LaserJet 4550 PCL"
|
|
#define kGenericPCLDriver L"HP LaserJet 4050 Series PCL"
|
|
|
|
|
|
// CThirdPage dialog
|
|
|
|
IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage)
|
|
CThirdPage::CThirdPage()
|
|
: CPropertyPage(CThirdPage::IDD),
|
|
m_manufacturerSelected( NULL ),
|
|
m_modelSelected( NULL ),
|
|
m_genericPostscript( NULL ),
|
|
m_genericPCL( NULL ),
|
|
m_initialized(false),
|
|
m_printerImage( NULL )
|
|
{
|
|
static const int bufferSize = 32768;
|
|
TCHAR windowsDirectory[bufferSize];
|
|
CString header;
|
|
WIN32_FIND_DATA findFileData;
|
|
HANDLE findHandle;
|
|
CString prnFiles;
|
|
CString ntPrint;
|
|
OSStatus err;
|
|
BOOL ok;
|
|
|
|
m_psp.dwFlags &= ~(PSP_HASHELP);
|
|
m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
|
|
|
|
m_psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_INSTALL_TITLE);
|
|
m_psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_INSTALL_SUBTITLE);
|
|
|
|
//
|
|
// load printers from ntprint.inf
|
|
//
|
|
ok = GetWindowsDirectory( windowsDirectory, bufferSize );
|
|
err = translate_errno( ok, errno_compat(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
|
|
//
|
|
// <rdar://problem/4826126>
|
|
//
|
|
// If there are no *prn.inf files, we'll assume that the information
|
|
// is in ntprint.inf
|
|
//
|
|
prnFiles.Format( L"%s\\%s", windowsDirectory, kVistaPrintFiles );
|
|
findHandle = FindFirstFile( prnFiles, &findFileData );
|
|
|
|
if ( findHandle != INVALID_HANDLE_VALUE )
|
|
{
|
|
CString absolute;
|
|
|
|
absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
|
|
err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
|
|
require_noerr( err, exit );
|
|
|
|
while ( FindNextFile( findHandle, &findFileData ) )
|
|
{
|
|
absolute.Format( L"%s\\inf\\%s", windowsDirectory, findFileData.cFileName );
|
|
err = LoadPrintDriverDefsFromFile( m_manufacturers, absolute, false );
|
|
require_noerr( err, exit );
|
|
}
|
|
|
|
FindClose( findHandle );
|
|
}
|
|
else
|
|
{
|
|
ntPrint.Format(L"%s\\%s", windowsDirectory, kNTPrintFile);
|
|
err = LoadPrintDriverDefsFromFile( m_manufacturers, ntPrint, false );
|
|
require_noerr(err, exit);
|
|
}
|
|
|
|
//
|
|
// load printer drivers that have been installed on this machine
|
|
//
|
|
err = LoadPrintDriverDefs( m_manufacturers );
|
|
require_noerr(err, exit);
|
|
|
|
//
|
|
// load our own special generic printer defs
|
|
//
|
|
err = LoadGenericPrintDriverDefs( m_manufacturers );
|
|
require_noerr( err, exit );
|
|
|
|
exit:
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
CThirdPage::FreeManufacturers( Manufacturers & manufacturers )
|
|
{
|
|
for ( Manufacturers::iterator it = manufacturers.begin(); it != manufacturers.end(); it++ )
|
|
{
|
|
for ( Models::iterator it2 = it->second->models.begin(); it2 != it->second->models.end(); it2++ )
|
|
{
|
|
delete *it2;
|
|
}
|
|
|
|
delete it->second;
|
|
}
|
|
}
|
|
|
|
|
|
CThirdPage::~CThirdPage()
|
|
{
|
|
FreeManufacturers( m_manufacturers );
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
// SelectMatch
|
|
//
|
|
// SelectMatch will do all the UI work associated with
|
|
// selected a manufacturer and model of printer. It also
|
|
// makes sure the printer object is update with the
|
|
// latest settings
|
|
//
|
|
// ----------------------------------------------------
|
|
void
|
|
CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model)
|
|
{
|
|
LVFINDINFO info;
|
|
int nIndex;
|
|
|
|
check( printer != NULL );
|
|
check( manufacturer != NULL );
|
|
check( model != NULL );
|
|
|
|
//
|
|
// select the manufacturer
|
|
//
|
|
info.flags = LVFI_STRING;
|
|
info.psz = manufacturer->name;
|
|
|
|
nIndex = m_manufacturerListCtrl.FindItem(&info);
|
|
|
|
if (nIndex != -1)
|
|
{
|
|
m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
|
|
//
|
|
//<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
|
|
//
|
|
AutoScroll(m_manufacturerListCtrl, nIndex);
|
|
}
|
|
|
|
//
|
|
// select the model
|
|
//
|
|
info.flags = LVFI_STRING;
|
|
info.psz = model->displayName;
|
|
|
|
nIndex = m_modelListCtrl.FindItem(&info);
|
|
|
|
if (nIndex != -1)
|
|
{
|
|
m_modelListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
|
|
AutoScroll( m_modelListCtrl, nIndex );
|
|
|
|
m_modelListCtrl.SetFocus();
|
|
}
|
|
|
|
CopyPrinterSettings( printer, service, manufacturer, model );
|
|
}
|
|
|
|
void
|
|
CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer * manufacturer, Model * model)
|
|
{
|
|
PopulateUI( manufacturers );
|
|
|
|
SelectMatch( printer, service, manufacturer, model );
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// CopyPrinterSettings
|
|
//
|
|
// This function makes sure that the printer object has the
|
|
// latest settings from the manufacturer and model objects
|
|
// --------------------------------------------------------
|
|
|
|
void
|
|
CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufacturer * manufacturer, Model * model )
|
|
{
|
|
DWORD portNameLen;
|
|
|
|
printer->manufacturer = manufacturer->name;
|
|
printer->displayModelName = model->displayName;
|
|
printer->modelName = model->name;
|
|
printer->driverInstalled = model->driverInstalled;
|
|
printer->infFileName = model->infFileName;
|
|
|
|
if ( service->type == kPDLServiceType )
|
|
{
|
|
printer->portName.Format(L"IP_%s.%d", static_cast<LPCTSTR>(service->hostname), service->portNumber);
|
|
service->protocol = L"Raw";
|
|
}
|
|
else if ( service->type == kLPRServiceType )
|
|
{
|
|
Queue * q = service->queues.front();
|
|
check( q );
|
|
|
|
if ( q->name.GetLength() > 0 )
|
|
{
|
|
printer->portName.Format(L"LPR_%s.%d.%s", static_cast<LPCTSTR>(service->hostname), service->portNumber, static_cast<LPCTSTR>(q->name) );
|
|
}
|
|
else
|
|
{
|
|
printer->portName.Format(L"LPR_%s.%d", static_cast<LPCTSTR>(service->hostname), service->portNumber);
|
|
}
|
|
|
|
service->protocol = L"LPR";
|
|
}
|
|
else if ( service->type == kIPPServiceType )
|
|
{
|
|
Queue * q = service->queues.front();
|
|
check( q );
|
|
|
|
if ( q->name.GetLength() > 0 )
|
|
{
|
|
printer->portName.Format(L"http://%s:%d/%s", static_cast<LPCTSTR>(service->hostname), service->portNumber, static_cast<LPCTSTR>(q->name) );
|
|
}
|
|
else
|
|
{
|
|
printer->portName.Format(L"http://%s:%d/", static_cast<LPCTSTR>(service->hostname), service->portNumber );
|
|
}
|
|
|
|
service->protocol = L"IPP";
|
|
}
|
|
|
|
// If it's not an IPP printr, truncate the portName so that it's valid
|
|
|
|
if ( service->type != kIPPServiceType )
|
|
{
|
|
portNameLen = printer->portName.GetLength() + 1;
|
|
|
|
if ( portNameLen > MAX_PORTNAME_LEN )
|
|
{
|
|
printer->portName.Delete( MAX_PORTNAME_LEN - 1, ( portNameLen - MAX_PORTNAME_LEN ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// DefaultPrinterExists
|
|
//
|
|
// Checks to see if a default printer has been configured
|
|
// on this machine
|
|
// --------------------------------------------------------
|
|
BOOL
|
|
CThirdPage::DefaultPrinterExists()
|
|
{
|
|
CPrintDialog dlg(FALSE);
|
|
|
|
dlg.m_pd.Flags |= PD_RETURNDEFAULT;
|
|
|
|
return dlg.GetDefaults();
|
|
}
|
|
|
|
// --------------------------------------------------------
|
|
// AutoScroll
|
|
//
|
|
// Ensure selected item is in middle of list
|
|
// --------------------------------------------------------
|
|
void
|
|
CThirdPage::AutoScroll( CListCtrl & list, int nIndex )
|
|
{
|
|
//
|
|
//<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
|
|
//
|
|
|
|
int top;
|
|
int count;
|
|
|
|
list.EnsureVisible( nIndex, FALSE );
|
|
|
|
top = list.GetTopIndex();
|
|
count = list.GetCountPerPage();
|
|
|
|
if ( ( nIndex == top ) || ( ( nIndex + 1 ) == ( top + count ) ) )
|
|
{
|
|
CRect rect;
|
|
int rows;
|
|
|
|
rows = ( count / 2 );
|
|
|
|
if ( nIndex == top )
|
|
{
|
|
list.GetItemRect(0, rect, LVIR_BOUNDS);
|
|
list.Scroll( CPoint( 0, rows * rect.Height() * -1 ) );
|
|
}
|
|
else
|
|
{
|
|
list.GetItemRect(0, rect, LVIR_BOUNDS);
|
|
list.Scroll( CPoint( 0, rows * rect.Height() ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// LoadPrintDriverDefsFromFile
|
|
//
|
|
// The only potentially opaque thing about this function is the
|
|
// checkForDuplicateModels flag. The problem here is that ntprint.inf
|
|
// doesn't contain duplicate models, and it has hundreds of models
|
|
// listed. You wouldn't check for duplicates there. But oftentimes,
|
|
// loading different windows print driver files contain multiple
|
|
// entries for the same printer. You don't want the UI to display
|
|
// the same printer multiple times, so in that case, you would ask
|
|
// this function to check for multiple models.
|
|
|
|
OSStatus
|
|
CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CString & filename, bool checkForDuplicateModels )
|
|
{
|
|
HINF handle = INVALID_HANDLE_VALUE;
|
|
const TCHAR * section = TEXT( "Manufacturer" );
|
|
LONG sectionCount;
|
|
TCHAR line[ 1000 ];
|
|
CString klass;
|
|
INFCONTEXT manufacturerContext;
|
|
BOOL ok;
|
|
OSStatus err = 0;
|
|
|
|
// Make sure we can open the file
|
|
handle = SetupOpenInfFile( filename, NULL, INF_STYLE_WIN4, NULL );
|
|
translate_errno( handle != INVALID_HANDLE_VALUE, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
|
|
// Make sure it's a printer file
|
|
ok = SetupGetLineText( NULL, handle, TEXT( "Version" ), TEXT( "Class" ), line, sizeof( line ), NULL );
|
|
translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
klass = line;
|
|
require_action( klass == TEXT( "Printer" ), exit, err = kUnknownErr );
|
|
|
|
sectionCount = SetupGetLineCount( handle, section );
|
|
translate_errno( sectionCount != -1, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
|
|
memset( &manufacturerContext, 0, sizeof( manufacturerContext ) );
|
|
|
|
for ( LONG i = 0; i < sectionCount; i++ )
|
|
{
|
|
Manufacturers::iterator iter;
|
|
Manufacturer * manufacturer;
|
|
CString manufacturerName;
|
|
CString temp;
|
|
CStringList modelSectionNameDecl;
|
|
CString modelSectionName;
|
|
CString baseModelName;
|
|
CString model;
|
|
INFCONTEXT modelContext;
|
|
LONG modelCount;
|
|
POSITION p;
|
|
|
|
if ( i == 0 )
|
|
{
|
|
ok = SetupFindFirstLine( handle, section, NULL, &manufacturerContext );
|
|
err = translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
}
|
|
else
|
|
{
|
|
ok = SetupFindNextLine( &manufacturerContext, &manufacturerContext );
|
|
err = translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
}
|
|
|
|
ok = SetupGetStringField( &manufacturerContext, 0, line, sizeof( line ), NULL );
|
|
err = translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
manufacturerName = line;
|
|
|
|
ok = SetupGetLineText( &manufacturerContext, handle, NULL, NULL, line, sizeof( line ), NULL );
|
|
err = translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
|
|
// Try to find some model section name that has entries. Explanation of int file structure
|
|
// can be found at:
|
|
//
|
|
// <http://msdn.microsoft.com/en-us/library/ms794359.aspx>
|
|
Split( line, ',', modelSectionNameDecl );
|
|
|
|
p = modelSectionNameDecl.GetHeadPosition();
|
|
modelSectionName = modelSectionNameDecl.GetNext( p );
|
|
modelCount = SetupGetLineCount( handle, modelSectionName );
|
|
baseModelName = modelSectionName;
|
|
|
|
while ( modelCount <= 0 && p )
|
|
{
|
|
CString targetOSVersion;
|
|
|
|
targetOSVersion = modelSectionNameDecl.GetNext( p );
|
|
modelSectionName = baseModelName + TEXT( "." ) + targetOSVersion;
|
|
modelCount = SetupGetLineCount( handle, modelSectionName );
|
|
}
|
|
|
|
if ( modelCount > 0 )
|
|
{
|
|
manufacturerName = NormalizeManufacturerName( manufacturerName );
|
|
|
|
iter = manufacturers.find( manufacturerName );
|
|
|
|
if ( iter != manufacturers.end() )
|
|
{
|
|
manufacturer = iter->second;
|
|
require_action( manufacturer, exit, err = kUnknownErr );
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
manufacturer = new Manufacturer;
|
|
}
|
|
catch (...)
|
|
{
|
|
manufacturer = NULL;
|
|
}
|
|
|
|
require_action( manufacturer, exit, err = kNoMemoryErr );
|
|
|
|
manufacturer->name = manufacturerName;
|
|
manufacturers[ manufacturerName ] = manufacturer;
|
|
}
|
|
|
|
memset( &modelContext, 0, sizeof( modelContext ) );
|
|
|
|
for ( LONG j = 0; j < modelCount; j++ )
|
|
{
|
|
CString modelName;
|
|
Model * model;
|
|
|
|
if ( j == 0 )
|
|
{
|
|
ok = SetupFindFirstLine( handle, modelSectionName, NULL, &modelContext );
|
|
err = translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
}
|
|
else
|
|
{
|
|
SetupFindNextLine( &modelContext, &modelContext );
|
|
err = translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
}
|
|
|
|
ok = SetupGetStringField( &modelContext, 0, line, sizeof( line ), NULL );
|
|
err = translate_errno( ok, GetLastError(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
|
|
modelName = line;
|
|
|
|
if (checkForDuplicateModels == true)
|
|
{
|
|
if ( MatchModel( manufacturer, ConvertToModelName( modelName ) ) != NULL )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Stock Vista printer inf files embed guids in the model
|
|
// declarations for Epson printers. Let's ignore those.
|
|
//
|
|
if ( modelName.Find( TEXT( "{" ), 0 ) != -1 )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
model = new Model;
|
|
}
|
|
catch (...)
|
|
{
|
|
model = NULL;
|
|
}
|
|
|
|
require_action( model, exit, err = kNoMemoryErr );
|
|
|
|
model->infFileName = filename;
|
|
model->displayName = modelName;
|
|
model->name = modelName;
|
|
model->driverInstalled = false;
|
|
|
|
manufacturer->models.push_back(model);
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if ( handle != INVALID_HANDLE_VALUE )
|
|
{
|
|
SetupCloseInfFile( handle );
|
|
handle = NULL;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------
|
|
// LoadPrintDriverDefs
|
|
//
|
|
// This function is responsible for loading the print driver
|
|
// definitions of all print drivers that have been installed
|
|
// on this machine.
|
|
// -------------------------------------------------------
|
|
OSStatus
|
|
CThirdPage::LoadPrintDriverDefs( Manufacturers & manufacturers )
|
|
{
|
|
BYTE * buffer = NULL;
|
|
DWORD bytesReceived = 0;
|
|
DWORD numPrinters = 0;
|
|
OSStatus err = 0;
|
|
BOOL ok;
|
|
|
|
//
|
|
// like a lot of win32 calls, we call this first to get the
|
|
// size of the buffer we need.
|
|
//
|
|
EnumPrinterDrivers(NULL, L"all", 6, NULL, 0, &bytesReceived, &numPrinters);
|
|
|
|
if (bytesReceived > 0)
|
|
{
|
|
try
|
|
{
|
|
buffer = new BYTE[bytesReceived];
|
|
}
|
|
catch (...)
|
|
{
|
|
buffer = NULL;
|
|
}
|
|
|
|
require_action( buffer, exit, err = kNoMemoryErr );
|
|
|
|
//
|
|
// this call gets the real info
|
|
//
|
|
ok = EnumPrinterDrivers(NULL, L"all", 6, buffer, bytesReceived, &bytesReceived, &numPrinters);
|
|
err = translate_errno( ok, errno_compat(), kUnknownErr );
|
|
require_noerr( err, exit );
|
|
|
|
DRIVER_INFO_6 * info = (DRIVER_INFO_6*) buffer;
|
|
|
|
for (DWORD i = 0; i < numPrinters; i++)
|
|
{
|
|
Manufacturer * manufacturer;
|
|
Model * model;
|
|
CString name;
|
|
|
|
//
|
|
// skip over anything that doesn't have a manufacturer field. This
|
|
// fixes a bug that I noticed that occurred after I installed
|
|
// ProComm. This program add a print driver with no manufacturer
|
|
// that screwed up this wizard.
|
|
//
|
|
if (info[i].pszMfgName == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// look for manufacturer
|
|
//
|
|
Manufacturers::iterator iter;
|
|
|
|
//
|
|
// save the name
|
|
//
|
|
name = NormalizeManufacturerName( info[i].pszMfgName );
|
|
|
|
iter = manufacturers.find(name);
|
|
|
|
if (iter != manufacturers.end())
|
|
{
|
|
manufacturer = iter->second;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
manufacturer = new Manufacturer;
|
|
}
|
|
catch (...)
|
|
{
|
|
manufacturer = NULL;
|
|
}
|
|
|
|
require_action( manufacturer, exit, err = kNoMemoryErr );
|
|
|
|
manufacturer->name = name;
|
|
|
|
manufacturers[name] = manufacturer;
|
|
}
|
|
|
|
//
|
|
// now look to see if we have already seen this guy. this could
|
|
// happen if we have already installed printers that are described
|
|
// in ntprint.inf. the extant drivers will show up in EnumPrinterDrivers
|
|
// but we have already loaded their info
|
|
//
|
|
//
|
|
if ( MatchModel( manufacturer, ConvertToModelName( info[i].pName ) ) == NULL )
|
|
{
|
|
try
|
|
{
|
|
model = new Model;
|
|
}
|
|
catch (...)
|
|
{
|
|
model = NULL;
|
|
}
|
|
|
|
require_action( model, exit, err = kNoMemoryErr );
|
|
|
|
model->displayName = info[i].pName;
|
|
model->name = info[i].pName;
|
|
model->driverInstalled = true;
|
|
|
|
manufacturer->models.push_back(model);
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if (buffer != NULL)
|
|
{
|
|
delete [] buffer;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// LoadGenericPrintDriverDefs
|
|
//
|
|
// This function is responsible for loading polymorphic
|
|
// generic print drivers defs. The UI will read
|
|
// something like "Generic / Postscript" and we can map
|
|
// that to any print driver we want.
|
|
// -------------------------------------------------------
|
|
OSStatus
|
|
CThirdPage::LoadGenericPrintDriverDefs( Manufacturers & manufacturers )
|
|
{
|
|
Manufacturer * manufacturer;
|
|
Model * model;
|
|
Manufacturers::iterator iter;
|
|
CString psDriverName;
|
|
CString pclDriverName;
|
|
OSStatus err = 0;
|
|
|
|
// <rdar://problem/4030388> Generic drivers don't do color
|
|
|
|
// First try and find our generic driver names
|
|
|
|
iter = m_manufacturers.find(L"HP");
|
|
require_action( iter != m_manufacturers.end(), exit, err = kUnknownErr );
|
|
manufacturer = iter->second;
|
|
|
|
// Look for Postscript
|
|
|
|
model = manufacturer->find( kGenericPSColorDriver );
|
|
|
|
if ( !model )
|
|
{
|
|
model = manufacturer->find( kGenericPSDriver );
|
|
}
|
|
|
|
if ( model )
|
|
{
|
|
psDriverName = model->name;
|
|
}
|
|
|
|
// Look for PCL
|
|
|
|
model = manufacturer->find( kGenericPCLColorDriver );
|
|
|
|
if ( !model )
|
|
{
|
|
model = manufacturer->find( kGenericPCLDriver );
|
|
}
|
|
|
|
if ( model )
|
|
{
|
|
pclDriverName = model->name;
|
|
}
|
|
|
|
// If we found either a generic PS driver, or a generic PCL driver,
|
|
// then add them to the list
|
|
|
|
if ( psDriverName.GetLength() || pclDriverName.GetLength() )
|
|
{
|
|
// Try and find generic manufacturer if there is one
|
|
|
|
iter = manufacturers.find(L"Generic");
|
|
|
|
if (iter != manufacturers.end())
|
|
{
|
|
manufacturer = iter->second;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
manufacturer = new Manufacturer;
|
|
}
|
|
catch (...)
|
|
{
|
|
manufacturer = NULL;
|
|
}
|
|
|
|
require_action( manufacturer, exit, err = kNoMemoryErr );
|
|
|
|
manufacturer->name = "Generic";
|
|
manufacturers[manufacturer->name] = manufacturer;
|
|
}
|
|
|
|
if ( psDriverName.GetLength() > 0 )
|
|
{
|
|
try
|
|
{
|
|
m_genericPostscript = new Model;
|
|
}
|
|
catch (...)
|
|
{
|
|
m_genericPostscript = NULL;
|
|
}
|
|
|
|
require_action( m_genericPostscript, exit, err = kNoMemoryErr );
|
|
|
|
m_genericPostscript->displayName = kGenericPostscript;
|
|
m_genericPostscript->name = psDriverName;
|
|
m_genericPostscript->driverInstalled = false;
|
|
|
|
manufacturer->models.push_back( m_genericPostscript );
|
|
}
|
|
|
|
if ( pclDriverName.GetLength() > 0 )
|
|
{
|
|
try
|
|
{
|
|
m_genericPCL = new Model;
|
|
}
|
|
catch (...)
|
|
{
|
|
m_genericPCL = NULL;
|
|
}
|
|
|
|
require_action( m_genericPCL, exit, err = kNoMemoryErr );
|
|
|
|
m_genericPCL->displayName = kGenericPCL;
|
|
m_genericPCL->name = pclDriverName;
|
|
m_genericPCL->driverInstalled = false;
|
|
|
|
manufacturer->models.push_back( m_genericPCL );
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
return err;
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// ConvertToManufacturerName
|
|
//
|
|
// This function is responsible for tweaking the
|
|
// name so that subsequent string operations won't fail because
|
|
// of capitalizations/different names for the same manufacturer
|
|
// (i.e. Hewlett-Packard/HP/Hewlett Packard)
|
|
//
|
|
CString
|
|
CThirdPage::ConvertToManufacturerName( const CString & name )
|
|
{
|
|
//
|
|
// first we're going to convert all the characters to lower
|
|
// case
|
|
//
|
|
CString lower = name;
|
|
lower.MakeLower();
|
|
|
|
//
|
|
// now we're going to check to see if the string says "hewlett-packard",
|
|
// because sometimes they refer to themselves as "hewlett-packard", and
|
|
// sometimes they refer to themselves as "hp".
|
|
//
|
|
if ( lower == L"hewlett-packard")
|
|
{
|
|
lower = "hp";
|
|
}
|
|
|
|
//
|
|
// tweak for Xerox Phaser, which doesn't announce itself
|
|
// as a xerox
|
|
//
|
|
else if ( lower.Find( L"phaser", 0 ) != -1 )
|
|
{
|
|
lower = "xerox";
|
|
}
|
|
|
|
return lower;
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// ConvertToModelName
|
|
//
|
|
// This function is responsible for ensuring that subsequent
|
|
// string operations don't fail because of differing capitalization
|
|
// schemes and the like
|
|
// ------------------------------------------------------
|
|
|
|
CString
|
|
CThirdPage::ConvertToModelName( const CString & name )
|
|
{
|
|
//
|
|
// convert it to lowercase
|
|
//
|
|
CString lower = name;
|
|
lower.MakeLower();
|
|
|
|
return lower;
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// NormalizeManufacturerName
|
|
//
|
|
// This function is responsible for tweaking the manufacturer
|
|
// name so that there are no aliases for vendors
|
|
//
|
|
CString
|
|
CThirdPage::NormalizeManufacturerName( const CString & name )
|
|
{
|
|
CString normalized = name;
|
|
|
|
//
|
|
// now we're going to check to see if the string says "hewlett-packard",
|
|
// because sometimes they refer to themselves as "hewlett-packard", and
|
|
// sometimes they refer to themselves as "hp".
|
|
//
|
|
if ( normalized == L"Hewlett-Packard")
|
|
{
|
|
normalized = "HP";
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// MatchPrinter
|
|
//
|
|
// This function is responsible for matching a printer
|
|
// to a list of manufacturers and models. It calls
|
|
// MatchManufacturer and MatchModel in turn.
|
|
//
|
|
|
|
OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * printer, Service * service, bool useCUPSWorkaround)
|
|
{
|
|
CString normalizedProductName;
|
|
Manufacturer * manufacturer = NULL;
|
|
Manufacturer * genericManufacturer = NULL;
|
|
Model * model = NULL;
|
|
Model * genericModel = NULL;
|
|
bool found = false;
|
|
CString text;
|
|
OSStatus err = kNoErr;
|
|
|
|
check( printer );
|
|
check( service );
|
|
|
|
Queue * q = service->SelectedQueue();
|
|
|
|
check( q );
|
|
|
|
//
|
|
// first look to see if we have a usb_MFG descriptor
|
|
//
|
|
if ( q->usb_MFG.GetLength() > 0)
|
|
{
|
|
manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( q->usb_MFG ) );
|
|
}
|
|
|
|
if ( manufacturer == NULL )
|
|
{
|
|
q->product.Remove('(');
|
|
q->product.Remove(')');
|
|
|
|
manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( q->product ) );
|
|
}
|
|
|
|
//
|
|
// if we found the manufacturer, then start looking for the model
|
|
//
|
|
if ( manufacturer != NULL )
|
|
{
|
|
if ( q->usb_MDL.GetLength() > 0 )
|
|
{
|
|
model = MatchModel ( manufacturer, ConvertToModelName ( q->usb_MDL ) );
|
|
}
|
|
|
|
if ( ( model == NULL ) && ( q->product.GetLength() > 0 ) )
|
|
{
|
|
q->product.Remove('(');
|
|
q->product.Remove(')');
|
|
|
|
model = MatchModel ( manufacturer, ConvertToModelName ( q->product ) );
|
|
}
|
|
|
|
if ( model != NULL )
|
|
{
|
|
// <rdar://problem/4124524> Offer Generic printers if printer advertises Postscript or PCL. Workaround
|
|
// bug in OS X CUPS printer sharing by selecting Generic driver instead of matched printer.
|
|
|
|
bool hasGenericDriver = false;
|
|
|
|
if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
|
|
{
|
|
hasGenericDriver = true;
|
|
}
|
|
|
|
// <rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS
|
|
// shared queue supports raw
|
|
|
|
if ( q->pdl.Find( L"application/octet-stream" ) != -1 )
|
|
{
|
|
useCUPSWorkaround = false;
|
|
}
|
|
|
|
if ( useCUPSWorkaround && printer->isCUPSPrinter && hasGenericDriver )
|
|
{
|
|
//
|
|
// <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
|
|
//
|
|
Manufacturers genericManufacturers;
|
|
|
|
LoadGenericPrintDriverDefs( genericManufacturers );
|
|
|
|
SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
|
|
|
|
FreeManufacturers( genericManufacturers );
|
|
}
|
|
else
|
|
{
|
|
SelectMatch(manufacturers, printer, service, manufacturer, model);
|
|
}
|
|
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
//
|
|
// display a message to the user based on whether we could match
|
|
// this printer
|
|
//
|
|
if (found)
|
|
{
|
|
text.LoadString(IDS_PRINTER_MATCH_GOOD);
|
|
err = kNoErr;
|
|
}
|
|
else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
|
|
{
|
|
if ( printer->isCUPSPrinter )
|
|
{
|
|
//
|
|
// <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
|
|
//
|
|
Manufacturers genericManufacturers;
|
|
|
|
LoadGenericPrintDriverDefs( genericManufacturers );
|
|
|
|
SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
|
|
|
|
text.LoadString(IDS_PRINTER_MATCH_GOOD);
|
|
|
|
FreeManufacturers( genericManufacturers );
|
|
}
|
|
else
|
|
{
|
|
SelectMatch( manufacturers, printer, service, genericManufacturer, genericModel );
|
|
text.LoadString(IDS_PRINTER_MATCH_MAYBE);
|
|
}
|
|
|
|
err = kNoErr;
|
|
}
|
|
else
|
|
{
|
|
text.LoadString(IDS_PRINTER_MATCH_BAD);
|
|
|
|
//
|
|
// if there was any crud in this list from before, get rid of it now
|
|
//
|
|
m_modelListCtrl.DeleteAllItems();
|
|
|
|
//
|
|
// select the manufacturer if we found one
|
|
//
|
|
if (manufacturer != NULL)
|
|
{
|
|
LVFINDINFO info;
|
|
int nIndex;
|
|
|
|
//
|
|
// select the manufacturer
|
|
//
|
|
info.flags = LVFI_STRING;
|
|
info.psz = manufacturer->name;
|
|
|
|
nIndex = m_manufacturerListCtrl.FindItem(&info);
|
|
|
|
if (nIndex != -1)
|
|
{
|
|
m_manufacturerListCtrl.SetItemState(nIndex, LVIS_SELECTED, LVIS_SELECTED);
|
|
|
|
//
|
|
//<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
|
|
//
|
|
AutoScroll(m_manufacturerListCtrl, nIndex);
|
|
}
|
|
}
|
|
|
|
err = kUnknownErr;
|
|
}
|
|
|
|
m_printerSelectionText.SetWindowText(text);
|
|
|
|
return err;
|
|
}
|
|
|
|
// ------------------------------------------------------
|
|
// MatchManufacturer
|
|
//
|
|
// This function is responsible for finding a manufacturer
|
|
// object from a string name. It does a CString::Find, which
|
|
// is like strstr, so it doesn't have to do an exact match
|
|
//
|
|
// If it can't find a match, NULL is returned
|
|
// ------------------------------------------------------
|
|
|
|
Manufacturer*
|
|
CThirdPage::MatchManufacturer( Manufacturers & manufacturers, const CString & name)
|
|
{
|
|
Manufacturers::iterator iter;
|
|
|
|
for (iter = manufacturers.begin(); iter != manufacturers.end(); iter++)
|
|
{
|
|
//
|
|
// we're going to convert all the manufacturer names to lower case,
|
|
// so we match the name passed in.
|
|
//
|
|
CString lower = iter->second->name;
|
|
lower.MakeLower();
|
|
|
|
//
|
|
// now try and find the lowered string in the name passed in.
|
|
//
|
|
if (name.Find(lower) != -1)
|
|
{
|
|
return iter->second;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// MatchModel
|
|
//
|
|
// This function is responsible for matching a model from
|
|
// a name. It does a CString::Find(), which works like strstr,
|
|
// so it doesn't rely on doing an exact string match.
|
|
//
|
|
|
|
Model*
|
|
CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name)
|
|
{
|
|
Models::iterator iter;
|
|
|
|
iter = manufacturer->models.begin();
|
|
|
|
for (iter = manufacturer->models.begin(); iter != manufacturer->models.end(); iter++)
|
|
{
|
|
Model * model = *iter;
|
|
|
|
//
|
|
// convert the model name to lower case
|
|
//
|
|
CString lowered = model->name;
|
|
lowered.MakeLower();
|
|
|
|
if (lowered.Find( name ) != -1)
|
|
{
|
|
return model;
|
|
}
|
|
|
|
//
|
|
// <rdar://problem/3841218>
|
|
// try removing the first substring and search again
|
|
//
|
|
|
|
if ( name.Find(' ') != -1 )
|
|
{
|
|
CString altered = name;
|
|
altered.Delete( 0, altered.Find(' ') + 1 );
|
|
|
|
if ( lowered.Find( altered ) != -1 )
|
|
{
|
|
return model;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// MatchGeneric
|
|
//
|
|
// This function will attempt to find a generic printer
|
|
// driver for a printer that we weren't able to match
|
|
// specifically
|
|
//
|
|
BOOL
|
|
CThirdPage::MatchGeneric( Manufacturers & manufacturers, Printer * printer, Service * service, Manufacturer ** manufacturer, Model ** model )
|
|
{
|
|
CString pdl;
|
|
BOOL ok = FALSE;
|
|
|
|
DEBUG_UNUSED( printer );
|
|
|
|
check( service );
|
|
|
|
Queue * q = service->SelectedQueue();
|
|
|
|
check( q );
|
|
|
|
Manufacturers::iterator iter = manufacturers.find( kGenericManufacturer );
|
|
require_action_quiet( iter != manufacturers.end(), exit, ok = FALSE );
|
|
|
|
*manufacturer = iter->second;
|
|
|
|
pdl = q->pdl;
|
|
pdl.MakeLower();
|
|
|
|
if ( m_genericPCL && ( pdl.Find( kPDLPCLKey ) != -1 ) )
|
|
{
|
|
*model = m_genericPCL;
|
|
ok = TRUE;
|
|
}
|
|
else if ( m_genericPostscript && ( pdl.Find( kPDLPostscriptKey ) != -1 ) )
|
|
{
|
|
*model = m_genericPostscript;
|
|
ok = TRUE;
|
|
}
|
|
|
|
exit:
|
|
|
|
return ok;
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// OnInitPage
|
|
//
|
|
// This function is responsible for doing initialization that
|
|
// only occurs once during a run of the wizard
|
|
//
|
|
|
|
OSStatus CThirdPage::OnInitPage()
|
|
{
|
|
CString header;
|
|
CString ntPrint;
|
|
OSStatus err = kNoErr;
|
|
|
|
// Load printer icon
|
|
check( m_printerImage == NULL );
|
|
|
|
m_printerImage = (CStatic*) GetDlgItem( 1 ); // 1 == IDR_MANIFEST
|
|
check( m_printerImage );
|
|
|
|
if ( m_printerImage != NULL )
|
|
{
|
|
m_printerImage->SetIcon( LoadIcon( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_PRINTER ) ) );
|
|
}
|
|
|
|
//
|
|
// The CTreeCtrl widget automatically sends a selection changed
|
|
// message which initially we want to ignore, because the user
|
|
// hasn't selected anything
|
|
//
|
|
// this flag gets reset in the message handler. Every subsequent
|
|
// message gets handled.
|
|
//
|
|
|
|
//
|
|
// we have to make sure that we only do this once. Typically,
|
|
// we would do this in something like OnInitDialog, but we don't
|
|
// have this in Wizards, because the window is a PropertySheet.
|
|
// We're considered fully initialized when we receive the first
|
|
// selection notice
|
|
//
|
|
header.LoadString(IDS_MANUFACTURER_HEADING);
|
|
m_manufacturerListCtrl.InsertColumn(0, header, LVCFMT_LEFT, -1 );
|
|
m_manufacturerSelected = NULL;
|
|
|
|
header.LoadString(IDS_MODEL_HEADING);
|
|
m_modelListCtrl.InsertColumn(0, header, LVCFMT_LEFT, -1 );
|
|
m_modelSelected = NULL;
|
|
|
|
return (err);
|
|
}
|
|
|
|
void CThirdPage::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CPropertyPage::DoDataExchange(pDX);
|
|
DDX_Control(pDX, IDC_PRINTER_MANUFACTURER, m_manufacturerListCtrl);
|
|
DDX_Control(pDX, IDC_PRINTER_MODEL, m_modelListCtrl);
|
|
DDX_Control(pDX, IDC_PRINTER_NAME, m_printerName);
|
|
DDX_Control(pDX, IDC_DEFAULT_PRINTER, m_defaultPrinterCtrl);
|
|
DDX_Control(pDX, IDC_PRINTER_SELECTION_TEXT, m_printerSelectionText);
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------
|
|
// OnSetActive
|
|
//
|
|
// This function is called by MFC after the window has been
|
|
// activated.
|
|
//
|
|
|
|
BOOL
|
|
CThirdPage::OnSetActive()
|
|
{
|
|
CPrinterSetupWizardSheet * psheet;
|
|
Printer * printer;
|
|
Service * service;
|
|
|
|
psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
|
|
require_quiet( psheet, exit );
|
|
|
|
psheet->SetWizardButtons( PSWIZB_BACK );
|
|
|
|
printer = psheet->GetSelectedPrinter();
|
|
require_quiet( printer, exit );
|
|
|
|
service = printer->services.front();
|
|
require_quiet( service, exit );
|
|
|
|
//
|
|
// call OnInitPage once
|
|
//
|
|
if (!m_initialized)
|
|
{
|
|
OnInitPage();
|
|
m_initialized = true;
|
|
}
|
|
|
|
//
|
|
// <rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
|
|
//
|
|
if ( DefaultPrinterExists() )
|
|
{
|
|
m_defaultPrinterCtrl.SetCheck( BST_UNCHECKED );
|
|
printer->deflt = false;
|
|
}
|
|
else
|
|
{
|
|
m_defaultPrinterCtrl.SetCheck( BST_CHECKED );
|
|
printer->deflt = true;
|
|
}
|
|
|
|
//
|
|
// update the UI with the printer name
|
|
//
|
|
m_printerName.SetWindowText(printer->displayName);
|
|
|
|
//
|
|
// populate the list controls with the manufacturers and models
|
|
// from ntprint.inf
|
|
//
|
|
PopulateUI( m_manufacturers );
|
|
|
|
//
|
|
// and try and match the printer
|
|
//
|
|
|
|
if ( psheet->GetLastPage() == psheet->GetPage(0) )
|
|
{
|
|
MatchPrinter( m_manufacturers, printer, service, true );
|
|
|
|
if ( ( m_manufacturerSelected != NULL ) && ( m_modelSelected != NULL ) )
|
|
{
|
|
GetParent()->PostMessage(PSM_SETCURSEL, 2 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SelectMatch(printer, service, m_manufacturerSelected, m_modelSelected);
|
|
}
|
|
|
|
exit:
|
|
|
|
return CPropertyPage::OnSetActive();
|
|
}
|
|
|
|
BOOL
|
|
CThirdPage::OnKillActive()
|
|
{
|
|
CPrinterSetupWizardSheet * psheet;
|
|
|
|
psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
|
|
require_quiet( psheet, exit );
|
|
|
|
psheet->SetLastPage(this);
|
|
|
|
exit:
|
|
|
|
return CPropertyPage::OnKillActive();
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// PopulateUI
|
|
//
|
|
// This function is called to populate the list of manufacturers
|
|
//
|
|
OSStatus
|
|
CThirdPage::PopulateUI(Manufacturers & manufacturers)
|
|
{
|
|
Manufacturers::iterator iter;
|
|
|
|
m_manufacturerListCtrl.DeleteAllItems();
|
|
|
|
for (iter = manufacturers.begin(); iter != manufacturers.end(); iter++)
|
|
{
|
|
int nIndex;
|
|
|
|
Manufacturer * manufacturer = iter->second;
|
|
|
|
nIndex = m_manufacturerListCtrl.InsertItem(0, manufacturer->name);
|
|
|
|
m_manufacturerListCtrl.SetItemData(nIndex, (DWORD_PTR) manufacturer);
|
|
|
|
m_manufacturerListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE_USEHEADER );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage)
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MANUFACTURER, OnLvnItemchangedManufacturer)
|
|
ON_NOTIFY(LVN_ITEMCHANGED, IDC_PRINTER_MODEL, OnLvnItemchangedPrinterModel)
|
|
ON_BN_CLICKED(IDC_DEFAULT_PRINTER, OnBnClickedDefaultPrinter)
|
|
ON_BN_CLICKED(IDC_HAVE_DISK, OnBnClickedHaveDisk)
|
|
END_MESSAGE_MAP()
|
|
|
|
// CThirdPage message handlers
|
|
void CThirdPage::OnLvnItemchangedManufacturer(NMHDR *pNMHDR, LRESULT *pResult)
|
|
{
|
|
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
|
|
|
|
POSITION p = m_manufacturerListCtrl.GetFirstSelectedItemPosition();
|
|
int nSelected = m_manufacturerListCtrl.GetNextSelectedItem(p);
|
|
|
|
if (nSelected != -1)
|
|
{
|
|
m_manufacturerSelected = (Manufacturer*) m_manufacturerListCtrl.GetItemData(nSelected);
|
|
|
|
m_modelListCtrl.SetRedraw(FALSE);
|
|
|
|
m_modelListCtrl.DeleteAllItems();
|
|
m_modelSelected = NULL;
|
|
|
|
Models::iterator iter;
|
|
|
|
for (iter = m_manufacturerSelected->models.begin(); iter != m_manufacturerSelected->models.end(); iter++)
|
|
{
|
|
Model * model = *iter;
|
|
|
|
int nItem = m_modelListCtrl.InsertItem( 0, model->displayName );
|
|
|
|
m_modelListCtrl.SetItemData(nItem, (DWORD_PTR) model);
|
|
|
|
m_modelListCtrl.SetColumnWidth( 0, LVSCW_AUTOSIZE_USEHEADER );
|
|
}
|
|
|
|
m_modelListCtrl.SetRedraw(TRUE);
|
|
}
|
|
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CThirdPage::OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult)
|
|
{
|
|
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
|
|
|
|
CPrinterSetupWizardSheet * psheet;
|
|
Printer * printer;
|
|
Service * service;
|
|
|
|
psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
|
|
require_quiet( psheet, exit );
|
|
|
|
printer = psheet->GetSelectedPrinter();
|
|
require_quiet( printer, exit );
|
|
|
|
service = printer->services.front();
|
|
require_quiet( service, exit );
|
|
|
|
check ( m_manufacturerSelected );
|
|
|
|
POSITION p = m_modelListCtrl.GetFirstSelectedItemPosition();
|
|
int nSelected = m_modelListCtrl.GetNextSelectedItem(p);
|
|
|
|
if (nSelected != -1)
|
|
{
|
|
m_modelSelected = (Model*) m_modelListCtrl.GetItemData(nSelected);
|
|
|
|
CopyPrinterSettings( printer, service, m_manufacturerSelected, m_modelSelected );
|
|
|
|
psheet->SetWizardButtons(PSWIZB_BACK|PSWIZB_NEXT);
|
|
}
|
|
else
|
|
{
|
|
psheet->SetWizardButtons(PSWIZB_BACK);
|
|
}
|
|
|
|
exit:
|
|
|
|
*pResult = 0;
|
|
}
|
|
|
|
void CThirdPage::OnBnClickedDefaultPrinter()
|
|
{
|
|
CPrinterSetupWizardSheet * psheet;
|
|
Printer * printer;
|
|
|
|
psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
|
|
require_quiet( psheet, exit );
|
|
|
|
printer = psheet->GetSelectedPrinter();
|
|
require_quiet( printer, exit );
|
|
|
|
printer->deflt = ( m_defaultPrinterCtrl.GetCheck() == BST_CHECKED ) ? true : false;
|
|
|
|
exit:
|
|
|
|
return;
|
|
}
|
|
|
|
void CThirdPage::OnBnClickedHaveDisk()
|
|
{
|
|
CPrinterSetupWizardSheet * psheet;
|
|
Printer * printer;
|
|
Service * service;
|
|
Manufacturers manufacturers;
|
|
|
|
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, L"Setup Information (*.inf)|*.inf||", this);
|
|
|
|
psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
|
|
require_quiet( psheet, exit );
|
|
|
|
printer = psheet->GetSelectedPrinter();
|
|
require_quiet( printer, exit );
|
|
|
|
service = printer->services.front();
|
|
require_quiet( service, exit );
|
|
|
|
for ( ;; )
|
|
{
|
|
if ( dlg.DoModal() == IDOK )
|
|
{
|
|
CString filename = dlg.GetPathName();
|
|
|
|
LoadPrintDriverDefsFromFile( manufacturers, filename, true );
|
|
|
|
// Sanity check
|
|
|
|
if ( manufacturers.size() > 0 )
|
|
{
|
|
PopulateUI( manufacturers );
|
|
|
|
if ( MatchPrinter( manufacturers, printer, service, false ) != kNoErr )
|
|
{
|
|
CString errorMessage;
|
|
CString errorCaption;
|
|
|
|
errorMessage.LoadString( IDS_NO_MATCH_INF_FILE );
|
|
errorCaption.LoadString( IDS_NO_MATCH_INF_FILE_CAPTION );
|
|
|
|
MessageBox( errorMessage, errorCaption, MB_OK );
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
CString errorMessage;
|
|
CString errorCaption;
|
|
|
|
errorMessage.LoadString( IDS_BAD_INF_FILE );
|
|
errorCaption.LoadString( IDS_BAD_INF_FILE_CAPTION );
|
|
|
|
MessageBox( errorMessage, errorCaption, MB_OK );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
FreeManufacturers( manufacturers );
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
CThirdPage::Split( const CString & string, TCHAR ch, CStringList & components )
|
|
{
|
|
CString temp;
|
|
int n;
|
|
|
|
temp = string;
|
|
|
|
while ( ( n = temp.Find( ch ) ) != -1 )
|
|
{
|
|
components.AddTail( temp.Left( n ) );
|
|
temp = temp.Right( temp.GetLength() - ( n + 1 ) );
|
|
}
|
|
|
|
components.AddTail( temp );
|
|
}
|