have been working on this for hours, couldn't get it work :(
below code gives exception "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." this is fixed, see below update
but when i change the return type to int and return a int value, it works. how to make it to return a float value? thanks.
vs2012
c++ code
extern "C" __declspec(dllexport)
float compute_similarity()
{
return 1.01;
}
c# code
[DllImport("demo.exe", EntryPoint = "compute_similarity", CallingConvention = CallingConvention.Cdecl)]
public static extern float compute_similarity();
public void Get()
{
float x = compute_similarity(); // here returns random value
}
=====================================
UPDATE
See comments from David below, the problem was the c# project is targeting x64 and c++ is targeting Win32. After changing the c# project to target to x86, the exception went away.
However the call from c# returns some random value instead of 1.01 expected
I think your problem is that your function is declared in an executable rather than a DLL. Convert your native code into a library project and compile a DLL.
Your code will result in a call to LoadLibrary passing the file name demo.exe. The documentation for LoadLibrary says:
LoadLibrary can also be used to load other executable modules. For example, the function can specify an .exe file to get a handle that can be used in FindResource or LoadResource. However, do not use LoadLibrary to run an .exe file. Instead, use the CreateProcess function.
And so your code is doing exactly what you are told not to do. The call to LoadLibrary will succeed. The subsequent calls to GetProcAddress will succeed. But the module that you loaded is not fit to execute code.
Related
Recently I have been trying to get some Point Cloud Library functionality going in my .NET framework application, and considering that there is no completely functional wrapper for PCL for C#, I made my own for a few functions as a test. Something like this:
[DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl)]
public extern static IntPtr StatisticalOutlierFilter(IntPtr data, int length, int meanK = 50, float mulThresh = 1.0f);
Which calls a function from a C++ library, such as this:
EXPORT VectorXYZ* StatisticalOutlierFilter(VectorXYZ* data, int length, int meanK, float mulThresh) {
auto processedCloud = process.StatisticalOutlierFilter(data, length, meanK, mulThresh);
auto processedVector = convert.ToVectorXYZ(processedCloud);
return processedVector;
}
Where EXPORT is defined such for gcc:
#define EXPORT extern "C" __attribute__ ((visibility ("default")))
And relevant processing function from PCL is implemented such in a class (note that the returned is a boost shared pointer):
PointCloud<PointXYZ>::Ptr Processors::StatisticalOutlierFilter(VectorXYZ* data, int length, int meanK, float mulThresh) {
auto cloud = PrepareCloud(data, length);
PointCloud<PointXYZ>::Ptr cloud_filtered(new PointCloud<PointXYZ>);
StatisticalOutlierRemoval<PointXYZ> sor;
sor.setInputCloud(cloud);
sor.setMeanK(meanK);
sor.setStddevMulThresh(mulThresh);
sor.filter(*cloud_filtered);
return cloud_filtered;
}
This procedure works well with a dll built w/MSVC and running the whole thing on Windows, though the final target is gcc/Linux/Mono, where I get several errors of the following type (this is from mono debug):
'libavpcl_dll.so': '/usr/lib/libavpcl_dll.so: undefined symbol: _ZN3pcl7PCLBaseINS_8PointXYZEE13setInputCloudERKN5boost10shared_ptrIKNS_10PointCloudIS1_EEEE'.
I have investigated quite a bit so far, and have set my CmakeLists.txt to set(CMAKE_CXX_VISIBILITY_PRESET hidden) , therefore, I imagine, only functions I defined as EXPORT should be visible and imported - however, that is not the case, and I get the aforementioned errors. PCL was installed on Windows via vcpkg and on Xubuntu via apt. I am somewhat stumped as to what is the error source, considering the code runs well on windows, and builds without issue on Linux. Thanks.
I've been running into the same issue as you. I solved it by adding each reference library into the CMakeLists.txt file (I was missing the reference files which gave me the similar missing symbol issues).
I'm at the 'I don't know why this worked' stage but I can give you step by step implementation (I'm also trying to use DllImport into .NET on Linux).
Started with this:
https://medium.com/#xaviergeerinck/how-to-bind-c-code-with-dotnet-core-157a121c0aa6
Then added my in-scope files thanks to the main comment here: How to create a shared library with cmake?:
add_library(mylib SHARED
sources/animation.cpp
sources/buffers.cpp
[...]
)
run cmake .
run make -j$(grep -c ^processor /proc/cpuinfo)
copy path to .so file
DllImport path from above to my c# app
I have made a plugin system that uses reflection to call functions in a plugin. A plugin has to implement the IPlugin interface to be used.
In the application which uses the plugins the plugin instance is created with the following code:
Assembly currentAssembly = Assembly.LoadFrom(startInfo.PluginAssemblyPath);
Type[] types = currentAssembly.GetTypes();
IPlugin pluginInstance = null;
foreach (Type type in types)
{
if (type.FullName == startInfo.PluginTypeName)
{
pluginInstance = (IPlugin)Activator.CreateInstance(type);
}
}
if (pluginInstance == null)
{
throw new Exception("Plugin loader error: Could not instantiate plugin: " + startInfo.ToString()); }
return pluginInstance;
I have made a plugin that uses some unmannaged dll's. When I call the IPlugin interface functions in a test project in the plugin solution everything works fine. But when I call the plugin via the plugin instance made in the code shown above I get the System.AccessViolationException: Attempted to read or write protected memory error when calling functions in the unmannaged dll's.
The unmannaged dll's are c++ dll's made by a third party. I tried enabling native code debugging but i do not have the .pdb files.
I am not sure why this is happening, is this because of the reflection? Or can there be other causes?
Edit:
In the stack I can see the unmannaged function being called:
[MarshalAs(UnmanagedType.LPStr)]
private readonly StringBuilder sb = new StringBuilder(256);
[DllImport("x.dll", EntryPoint = "xLib")]
static extern int _xLib(int a1, int a2, int a3, int a4, int a5, int a6, [Out]StringBuilder str);
The exception is thrown when calling the _xLib function.
Edit: Somewhere in this _xLib function the following function is called:
handle = x_Open();
which is in an other dll and is defined as:
DllExport x_Handle *x_Open();
As soon as anything in the handle is used like:
"%s", handle->x.string
The exception is thrown.
I still do not understand why this is working in the test project and not when I am using it in the app as a plugin.
Maybe you have to pin the StringBuilder to allow unmanaged code to interact with it.
Pinned object is one that is not allowed to move. The garbage collector is normally compacting the memory in that it moves all objects to "one or more clusters". This is to create large chunks of free space.
This basically means if someone else (outside) has a pointer to the memory address of an object, this may point to random content - as the object has moved.
Pinning an object tells the GC to NOT MOVE IT. This is normally useless and ONLY makes sense when working with pointers - like when using PInvoke... and I can see a pointer to a StringBuilder instance in _xlib function
Well after some intensive debugging I found the problem was the handle having some wrong address which caused the violation. The cause of the address being wrong was the x_open function loaded yet another dll with the LoadLibraryA function. This dll was not in the same directory as the executable file so it was not found.
I solved it by adding the directory of this last dll to the environment path.
I am trying to call a function from a DLL generated in LabVIEW. I thought this was going to be far more straightforward than it is turning out to be. The function is described below:
void __cdecl Device_Init(char DevName[]);
So in my C# code I am trying the following:
[DllImport(#"Device.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void Device_Init(StringBuilder name);
I call this in my application by simply using the following:
StringBuilder devName = new StringBuilder(DeviceName);
Device_Init(devName);
Rather than getting any initialization on my device, I see a LabVIEW vi window pop up that has a title akin to a different method within the dll (i.e. AF1_GetPressure.vi). The application then hangs with this LabVIEW window popped up and I have to exit the debugging session.
I guess my question is how my function signature might be erroneous... I used StringBuilder as I found an example on the NI website that seemed to indicate that LabVIEW requires this variable type to better ascertain the number of characters in the array. http://www.ni.com/example/31050/en/
I have tried all kinds of different combinations of parameter types but I simply can't seem to get this to work. If I try calling the dll from C++ then I can get things to work. Although, oddly, I had to dynamically load the dll in C++ because I was getting a dll initialization failure when I tried to load it with the application.
Any help would be greatly appreciated!
I was able to build a DLL with LabView 2012, and import it into a .NET 4.0 console application, call the function, and receive a result. Here is a screenshot of the VI:
And here is the import statement in C#:
[DllImport(#"SharedLib.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int StringLength(string str);
I would recommend trying something very simple like this and see if you can get it working.
I should note that I tried passing my parameter as a StringBuilder object and that worked as well - and I didn't expect it to!
Also, I recommend posting this question on the LabView forums. I was always able to get a very quick response there, and I think with LabView, you're likely to get a better response there than StackOverflow.
As requested, here are the contents of the .h file generated by LabView:
#include "extcode.h"
#pragma pack(push)
#pragma pack(1)
#ifdef __cplusplus
extern "C" {
#endif
/*!
* StringLength
*/
int32_t __cdecl StringLength(char String[]);
long __cdecl LVDLLStatus(char *errStr, int errStrLen, void *module);
#ifdef __cplusplus
} // extern "C"
#endif
#pragma pack(pop)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
A call to PInvoke function '[…]' has unbalanced the stack
I'm trying to wrap a few functions written in c++, in order to use them in a c# program (WPF, or as an example a console app), but get run-time exceptions.
I guess this is a compilation issue (of either the c++ project of the C# one). When I change the platform target for the C# projects, I get different exceptions. when the platform target is x64 I get
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
When I try to compile it as x86, I get:
A call to PInvoke function 'Wrapper!Wrapper.IWrapper::create' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
I'm running VS2010 on windows 7 64.
Would be happy for any ideas on how to solve this.
This is what I do:
c++ code. cpp:
int create(int Handle)
{
return 1;
}
and h:
#define EXPORT_DLL __declspec(dllexport)
extern "C"
{
EXPORT_DLL int create(int Handle);
}
Then in a second C# project, I call this dll, where the c++ project's name is wrapAttemptC
namespace Wrapper
{
internal class IWrapper
{
const string SHADOW_DLL_NAME = "wrapAttemptC.dll";
[DllImport(SHADOW_DLL_NAME)]
public static extern int create(int Handle);
}
public class CWW
{
public CWW(){}
public int Connect(int cam)
{
return IWrapper.create(cam);
}
}
}
Then, I put the DLL file created in the c++ project in the bin/Debug of this c# project and of the app c# project (WPF), and try to call
CWW cww = new CWW();
cww.Connect(5);
The default calling convention for C++ exported functions is cdecl, but the default calling convention for the DllImport attribute is WinApi (which defaults to stdcall). So you have a mismatch there that could indeed mess up your stack. Try stating the calling convention explicitly in the DllImport Attribute, your C++ function declaration, or better, both (so that they match). Like this:
EXPORT_DLL __stdcall int create(int Handle);
And in your C# project:
[DllImport(SHADOW_DLL_NAME, CallingConvention = CallingConvention.StdCall)]
dll written in Delphi, according to the manual I have to first set the xml path by SET_XML(), then use any function you like.
Delphi functions according the manual:
function SET_XML(var path: PAnsiChar): LongInt;
function GET_CALCULATION_FAN_ALONE(var fanDescription: PAnsiChar): LongInt;
Use in VB according to the manual:
Public Declare Function SET_XML_PATH Lib "fan.dll" (ByRef path As String) As Long
Public Declare Function GET_CALCULATION_FAN_ALONE Lib "fan.dll" (ByRef path As String) As Long
Sub Main()
Dim a As Long, b As Long, Str_Result As String, Str_Input As String
Str_Input = "C:\Users\Sebastiaan\Documents\Visual Studio 2010\Projects\Lucam selectie\Lucam selectie\bin"
a = SET_XML_PATH(Str_Input)
Str_Result = "65464;;;1,2;;23;424,8;0,3766;;"
b = GET_CALCULATION_FAN_ALONE(Str_Result)
End Sub
I did rewrite it in C#
const string _dllLocation = "EbmPapstFan.dll";
[DllImport(_dllLocation)]
public static extern long SET_XML_PATH(ref String path);
[DllImport(_dllLocation)]
public static extern long GET_CALCULATION_FAN_ALONE(ref String fanDescription);
public Main()
{
String path = #"C:\Users\Sebastiaan\Documents\Visual Studio 2010\Projects\Lucam selectie\Lucam selectie\bin";
long a = SET_XML_PATH(ref path);
String fanDescription = "65464;;;1,2;;23;424,8;0,3766;;";
long c = GET_CALCULATION_FAN_ALONE(ref fanDescription);
}
When running de application I get an AccessViolationException
Attempt to read or write protected memory. This often indicates that other memory is corrupt.
When setting a breakpoint and debugging the code step by step nothing every thing rusn just fine. sometimes i got the error in the debug mode (on line "long c = GET_CALU...")
What am I doing wrong?
I'm not familiar with calling Delphi from C#, but from a quick search it appears that there are some issues with the calling conventions (how values are pushed and popped from the stack). See these threads:
Calling a Delphi DLL from C# produces unexpected results
Calling a delphi DLL method from C# Code
From these, it sounds like it may not be possible to call this directly due to the "fastcall" calling convention. You could try changing the calling convention, that could be worth a quick test. See this page:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx
If that doesn't work, I would probably just write a C wrapper DLL that calls the Delphi DLL, and verify that works (make sure it's not just a bug in the DLL). If it does, then you could just call the C DLL from the C# program by using DllImport on your wrapper DLL's function.
Hope that helps a bit,
John