Szukaj…


Składnia

  • [DllImport („Example.dll”)] static extern void SetText (string inString);
  • [DllImport („Example.dll”)] static extern void GetText (StringBuilder outString);
  • [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] tekst ciąg;
  • [MarshalAs (UnmanagedType.ByValArray, SizeConst = 128)] byte [] byteArr;
  • [StructLayout (LayoutKind.Sequential)] public struct PERSON {...}
  • [StructLayout (LayoutKind.Explicit)] public struct MarshaledUnion {[FieldOffset (0)] ...}

Wywoływanie funkcji DLL 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);
    }
}

Zadeklaruj funkcję jako static extern parametr DllImportAttribute z jej Value ustawioną na .dll name. Nie zapomnij użyć przestrzeni nazw System.Runtime.InteropServices . Następnie nazwij to zwykłą metodą statyczną.

Platformy Invocation Services zajmą się ładowaniem .dll i znalezieniem żądanego zakończenia. P / Invoke w najprostszych przypadkach będzie również zbierać parametry i zwracać wartość do iz pliku .dll (tj. Konwertować z typów danych .NET na typy Win32 i odwrotnie).

Korzystanie z Windows API

Użyj pinvoke.net .

Zanim zadeklarujesz extern funkcję Windows API w swoim kodzie, zastanów się, czy jej nie szukać na pinvoke.net . Najprawdopodobniej mają już odpowiednią deklarację ze wszystkimi rodzajami wsparcia i dobrymi przykładami.

Tablice Marshallinga

Tablice prostego typu

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

Tablice sznurka

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

Struktury Marshaling

Prosta struktura

Podpis w C ++:

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

void GetSpouse(PERSON person, LP_PERSON spouse);

Definicja C #

[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 z polami o nieznanej wielkości. Przechodząc

Podpis w C ++

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

void SetVector(VECTOR &vector);

Po przekazaniu z kodu zarządzanego do niezarządzanego to

Tablicę data należy zdefiniować jako IntPtr, a pamięć powinna zostać jawnie przydzielona za pomocą Marshal.AllocHGlobal() (i zwolniona za pomocą 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 z polami o nieznanej wielkości. Odbieranie

Podpis w C ++:

typedef struct
{
    char *name;
} USER;

bool GetCurrentUser(USER *user);

Gdy takie dane są przekazywane z niezarządzanego kodu, a pamięć jest przydzielana przez niezarządzane funkcje, zarządzający wywołujący powinien otrzymać je do zmiennej IntPrt i przekonwertować bufor na zarządzaną tablicę. W przypadku łańcuchów istnieje wygodna 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);

Związki zrzeszające

Tylko pola typu wartości

Deklaracja C ++

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

Deklaracja C #

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

Mieszanie pól typu wartości i odniesienia

Nakładanie wartości referencyjnej na typ wartości jeden jest niedozwolone, więc nie można po prostu użyć FieldOffset(0) text; FieldOffset(0) i; nie będzie się kompilował dla

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

i generalnie musiałbyś zastosować niestandardowe zestawianie. Jednak w szczególnych przypadkach, takich jak ta, można zastosować prostsze techniki:

[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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow