Recherche…


Syntaxe

  • [DllImport ("Example.dll")] static extern void SetText (string inString);
  • [DllImport ("Example.dll")] static externe void GetText (StringBuilder outString);
  • [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] texte de chaîne;
  • [MarshalAs (UnmanagedType.ByValArray, SizeConst = 128)] byte [] byteArr;
  • [StructLayout (LayoutKind.Sequential)] structure publique PERSON {...}
  • [StructLayout (LayoutKind.Explicit)] public struct MarshaledUnion {[FieldOffset (0)] ...}

Appeler une fonction Win32 dll

using System.Runtime.InteropServices;

class PInvokeExample
{
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern uint MessageBox(IntPtr hWnd, String text, String caption, int options);

    public static void test()
    {
        MessageBox(IntPtr.Zero, "Hello!", "Message", 0);
    }
}

Déclarez une fonction en tant que fichier static extern DllImportAttribute avec sa propriété Value définie sur .dll name. N'oubliez pas d'utiliser l'espace de noms System.Runtime.InteropServices . Puis appelez-le comme une méthode statique régulière.

Platform Invocation Services se chargera de charger le fichier .dll et de trouver la finition souhaitée. Dans la plupart des cas, le P / Invoke regroupera également les paramètres et renverra la valeur vers et depuis le fichier .dll (c.-à-d. La conversion des types de données .NET en fichiers Win32 et inversement).

Utiliser l'API Windows

Utilisez pinvoke.net .

Avant de déclarer une fonction API Windows extern dans votre code, envisagez de la rechercher sur pinvoke.net . Ils ont probablement déjà une déclaration appropriée avec tous les types de support et de bons exemples.

Matrices de Marshalling

Tableaux de type simple

[DllImport("Example.dll")]
static extern void SetArray(
    [MarshalAs(UnmanagedType.LPArray, SizeConst = 128)]
    byte[] data);

Tableaux de chaîne

[DllImport("Example.dll")]
static extern void SetStrArray(string[] textLines);

Structures de marshaling

Structure simple

Signature C ++:

typedef struct _PERSON
{
    int age;
    char name[32];
} PERSON, *LP_PERSON;

void GetSpouse(PERSON person, LP_PERSON spouse);

C # définition

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PERSON
{
    public int age;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string name;
}

[DllImport("family.dll", CharSet = CharSet.Auto)]
public static extern bool GetSpouse(PERSON person, ref PERSON spouse);

Struct avec des champs de tableau de taille inconnue. En passant

Signature C ++

typedef struct
{
    int length;
    int *data;
} VECTOR;

void SetVector(VECTOR &vector);

Lorsqu'elle est passée du code géré au code non géré, cette

Le tableau de data doit être défini comme IntPtr et la mémoire doit être explicitement allouée avec Marshal.AllocHGlobal() (et libérée avec les Marshal.FreeHGlobal() ):

[StructLayout(LayoutKind.Sequential)]
public struct VECTOR : IDisposable
{
    int length;
    IntPtr dataBuf;

    public int[] data
    {
        set
        {
            FreeDataBuf();
            if (value != null && value.Length > 0)
            {
                dataBuf = Marshal.AllocHGlobal(value.Length * Marshal.SizeOf(value[0]));
                Marshal.Copy(value, 0, dataBuf, value.Length);
                length = value.Length;
            }
        }
    }
    void FreeDataBuf()
    {
        if (dataBuf != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(dataBuf);
            dataBuf = IntPtr.Zero;
        }
    }
    public void Dispose()
    {
        FreeDataBuf();
    }
}

[DllImport("vectors.dll")]
public static extern void SetVector([In]ref VECTOR vector);

Struct avec des champs de tableau de taille inconnue. Recevoir

Signature C ++:

typedef struct
{
    char *name;
} USER;

bool GetCurrentUser(USER *user);

Lorsque de telles données sont transmises à partir de code non géré et que la mémoire est allouée par les fonctions non gérées, l'appelant géré doit le recevoir dans une variable IntPrt et convertir le tampon en un tableau géré. Dans le cas de chaînes, il existe une Marshal.PtrToStringAnsi() pratique Marshal.PtrToStringAnsi() :

[StructLayout(LayoutKind.Sequential)]
public struct USER
{
    IntPtr nameBuffer;
    public string name { get { return Marshal.PtrToStringAnsi(nameBuffer); } }
}

[DllImport("users.dll")]
public static extern bool GetCurrentUser(out USER user);

Union de marshaling

Champs de type valeur uniquement

Déclaration C ++

typedef union
{
    char c;
    int i;
} CharOrInt;

Déclaration C #

[StructLayout(LayoutKind.Explicit)]
public struct CharOrInt
{
    [FieldOffset(0)]
    public byte c;
    [FieldOffset(0)]
    public int i;
}

Mélanger les champs de type valeur et référence

Le chevauchement d'une valeur de référence avec un type de valeur un n'est pas autorisé, vous ne pouvez donc pas simplement utiliser le FieldOffset(0) text; FieldOffset(0) i; ne compilera pas pour

typedef union
{
    char text[128];
    int i;
} TextOrInt;

et généralement vous devriez employer le marshaling fait sur commande. Cependant, dans des cas particuliers comme celui-ci, des techniques plus simples peuvent être utilisées:

[StructLayout(LayoutKind.Sequential)]
public struct TextOrInt
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
    public byte[] text;
    public int i { get { return BitConverter.ToInt32(text, 0); } }
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow