I have never created a P/Invoke wrapper method in C# because there's a way to do it "the managed way" using .NET Framework classes.
However, I have the need to invoke Win32 API function and I discovered that it's not as easy as I thought.
The function in IsWowProcess2, and the code to call it from C++ is illustrated here.
http://www.rudyhuyn.com/blog/2017/12/13/how-to-detect-that-your-x86-application-runs-on-windows-on-arm/
I've created a silly program to test it, but of course, it doesn't work:
class Program
{
static void Main(string[] args)
{
var result = IsWowProcess2();
}
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = false, PreserveSig = true)]
private static extern MyStruct IsWowProcess2();
}
internal class MyStruct
{
public ushort One { get; set; }
public ushort Two { get; set; }
}
What's the correct way to create the wrapper method and how to invoke it?
Start by reading the documentation. This gives the signature as:
BOOL IsWow64Process2(
HANDLE hProcess,
USHORT *pProcessMachine,
USHORT *pNativeMachine
);
As a pinvoke that is:
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool IsWow64Process2(
IntPtr process,
out ushort processMachine,
out ushort nativeMachine
);
I've no idea where your attempt came from but it looks nothing like the correct declaration, and in fact even the name of the function is wrong. Interop programming is all about detail and matching one binary interface to another. You don't get to invent the interface. Details like the parameters to be passed, the name of the function, etc. all need to match.
You can call it like this:
ushort processMachine;
ushort nativeMachine;
if (!IsWow64Process2(GetCurrentProcess(), out processMachine, out nativeMachine))
throw new Win32Exception();
You also need a declaration for GetCurrentProcess. You can use this:
[DllImport("kernel32.dll")]
private static extern IntPtr GetCurrentProcess();
Related
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!
}
}
The System.Windows.Forms.dll
I wish to wrap a few functions in this file in a C# class.
Specifically these: https://msdn.microsoft.com/en-us/library/system.windows.forms.cursor(v=vs.110).aspx
But I'm not sure how to get a list of functions. I've tried programs that returned no results. I was wondering if someone could give me 1 and only 1 example?
This, for example, returns an EntryPointNotFoundException
[DllImport("System.Windows.Forms.dll")]
public static extern void SetCursor(String s);
First, you need to enable interop services in order to call into windows functions:
using System.Runtime.InteropServices;
Then, you simply declare the methods that you want to import as such:
[DllImport("winmm.dll")]
public static extern bool PlaySound(string filename,long hmodule, int dword );
This creates a "mapping" to the PlaySound method in the unmanaged winmm.dll
The method is created as static and the use of the extern keywords tells the compilar that the method is external to your class (not running inside it)
To get list / search of unmanaged functions you can use
http://www.pinvoke.net
For instance, for SetCursor you can call
http://www.pinvoke.net/search.aspx?search=SetCursor&namespace=[All]
E.g. to place cursor at a position provided SetCursorPos you can do
using System.Runtime.InteropServices;
...
// Wrapper
class CursorNativeMethods {
[DllImport("User32.dll",
EntryPoint = "SetCursorPos",
CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean SetCursorPos(Point point);
...
[DllImport("User32.dll",
EntryPoint = "GetCursorPos",
CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean GetCursorPos([Out] out Point point);
...
}
// Your Routine
public static class MyCursor {
public Point Location {
get {
Point pt = new Point(-1, -1);
if (CursorNativeMethods.GetCursorPos(out pt))
return pt;
else
return new Point(-1, -1);
}
set {
CursorNativeMethods.SetCursorPos(value);
}
}
...
}
Please note, that System.Windows.Forms.dll is managed assembly (you should not interop with), and User32.dll is unmanaged library.
I'd like to know a way how to marshal 2 Classes that I made in C++ in C# language.
(a tutorial link would be perfect, I tried to google this for myself, but my english knowledge is not that advance, to search for the right thing. I am new to marshaling from C++ to C#)
Well basically what I have is something like this:
C++
EXPORT_API CarClass* DLL_AddCar();
EXPORT_API CarWheel* DLL_AddWheel();
EXPORT_API void DLL_GiveWheelToCar(CarClass* car,CarWheel* wheel);
C#
public class Car
{
#region Members
private IntPtr nativeCarObject;
#endregion Members
public Car()
{
this.nativeCarObject = Sim.DLL_AddCar();
}
// ---> this part is not working
//#region Wrapper methods
//public void GiveWheel(Wheel myWheel){Sim.DLL_GiveWheelToCar(this.nativeCarObject,myWheel);}
//#endregion Wrapper methods
}
public class Wheel
{
#region Members
private IntPtr nativeCarObject;
#endregion Members
public Wheel()
{
this.nativeCarObject = Sim.DLL_AddWheel();
}
}
internal class Sim
{
public const string pluginName = "MyDLL";
#region PInvokes
[DllImport(pluginName)] public static extern IntPtr DLL_AddCar();
[DllImport(pluginName)] public static extern IntPtr DLL_AddWheel();
[DllImport(pluginName)] public static extern void DLL_GiveWheelToCar(IntPtr car,IntPtr wheel);
#endregion PInvokes
}
Now My question is where would I use "DLL_GiveWheelToCar" ?
The method I tryed is commented out, because it didnt work, is it a logic error or should I change the way I'm marshaling?
Thanks for advice.
public void GiveWheel(Wheel myWheel){
Sim.DLL_GiveWheelToCar(this.nativeCarObject, myWheel);
}
Here you are passing myWheel which is of type Wheel to a function that expects an IntPtr. You need to pass the private field of the Wheel class that is currently (mis)named nativeCarObject.
Other points:
As I hinted above, the nativeCarObject member of Wheel should be renamed as nativeWheelObject.
The DLL looks like it uses the cdecl calling convention. You should specify that in your p/invoke declarations.
It looks like you code leaks the objects that the DLL supplies. I suspect you need to supply some tidy up helpers.
The code might look like something this:
public class Car
{
public readonly IntPtr nativeCarObject = Sim.DLL_AddCar();
public void GiveWheel(Wheel myWheel)
{
Sim.DLL_GiveWheelToCar(this.nativeCarObject, myWheel.nativeWheelObject);
}
}
public class Wheel
{
public readonly IntPtr nativeWheelObject = Sim.DLL_AddWheel();
}
internal class Sim
{
public const string pluginName = "MyDLL";
[DllImport(pluginName, CallingConvention=CallingConvention.Cdecl)]
public static extern IntPtr DLL_AddCar();
[DllImport(pluginName, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr DLL_AddWheel();
[DllImport(pluginName, CallingConvention = CallingConvention.Cdecl)]
public static extern void DLL_GiveWheelToCar(IntPtr car, IntPtr wheel);
}
This code is still leaking those objects. I'll let you sort that out.
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.
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.