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
- Interop calls are slower than normal C# methods (due to marshaling overhead).
- Errors in unmanaged code (memory leaks, pointer errors) can crash the application directly.
- Therefore, it should only be used when truly necessary.
TL;DR
- Interop: Provides access to C/C++ libraries from C#.
- Native functions are called with the
DllImportattribute. - Structs must be properly mapped with
StructLayout. - There is performance overhead, so it should be used carefully.
Related Articles
C# Basic Data Types
Basic data types in C#: numeric, text, logical, object-based, and nullable types.
C# Exception Handling (try, catch, finally)
Learn how to handle exceptions in C# using try, catch, and finally blocks to manage errors safely with clear examples.
C# Type Conversions
Learn how type conversions work in C#, including implicit and explicit casting, Parse, TryParse, and Convert methods with examples.
Structs in C# – Differences from Classes
Learn the key differences between structs and classes in C#, including memory model, inheritance, boxing, and performance.