From 57d946bf33f300f8a3a1ae795a0b9f2a07dacb3e Mon Sep 17 00:00:00 2001 From: S T Chan Date: Mon, 23 Dec 2013 18:35:10 -0500 Subject: [PATCH] more refactoring --- PdfScribeCore/NativeMethods.cs | 21 +++ PdfScribeCore/PdfScribeCore.csproj | 1 + PdfScribeCore/PdfScribeInstaller.cs | 202 ++++++++++++++++++++++------ PdfScribeUnitTests/UnitTests.cs | 15 ++- 4 files changed, 197 insertions(+), 42 deletions(-) diff --git a/PdfScribeCore/NativeMethods.cs b/PdfScribeCore/NativeMethods.cs index 747b523..dde278b 100644 --- a/PdfScribeCore/NativeMethods.cs +++ b/PdfScribeCore/NativeMethods.cs @@ -28,6 +28,23 @@ namespace PdfScribeCore public UInt32 dwHighDateTime; } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct DRIVER_INFO_2 + { + public uint cVersion; + [MarshalAs(UnmanagedType.LPTStr)] + public string pName; + [MarshalAs(UnmanagedType.LPTStr)] + public string pEnvironment; + [MarshalAs(UnmanagedType.LPTStr)] + public string pDriverPath; + [MarshalAs(UnmanagedType.LPTStr)] + public string pDataFile; + [MarshalAs(UnmanagedType.LPTStr)] + public string pConfigFile; + } + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct DRIVER_INFO_6 { @@ -147,6 +164,10 @@ namespace PdfScribeCore int Level, ref DRIVER_INFO_6 pDriverInfo); + [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] + internal static extern bool EnumPrinterDrivers(String pName, String pEnvironment, uint level, IntPtr pDriverInfo, uint cdBuf, ref uint pcbNeeded, ref uint pcReturned); + + [DllImport("winspool.drv")] internal static extern bool GetPrinterDriverDirectory(StringBuilder pName, StringBuilder pEnv, diff --git a/PdfScribeCore/PdfScribeCore.csproj b/PdfScribeCore/PdfScribeCore.csproj index 1252ffa..3f10d62 100644 --- a/PdfScribeCore/PdfScribeCore.csproj +++ b/PdfScribeCore/PdfScribeCore.csproj @@ -82,6 +82,7 @@ + diff --git a/PdfScribeCore/PdfScribeInstaller.cs b/PdfScribeCore/PdfScribeInstaller.cs index 4147afc..acb8d19 100644 --- a/PdfScribeCore/PdfScribeInstaller.cs +++ b/PdfScribeCore/PdfScribeInstaller.cs @@ -30,6 +30,7 @@ namespace PdfScribeCore const uint DPD_DELETE_SPECIFIC_VERSION = 0x00000002; const uint DPD_DELETE_ALL_FILES = 0x00000004; + const int WIN32_FILE_ALREADY_EXISTS = 183; // Returned by XcvData "AddPort" if the port already exists #endregion //private static readonly TraceSource logEventSource = new TraceSource("PdfScribeCore"); @@ -78,6 +79,10 @@ namespace PdfScribeCore const string NATIVE_COULDNOTREVERT64REDIRECTION = "Could not revert 64-bit file system redirection."; const string INSTALL_ROLLBACK_FAILURE_AT_FUNCTION = "Partial uninstallation failure. Function {0} returned false."; + + const string REGISTRYCONFIG_NOT_ADDED = "Could not add port configuration to registry. Exception message: {0}"; + const string REGISTRYCONFIG_NOT_DELETED = "Could not delete port configuration from registry. Exception message: {0}"; + #endregion @@ -123,6 +128,7 @@ namespace PdfScribeCore switch (portAddResult) { case 0: + case WIN32_FILE_ALREADY_EXISTS: // Port already exists - this is OK, we'll just keep using it portAdded = true; break; } @@ -412,6 +418,7 @@ namespace PdfScribeCore return monitorExists; } + public List EnumerateMonitors() { List portMonitors = new List(); @@ -436,14 +443,14 @@ namespace PdfScribeCore } else { - // Failed to retrieve enumerate - throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not enumerate monitor ports."); + // Failed to retrieve enumerated monitors + throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not enumerate port monitors."); } } else { - throw new ApplicationException("Call to EnumMonitors in winspool.drv succeeded with a zero size buffer - unexpected error."); + throw new Win32Exception(Marshal.GetLastWin32Error(), "Call to EnumMonitors in winspool.drv succeeded with a zero size buffer - unexpected error."); } return portMonitors; @@ -477,19 +484,19 @@ namespace PdfScribeCore /// Directory where the uninstalled printer driver files are located /// An array containing the printer driver's filenames /// An array containing dependent filenames - /// true if printer installed, false if failed + /// true if installation suceeds, false if failed public bool InstallPdfScribePrinter(String driverSourceDirectory) { bool printerInstalled = false; - Stack undoInstallActions = new Stack(); String driverDirectory = RetrievePrinterDriverDirectory(); - undoInstallActions.Push(this.RemovePdfScribePortMonitor); + undoInstallActions.Push(this.DeletePdfScribePortMonitorDll); if (AddPdfScribePortMonitor(driverSourceDirectory)) { + undoInstallActions.Push(this.RemovePdfScribePortMonitor); if (CopyPrinterDriverFiles(driverSourceDirectory, printerDriverFiles.Concat(printerDriverDependentFiles).ToArray())) { undoInstallActions.Push(this.RemovePdfScribePortMonitor); @@ -580,6 +587,7 @@ namespace PdfScribeCore printerUninstalled = false; if (!RemovePdfScribePortConfig()) printerUninstalled = false; + DeletePdfScribePortMonitorDll(); return printerUninstalled; } @@ -667,46 +675,111 @@ namespace PdfScribeCore } - private bool InstallPdfScribePrinterDriver() +#if DEBUG + public bool IsPrinterDriverInstalled_Test(String driverName) { - - String driverSourceDirectory = RetrievePrinterDriverDirectory(); - - StringBuilder nullTerminatedDependentFiles = new StringBuilder(); - if (printerDriverDependentFiles.Length > 0) + return IsPrinterDriverInstalled(driverName); + } +#endif + private bool IsPrinterDriverInstalled(String driverName) + { + bool driverInstalled = false; + List installedDrivers = EnumeratePrinterDrivers(); + foreach (DRIVER_INFO_6 printerDriver in installedDrivers) { - for (int loop = 0; loop <= printerDriverDependentFiles.GetUpperBound(0); loop++) + if (printerDriver.pName == driverName) { - nullTerminatedDependentFiles.Append(printerDriverDependentFiles[loop]); - nullTerminatedDependentFiles.Append("\0"); + driverInstalled = true; + break; + } + } + return driverInstalled; + } + + public List EnumeratePrinterDrivers() + { + List installedPrinterDrivers = new List(); + + uint pcbNeeded = 0; + uint pcReturned = 0; + + if (!NativeMethods.EnumPrinterDrivers(null, ENVIRONMENT_64, 6, IntPtr.Zero, 0, ref pcbNeeded, ref pcReturned)) + { + IntPtr pDrivers = Marshal.AllocHGlobal((int)pcbNeeded); + if (NativeMethods.EnumPrinterDrivers(null, ENVIRONMENT_64, 6, pDrivers, pcbNeeded, ref pcbNeeded, ref pcReturned)) + { + IntPtr currentDriver = pDrivers; + for (int loop = 0; loop < pcReturned; loop++) + { + installedPrinterDrivers.Add((DRIVER_INFO_6)Marshal.PtrToStructure(currentDriver, typeof(DRIVER_INFO_6))); + currentDriver = (IntPtr)(currentDriver.ToInt32() + Marshal.SizeOf(typeof(DRIVER_INFO_6))); + } + Marshal.FreeHGlobal(pDrivers); + } + else + { + // Failed to enumerate printer drivers + throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not enumerate printer drivers."); } - nullTerminatedDependentFiles.Append("\0"); } else { - nullTerminatedDependentFiles.Append("\0\0"); + throw new Win32Exception(Marshal.GetLastWin32Error(), "Call to EnumPrinterDrivers in winspool.drv succeeded with a zero size buffer - unexpected error."); } - DRIVER_INFO_6 printerDriverInfo = new DRIVER_INFO_6(); + return installedPrinterDrivers; + } - printerDriverInfo.cVersion = 3; - printerDriverInfo.pName = DRIVERNAME; - printerDriverInfo.pEnvironment = ENVIRONMENT_64; - printerDriverInfo.pDriverPath = Path.Combine(driverSourceDirectory, DRIVERFILE); - printerDriverInfo.pConfigFile = Path.Combine(driverSourceDirectory, DRIVERUIFILE); - printerDriverInfo.pHelpFile = Path.Combine(driverSourceDirectory, DRIVERHELPFILE); - printerDriverInfo.pDataFile = Path.Combine(driverSourceDirectory, DRIVERDATAFILE); - printerDriverInfo.pDependentFiles = nullTerminatedDependentFiles.ToString(); + private bool InstallPdfScribePrinterDriver() + { + bool pdfScribePrinterDriverInstalled = false; - printerDriverInfo.pMonitorName = PORTMONITOR; - printerDriverInfo.pDefaultDataType = String.Empty; - printerDriverInfo.dwlDriverVersion = 0x0000000200000000U; - printerDriverInfo.pszMfgName = DRIVERMANUFACTURER; - printerDriverInfo.pszHardwareID = HARDWAREID; - printerDriverInfo.pszProvider = DRIVERMANUFACTURER; + if (IsPrinterDriverInstalled(DRIVERNAME)) + { + String driverSourceDirectory = RetrievePrinterDriverDirectory(); + + StringBuilder nullTerminatedDependentFiles = new StringBuilder(); + if (printerDriverDependentFiles.Length > 0) + { + for (int loop = 0; loop <= printerDriverDependentFiles.GetUpperBound(0); loop++) + { + nullTerminatedDependentFiles.Append(printerDriverDependentFiles[loop]); + nullTerminatedDependentFiles.Append("\0"); + } + nullTerminatedDependentFiles.Append("\0"); + } + else + { + nullTerminatedDependentFiles.Append("\0\0"); + } + + DRIVER_INFO_6 printerDriverInfo = new DRIVER_INFO_6(); + + printerDriverInfo.cVersion = 3; + printerDriverInfo.pName = DRIVERNAME; + printerDriverInfo.pEnvironment = ENVIRONMENT_64; + printerDriverInfo.pDriverPath = Path.Combine(driverSourceDirectory, DRIVERFILE); + printerDriverInfo.pConfigFile = Path.Combine(driverSourceDirectory, DRIVERUIFILE); + printerDriverInfo.pHelpFile = Path.Combine(driverSourceDirectory, DRIVERHELPFILE); + printerDriverInfo.pDataFile = Path.Combine(driverSourceDirectory, DRIVERDATAFILE); + printerDriverInfo.pDependentFiles = nullTerminatedDependentFiles.ToString(); + + printerDriverInfo.pMonitorName = PORTMONITOR; + printerDriverInfo.pDefaultDataType = String.Empty; + printerDriverInfo.dwlDriverVersion = 0x0000000200000000U; + printerDriverInfo.pszMfgName = DRIVERMANUFACTURER; + printerDriverInfo.pszHardwareID = HARDWAREID; + printerDriverInfo.pszProvider = DRIVERMANUFACTURER; - return InstallPrinterDriver(ref printerDriverInfo); + pdfScribePrinterDriverInstalled = InstallPrinterDriver(ref printerDriverInfo); + } + else + { + pdfScribePrinterDriverInstalled = true; // Driver is already installed, we'll just use the installed driver + } + + return pdfScribePrinterDriverInstalled; } private bool InstallPrinterDriver(ref DRIVER_INFO_6 printerDriverInfo) @@ -808,9 +881,38 @@ namespace PdfScribeCore } return printerDeleted; } + + + public bool IsPdfScribePrinterInstalled() + { + bool pdfScribeInstalled = false; + + PRINTER_DEFAULTS scribeDefaults = new PRINTER_DEFAULTS(); + scribeDefaults.DesiredAccess = 0x00008; // Use access + scribeDefaults.pDatatype = null; + scribeDefaults.pDevMode = IntPtr.Zero; + + IntPtr scribeHandle = IntPtr.Zero; + if (NativeMethods.OpenPrinter(PRINTERNAME, ref scribeHandle, scribeDefaults) != 0) + { + pdfScribeInstalled = true; + } + else + { + int errorCode = Marshal.GetLastWin32Error(); + if (errorCode == 0x5) pdfScribeInstalled = true; // Printer is installed, but user + // has no privileges to use it + } + + return pdfScribeInstalled; + } + #endregion + + + #region Configuration and Registry changes #if DEBUG @@ -821,6 +923,12 @@ namespace PdfScribeCore #endif private bool ConfigurePdfScribePort() + { + return ConfigurePdfScribePort(String.Empty, String.Empty); + + } + private bool ConfigurePdfScribePort(String commandValue, + String argumentsValue) { bool registryChangesMade = false; // Add all the registry info @@ -832,8 +940,8 @@ namespace PdfScribeCore PORTMONITOR + "\\Ports\\" + PORTNAME); portConfiguration.SetValue("Description", "PDF Scribe", RegistryValueKind.String); - portConfiguration.SetValue("Command", "", RegistryValueKind.String); - portConfiguration.SetValue("Arguments", "", RegistryValueKind.String); + portConfiguration.SetValue("Command", commandValue, RegistryValueKind.String); + portConfiguration.SetValue("Arguments", argumentsValue, RegistryValueKind.String); portConfiguration.SetValue("Printer", PRINTERNAME, RegistryValueKind.String); portConfiguration.SetValue("Output", 0, RegistryValueKind.DWord); portConfiguration.SetValue("ShowWindow", 2, RegistryValueKind.DWord); @@ -846,10 +954,18 @@ namespace PdfScribeCore registryChangesMade = true; } - catch (UnauthorizedAccessException) - { } - catch (SecurityException) - { } + catch (UnauthorizedAccessException unauthorizedEx) + { + logEventSource.TraceEvent(TraceEventType.Error, + (int)TraceEventType.Error, + String.Format(REGISTRYCONFIG_NOT_ADDED, unauthorizedEx.Message)); + } + catch (SecurityException securityEx) + { + logEventSource.TraceEvent(TraceEventType.Error, + (int)TraceEventType.Error, + String.Format(REGISTRYCONFIG_NOT_ADDED, securityEx.Message)); + } return registryChangesMade; } @@ -864,8 +980,12 @@ namespace PdfScribeCore PORTMONITOR + "\\Ports\\" + PORTNAME, false); registryEntriesRemoved = true; } - catch (UnauthorizedAccessException) - { } + catch (UnauthorizedAccessException unauthorizedEx) + { + logEventSource.TraceEvent(TraceEventType.Error, + (int)TraceEventType.Error, + String.Format(REGISTRYCONFIG_NOT_DELETED, unauthorizedEx.Message)); + } return registryEntriesRemoved; diff --git a/PdfScribeUnitTests/UnitTests.cs b/PdfScribeUnitTests/UnitTests.cs index 421e1e7..279edc2 100644 --- a/PdfScribeUnitTests/UnitTests.cs +++ b/PdfScribeUnitTests/UnitTests.cs @@ -33,6 +33,19 @@ namespace PdfScribeUnitTests scribeInstaller.RemovePDFScribePrinterDriver(); } + //[Test] + public void Test_AddPdfScribePort() + { + var scribeInstaller = new PdfScribeInstaller(); + scribeInstaller.AddPdfScribePort_Test(); + } + + [Test] + public void Test_IsPrinterDriverInstalled() + { + var scribeInstaller = new PdfScribeInstaller(); + scribeInstaller.IsPrinterDriverInstalled_Test("PDF Scribe Virtual Printer"); + } //[Test] public void Test_InstallPdfScribePrinter() { @@ -56,7 +69,7 @@ namespace PdfScribeUnitTests #endregion - [Test] + //[Test] public void Test_ShowActivityWindows() { var activityWindowTester = new PdfScribe.ActivityNotificationPresenter();