Suche…


Syntax

  • [DllImport ("Example.dll")] statisch extern void SetText (Zeichenfolge inString);
  • [DllImport ("Example.dll")] statisch extern void GetText (StringBuilder outString);
  • [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] Zeichenfolgentext;
  • [MarshalAs (UnmanagedType.ByValArray, SizeConst = 128)] Byte [] ByteArr;
  • [StructLayout (LayoutKind.Sequential)] public struct PERSON {...}
  • [StructLayout (LayoutKind.Explicit)] öffentliche Struktur MarshaledUnion {[FieldOffset (0)] ...}

Aufrufen einer Win32-DLL-Funktion

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

Deklarieren Sie eine Funktion als static extern indem Sie DllImportAttribute mit der Eigenschaft Value auf .dll name setzen. Vergessen Sie nicht, den Namespace System.Runtime.InteropServices zu verwenden. Dann rufen Sie es als normale statische Methode auf.

Die Platform Invocation Services kümmern sich darum, die DLL zu laden und die gewünschte Funktion zu finden. In den meisten einfachen Fällen wird das P / Invoke auch Parameter marshallieren und Werte von und zur DLL zurückgeben (dh Konvertierung von .NET-Datentypen in Win32-Datentypen und umgekehrt).

Windows-API verwenden

Verwenden Sie pinvoke.net .

Bevor Sie eine extern Windows-API-Funktion in Ihrem Code deklarieren, sollten Sie sie auf pinvoke.net suchen . Sie haben höchstwahrscheinlich bereits eine passende Erklärung mit allen unterstützenden Typen und guten Beispielen.

Marshalling-Arrays

Arrays einfacher Art

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

Arrays von Zeichenfolgen

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

Marshaling-Strukturen

Einfache Struktur

C ++ - Signatur:

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

void GetSpouse(PERSON person, LP_PERSON spouse);

C # -Definition

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

Struktur mit Arrayfeldern unbekannter Größe. Übergeben

C ++ - Signatur

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

void SetVector(VECTOR &vector);

Wenn dieser Code von verwaltetem an nicht verwalteten Code übergeben wird

Das data ist als IntPtr definiert und Speicher sollte explizit zugewiesen Marshal.AllocHGlobal() (und befreit Marshal.FreeHGlobal() anschliessend):

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

Struktur mit Arrayfeldern unbekannter Größe. Empfang

C ++ - Signatur:

typedef struct
{
    char *name;
} USER;

bool GetCurrentUser(USER *user);

Wenn solche Daten aus nicht verwaltetem Code übergeben werden und der Speicher von den nicht verwalteten Funktionen zugewiesen wird, sollte der verwaltete Aufrufer sie in eine IntPrt Variable empfangen und den Puffer in ein verwaltetes Array konvertieren. Im Fall von Strings gibt es eine praktische Marshal.PtrToStringAnsi() -Methode:

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

Gewerkschaften marschieren

Nur Felder mit Werttyp

C ++ - Deklaration

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

C # -Deklaration

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

Wertetyp und Referenzfelder mischen

Die Überlappung eines Referenzwerts mit dem Werttyp Eins ist nicht zulässig. Sie können also nicht einfach den FieldOffset(0) text; FieldOffset(0) i; wird nicht für kompilieren

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

Im Allgemeinen müssten Sie ein benutzerdefiniertes Marshalling verwenden. In besonderen Fällen wie dieser können jedoch einfachere Techniken verwendet werden:

[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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow