C#删除Windows打印机管理中的打印机端口

时间:2018-01-12 19:34:07

标签: c# .net printing

我目前正在为Windows打印机管理编写一个帮助程序类(包装器)。

目前,我可以创建和删除打印机对象。

在接下来的一个步骤中,我想对打印机端口执行相同的操作。

目前,我正在使用以下代码在Windows打印机管理中创建一个新的打印机端口。

1。)DLL-Import

[DllImport("winspool.drv")]
private static extern bool OpenPrinter(string printerName, out IntPtr phPrinter, ref PrinterDefaults printerDefaults);
[DllImport("winspool.drv")]
private static extern bool ClosePrinter(IntPtr phPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode)]
private static extern bool XcvDataW(IntPtr hXcv, string pszDataName, IntPtr pInputData, UInt32 cbInputData, out IntPtr pOutputData, UInt32 cbOutputData, out UInt32 pcbOutputNeeded, out UInt32 pdwStatus);

2。)结构

/// <summary>
/// Defines the printer default settings like the access rights
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct PrinterDefaults
{
    public IntPtr pDataType;
    public IntPtr pDevMode;
    public PrinterAccess DesiredAccess;
}

/// <summary>
/// Stores the port data for adding a new printer port
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CreatePortData
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
    public string sztPortName;
    public UInt32 dwVersion;
    public UInt32 dwProtocol;
    public UInt32 cbSize;
    public UInt32 dwReserved;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)]
    public string sztHostAddress;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
    public string sztSNMPCommunity;
    public UInt32 dwDoubleSpool;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
    public string sztQueue;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
    public string sztIPAddress;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 540)]
    public byte[] Reserved;
    public UInt32 dwPortNumber;
    public UInt32 dwSNMPEnabled;
    public UInt32 dwSNMPDevIndex;
}

/// <summary>
/// Specifies identifiers to indicate the printer access
/// </summary>
internal enum PrinterAccess
{
    ServerAdmin = 0x01,
    ServerEnum = 0x02,
    PrinterAdmin = 0x04,
    PrinterUse = 0x08,
    JobAdmin = 0x10,
    JobRead = 0x20,
    StandardRightsRequired = 0x000f0000,
    PrinterAllAccess = (StandardRightsRequired | PrinterAdmin | PrinterUse)
}

3。)方法

/// <summary>
/// Adds a new printer port to the windows print management
/// </summary>
/// <param name="configurationType">The configuration type of the port. For example Standard TCP/IP Port.</param>
/// <param name="portName"></param>
/// <param name="portType"></param>
/// <param name="endpoint"></param>
/// <exception cref="ArgumentNullException">Occurs when a parameter is null or empty</exception>
/// <exception cref="PrinterManagementHelperException">Occurs when adding a new TCP printer port to the printer management failed</exception>
public static void CreatePrinterPort(string configurationType, string portName, PrinterPortType portType, string endpoint)
{
    // Validation
    if (String.IsNullOrEmpty(configurationType))
        throw new ArgumentNullException(nameof(configurationType));
    if (String.IsNullOrEmpty(portName))
        throw new ArgumentNullException(nameof(portName));
    if (String.IsNullOrEmpty(endpoint))
        throw new ArgumentNullException(nameof(endpoint));

    // Opens the printer management
    PrinterDefaults defaults = new PrinterDefaults { DesiredAccess = PrinterAccess.ServerAdmin };
    if (!OpenPrinter(",XcvMonitor " + configurationType, out IntPtr printerHandle, ref defaults))
    {
        string message = String.Format(Resources.FailedToOpenPrinterManagement, configurationType);
        throw new PrinterManagementHelperException(message);
    }

    try
    {
        // Defines the port properties
        CreatePortData portData = new CreatePortData
        {
            dwVersion = 1,
            dwProtocol = (uint)portType,
            dwPortNumber = portType == PrinterPortType.Raw ? 9100u : 515u,
            dwReserved = 0,
            sztPortName = portName,
            sztIPAddress = endpoint,
            sztHostAddress = endpoint,
            sztSNMPCommunity = "public",
            dwSNMPEnabled = 1,
            dwSNMPDevIndex = 1
        };

        // Sets the port properties into the pointer
        uint size = (uint)Marshal.SizeOf(portData);
        portData.cbSize = size;
        IntPtr pointer = Marshal.AllocHGlobal((int)size);
        Marshal.StructureToPtr(portData, pointer, true);

        try
        {
            // Adds the port to the printer management
            if (!XcvDataW(printerHandle, "AddPort", pointer, size, out IntPtr outputData, 0, out uint outputNeeded, out uint status))
                throw new PrinterManagementHelperException(Resources.FailedToAddTcpPrinterPortToPrinterManagement);
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            Marshal.FreeHGlobal(pointer);
        }
    }
    catch (Exception exception)
    {
        string message = String.Format(Resources.FailedToAddTcpPrinterPort,
            configurationType, portName, portType, endpoint);
        throw new PrinterManagementHelperException(message, exception);
    }
    finally
    {
        ClosePrinter(printerHandle);
    }
}

