Here is a sample of my C# code. Is there a way to decrease the amount of DllImport attributes?
namespace CSLib
{
class Program
{
static void Main(string[] args)
{
CLib.test();
CLib.test2(3);
A a = new A() { a = 9, b = 5 };
CLib.test3(ref a);
}
}
class CLib
{
[DllImport("path/to/CDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern void test();
[DllImport("path/to/CDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern void test2(int a);
[DllImport("path/to/CDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern void test3(ref A a);
}
[StructLayout(LayoutKind.Sequential)]
struct A
{
[MarshalAs(UnmanagedType.I4)]
public int a, b;
}
}
Either expose the methods as COM methods, or create a C++/CLI wrapper around them.
Related
I am getting error as "'Cannot marshal 'parameter #1': Non-blittable generic types cannot be marshaled.'"
in C code I have
#include <stdio.h>
#include "pch.h"
typedef void(*RECV_CALLBACK)();
RECV_CALLBACK pfRecvCallBack;
typedef void(*RECV_CALLBACKINT_PARA)(int);
RECV_CALLBACKINT_PARA pfRecvCallBackIntPara;
extern "C"
{
__declspec(dllexport) void MethodWith_INT_Para(RECV_CALLBACKINT_PARA pfIntPara)
{
if (pfIntPara)
{
pfRecvCallBackIntPara = pfIntPara;
}
}
__declspec(dllexport) void MethodWithNo_Int_Para(RECV_CALLBACK pfRecv)
{
if (pfRecv)
{
pfRecvCallBack = pfRecv;
}
}
__declspec(dllexport) void Calling_INT_PARA(int a, int b)
{
pfRecvCallBackIntPara(a + b);
}
__declspec(dllexport) void Calling_without_Para(int a, int b)
{
pfRecvCallBack();
}
}
When i try to call this in C# call back without int parameter is working fine, but the callback with int parameter(line ->MethodWith_INT_Para(testWithIntPara);) is giving error as mention above.
C# code
using System.Runtime.InteropServices;
[DllImport("Sample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "MethodWithNo_Int_Para")]
static extern void MethodWithNo_Int_Para(Action ptr);
[DllImport("Sample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "MethodWith_INT_Para")]
static extern void MethodWith_INT_Para(Action<Int32> ptr);
[DllImport("Sample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "Calling_INT_PARA")]
static extern void Calling_INT_PARA(int x, int y);
[DllImport("Sample.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "Calling_without_Para")]
static extern void Calling_without_Para();
Console.WriteLine("After calling Declare");
MethodWithNo_Int_Para(testWithoutIntPara);
Calling_without_Para();
void testWithoutIntPara()
{
Console.WriteLine("Without int para : called by Calling_without_Para");
}
MethodWith_INT_Para(testWithIntPara);
Calling_INT_PARA(1, 3);
void testWithIntPara(int x)
{
Console.WriteLine("With Int Para {x} : called by Calling_INT_PARA");
}
Console.ReadLine();
I am using Action to define callback function, please let me know if there is any other way to do this ?
Action<int> is generic, which cannot be marshalled. You need to create a custom delegate. Another problem is that C is expecting a function with the CDecl calling convention, bu the default is StdCall.
You need to use the following types, instead of Action and Action<int>
[UnmanagedFunctionPointer(CallingConvention.CDecl)]
public delegate void ActionCDecl();
[UnmanagedFunctionPointer(CallingConvention.CDecl)]
public delegate void ActionIntCDecl(int p1);
dll C++
extern "C"
{
__declspec(dllexport) int mainfun()
{
return x;
}
}
In C#
[DllImport("example.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mainfun();
I only know how to return and call one variable from C++ to C#. I am writing a program where i need to call two different varables in C# from c++ dll
(like return x,y;). Please i need help.
EDIT1:
In C++
struct Point
{
int count_err;
int statement;
} obj;
extern "C"
{
__declspec(dllexport) Point mainfun()
{
return obj;
}
}
In C#
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public int errsize;
public int statmnt;
}
[DllImport("example.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Point mainfun();
errsize = mainfun();
statmnt = mainfun();
Here errsize is giving an error-"the name 'errsize' does not exist in the current context".. What to do?
EDIT2:
In C#
total_errors.Text = p.errsize.ToString();
giving same error-"the name 'p' does not exist in the current." context"
Define new struct or array of data. Something like this:
C++:
struct Point
{
int count_err;
int statement;
} obj;
extern "C"
{
__declspec(dllexport) Point mainfun()
{
return obj;
}
}
C#:
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public int errsize;
public int statmnt;
}
[DllImport("example.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Point mainfun();
Point p = mainfun();
var errsize = p.errsize;
var statmnt = p.statmnt;
First understand that if you want to return more than one value from any function, then you will need an object which can hold multiple values like struct, class object, list etc. But in your case you cannot use LIST or KeyValuePairList of C# because you have direct dependency with C++ code.
So use structure which is same in both the platforms. Now first you need to create a suitable data structure and change the return type of mainfun() when you are calling it as follows..
public struct abc {
public int a;
public int b;
}
[DllImport("example.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern abc mainfun();
Now in your C++ library, add the data structure and change the function definition.
typedef struct {
int a;
int b;
} abc;
extern "C"
{
__declspec(dllexport) abc mainfun()
{
abc obj;
obj.x = 1;
obj.y = 2;
return obj;
}
}
Imagine I have a function called
Myfunction(const void * x);
My C# declaration could be
MyFunction(IntPtr x);
Is this functionally and technically equivalent to
struct MyStruct { IntPtr P; }
MyFunction(MyStruct x);
Or will there be a difference in how they are marshalled.
I'm asking this because the library I'm calling is all void *, typedef'd to other names, and in C# I'd like to get type safety, for what it's worth.
If your StructLayout is Sequential, then it is indeed identical.
Easiest way to verify this for yourself is to try it out, of course:
Make a C++ Win32 DLL project:
extern "C"
{
__declspec(dllexport) void MyFunction(const void* ptr)
{
// put a breakpoint and inspect
}
}
Make a C# project:
public struct Foo
{
public IntPtr x;
}
[DllImport(#"Win32Project1.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunctionWithIntPtr(IntPtr x);
[DllImport(#"Win32Project1.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunctionWithStruct(Foo x);
static void Main(string[] args)
{
IntPtr j = new IntPtr(10);
var s = new Foo();
s.x = new IntPtr(10);
MyFunctionWithIntPtr(j);
MyFunctionWithStruct(s);
}
In your debug settings, make sure you select Native debugging is enabled.
You'll see both values to be 0xA.
Note, however, if you use out/ref parameters for your IntPtr vs Struct, they will be different values.
I have some simple C-code which uses a single global-variable. Obviously this is not thread-safe, so when I call it from multiple threads in C# using P/invoke, things screw up.
How can I either import this function separately for each thread, or make it thread-safe?
I tried declaring the variable __declspec(thread), but that caused the program to crash. I also tried making a C++/CLI class, but it doesn't allow member-functions to be __declspec(naked), which I need (I'm using inline-assembly). I'm not very experienced writing multi-threaded C++ code, so there might be something I'm missing.
Here is some example code:
C#
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SomeFunction(int parameter1, int parameter2);
C++
extern "C"
{
int someGlobalVariable;
int __declspec(naked) _someFunction(int parameter1, int parameter2)
{
__asm
{
//someGlobalVariable read/written here
}
}
int __declspec(dllexport) SomeFunction(int parameter1, int parameter2)
{
return _someFunction(parameter1, parameter2);
}
}
[Edit]: The result of SomeFunction() must go in some prescribed order based on someGlobalVariable (think of eg. a PRNG, with someGlobalVariable as the internal state). So, using a mutex or other sort of lock is not an option - each thread must have its own copy of someGlobalVariable.
A common pattern is to have
a function that allocates memory for the state,
a function that has no side-effects but mutating the passed-in state, and
a function that releases the memoy for the state.
The C# side would look like this:
Usage:
var state = new ThreadLocal<SomeSafeHandle>(NativeMethods.CreateSomeState);
Parallel.For(0, 100, i =>
{
var result = NativeMethods.SomeFunction(state.Value, i, 42);
Console.WriteLine(result);
});
Declarations:
internal static class NativeMethods
{
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern SomeSafeHandle CreateSomeState();
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SomeFunction(SomeSafeHandle handle,
int parameter1,
int parameter2);
[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int FreeSomeState(IntPtr handle);
}
SafeHandle magic:
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal class SomeSafeHandle : SafeHandle
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public SomeSafeHandle()
: base(IntPtr.Zero, true)
{
}
public override bool IsInvalid
{
get { return this.handle == IntPtr.Zero; }
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.FreeSomeState(this.handle) == 0;
}
}
You can either make sure what you only call _someFunction once at a time in your C# code or change the C code to wrap the access to the global variable in a synchronization primitive like a critical section.
I would recommend changing the C# code rather than the C code, as the C# code is multi-threaded, not the C code.
Personally if the C code was to be called elsewhere I would use a mutex there. If that doesn't float your boat you can lock in .Net quite easily:
static object SomeFunctionLock = new Object();
public static int SomeFunction(int parameter1, int parameter2){
lock ( SomeFunctionLock ){
return _SomeFunction( parameter1, parameter2 );
}
}
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int _SomeFunction(int parameter1, int parameter2);
[Edit..]
As pointed out, this serializes access to the function which you can't do yourself in this case. You have some C/C++ code that (wrongly IMO) uses a global for state during the call to the exposed function.
As you have observed that the __declspec(thread) trick doesn't work here then I would try to pass your state/context back and forth as an opaque pointer like so:-
extern "C"
{
int _SomeOtherFunction( void* pctx, int p1, int p2 )
{
return stuff;
}
// publically exposed library function
int __declspec(dllexport) SomeFunction(int parameter1, int parameter2)
{
StateContext ctx;
return _SomeOtherFunction( &ctx, parameter1, parameter2 );
}
// another publically exposed library function that takes state
int __declspec(dllexport) SomeFunctionWithState(StateContext * ctx, int parameter1, int parameter2)
{
return _SomeOtherFunction( ctx, parameter1, parameter2 );
}
// if you wanted to create/preserve/use the state directly
StateContext * __declspec(dllexport) GetState(void) {
ctx = (StateContext*) calloc( 1 , sizeof(StateContext) );
return ctx;
}
// tidy up
void __declspec(dllexport) FreeState(StateContext * ctx) {
free (ctx);
}
}
And the corresponding C# wrapper as before:
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SomeFunction(int parameter1, int parameter2);
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SomeFunctionWithState(IntPtr ctx, int parameter1, int parameter2);
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr GetState();
[DllImport("MyDll", CallingConvention = CallingConvention.Cdecl)]
internal static extern void FreeState(IntPtr);
The good news, you can create a __declspec(naked) function as a member of C++ (non-CLI) class:
class A {
int n;
public:
A() { n = 0; }
void f(int n1, int n2);
};
__declspec(naked) void A::f(int n1, int n2)
{
n++;
}
The bad news, you will need COM to be able to use such class. That's right: asm wrapped in C++, wrapped in COM, wrapped in RCW, wrapped in CLR...
I have a C++ assembly that I am importing using DLLImport.
I am attempting to call its method:
namespace Testing
{
class Test{
int Run(char* filePath, bool bEntry, double duration){//code}
};
}
by
[DllImport(dllName, CharSet = CharSet.Auto)]
public static extern int Run(string filePath, bool bEntry, double duration)
);
When I call its method, I get the error message:
Unable to find an entry point named Run in dll
The "Run" looks to be a non-static class method. Although, it's possible to call such methods from C# this is not the primary use-case. It would be way easier to consume it from .NET if you expose it via COM, or at-least as a plain C interface:
extern "C" __declspec(dllexport) void* Testing_Test_Create();
extern "C" __declspec(dllexport) void Testing_Test_Destroy(void* self);
extern "C" __declspec(dllexport) int Testing_Test_Run(void* self, char* filePath, bool bEntry, double duration);
And here is a sample how to call C++ class methods from C#:
// Test.cpp in NativeLib.dll
namespace Testing
{
class __declspec(dllexport) Test
{
public:
explicit Test(int data)
: data(data)
{
}
int Run(char const * path)
{
return this->data + strlen(path);
}
private:
int data;
};
}
// Program.cs in CSharpClient.exe
class Program
{
[DllImport(
"NativeLib.dll",
EntryPoint = "??0Test#Testing##QAE#H#Z",
CallingConvention = CallingConvention.ThisCall,
CharSet = CharSet.Ansi)]
public static extern void TestingTestCtor(IntPtr self, int data);
[DllImport(
"NativeLib.dll",
EntryPoint = "?Run#Test#Testing##QAEHPBD#Z",
CallingConvention = CallingConvention.ThisCall,
CharSet = CharSet.Ansi)]
public static extern int TestingTestRun(IntPtr self, string path);
static void Main(string[] args)
{
var test = Marshal.AllocCoTaskMem(4);
TestingTestCtor(test, 10);
var result = TestingTestRun(test, "path");
Console.WriteLine(result);
Marshal.FreeCoTaskMem(test);
}
}
Entry point names might be different for your build configuration/compiler, so use dumpbin utility to obtain them. Again, this is just a proof of concept, in real code it would be better to use COM.
See here: http://dotnetperls.com/dllimport
I'm not sure this will help if the function is a member of a class, but to locate the entry point by name, not ordinal, you'll need a .def file in your dll..
LIBRARY mylib
Run #1