Loading...

Interop in C# (Working with C/C++ Libraries)

Learn how to use Interop in C# to work with C/C++ libraries, including P/Invoke, unmanaged code, and data marshaling.

In .NET applications, sometimes it is necessary to leverage existing C or C++ libraries. This is called Interop (interoperability). C# provides access to unmanaged code through the DllImport attribute. This way, high-performance or system-level functions can be invoked directly.


Calling Native Functions with DllImport

On Windows, functions in system libraries such as user32.dll or kernel32.dll can be called directly from C# code. For this, the System.Runtime.InteropServices namespace is used.


using System;
using System.Runtime.InteropServices;

class Program
{
    // Importing a Win32 API function
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern int MessageBox(IntPtr hWnd, string text, string caption, int type);

    static void Main()
    {
        MessageBox(IntPtr.Zero, "Hello Interop!", "Interop Example", 0);
    }
}

Here, the Win32 API function MessageBox is called. Although compiled by C#, it is actually executing native (C) code.


Calling a Function Written in C

You can also use your own C/C++ library (for example mylib.dll). First, a function is defined on the C side:


// mylib.c
__declspec(dllexport) int AddNumbers(int a, int b)
{
    return a + b;
}

// Imported on the C# side
using System.Runtime.InteropServices;

class NativeMethods
{
    [DllImport("mylib.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern int AddNumbers(int x, int y);
}

class Program
{
    static void Main()
    {
        int result = NativeMethods.AddNumbers(5, 7);
        Console.WriteLine($"Sum: {result}");
    }
}

In this example, the C function AddNumbers is called from C#. Parameters are automatically converted to the appropriate types through marshaling.


Structs and Marshaling

C libraries may use not only primitive types but also struct types. In this case, the same structure must be defined on the C# side with the StructLayout attribute.


// C side
typedef struct
{
    int width;
    int height;
} Size;

__declspec(dllexport) int CalcArea(Size s)
{
    return s.width * s.height;
}

// C# side
[StructLayout(LayoutKind.Sequential)]
public struct Size
{
    public int width;
    public int height;
}

class NativeMethods
{
    [DllImport("mylib.dll")]
    public static extern int CalcArea(Size s);
}

class Program
{
    static void Main()
    {
        var size = new Size { width = 10, height = 20 };
        int area = NativeMethods.CalcArea(size);
        Console.WriteLine($"Area: {area}");
    }
}

Performance and Safety


TL;DR

  • Interop: Provides access to C/C++ libraries from C#.
  • Native functions are called with the DllImport attribute.
  • Structs must be properly mapped with StructLayout.
  • There is performance overhead, so it should be used carefully.

Related Articles

C# Type Conversions

Learn how type conversions work in C#, including implicit and explicit casting, Parse, TryParse, and Convert methods with examples.