From eb1bf547c267824b8e8b3bc60aa563815355396d Mon Sep 17 00:00:00 2001 From: David Hall Date: Fri, 13 Dec 2019 14:28:25 -0700 Subject: [PATCH] Added unit tests for newly added functions and applied needed fixes. --- PInvoke/Printing/WinSpool.DrvFuncs.cs | 47 ++++++-- PInvoke/Printing/WinSpool.Funcs.cs | 12 +-- UnitTests/PInvoke/Printing/Printing.csproj | 4 + UnitTests/PInvoke/Printing/PrintingTests.cs | 162 ++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+), 13 deletions(-) diff --git a/PInvoke/Printing/WinSpool.DrvFuncs.cs b/PInvoke/Printing/WinSpool.DrvFuncs.cs index d8c9a7e4..ac858e6c 100644 --- a/PInvoke/Printing/WinSpool.DrvFuncs.cs +++ b/PInvoke/Printing/WinSpool.DrvFuncs.cs @@ -1,6 +1,9 @@ -using System; +using Microsoft.Win32; +using System; +using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Security.AccessControl; using System.Text; using Vanara.InteropServices; using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; @@ -667,7 +670,7 @@ namespace Vanara.PInvoke [PInvokeData("winspool.h", MSDNShortId = "f34549c3-0474-48ba-9307-5b36f02dbe1c")] public static bool AddPrintProvidor([Optional] string pName, in T pProviderInfo) where T : struct { - if (!TryGetLevel("DRIVER_INFO_", out var lvl)) + if (!TryGetLevel("PROVIDOR_INFO_", out var lvl)) throw new ArgumentException($"{nameof(AddPrintProvidor)} cannot process a structure of type {typeof(T).Name}."); using var mem = SafeCoTaskMemHandle.CreateFromStructure(pProviderInfo); return AddPrintProvidor(pName, lvl, mem); @@ -857,7 +860,7 @@ namespace Vanara.PInvoke [DllImport(Lib.Winspool, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("winspool.h", MSDNShortId = "1a3d7c7f-1d45-4877-a8f7-a77f40e3c319")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeletePrinterDriverEx([Optional] string pName, [Optional] string pEnvironment, string pDriverName, DPD dwDeleteFlag, uint dwVersionFlag); + public static extern bool DeletePrinterDriverEx([Optional] string pName, [Optional] string pEnvironment, string pDriverName, DPD dwDeleteFlag, uint dwVersionFlag = 0); /// Deletes a printer driver package from the driver store. /// @@ -932,6 +935,36 @@ namespace Vanara.PInvoke [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DeletePrintProvidor([Optional] string pName, [Optional] string pEnvironment, string pPrintProviderName); + /// Retrieves GUID, version, and date of all core printer drivers and the path to their packages. + /// + /// A pointer to a constant, null-terminated string that specifies the name of the print server. Use NULL for the local computer. + /// + /// + /// A pointer to a constant, null-terminated string that specifies the processor architecture (for example, Windows NT x86). This + /// can be NULL. + /// + /// A sequence of CORE_PRINTER_DRIVER structures. + /// + /// This is a blocking or synchronous function and might not return immediately. How quickly this function returns depends on + /// run-time factors such as network status, print server configuration, and printer driver implementation factors that are + /// difficult to predict when writing an application. Calling this function from a thread that manages interaction with the user + /// interface could make the application appear to be unresponsive. + /// + public static IEnumerable EnumCorePrinterDrivers([Optional] string pszServer, [Optional] string pszEnvironment) + { + const string subKey32 = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\PackageInstallation\Windows NT x86\CorePrinterDrivers"; + const string subKey64 = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\PackageInstallation\Windows x64\CorePrinterDrivers"; + + var is64bit = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432")); + using var baseKey = string.IsNullOrEmpty(pszServer) ? null : RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, pszServer); + using var reg = (baseKey ?? Registry.LocalMachine).OpenSubKey(is64bit ? subKey64 : subKey32, false);// RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.EnumerateSubKeys); + var keys = reg?.GetSubKeyNames(); + if (keys?.Length == 0) return new CORE_PRINTER_DRIVER[0]; + var drvs = new CORE_PRINTER_DRIVER[keys.Length]; + GetCorePrinterDrivers(pszServer, pszEnvironment, keys, (uint)keys.Length, drvs).ThrowIfFailed(); + return drvs; + } + /// The EnumMonitors function retrieves information about the port monitors installed on the specified server. /// /// A pointer to a null-terminated string that specifies the name of the server on which the monitors reside. If this parameter is @@ -1244,7 +1277,7 @@ namespace Vanara.PInvoke /// A sequence of DATATYPES_INFO_1 structures. /// Starting with Windows Vista, the data type information from remote print servers is retrieved from a local cache. [PInvokeData("winspool.h", MSDNShortId = "27b6e074-d303-446b-9e5f-6cfa55c30d26")] - public static IEnumerable EnumPrintProcessorDatatypes([Optional] string pName, string pPrintProcessorName) where T : struct + public static IEnumerable EnumPrintProcessorDatatypes(string pPrintProcessorName, [Optional] string pName) where T : struct { if (!TryGetLevel("DATATYPES_INFO_", out var lvl)) throw new ArgumentException($"{nameof(EnumPrintProcessorDatatypes)} cannot process a structure of type {typeof(T).Name}."); @@ -1645,7 +1678,7 @@ namespace Vanara.PInvoke [DllImport(Lib.Winspool, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("winspool.h", MSDNShortId = "69c9cc87-d7e3-496a-b631-b3ae30cdb3fd")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetPrinterDriverDirectory([Optional] string pName, [Optional] string pEnvironment, uint Level, StringBuilder pDriverDirectory, uint cbBuf, out uint pcbNeeded); + public static extern bool GetPrinterDriverDirectory([Optional] string pName, [Optional] string pEnvironment, uint Level, StringBuilder pDriverDirectory, int cbBuf, out int pcbNeeded); /// Retrieves the path to the specified printer driver package on a print server. /// @@ -1682,7 +1715,7 @@ namespace Vanara.PInvoke // pszDriverPackageCab, _In_ DWORD cchDriverPackageCab, _Out_ LPDWORD pcchRequiredSize ); [DllImport(Lib.Winspool, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("winspool.h", MSDNShortId = "e88e984b-d2c0-43b4-8f70-b05ec202ab14")] - public static extern HRESULT GetPrinterDriverPackagePath([Optional] string pszServer, [Optional] string pszEnvironment, [Optional] string pszLanguage, string pszPackageID, StringBuilder pszDriverPackageCab, uint cchDriverPackageCab, out uint pcchRequiredSize); + public static extern HRESULT GetPrinterDriverPackagePath([Optional] string pszServer, [Optional] string pszEnvironment, [Optional] string pszLanguage, string pszPackageID, StringBuilder pszDriverPackageCab, int cchDriverPackageCab, out int pcchRequiredSize); /// /// The GetPrintProcessorDirectory function retrieves the path to the print processor directory on the specified server. @@ -1717,7 +1750,7 @@ namespace Vanara.PInvoke [DllImport(Lib.Winspool, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("winspool.h", MSDNShortId = "a2443cfd-e5ba-41c6-aaf4-45051a3d0e26")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetPrintProcessorDirectory([Optional] string pName, [Optional] string pEnvironment, uint Level, StringBuilder pPrintProcessorInfo, uint cbBuf, out uint pcbNeeded); + public static extern bool GetPrintProcessorDirectory([Optional] string pName, [Optional] string pEnvironment, uint Level, StringBuilder pPrintProcessorInfo, int cbBuf, out int pcbNeeded); /// Installs a printer driver from a driver package that is in the print server's driver store. /// diff --git a/PInvoke/Printing/WinSpool.Funcs.cs b/PInvoke/Printing/WinSpool.Funcs.cs index 48ac1148..bc594e3d 100644 --- a/PInvoke/Printing/WinSpool.Funcs.cs +++ b/PInvoke/Printing/WinSpool.Funcs.cs @@ -1834,7 +1834,7 @@ namespace Vanara.PInvoke public static IEnumerable<(string valueName, REG_VALUE_TYPE valueType, object value)> EnumPrinterData(HPRINTER hPrinter) { var idx = 0U; - EnumPrinterData(hPrinter, idx, null, 0, out var valueNameSz, out var valueType, default, 0, out var dataSz).ThrowIfFailed(); + EnumPrinterData(hPrinter, idx, null, 0, out var valueNameSz, out _, default, 0, out var dataSz).ThrowIfFailed(); if (valueNameSz == 0) yield break; var name = new StringBuilder(1024); using var mem = new SafeCoTaskMemHandle(dataSz); @@ -1842,7 +1842,7 @@ namespace Vanara.PInvoke { name.EnsureCapacity((int)valueNameSz); if (mem.Size < dataSz) mem.Size = dataSz; - var ret = EnumPrinterData(hPrinter, idx, name, (uint)name.Capacity, out valueNameSz, out valueType, mem, mem.Size, out dataSz); + var ret = EnumPrinterData(hPrinter, idx, name, (uint)name.Capacity, out valueNameSz, out var valueType, mem, mem.Size, out dataSz); if (ret == Win32Error.ERROR_NO_MORE_ITEMS) break; if (ret == Win32Error.ERROR_MORE_DATA) continue; ret.ThrowIfFailed(); @@ -3997,9 +3997,9 @@ namespace Vanara.PInvoke [PInvokeData("winspool.h", MSDNShortId = "b5a44b27-a4aa-4e58-9a64-05be87d12ab5")] public static object GetPrinterData(HPRINTER hPrinter, string pValueName) { - GetPrinterData(hPrinter, pValueName, out var type, default, 0, out var sz).ThrowUnless(Win32Error.ERROR_MORE_DATA); + GetPrinterData(hPrinter, pValueName, out _, default, 0, out var sz).ThrowUnless(Win32Error.ERROR_MORE_DATA); using var mem = new SafeCoTaskMemHandle(sz); - GetPrinterData(hPrinter, pValueName, out type, mem, mem.Size, out sz).ThrowIfFailed(); + GetPrinterData(hPrinter, pValueName, out var type, mem, mem.Size, out sz).ThrowIfFailed(); return type.GetValue(mem, mem.Size); } @@ -4487,9 +4487,9 @@ namespace Vanara.PInvoke [PInvokeData("winspool.h", MSDNShortId = "5d9183a7-97cc-46de-848e-e37ce51396eb")] public static object GetPrinterDataEx(HPRINTER hPrinter, string pKeyName, string pValueName) { - GetPrinterDataEx(hPrinter, pKeyName, pValueName, out var type, default, 0, out var sz).ThrowUnless(Win32Error.ERROR_MORE_DATA); + GetPrinterDataEx(hPrinter, pKeyName, pValueName, out _, default, 0, out var sz).ThrowUnless(Win32Error.ERROR_MORE_DATA); using var mem = new SafeCoTaskMemHandle(sz); - GetPrinterDataEx(hPrinter, pKeyName, pValueName, out type, mem, mem.Size, out sz).ThrowIfFailed(); + GetPrinterDataEx(hPrinter, pKeyName, pValueName, out var type, mem, mem.Size, out sz).ThrowIfFailed(); return type.GetValue(mem, mem.Size); } diff --git a/UnitTests/PInvoke/Printing/Printing.csproj b/UnitTests/PInvoke/Printing/Printing.csproj index 79e290fc..afa82e5a 100644 --- a/UnitTests/PInvoke/Printing/Printing.csproj +++ b/UnitTests/PInvoke/Printing/Printing.csproj @@ -50,6 +50,10 @@ {d3e1f2b8-d475-4922-b334-919795b858cb} Vanara.PInvoke.Printing + + {392a14b0-1e10-4e88-9c13-0d965665ffb5} + Vanara.PInvoke.Security + {a5e519e9-feba-4fe3-93a5-b8269bef72f4} Vanara.PInvoke.Shared diff --git a/UnitTests/PInvoke/Printing/PrintingTests.cs b/UnitTests/PInvoke/Printing/PrintingTests.cs index 4603b916..f6a8785f 100644 --- a/UnitTests/PInvoke/Printing/PrintingTests.cs +++ b/UnitTests/PInvoke/Printing/PrintingTests.cs @@ -27,6 +27,23 @@ namespace Vanara.PInvoke.Tests [OneTimeTearDown] public void _TearDown() => hprnt?.Dispose(); + [Test] + public void AddMonitorTest() + { + const string name = "mytestmon"; + var mon = EnumMonitors().First(); + mon.pName = name; + Assert.That(AddMonitor(null, mon), ResultIs.Successful); + Assert.That(DeleteMonitor(null, mon.pEnvironment, mon.pName), ResultIs.Successful); + } + + [Test] + public void AddPortTest() + { + var mon = EnumMonitors().First().pName; + Assert.That(AddPort(null, HWND.NULL, mon), ResultIs.Successful); + } + [Test] public void AddPrinterConnection2Test() { @@ -42,6 +59,17 @@ namespace Vanara.PInvoke.Tests Assert.That(DeletePrinterConnection(connPtrName), ResultIs.Successful); } + [Test] + public void AddPrinterDriverExTest() + { + const string name = "mydriver"; + var di2 = EnumPrinterDrivers().First(); + di2.pName = name; + using var priv = new ElevPriv("SeLoadDriverPrivilege"); + Assert.That(AddPrinterDriverEx(null, di2), ResultIs.Successful); + Assert.That(DeletePrinterDriverEx(null, null, name, DPD.DPD_DELETE_UNUSED_FILES, 0), ResultIs.Successful); + } + [Test] public void AddPrinterTest() { @@ -91,6 +119,23 @@ namespace Vanara.PInvoke.Tests Assert.That(DeletePrinterKey(p2, key), ResultIs.Successful); } } + + [Test] + public void AddPrintProcessorTest() + { + using var priv = new ElevPriv("SeLoadDriverPrivilege"); + Assert.That(AddPrintProcessor(null, null, "dummy.dll", "Dummy"), ResultIs.Successful); + Assert.That(DeletePrintProcessor(null, null, "Dummy"), ResultIs.Successful); + } + + [Test] + public void AddPrintProvidorTest() + { + var pi1 = new PROVIDOR_INFO_1 { pName = "Dummy", pDLLName = "dummy.dll" }; + Assert.That(AddPrintProvidor(null, pi1), ResultIs.Successful); + Assert.That(DeletePrintProvidor(null, null, pi1.pName), ResultIs.Successful); + } + [Test] public void AdvancedDocumentPropertiesTest() { @@ -107,6 +152,12 @@ namespace Vanara.PInvoke.Tests p.Dispose(); } + [Test] + public void CorePrinterDriverInstalledTest() + { + //Assert.That(CorePrinterDriverInstalled(null, null, ), ResultIs.Successful); + } + [Test] public void EnumFormsTest() { @@ -127,6 +178,28 @@ namespace Vanara.PInvoke.Tests Assert.That(EnumJobs(hprnt), Is.Empty); } + [Test] + public void EnumMonitorsTest() + { + MONITOR_INFO_1[] mon1; + Assert.That(mon1 = EnumMonitors().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", mon1.Select(v => v.pName))); + MONITOR_INFO_2[] mon2; + Assert.That(mon2 = EnumMonitors().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", mon2.Select(v => v.pEnvironment))); + } + + [Test] + public void EnumPortsTest() + { + PORT_INFO_1[] port1; + Assert.That(port1 = EnumPorts().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", port1.Select(v => v.pName))); + PORT_INFO_2[] port2; + Assert.That(port2 = EnumPorts().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", port2.Select(v => v.fPortType))); + } + [Test] public void EnumPrinterDataExTest() { @@ -143,6 +216,32 @@ namespace Vanara.PInvoke.Tests TestContext.WriteLine(string.Join(",", res1.Select(v => $"{v.valueName}={v.value} ({v.valueType})"))); } + [Test] + public void EnumPrinterDriversTest() + { + DRIVER_INFO_1[] res1; + Assert.That(res1 = EnumPrinterDrivers().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res1.Select(v => v.pName))); + DRIVER_INFO_2[] res2; + Assert.That(res2 = EnumPrinterDrivers().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res2.Select(v => v.pEnvironment))); + DRIVER_INFO_3[] res3; + Assert.That(res3 = EnumPrinterDrivers().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res3.Select(v => v.pDriverPath))); + DRIVER_INFO_4[] res4; + Assert.That(res4 = EnumPrinterDrivers().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res4.Select(v => v.pDataFile))); + DRIVER_INFO_5[] res5; + Assert.That(res5 = EnumPrinterDrivers().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res5.Select(v => v.pConfigFile))); + DRIVER_INFO_6[] res6; + Assert.That(res6 = EnumPrinterDrivers().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res6.Select(v => v.pHelpFile))); + DRIVER_INFO_8[] res8; + Assert.That(res8 = EnumPrinterDrivers().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res8.Select(v => v.pszMfgName))); + } + [Test] public void EnumPrinterKeyTest() { @@ -178,6 +277,23 @@ namespace Vanara.PInvoke.Tests //Assert.That(res9 = EnumPrinters().ToArray(), Is.Not.Empty); } + [Test] + public void EnumPrintProcessorDatatypesTest() + { + var proc = EnumPrintProcessors().First().pName; + DATATYPES_INFO_1[] res1; + Assert.That(res1 = EnumPrintProcessorDatatypes(proc).ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res1.Select(v => v.pName))); + } + + [Test] + public void EnumPrintProcessorsTest() + { + PRINTPROCESSOR_INFO_1[] res1; + Assert.That(res1 = EnumPrintProcessors().ToArray(), Is.Not.Empty); + TestContext.WriteLine(string.Join(",", res1.Select(v => v.pName))); + } + [Test] public void FormTest() { @@ -202,6 +318,12 @@ namespace Vanara.PInvoke.Tests } } + [Test] + public void GetCorePrinterDriversTest() + { + Assert.That(() => TestHelper.WriteValues(EnumCorePrinterDrivers(null, null)), Throws.Nothing); + } + [Test] public void GetDefaultPrinterTest() { @@ -211,6 +333,37 @@ namespace Vanara.PInvoke.Tests TestContext.WriteLine(sb); } + [Test] + public void GetPrinterDriverTest() + { + Assert.That(() => TestHelper.WriteValues(GetPrinterDriver(hprnt)), Throws.Nothing); + } + + [Test] + public void GetPrinterDriver2Test() + { + Assert.That(() => TestHelper.WriteValues(GetPrinterDriver2(hprnt)), Throws.Nothing); + } + + [Test] + public void GetPrinterDriverDirectoryTest() + { + Assert.That(GetPrinterDriverDirectory(null, null, 1, null, 0, out var req), ResultIs.Failure); + var sb = new StringBuilder(req); + Assert.That(GetPrinterDriverDirectory(null, null, 1, sb, sb.Capacity, out _), ResultIs.Successful); + TestContext.Write(sb); + } + + [Test] + public void GetPrinterDriverPackagePathTest() + { + var pkg = EnumCorePrinterDrivers().First().szPackageID; + Assert.That(GetPrinterDriverPackagePath(null, null, null, pkg, null, 0, out var req), ResultIs.Successful); + var sb = new StringBuilder(req); + Assert.That(GetPrinterDriverPackagePath(null, null, null, pkg, sb, sb.Capacity, out _), ResultIs.Successful); + TestContext.Write(sb); + } + [Test] public void GetPrintExecutionDataTest() { @@ -218,6 +371,15 @@ namespace Vanara.PInvoke.Tests TestHelper.WriteValues(data); } + [Test] + public void GetPrintProcessorDirectoryTest() + { + Assert.That(GetPrintProcessorDirectory(null, null, 1, null, 0, out var req), ResultIs.Failure); + var sb = new StringBuilder(req); + Assert.That(GetPrintProcessorDirectory(null, null, 1, sb, sb.Capacity, out _), ResultIs.Successful); + TestContext.Write(sb); + } + [Test] public void JobTest() {