2009-07-09 7 views
0

Ceci est ma première tentative sérieuse de P/invoke. C'est une application de console que j'utilise pour élaborer le code d'un service Web qui, je l'espère, retournera une adresse mac à partir d'une adresse IP ou d'un nom de système complet. Le code compile. Cependant, lorsqu'il est exécuté sans arguments, j'obtiens une exception non gérée: IndexOutOfRangeException. Si je l'exécute avec des arguments, j'obtiens une exception non gérée différente, AccessViolationException: Tentative de lecture ou d'écriture de mémoire protégée. Et, je suis autodidacte ... S'il vous plaît soyez gentil si j'ai fait quelque chose de stupide. Voici mon code:Problème de Pinvoke avec l'API d'assistance Windows

using System; 
using System.Diagnostics; 
using System.Net; 
using System.Runtime.InteropServices; 
using System.Text; 

namespace GetMac 
{ 
    class Program 
    { 
     const int NET_STRING_IPV4_ADDRESS = 1; // 192.168.100.10 
     const int NET_STRING_IPV4_SERVICE = 2; // 192.168.100.10:80 
     const int NET_STRING_IPV4_NETWORK = 4; // 192.168.100/24 
     const int NET_STRING_IPV6_ADDRESS = 8; // 21DA:00D3:0000:2F3B:02AA:00FF:FE28:9C5A%2 
     const int NET_STRING_IPV6_ADDRESS_NO_SCOPE = 8; // 21DA:00D3:0000:2F3B:02AA:00FF:FE28:9C5A 
     const int NET_STRING_IPV6_SERVICE = 32; // [21DA:00D3:0000:2F3B:02AA:00FF:FE28:9C5A%2]:8080 
     const int NET_STRING_IPV6_SERVICE_NO_SCOPE = 64; // 21DA:00D3:0000:2F3B:02AA:00FF:FE28:9C5A:8080 
     const int NET_STRING_IPV6_NETWORK = 128; // 21DA:D3::/48 
     const int NET_STRING_NAMED_ADDRESS = 256; // www.microsoft.com 
     const int NET_STRING_NAMED_SERVICE = 512; // www.microsoft.com:80 

     internal static class NativeMethods 
     { 
      [DllImport("IpHlpApi.dll", CharSet = CharSet.Unicode)] 
      //public static extern uint ParseNetworkString(ref string networkString, int types, out NetAddressInfo addressInfo, out ushort portNumber, out byte prefixLength); 
      public static extern uint ParseNetworkString(string networkString, int types); 
     } 

     public static string GetMacAddress(IPAddress ipAddress) 
     { 
      string strMacAddress = string.Empty; 

      try 
      { 
       char delimChar = '='; 
       string strTempMacAddress = string.Empty; 
       ProcessStartInfo objProcessStartInfo = new ProcessStartInfo(); 
       Process objProcess = new Process(); 
       objProcessStartInfo.FileName = "nbtstat"; 
       objProcessStartInfo.RedirectStandardInput = false; 
       objProcessStartInfo.RedirectStandardOutput = true; 
       objProcessStartInfo.Arguments = "-A " + ipAddress; 
       objProcessStartInfo.UseShellExecute = false; 
       objProcess = Process.Start(objProcessStartInfo); 

       int Counter = -1; 
       while (Counter <= -1) 
       { 
        Counter = strTempMacAddress.Trim().ToLower().IndexOf("mac address", 0); 
        if (Counter > -1) 
        { 
         break; 
        } 
        strTempMacAddress = objProcess.StandardOutput.ReadLine(); 
       } 
       objProcess.WaitForExit(); 
       string[] words = strTempMacAddress.Split(delimChar); 
       strTempMacAddress = words[1]; 
       strMacAddress = strTempMacAddress.Trim(); 
       strMacAddress = strMacAddress.Replace('-', ':'); 
      } 
      catch (Exception Ex) 
      { 
       Console.WriteLine(Ex.ToString()); 
       Console.ReadLine(); 
      } 
      return strMacAddress; 
     } 

     static void Main(string[] args) 
     { 
      string macAddress = null; 
      IPAddress ipAddress = null; 
      string strHostOrIp; 

      if (args[0] == null) 
      { 
       Console.WriteLine("Please enter an IP address or fully qualified host name"); 
       return; 
      } 
      else 
      { 
       strHostOrIp = args[0]; 
      } 
      if (NativeMethods.ParseNetworkString(strHostOrIp, NET_STRING_IPV4_ADDRESS) == 0) //true if it's an IP address 
      { 
       IPAddress address = IPAddress.Parse(strHostOrIp); 
       ipAddress = address; 
      } 
      else if (NativeMethods.ParseNetworkString(strHostOrIp, NET_STRING_NAMED_SERVICE) == 0) //true if it's a fully qualified host name 
      { 
       IPHostEntry hostEntry = null; 
       try 
       { 
        hostEntry = Dns.GetHostEntry(strHostOrIp); 
       } 
       catch 
       { 
        return; 
       } 
       if (hostEntry.AddressList.Length == 0) 
       { 
        return; 
       } 
       foreach (IPAddress ip in hostEntry.AddressList) 
       { 
        if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) // true if we have IPv4 
        { 
         ipAddress = ip; 
         break; 
        } 
       } 
      } 
      else 
      { 
       ipAddress = null; 
      } 
      macAddress = GetMacAddress(ipAddress); 
      Console.WriteLine(macAddress); 
     } 
    } 
} 
// DWORD WINAPI ParseNetworkString(-in const WCHAR *NetworkString, 
//         -in DWORD Types, 
//         -out_opt PNET_ADDRESS_INFO AddressInfo, 
//         -out_opt USHORT *PortNumber, 
//         -out_opt BYTE *PrefixLength); 

// ParseNetworkString function parses the input network string and checks whether it is a legal 
// representation of the specified IP network string type. If the string matches a type and its 
// specification, the function can optionally return the parsed result 

// Return Value 
// If the function succeeds, the return value is ERROR_SUCCESS. // I think this means it returns 0. 
// If the function fails, the return value is one of the following error codes. 
// ERROR_INSUFFICIENT_BUFFER - The buffer passed to the function is too small. This error is returned if the buffer pointed to by the AddressInfo parameter is too small to hold the parsed network address. 
// ERROR_INVALID_PARAMETER - An invalid parameter was passed to the function. This error is returned if a NULL pointer is passed in the NetworkString parameter 

// http://msdn.microsoft.com/en-us/library/bb408412(VS.85).aspx 

Merci d'avance.

Répondre

0

Les trois paramètres "facultatifs" de ParseNetworkString ne sont pas facultatifs dans le sens où vous pouvez les omettre. Vous devez les fournir, mais vous pouvez passer null (ou zéro) pour dire que vous ne voulez pas que cette valeur particulière soit retournée.

1

C'est un DllImport correct "plus":

[DllImport("iphlpapi.dll", CharSet = CharSet.Unicode)] 
public static extern uint ParseNetworkString(string networkString, uint types, IntPtr addressInfo, IntPtr portNumber, IntPtr prefixLength); 

Exemple d'utilisation:

Console.WriteLine(ParseNetworkString("192.168.100.10:20", NET_STRING_IPV4_SERVICE, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)); 
Questions connexes