我在MSDN找到了以下主题。基于这个主题,我必须更改“AddPort”#39;参数为&#39; DeletePort&#39;。更改参数值不会从打印机管理中删除打印机端口。方法返回的状态是13(HEX:0x0000000d)。关于Win32 Error Codes,数据似乎无效。当我想删除打印机端口时,有没有人知道如何设置数据?

更新1

我发现我在上面的代码示例中使用的端口数据结构仅用于添加打印机端口。我在MSDN找到了一个主题。关于删除打印机端口的结构还有另一个topic。我尝试根据 CreatePortData 结构示例重建模型。我创建了以下结构

/// <summary>
/// Stores the port data for deleting an existing printer port
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DeletePortData
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
    public string sztPortName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)]
    public string sztName;
    public UInt32 dwVersion;
    public UInt32 dwReserved;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 540)]
    public byte[] Reserved;
}

现在删除打印机端口的完整源代码如下所示:

/// <summary>
/// Deletes an existing printer port from the printer management
/// </summary>
/// <param name="configurationType">The configuration type of the port. For example Standard TCP/IP Port.</param>
/// <param name="portName"></param>
public static void DeletePrinterPort(string configurationType, string portName)
{
    // Validation
    if (String.IsNullOrEmpty(configurationType))
        throw new ArgumentNullException(nameof(configurationType));
    if (String.IsNullOrEmpty(portName))
        throw new ArgumentNullException(nameof(portName));

    // Opens the printer management
    PrinterDefaults defaults = new PrinterDefaults { DesiredAccess = PrinterAccess.ServerAdmin };
    if (!OpenPrinter(",XcvMonitor " + configurationType, out IntPtr printerHandle, ref defaults))
    {
        string message = String.Format(Resources.FailedToOpenPrinterManagement, configurationType);
        throw new PrinterManagementHelperException(message);
    }

    try
    {
        // Defines the port properties
        DeletePortData portData = new DeletePortData
        {
            dwVersion = 1,
            dwReserved = 0,
            sztPortName = portName
        };

        // Sets the port properties into the pointer
        uint size = (uint)Marshal.SizeOf(portData);
        IntPtr pointer = Marshal.AllocHGlobal((int)size);
        Marshal.StructureToPtr(portData, pointer, true);

        try
        {
            // Deletes the port from the printer management
            if (!XcvDataW(printerHandle, "DeletePort", pointer, size, out IntPtr outputData, 0, out uint outputNeeded, out uint status))
                throw new PrinterManagementHelperException(Resources.FailedToDeletePrinterPortFromPrinterManagement);
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            Marshal.FreeHGlobal(pointer);
        }
    }
    catch (Exception exception)
    {
        string message = string.Format(Resources.FailedToDeletePrinterPort, configurationType, portName);
        throw new PrinterManagementHelperException(message, exception);
    }
    finally
    {
        ClosePrinter(printerHandle);
    }
}

