Calling C++ Dll from C#
Why I Use Dynamic Invoke Instead of Static Invoke?
Sometimes when I want to write and call some unmanaged function (C++ DLL function), I do the following:
In the *.cpp file...
Hide Copy Code
int __declspec(dllexport) a(int b)
{
return b;
}
... compile the *.cpp file to a *.dll file and in the C# file:
Hide Copy Code
class Program
{
[DllImport(@"c:\a.dll")]
private static extern int a(int b);
static void Main(string[] args)
{
Console.WriteLine(a(3));
}
}
In this method, you see that I have to declare a
static
DLL filename, and when I compile to an excutable file (*.exe), I cannot change the DLL filename.
The second case is, I want to write some C++ DLL function for an ASP.NET/IIS (Internet Information Services) Web site. If I static invoke unmanaged, when I want to update the DLL file, I stop the Web site in IIS and replace the old file with the new file, but .. IIS still keeps the old DLL file. It does not release the file, and I have to stop the entire Web site, all services running in IIS for replacing the file.
So, I want to dynamically invoke an unmanaged file. I can load, invoke and free unmanaged DLL function initiatively.
How to Dynamic Invoke Unmanaged DLL Function?
The first way is by referring to dynamicinvokedll.aspx.
The second way that I want to introduce is how to use the
WindowAPI
function. We use three functions in kernel32.dll (this is a kernel DLL file and appears in [WindowRoot]\System32) LoadLibrary
, GetProcess
, and FreeLibrary
. You can find the C++ declare type functions on MSDN (msdn.com). I only show the declare in C#:
Hide Copy Code
class Program
{
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
static extern int LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
[DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
static extern IntPtr GetProcAddress( int hModule,
[MarshalAs(UnmanagedType.LPStr)] string lpProcName);
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
static extern bool FreeLibrary(int hModule);
}
The
LoadLibrary
function loads an unmanaged file, the GetProcAddress
function gets the function pointer of an unmanaged file and the FreeLibrary
function frees the unmanaged file. Now I can get the function pointer in a.dll very easily:
Hide Copy Code
int hModule = LoadLibrary(@"c:\a.dll");
if (hModule == 0) return false;
IntPtr intPtr = GetProcAddress(hModule, "a");
And when I want to free the a.dll file, I can call:
Hide Copy Code
FreeLibrary(hModule);
But C# doesn’t suport C++ function pointer, so we cannot invoke a C++ function pointer here. C# only has
Delegate
objects and we have to convert the function pointer to Delegate
by Marshal.GetDelegateForFunctionPointer
. It is declared in System.Runtime.InteropServices
as follows:
Hide Copy Code
public static Delegate GetDelegateForFunctionPointer (
IntPtr ptr,
Type t
)
(You can find more support for this function in MSDN.)
We first declare the
Delegate
for a function:
Hide Copy Code
delegate int A(int b);
And get the
delegate
object as follows:
A a = (A)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(A));
Now we can invoke a function as follows:
Hide Copy Code
static void Main(string[] args)
{
Console.WriteLine(a(3));
}
//Program.cs File
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace DLLCall
{
class Program
{
// NativeMethods
[DllImport("kernel32.dll")]
static extern int LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)] string strLibfilName);
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(int hModule,
[MarshalAs(UnmanagedType.LPStr)] string ProcName);
[DllImport("kernel32.dll")]
static extern void FreeLibrary(int hModule);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int myfunc(int number1, int number2);
[DllImport(@"E:\CPPDLL.dll",CallingConvention=CallingConvention.StdCall)]
static extern int Add(int a , int b);
static void Main(string[] args)
{
int b= Add(50, 600); // Direct Dll Import bby calling convention...
// Enable Unmanged Code Debugging in C# Project Properties for debuging in Cpp.
// Using LoadLibrary function Call
int hModule = LoadLibrary(@"E:\CPPDLL.dll");
IntPtr intptr;
if (hModule == 0)
return;
else
intptr = GetProcAddress(hModule, "Add");
myfunc cppfuntion = (myfunc)Marshal.GetDelegateForFunctionPointer(intptr,typeof(myfunc));
int c = cppfuntion(60, 80);
FreeLibrary(hModule);
}
}
}
// C++ Dll Project File
// CPPDLL.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
extern "C"
{
__declspec(dllexport) int Add(int a , int b)
{
return a+b;
}
}
Comments
Post a Comment