.NET_Framework

.NET Core.NET Framework Acronym Glossary.NET Framework ADO.NET.NET Framework CLR.NET Framework Code Contracts.NET Framework Collections.NET Framework Custom Types.NET Framework DateTime parsing.NET Framework Dependency Injection.NET Framework Dictionaries.NET Framework Encryption / Cryptography.NET Framework Exceptions.NET Framework Expression Trees.NET Framework File Input/Output.NET Framework ForEach.NET Framework Garbage Collection.NET Framework Globalization in ASP.NET MVC using Smart internationalization for ASP.NET.NET Framework HTTP clients.NET Framework HTTP servers.NET Framework Introduction.NET Framework JIT compiler.NET Framework JSON Serialization.NET Framework LINQ.NET Framework Managed Extensibility.NET Framework Memory management.NET Framework Networking.NET Framework NuGet packaging system.NET Framework Platform Invoke.NET Framework Process and Thread affinity setting.NET Framework Reading and writing Zip files.NET Framework ReadOnlyCollections.NET Framework Reflection.NET Framework Regular Expressions (System.Text.RegularExpressions).NET Framework Serial Ports.NET Framework Settings.NET Framework SpeechRecognitionEngine class to recognize speech.NET Framework Stack and Heap.NET Framework Strings.NET Framework Synchronization Contexts.NET Framework System.Diagnostics.NET Framework System.IO.NET Framework System.IO.File class.NET Framework System.Net.Mail.NET Framework System.Reflection.Emit namespace.NET Framework System.Runtime.Caching.MemoryCache (ObjectCache).NET Framework Task Parallel Library (TPL).NET Framework Task Parallel Library (TPL) API Overviews.NET Framework Threading.NET Framework TPL Dataflow.NET Framework Unit testing.NET Framework Upload file and POST data to webserver.NET Framework Using ProgressT and IProgressT.NET Framework VB Forms.NET Framework Work with SHA1 in C Sharp.NET Framework Write to and read from StdErr stream.NET Framework XmlSerializerJSON in .NET with Newtonsoft.JsonParallel processing using .NET framework



.NET Framework Platform Invoke

From WikiOD

Syntax[edit | edit source]

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

Calling a Win32 dll function[edit | edit source]

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

Declare a function as static extern stting DllImportAttribute with its Value property set to .dll name. Don't forget to use System.Runtime.InteropServices namespace. Then call it as an regular static method.

The Platform Invocation Services will take care of loading the .dll and finding the desired finction. The P/Invoke in most simple cases will also marshal parameters and return value to and from the .dll (i.e. convert from .NET datatypes to Win32 ones and vice versa).

Using Windows API[edit | edit source]

Use pinvoke.net.

Before declaring an extern Windows API function in your code, consider looking for it on pinvoke.net. They most likely already have a suitable declaration with all supporting types and good examples.

Marshalling arrays[edit | edit source]

Arrays of simple type

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

Arrays of string

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

Marshaling structs[edit | edit source]

Simple struct

C++ signature:

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

Struct with unknown size array fields. Passing in

C++ signature

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

void SetVector(VECTOR &vector);

When passed from managed to unmanaged code, this

The data array should be defined as IntPtr and memory should be explicitly allocated with Marshal.AllocHGlobal() (and freed with Marshal.FreeHGlobal() afterwords):

[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 with unknown size array fields. Receiving

C++ signature:

typedef struct
{
    char *name;
} USER;

bool GetCurrentUser(USER *user);

When such data is passed out of unmanaged code and memory is allocated by the unmanaged functions, the managed caller should receive it into an IntPrt variable and convert the buffer to a managed array. In case of strings there is a convenient Marshal.PtrToStringAnsi() method:

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

Marshaling unions[edit | edit source]

Value*type fields only

C++ declaration

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

C# declaration

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

Mixing value-type and reference fields

Overlapping a reference value with a value type one is not allowed so you cannot simply use the FieldOffset(0) text; FieldOffset(0) i; will not compile for

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

and generally you would have to employ custom marshaling. However, in particular cases like this simpler technics may be used:

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

Credit:Stack_Overflow_Documentation