PROWAREtech
.NET: Call an External Function Using DllImport in C#
Learn the difference between "cdecl" and "stdcall" with assembly.
Declare a callback function for a .DLL file written in C/C++.
When writing external functions for use by .NET, it may help to know which calling convention to use. Generally, use
CallingConvention.StdCall
which can be declared in Microsoft's Visual Studio C++ compiler by simply adding a __stdcall
between the function return type
and the function name. Also, make sure to declare the function an extern "C" function by wrapping it and others in a extern "C" { }
block of code. This prevents the C++ compiler from
mangling the name of the function up.
The IntPtr
type is an interesting one. Use it for pointers to objects in memory, not primitive data types. A pointer to a pointer would be declared
out IntPtr
. There is an example of this below.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Runtime.InteropServices;
using System.Text;
namespace Code
{
class FunctionImports
{
// NOTE: STDCALL: The callee cleans the stack. The majority of Window API functions use this calling convention.
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall)]
private static extern uint SetThreadExecutionState(uint esFlags);
// NOTE: CDECL: The caller cleans the stack.This enables calling functions with variable arguments because the caller knows
// how many were passed.This makes it appropriate to use methods that accept a variable number of parameters, like printf() does.
[DllImport("prowaretech.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern uint SomeFunc(double[] floating_points);
// NOTE: The name of the function as exported by the library is "UglyFuncName" and this
// is a useful way to import a function while giving it a more descriptive name.
[DllImport("prowaretech.dll", EntryPoint = "UglyFuncName", CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr PrettyFuncName(out IntPtr ppVar); // NOTE: a pointer to a pointer
// NOTE: FASTCALL: FastCall is not supported! Use at one's own discretion!
[DllImport("prowaretech.dll", CallingConvention = CallingConvention.FastCall)]
private static extern void BasicFunc(string str);
// NOTE: THISCALL: The first parameter is the "this" pointer and is stored in the ECX register. Other parameters
// are pushed in the stack. This calling convention is used to call methods on classes from an unmanaged DLL.
[DllImport("prowaretech.dll", CallingConvention = CallingConvention.ThisCall)]
private static extern void BasicFuncOfAnObject(uint[] uint_array);
}
}