PROWAREtech
ASP.NET Core: 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, you will want to 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 Class1
{
// 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.Cdecl)]
private static extern IntPtr PrettyFuncName(out IntPtr ppVar); // NOTE: a pointer to a pointer
// NOTE: FASTCALL: FastCall is not supported! Use at your 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);
}
}