I have simple C++ dll function:
__declspec(dllexport) int tst1(int a);
int tst1(int a)
{
return a + 1;
}
I have C# application that calls it:
[DllImport("Project1.dll")]
public static extern int tst1(int i);
static void Main(string[] args)
{
Console.WriteLine( tst1(1) );
Console.ReadLine();
}
}
Got EntryPointNotFoundException error:
What I do wrong?
The name is getting mangled by C++ decoration. Add extern "C" to prevent the mangling of the name:
extern "C" __declspec(dllexport) int tst1(int a);
Related
I have created a Qt/C++ .dll for use in a C#/WPF project.
The Qt section code is as below:
cpluspart_global.h:
#ifndef CPLUSPART_GLOBAL_H
#define CPLUSPART_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(CPLUSPART_LIBRARY)
# define CPLUSPARTSHARED_EXPORT Q_DECL_EXPORT
#else
# define CPLUSPARTSHARED_EXPORT Q_DECL_IMPORT
#endif
extern "C" __declspec(dllexport) void ShowSampleUI();
extern "C" __declspec(dllexport) int Sum(int a, int b);
#endif // CPLUSPART_GLOBAL_H
cpluspart.cpp:
#include "cpluspart.h"
CPlusPart::CPlusPart()
{
}
extern "C" void ShowSampleUI()
{
BenQ *sampleUI = new BenQ();
sampleUI->show();
}
extern "C" int Sum(int a, int b)
{
return a + b;
}
BenQ is an empty QDialog that is just used for tests.
Here is the implementation in C#:
[DllImport("CPlusPart.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void ShowSampleUI();
[DllImport("CPlusPart.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Sum(int a, int b);
The "Sum" method works properly. However, when I want to call "ShowSampleUI", I receive the following error:
Unhandled exception at 0x00007FFCD125286E (ucrtbase.dll) in CPlusInWPF.exe: Fatal program exit requested.
I would appreciate it if you could kindly help me with this issue.
My C++ DLL name is MyDLL.dll, which is communicating with TestDLL.dll
Now, I want to call functions from MyDLL.dll in my C# project
Visualization
----------- communicates ------------- communicates ---------------
- C# Code - --------------> - MyDLL.dll - --------------> - TestDLL.dll -
----------- ------------- ---------------
MyDLL.dll is written in C++
TestDLL.dll is written in C
Here is the Code
MyDLL.h
#define MyDLL_API __declspec(dllexport)
extern "C" {
MyDLL_API int sum(int a, int b);
MyDLL_API int do();
}
MyDLL.cpp
#include "MyDLL.h"
#include <Windows.h>
extern "C" {
typedef int (CALLBACK* MYFUNC1)(int, int);
typedef short* (CALLBACK* MYFUNC2)(const char*);
int MyDLL_API sum(int a, int b) // This function works fine
{
return a + b;
}
int MyDLL_API do()
{
int t = -1;
HINSTANCE test_dll;
MYFUNC1 myFunc1;
MYFUNC2 myFunc1;
test_dll = LoadLibraryA("c:\\TestDLL.dll");
if (!test_dll) {
t=0;
}
myFunc1 = (MYFUNC1)GetProcAddress(test_dll, "TestFunc");
if (!myFunc1) {
t=1;
}
myFunc2 = (MYFUNC2)GetProcAddress(test_dll, "AuthFunc");
if (!myFunc2) {
t=2;
}
// If I put 'return t' here, it works fine!
(*myFunc2)("Hello World"); // <-- This line causing the error
return t;
}
}
C# Main Program
class Program
{
public class MyClass
{
[DllImport(#"c:\MyDLL.dll", EntryPoint = "sum")]
public static extern int Sum(int a, int b);
[DllImport(#"c:\MyDLL.dll", EntryPoint = "do")]
public static extern int Do();
}
static void Main(string[] args)
{
int summation = MyClass.Sum(30, 20); // This runs fine.
Console.WriteLine("Sum is: " + summation);
int resultCode = MyClass.Do(); // This causing the ERROR.
Console.WriteLine("Result code is: " + resultCode);
Console.ReadLine();
}
}
Exception Hint
System.AccessViolationException: 'Attempted to read or write protected
memory. This is often an indication that other memory is corrupt.'
I'm trying to pass a C# method to Rust to be used as a callback.
I've managed to pass a static function and it works fine (see below).
Now I'd like to call an instance method, which means that the trigger function below should also receive an opaque (libc::c_void) this pointer.
How can I get the IntPtr which Rust should pass as the instance pointer to the callback function?
C#
class Program
{
delegate void PrintFn(int x);
public static void Main(string[] args)
{
PrintFn fn = Print;
var ptr = Marshal.GetFunctionPointerForDelegate(fn);
IntPtr handle = IntPtr.Zero;
create(ptr, out handle);
trigger(handle, 3);
}
public static void Print(int x)
{
Console.WriteLine($"C#: {x}");
}
[DllImport(#"/path/to/rust/dll")]
public static extern int create(IntPtr readFn, out IntPtr callback);
[DllImport(#"/path/to/rust/dll")]
public static extern int trigger(IntPtr handle, int x);
}
Rust:
use std::boxed::Box;
pub struct RustCallback {
callback: extern "stdcall" fn(i32),
}
impl RustCallback {
fn new(callback: extern "stdcall" fn(i32)) -> RustCallback {
RustCallback {
callback: read_fn,
}
}
}
pub fn set_output_arg<T>(out: *mut T, value: T) {
unsafe { *out.as_mut().unwrap() = value };
}
#[no_mangle]
pub extern "C" fn create(callback: extern "stdcall" fn(i32), sc: *mut *mut RustCallback) -> u32 {
set_output_arg(sc, Box::into_raw(Box::new(RustCallback::new(callback))));
0
}
#[no_mangle]
pub extern "C" fn trigger(sc: *mut RustCallback, x: i32) -> u32 {
let sc = unsafe { sc.as_mut().unwrap() };
let f = sc.read_fn;
f(x);
0
}
I was dealing with the same code. I found a simpler way than the one you expose, look:
fn operation(number: i32, f: &dyn Fn(i32) -> i32) {
f(number);
}
#[no_mangle]
fn print(number: i32) {
println!("Rust: {}", number);
}
#[no_mangle]
pub extern "C" fn c_print(number: i32, callback: unsafe extern "C" fn(i32) -> i32) {
operation(number, &|n| unsafe { callback(n) });
}
Then, in C#:
delegate void PrintFn(int number);
public static void Run()
{
int number = 1234;
// passing a C# function as parameter of Rust function
c_print(number, Print);
// passing a Rust function as callback inside the same Rust function
print(number);
}
static void Print(int number)
{
Console.WriteLine($"C#: {number}\n");
}
[DllImport(RLIB)] static extern void c_print(int number, PrintFn fn);
[DllImport(RLIB)] static extern void print(int number);
When I started to deal with this, look for: «How to use from C# a Rust function that has another function as a parameter?»
I have this code in a c++ file, with compiles to a dll.
#include "stdafx.h"
#include "WHUU.h"
#include "stdafx.h"
typedef int (__stdcall * Callback)(const int text);
static int x , y= 0;
Callback Handler = 0;
int getX()
{
return x;
}
void setX(int i)
{
x = i;
}
void setY(int i)
{
y = i;
}
int getY()
{
return y;
}
extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
Handler = handler;
}
extern "C" __declspec(dllexport)
void __stdcall addX(int x) {
setX(x);
}
extern "C" __declspec(dllexport)
void __stdcall addY(int y) {
setY(y);
}
extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
int z = getX() + getY();
int retval = Handler(z);
}
My c# application now has to load this dll on runtime. Add to the callback and call the functions. I dont want to use a class. I could load the class and with
Type[] types = moduleAssembly.GetTypes();
But this overkill! Also c++ is not managed.
I mean its so tiny! (and yes this is an example , but the "real" is just as big as this example).
How do i do that?
Thanks you for your help!
add:
i dont like frameworks (like pinvoke / assembly)
the function names / types are fixed and will never change (think of a driver.dll read write)
this dll is written by customers so it should be as easy as possible!
You could also do it over p/invoke, as example:
[DllImport("unmanaged.dll", CharSet = CharSet.Ansi)]
private extern static int yourFunction(int var1, int var2);
i dont like frameworks (like pinvoke / assembly)
I'll suggest P/Invoke anyway. I don't think there are any reasonable alternatives. Perhaps writing a managed wrapper in managed C++, but really?
When you use P/Invoke the .NET runtime will dynamically load the DLL's that you have specified (and this is done when you first call the function). There is no reason to use P/Invoke to call LoadLibrary first.
You can either use P/Invoke to call the dll directly, or you can create a C++/CLI wrapper for it.
Here's how you can do it using P/Invoke:
Add the compiled dll to your C# project, set its 'Copy to Output Directory' property to 'Copy Always'. and call it like this:
class Program
{
[DllImport("cppdll.dll")]
private static extern void addX(int x);
[DllImport("cppdll.dll")]
private static extern void addY(int y);
static void Main(string[] args)
{
addX(5);
addY(7);
}
}
One way to do this would be through API. Find below an example for the setX and getX method from your sample above.
[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern IntPtr LoadLibraryEx(string libraryPath, IntPtr fileHandle, int actionFlag);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern bool FreeLibrary(IntPtr libraryHandle);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern IntPtr GetProcAddress(IntPtr dllPointer, string functionName);
IntPtr ptr = IntPtr.Zero;
private delegate void setX (int i);
private delegate int getX();
private setX setXDel;
private getX getXDel;
public Constructor()
{
loadLib();
}
public void YourMethod()
{
setXDel(100);
int y = getXDel();
Console.WriteLine(y.ToString());
}
private void loadLib()
{
string path = "your dll path";
ptr = LoadLibraryEx(path, IntPtr.Zero, 0);
if (ptr == IntPtr.Zero)
throw new Exception("Cannot load dll.");
IntPtr addressPtr = GetProcAddress(ptr, "setX");
setXDel = (setX)Marshal.GetDelegateForFunctionPointer(addressPtr, typeof(setX));
addressPtr = GetProcAddress(unrarPtr, "getX");
getXDel = (getX)Marshal.GetDelegateForFunctionPointer(addressPtr, typeof(getX));
}
public void Dispose()
{
if (ptr != IntPtr.Zero)
{
FreeLibrary(ptr);
}
}
I used P/Invoke, post my own cause the callback was not included by the others. But they were good answers! The C# Applicationhas use this GUI.
The Code for the Application is this : (mind it is a prototype to answer a technical question)
public partial class Form1 : Form
{
private delegate int Callback(int text);
private Callback mInstance; // Ensure it doesn't get garbage collected
[DllImport(#"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]
private static extern void SetCallback(Callback fn);
[DllImport(#"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]
private static extern void addX(int x);
[DllImport(#"C:\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]
private static extern void addY(int y);
[DllImport(#"C:\\Visual Studio 2010\Projects\kalkulatorius\Debug\WHUU1.dll")]
private static extern void TestCallback();
private int Handler(int text)
{
textBox3.Text = text.ToString();
return 42;
}
private void button1_Click(object sender, System.EventArgs e)
{
mInstance = new Callback(Handler); // to set the callback in lib
SetCallback(mInstance); // could also be withhin constructor!
addX(int.Parse(textBox1.Text)); // other people in this thread posted this correct answer
addY(int.Parse(textBox2.Text));
TestCallback();
}
public Form1()
{
InitializeComponent();
}
So if you want to use a c++ lib with functions and callbacks (like in the question posted) you can use this.
But how to change the lib?
The Path to the lib is hardcoded (see [dllImport ......] ). But you
can swop the lib in filesystem. This can happen AFTER you build this
application.
If the lib is not on the given path an exception is thrown. So if
your program wants to use this lib first check the lib is present on the filesystem.
(not included in this simple prototype)
So to switch functionality (swop a driver lib ect) you copy a different lib with the
same name into the given path. (Copy paste - maybe change name)
This solution has the least overhead and is good if you never change the interface of an dll after the application was build!
I'm trying to learn how to use DLL's in C#. I have a very simple DLL just to test the basics.
// MainForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace DLL_Test
{
public partial class Form1 : Form
{
[DllImport("TestDLL.dll",
EntryPoint="?Add##YGHHH#Z",
ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int Add(int a, int b);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int num;
try
{
num = Add(2, 3);
richTextBox1.AppendText(num.ToString() + "\n");
}
catch (DllNotFoundException ex)
{
MessageBox.Show(ex.ToString());
}
catch (EntryPointNotFoundException ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
And the DLL code:
// TestDLL.cpp
__declspec(dllexport) int __stdcall Add(int a, int b) {
return(a + b);
}
dumpbin returns the following:
ordinal hint RVA name
1 0 00011005 ?Add##YGHHH#Z = #ILT+0(?Add##YGHHH#Z)
This (and other attempts listed below) have all returned the same exception:
System.EntryPointException: Unable to find entry point named "..."
So I am at a loss for how to solve this. Perhaps I do not understand how DllMain functions as the C# entry point for a DLL. TestDLL.dll works when I test it in a C++ application.
After searching for help, I've attempted the following changes:
// TestDLL.cpp
extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) {
return(a + b);
}
Which results in this from dumpbin
ordinal hint RVA name
1 0 00011005 _Add#8 = #ILT+135(_Add#8)
Thus, I changed my C# code:
// MainForm.cs
...
[DllImport("TestDLL.dll",
EntryPoint="_Add",
ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int Add(int a, int b);
...
I've also tried __cdecl:
// TestDLL.cpp
extern "C" __declspec(dllexport) int __cdecl Add(int a, int b) {
return(a + b);
}
.
// MainForm.cs
...
[DllImport("TestDLL.dll",
EntryPoint="_Add",
ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int a, int b);
...
Perhaps I'm misunderstanding the calling conventions. Any help would be very appreciated. Thank you.
use
extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) { ... }
and
[DllImport("TestDLL.dll", CallingConvention = CallingConvention.Stdcall)]
public static extern int Add(int a, int b);
extern "C" will prevent name mangling with params and return type such as ?Add##YGHHH#Z.
__stdcall will prepend an _ and add #8 : _Add#8 (where 8 is the total size of arguments). Note that it also affects the way parameters are pushed on the stack.
In your DLLImport statement, since you specify CallingConvention.StdCall, you don't need to specify the name mangling. Just give the regular name (Add) and .NET will take care of name mangling (_Add#8).
Note that you must specify the CallingConvention or .NET wouldn't emit the correct code to push arguments on the stack
The following should work.
Unmanged:
extern "C" __declspec(dllexport) int Add(int a, int b)
{
return(a + b);
}
Managed:
class Program
{
[DllImport("TestDLL.dll")]
public static extern int Add(int a, int b);
static void Main()
{
Console.WriteLine(Add(1, 2));
}
}
For future reference: I had a similar problem, solved creating an EMPTY C++ dll project. Probably the standard Visual Studio template causes some trouble.
Refer to this link: http://www.codeproject.com/Articles/9826/How-to-create-a-DLL-library-in-C-and-then-use-it-w