.NET Framework
Wywołanie platformy
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ć nie będzie się kompilował dla FieldOffset(0) text; FieldOffset(0) i;
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); } }
}