C# Error Finding Method in DLLImport - c#

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

Related

C# Marshaling a C++ DLL with C interface. Problem passing Objects

I'm trying to Marshal this C++ test DLL with C interface which works when calling from Python using CFFI:
#define AS_TYPE(Type, Obj) reinterpret_cast<Type *>(Obj)
#define AS_CTYPE(Type, Obj) reinterpret_cast<const Type *>(Obj)
struct mytype_s;
typedef struct mytype_s mytype_t;
namespace TestDLL {
class Test {
public:
Test() { return; }
~Test() { return; }
int test_function() const { return 314159; }
};
}
mytype_t *test_new() {
return AS_TYPE(mytype_t, new TestDLL::Test());
}
int test_function(const mytype_t *mytype) {
return AS_CTYPE(TestDLL::Test, mytype)->test_function();
}
From C# I tried using an IntPtr for mytype_t which had worked for me with structures in the past. The C# code:
[DllImport(dllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr test_new();
[DllImport(dllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int test_function(IntPtr mytype);
IntPtr mytype;
mytype = test_new();
Console.WriteLine("Alloc complete");
int result;
result = test_function(mytype);
Console.WriteLine("test: {0}", result);
But I get the error:
Alloc complete
Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'test_function' in DLL
Is this related to how I marshalled the mytype_t or a more complex issue with passing the object from C++ to C#?
Thanks

Calling C++ DLL from C++ and C#

I have a C++ application that I have to convert to a DLL. I have all the source.
my function is
extern "C"
__declspec(dllexport) int mymain(int i, std::wstring myArgs)
I need to be able to pass in the arguments from a c++ or c# wrapper. I am able to call this from a c++ console application without error. I am now trying to call it from C#.
This is my c# code:
public static class DllHelper
{
[DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mymain(int iArgs, string aArgs);
}
class Program
{
static void Main(string[] args)
{
string s = "my string data";
DllHelper.mymain(0, s);
}
}
}
When I run it I get
System.Runtime.InteropServices.SEHException: 'External component has thrown an exception.'
I am out of ideas.
TIA
Specify Unicode but also, in your C or C++ function, use printf with "%S" (upper-case 'S' means wide-character string).. OR std::wcout.
Without that, it might print weird or terminate at the first null char it finds. Also, you might want to actually pass the length of the string, but that's entirely up to you.
Note the signature of the C++ function uses LPCWSTR (const wchar_t*) for the myArgs parameter..
public static class DllHelper
{
[DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern int mymain(int iArgs, string aArgs);
}
class Program
{
static void Main(string[] args)
{
string s = "my string data";
DllHelper.mymain(0, s);
}
}
#ifdef __cplusplus
extern "C" {
#endif
int __declspec(dllexport) mymain(int i, const wchar_t* myArgs)
{
#ifdef __cplusplus
std::wcout<<std::wstring(myArgs)<<L"\n";
#else
printf(L"%S\n", myArgs);
#endif
}
#ifdef __cplusplus
}
#endif
Based on yr last comment u might need to:
[DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
anyway since I dont have rep.dll it's hard to guess
The naming used in your code:
mymain(int iArgs, string aArgs);
makes me think that what you are trying to do is probably passing an array of strings (similar to wmain(int argc, wchar_t** argv)).
If this is what you want, then on the native DLL side your function prototype would look like this:
extern "C" int __declspec(dllexport) mymain(int iArgs, wchar_t** aArgs)
And on the C# side, you would write a PInvoke declaration like this:
[DllImport("rep.dll",
CallingConvention=CallingConvention.Cdecl,
CharSet=CharSet.Unicode)]
public static extern int mymain(int iArgs, [In] string[] aArgs);
that you can invoke in C# like this:
string[] test = { "C64", "Bravo", "Charlie" };
int returnCode = mymain(test.Length, test);

PInvoke with a void * versus a struct with an IntPtr

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.

Data values in the parameters are beeing copied to the other parameters c++, c#

In c++ the method that I am exporting is:
__declspec(dllexport) int __thiscall A::check(char *x,char *y,char *z)
{
temp=new B(x,y,z);
}
In c# I am importing this method like this:
[DllImport("IDLL.dll", CallingConvention=CallingConvention.ThisCall, ExactSpelling = true, EntryPoint = "check")]
public static extern int check(string x, string y, string z);
I am calling this method in c# like this and passing the values:
public int temp()
{
string x="sdf";
string y="dfggh";
string z="vbnfg";
int t;
t=Class1.check(x,y,z);
return t;
}
The problem is that when I debug in to the native code I see that the parameters x,y,z having values sdf,dfggh,vbnfg and being altered when they reach c++ dll like this even before it is entering the native c++ dll method.
x=dfggh,y=vbnfg,z=null value
and is giving me the error saying that null pointer value is passed to the function. Can any one help me out fixing this weird problem.
Looks like your native method is an instance(vs static) method. I guess your first parameter gets mapped to 'this' somehow.
Here is an example:
#include <fstream>
using namespace std;
class A
{
public:
__declspec(dllexport) static int __stdcall check(char *x,char *y,char *z)
{
ofstream f;
f.open("c:\\temp\\test.txt");
f<<x<<endl;
f<<y<<endl;
f<<z<<endl;
return 0;
}
__declspec(dllexport) int __thiscall checkInst(char *x,char *y,char *z)
{
ofstream f;
f.open("c:\\temp\\testInst.txt");
f<<x<<endl;
f<<y<<endl;
f<<z<<endl;
return 0;
}
};
see the static keyword on the first one?
Imports(i used the mangled names because I'm lazy):
[DllImport("TestDLL.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "?check#A##SGHPAD00#Z")]
public static extern int check(string x, string y, string z);
[DllImport("TestDLL.dll", CallingConvention = CallingConvention.ThisCall, ExactSpelling = true, EntryPoint = "?checkInst#A##QAEHPAD00#Z")]
public static extern int checkInst(IntPtr theObject, string x, string y, string z);
That makes it work just like that:
check("x", "yy", "zzz");
the instance method requires an IntPtr
IntPtr obj = IntPtr.Zero;
checkInst(obj, "1", "12", "123");
and the contents of my test.txt are:
x
yy
zzz
and testInst.txt
1
12
123

Pass string from C# to C DLL

I am trying to pass a string from C# to a C DLL. From what I have read .NET should do the conversion from string to char* for me, however I get "error CS1503: Argument '1': cannot convert from 'string' to 'char*'" Can someone advise me of where I have went wrong? Thanks.
C# code
[DllImport("Source.dll", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static unsafe extern bool StreamReceiveInitialise(char* filepath);
const string test = "test";
// This method that will be called when the thread is started
public void Stream()
{
if (StreamReceiveInitialise(test))
{
}
}
C DLL
extern "C"
{
__declspec(dllexport) bool __cdecl StreamReceiveInitialise(char* filepath);
}
Declare your external method as:
public static extern bool StreamReceiveInitialise(string filepath);
Use a StringBuilder in place of char*. See this
[DllImport("Source.dll")]
public static extern bool StreamReceiveInitialise(StringBuilder filepath);
Do it like this:
[DllImport("Source.dll", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.ANSI)]
static extern bool StreamReceiveInitialise([MarshalAs(UnmanagedType.LPStr)] string filepath);
(Marshalling as UnmanagedType.LPStr is the default, but I like being explicit).

Categories