Accessing more than one functions in C++ DLL from C# program - c#

I implemented two functions in Visual C++ DLL project. These functions will be called from C# program.
These are my functions in C++ DLL (not the actual implementation). mytest.cpp project.
extern "C"
{
__declspec(dllexport)void print_DB(null *head)
{
/*print all nodes*/
return;
}
__declspec(dllexport)void* add_node(void *head, int data)
{
/*Add node to data base*/
return (head);
}
}
My C# program is as follows.
namespace example
{
class test
{
[DllImport("mytest.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern void* add_node(void *head, int data);
unsafe public static extern void print_DB(void *head);
unsafe static void Main(string[] args)
{
/*initilialization*/
head = add_node(head, a)
head = add_node(head, b)
head = add_node(head, c)
printDB(head);
}
}
}
I am able to use on function at a time. ie, If I comment print_DB() deceleration from C# program, add_node() functionality is working. If I commented add_node() function print_DB() function is working. In this way both functions are giving the expected results.
If I am using both functions together, the function which is declared at the end is giving error as below. Invoking or not invoking the functions don't have any effect on the behavior.
Could not load type 'ConsoleApplication2.Program' from assembly
'ConsoleApplication2, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null' because the method 'printDB' has no
implementation (no RVA).
where "ConsoleApplication2.Program" is the name of my C# program.
If I change the order of the functions deceleration, will get same error for the other function.
These are my questions
1)I am new to C# programming. my expectation is this functions should work irrespective of how many functions we declared in the C# program. Is this is a expected behavior?
2)If it not the expected behavior What am I doing wrong?

