C# P\Invoke DLL no entry point into C++? - c#

I have a C++ Dll "TheFoo.dll" with a method "Foo()"
I have access to other C++ code that uses this method by simply calling:
Foo();
I believe the Method does have the:
__declspec( dllexport )
So, with the reading I've done about P/Invoke, i thought i should be able to simply call the same method from my C# code:
namespace PInvokeExample1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
[DllImport(#"C:\MyFolder\TheFoo.dll")]
public static extern
void Foo();
private void button1_Click(object sender, RoutedEventArgs e)
{
Foo();
}
}
}
When i run it, i get an error:
Unable to find an entry point named 'Foo' in DLL 'C:\MyFolder\TheFoo.dll'.
Any ideas why it is not found?

The C++ language supports overloading, much like C# does. You could export an function void Foo(int) and a function void Foo(double). Clearly those two functions could not both be exported as "Foo", the client of the DLL wouldn't know which one to pick. So it is not.
The C++ compiler solves that problem by decorating the name of the function. Adding extra characters that makes a Foo(int) different from a Foo(double). You can see those decorated names by running Dumpbin.exe /exports foo.dll from the Visual Studio Command Prompt, that lists the name of the exported functions. Assuming your declaration was relevant, you'd see ?Foo##YAXXZ.
So the corresponding declaration in your C# program should be:
[DllImport("foo.dll", EntryPoint = "?Foo##YAXXZ",
ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern void Foo();
There are ways to change the C++ function declaration to make the C# declaration easier. Which is actually not a good idea, these decorated names actually help catch mistakes.

You should provide more information on your C++. Try using extern "C" __declspec(dllexport) instead. C++ exports with strange names so using extern "C" avoids that.

If you didn't declare it extern "C" in your dll, its name has likely been "mangled". You can use something like Dependency Walker to see what symbols your dll exports.

Related

Unmanaged code with file access fails in a .NET/C# application

Here's the scenario I am confronted with:
in a simple DLL, written in C, there are functions which access files, for example:
DLL_EXPORT void Virt_Hello(void) {
FILE *f = fopen("Hello_world", "w");
if (f) {
fprintf(f, "Hello world!\n");
}
fclose(f);
}
in the managed code:
[SuppressUnmanagedCodeSecurity]
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void Virt_HelloDelegate();
private IntPtr m_helloPtr;
m_helloPtr = GetProcAddress(m_libraryPtr, "Virt_Hello");
Virt_Hello = Virt_HelloDelegate)Marshal.GetDelegateForFunctionPointer(m_helloPtr, typeof(Virt_HelloDelegate));
and later, this function is called as:
[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
public void Hello()
{
Virt_Hello();
}
I've been reading for the last couple of days pretty much everything I could find on this topic however it still doesn't work: the file is not open, and the calling managed code/process just hangs - no exceptions are thrown either.
Tried StdCall calling convention, changed several parameters on the SecurityPermission attribute - to no avail. I've even made sure all assembly dependencies are signed.
Of course I would prefer to integrate it through C++/CLI instead of PInvoke-ing however the DLL is a blackbox for me.
Any help or suggestion how to go forward would be much appreciated.
I'm pretty sure I'm missing something obvious but right now I just can't see it.
My best regards to the community!

Run-Time Check Failure #0 only executing a function inside the called function

In my c# code I need to call a c++ function (myWrapper) that is exported by a dll that I've created.
When myWrapper returns I get the following runtime error:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
As I will show below, I already specified the calling conventions a __cdecl.
In detail, my C# code:
class myClass
{
[DllImport("MyWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void myWrapper();
public void myMethod()
{
myWrapper();
}
}
c++ code for myWrapper:
#include "IpIpoptApplication.hpp"
extern "C" __declspec(dllexport) void (__cdecl myWrapper)()
{
SmartPtr<IpoptApplication> solver = IpoptApplicationFactory();
ApplicationReturnStatus status = solver->Initialize();
}
The IpoptAppliationFactory function is imported from an external dll in IpOptApplication.hpp (which is part of an open source project and can be viewed from https://projects.coin-or.org/svn/Ipopt/stable/3.11/Ipopt/src/Interfaces/IpIpoptApplication.hpp) with this line:
extern "C" __declspec(dllexport) class Ipopt::IpoptApplication * __cdecl IpoptApplicationFactory();
The strange thing is that the error happens only when "solver->Initialize()" in myWrapper is called. If I comment the call to this method myWrapper returns without errors.
The problem is not related to the definition of "Ipopt::IpoptApplication", nor in the implementation of IpoptApplicationFactory() or Initialize() because 1) they are from a well known open source project (http://www.coin-or.org/projects/Ipopt.xml) used by thousands of programmers, 2) myWrapper works correctly if used in a standalone executable written in c++ code.
I've already googled for hours and I believe that the problem is in the way I call myWrapper but I can't find a solution.
Can anyone give me some suggestion? Thanks a lot.
Roberto
Thanks to Hans Passant the problem has been solved. I must compile "myWrapper" in release mode.
IPOPT DLLS CAN BE COMPILED ONLY IN RELEASE MODE (see readme.txt distributed with IpOpt dlls)! I've set the configuration manager to compile this project always in release mode (even when the solution is in debug).
To debug my myWrapper function (which calls IpOpt dlls), it's necessary to set in the properties of my StartUp project, the check box "Enable unmanaged code debugging"
Since unmanaged code debugging does not allow code modifications during debug, I keep diabled this if I don't need to debug myWrapper.
I hope this will help

How To hook unmanaged function inside managed function?

Here is my C++ Code:
This function is exported in my DLL.
EXPORT set_hook(fnc_public_hook hook){
public_hook = hook;
}
Now if I hook it from unmanaged code like following everything works fine.
set_hook(my_fnc);
Now before every event in my DLL my_fnc is called, so I can do some pre process on data.
The problem is that I don't know how to do this in .NET.
How to get .NET function pointer ? And how to use set_hook() to call my .NET function before every event ?
using System.Runtime.InteropServices;
Somewhere, create a delegate to your function you would like called
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate uint YourFunctionDelegate();
Set your delegate to point to your function, ie in your constructor,
YourFunctionDelegate = myDotNetFunc;
In NativeMethods class inside your namespace,
[DllImport("YourDLL.dll", EntryPoint = "set_hook", CallingConvention = CallingConvention.Cdecl)]
private static extern int setHook([MarshalAs(UnmanagedType.FunctionPtr)]YourFunctionDelegate myDelegate);
Finally, you can call your c++ function with
NativeMethods.setHook(YourFunctionDelegate);
Make sure you know which calling convention is appropriate.
EDIT: Dont get garbage collected!
http://msdn.microsoft.com/en-us/library/ms182294%28v=vs.80%29.aspx
Preventing unmanaged function pointer garbage collection

Calling C++ function in namespace from C# with DlImport, Entrypoint

I have read several questions related to mine, but none of the multiple answers worked for me.
I need to call a function from an unmanaged DLL. I have the 32 bit version of the DLL in SysWow64 and the 64 bit version in system32. Anyway, I am compiling for x86. I don't have the source for the DLL, so recompiling with extern "C" is not an option.
The relevant parts of the include file for the DLL:
(...)
#include <string>
namespace SomeNamespace
{
(...)
typedef std::wstring STRING;
(...)
class SomeClass
{
(...)
static bool SomeFunc(const STRING& p1, bool p2);
(...)
}
}
When calling SomeFunc, I am getting an exception: "Can't found the entry point named '?' in DllName.dll" (translation is mine, could be inexact).
My declaration in C#:
[System.Runtime.InteropServices.DllImport("DllName.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?SomeFunc#SomeClass#SomeNamespace##SA_NABV?$basic_string#_WU?$char_traits#_W#std##V?$allocator#_W#2##std##_N#Z")]
bool SomeFunc(string p1, bool p2);
I have also tried the following:
[System.Runtime.InteropServices.DllImport("DllName.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "#15")]
bool SomeFunc(string p1, bool p2);
15 is the function ordinal according to Depends, and the EntryPoint in the first version is also obtained from Depends.
According to undname.exe, this is the original declaration of the function:
public: static bool __cdecl SomeFunc(class ?? :: ?? ::Z::basic_string<wchar_t,str
uct std::char_traits<wchar_t>,class w::allocator<wchar_t>,td,bool> const &, ?? )
throw( ?? )
It doesn't seem to be parsing it correctly; the bool should be a parameter for FuncName, not a type parameter for basic_string. However, I'm not sure if this is just a parsing error from undname.exe or something more serious.
How can I fix it?
Update: When using the ordinal of the function as entry point, I don't get an exception. I am calling this from the Load event of a Form, and when debugging, I lost the control. I mean, I am debugging with the cursor on the SomeFunc() line, I hit F10, and the app continues as if I wasn't debugging. I don't get a ThreadException or an UnhandledException.
The calling code:
public bool CallSomeFunc()
{
try
{
SomeFunc("p1", true);
}
catch (Exception ex)
{
ex.ToString(); // I just use this to put a breakpoint while debugging.
}
return true;
}
End Update
You need C++/CLI as a wrapper to call methods from C++ classes.
PInvoke only works with global exported functions.
Take a look at C++/CLI wrapper for native C++ to use as reference in C#.
you can call mangled methods that are exposed in the dll.
see this post on instructions:
using mangled names in DllImport including namespaces

Shared memory between C++ DLL and C# code

I am currently working on a project with really short deadline, so I don't have much time to understand everything. Also, I am not an expert in C++ development and memory management.
So, what I am trying to do is to create a DLL in with both C and C++ code. Then, I would like to call this DLL in a C# code. Currently, the communication between C++ and C# is OK. The problem comes up when I try to transfer a string from the DLL to the C# code. The error is this one :
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
at NMSPRecognitionWrapper.Program.<Main>b__0() in <my dir>\Program.cs:line 54
at NMSPRecognitionWrapper.Program.StartRecognitionExt()
at NMSPRecognitionWrapper.Program.Main(String[] args) in <my dir>\Program.cs:line 60
Also, I can give you some piece of code below (really simplified !). Actually, the C++ expose two methods : StartRecognition() launch operations to get some data from microphone, then process them and store the results. GetResults() return an instance of the results previously stored. The WrapperCallback() allows the C# part to be called when a Result is able for processing. The C# part, when the Callback is called, will ask to get the results using the GetResults() method.
I know the architecture may seem really inappropriate in this presentation, but I don't want to explain the whole project to validate the model, please be sure everything is correct.
To finish, the problem is when the C# callback call the GetResults() method. Trying to access to the resultsForCS seems to be impossible from the C#.
C++ part - header
// NMSPRecognitionLib.h
#pragma once
#include <iostream>
using namespace std;
extern "C" __declspec(dllexport) char* GetResults();
extern "C" static void DoWork();
extern "C" __declspec(dllexport) void StartRecognition();
C++ part - sources
#include "stdafx.h"
#include "NMSPRecognitionLib.h"
static char * resultsForCS;
static SUCCESS ProcessResult(NMSPCONNECTION_OBJECTS *pNmspConnectionObjects, LH_OBJECT hResult)
{
[...]
char* szResult;
[...]
resultsForCS = szResult;
DoWork();
[...]
return Success;
error:
return Failure;
} /* End of ProcessResult */
extern "C" __declspec(dllexport) char* GetResults()
{
return resultsForCS;
}
extern "C"
{
typedef void (*callback_function)();
callback_function gCBF;
__declspec(dllexport) void WrapperCallback(callback_function callback) {
gCBF = callback;
}
static void DoWork() {
gCBF();
}
}
extern "C" __declspec(dllexport) void StartRecognition()
{
char* argv[] = { "path", "params" };
entryPoint(2, argv);
}
C# part
class Program
{
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetResultsExt();
public delegate void message_callback_delegate();
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "WrapperCallback")]
public static extern void WrapperCallbackExt(message_callback_delegate callback);
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "StartRecognition")]
public static extern void StartRecognitionExt();
static void Main(string[] args)
{
WrapperCallbackExt(
delegate()
{
Console.WriteLine(GetResultsExt());
}
);
StartRecognitionExt();
Console.WriteLine("\nPress any key to finish... ");
var nothing = Console.ReadLine();
}
}
I understand that the problem comes because I am using a pointer to store the results (char *), but I actually don't know how to do this in another way. The szResults type is char * too and I can't change this !
Yes, the return type is the problem. The pinvoke marshaller must do something to release the memory that was allocated for the string. The contract is that memory allocations that need to be released by the caller must be allocated from the COM heap. CoTaskMemAlloc() in native code, also exposed in .NET as Marshal.AllocCoTaskMem().
This rarely comes to a good end, most native code allocates with malloc() or ::operator new, allocating from a heap that's created by the C runtime library. The wrong heap. So inevitably the CoTaskMemFree() call will fail. Ignored silently in Windows XP and earlier, a kaboom on Vista and up.
You must stop the pinvoke marshaller from trying to release the memory. Do so by declaring the return value as IntPtr. And use Marshal.PtrToStringAnsi() to recover the string.
You still have a Big Problem, the kind of problem that bedevils any native code that tries to use this function as well. You still have a string buffer that needs to be released. You cannot do that from C#, you can't pinvoke the correct version of free() or ::operator delete. A memory leak is inevitable. The only thing you can hope for is that the native code takes care of it, somehow. If it doesn't then you must use C++/CLI to interop with it. With the additional requirement that the native code needs to be rebuilt with the same compiler so that it uses the same shared CRT. Code that's difficult to use correctly from native code is also hard to pinvoke. That's a design flaw, always allow the caller to pass a buffer to be filled in so there's never a question who owns the memory.
Looking at:
at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
I can see that your callback is called, but the runtime tries to free some memory. I think it assumes your pointer would be to com memory. Try converting the string yourself, it is easy!
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
public static extern IntPtr GetResultsExt();
[...]
string result = Marshal.PtrToStringAnsi(GetResultsExt())
No 100% guarantee, but worth a try.
I have found that it is usually easier to write a wrapper in C++/CLI around the C++ native code. A C++/CLI class can directly call and use native C++, but is accessible from C# (and any .Net language). In my experience, using DLLImport as you do leads to hard to debug and find errors.

Categories

Resources