2010-11-23 92 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); 

我給了我一個在我的機器上的快速測試,並可以確認這將解決您的問題。