////////////////////////////////////////////////////////////////////////////// // // 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 #include #include // 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; }