2010-11-23 29 views
1

J'ai un problème lors de la récupération des informations sur les ports de l'imprimante. J'utilise déjà XcvData fonction pour ajouter, configurer et supprimer des ports, mais je ne peux pas obtenir ce qui suit pour courir comme je l'attends à:Problème lors de la lecture des informations de port

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; 
} 

de 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; 
    } 

commentaire supplémentaire: Je ne peux pas utilisez WMI ou prnadmin.dll comme alternative.

+1

Veuillez définir "exécuter comme je l'espère". Des exceptions sont-elles levées? Qu'est-ce qui se passe réellement? Où exactement le code ne fait-il pas ce que vous attendez? – Polyfun

+0

Je m'attendrais à ce que cela fonctionne ;-), je reçois une AccessViolationException sur l'appel ci-dessous var retVal = PrinterNativeMethods.XcvData (...). J'ai remarqué que le portDataHandle IntPtr a une valeur différente après l'appel à XcvData. – SomeCallMeTim

Répondre

0

Le problème que vous rencontrez est dans la définition de votre définition XcvData. Le paramètre outputData du MS definition veut simplement un pointeur pour écrire des données, un IntPtr est un pointeur, mais en réglant le paramètre sur sur IntPtr, vous en faites un pointeur vers un pointeur, c'est pourquoi l'adresse de votre paramètre semble changer. Changer la signature à la ci-dessous permettra de résoudre votre problème.

[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); 

Vous pouvez également éviter une allocation/désallocation inutile en modifiant les choses un peu.

Changer votre signature de la méthode pour 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); 

En supposant que vous utiliserez XcvData pour plus que cet appel unique, vous pouvez faire plusieurs références à elle avec des signatures légèrement différentes en définissant la propriété EntryPoint sur la Attribut DllImport. J'ai fait un test rapide sur ma machine et je peux confirmer que cela va résoudre votre problème.