Importation: Syntax translation for using C++ library under C# - c#

Currently I'm trying to use a C++ library under C# using DLL importation. Library is called Interception.
The problem is that I don't know how to translate #define entries and typedef declaration of the header file:
https://github.com/oblitum/Interception/blob/master/include/interception.h
I tried to use "using" directive, but with no success (I can't access to the void definition).
Moreover, I didn't understood the role of __declspec(dllimport) in this header. In my c# project, I just ignored it? Is it good to do that?
This is the code I want to use in c# (it's a sample of the library)
https://github.com/oblitum/Interception/blob/master/samples/hardwareid/main.cpp
EDIT:
What I've tried: basic importation:
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
void interception_set_filter(void* context, InterceptionPredicate predicate, ushort filter);
I don't know ho to convert InterceptionPredicate. According the header file, InterceptionFilter is a ushort, and InterceptionContext is a void pointer (void*).

The C++ library should be compiled as a .DLL file. This .DLL file should have exported functions. You can use the Depends tool to check what's exported from a .DLL. .NET code can call C++ exported functions using what's called "Platform Invoke".
Now, I strongly suggest you take a deep look at this Platform Invoke Tutorial that will guide you.
PS: void * should be declared in c# as IntPtr. enums should be redeclared as enums. Functions should be declared as static extern methods marked with the DllImport attribute.

First, it looks like you're trying to implement a global keyboard/mouse hook .. if that's the case, I'd recommend googling 'C# low level keyboard and mouse hook'.
Now for your question, first is the __declspec(dllimport) issue: this would be if you were actually using the header in a C++ application, that is the C++ equivilent of the C# DllImport .. so in effect you didn't ignore it, you implemented it. In C++ it just tells the linker that the function declared as such will be imported from a specific DLL instead of it being a local function (pretty similar to what the C# DllImport directive does)
Next is for function pointer issue (InterceptionPredicate). In the header it is defined as such:
typedef int (*InterceptionPredicate)(InterceptionDevice device);
And InterceptionDevice is just an 'int'. So the InterceptionPredicate is just a function pointer type (or Delegate in C#), so your delegate definition for InterceptionPredicate would look like this:
// [UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate int InterceptionPredicate (int device);
A note about the UnmanagedFunctionPointer calling convention descriptor: IF you know what kind of calling convention (stdcall, fastcall, cdecl) the exported function might be using, you could specify here so that the .NET marshaler will know how to pass the data between the managed/unmanaged code, but if you don't know it or it's not specified typically you can just leave that off.
Also, as others have mentioned, unless you have the 'unsafe' flag specified in your C# properties, a void* type should always be an IntPtr in C#.
Also, be sure to mark the dll function in your C# code as public static extern, see example below.
So to make an example of the function you've specified, here's what could be done:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace InterceptorTest
{
public class Interceptor : IDisposable
{
#region DllImports
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr interception_create_context();
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern void interception_destroy_context(IntPtr context);
[DllImport("interception.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern void interception_set_filter(IntPtr context, InterceptionPredicate predicate, ushort filter);
// The function pointer type as defined in interception.h that needs to be defined as a delegate here
public delegate int InterceptionPredicate(int device);
#endregion
#region private members
private InterceptionPredicate m_PredicateDelegate { get; set; }
private IntPtr m_Context { get; set; }
#endregion
#region methods
public Interceptor(ushort filter)
{
// be sure to initialize the context
this.m_PredicateDelegate = new InterceptionPredicate(this.DoSomethingWithInterceptionPredicate);
this.m_Context = interception_create_context();
interception_set_filter(this.m_Context, this.m_PredicateDelegate, filter);
}
private void Cleanup()
{
interception_destroy_context(this.m_Context);
// the next line is not really needed but since we are dealing with
// managed to unmanaged code it's typically best to set to 0
this.m_Context = IntPtr.Zero;
}
public void Dispose()
{
this.Cleanup();
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing) { this.Cleanup(); }
}
public int DoSomethingWithInterceptionPredicate(int device)
{
// this function is something you would define that would do something with
// the device code (or whatever other paramaters your 'DllImport' function might have
// and return whatever interception_set_filter is expecting
return device;
}
#endregion
}
static class Program
{
[STAThread]
private static void Main(string[] argv)
{
Interceptor icp = new Interceptor(10);
// do something with the Interceptor object
}
}
}
Hope that gets you on the right track.

Ok, I found an example code that was hidden on the GIT. Thank you google!
https://gist.github.com/1959219
It precises all function from DLL importation, with a working example.

Related

How do I load a struct containing function pointers from an external dll?

I have been given an external c++ dll that I need to load and use in my C# project. The dll comes with a header file, which is this (simplified / anonymized):
typedef struct
{
int (*GetVersion)();
int (*StartServer)(const char *ip, int port);
void (*OnRemoteError)(void *caller, int error);
} RemoteServerPluginI;
extern "C" __declspec(dllexport) RemoteServerPluginI* GetServerPluginInterface();
I have a few questions on how to use this in my C# project:
do I translate "void*" with object?
do I translate the char* array to a string or to a char[] ?
OnRemoteError is supposed to be a callback; to register my callback, should I simply assign my callback function to this field?
Any link to the relevant documentation is most appreciated.
I might have figured it out, after a ton of reading and helpful pointers both here on SO and reddit (a special thank you to this comment).
BIG DISCLAIMER: at this time I haven't been able to interface with the actual system, so this might be wrong. However I've successfully loaded the dll and read the version, which makes me think I might have solved it. If anything comes up I will update the answer.
First thing is to declare a struct to map the C++ struct into our C# code.
We can use the MarshalAs attribute to tell the marshaller that these delegates are really just function pointers:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int GetVersionT();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int StartServerT(string ip, int port);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OnRemoteErrorT(object caller, int error);
public struct RemoteServerPluginI
{
[MarshalAs(UnmanagedType.FunctionPtr)] public GetVersionT GetVersion;
[MarshalAs(UnmanagedType.FunctionPtr)] public StartServerT StartServer;
[MarshalAs(UnmanagedType.FunctionPtr)] public OnRemoteErrorT OnRemoteError;
// a lot of other methods not shown
}
Then we make a helper class that loads the DLL using DLLImport and calls the method that was defined in the dll.
This is easily done using an extern method:
[DllImport("data/remoteplugin.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetServerPluginInterface();
Note that we had to specify the calling convention.
Another important thing to note: this method returns an IntPtr object.
Luckily we are done now, we just need to cast this to the correct type:
var ptr = GetServerPluginInterface();
var server = (RemoteServerPluginI)Marshal.PtrToStructure(ptr, typeof(RemoteServerPluginI));
At this point I just wrapped everything into a convenience class to manage access, and voilà!
Here is the final code:
public static class IntPtrExtensions
{
// I'm lazy
public static T ToStruct<T>(this IntPtr ptr)
=> (T)Marshal.PtrToStructure(ptr, typeof(T));
}
public static class RemoteControlPlugin
{
[DllImport("path/to/remoteplugin.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GetServerPluginInterface();
private static RemoteServerPluginI? _instance = null;
public static RemoteServerPluginI Instance =>
(RemoteServerPluginI)(
_instance ??
(_instance = GetServerPluginInterface().ToStruct<RemoteServerPluginI>())
);
}
internal static class Program
{
private static void Main(string[] args)
{
var remoteServer = RemoteControlPlugin.Instance;
Console.WriteLine(remoteServer.GetVersion()); // Easy!
}
}

Using a dynamically loaded dll that contains a dynamically loaded dll itself

Intro
My program allows other developers to write plugins. These plugins(which are dll files) are placed in a certain directory and my program is able to load them at runtime like this:
Assembly assembly = Assembly.LoadFrom("MyPluginPath");
object Plugin = assembly.CreateInstance("Plugins.Main", true);
Then the program will be able to call the main method from the plugin this way:
var pluginType = Plugin.GetType();
var methodOutput = pluginType.GetMethod("MyInternalMethod").Invoke(Plugin, new object[] {param});
This works fine for all the plugins I've wrote so far that followed a certain structure as below:
namespace Plugins
{
public class Main : IDisposable
{
public Bitmap MyInternalMethod(Bitmap param)
{
// method body
}
}
}
Problem
Now there is this new plugin I've to wrote which loads an external dll at runtime itself:
namespace Plugins
{
public class Main : IDisposable
{
[System.Runtime.InteropServices.DllImport("MyExternalDLL.dll")]
unsafe private static extern int Initialize(int* arg1, char* arg2);
public Bitmap MyInternalMethod(Bitmap param)
{
// method body
Initialize(x,y);
}
}
}
Initialize(x,y) method in the above code gives me an error that says
Failed to initialize com library.
Notes
I created an executable test application for my plugin and it worked fine, so I know the problem occurs when using it as a dll at runtime.
I thought maybe I should load my external dll in the main program and then pass it as a Func<> object to my plugin but Func<> doesn't allow pointer variables (Initialize method contains arguments like int* and char*) and even if it does, I'm not sure if this solution is gonna work.
I tried using winApi as "Sinatr" suggested in the comments by following this answer but the error stays. I even tried loading MyExternalDLL.dll in the main program using winApi and passing the retrieved address of Initialize method to my plugin like the following code but the error remains the same (this way the error happens on func(x,y)):
Main program:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string name);
IntPtr dllHandle = IntPtr.Zero;
IntPtr addr = IntPtr.Zero;
private void RunPlugin()
{
dllHandle = LoadLibrary("MyExternalDLL.dll");
addr = GetProcAddress(dllHandle, "Initialize");
var methodOutput = pluginType.GetMethod("MyInternalMethod").Invoke(Plugin, new object[] {param, addr});
}
Plugin:
public class Main : IDisposable
{
private unsafe delegate byte initialize_api(int* arg1, char* arg2);
public Bitmap MyInternalMethod(Bitmap param, IntPtr addr)
{
// method body
//initialize_api is a delegate with the same signature as Initialize(x,y);
var func = (initialize_api)Marshal.GetDelegateForFunctionPointer(addr, typeof(initialize_api));
func(x,y);
}
}
Since we are talking about plugins here, I don't think implementing a common Interface which both my program and the plugins can use is possible.
Question
Is it even possible to use a dynamically loaded dll that contains a dynamically loaded dll the way I described? if it is, what should I do to make this work?

access violation upon return from function which does reverse P/Invoke

I have a c# managed project that imports an unmanaged c++ dll. What I wanted was to get logging to work using the logging function I wrote in the C# code. So I added the following to my C# side:
public struct API
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void FunctionPointer(string msg);
[DllImport("mydll.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
unsafe public static extern void setLoggerPointer(IntPtr fctPointer);
[DLLImport("mydll.dll", SetLastError = true)]
[return: MarshalAsAttribute(UnmanagedType.I1)] unsafe public static extern bool init();
}
public unsafe class MyInterface
{
public MyInterface()
{
API.FunctionPointer loggerDelegate;
loggerDelegate = new API.FunctionPointer(Logger.LogMessage);
IntPtr loggerPtr = Marshal.GetFunctionPointerForDelegate(loggerDelegate);
API.setLoggerPointer(loggerPtr);
if (API.init())
{
//do stuff
}
}
}
Here is my Logger class definition:
public static class Logger
{
public static void LogMessage(string msg)
{
Console.WriteLine(msg);
fileStream.Write(msg);
}
}
I have the following on the c++ side header:
#define MY_C_API extern "C" __declspec(dllexport);
MY_C_API __declspec(dllexport) void __stdcall setLoggerPointer( void *fctPointer(LPCTSTR msg) );
MY_C_API __declspec(dllexport) bool __stdcall init();
And in the C++ source:
//global variable
void *(*logger)(LPCTSTR msg);
void __stdcall setLoggerPointer( void *fctPointer(LPCTSTR msg) )
{
logger = fctPointer;
}
bool __stdcall init()
{
logger("WOOO");
return true; //I'm getting the AccessViolation right here
}
I'm getting a System.AccessViolationException upon returning from the init() function in atlsimpstr.h Release() function inside the mfc100.dll
Anybody know what I'm doing wrong? All the questions I've seen about this sort of thing have been how to do the reverse P/Invoke without access violation but it's working fine for me, it's just when returning from the other invocation it is messed up, as if that section of memory is now considered part of the C# application.
The problem is that the calling conventions for the callback do not match. Your native code expects the callback to be cdecl, but the managed code declares it to be stdcall. You can fix this either in the managed code or in the native code. For simplicity, I'll show how to fix it in the managed code.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void FunctionPointer(string msg);
Some other points:
Don't set the SetLastError parameter to true since your functions are not setting the Win32 last error.
Don't use unsafe anywhere in this code. As a general rule you should avoid unsafe and you just don't need it for any of this.

Registering _set_purecall_handler function using P/Invoke in C#

I'm having trouble using _set_purecall_handler with P/Invoke in C#.
Basically, this works:
(C++)
_set_purecall_handler(MyPureCallHandler);
void MyPureCallHandler(void)
{
// gets called
}
But this doesn’t:
(C#)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void PureCallHandler();
[DllImport("msvcr100.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr _set_purecall_handler([MarshalAs(UnmanagedType.FunctionPtr)] PureCallHandler handler);
_set_purecall_handler(MyPureCallHandler);
private void MyPureCallHandler()
{
// *** doesn’t get called ***
}
I’m not sure if my P/Invoke method signature is correct, but it doesn't throw any errors when I call the function (it just doesn't fire the callback on a pure virtual call error).
Background
We have a number of apps (C++, C++/CLI and C#) that use a single C# library for catching exceptions. This registers various handlers (AppDomain.CurrentDomain.UnhandledException, SetUnhandledExceptionFilter, etc) and catches most exceptions.
However, it doesn't catch pure virtual call errors and so we need to register the above function.
After trial and error, I found that referencing msvcr100d.dll (d = debug) instead of msvcr100.dll worked as I was under the debugger.
Here's my source (I don't know if this is good practice, but I've successfully tested under debug / release mode):
private const string DllName =
#if DEBUG
"msvcr100d.dll";
#else
"msvcr100.dll";
#endif
public delegate void PureCallHandler();
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
public static extern PureCallHandler _set_purecall_handler(PureCallHandler handler);

Setting dllimport programmatically in C#

I am using DllImport in my solution.
My problem is that I have two versions of the same DLL one built for 32 bit and another for 64 bit.
They both expose the same functions with identical names and identical signatures.
My problem is that I have to use two static methods which expose these and then at run time use IntPtr size to determine the correct one to invoke.
private static class Ccf_32
{
[DllImport(myDllName32)]
public static extern int func1();
}
private static class Ccf_64
{
[DllImport(myDllName64)]
public static extern int func1();
}
I have to do this because myDllName32 and myDllName64 must be constant and I have not found a way to set it at run time.
Does anyone have an elegant solution for this so I could get rid of the code duplication and the constant IntPtr size checking.
If I could set the file name, I would only have to check once and I could get rid of a ton of repeated code.
I prefer to do this by using the LoadLibrary call from kernel32.dll to force a particular DLL to load from a specific path.
If you name your 32-bit and 64-bit DLLs the same but placed them in different paths, you could then use the following code to load the correct based on the version of Windows you are running. All you need to do is call ExampleDllLoader.LoadDll() BEFORE any code referencing the ccf class is referenced:
private static class ccf
{
[DllImport("myDllName")]
public static extern int func1();
}
public static class ExampleDllLoader
{
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
private extern static IntPtr LoadLibrary(string librayName);
public static void LoadDll()
{
String path;
//IntPtr.Size will be 4 in 32-bit processes, 8 in 64-bit processes
if (IntPtr.Size == 4)
path = "c:/example32bitpath/myDllName.dll";
else
path = "c:/example64bitpath/myDllName.dll";
LoadLibrary(path);
}
}
You can probably achieve this with the #if keyword. If you define a conditional compiler symbol called win32, the following code will use the win32-block, if you remove it it will use the other block:
#if win32
private static class ccf_32
{
[DllImport(myDllName32)]
public static extern int func1();
}
#else
private static class ccf_64
{
[DllImport(myDllName64)]
public static extern int func1();
}
#endif
This probably means that you can remove the class wrapping that you have now:
private static class ccf
{
#if win32
[DllImport(myDllName32)]
public static extern int func1();
#else
[DllImport(myDllName64)]
public static extern int func1();
#endif
}
For convenience, I guess you could create build configurations for controlling the compilation symbol.
I know this is a really old question (I'm new - is it bad to answer an old question?), but I just had to solve this same problem. I had to dynamically reference a 32-bit or 64-bit DLL based on OS, while my .EXE is compiled for Any CPU.
You can use DLLImport, and you don't need to use LoadLibrary().
I did this by using SetDLLDirectory. Contrary to the name, SetDLLDirectory adds to the DLL search path, and does not replace the entire path. This allowed me to have a DLL with the same name ("TestDLL.dll" for this discussion) in Win32 and Win64 sub-directories, and called appropriately.
public partial class frmTest : Form
{
static bool Win32 = Marshal.SizeOf(typeof(IntPtr)) == 4;
private string DLLPath = Win32 ? #"\Win32" : #"\Win64";
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetDllDirectory(string lpPathName);
[DllImport("TestDLL.dll", SetLastError = true)]
static extern IntPtr CreateTestWindow();
private void btnTest_Click(object sender, EventArgs e)
{
string dllDir = String.Concat(Directory.GetCurrentDirectory(), DLLPath);
SetDllDirectory(dllDir);
IntPtr newWindow = CreateTestWindow();
}
}
Why not wrap them into a method?
private static class ccf_32_64
{
private static class ccf_32
{
[DllImport(myDllName32)]
private static extern int func1();
}
private static class ccf_64
{
[DllImport(myDllName64)]
private static extern int func1();
}
public static int func1()
{
if (32bit)
{
return ccf_32.func1();
}
else
{
return ccf_64.func1();
}
}
}
One alternative option is to have both the 32- and 64-bit versions of the unmanaged DLL have the same name, but have them live in separate folders in your build output (say, x86\ and x64\).
Then, your installer or however else you're distributing this is updated so it knows to install the proper DLL for the platform it's installing on.
you can create two methods and choose one in a runtime, so you can keep Any CPU
public static class Ccf
{
[DllImport(myDllName32)]
private static extern int func32();
[DllImport(myDllName64)]
private static extern int func64();
public static int func()
{
if(Environment.Is64BitProcess)
{
return func64();
}
return func32();
}
}
You can't do this the way you want. You need to think of the DllImport attribute as metadata that is used at compile time. As a result you can't change the DLL it is importing dynamically.
If you want to keep your managed code targeted to "Any CPU" then you either need to import both the 32-bit and 64-bit libraries wrapped as two different functions that you can call depending on the runtime environment or use some additional Win32 API calls to late-load the correct version of the unmanaged assembly at runtime and additional Win32 calls to execute the required methods. The drawback there is that you won't have compile time support for any of that type of code for type safety, etc.
Hmm, I'm wondering if you could create an interface and then a class with the methods based on the 32 bit and 64 bit dlls.
I'm not sure if there is an explicit method to determine if you are running 64 bit, but the following might work: allow unsafe code and have an unsafe function that gets a pointer to some address and then determine whether the pointer is 4 or 8 bytes in size. Based on the result determine which implementation of the interface to create.
You can determine whether you are running 64Bits or not by checking the size of the IntPtr type (which is called native int anyways).
Then you can load the approriate DLL using an imported LoadLibraryW call, get the function pointer using GetProcAddress, and then, check out Marshal.GetDelegateForFunctionPointer
This not nearly as complicated as it might look like. You have to DllImport both LoadLibraryW and GetProcAddress.

Categories