mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1342 lines
31 KiB
1342 lines
31 KiB
/*++
|
|
|
|
Copyright (c) 1990-1994 Microsoft Corporation
|
|
All rights reserved
|
|
|
|
Module Name:
|
|
|
|
SetupDlg.c
|
|
|
|
Abstract:
|
|
|
|
Handles the generic setup dialogs to setup drivers and monitors.
|
|
|
|
Author:
|
|
|
|
AlbertT [ported from printman]
|
|
|
|
Environment:
|
|
|
|
User Mode -Win32
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "printman.h"
|
|
#include "pmdef.h"
|
|
#include <commdlg.h>
|
|
#include <stdarg.h>
|
|
#include <prsinf.h>
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
INSTALLDRIVERDATA iddPrinter = {
|
|
IDS_PRINTER_INSTALL_TITLE,
|
|
IDS_PRINTER_SELECT_TITLE,
|
|
IDS_PRINTER_TYPE,
|
|
DLG_INSTALLDRIVER,
|
|
DLG_SELECTDRIVER,
|
|
|
|
TEXT("PRINTER.INF"),
|
|
TEXT("PRINTER"),
|
|
TEXT("OPTIONS"),
|
|
|
|
CB_INSERTSTRING,
|
|
CB_FINDSTRINGEXACT,
|
|
CB_SETCURSEL,
|
|
CB_RESETCONTENT,
|
|
|
|
sizeof(DRIVER_INFO_1),
|
|
(DWORD)&(((PDRIVER_INFO_1)0)->pName),
|
|
|
|
(PFNGETINSTALLED)GetInstalledDrivers
|
|
};
|
|
|
|
INSTALLDRIVERDATA iddMonitor = {
|
|
IDS_MONITOR_INSTALL_TITLE,
|
|
IDS_MONITOR_SELECT_TITLE,
|
|
IDS_MONITOR_TYPE,
|
|
DLG_INSTALLMONITOR,
|
|
DLG_SELECTMONITOR,
|
|
|
|
TEXT("MONITOR.INF"),
|
|
TEXT("MONITOR"),
|
|
TEXT("OPTIONS"),
|
|
|
|
LB_INSERTSTRING,
|
|
LB_FINDSTRINGEXACT,
|
|
LB_SETCURSEL,
|
|
LB_RESETCONTENT,
|
|
|
|
sizeof(MONITOR_INFO_1),
|
|
(DWORD)&(((PMONITOR_INFO_1)0)->pName),
|
|
|
|
(PFNGETINSTALLED)GetInstalledMonitors
|
|
};
|
|
|
|
|
|
//
|
|
// structs, private
|
|
//
|
|
typedef struct _INF_CACHE {
|
|
LPTSTR pszzDrivers;
|
|
UINT uDrivers; // uninstalled driver count
|
|
UINT uTotal; // total count
|
|
INFDRIVER aInfDriver[1]; // sorted list of installed/uninstalled drivers
|
|
} INFCACHE;
|
|
|
|
|
|
//
|
|
// Prototypes
|
|
//
|
|
|
|
VOID
|
|
Insert(
|
|
PINFCACHE pInfCache,
|
|
LPTSTR pszDriver,
|
|
BOOL bInstalled);
|
|
|
|
UINT
|
|
GetDriverCount(
|
|
LPTSTR pszzDriver,
|
|
PINFCACHE pInfCache);
|
|
|
|
HANDLE
|
|
OpenInfFileW(
|
|
PWCHAR szFileName,
|
|
PWCHAR szInfType);
|
|
|
|
PWCHAR
|
|
GetOptionListW(
|
|
HANDLE hndInf,
|
|
PWCHAR szOptionSection);
|
|
|
|
PTCHAR
|
|
GetOptionFromListSelection(
|
|
INT Selection,
|
|
PTCHAR pOption );
|
|
|
|
TCHAR LastChar(TCHAR *string);
|
|
void AppendChar(TCHAR *string, TCHAR ch);
|
|
|
|
|
|
//
|
|
// Procedures
|
|
//
|
|
|
|
VOID
|
|
DestroyInfParms(
|
|
PINFPARMS pInfParms)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees information in pInfParms, BUT NOT pInfParms!
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
if (pInfParms->pInstalled)
|
|
FreeSplMem(pInfParms->pInstalled);
|
|
|
|
pInfParms->pInstalled = NULL;
|
|
pInfParms->cbInstalled = 0;
|
|
|
|
DestroyInfCache(pInfParms->pInfCache);
|
|
pInfParms->pInfCache = NULL;
|
|
}
|
|
|
|
VOID
|
|
DestroyInfCache(
|
|
PINFCACHE pInfCache)
|
|
{
|
|
if (pInfCache && pInfCache->pszzDrivers) {
|
|
LocalFree(pInfCache->pszzDrivers);
|
|
FreeSplMem(pInfCache);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
HandleSelChange(
|
|
HWND hwnd,
|
|
PINFPARMS pInfParms,
|
|
UINT uAddSel)
|
|
{
|
|
PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
|
|
|
|
PTCHAR pInstalledDriverOption;
|
|
BOOL OK;
|
|
DWORD cInstalledDrivers;
|
|
|
|
BOOL bReturnValue = FALSE;
|
|
|
|
//
|
|
// pInfParms->pOptions must be cleared since this dialog box
|
|
// may fail, and we want to know if pOptions is valid.
|
|
//
|
|
pInfParms->pOptions = NULL;
|
|
|
|
OK = DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(DLG_INSTALLDRIVER),
|
|
hwnd,
|
|
(DLGPROC)InstallDriverDlg,
|
|
(LONG)pInfParms);
|
|
|
|
//
|
|
// Remember, we are responsible for freeing
|
|
// pOptions since pOptionSelected points into it.
|
|
//
|
|
pInstalledDriverOption = pInfParms->pOptionSelected;
|
|
|
|
|
|
if( OK && pInstalledDriverOption )
|
|
{
|
|
//
|
|
// Refresh our list of things.
|
|
//
|
|
cInstalledDrivers = (*pInstallDriverData->pfnGetInstalled)(pInfParms);
|
|
|
|
/* Check whether the number of installed drivers has actually increased.
|
|
* This may not be the case if a driver was installed to update an
|
|
* already installed driver.
|
|
*/
|
|
if( cInstalledDrivers > pInfParms->cInstalled )
|
|
{
|
|
DBGMSG( DBG_INFO, ( "Total of %d installed drivers. Updating list.\n",
|
|
cInstalledDrivers ) );
|
|
|
|
//
|
|
// If so, we need to update the list of merged drivers too:
|
|
//
|
|
pInfParms->cInstalled = cInstalledDrivers;
|
|
|
|
SetupInfDlg(pInfParms);
|
|
|
|
}
|
|
else
|
|
{
|
|
DBGMSG( DBG_INFO, ( "A driver was updated. No new drivers installed.\n" ) );
|
|
}
|
|
|
|
//
|
|
// Select the new driver
|
|
//
|
|
pInfParms->uCurSel = SendMessage(pInfParms->hwnd,
|
|
pInstallDriverData->uFindMsg,
|
|
(WPARAM)-1,
|
|
(LPARAM)pInstalledDriverOption);
|
|
|
|
if (pInfParms->uCurSel == (UINT)-1) {
|
|
pInfParms->uCurSel = 0;
|
|
goto RestorePrevious;
|
|
}
|
|
|
|
SendMessage(pInfParms->hwnd,
|
|
pInstallDriverData->uSelectMsg,
|
|
pInfParms->uCurSel,
|
|
0L);
|
|
}
|
|
else
|
|
{
|
|
|
|
RestorePrevious:
|
|
|
|
DBGMSG( DBG_WARNING, ( "Driver was not installed or failed to find.\n" ) );
|
|
|
|
//
|
|
// If we didn't install a new driver, don't keep the "Other..."
|
|
// selection in the list box; return it to the previous one:
|
|
//
|
|
SendMessage(pInfParms->hwnd,
|
|
pInstallDriverData->uSelectMsg,
|
|
pInfParms->uCurSel,
|
|
0L);
|
|
|
|
/* Ensure that we do actually have a driver now.
|
|
* This is a fix for bug #16383, which happened
|
|
* when there were no drivers installed and PRINTER.INF
|
|
* was missing. The Create Printer dialog prompted
|
|
* for a source path, and the user canceled out,
|
|
* then typed a printer name and clicked OK.
|
|
* Only "Other..." was in the Drivers list, but the
|
|
* code assumed there was a driver.
|
|
*/
|
|
|
|
if (pInfParms->uCurSel == uAddSel)
|
|
{
|
|
Message( hwnd, MSG_ERROR, IDS_PRINTMANAGER,
|
|
IDS_NO_DRIVERS_INSTALLED, pInstallDriverData->pszInfFile );
|
|
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
bReturnValue = TRUE;
|
|
|
|
Done:
|
|
|
|
//
|
|
// Must be local free'd since allocated by inf code rather than
|
|
// spooler (Don't use FreeSplMem).
|
|
//
|
|
if (pInfParms->pOptions)
|
|
LocalFree(pInfParms->pOptions);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PINFCACHE
|
|
SetupInfDlg(
|
|
PINFPARMS pInfParms)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up the window with the installed and installable drivers.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
pInfCacheNew buffer must be freed by callee or used in pInfCache
|
|
on the next call. If cache used, then the return value is the cache.
|
|
|
|
NULL = Error, use GetLastError()
|
|
|
|
--*/
|
|
|
|
{
|
|
PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
|
|
|
|
LPTSTR pszzDrivers = NULL;
|
|
UINT uDrivers = 0;
|
|
HANDLE hInfFile;
|
|
TCHAR string[128];
|
|
|
|
PINFCACHE pInfCache = pInfParms->pInfCache;
|
|
|
|
HWND hwnd = pInfParms->hwnd;
|
|
UINT uInsertMsg = pInstallDriverData->uInsertMsg;
|
|
UINT uFindMsg = pInstallDriverData->uFindMsg;
|
|
UINT uSelectMsg = pInstallDriverData->uSelectMsg;
|
|
|
|
PBYTE pInstalled = pInfParms->pInstalled;
|
|
UINT uInstalled = pInfParms->cInstalled;
|
|
|
|
DWORD cbSize = pInstallDriverData->cbSize;
|
|
DWORD cbOffset = pInstallDriverData->cbOffset;
|
|
|
|
LPTSTR pszCurrentDriver = pInfParms->pszCurrentDriver;
|
|
|
|
UINT i;
|
|
|
|
//
|
|
// If pInfCache valid but hInfFile isn't, then we won't read
|
|
// in inf file until pInfCache is invalid.
|
|
//
|
|
if (!pInfCache) {
|
|
|
|
hInfFile = OpenInfFileW(pInstallDriverData->pszInfFile,
|
|
pInstallDriverData->pszInfType);
|
|
|
|
if (hInfFile != INVALID_HANDLE_VALUE) {
|
|
|
|
pszzDrivers = GetOptionListW(hInfFile, pInstallDriverData->pszSection);
|
|
|
|
CloseInfFile(hInfFile);
|
|
|
|
if (pszzDrivers) {
|
|
|
|
uDrivers = GetDriverCount(pszzDrivers, NULL);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
uDrivers = pInfCache->uDrivers;
|
|
pszzDrivers = pInfCache->pszzDrivers;
|
|
|
|
FreeSplMem(pInfCache);
|
|
}
|
|
|
|
|
|
pInfCache = AllocSplMem(sizeof(INFCACHE) +
|
|
(uDrivers+uInstalled) * sizeof(INFDRIVER));
|
|
|
|
pInfParms->pInfCache = pInfCache;
|
|
|
|
if (!pInfCache) {
|
|
|
|
LocalFree(pszzDrivers);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// pInfCache->uTotal = 0;
|
|
//
|
|
|
|
pInfCache->uDrivers = uDrivers;
|
|
pInfCache->pszzDrivers = pszzDrivers;
|
|
|
|
//
|
|
// Reset the box
|
|
//
|
|
SendMessage(hwnd,
|
|
pInstallDriverData->uResetMsg,
|
|
0,
|
|
0L);
|
|
|
|
//
|
|
// Add in uninstalled drivers
|
|
//
|
|
GetDriverCount(pszzDrivers, pInfCache);
|
|
|
|
//
|
|
// Add in installed drivers
|
|
//
|
|
if (pInstalled) {
|
|
|
|
for(i=0, ((PBYTE)pInstalled) += cbOffset;
|
|
i<uInstalled;
|
|
i++, ((PBYTE)pInstalled) += cbSize) {
|
|
|
|
Insert(pInfCache, *((LPTSTR*)pInstalled), TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// pInstalled is now garbage
|
|
//
|
|
|
|
//
|
|
// Now everything is sorted and added (Insert removes dups)
|
|
// Do Insert!
|
|
//
|
|
|
|
for(i = 0; i < pInfCache->uTotal; i++) {
|
|
|
|
SendMessage(hwnd,
|
|
uInsertMsg,
|
|
i,
|
|
(LPARAM)pInfCache->aInfDriver[i].pszDriver);
|
|
}
|
|
|
|
if (pszCurrentDriver) {
|
|
|
|
pInfParms->uCurSel = SendMessage(hwnd,
|
|
uFindMsg,
|
|
0,
|
|
(LPARAM)pszCurrentDriver);
|
|
|
|
if (pInfParms->uCurSel == (DWORD)-1)
|
|
pInfParms->uCurSel = 0;
|
|
|
|
} else {
|
|
|
|
pInfParms->uCurSel = 0;
|
|
}
|
|
|
|
SendMessage(hwnd, uSelectMsg, pInfParms->uCurSel, 0L);
|
|
|
|
LoadString( hInst, IDS_OTHER, string,
|
|
sizeof( string ) / sizeof( *string ) );
|
|
|
|
i = SendMessage(hwnd,
|
|
uInsertMsg,
|
|
(WPARAM)-1,
|
|
(LPARAM)string );
|
|
|
|
//
|
|
// Use the combo box reserved user long to store the unlisted index:
|
|
//
|
|
SetWindowLong(hwnd, GWL_USERDATA, i);
|
|
|
|
return pInfCache;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
Insert(
|
|
PINFCACHE pInfCache,
|
|
LPTSTR pszDriver,
|
|
BOOL bInstalled)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inserts a string and bInstalled option into pInfCache. Assume
|
|
string compares slow, moving items fast (true since NLS sorting
|
|
is enabled).
|
|
|
|
This does a binary sort in place, which causes a lot of item movement
|
|
(not pointers, but actual objects), so if INFDRIVER gets big,
|
|
rewrite this code.
|
|
|
|
Duplicates disallowed; bInstalled turned on if duplicate has it on.
|
|
|
|
Arguments:
|
|
|
|
pInfCache -- Structure to insert item into. Assumes uTotal is
|
|
accurate and there is enough space for the new item.
|
|
|
|
pszDriver -- Driver string to insert. Must not be freed until pInfCache
|
|
is no longer needed.
|
|
|
|
bInstalled -- Extra param for INFDRIVER.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
INT iMax, iMin, iMid, j, iCompare;
|
|
PINFDRIVER pInfDriver = pInfCache->aInfDriver;
|
|
UINT uTotal = pInfCache->uTotal;
|
|
|
|
//
|
|
// Check if iMax is != 0. If so, must sort insert.
|
|
//
|
|
if (iMax = uTotal) {
|
|
|
|
iMin = 0;
|
|
|
|
//
|
|
// Quick hack for presorted lists
|
|
//
|
|
// Since they sort already (excepting strange chars/localization)
|
|
// do a quick check if it goes at the end of the list.
|
|
//
|
|
// Check if it DOESN'T, then insert
|
|
//
|
|
iCompare = lstrcmpi(pInfDriver[iMax-1].pszDriver, pszDriver);
|
|
|
|
if (!iCompare) {
|
|
|
|
//
|
|
// On match, just turn on bInstalled bit.
|
|
//
|
|
pInfDriver[iMax-1].bInstalled |= bInstalled;
|
|
return;
|
|
|
|
} else if (iCompare > 0) {
|
|
|
|
//
|
|
// do a binary insert
|
|
//
|
|
do {
|
|
iMid = (iMax + iMin) / 2;
|
|
|
|
iCompare = lstrcmpi(pInfDriver[iMid].pszDriver, pszDriver);
|
|
|
|
if (iCompare < 0)
|
|
iMin = iMid + 1;
|
|
else if (iCompare > 0)
|
|
iMax = iMid - 1;
|
|
else {
|
|
iMin = iMax = iMid;
|
|
}
|
|
|
|
} while (iMax > iMin);
|
|
|
|
if (iMax < 0)
|
|
iMax = 0;
|
|
|
|
//
|
|
// Insert after this item.
|
|
//
|
|
if ((iCompare=lstrcmpi(pInfDriver[iMax].pszDriver, pszDriver)) < 0) {
|
|
|
|
iMax++;
|
|
}
|
|
|
|
//
|
|
// If if not a duplicate
|
|
//
|
|
if (iCompare) {
|
|
|
|
if (iMax != (INT)uTotal) {
|
|
for (j = uTotal; j > iMax; j--)
|
|
pInfDriver[j] = pInfDriver[j-1];
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If its a duplicate, don't install it, just make sure
|
|
// to update the bInstalled flag.
|
|
//
|
|
if (!iCompare) {
|
|
pInfDriver[iMax].bInstalled |= bInstalled;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// New driver, add it to the list
|
|
//
|
|
pInfDriver[iMax].pszDriver = pszDriver;
|
|
pInfDriver[iMax].bInstalled = bInstalled;
|
|
|
|
pInfCache->uTotal++;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT
|
|
GetDriverCount(
|
|
LPTSTR pszzDriver,
|
|
PINFCACHE pInfCache)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Gets the number of strings in a list of strings (null term).
|
|
If ppszDriver is != NULL, fills it with pointers into the array.
|
|
|
|
Arguments:
|
|
|
|
pszzDriver -- List of strings, NULL terminated
|
|
Can be NULL.
|
|
pInfCache -- [OPTIONAL] pInfCache struct to update
|
|
These drivers are added to the structure as NOT_INSTALLED!
|
|
|
|
Return Value:
|
|
|
|
Number of strings in pOptions
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT uCount = 0;
|
|
|
|
if (!pszzDriver)
|
|
return 0;
|
|
|
|
while( *pszzDriver ) {
|
|
|
|
if (pInfCache) {
|
|
Insert(pInfCache, pszzDriver, FALSE);
|
|
}
|
|
|
|
uCount++;
|
|
|
|
//
|
|
// Scan to the end of this option:
|
|
//
|
|
while( *pszzDriver )
|
|
pszzDriver++;
|
|
|
|
//
|
|
// Step over the null-terminator:
|
|
//
|
|
pszzDriver++;
|
|
}
|
|
|
|
return uCount;
|
|
}
|
|
|
|
|
|
PWCHAR
|
|
GetOptionListW(
|
|
HANDLE hndInf,
|
|
PWCHAR szOptionSection)
|
|
{
|
|
PCHAR szos;
|
|
PCHAR szList;
|
|
PCHAR p;
|
|
int cchos;
|
|
PWCHAR szReturn;
|
|
PWCHAR szPtr;
|
|
int size;
|
|
|
|
cchos = (lstrlenW(szOptionSection)+1)*sizeof(TCHAR);
|
|
szos = AllocSplMem(cchos);
|
|
|
|
WideCharToMultiByte( CP_ACP, 0,
|
|
szOptionSection, lstrlenW(szOptionSection)+1,
|
|
szos, cchos,
|
|
NULL, NULL );
|
|
|
|
szList = p = GetOptionList(hndInf, szos);
|
|
|
|
szReturn = AllocSplMem( LocalSize(szList) *sizeof(TCHAR) );
|
|
szPtr = szReturn;
|
|
while( *p ) {
|
|
size = lstrlenA(p)+1;
|
|
MultiByteToWideChar(CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
p,
|
|
size,
|
|
szPtr,
|
|
size*sizeof(TCHAR) );
|
|
|
|
p += size;
|
|
szPtr += (lstrlenW(szPtr)+1);
|
|
}
|
|
|
|
LocalFree(szList);
|
|
FreeSplMem(szos);
|
|
return szReturn;
|
|
}
|
|
|
|
|
|
HANDLE
|
|
OpenInfFileW(
|
|
PWCHAR szFileName,
|
|
PWCHAR szInfType)
|
|
{
|
|
PCHAR szfn;
|
|
PCHAR szit;
|
|
int cchfn;
|
|
int cchit;
|
|
HANDLE h;
|
|
|
|
cchfn = (lstrlenW(szFileName)+1)*sizeof(TCHAR);
|
|
cchit = (lstrlenW(szInfType)+1)*sizeof(TCHAR);
|
|
szfn = AllocSplMem(cchfn);
|
|
szit = AllocSplMem(cchit);
|
|
|
|
WideCharToMultiByte( CP_ACP, 0,
|
|
szFileName, lstrlenW(szFileName)+1,
|
|
szfn, cchfn,
|
|
NULL, NULL );
|
|
|
|
WideCharToMultiByte( CP_ACP, 0,
|
|
szInfType, lstrlenW(szInfType)+1,
|
|
szit, cchit,
|
|
NULL, NULL );
|
|
|
|
h = OpenInfFile(szfn, szit);
|
|
|
|
FreeSplMem(szfn);
|
|
FreeSplMem(szit);
|
|
return h;
|
|
}
|
|
|
|
|
|
PINFDRIVER
|
|
GetInfDriver(
|
|
PINFCACHE pInfCache,
|
|
UINT uIndex)
|
|
{
|
|
return &pInfCache->aInfDriver[uIndex];
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL APIENTRY
|
|
SelectDriverDlg(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wparam,
|
|
LPARAM lparam)
|
|
{
|
|
PINFPARMS pInfParms;
|
|
|
|
switch(msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return SelectDriverInitDialog(hwnd, (PINFPARMS)lparam);
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wparam))
|
|
{
|
|
case IDOK:
|
|
return SelectDriverCommandOK(hwnd);
|
|
|
|
case IDCANCEL:
|
|
return SelectDriverCommandCancel(hwnd);
|
|
|
|
case IDD_SD_LB_PRINTERDRIVERS:
|
|
switch (HIWORD(wparam))
|
|
{
|
|
case CBN_DBLCLK:
|
|
return SelectDriverCommandOK(hwnd);
|
|
}
|
|
break;
|
|
|
|
case IDD_SD_PB_HELP:
|
|
goto DoHelp;
|
|
}
|
|
}
|
|
|
|
if( msg == WM_Help ) {
|
|
|
|
DoHelp:
|
|
pInfParms = (PINFPARMS)GetWindowLong(hwnd,
|
|
GWL_USERDATA);
|
|
|
|
ShowHelp(hwnd,
|
|
HELP_CONTEXT,
|
|
pInfParms->pInstallDriverData->dlgSelectHelp);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SelectDriverInitDialog(
|
|
HWND hwnd,
|
|
PINFPARMS pInfParms)
|
|
{
|
|
PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
|
|
PTCHAR pOptions;
|
|
LPTSTR pszTitle;
|
|
|
|
SetWindowLong(hwnd, GWL_USERDATA, (LONG)pInfParms);
|
|
|
|
// #ifndef JAPAN
|
|
|
|
if (!bJapan) {
|
|
SETDLGITEMFONT(hwnd, IDD_SD_EF_SOURCEDIRECTORY, hfontHelv);
|
|
SETDLGITEMFONT(hwnd, IDD_SD_LB_PRINTERDRIVERS, hfontHelv);
|
|
}
|
|
// #endif
|
|
|
|
SetDlgItemText(hwnd,
|
|
IDD_SD_EF_SOURCEDIRECTORY,
|
|
pInfParms->pInfDirectory);
|
|
|
|
SendDlgItemMessage(hwnd, IDD_SD_EF_SOURCEDIRECTORY, EM_LIMITTEXT, MAX_PATH, 0);
|
|
SendDlgItemMessage(hwnd, IDD_SD_EF_SOURCEDIRECTORY, WM_KEYDOWN, (WPARAM)VK_END, 0);
|
|
|
|
pOptions = pInfParms->pOptions;
|
|
|
|
pszTitle = GetString(pInstallDriverData->idsSelectTitle);
|
|
|
|
if (pszTitle) {
|
|
|
|
SetWindowText(hwnd, pszTitle);
|
|
FreeSplStr(pszTitle);
|
|
}
|
|
|
|
pszTitle = GetString(pInstallDriverData->idsType);
|
|
|
|
if (pszTitle) {
|
|
|
|
SetDlgItemText(hwnd, IDD_SD_TX_TYPE, pszTitle);
|
|
FreeSplStr(pszTitle);
|
|
}
|
|
|
|
|
|
/* Only continue as long as we get a valid option text.
|
|
* If GetOptionTextW returns NULL, we've probably got
|
|
* a corrupted INF file.
|
|
*/
|
|
while( *pOptions /*&& pOptionText*/ )
|
|
{
|
|
/* !!! What do we do with the language here ???
|
|
* IGNORE IT!
|
|
*/
|
|
SendDlgItemMessage( hwnd, IDD_SD_LB_PRINTERDRIVERS, LB_INSERTSTRING,
|
|
(UINT)-1, (LONG)(LPTSTR)pOptions);
|
|
|
|
while(*pOptions++);
|
|
}
|
|
|
|
SetFocus( GetDlgItem( hwnd, IDD_SD_LB_PRINTERDRIVERS ) );
|
|
SendMessage( GetDlgItem( hwnd, IDD_SD_LB_PRINTERDRIVERS ),
|
|
LB_SETCURSEL, 0, 0 );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
BOOL SelectDriverCommandOK(HWND hwnd)
|
|
{
|
|
PINFPARMS pInfParms;
|
|
TCHAR string[MAX_PATH];
|
|
PTCHAR pOptions;
|
|
int Selection;
|
|
|
|
pInfParms = (PINFPARMS)GetWindowLong( hwnd, GWL_USERDATA );
|
|
|
|
GetDlgItemText(hwnd,
|
|
IDD_SD_EF_SOURCEDIRECTORY,
|
|
string,
|
|
sizeof (string)/sizeof(TCHAR) );
|
|
|
|
// if(LastChar(string) != BACKSLASH)
|
|
// AppendChar(string, BACKSLASH);
|
|
|
|
ReallocSplStr( &pInfParms->pSetupDirectory, string );
|
|
|
|
Selection = GETLISTSELECT( hwnd, IDD_SD_LB_PRINTERDRIVERS );
|
|
|
|
GETLISTTEXT( hwnd, IDD_SD_LB_PRINTERDRIVERS, Selection, string );
|
|
|
|
pOptions = pInfParms->pOptions;
|
|
|
|
pInfParms->pOptionSelected = GetOptionFromListSelection( Selection,
|
|
pOptions );
|
|
|
|
EndDialog( hwnd, TRUE );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
BOOL SelectDriverCommandCancel(HWND hwnd)
|
|
{
|
|
EndDialog(hwnd, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
PTCHAR
|
|
GetOptionFromListSelection(
|
|
INT Selection,
|
|
PTCHAR pOption)
|
|
{
|
|
int i = 0;
|
|
|
|
while( i < Selection )
|
|
{
|
|
while( *pOption ) /* Increment to null terminator */
|
|
pOption++;
|
|
pOption++; /* Increment to beginning of next option */
|
|
i++;
|
|
}
|
|
|
|
return pOption;
|
|
}
|
|
|
|
|
|
|
|
BOOL APIENTRY
|
|
InstallDriverDlg(
|
|
HWND hwnd,
|
|
UINT msg,
|
|
WPARAM wparam,
|
|
LPARAM lparam)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dialog for user to type in a path for the in file. This dialog
|
|
then creates the select dialog to choose a new driver.
|
|
|
|
** NOTE ** Callee must free pOptions, since pOptionSelected
|
|
points into this buffer.
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PINFPARMS pInfParms;
|
|
|
|
switch(msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return InstallDriverInitDialog(hwnd, (PINFPARMS)lparam);
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wparam))
|
|
{
|
|
case IDOK:
|
|
return InstallDriverCommandOK(hwnd);
|
|
|
|
case IDCANCEL:
|
|
return InstallDriverCommandCancel(hwnd);
|
|
|
|
case IDD_ID_HELP:
|
|
goto DoHelp;
|
|
}
|
|
}
|
|
|
|
if( msg == WM_Help ) {
|
|
|
|
DoHelp:
|
|
pInfParms = (PINFPARMS)GetWindowLong(hwnd,
|
|
GWL_USERDATA);
|
|
ShowHelp(hwnd,
|
|
HELP_CONTEXT,
|
|
pInfParms->pInstallDriverData->dlgInstallHelp);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
BOOL
|
|
InstallDriverInitDialog(
|
|
HWND hwnd,
|
|
PINFPARMS pInfParms)
|
|
{
|
|
LPTSTR pszTitle;
|
|
PINSTALLDRIVERDATA pInstallDriverData = pInfParms->pInstallDriverData;
|
|
|
|
SetWindowLong(hwnd, GWL_USERDATA, (LONG)pInfParms);
|
|
|
|
// #ifndef JAPAN
|
|
if (!bJapan) {
|
|
SETDLGITEMFONT(hwnd, IDD_ID_EF_DRIVERPATH, hfontHelv);
|
|
}
|
|
// #endif
|
|
|
|
|
|
pszTitle = GetString(pInstallDriverData->idsInstallTitle);
|
|
|
|
if (pszTitle) {
|
|
|
|
SetWindowText(hwnd, pszTitle);
|
|
FreeSplStr(pszTitle);
|
|
}
|
|
|
|
SendDlgItemMessage(hwnd, IDD_ID_EF_DRIVERPATH, EM_LIMITTEXT, MAX_PATH, 0);
|
|
SetDlgItemText(hwnd, IDD_ID_EF_DRIVERPATH, TEXT("A:\\"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
BOOL InstallDriverCommandOK(HWND hwnd)
|
|
{
|
|
TCHAR FileName[MAX_PATH+1+1+11];
|
|
// Note maximum possible characters retrievable from
|
|
// the dialog box MAX_PATH + 1 char for the '\\' +
|
|
// 11 chars for the szSetupInf + 1 char null terminator
|
|
|
|
HANDLE hInfFile;
|
|
PTCHAR pOptions;
|
|
BOOL SetupOK;
|
|
DWORD ExitCode;
|
|
PINSTALLDRIVERDATA pInstallDriverData;
|
|
PINFPARMS pInfParms;
|
|
TCHAR FullPath[MAX_PATH+1+1+11];
|
|
BOOL OK = FALSE;
|
|
PTCHAR pFilePart;
|
|
|
|
pInfParms = (PINFPARMS)GetWindowLong( hwnd, GWL_USERDATA );
|
|
pInstallDriverData =pInfParms->pInstallDriverData;
|
|
|
|
//
|
|
// Get the path, which may or may not have been modified by the user:
|
|
//
|
|
memset(FileName, 0, MAX_PATH+13);
|
|
GetDlgItemText(hwnd, IDD_ID_EF_DRIVERPATH, FileName, MAX_PATH);
|
|
|
|
if(LastChar(FileName) != BACKSLASH) /* Ensure it's terminated with backslash */
|
|
AppendChar(FileName, BACKSLASH);
|
|
|
|
/* Append the setup filename to the path:
|
|
*/
|
|
_tcscat(FileName, pInstallDriverData->pszInfFile);
|
|
|
|
hInfFile = OpenInfFileW(FileName, pInstallDriverData->pszInfType);
|
|
|
|
if(hInfFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
Message(hwnd, MSG_ERROR, IDS_PRINTMANAGER,
|
|
IDS_COULDNOTFINDINFFILE, FileName);
|
|
|
|
OK = FALSE;
|
|
}
|
|
else
|
|
{
|
|
GetDlgItemText(hwnd, IDD_ID_EF_DRIVERPATH, FileName, sizeof FileName/sizeof(TCHAR));
|
|
|
|
/* Now get a full path name which will be passed on to SETUP.
|
|
* We will give SETUP the full path name in case the user typed in
|
|
* a relative path. In this instance, SETUP will assume that the
|
|
* default directory is System32, but this might just possibly
|
|
* not correspond to Print Manager's default.
|
|
* We just found the .INF file in the directory, so it's safe to
|
|
* assume that GetFullPathname will succeed.
|
|
*/
|
|
if( GetFullPathName( FileName, sizeof FullPath/sizeof(TCHAR), FullPath, &pFilePart ) )
|
|
{
|
|
pOptions = GetOptionListW(hInfFile, pInstallDriverData->pszSection);
|
|
|
|
/* Assume the drivers are in the same directory as the INF file;
|
|
* this can be overridden by the user:
|
|
*/
|
|
pInfParms->pSetupDirectory = AllocSplStr(FullPath);
|
|
|
|
pInfParms->pInfDirectory = AllocSplStr(FullPath);
|
|
|
|
if(pOptions && pInfParms->pSetupDirectory
|
|
&& pInfParms->pInfDirectory)
|
|
{
|
|
pInfParms->pOptions = pOptions;
|
|
|
|
SetCursor( hcursorWait );
|
|
|
|
if( DialogBoxParam(hInst, MAKEINTRESOURCE(DLG_SELECTDRIVER),
|
|
hwnd, (DLGPROC)SelectDriverDlg,
|
|
(DWORD)pInfParms) == IDOK )
|
|
{
|
|
SetupOK = InvokeSetup( hwnd,
|
|
pInstallDriverData->pszInfFile,
|
|
pInfParms->pSetupDirectory,
|
|
pInfParms->pInfDirectory,
|
|
pInfParms->pOptionSelected,
|
|
pInfParms->pServerName,
|
|
&ExitCode );
|
|
|
|
if( SetupOK && ( ExitCode == 0 ) )
|
|
{
|
|
DBGMSG( DBG_INFO, ( "%s was installed.\n",
|
|
pInfParms->pOptionSelected ) );
|
|
|
|
OK = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DBGMSG( DBG_WARNING, ( "Setup failed: return code %d; exit code %d\n",
|
|
SetupOK, ExitCode ) );
|
|
}
|
|
}
|
|
|
|
FreeSplStr( pInfParms->pSetupDirectory );
|
|
FreeSplStr( pInfParms->pInfDirectory );
|
|
|
|
|
|
//
|
|
// Callee is responsible for LocalFree(pOptions);
|
|
// since pOptionSelected points into the buffer.
|
|
//
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
/* This should not happen.
|
|
*/
|
|
DBGMSG( DBG_WARNING, ("GetFullPathName( %s ) failed: Error %d\n",
|
|
FileName, GetLastError( ) ) );
|
|
}
|
|
|
|
CloseInfFile(hInfFile);
|
|
}
|
|
|
|
if( OK )
|
|
EndDialog(hwnd, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
BOOL InstallDriverCommandCancel(HWND hwnd)
|
|
{
|
|
EndDialog(hwnd, FALSE);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
TCHAR LastChar(TCHAR *string)
|
|
{
|
|
while(*string) /* Increment to the null terminator */
|
|
string++;
|
|
|
|
return *(--string);
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
void AppendChar(TCHAR *string, TCHAR ch)
|
|
{
|
|
while(*string) /* Increment to the null terminator */
|
|
string++;
|
|
|
|
*string++ = ch;
|
|
*string = NULLC;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// InvokeSetup
|
|
//
|
|
// Call the SETUP.EXE program to install an option listed in an .INF file.
|
|
// The SETUP program will make the correct registry entries for this option
|
|
// under both HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER. It will set the
|
|
// new default value for the USER (i.e. a new locale or keyboard layout).
|
|
//
|
|
|
|
BOOL InvokeSetup (HWND hwnd, LPTSTR pszInfFile, LPTSTR pszSetupDirectory,
|
|
LPTSTR pszInfDirectory, LPTSTR pszOption, LPTSTR pszServerName,
|
|
PDWORD pExitCode)
|
|
{
|
|
TCHAR *pszSetupString = TEXT("\\SETUP.EXE -f -s %s -i %s\\%s -c ExternalInstallOption \
|
|
/t STF_LANGUAGE = ENG /t OPTION = \"%s\" /t STF_PRINTSERVER = \"%s\" /t ADDCOPY = YES \
|
|
/t DOCOPY = YES /t DOCONFIG = YES /w %d");
|
|
|
|
int CmdSetupLength;
|
|
TCHAR pszSetup[200+MAX_PATH];
|
|
TCHAR *pszCmdSetup;
|
|
MSG Msg;
|
|
STARTUPINFO StartupInfo;
|
|
PROCESS_INFORMATION ProcessInformation;
|
|
BOOL b;
|
|
|
|
// Create command line to invoke SETUP program
|
|
|
|
*pszSetup = NULLC;
|
|
GetSystemDirectory( pszSetup, sizeof pszSetup/sizeof(TCHAR) );
|
|
|
|
_tcscat( pszSetup, pszSetupString );
|
|
|
|
/* SLIGHT HACK:
|
|
*
|
|
* Currently we specify both setup and inf directories, or neither:
|
|
* We'll need to get more sophisticated if other combinations are needed.
|
|
*/
|
|
if( !pszSetupDirectory && !pszInfDirectory )
|
|
{
|
|
DeleteSubstring( pszSetup, TEXT("-s %s ") );
|
|
DeleteSubstring( pszSetup, TEXT("%s\\") );
|
|
}
|
|
|
|
/* Find out how much buffer we need for the command.
|
|
* Theoretically this could be enormous.
|
|
*
|
|
* The 20 is for the window handle passed in ascii.
|
|
*
|
|
*/
|
|
|
|
CmdSetupLength = ( _tcslen( pszSetup )+1
|
|
+ ( pszSetupDirectory ? _tcslen( pszSetupDirectory )+1 : 0 )
|
|
+ ( pszInfDirectory ? _tcslen( pszInfDirectory )+1 : 0 )
|
|
+ ( pszServerName ? _tcslen( pszServerName )+1 : 0 )
|
|
+ _tcslen( pszOption )+1
|
|
+ _tcslen( pszInfFile )+1 ) * sizeof(TCHAR)
|
|
+ 20;
|
|
|
|
if( !( pszCmdSetup = AllocSplMem( CmdSetupLength ) ) )
|
|
return FALSE;
|
|
|
|
if( !pszServerName )
|
|
pszServerName = TEXT("");
|
|
|
|
if( !pszSetupDirectory && !pszInfDirectory )
|
|
{
|
|
wsprintf (pszCmdSetup,
|
|
pszSetup,
|
|
pszInfFile,
|
|
pszOption,
|
|
pszServerName,
|
|
hwnd);
|
|
}
|
|
else
|
|
{
|
|
wsprintf (pszCmdSetup,
|
|
pszSetup,
|
|
pszSetupDirectory,
|
|
pszInfDirectory,
|
|
pszInfFile,
|
|
pszOption,
|
|
pszServerName,
|
|
hwnd);
|
|
}
|
|
|
|
// Create screen saver process
|
|
ZERO_OUT( &StartupInfo );
|
|
StartupInfo.cb = sizeof(StartupInfo);
|
|
StartupInfo.wShowWindow = SW_SHOW;
|
|
|
|
|
|
b = CreateProcess ( NULL,
|
|
pszCmdSetup,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
&ProcessInformation
|
|
);
|
|
// If process creation successful, wait for it to
|
|
// complete before continuing
|
|
|
|
if ( b )
|
|
{
|
|
EnableWindow (hwnd, FALSE);
|
|
while (MsgWaitForMultipleObjects (
|
|
1,
|
|
&ProcessInformation.hProcess,
|
|
FALSE,
|
|
(DWORD)-1,
|
|
QS_ALLINPUT) != 0)
|
|
{
|
|
// This message loop is a duplicate of main
|
|
// message loop with the exception of using
|
|
// PeekMessage instead of waiting inside of
|
|
// GetMessage. Process wait will actually
|
|
// be done in MsgWaitForMultipleObjects api.
|
|
//
|
|
while (PeekMessage (&Msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage (&Msg);
|
|
DispatchMessage (&Msg);
|
|
}
|
|
|
|
}
|
|
|
|
GetExitCodeProcess (ProcessInformation.hProcess, pExitCode);
|
|
|
|
CloseHandle (ProcessInformation.hProcess);
|
|
CloseHandle (ProcessInformation.hThread);
|
|
|
|
EnableWindow (hwnd, TRUE);
|
|
|
|
SetForegroundWindow (hwnd);
|
|
}
|
|
else
|
|
{
|
|
ReportFailure( hwnd, 0, IDS_ERRORRUNNINGSETUP );
|
|
}
|
|
|
|
FreeSplMem( pszCmdSetup );
|
|
|
|
return b;
|
|
}
|