The DllImport line must be present before every imported function declaration, like so:
namespace example
{
class test
{
[DllImport("mytest.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern void* add_node(void *head, int data);
[DllImport("mytest.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern void print_DB(void *head);
unsafe static void Main(string[] args)
{
/*initilialization*/
head = add_node(head, a)
head = add_node(head, b)
head = add_node(head, c)
printDB(head);
}
}
}

Related

How to get profiler attached true in c# profiling? [duplicate]

I have written a DLL in dev C++. The DLL's name is "DllMain.dll" and it contains two functions: HelloWorld and ShowMe. The header file looks like this:
DLLIMPORT void HelloWorld();
DLLIMPORT void ShowMe();
And the source file looks like this:
DLLIMPORT void HelloWorld ()
{
MessageBox (0, "Hello World from DLL!\n", "Hi",MB_ICONINFORMATION);
}
DLLIMPORT void ShowMe()
{
MessageBox (0, "How are u?", "Hi", MB_ICONINFORMATION);
}
I compile the code into a DLL and call the two functions from C#. The C# code looks like this:
[DllImport("DllMain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void HelloWorld();
[DllImport("DllMain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void ShowMe();
When I call the function "HelloWorld" it runs well and pops up a messageBox, but when I call the function ShowMe an EntryPointNotFoundException occurs. How do I avoid this exception? Do I need to add extern "C" in the header file?
The following code in VS 2012 worked fine:
#include <Windows.h>
extern "C"
{
__declspec(dllexport) void HelloWorld ()
{
MessageBox (0, L"Hello World from DLL!\n", L"Hi",MB_ICONINFORMATION);
}
__declspec(dllexport) void ShowMe()
{
MessageBox (0, L"How are u?", L"Hi", MB_ICONINFORMATION);
}
}
NOTE: If I remove the extern "C" I get exception.
using System;
using System.Runtime.InteropServices;
namespace MyNameSpace
{
public class MyClass
{
[DllImport("DllMain.dll", EntryPoint = "HelloWorld")]
public static extern void HelloWorld();
[DllImport("DllMain.dll", EntryPoint = "ShowMe")]
public static extern void ShowMe();
}
}
things that helped:
The: extern "C" { function declarations here in h file } will disable C++ name encoding. so c# will find the function
Use __stdcall for the C declaration or CallingConvention.Cdecl in the
C# declaration
maybe use BSTR/_bstr_t as string type and use other vb types. http://support.microsoft.com/kb/177218/EN-US
download "PInvoke Interop Assistant" https://clrinterop.codeplex.com/releases/view/14120
paste function declaration from .h file in the 3rd tab = c#
declaration. replace with dll filename.

call DLL developed in C/C++ by C#? [duplicate]

I have written a DLL in dev C++. The DLL's name is "DllMain.dll" and it contains two functions: HelloWorld and ShowMe. The header file looks like this:
DLLIMPORT void HelloWorld();
DLLIMPORT void ShowMe();
And the source file looks like this:
DLLIMPORT void HelloWorld ()
{
MessageBox (0, "Hello World from DLL!\n", "Hi",MB_ICONINFORMATION);
}
DLLIMPORT void ShowMe()
{
MessageBox (0, "How are u?", "Hi", MB_ICONINFORMATION);
}
I compile the code into a DLL and call the two functions from C#. The C# code looks like this:
[DllImport("DllMain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void HelloWorld();
[DllImport("DllMain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void ShowMe();
When I call the function "HelloWorld" it runs well and pops up a messageBox, but when I call the function ShowMe an EntryPointNotFoundException occurs. How do I avoid this exception? Do I need to add extern "C" in the header file?
The following code in VS 2012 worked fine:
#include <Windows.h>
extern "C"
{
__declspec(dllexport) void HelloWorld ()
{
MessageBox (0, L"Hello World from DLL!\n", L"Hi",MB_ICONINFORMATION);
}
__declspec(dllexport) void ShowMe()
{
MessageBox (0, L"How are u?", L"Hi", MB_ICONINFORMATION);
}
}
NOTE: If I remove the extern "C" I get exception.
using System;
using System.Runtime.InteropServices;
namespace MyNameSpace
{
public class MyClass
{
[DllImport("DllMain.dll", EntryPoint = "HelloWorld")]
public static extern void HelloWorld();
[DllImport("DllMain.dll", EntryPoint = "ShowMe")]
public static extern void ShowMe();
}
}
things that helped:
The: extern "C" { function declarations here in h file } will disable C++ name encoding. so c# will find the function
Use __stdcall for the C declaration or CallingConvention.Cdecl in the
C# declaration
maybe use BSTR/_bstr_t as string type and use other vb types. http://support.microsoft.com/kb/177218/EN-US
download "PInvoke Interop Assistant" https://clrinterop.codeplex.com/releases/view/14120
paste function declaration from .h file in the 3rd tab = c#
declaration. replace with dll filename.

Pass a function as parameter to an external dll C#

I'm trying to use an dll on my project which have a method that receives a function as parameter, but I don't know how to do that call using C#.
Here is the example that the dll manual provides.
do_pkd(void(*put-byte) (char));
I think it's an example writed in C and I don't know how to perform the same call on C#
Here is the way that I'm trying to do now
public static void Main(string[] args)
{
Console.WriteLine(do_pkd(put_byte));
}
[DllImport(#"C:\pkwin32.dll", CallingConvention = CallingConvention.Cdecl)]
static unsafe extern char do_pkd(Action<char> put_byte);
private static void put_byte(char s)
{
//TO-DO
Console.WriteLine(s);
}
I'm receiving the following error:
Can not perform marshalling of 'parameter # 1': Can not perform marshalling of generic types.

Register C# delegate to C++ callback, what does Marshal.GetFunctionPointerForDelegate do?

I used to register a delegate from C# to a callback function pointer like this (without using Marshal.GetFunctionPointerForDelegate):
C++ (Test.dll)
typedef void (__stdcall* Callback)(int num);
Callback pCallback = 0;
void __stdcall SetCallback(Callback callback)
{
pCallback = callback;
}
void __stdcall ActionCpp()
{
if(pCallback)
{
pCallback();
}
}
C#
class Program
{
[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void SetCallBack(Callback callback);
[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void ActionCpp();
public delegate void Callback();
static void Action()
{
Console.WriteLine("Callback succeeded.");
}
static void Main(string[] args)
{
Callback myAction = new Callback(Action);
SetCallback(myAction);
ActionCpp(); //Suppose to do the same thing as Action();
}
}
It seems that this way works fine. However, I found that we can do the same thing by using Marshal.GetFunctionPointerForDelegate and register the IntPtr of the delegate to the function pointer in C++.
I would like to know what the difference is and which practice is better? (And also Why? Thanks in advance.)
Here is the C# code when using Marshal.GetFunctionPointerForDelegate. (Nothing changes in C++ code.)
C# (With Marshal.GetFunctionPointerForDelegate)
class Program
{
[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void SetCallBack(IntPtr pCallBack); //change to type "IntPtr" this time.
[DllImport("Test.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void ActionCpp();
public delegate void Callback();
static void Action()
{
Console.WriteLine("Callback succeeded.");
}
static void Main(string[] args)
{
Callback myAction = new Callback(Action);
//GCHandle gcHandle = GCHandle.Alloc(myAction); <-- Is this necessary?
IntPtr pMyAction = Marshal.GetFunctionPointerForDelegate(myAction);
SetCallback(pMyAction);
ActionCpp();
//gcHandle.Free();
}
}
I have another further but related question about whether it is necessary to use "GCHandle.Alloc" (as in my comments in the above code) to avoid any GC action as long as my Callback myAction is still alive?
I am a newbie on C# and C++ callbacks, please let me know if I have naive mistakes made.
A callback requires the start address of the method that handles the event. So your two methods are both getting the same start address. The first method is clear since you are using the name of the method. 2nd method you have more statements that accomplishes the same as first method.
c# is managed language while c++ is un-managed. Which basically means that extra protection was added to c# to prevent PC from going blue screen. So when calling un-managed c++ from c# rules must be followed to prevent blue screen. So any pointer variables passed to a c++ method must be allocated in c# as un-managed using GCHandle.Alloc or by using other Marshal methods. Marshal.StrToPtr will also allocate the un-managed memory.

Correct way to call a C DLL method from C#

I'm trying to execute some methods (in this particular case, rdOnAllDone) from a third party DLL, written in C, and looking trough the headers files, I found this:
#ifndef TDECLSDONE
#ifdef STDCALL
#define CCON __stdcall
#else
#define CCON __cdecl
#endif
#define TDECLSDONE
#endif
#define DLLIMP __declspec (dllimport)
DLLIMP int CCON rdOnAllDone (void(CCON *)(int));
After goggling for a way to call this method, I made this:
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(Delegate d);
public delegate void rdOnAllDoneCallbackDelegate();
private static void rdOnAllDoneCallback()
{
Console.WriteLine("rdOnAllDoneCallback invoked");
}
The method was called correctly except that I couldn't get the int parameter. So I tried adding the input parameter int like this
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(Delegate d);
public delegate void rdOnAllDoneCallbackDelegate(int number);
private static void rdOnAllDoneCallback(int number)
{
Console.WriteLine("rdOnAllDoneCallback invoked " + number);
}
But now delegate is called twice and and it crashes the program with the following error " vshosts32.exe has stopped working"
What's the correct way to call this DLL method?
EDIT: Forgot to add the Main method:
public static void Main()
{
rdOnAllDoneCallbackDelegate del3 = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback);
rdOnAllDone(del3);
while (true)
{
Thread.Sleep(1000);
}
}
Three things you need to do to make this work right:
you need to tell the pinvoke marshaller about the actual delegate type, using Delegate isn't good enough. That will create the wrong thunk that won't properly marshal the argument. Which is what you saw happening.
you need to tell the marshaller about the calling convention if it isn't __stdcall with the [UnmanagedFunctionPointer] attribute. Getting this wrong imbalances the stack with good odds for a hard crash.
you need to store a reference to the delegate object so that the garbage collector won't collect it. It cannot see references held by native code. Getting this wrong makes the native code fail with a hard crash after the next garbage collection.
So this ought to work better, tweak as necessary:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void rdOnAllDoneCallbackDelegate(int parameter);
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate d);
class Foo {
private static rdOnAllDoneCallbackDelegate callback; // Keeps it referenced
public static void SetupCallback() {
callback = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback);
rdOnAllDone(callback);
}
private static void rdOnAllDoneCallback(int parameter) {
Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter);
}
}
Your delegates signature has to match that of the native callback, also it has to have the UnmanagedFunctionPointerAttribute set appropriately.
In your case like so:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public delegate void rdOnAllDoneCallbackDelegate(int parameter);
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate callback);
Usage:
{
rdOnAllDone(rdOnAllDoneCallback);
}
private static void rdOnAllDoneCallback(int parameter)
{
Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter);
}

Categories

Resources