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.
2018 lines
66 KiB
2018 lines
66 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// File Name: fxocPrnt.cpp
|
|
//
|
|
// Abstract: This provides the printer routines used in the FaxOCM
|
|
// code base.
|
|
//
|
|
// Environment: Windows XP / User Mode
|
|
//
|
|
// Copyright (c) 2000 Microsoft Corporation
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Date: Developer: Comments:
|
|
// ----- ---------- ---------
|
|
// 17-Feb-1996 Wesley Witt (wesw) Created routines originally from util.cpp
|
|
// 21-Mar-2000 Oren Rosenbloom (orenr) Cleaned up, renamed, re-organized fns
|
|
// 17-Jul-2000 Eran Yariv (erany) Added CoClassInstalled code
|
|
// 08-Jan-2001 Mooly Beery (moolyb) Modified CoClassInstaller (wizard integration)
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "faxocm.h"
|
|
#pragma hdrstop
|
|
#include <shellapi.h>
|
|
#include <winsprlp.h>
|
|
#include <setuputil.h>
|
|
|
|
|
|
// W2K Printer defines
|
|
#define prv_W2K_FAX_PORT_NAME _T("MSFAX:") // Win2K Fax printer port name
|
|
#define prv_W2K_FAX_DRIVER_NAME _T("Windows NT Fax Driver") // Win2K Fax printer driver name
|
|
#define prv_W2K_FAX_MONITOR_NAME _T("Windows NT Fax Monitor") // Win2K Fax printer monitor name
|
|
|
|
#define prv_W9X_PRINTER_DRIVER_FOLDER _T("\\clients\\faxclient\\drivers\\W9X")
|
|
#define prv_NT4_PRINTER_DRIVER_FOLDER _T("\\clients\\faxclient\\drivers\\NT4")
|
|
#define prv_PRINTER_DRIVER_FOLDER _T("\\clients\\faxclient\\drivers")
|
|
|
|
#define prv_SYSTEM32_PATH _T("%windir%\\system32")
|
|
#define prv_SERVER_SERVICE_NAME _T("LanmanServer")
|
|
#define prv_SPOOLER_SERVICE_NAME _T("Spooler")
|
|
|
|
//////////////////////// Static Function Prototypes /////////////////////////
|
|
static DWORD prv_DeleteFaxPrinter(LPCTSTR lpctstrDriverName, LPCTSTR lpctstrPortName);
|
|
|
|
static DWORD prv_CreatePrintMonitor(const TCHAR *pszMonitorName,
|
|
const TCHAR *pszMonitorFile);
|
|
|
|
static DWORD prv_DeletePrintMonitor(const TCHAR *pszMonitorName);
|
|
|
|
static DWORD prv_DeleteFaxPrinterDriver(LPTSTR lptstrDriverName,
|
|
LPTSTR pEnviroment,
|
|
DWORD dwVersionFlag);
|
|
|
|
static DWORD prv_AddFaxPrinterDriver(LPCTSTR lpctstrDriverSourcePath,LPCTSTR pEnvironment=NULL);
|
|
|
|
DWORD IsFaxInstalled (LPBOOL lpbInstalled);
|
|
|
|
static INT_PTR CALLBACK prv_dlgInstallFaxQuestion(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
///////////////////////////////
|
|
// prv_GVAR
|
|
//
|
|
//
|
|
static struct prv_GVAR
|
|
{
|
|
TCHAR szFaxPrinterName[255 + 1];
|
|
} prv_GVAR;
|
|
|
|
static bool bIsPnpInstallation = true;
|
|
|
|
///////////////////////////////
|
|
// fxocPrnt_Init
|
|
//
|
|
// Initialize the fax printer
|
|
// subsystem.
|
|
//
|
|
// Params:
|
|
// - void.
|
|
// Returns:
|
|
// - NO_ERROR on success.
|
|
// - error code otherwise.
|
|
//
|
|
DWORD fxocPrnt_Init(void)
|
|
{
|
|
DWORD dwRes = NO_ERROR;
|
|
DBG_ENTER(_T("Init Print Module"),dwRes);
|
|
return dwRes;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// fxocPrnt_Term
|
|
//
|
|
// Terminate the fax printer
|
|
// subsystem.
|
|
//
|
|
// Params:
|
|
// - void.
|
|
// Returns:
|
|
// - NO_ERROR on success.
|
|
// - error code otherwise.
|
|
//
|
|
DWORD fxocPrnt_Term(void)
|
|
{
|
|
DWORD dwRes = NO_ERROR;
|
|
DBG_ENTER(_T("Term Print Module"),dwRes);
|
|
return dwRes;
|
|
}
|
|
|
|
|
|
///////////////////////////////
|
|
// fxocPrnt_Install
|
|
//
|
|
// Install fax printer monitor and driver(s)
|
|
// Note: Doesn't install the actual printer!
|
|
//
|
|
// Params:
|
|
// - pszSubcomponentId
|
|
// - pszInstallSection
|
|
// Returns:
|
|
// - NO_ERROR on success.
|
|
// - error code otherwise.
|
|
//
|
|
DWORD fxocPrnt_Install(const TCHAR *pszSubcomponentId,
|
|
const TCHAR *pszInstallSection)
|
|
{
|
|
DWORD dwReturn = NO_ERROR;
|
|
|
|
DBG_ENTER( _T("fxocPrnt_Install"),
|
|
dwReturn,
|
|
_T("%s - %s"),
|
|
pszSubcomponentId,
|
|
pszInstallSection);
|
|
//
|
|
// Before we do anything related to the printer, make sure that the 'LanManServer'
|
|
// service is started.
|
|
// The AddPrinter() code in the spooler service requires the LanManServer (SMB file sharing service)
|
|
// service to be running.
|
|
// For some reason LanManServer is not running yet when doing a system install (GUI mode) of
|
|
// Windows XP Professional (in Server it does).
|
|
//
|
|
|
|
// it's possible that LanmanServer is not installed on Desktop SKUs
|
|
if (!IsDesktopSKU())
|
|
{
|
|
dwReturn = fxocSvc_StartService(prv_SERVER_SERVICE_NAME);
|
|
if (dwReturn == NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Successfully started '%s' service, continuing Printer Install"),
|
|
prv_SERVER_SERVICE_NAME);
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to start '%s' service, rc = 0x%lx, abandoning ")
|
|
_T("fax printer installation"),
|
|
prv_SERVER_SERVICE_NAME,
|
|
dwReturn);
|
|
|
|
return dwReturn;
|
|
}
|
|
}
|
|
|
|
// verify that the spooler is up
|
|
dwReturn = fxocSvc_StartService(prv_SPOOLER_SERVICE_NAME);
|
|
if (dwReturn == NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Successfully started '%s' service, continuing Printer Install"),
|
|
prv_SPOOLER_SERVICE_NAME);
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to start '%s' service, rc = 0x%lx, abandoning ")
|
|
_T("fax printer installation"),
|
|
prv_SPOOLER_SERVICE_NAME,
|
|
dwReturn);
|
|
|
|
return dwReturn;
|
|
}
|
|
//
|
|
// always attemp to remove W2K fax printer
|
|
dwReturn = prv_DeleteFaxPrinter(prv_W2K_FAX_DRIVER_NAME, prv_W2K_FAX_PORT_NAME);
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Failed to delete W2K fax printer, rc = 0x%lx"),
|
|
dwReturn);
|
|
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
//
|
|
// delete the W2K printer driver files
|
|
//
|
|
dwReturn = prv_DeleteFaxPrinterDriver(prv_W2K_FAX_DRIVER_NAME, NULL, 3);
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Failed to delete W2K fax drivers, rc = 0x%lx"),
|
|
dwReturn);
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
//
|
|
// delete the W2K fax print monitor.
|
|
//
|
|
dwReturn = prv_DeletePrintMonitor(prv_W2K_FAX_MONITOR_NAME);
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Failed to delete W2K fax monitor, rc = 0x%lx"),
|
|
dwReturn);
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
//
|
|
// okay lets go and create a fax printer monitor.
|
|
//
|
|
if (dwReturn == NO_ERROR)
|
|
{
|
|
// create the print monitor
|
|
dwReturn = prv_CreatePrintMonitor(FAX_MONITOR_NAME,
|
|
FAX_MONITOR_FILE);
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Fax Printer Install, ")
|
|
_T("failed to create fax printer monitor, rc=0x%lx"),
|
|
dwReturn);
|
|
|
|
}
|
|
}
|
|
//
|
|
// Copy the fax printer driver files
|
|
//
|
|
if (dwReturn == NO_ERROR)
|
|
{
|
|
dwReturn = prv_AddFaxPrinterDriver(prv_SYSTEM32_PATH prv_PRINTER_DRIVER_FOLDER);
|
|
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to copy Fax Printer Drivers from '%s', ")
|
|
_T("attempting to install fax printer anyway..., rc=0x%lx"),
|
|
prv_SYSTEM32_PATH,
|
|
dwReturn);
|
|
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
if (IsFaxShared())
|
|
{
|
|
//
|
|
// For SKUs which support fax sharing, let's add the printer drivers for W9X and NT4 too.
|
|
//
|
|
dwReturn = prv_AddFaxPrinterDriver(prv_SYSTEM32_PATH prv_W9X_PRINTER_DRIVER_FOLDER,W9X_PRINT_ENV);
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to copy Fax Printer Drivers for W9X, rc=0x%lx"),
|
|
dwReturn);
|
|
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
dwReturn = prv_AddFaxPrinterDriver(prv_SYSTEM32_PATH prv_NT4_PRINTER_DRIVER_FOLDER,NT4_PRINT_ENV);
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to copy Fax Printer Drivers for NT4, rc=0x%lx"),
|
|
dwReturn);
|
|
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////
|
|
// fxocPrnt_InstallPrinter
|
|
//
|
|
// Checks whether there are any Fax-capable TAPI devices
|
|
// If there are, installs the Fax printer.
|
|
//
|
|
// Params:
|
|
// Returns:
|
|
// - NO_ERROR on success.
|
|
// - error code otherwise.
|
|
//
|
|
DWORD fxocPrnt_InstallPrinter()
|
|
{
|
|
DWORD dwReturn = NO_ERROR;
|
|
DWORD dwFaxDevicesCount = 0;
|
|
|
|
DBG_ENTER( _T("fxocPrnt_InstallPrinter"), dwReturn);
|
|
//
|
|
// Count the number of Fax-capable modems the system has
|
|
//
|
|
dwReturn = GetFaxCapableTapiLinesCount(&dwFaxDevicesCount, FAX_MODEM_PROVIDER_NAME);
|
|
if (ERROR_SUCCESS != dwReturn)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("GetFaxCapableTapiLinesCount"), dwReturn);
|
|
//
|
|
// Assume no fax-capable devices exist
|
|
//
|
|
dwFaxDevicesCount = 0;
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
//
|
|
// We do not create the printer by default unless;
|
|
// 1. There are now fax-capable modems in the system or
|
|
// 2. a fax printer was already there.
|
|
//
|
|
// Otherwise, only the monitor and drivers are installed.
|
|
// The printer itself will be added either when an FSP / EFSP is registered or
|
|
// when a modem is installed.
|
|
//
|
|
if (dwFaxDevicesCount && (dwReturn == NO_ERROR))
|
|
{
|
|
TCHAR szFaxPrinterName[255 + 1] = {0};
|
|
|
|
dwReturn = fxocPrnt_GetFaxPrinterName(szFaxPrinterName,
|
|
sizeof(szFaxPrinterName) / sizeof(TCHAR));
|
|
if (ERROR_SUCCESS != dwReturn)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("fxocPrnt_GetFaxPrinterName"), dwReturn);
|
|
return dwReturn;
|
|
}
|
|
//
|
|
// Create the fax printer.
|
|
//
|
|
dwReturn = AddLocalFaxPrinter (szFaxPrinterName, NULL);
|
|
if (dwReturn == NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Fax Printer Install, created fax printer ")
|
|
_T("Name = '%s', Driver Name = '%s'"),
|
|
szFaxPrinterName,
|
|
FAX_DRIVER_NAME);
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("fxocPrnt_Install, ")
|
|
_T("failed to create fax printer, rc = 0x%lx"),
|
|
dwReturn);
|
|
}
|
|
}
|
|
return dwReturn;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// fxocPrnt_Uninstall
|
|
//
|
|
// Remove all fax printers on this
|
|
// machine.
|
|
//
|
|
// Params:
|
|
// - pszSubcomponentId
|
|
// - pszUninstallSection.
|
|
// Returns:
|
|
// - NO_ERROR on success.
|
|
// - error code otherwise.
|
|
//
|
|
//
|
|
DWORD fxocPrnt_Uninstall(const TCHAR *pszSubcomponentId,
|
|
const TCHAR *pszUninstallSection)
|
|
{
|
|
DWORD dwReturn = NO_ERROR;
|
|
|
|
// before we do anything related to the printer, make sure that the 'Server'
|
|
// service is started.
|
|
DBG_ENTER( _T("fxocPrnt_Uninstall"),
|
|
dwReturn,
|
|
_T("%s - %s"),
|
|
pszSubcomponentId,
|
|
pszUninstallSection);
|
|
|
|
// it's possible that LanmanServer is not installed on Desktop SKUs
|
|
if (!IsDesktopSKU())
|
|
{
|
|
dwReturn = fxocSvc_StartService(prv_SERVER_SERVICE_NAME);
|
|
if (dwReturn == NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Successfully started '%s' service, continuing Printer uninstall"),
|
|
prv_SERVER_SERVICE_NAME);
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to start '%s' service, rc = 0x%lx, abandoning ")
|
|
_T("fax printer uninstall"),
|
|
prv_SERVER_SERVICE_NAME,
|
|
dwReturn);
|
|
|
|
return dwReturn;
|
|
}
|
|
}
|
|
// verify that the spooler is up
|
|
dwReturn = fxocSvc_StartService(prv_SPOOLER_SERVICE_NAME);
|
|
if (dwReturn == NO_ERROR)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Successfully started '%s' service, continuing Printer Install"),
|
|
prv_SPOOLER_SERVICE_NAME);
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to start '%s' service, rc = 0x%lx, abandoning ")
|
|
_T("fax printer installation"),
|
|
prv_SPOOLER_SERVICE_NAME,
|
|
dwReturn);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
// remove the fax printer
|
|
prv_DeleteFaxPrinter(FAX_DRIVER_NAME, FAX_MONITOR_PORT_NAME);
|
|
|
|
// remove fax printer monitor
|
|
prv_DeletePrintMonitor(FAX_MONITOR_NAME);
|
|
|
|
// remove all fax printer drivers
|
|
prv_DeleteFaxPrinterDriver(FAX_DRIVER_NAME, NULL, 3);
|
|
//
|
|
// For SKUs which support fax sharing, remove down-level drivers as well.
|
|
//
|
|
if (IsFaxShared())
|
|
{
|
|
prv_DeleteFaxPrinterDriver(FAX_DRIVER_NAME, NT4_PRINT_ENV, 2);
|
|
prv_DeleteFaxPrinterDriver(FAX_DRIVER_NAME, W9X_PRINT_ENV, 0);
|
|
}
|
|
return dwReturn;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// fxocPrnt_SetFaxPrinterName
|
|
//
|
|
// Sets the name of the fax printer.
|
|
// This must be called prior to the
|
|
// creation of the fax printer via
|
|
// fxocPrnt_Install.
|
|
//
|
|
// Params:
|
|
// - pszFaxPrinterName - new name for fax printer.
|
|
// Returns:
|
|
// - void.
|
|
//
|
|
void fxocPrnt_SetFaxPrinterName(const TCHAR* pszFaxPrinterName)
|
|
{
|
|
DBG_ENTER( _T("fxocPrnt_SetFaxPrinterName"),
|
|
_T("%s"),
|
|
pszFaxPrinterName);
|
|
|
|
if (pszFaxPrinterName)
|
|
{
|
|
_tcsncpy(prv_GVAR.szFaxPrinterName,
|
|
pszFaxPrinterName,
|
|
sizeof(prv_GVAR.szFaxPrinterName) / sizeof(TCHAR));
|
|
}
|
|
else
|
|
{
|
|
memset(prv_GVAR.szFaxPrinterName,
|
|
0,
|
|
sizeof(prv_GVAR.szFaxPrinterName));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void fxocPrnt_SetFaxPrinterShared(BOOL IsFaxPrinterShared)
|
|
{
|
|
DBG_ENTER( _T("fxocPrnt_SetFaxPrinterShared"),
|
|
_T("%d"),
|
|
IsFaxPrinterShared);
|
|
|
|
HKEY hFaxKey = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_FAX_SETUP,TRUE,KEY_WRITE);
|
|
if (hFaxKey)
|
|
{
|
|
if (SetRegistryDword(hFaxKey,REGVAL_IS_SHARED_FAX_PRINTER,(IsFaxPrinterShared ? 1 : 0)))
|
|
{
|
|
VERBOSE(DBG_MSG, TEXT("Fax is installed in a mode that enables sharing"));
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(DBG_MSG, TEXT("SetRegistryDword failed (ec=%d)"),GetLastError());
|
|
}
|
|
RegCloseKey(hFaxKey);
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR, TEXT("Failed to create REGKEY_FAX_SETUP, printer won't be shared (ec=%d)"),GetLastError());
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////
|
|
// fxocPrnt_GetFaxPrinterName
|
|
//
|
|
// Returns the current name of the
|
|
// fax printer.
|
|
//
|
|
// Params:
|
|
// - pszFaxPrinterName - OUT
|
|
// - dwNumBufChars
|
|
// Returns:
|
|
// - NO_ERROR on success
|
|
// - error code otherwise.
|
|
//
|
|
DWORD fxocPrnt_GetFaxPrinterName(TCHAR* pszFaxPrinterName,
|
|
DWORD dwNumBufChars)
|
|
{
|
|
DWORD dwReturn = NO_ERROR;
|
|
DBG_ENTER( _T("fxocPrnt_GetFaxPrinterName"), dwReturn);
|
|
|
|
if ((pszFaxPrinterName == NULL) ||
|
|
(dwNumBufChars == 0))
|
|
{
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
return dwReturn;
|
|
}
|
|
|
|
if (prv_GVAR.szFaxPrinterName[0] != 0)
|
|
{
|
|
_tcsncpy(pszFaxPrinterName,
|
|
prv_GVAR.szFaxPrinterName,
|
|
dwNumBufChars);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// nobody set the fax printer name, so return the default
|
|
// table.
|
|
_tcsncpy(pszFaxPrinterName,
|
|
FAX_PRINTER_NAME,
|
|
dwNumBufChars);
|
|
}
|
|
|
|
return dwReturn;
|
|
} // fxocPrnt_GetFaxPrinterName
|
|
|
|
LPCTSTR lpctstrDriverFilesW2KandXP[] =
|
|
{
|
|
FAX_UI_MODULE_NAME, // FXSUI.DLL
|
|
FAX_DRV_MODULE_NAME, // FXSDRV.DLL
|
|
FAX_WZRD_MODULE_NAME, // FXSWZRD.DLL
|
|
FAX_TIFF_MODULE_NAME, // FXSTIFF.DLL
|
|
FAX_API_MODULE_NAME, // FXSAPI.DLL
|
|
FAX_RES_FILE
|
|
};
|
|
|
|
LPCTSTR lpctstrDriverFilesNT4[] =
|
|
{
|
|
FAX_NT4_DRV_MODULE_NAME, // FXSDRV4.DLL
|
|
FAX_UI_MODULE_NAME, // FXSUI.DLL
|
|
FAX_WZRD_MODULE_NAME, // FXSWZRD.DLL
|
|
FAX_API_MODULE_NAME, // FXSAPI.DLL
|
|
FAX_TIFF_FILE, // FXSTIFF.DLL
|
|
FAX_RES_FILE
|
|
};
|
|
|
|
LPCTSTR lpctstrDriverFilesW9X[] =
|
|
{
|
|
FAX_DRV_WIN9X_32_MODULE_NAME, // FXSDRV32.DLL
|
|
FAX_DRV_WIN9X_16_MODULE_NAME, // FXSDRV16.DRV
|
|
FAX_API_MODULE_NAME, // FXSAPI.DLL
|
|
FAX_DRV_UNIDRV_MODULE_NAME, // UNIDRV.DLL
|
|
FAX_DRV_UNIDRV_HELP, // UNIDRV.HLP
|
|
FAX_DRV_ICONLIB, // ICONLIB.DLL
|
|
FAX_WZRD_MODULE_NAME, // FXSWZRD.DLL
|
|
FAX_TIFF_FILE, // FXSTIFF.DLL
|
|
FAX_RES_FILE
|
|
};
|
|
|
|
///////////////////////////////////
|
|
// prv_AddFaxPrinterDriver
|
|
//
|
|
// Add printer driver to the server machine.
|
|
// In case of failure, do clean-up and returns FALSE.
|
|
// Temp files are deleted allways.
|
|
//
|
|
// Params:
|
|
// - lpctstrDriverSourcePath : The directory where the printer's driver files
|
|
// are located (put there by the setup)
|
|
// - pEnvironment : for which platform are the drivers added
|
|
//
|
|
static DWORD prv_AddFaxPrinterDriver(LPCTSTR lpctstrDriverSourcePath,LPCTSTR pEnvironment)
|
|
{
|
|
DWORD dwReturn = NO_ERROR;
|
|
BOOL bSuccess = FALSE;
|
|
LPCTSTR* filesToCopy = NULL;
|
|
DWORD dwFileCount = 0;
|
|
DWORD dwNeededSize = 0;
|
|
TCHAR szPrinterDriverDirectory[MAX_PATH] = {0};
|
|
TCHAR szSourceDir[MAX_PATH] = {0};
|
|
DWORD dwNumChars = 0;
|
|
|
|
DBG_ENTER( _T("prv_AddFaxPrinterDriver"),
|
|
dwReturn,
|
|
_T("%s - %s"),
|
|
lpctstrDriverSourcePath,
|
|
pEnvironment);
|
|
|
|
if (!GetPrinterDriverDirectory(NULL,
|
|
(LPTSTR)pEnvironment,
|
|
1,
|
|
(LPBYTE)szPrinterDriverDirectory,
|
|
sizeof(szPrinterDriverDirectory),
|
|
&dwNeededSize))
|
|
{
|
|
dwReturn = GetLastError();
|
|
VERBOSE(SETUP_ERR,
|
|
TEXT("GetPrinterDriverDirectory failed - %d."),
|
|
dwReturn);
|
|
return dwReturn;
|
|
}
|
|
|
|
bSuccess = TRUE;
|
|
|
|
VERBOSE(DBG_MSG,
|
|
_T("Printer driver directory is %s\n"),
|
|
szPrinterDriverDirectory);
|
|
|
|
if (pEnvironment==NULL)
|
|
{
|
|
filesToCopy = lpctstrDriverFilesW2KandXP;
|
|
dwFileCount = sizeof(lpctstrDriverFilesW2KandXP)/sizeof(LPCTSTR);
|
|
}
|
|
else if (_tcsicmp(pEnvironment,NT4_PRINT_ENV)==0)
|
|
{
|
|
filesToCopy = lpctstrDriverFilesNT4;
|
|
dwFileCount = sizeof(lpctstrDriverFilesNT4)/sizeof(LPCTSTR);
|
|
}
|
|
else if (_tcsicmp(pEnvironment,W9X_PRINT_ENV)==0)
|
|
{
|
|
filesToCopy = lpctstrDriverFilesW9X;
|
|
dwFileCount = sizeof(lpctstrDriverFilesW9X)/sizeof(LPCTSTR);
|
|
}
|
|
|
|
if (bSuccess)
|
|
{
|
|
dwNumChars = ExpandEnvironmentStrings(lpctstrDriverSourcePath,
|
|
szSourceDir,
|
|
sizeof(szSourceDir) / sizeof(TCHAR));
|
|
if (dwNumChars == 0)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("ExpandEnvironmentStrings failed, rc = 0x%lx"),
|
|
::GetLastError());
|
|
|
|
bSuccess = FALSE;
|
|
}
|
|
}
|
|
|
|
if (bSuccess)
|
|
{
|
|
bSuccess = MultiFileCopy(dwFileCount,
|
|
filesToCopy,
|
|
szSourceDir,
|
|
szPrinterDriverDirectory);
|
|
|
|
if (!bSuccess)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("MultiFileCopy failed (ec: %ld)"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
if (bSuccess)
|
|
{
|
|
|
|
DRIVER_INFO_3 DriverInfo3;
|
|
ZeroMemory(&DriverInfo3,sizeof(DRIVER_INFO_3));
|
|
|
|
// fill DRIVER_INFO_3 depending on pEnv...
|
|
bSuccess = FillDriverInfo(&DriverInfo3,pEnvironment);
|
|
if (bSuccess)
|
|
{
|
|
bSuccess = AddPrinterDriverEx(NULL,
|
|
3,
|
|
(LPBYTE)&DriverInfo3,
|
|
APD_COPY_NEW_FILES|APD_DONT_SET_CHECKPOINT);
|
|
if (bSuccess)
|
|
{
|
|
VERBOSE(DBG_MSG,_T("Successfully added new fax printer drivers"));
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,_T("AddPrinterDriverEx failed (ec: %ld)"),GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,_T("FillDriverInfo failed, try to continue"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Delete the temporary fax DLL files.
|
|
//
|
|
if (!MultiFileDelete(dwFileCount,
|
|
filesToCopy,
|
|
szPrinterDriverDirectory))
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("MultiFileDelete() failed (ec: %ld)"),
|
|
GetLastError());
|
|
}
|
|
|
|
if (!bSuccess)
|
|
{
|
|
dwReturn = ::GetLastError();
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////
|
|
// prv_DeletePrinter
|
|
//
|
|
// Delete printer by name. The driver name and the port name are just for debug print.
|
|
//
|
|
// Params:
|
|
// - pszPrinterName - name of printer to delete
|
|
// - pszFaxDriver - name of associated driver
|
|
// - pszPortName - name of associated port.
|
|
//
|
|
static DWORD prv_DeletePrinter(const TCHAR *pszPrinterName,
|
|
const TCHAR *pszFaxDriver,
|
|
const TCHAR *pszPortName)
|
|
{
|
|
DWORD dwReturn = NO_ERROR;
|
|
BOOL bSuccess = FALSE;
|
|
HANDLE hPrinter = NULL;
|
|
PRINTER_DEFAULTS PrinterDefaults =
|
|
{
|
|
NULL,
|
|
NULL,
|
|
PRINTER_ALL_ACCESS
|
|
};
|
|
|
|
DBG_ENTER( _T("prv_DeletePrinter"),
|
|
dwReturn,
|
|
_T("%s - %s - %s"),
|
|
pszPrinterName,
|
|
pszFaxDriver,
|
|
pszPortName);
|
|
|
|
if ((pszPrinterName == NULL) ||
|
|
(pszFaxDriver == NULL) ||
|
|
(pszPortName == NULL))
|
|
{
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
return dwReturn;
|
|
}
|
|
|
|
bSuccess = ::OpenPrinter((TCHAR*) pszPrinterName,
|
|
&hPrinter,
|
|
&PrinterDefaults);
|
|
|
|
if (bSuccess)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("prv_DeletePrinter, deleting ")
|
|
_T("printer '%s' with Driver Name = '%s', ")
|
|
_T("Port Name = '%s'"),
|
|
pszPrinterName,
|
|
pszFaxDriver,
|
|
pszPortName);
|
|
|
|
if (!SetPrinter(hPrinter,0,NULL,PRINTER_CONTROL_PURGE))
|
|
{
|
|
// Don't let a failure here keep us from attempting the delete
|
|
VERBOSE(PRINT_ERR,TEXT("SetPrinter failed (purge jobs before uninstall) ec=%d"),GetLastError());
|
|
}
|
|
|
|
bSuccess = ::DeletePrinter(hPrinter);
|
|
|
|
if (!bSuccess)
|
|
{
|
|
dwReturn = ::GetLastError();
|
|
|
|
VERBOSE(SETUP_ERR,
|
|
_T("prv_DeletePrinter, failed to delete ")
|
|
_T("fax printer '%s', rc = 0x%lx"),
|
|
pszPrinterName,
|
|
dwReturn);
|
|
}
|
|
|
|
bSuccess = ::ClosePrinter(hPrinter);
|
|
|
|
if (!bSuccess)
|
|
{
|
|
dwReturn = ::GetLastError();
|
|
|
|
VERBOSE(SETUP_ERR,
|
|
_T("prv_DeletePrinter, failed to Close ")
|
|
_T("fax printer '%s', rc = 0x%lx"),
|
|
pszPrinterName,
|
|
dwReturn);
|
|
}
|
|
|
|
hPrinter = NULL;
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// prv_DeleteFaxPrinter
|
|
//
|
|
// Delete fax printer with driver name and port as passed in params
|
|
//
|
|
// Params:
|
|
// LPCTSTR lpctstrDriverName - printer driver name to delete
|
|
// LPCTSTR lpctstrPortName - printer port name
|
|
|
|
//
|
|
//
|
|
//
|
|
static DWORD prv_DeleteFaxPrinter(LPCTSTR lpctstrDriverName, LPCTSTR lpctstrPortName)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
DWORD dwReturn = NO_ERROR;
|
|
DWORD dwCount = 0;
|
|
DWORD i = 0;
|
|
PPRINTER_INFO_2 pPrinterInfo = NULL;
|
|
|
|
DBG_ENTER(_T("prv_DeleteFaxPrinter"),dwReturn);
|
|
|
|
pPrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters(NULL,
|
|
2,
|
|
&dwCount,
|
|
PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
|
|
|
|
VERBOSE(DBG_MSG,
|
|
_T("DeleteFaxPrinter, found %lu printers installed ")
|
|
_T("on this computer"),
|
|
dwCount);
|
|
|
|
if (pPrinterInfo)
|
|
{
|
|
for (i=0; i < dwCount; i++)
|
|
{
|
|
// Check if printer has same driver same port name
|
|
if (_tcsicmp(pPrinterInfo[i].pDriverName, lpctstrDriverName) == 0 &&
|
|
_tcsicmp(pPrinterInfo[i].pPortName, lpctstrPortName) == 0)
|
|
|
|
{
|
|
// We can have a Local printer here or a Printer connection.
|
|
// we differentiate between the two by the ServerName field of
|
|
// PRINTER_INFO_2
|
|
if (pPrinterInfo[i].pServerName==NULL)
|
|
{
|
|
// this is a local printer.
|
|
dwReturn = prv_DeletePrinter(pPrinterInfo[i].pPrinterName,
|
|
lpctstrDriverName,
|
|
lpctstrPortName);
|
|
if (dwReturn != NO_ERROR)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to delete printer '%s', rc = 0x%lx, ")
|
|
_T("continuing anyway..."),
|
|
pPrinterInfo[i].pPrinterName,
|
|
dwReturn);
|
|
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this is a printer connection
|
|
if (!DeletePrinterConnection(pPrinterInfo[i].pPrinterName))
|
|
{
|
|
dwReturn = GetLastError();
|
|
VERBOSE(SETUP_ERR,
|
|
_T("Failed to delete printer connection '%s', rc = 0x%lx, ")
|
|
_T("continuing anyway..."),
|
|
pPrinterInfo[i].pPrinterName,
|
|
dwReturn);
|
|
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MemFree(pPrinterInfo);
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
///////////////////////////////
|
|
// prv_CreatePrintMonitor
|
|
//
|
|
// Create the printer monitor
|
|
//
|
|
// Params:
|
|
// - pszMonitorName - name of printer monitor
|
|
// - pszMonitorFile - name of print monitor file
|
|
// Returns:
|
|
// - NO_ERROR on success
|
|
// - error code otherwise.
|
|
//
|
|
static DWORD prv_CreatePrintMonitor(const TCHAR *pszMonitorName,
|
|
const TCHAR *pszMonitorFile)
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
DWORD dwReturn = NO_ERROR;
|
|
MONITOR_INFO_2 MonitorInfo;
|
|
|
|
DBG_ENTER( _T("prv_CreatePrintMonitor"),
|
|
dwReturn,
|
|
_T("%s - %s"),
|
|
pszMonitorName,
|
|
pszMonitorFile);
|
|
|
|
if ((pszMonitorName == NULL) ||
|
|
(pszMonitorFile == NULL))
|
|
{
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
return dwReturn;
|
|
}
|
|
|
|
MonitorInfo.pName = (TCHAR*) pszMonitorName;
|
|
MonitorInfo.pDLLName = (TCHAR*) pszMonitorFile;
|
|
MonitorInfo.pEnvironment = NULL;
|
|
|
|
bSuccess = ::AddMonitor(NULL, 2, (LPBYTE) &MonitorInfo);
|
|
|
|
if (bSuccess)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("Successfully created fax monitor '%s', ")
|
|
_T("File Name '%s'"),
|
|
pszMonitorName,
|
|
pszMonitorFile);
|
|
}
|
|
else
|
|
{
|
|
dwReturn = ::GetLastError();
|
|
|
|
if (dwReturn == ERROR_PRINT_MONITOR_ALREADY_INSTALLED)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("AddMonitor, failed because '%s' monitor already ")
|
|
_T("exists. This is fine, let's continue..."),
|
|
pszMonitorName);
|
|
|
|
dwReturn = NO_ERROR;
|
|
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("CreatePrinterMonitor, failed to ")
|
|
_T("add new print monitor '%s', rc = 0x%lx"),
|
|
pszMonitorName,
|
|
dwReturn);
|
|
}
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
///////////////////////////////
|
|
// prv_DeletePrintMonitor
|
|
//
|
|
// Delete the printer monitor
|
|
//
|
|
// Params:
|
|
// - pszMonitorName - name of print monitor to delete
|
|
// Returns:
|
|
// - NO_ERROR on success
|
|
// - error code otherwise.
|
|
//
|
|
static DWORD prv_DeletePrintMonitor(const TCHAR *pszMonitorName)
|
|
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
DWORD dwReturn = NO_ERROR;
|
|
DBG_ENTER( _T("prv_DeletePrintMonitor"),
|
|
dwReturn,
|
|
_T("%s"),
|
|
pszMonitorName);
|
|
|
|
if (pszMonitorName == NULL)
|
|
{
|
|
dwReturn = ERROR_INVALID_PARAMETER;
|
|
return dwReturn;
|
|
}
|
|
|
|
bSuccess = ::DeleteMonitor(NULL, NULL, (LPTSTR) pszMonitorName);
|
|
|
|
if (bSuccess)
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
_T("DeletePrinterMonitor, successfully ")
|
|
_T("deleted print monitor name '%s'"),
|
|
pszMonitorName);
|
|
}
|
|
else
|
|
{
|
|
dwReturn = ::GetLastError();
|
|
|
|
if (dwReturn != ERROR_UNKNOWN_PRINT_MONITOR)
|
|
{
|
|
VERBOSE(SETUP_ERR,
|
|
_T("DeletePrinterMonitor, failed to ")
|
|
_T("remove print monitor '%s', rc = 0x%lx"),
|
|
pszMonitorName,
|
|
dwReturn);
|
|
}
|
|
else
|
|
{
|
|
dwReturn = NO_ERROR;
|
|
}
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
////////////////////////////
|
|
// prv_DeleteFaxPrinterDriver
|
|
//
|
|
// Delete fax printer driver from current machine
|
|
// In case of failure, log it and returns FALSE.
|
|
//
|
|
// Params:
|
|
// - LPTSTR lptstrDriverName - Driver name to delete
|
|
// - pEnvironment - for which platform are the drivers deleted
|
|
// - DWORD dwVersionFlag - The version of the driver that should be deleted.
|
|
// Valid valuse {0,1,2,3} only.
|
|
// Returns;
|
|
// - Returns ERROR_SUCCESS on success, on failue retuen the error code.
|
|
//
|
|
static DWORD prv_DeleteFaxPrinterDriver(LPTSTR lptstrDriverName,
|
|
LPTSTR pEnviroment,
|
|
DWORD dwVersionFlag)
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
DWORD ec = ERROR_SUCCESS;
|
|
|
|
DBG_ENTER(_T("prv_DeleteFaxPrinterDriver"),ec);
|
|
|
|
ASSERTION(dwVersionFlag<=3);
|
|
|
|
// delete driver.
|
|
bSuccess = DeletePrinterDriverEx(NULL,
|
|
pEnviroment,
|
|
lptstrDriverName,
|
|
DPD_DELETE_SPECIFIC_VERSION|DPD_DELETE_ALL_FILES,
|
|
dwVersionFlag);
|
|
if (!bSuccess)
|
|
{
|
|
ec = GetLastError();
|
|
VERBOSE(DBG_MSG,
|
|
TEXT("DeletePrinterDriverEx() for driver %s, version %ld failed (ec: %ld)"),
|
|
lptstrDriverName,
|
|
dwVersionFlag,
|
|
ec);
|
|
}
|
|
else
|
|
{
|
|
VERBOSE(DBG_MSG,
|
|
TEXT("DeletePrinterDriverEx() for driver %s, version %ld succeeded"),
|
|
lptstrDriverName,
|
|
dwVersionFlag);
|
|
}
|
|
|
|
return ec;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************************
|
|
** **
|
|
** C o C l a s s I n s t a l l e r s e c t i o n **
|
|
** **
|
|
***************************************************************************************/
|
|
|
|
|
|
#ifdef ENABLE_LOGGING
|
|
|
|
typedef struct _DIF_DEBUG {
|
|
DWORD DifValue;
|
|
LPTSTR DifString;
|
|
} DIF_DEBUG, *PDIF_DEBUG;
|
|
|
|
DIF_DEBUG DifDebug[] =
|
|
{
|
|
{ 0, L"" }, // 0x00000000
|
|
{ DIF_SELECTDEVICE, L"DIF_SELECTDEVICE" }, // 0x00000001
|
|
{ DIF_INSTALLDEVICE, L"DIF_INSTALLDEVICE" }, // 0x00000002
|
|
{ DIF_ASSIGNRESOURCES, L"DIF_ASSIGNRESOURCES" }, // 0x00000003
|
|
{ DIF_PROPERTIES, L"DIF_PROPERTIES" }, // 0x00000004
|
|
{ DIF_REMOVE, L"DIF_REMOVE" }, // 0x00000005
|
|
{ DIF_FIRSTTIMESETUP, L"DIF_FIRSTTIMESETUP" }, // 0x00000006
|
|
{ DIF_FOUNDDEVICE, L"DIF_FOUNDDEVICE" }, // 0x00000007
|
|
{ DIF_SELECTCLASSDRIVERS, L"DIF_SELECTCLASSDRIVERS" }, // 0x00000008
|
|
{ DIF_VALIDATECLASSDRIVERS, L"DIF_VALIDATECLASSDRIVERS" }, // 0x00000009
|
|
{ DIF_INSTALLCLASSDRIVERS, L"DIF_INSTALLCLASSDRIVERS" }, // 0x0000000A
|
|
{ DIF_CALCDISKSPACE, L"DIF_CALCDISKSPACE" }, // 0x0000000B
|
|
{ DIF_DESTROYPRIVATEDATA, L"DIF_DESTROYPRIVATEDATA" }, // 0x0000000C
|
|
{ DIF_VALIDATEDRIVER, L"DIF_VALIDATEDRIVER" }, // 0x0000000D
|
|
{ DIF_MOVEDEVICE, L"DIF_MOVEDEVICE" }, // 0x0000000E
|
|
{ DIF_DETECT, L"DIF_DETECT" }, // 0x0000000F
|
|
{ DIF_INSTALLWIZARD, L"DIF_INSTALLWIZARD" }, // 0x00000010
|
|
{ DIF_DESTROYWIZARDDATA, L"DIF_DESTROYWIZARDDATA" }, // 0x00000011
|
|
{ DIF_PROPERTYCHANGE, L"DIF_PROPERTYCHANGE" }, // 0x00000012
|
|
{ DIF_ENABLECLASS, L"DIF_ENABLECLASS" }, // 0x00000013
|
|
{ DIF_DETECTVERIFY, L"DIF_DETECTVERIFY" }, // 0x00000014
|
|
{ DIF_INSTALLDEVICEFILES, L"DIF_INSTALLDEVICEFILES" }, // 0x00000015
|
|
{ DIF_UNREMOVE, L"DIF_UNREMOVE" }, // 0x00000016
|
|
{ DIF_SELECTBESTCOMPATDRV, L"DIF_SELECTBESTCOMPATDRV" }, // 0x00000017
|
|
{ DIF_ALLOW_INSTALL, L"DIF_ALLOW_INSTALL" }, // 0x00000018
|
|
{ DIF_REGISTERDEVICE, L"DIF_REGISTERDEVICE" }, // 0x00000019
|
|
{ DIF_NEWDEVICEWIZARD_PRESELECT, L"DIF_NEWDEVICEWIZARD_PRESELECT" }, // 0x0000001A
|
|
{ DIF_NEWDEVICEWIZARD_SELECT, L"DIF_NEWDEVICEWIZARD_SELECT" }, // 0x0000001B
|
|
{ DIF_NEWDEVICEWIZARD_PREANALYZE, L"DIF_NEWDEVICEWIZARD_PREANALYZE" }, // 0x0000001C
|
|
{ DIF_NEWDEVICEWIZARD_POSTANALYZE, L"DIF_NEWDEVICEWIZARD_POSTANALYZE" }, // 0x0000001D
|
|
{ DIF_NEWDEVICEWIZARD_FINISHINSTALL, L"DIF_NEWDEVICEWIZARD_FINISHINSTALL" }, // 0x0000001E
|
|
{ DIF_UNUSED1, L"DIF_UNUSED1" }, // 0x0000001F
|
|
{ DIF_INSTALLINTERFACES, L"DIF_INSTALLINTERFACES" }, // 0x00000020
|
|
{ DIF_DETECTCANCEL, L"DIF_DETECTCANCEL" }, // 0x00000021
|
|
{ DIF_REGISTER_COINSTALLERS, L"DIF_REGISTER_COINSTALLERS" }, // 0x00000022
|
|
{ DIF_ADDPROPERTYPAGE_ADVANCED, L"DIF_ADDPROPERTYPAGE_ADVANCED" }, // 0x00000023
|
|
{ DIF_ADDPROPERTYPAGE_BASIC, L"DIF_ADDPROPERTYPAGE_BASIC" }, // 0x00000024
|
|
{ DIF_RESERVED1, L"DIF_RESERVED1" }, // 0x00000025
|
|
{ DIF_TROUBLESHOOTER, L"DIF_TROUBLESHOOTER" }, // 0x00000026
|
|
{ DIF_POWERMESSAGEWAKE, L"DIF_POWERMESSAGEWAKE" }, // 0x00000027
|
|
{ DIF_ADDREMOTEPROPERTYPAGE_ADVANCED, L"DIF_ADDREMOTEPROPERTYPAGE_ADVANCED" } // 0x00000028
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// SaveDontShowMeThisAgain
|
|
//
|
|
// Purpose:
|
|
// Check if the user checked the 'Don't show me this again'
|
|
// If he did, set the registry key
|
|
//
|
|
// Params:
|
|
// Handle to window
|
|
//
|
|
// Return Value:
|
|
// None
|
|
//
|
|
// Author:
|
|
// Mooly Beery (MoolyB) 17-Jan-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
void SaveDontShowMeThisAgain(HWND hwndDlg)
|
|
{
|
|
DBG_ENTER(_T("SaveDontShowMeThisAgain"));
|
|
|
|
//
|
|
// let's save the "Don't show me again" state
|
|
//
|
|
if (BST_CHECKED == ::SendMessage (::GetDlgItem (hwndDlg, IDC_DONT_SHOW), BM_GETCHECK, 0, 0))
|
|
{
|
|
//
|
|
// User pressed the "Don't show me again" checkbox
|
|
//
|
|
HKEY hFaxKey = OpenRegistryKey (HKEY_LOCAL_MACHINE,
|
|
REGKEY_FAX_SETUP,
|
|
TRUE,
|
|
KEY_WRITE);
|
|
if (!hFaxKey)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("OpenRegistryKey(REGKEY_FAX_SETUP)"), GetLastError());
|
|
}
|
|
else
|
|
{
|
|
if (!SetRegistryDword (hFaxKey,
|
|
REGVAL_DONT_UNATTEND_INSTALL,
|
|
1))
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("SetRegistryDword(REGVAL_DONT_UNATTEND_INSTALL)"), GetLastError());
|
|
}
|
|
RegCloseKey (hFaxKey);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static
|
|
INT_PTR
|
|
CALLBACK
|
|
prv_dlgInstallFaxQuestionPropPage(
|
|
HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine name : prv_dlgInstallFaxQuestionPropPage
|
|
|
|
Routine description:
|
|
|
|
Dialogs procedure for "Install fax" dialog
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Jul, 2000
|
|
|
|
Arguments:
|
|
|
|
hwndDlg [in] - Handle to dialog box
|
|
uMsg [in] - Message
|
|
wParam [in] - First message parameter
|
|
parameter [in] - Second message parameter
|
|
|
|
Return Value:
|
|
|
|
Standard dialog return value
|
|
|
|
--*/
|
|
/*
|
|
{
|
|
DWORD dwRes = NO_ERROR;
|
|
DBG_ENTER(_T("prv_dlgInstallFaxQuestionPropPage"));
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
// no return value here.
|
|
PropSheet_SetWizButtons(GetParent(hwndDlg),PSWIZB_NEXT);
|
|
|
|
SetFocus(hwndDlg);
|
|
if (!CheckDlgButton(hwndDlg,IDC_INSTALL_FAX_NOW,BST_CHECKED))
|
|
{
|
|
dwRes = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("CheckDlgButton"), dwRes);
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR*)lParam)->code)
|
|
{
|
|
case PSN_WIZNEXT:
|
|
SaveDontShowMeThisAgain(hwndDlg);
|
|
//
|
|
// let's get the "Install Fax Now" state
|
|
//
|
|
if (BST_CHECKED == ::SendMessage (::GetDlgItem (hwndDlg, IDC_INSTALL_FAX_NOW), BM_GETCHECK, 0, 0))
|
|
{
|
|
//
|
|
// User pressed the "Install Fax Now" checkbox
|
|
//
|
|
dwRes = InstallFaxUnattended();
|
|
if (dwRes!=ERROR_SUCCESS)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("InstallFaxUnattended"), dwRes);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
}
|
|
return FALSE;
|
|
} // prv_dlgInstallFaxQuestionPropPage
|
|
*/
|
|
|
|
/*
|
|
static
|
|
INT_PTR
|
|
CALLBACK
|
|
prv_dlgInstallFaxQuestion(
|
|
HWND hwndDlg,
|
|
UINT uMsg,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine name : prv_dlgInstallFaxQuestion
|
|
|
|
Routine description:
|
|
|
|
Dialogs procedure for "Install fax" dialog
|
|
|
|
Author:
|
|
|
|
Eran Yariv (EranY), Jul, 2000
|
|
|
|
Arguments:
|
|
|
|
hwndDlg [in] - Handle to dialog box
|
|
uMsg [in] - Message
|
|
wParam [in] - First message parameter
|
|
parameter [in] - Second message parameter
|
|
|
|
Return Value:
|
|
|
|
Standard dialog return value
|
|
|
|
--*/
|
|
/*
|
|
{
|
|
INT_PTR iRes = IDIGNORE;
|
|
DBG_ENTER(_T("prv_dlgInstallFaxQuestion"));
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
SetFocus(hwndDlg);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDC_ANSWER_YES:
|
|
iRes = IDYES;
|
|
break;
|
|
|
|
case IDC_ANSWER_NO:
|
|
iRes = IDNO;
|
|
break;
|
|
}
|
|
if (IDIGNORE != iRes)
|
|
{
|
|
SaveDontShowMeThisAgain(hwndDlg);
|
|
EndDialog (hwndDlg, iRes);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
} // prv_dlgInstallFaxQuestion
|
|
*/
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// AllowInstallationProposal
|
|
//
|
|
// Purpose:
|
|
// Verify we can propose to the user to install Fax
|
|
// Check if Fax is installed
|
|
// Check if the user has marked the 'don't show this again'
|
|
//
|
|
// Params:
|
|
// None
|
|
//
|
|
// Return Value:
|
|
// true - ok to propose the installation of Fax
|
|
// false - do not propose the Fax installation
|
|
//
|
|
// Author:
|
|
// Mooly Beery (MoolyB) 17-Jan-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
bool AllowInstallationProposal()
|
|
{
|
|
DWORD ec = NO_ERROR;
|
|
BOOL bFaxInstalled = FALSE;
|
|
|
|
DBG_ENTER(_T("AllowInstallationProposal"));
|
|
|
|
ec = IsFaxInstalled (&bFaxInstalled);
|
|
if (ec!=ERROR_SUCCESS)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("IsFaxInstalled"), ec);
|
|
return false;
|
|
}
|
|
if (bFaxInstalled)
|
|
{
|
|
VERBOSE(DBG_MSG,TEXT("Fax is already installed"));
|
|
return false;
|
|
}
|
|
//
|
|
// Let's find out if we're allowed to add a property page
|
|
//
|
|
BOOL bDontShowThisAgain = FALSE;
|
|
HKEY hFaxKey = OpenRegistryKey (HKEY_LOCAL_MACHINE,
|
|
REGKEY_FAX_SETUP,
|
|
FALSE,
|
|
KEY_READ);
|
|
if (!hFaxKey)
|
|
{
|
|
//
|
|
// No value there
|
|
//
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("OpenRegistryKey(REGKEY_FAX_SETUP)"), ec);
|
|
// let's go on.
|
|
}
|
|
else
|
|
{
|
|
bDontShowThisAgain = GetRegistryDword (hFaxKey,REGVAL_DONT_UNATTEND_INSTALL);
|
|
RegCloseKey (hFaxKey);
|
|
}
|
|
if (bDontShowThisAgain)
|
|
{
|
|
//
|
|
// User previously checked the "Don't ask me again" checkbox
|
|
//
|
|
VERBOSE (DBG_MSG, TEXT("Used previously checked the \"Don't ask me again\" checkbox"));
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// HandleNonPnpDevices
|
|
//
|
|
// Purpose:
|
|
// Handles DIF_INSTALLDEVICE
|
|
// A new device has finished installing and we check if this is a non PnP device
|
|
// if it is we propose the user to install Fax using a message box.
|
|
//
|
|
// Params:
|
|
// None
|
|
//
|
|
// Return Value:
|
|
// NO_ERROR - everything was ok.
|
|
// Win32 Error code in case if failure.
|
|
//
|
|
// Author:
|
|
// Mooly Beery (MoolyB) 17-Jan-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
DWORD HandleNonPnpDevices()
|
|
{
|
|
DWORD ec = NO_ERROR;
|
|
DBG_ENTER(_T("HandleNonPnpDevices"), ec);
|
|
|
|
// if this is a PnP installation don't do anything here
|
|
if (bIsPnpInstallation)
|
|
{
|
|
VERBOSE(DBG_MSG,_T("This is a PnP device installation, exiting"));
|
|
goto exit;
|
|
}
|
|
|
|
// if Fax is installed or the user has checked the 'Don't show me this again' do not propose
|
|
if (!AllowInstallationProposal())
|
|
{
|
|
VERBOSE(DBG_MSG,TEXT("Not allowed to install, exit"));
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Let's ask the user if he wishes to install a fax now
|
|
//
|
|
INT_PTR iResult = DialogBox (faxocm_GetAppInstance(),
|
|
MAKEINTRESOURCE(IDD_INSTALL_FAX),
|
|
NULL,
|
|
prv_dlgInstallFaxQuestion);
|
|
if (iResult==-1)
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (RESOURCE_ERR, TEXT("DialogBox(IDD_INSTALL_FAX)"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
if (iResult==IDYES)
|
|
{
|
|
//
|
|
// User wishes to install the fax now - do so.
|
|
//
|
|
ec = InstallFaxUnattended();
|
|
if (ec!=ERROR_SUCCESS)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("InstallFaxUnattended"), ec);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return ec;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// GetModemDriverInfo
|
|
//
|
|
// Purpose:
|
|
// Gets the modem's selected driver and retrieves the modem's INF
|
|
// filename and section within the INF file
|
|
//
|
|
// Params:
|
|
// IN HDEVINFO hDeviceInfoSet - passed from CoDevice Installer
|
|
// IN PSP_DEVINFO_DATA pDeviceInfoData - passed from CoDevice Installer
|
|
// OUT PSP_DRVINFO_DETAIL_DATA pspDrvInfoDetailData - passes out the driver details
|
|
//
|
|
// Return Value:
|
|
// NO_ERROR - everything was ok.
|
|
// Win32 Error code in case if failure.
|
|
//
|
|
// Caller must call MemFree on returned pointer.
|
|
//
|
|
// Author:
|
|
// Mooly Beery (MoolyB) 28-Mar-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
static DWORD GetModemDriverInfo
|
|
(
|
|
IN HDEVINFO hDeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA pDeviceInfoData,
|
|
OUT PSP_DRVINFO_DETAIL_DATA pspDrvInfoDetailData
|
|
)
|
|
{
|
|
DWORD ec = NO_ERROR;
|
|
DWORD dwRequiredSize = 0;
|
|
SP_DRVINFO_DATA spDrvInfoData;
|
|
|
|
DBG_ENTER(_T("GetModemDriverInfo"), ec);
|
|
|
|
pspDrvInfoDetailData = NULL;
|
|
spDrvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
|
|
|
if (SetupDiGetSelectedDriver(hDeviceInfoSet,pDeviceInfoData,&spDrvInfoData))
|
|
{
|
|
if (!SetupDiGetDriverInfoDetail(hDeviceInfoSet,pDeviceInfoData,&spDrvInfoData,NULL,0,&dwRequiredSize))
|
|
{
|
|
ec = GetLastError();
|
|
if (ec==ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
ec = NO_ERROR;
|
|
if (pspDrvInfoDetailData = (PSP_DRVINFO_DETAIL_DATA)MemAlloc(dwRequiredSize))
|
|
{
|
|
pspDrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
|
|
if (SetupDiGetDriverInfoDetail(hDeviceInfoSet,pDeviceInfoData,&spDrvInfoData,pspDrvInfoDetailData,dwRequiredSize,NULL))
|
|
{
|
|
VERBOSE(DBG_MSG,_T("Driver Inf Name is: %s"),pspDrvInfoDetailData->InfFileName);
|
|
VERBOSE(DBG_MSG,_T("Driver Section Name is: %s"),pspDrvInfoDetailData->SectionName);
|
|
VERBOSE(DBG_MSG,_T("Driver Description is: %s"),pspDrvInfoDetailData->DrvDescription);
|
|
VERBOSE(DBG_MSG,_T("Driver Hardware ID is: %s"),pspDrvInfoDetailData->HardwareID);
|
|
}
|
|
else
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("SetupDiGetDriverInfoDetail"), ec);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ec = ERROR_NOT_ENOUGH_MEMORY;
|
|
VERBOSE(GENERAL_ERR, TEXT("MemAlloc failed"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("SetupDiGetDriverInfoDetail"), ec);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ec = ERROR_INVALID_PARAMETER;
|
|
VERBOSE(GENERAL_ERR, TEXT("SetupDiGetDriverInfoDetail should have failed"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("SetupDiGetSelectedDriver"), ec);
|
|
}
|
|
|
|
return ec;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// SearchModemInfFaxSection
|
|
//
|
|
// Purpose:
|
|
// Search the modem's INF to find if a Fax section exists.
|
|
// If a Fax section exists, try to find the InstallFax key
|
|
// If it's there, install Fax unattended.
|
|
//
|
|
// Params:
|
|
// IN HDEVINFO hDeviceInfoSet - passed from CoDevice Installer
|
|
// IN PSP_DEVINFO_DATA pDeviceInfoData - passed from CoDevice Installer
|
|
//
|
|
// Return Value:
|
|
// NO_ERROR - everything was ok.
|
|
// Win32 Error code in case if failure.
|
|
//
|
|
// Author:
|
|
// Mooly Beery (MoolyB) 28-Mar-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
DWORD SearchModemInfFaxSection
|
|
(
|
|
IN HDEVINFO hDeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA pDeviceInfoData
|
|
)
|
|
{
|
|
DWORD ec = NO_ERROR;
|
|
DWORD Size = sizeof(DWORD);
|
|
DWORD Type = 0;
|
|
DWORD Value = 0;
|
|
HKEY hDeviceKey = NULL;
|
|
HKEY hFaxKey = NULL;
|
|
LPTSTR lptstrInstallFax = NULL;
|
|
|
|
DBG_ENTER(_T("SearchModemInfFaxSection"), ec);
|
|
|
|
// get the device key under HKLM\SYSTEM\CurrentControlSet\Control\Class\ClassGUID\InstanceID
|
|
hDeviceKey = SetupDiOpenDevRegKey(hDeviceInfoSet,pDeviceInfoData,DICS_FLAG_GLOBAL,0,DIREG_DRV,KEY_READ);
|
|
if (hDeviceKey==NULL)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("SetupDiOpenDevRegKey"), ec);
|
|
goto exit;
|
|
}
|
|
// check if the Fax subkey exists.
|
|
hFaxKey = OpenRegistryKey(hDeviceKey,_T("Fax"),FALSE,KEY_READ);
|
|
if (hFaxKey==NULL)
|
|
{
|
|
VERBOSE(DBG_MSG, TEXT("This modem does not have a Fax section, exit..."));
|
|
ec = NO_ERROR;
|
|
goto exit;
|
|
}
|
|
// this modem has a Fax section.
|
|
// let's check if it uses the 'InstallFax' REG_SZ
|
|
lptstrInstallFax = GetRegistryString(hFaxKey,_T("InstallFax"),NULL);
|
|
if (lptstrInstallFax==NULL)
|
|
{
|
|
VERBOSE(DBG_MSG, TEXT("This modem does not have an InstallFax REG_SZ in the Fax section, exit..."));
|
|
ec = NO_ERROR;
|
|
goto exit;
|
|
}
|
|
// check if the InstallFax is 0 (unlikely, but...)
|
|
if (_tcsicmp(lptstrInstallFax,_T("0"))==0)
|
|
{
|
|
VERBOSE(DBG_MSG, TEXT("This modem does has an InstallFax=0 REG_SZ in the Fax section, exit..."));
|
|
ec = NO_ERROR;
|
|
goto exit;
|
|
}
|
|
//if (InSystemSetup(hDeviceInfoSet,pDeviceInfoData))
|
|
{
|
|
// if we're in system setup, we should just notify our component that it should install.
|
|
}
|
|
//else
|
|
{
|
|
// finally, Install Fax.
|
|
ec = InstallFaxUnattended();
|
|
if (ec!=ERROR_SUCCESS)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("InstallFaxUnattended"), ec);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if (hDeviceKey)
|
|
{
|
|
RegCloseKey(hDeviceKey);
|
|
}
|
|
if (hFaxKey)
|
|
{
|
|
RegCloseKey(hFaxKey);
|
|
}
|
|
return ec;
|
|
}
|
|
|
|
*/
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// HandleInstallDevice
|
|
//
|
|
// Purpose:
|
|
// Handles DIF_INSTALLDEVICE
|
|
// A new device has finished installing and we're allowed to install a printer
|
|
// if Fax is already on the box
|
|
// In this case we do the following:
|
|
//
|
|
// 1. Check if Fax is installed, it it's not then attemp to install Fax based on INF
|
|
// 2. Check if there's a Fax printer, if there is leave
|
|
// 3. Install a Fax printer
|
|
// 4. Ensure the service is up
|
|
// 5. Leave
|
|
//
|
|
// Params:
|
|
// IN HDEVINFO hDeviceInfoSet - passed from CoDevice Installer
|
|
// IN PSP_DEVINFO_DATA pDeviceInfoData - passed from CoDevice Installer
|
|
//
|
|
// Return Value:
|
|
// NO_ERROR - everything was ok.
|
|
// Win32 Error code in case if failure.
|
|
//
|
|
// Author:
|
|
// Eran Yariv (EranY) 17-Jul-2000
|
|
// Mooly Beery (MoolyB) 08-Jan-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
DWORD HandleInstallDevice
|
|
(
|
|
IN HDEVINFO hDeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA pDeviceInfoData
|
|
)
|
|
{
|
|
DWORD ec = NO_ERROR;
|
|
BOOL bFaxInstalled;
|
|
BOOL bLocalFaxPrinterInstalled;
|
|
|
|
DBG_ENTER(_T("HandleInstallDevice"), ec);
|
|
|
|
// Now we know a new modem installation succeeded.
|
|
// Let's check if our component is installed.
|
|
//
|
|
|
|
ec = IsFaxInstalled(&bFaxInstalled);
|
|
if (ec!=ERROR_SUCCESS)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("IsFaxInstalled"), ec);
|
|
goto exit;
|
|
}
|
|
if (!bFaxInstalled)
|
|
{
|
|
VERBOSE(DBG_MSG,TEXT("Fax is not installed, search modem's INF for Fax section..."));
|
|
/*
|
|
ec = SearchModemInfFaxSection(hDeviceInfoSet,pDeviceInfoData);
|
|
if (ec!=ERROR_SUCCESS)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("SearchModemInfFaxSection"), ec);
|
|
}*/
|
|
goto exit;
|
|
}
|
|
//
|
|
// Let's see if we have a local fax printer
|
|
//
|
|
ec = IsLocalFaxPrinterInstalled (&bLocalFaxPrinterInstalled);
|
|
if (ec!=ERROR_SUCCESS)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("IsLocalFaxPrinterInstalled"), ec);
|
|
goto exit;
|
|
}
|
|
if (bLocalFaxPrinterInstalled)
|
|
{
|
|
VERBOSE(DBG_MSG,TEXT("Fax Printer is installed, exit"));
|
|
goto exit;
|
|
}
|
|
//
|
|
// This is the time to install a local fax printer.
|
|
//
|
|
ec = AddLocalFaxPrinter (FAX_PRINTER_NAME, NULL);
|
|
if (ERROR_SUCCESS != ec)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("AddLocalFaxPrinter"), ec);
|
|
goto exit;
|
|
}
|
|
//
|
|
// Make sure the service is running.
|
|
// This is important because there may have been jobs in the queue that now, when we have
|
|
// a new modem device, can finally be executed.
|
|
//
|
|
if (!EnsureFaxServiceIsStarted (NULL))
|
|
{
|
|
ec = GetLastError ();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("EnsureFaxServiceIsStarted"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
return ec;
|
|
}
|
|
|
|
/*
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// HandleNewDeviceWizardFinishInstall
|
|
//
|
|
// Purpose:
|
|
// Handles DIF_NEWDEVICEWIZARD_FINISHINSTALL
|
|
// A new device has finished installing and we're allowed to add a property page
|
|
// asking the user to install Fax
|
|
// In this case we do the following:
|
|
//
|
|
// 1. Check if Fax is installed, if it is leave
|
|
// 2. Check if we're allowed to add a property page, if not leave
|
|
// 3. Add a property page to the wizard.
|
|
// 4. Leave
|
|
//
|
|
// Params:
|
|
// See CoClassInstaller documentation in DDK
|
|
//
|
|
// Return Value:
|
|
// NO_ERROR - everything was ok.
|
|
// Win32 Error code in case if failure.
|
|
//
|
|
// Author:
|
|
// Eran Yariv (EranY) 17-Jul-2000
|
|
// Mooly Beery (MoolyB) 08-Jan-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
DWORD HandleNewDeviceWizardFinishInstall
|
|
(
|
|
IN HDEVINFO hDeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA pDeviceInfoData OPTIONAL
|
|
)
|
|
{
|
|
DWORD ec = NO_ERROR;
|
|
BOOL bFaxInstalled = FALSE;
|
|
TCHAR* WizardTitle = NULL;
|
|
TCHAR* WizardSubTitle = NULL;
|
|
SP_NEWDEVICEWIZARD_DATA nddClassInstallParams = {0};
|
|
DWORD dwClassInstallParamsSize = sizeof(SP_NEWDEVICEWIZARD_DATA);
|
|
HPROPSHEETPAGE hPsp = NULL;
|
|
PROPSHEETPAGE psp = {0};
|
|
|
|
DBG_ENTER(_T("HandleNewDeviceWizardFinishInstall"), ec);
|
|
|
|
if (!AllowInstallationProposal())
|
|
{
|
|
VERBOSE(DBG_MSG,TEXT("Not allowed to install, exit"));
|
|
goto exit;
|
|
}
|
|
|
|
nddClassInstallParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
|
|
|
|
// get the class install parameters by calling SetupDiGetClassInstallParams
|
|
if (!SetupDiGetClassInstallParams( hDeviceInfoSet,
|
|
pDeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&nddClassInstallParams,
|
|
dwClassInstallParamsSize,
|
|
NULL))
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("SetupDiGetClassInstallParams"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
// check whether NumDynamicPages has reached the max
|
|
if (nddClassInstallParams.NumDynamicPages>=MAX_INSTALLWIZARD_DYNAPAGES)
|
|
{
|
|
VERBOSE (GENERAL_ERR, TEXT("Too many property pages, can't add another one"));
|
|
ec = ERROR_BUFFER_OVERFLOW;
|
|
goto exit;
|
|
}
|
|
// fill in the PROPSHEETPAGE structure
|
|
psp.dwSize = sizeof(PROPSHEETPAGE);
|
|
psp.dwFlags = PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
|
|
|
|
psp.hInstance = faxocm_GetAppInstance();
|
|
psp.pszTemplate = MAKEINTRESOURCE(IDD_INSTALL_FAX_PROP);
|
|
psp.pfnDlgProc = prv_dlgInstallFaxQuestionPropPage;
|
|
|
|
WizardTitle = (TCHAR*)MemAlloc(MAX_PATH * sizeof(TCHAR) );
|
|
if(WizardTitle)
|
|
{
|
|
if (!LoadString(psp.hInstance, IDS_NEW_DEVICE_TITLE, WizardTitle, MAX_PATH))
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("LoadString"), ec);
|
|
WizardTitle[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
psp.pszHeaderTitle = WizardTitle;
|
|
}
|
|
}
|
|
|
|
WizardSubTitle = (TCHAR*)MemAlloc(MAX_PATH * sizeof(TCHAR) );
|
|
if(WizardSubTitle)
|
|
{
|
|
if (!LoadString(psp.hInstance, IDS_NEW_DEVICE_SUBTITLE, WizardSubTitle, MAX_PATH))
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("LoadString"), ec);
|
|
WizardSubTitle[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
psp.pszHeaderSubTitle = WizardSubTitle;
|
|
}
|
|
}
|
|
// add the page and increment the NumDynamicPages counter
|
|
hPsp = CreatePropertySheetPage(&psp);
|
|
if (hPsp==NULL)
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("CreatePropertySheetPage"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
nddClassInstallParams.DynamicPages[nddClassInstallParams.NumDynamicPages++] = hPsp;
|
|
|
|
// apply the modified params by calling SetupDiSetClassInstallParams
|
|
if (!SetupDiSetClassInstallParams( hDeviceInfoSet,
|
|
pDeviceInfoData,
|
|
(PSP_CLASSINSTALL_HEADER)&nddClassInstallParams,
|
|
dwClassInstallParamsSize))
|
|
{
|
|
ec = GetLastError();
|
|
CALL_FAIL (GENERAL_ERR, TEXT("LoadString"), ec);
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
return ec;
|
|
}
|
|
*/
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
// Function:
|
|
// FaxModemCoClassInstaller
|
|
//
|
|
// Purpose:
|
|
// Our Fax CoClassInstaller, handles newly discovered modems
|
|
//
|
|
// Params:
|
|
// See CoClassInstaller documentation in DDK
|
|
//
|
|
// Return Value:
|
|
// NO_ERROR - everything was ok.
|
|
// Win32 Error code in case if failure.
|
|
//
|
|
// Author:
|
|
// Eran Yariv (EranY) 17-Jul-2000
|
|
// Mooly Beery (MoolyB) 08-Jan-2001
|
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
DWORD CALLBACK FaxModemCoClassInstaller
|
|
(
|
|
IN DI_FUNCTION InstallFunction,
|
|
IN HDEVINFO hDeviceInfoSet,
|
|
IN PSP_DEVINFO_DATA pDeviceInfoData OPTIONAL,
|
|
IN OUT PCOINSTALLER_CONTEXT_DATA Context
|
|
)
|
|
{
|
|
DWORD ec = NO_ERROR;
|
|
|
|
DBG_ENTER(_T("FaxModemCoClassInstaller"), ec, TEXT("Processing %s request"), DifDebug[InstallFunction].DifString);
|
|
|
|
// We handle two events:
|
|
//
|
|
// DIF_INSTALLDEVICE
|
|
// A new device has finished installing and we're allowed to install a printer
|
|
// if Fax is already on the box
|
|
// In this case we do the following:
|
|
//
|
|
// 1. Check if Fax is installed, if it's not leave
|
|
// 2. Check if there's a Fax printer, if there is leave
|
|
// 3. Install a Fax printer
|
|
// 4. Ensure the service is up
|
|
// 5. Leave
|
|
//
|
|
// DIF_NEWDEVICEWIZARD_FINISHINSTALL
|
|
// A new device has finished installing and we're allowed to add a property page
|
|
// asking the user to install Fax
|
|
// In this case we do the following:
|
|
//
|
|
// 1. Check if Fax is installed, if it is leave
|
|
// 2. Check if we're allowed to add a property page, if not leave
|
|
// 3. Add a property page to the wizard.
|
|
// 4. Leave
|
|
switch (InstallFunction)
|
|
{
|
|
case DIF_INSTALLWIZARD:
|
|
VERBOSE (DBG_MSG, L"Marking installation as potential non PnP");
|
|
bIsPnpInstallation = false;
|
|
break;
|
|
|
|
case DIF_INSTALLDEVICE:
|
|
if (!Context->PostProcessing)
|
|
{
|
|
//
|
|
// The modem device is not installed yet
|
|
//
|
|
VERBOSE (DBG_MSG, L"Pre-installation, waiting for post-installation call");
|
|
ec = ERROR_DI_POSTPROCESSING_REQUIRED;
|
|
return ec;
|
|
}
|
|
if (Context->InstallResult!=NO_ERROR)
|
|
{
|
|
//
|
|
// The modem device had some problems during installation
|
|
//
|
|
VERBOSE (DBG_MSG, L"Previous error causing installation failure, 0x%08x", Context->InstallResult);
|
|
ec = Context->InstallResult;
|
|
return ec;
|
|
}
|
|
if (HandleInstallDevice(hDeviceInfoSet,pDeviceInfoData)!=NO_ERROR)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("HandleInstallDevice"), GetLastError());
|
|
// do not fail the CoClassInstaller
|
|
}
|
|
/* No UI until futher notice
|
|
if (HandleNonPnpDevices()!=NO_ERROR)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("HandleNonPnpDevices"), GetLastError());
|
|
// do not fail the CoClassInstaller
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case DIF_NEWDEVICEWIZARD_FINISHINSTALL:
|
|
/* No UI until futher notice
|
|
Assert(bIsPnpInstallation);
|
|
if (HandleNewDeviceWizardFinishInstall(hDeviceInfoSet,pDeviceInfoData)!=NO_ERROR)
|
|
{
|
|
CALL_FAIL (GENERAL_ERR, TEXT("HandleNewDeviceWizardFinishInstall"), GetLastError());
|
|
// do not fail the CoClassInstaller
|
|
}
|
|
*/
|
|
break;
|
|
|
|
default:
|
|
VERBOSE(DBG_MSG,TEXT("We do not handle %s"),DifDebug[InstallFunction].DifString);
|
|
break;
|
|
}
|
|
|
|
return ec;
|
|
}
|