2010-11-23 91 views
1

检索打印机端口信息时出现问题。我已经使用XcvData功能添加,配置和删除端口,但我不能让下面跑,我就想到:阅读端口信息问题

public PrinterNativeMethods.PORT_DATA_1 GetPortData1FromPort(string serverName, string portName) 
{ 
    IntPtr printerHandle; 
    PrinterNativeMethods.PRINTER_DEFAULTS defaults = new PrinterNativeMethods.PRINTER_DEFAULTS 
    { 
     DesiredAccess = PrinterNativeMethods.PrinterAccess.ServerAdmin 
    }; 

    string connection = string.Format(@"{0},XcvPort {1}", serverName, portName); 

    PrinterNativeMethods.OpenPrinter(connection, out printerHandle, ref defaults); 

    PrinterNativeMethods.CONFIG_INFO_DATA_1 configData = new PrinterNativeMethods.CONFIG_INFO_DATA_1 
    { 
     dwVersion = 1, 
    }; 

    uint size = (uint)Marshal.SizeOf(configData); 

    IntPtr pointer = Marshal.AllocHGlobal((int)size); 
    Marshal.StructureToPtr(configData, pointer, true); 

    PrinterNativeMethods.PORT_DATA_1 portData = new PrinterNativeMethods.PORT_DATA_1(); 
    uint portDataSize = (uint)Marshal.SizeOf(portData); 
    IntPtr portDataHandle = Marshal.AllocHGlobal((int)portDataSize); 

    try 
    { 
     uint outputNeeded; 
     uint status; 

     var retVal = PrinterNativeMethods.XcvData(printerHandle, "GetConfigInfo", pointer, size, out portDataHandle, portDataSize, out outputNeeded, out status); 
     //portDataHandle now points to a different location!? Unmarshalling will fail: 
     portData = (PrinterNativeMethods.PORT_DATA_1)Marshal.PtrToStructure(portDataHandle, typeof(PrinterNativeMethods.PORT_DATA_1)); 

    } 
    finally 
    { 
     PrinterNativeMethods.ClosePrinter(printerHandle); 
     Marshal.FreeHGlobal(pointer); 
     Marshal.FreeHGlobal(portDataHandle); 
    } 

    return portData; 
} 

从PrinterNativeMethods:

[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)] 
    internal static extern int XcvData(
     IntPtr handle, 
     string dataName, 
     IntPtr inputData, 
     uint inputDataSize, 
     out IntPtr outputData, 
     uint outputDataSize, 
     out uint outputNeededSize, 
     out uint status); 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    public struct PORT_DATA_1 
    { 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] 
     public string sztPortName; 

     public uint dwVersion; 

     public uint dwProtocol; 

     public uint cbSize; 

     public uint dwReserved; 

     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 49)] 
     public string sztHostAddress; 

     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33h)] 
     public string sztSNMPCommunity; 

     public uint 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 uint dwPortNumber; 

     public uint dwSNMPEnabled; 

     public uint dwSNMPDevIndex; 
    } 

附加注释:我不能使用WMI或prnadmin.dll作为替代方案。

+1

请定义“按我的预期运行”。是否抛出任何异常?究竟发生了什么?代码在哪里没有做你期望的? – Polyfun 2010-11-23 09:57:42

回答

0

您遇到的问题是您的XcvData定义的定义。由MS的definition的outputData参数只是简单地想要一个指针来写入数据,而一个IntPtr是一个指针,但是通过设置参数为out IntPtr你使它成为指针的指针,这就是为什么地址你的参数似乎在改变。将签名更改为下面的内容将解决您的问题。

[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)] 
internal static extern int XcvData(
    IntPtr handle, 
    string dataName, 
    IntPtr inputData, 
    uint inputDataSize, 
    IntPtr outputData, 
    uint outputDataSize, 
    out uint outputNeededSize, 
    out uint status); 

你也可以通过改变一些东西来避免一些不必要的分配/解除分配。

为XcvData你的方法的签名更改为

[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode)] 
internal static extern int XcvData(
    IntPtr handle, 
    string dataName, 
    IntPtr inputData, 
    uint inputDataSize, 
    ref PORT_DATA_1 outputData, 
    uint outputDataSize, 
    out uint outputNeededSize, 
    out uint status); 

假设你将使用XcvData的不仅仅是这一个电话越多,你可以通过设置在入口点属性进行多次引用它略有不同的签名DllImport属性。

[DllImport("winspool.drv", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint="XcvData")] 
internal static extern int XcvDataGetPortData1(
    IntPtr handle, 
    string dataName, 
    IntPtr inputData, 
    uint inputDataSize, 
    ref PORT_DATA_1 outputData, 
    uint outputDataSize, 
    out uint outputNeededSize, 
    out uint status); 

我给了我一个在我的机器上的快速测试,并可以确认这将解决您的问题。