该方法仍然返回状态13.数据仍然无效。有谁知道我做错了什么?

如果有人可以帮助我,我将不胜感激。

提前致谢!

1 个答案:

答案 0 :(得分:1)

我找到了解决问题的方法。我必须从 DeletePortData 结构中删除保留属性。

<强>要点:

要从打印机管理中删除现有的打印机端口,您必须执行以下步骤:

1。)DLL-Import

[DllImport("winspool.drv")]
private static extern bool OpenPrinter(string printerName, out IntPtr phPrinter, ref PrinterDefaults printerDefaults);
[DllImport("winspool.drv")]
private static extern bool ClosePrinter(IntPtr phPrinter);
[DllImport("winspool.drv", CharSet = CharSet.Unicode)]
private static extern bool XcvDataW(IntPtr hXcv, string pszDataName, IntPtr pInputData, UInt32 cbInputData, out IntPtr pOutputData, UInt32 cbOutputData, out UInt32 pcbOutputNeeded, out UInt32 pdwStatus);

2.)定义所需的结构:

/// <summary>
/// Defines the printer default settings like the access rights
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct PrinterDefaults
{
    public IntPtr pDataType;
    public IntPtr pDevMode;
    public PrinterAccess DesiredAccess;
}

/// <summary>
/// Stores the port data for deleting an existing printer port
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DeletePortData
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
    public string sztPortName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)]
    public string sztName;
    public UInt32 dwVersion;
    public UInt32 dwReserved;
}

/// <summary>
/// Specifies identifiers to indicate the printer access
/// </summary>
internal enum PrinterAccess
{
    ServerAdmin = 0x01,
    ServerEnum = 0x02,
    PrinterAdmin = 0x04,
    PrinterUse = 0x08,
    JobAdmin = 0x10,
    JobRead = 0x20,
    StandardRightsRequired = 0x000f0000,
    PrinterAllAccess = (StandardRightsRequired | PrinterAdmin | PrinterUse)
}

2.。)实施以下方法

/// <summary>
/// Deletes an existing printer port from the printer management
/// </summary>
/// <param name="configurationType">The configuration type of the port. For example Standard TCP/IP Port.</param>
/// <param name="portName"></param>
public static void DeletePrinterPort(string configurationType, string portName)
{
    // Validation
    if (String.IsNullOrEmpty(configurationType))
        throw new ArgumentNullException(nameof(configurationType));
    if (String.IsNullOrEmpty(portName))
        throw new ArgumentNullException(nameof(portName));

    // Opens the printer management
    PrinterDefaults defaults = new PrinterDefaults { DesiredAccess = PrinterAccess.ServerAdmin };
    if (!OpenPrinter(",XcvMonitor " + configurationType, out IntPtr printerHandle, ref defaults))
    {
        string message = String.Format(Resources.FailedToOpenPrinterManagement, configurationType);
        throw new PrinterManagementHelperException(message);
    }

    try
    {
        // Defines the port properties
        DeletePortData portData = new DeletePortData
        {
            dwVersion = 1,
            dwReserved = 0,
            sztPortName = portName
        };

        // Sets the port properties into the pointer
        uint size = (uint)Marshal.SizeOf(portData);
        IntPtr pointer = Marshal.AllocHGlobal((int)size);
        Marshal.StructureToPtr(portData, pointer, true);

        try
        {
            // Deletes the port from the printer management
            if (!XcvDataW(printerHandle, "DeletePort", pointer, size, out IntPtr outputData, 0, out uint outputNeeded, out uint status))
                throw new PrinterManagementHelperException(Resources.FailedToDeletePrinterPortFromPrinterManagement);
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            Marshal.FreeHGlobal(pointer);
        }
    }
    catch (Exception exception)
    {
        string message = string.Format(Resources.FailedToDeletePrinterPort, configurationType, portName);
        throw new PrinterManagementHelperException(message, exception);
    }
    finally
    {
        ClosePrinter(printerHandle);
    }
}