I have written an C++/Cli wrapper for a native C++ dll, but when I call some method from C# I get an System.AccessViolationException error in my C++/Cli Wrapper dll! It's necessary to marshal the unmanaged types or something else?!
// Wrapper.h
typedef UnmanagedClass* (*Instance)(void);
private:
UnmanagedClass *m_object; // unmanaged object
// Wrapper.cpp
Wrapper:Wrapper()
{
HINSTANCE unmanagedLib;
unmangedLib = LoadLibrary(SystemStringToLPCSTR(dllPath+dllName));
// load instance
Instance _createInstance = (Instance)GetProcAddress(unmangedLib, "GetInstance");
m_object = (_createInstance)();
}
Wrapper::~Wrapper()
{
m_object->~UnmanagedClass();
}
Uint32 Wrapper::SomeMethod(Uint8 *bytRecvBuffer, int &iRecvLen)
{
return m_object->SomeMethod(bytRecvBuffer, iRecvLen);
}
// Unmanaged Class
class UnmanagedClass
{
public:
/**
* Default constructor.
*/
UnmanagedClass(void);
/**
* Default Destructor
*/
~UnmanagedClass(void);
virtual Uint32 Wrapper::SomeMethod(Uint8 *bytRecvBuffer, int &iRecvLen);
};
// export the UnmanagedClass object
extern "C" _declspec(dllexport) UnmanagedClass* GetInstance();
// UnamangedClass.cpp
UnamangedClass::~UnamangedClass(void)
{
if (UnamangedClassDLL != NULL)
FreeLibrary(UnamangedClassDLL);
UnamangedClassDLL = NULL;
}
extern "C" _declspec(dllexport) UnmanagedClass* GetInstance()
{
return new UnmanagedClass();
}
When I call at example SomeMethod from C# I get the error in C++/Cli dll!
(I included the C++/cli dll with add reference in C sharp project and create the Wrapper object)
Thank you for your help!
greets
It is inappropriate to directly call the destructor of an object that was allocated with (non-placement) new. Try changing
m_object->~UnmanagedClass();
to
delete m_object;
m_object = 0;
(m_object = 0; is necessary because unlike a native C++ type's destructor, which may only be called once, an managed type's Dispose implementation may be called repeatedly, and doing so must have defined behavior.)
Or, better yet, in addition to exposing a GetInstance function, also expose a DestroyInstance function and call that instead of using delete so that consuming code does not need to depend on the implementation details of GetInstance (i.e., that it allocates its instance using operator new).
I have found the error (System.AccessViolationException):
I'm using an other object in the unmanaged code without initialization (null object -> only declared)!
Init the object with new() and all should run properly!
Related
I have a c++ dll from a third party, I can't modify.
I've made a c++ wrapper to call the functions inside that c++ dll.
That wrapper is called from a C# class with IJW.
It works well with natives types, but I ran into a struct array problem.
This is the c++ wrapper class :
int Helper::GetCameras(cameraStruct * cameraArray, size_t * size)
{
return originalC++Dll_getCameraList(cameraArray, size);
}
And the C# call :
var ret = m_Helper.GetCameras(pointer, size);
Do I need to redefine the "cameraStruct" in c# like this ?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class aivusdk_cameraInfo
{
public int blabla;
}
To use it like with a pointer in the C# function, or is it another way of doing it (mashalling), or am I completly wrong ?
Forgive my bad english and thanks for your response.
The primary reason to use IJW is to avoid all the hassle of trying to define parallel structures in your C# code using StructLayout and calling all that stuff in the Marshal class. If you are going to go to that trouble, you may as well do everything using P/Invoke.
One approach would be to define, in your C# assembly, an interface that will be implemented by the c++/clr assembly and a managed class containing properties corresponding to the interesting fields of the cameraStruct structure.
public interface IHelper
{
public void GetCameras(IList<Camera> cameras);
public Picture TakePicture(Camera camera);
public void LoseCamera(Camera camera);
}
public class Camera
{
public string Name { get; set; }
public int BlaBla { get; set; }
}
The Helper class in your c++/clr assembly would implement the IHelper interface. The implementation of the GetCameras method would call originalDLL_getCameraList with a locally allocated array of cameraStruct. It would then iterate over the returned cameras and gcnew a Camera object for each one. It would copy the information from the cameraStruct to the Camera object and then add the Camera object to the cameras list. The locally allocated cameraStruct array can then be freed.
One issue is that the c++/clr project must have a build dependency (reference) to the C# project. The C# project cannot have a reference to the c++/clr project. For your C# code to get a Helper object, you could dynamically load the c++/clr assembly from the C# assembly and use reflection to create a Helper object that you cast to an IHelper.
You can turn that relationship around, but that means defining more in c++/clr and less in C#. (For example, you would need to define the Camera class in the c++/clr assembly.) I prefer to define things using C# when practical.
You need to allocate unmanaged memory for the array that you can pass to the API.
This is how I would do that:
// the input here is a managed C# array
public IntPtr AllocateNativeArray(CameraInfo[] myArray)
{
if (myArray == null || myArray.Count == 0)
return IntPtr.Zero;
// building native structures
var nativeArray = new Aivusdk_CameraInfo[myArray.Length];
for (int i = 0; i < myArray.Length; i++)
{
// TODO: fill properties
}
// allocating unmanaged memory and marshaling elements
int elementSize = Marshal.SizeOf(typeof(Aivusdk_CameraInfo));
IntPtr result = Marshal.AllocHGlobal(nativeArray.Length * elementSize);
for (int i = 0; i < nativeArray.Length; i++)
{
Marshal.StructureToPtr(nativeArray[i], new IntPtr((long)result + i * elementSize), false);
}
return result;
}
After calling the C++ API you might need to free the array (unless the C++ part does that):
private static void FreeNativeArray(IntPtr address, uint length)
{
if (address== IntPtr.Zero)
return;
int elementSize = Marshal.SizeOf(typeof(Aivusdk_CameraInfo));
for (int i = 0; i < count; i++)
{
Marshal.DestroyStructure(new IntPtr((long)address + i * elementSize), typeof(Aivusdk_CameraInfo));
}
Marshal.FreeHGlobal(address);
}
I am trying to re-create some C++ sample API usage code in C#.
It's looking like I might need to create a C++/CLI wrapper to make the API functions accessible to the managed world, but I'd like to avoid that if possible. The API library itself only has a single exported function: data_api_func_tab.
This is what the C++ API usage looks like:
//
// .h file
//
typedef struct _DATA_API_FUNC_TAB {
short (*api_init)();
// ... lots of other methods ...
} DATA_API_FUNC_TAB
extern "C" typedef short (* MAPIINIT)(short);
// ... lots of other methods ...
#undef EXTERN
#ifdef _MAIN
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN MAPIINIT ncm_api_init;
// ... lots of other methods ...
public:
UCHAR SomeVariable;
void SomeMethod( arguments );
//
// .cpp file
//
/// Constructor
CWidgetDataApi::CWidgetDataApi()
{
SomeVariable = 0;
m_hInstHdl = ::LoadLibrary(_T(".\\NATIVEAPI.dll"));
if( NULL != m_hInstHdl )
{
DATA_API_FUNC_TAB* p_data_api_func_tab =
(DATA_API_FUNC_TAB*) ::GetProcAddress(m_hInstHdl, "data_api_func_tab");
SomeVariable = 1;
if( p_data_api_func_tab == NULL )
{
::FreeLibrary(m_hInstHdl);
m_hInstHdl = NULL;
SomeVariable = 0;
}
else
{
api_init = (MAPINIT) p_data_api_func_tab->api_init;
// ... lots of other methods ...
short Ret = api_init(index);
}
}
}
/// Method
void CWidgetDataApi::SomeMethod( arguments )
{
// ... Makes use of the various other methods ...
}
//
// Usage in another class
//
DataAPI = new CWidgetDataApi;
if( DataAPI->SomeVariable == 1 )
{
DataAPI->SomeMethod( arguments );
...
}
Since I can't use reflection on the native library (not to mention it would be slow), PInvoke seems to be the only way in.
I have recreated the appropriate structures in C# and tried the following PInvoke signatures,
[DllImport("NATIVEAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern struct data_api_func_tab { };
[DllImport("NATIVEAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern short api_init([In, Out] ref _DATA_API_FUNC_TAB data_api_func_tab);
but they produce the exception
Unable to find an entry point named '... whatever I try...' in NATIVEAPI.dll
I've searched around for a way to do this but only seem to find unmanaged to C++/CLI solutions. Is what I am attempting to do even possible (given that the individual methods contained in the structure are not exported)?
This is a pretty far out API. Instead of exporting functions, the library exports the address of a struct containing function pointers. Notice how the C++ code call GetProcAddress and then interprets the result as a pointer to a struct and not as is more common, as a pointer to a function.
From the documentation of GetProcAddress, with my emphasis:
Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).
You cannot use DllImport to access this library's export because DllImport is for functions rather than variables.
Here's what you must do:
Use LoadLibrary to load the DLL and obtain a module handle as an IntPtr.
Call GetProcAddress to obtain the address of the struct.
Use Marshal.PtrToStructure to get a managed struct containing the function pointers.
Use Marshal.GetDelegateForFunctionPointer for each member of the struct to obtain a delegate which you can then call.
When you are done with the library unload it by calling FreeLibrary. You can omit this step if you are happy to wait until the process terminates and the system unloads automatically.
Assuming you can obtain p/invoke signatures for LoadLibrary and friends, the code looks like this:
// declare the structure of function pointers
struct DATA_API_FUNC_TAB
{
IntPtr api_init;
// more function pointers here
}
....
// load the DLL, and obtain the structure of function pointers
IntPtr lib = LoadLibrary(#"full\path\to\dll");
if (lib == IntPtr.Zero)
throw new Win32Exception();
IntPtr funcTabPtr = GetProcAddress(lib, "data_api_func_tab");
if (funcTabPtr == IntPtr.Zero)
throw new Win32Exception();
DATA_API_FUNC_TAB funcTab = (DATA_API_FUNC_TAB)Marshal.PtrToStructure(funcTabPtr, typeof(DATA_API_FUNC_TAB));
....
// declare the delegate types, note the calling convention
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate short api_init_delegate();
....
// obtain a delegate instance
api_init_delegate api_init = (api_init_delegate)Marshal.GetDelegateForFunctionPointer(funcTab.api_init, typeof(api_init_delegate));
....
// finally we can call the function
short retval = api_init();
It's plausible that the marshaller is capable of creating the delegate for you. In which case the struct would be:
struct DATA_API_FUNC_TAB
{
api_init_delegate api_init;
// more delegates here
}
In which case the Marshal.GetDelegateForFunctionPointer step would obviously not be necessary, the marshaller having already performed it on your behalf.
I've not tested any of this code, just typed it into the browser. No doubt there are a few wrinkles, but this code is intended more as a guide than as code that you could use directly.
I have an dll written in C (no access to the source code) which I wish to call from C#. If the dll used simple types I would know how to handle it via PInvoke, but it doesn't :(
The function in the dll I'm trying to call takes no parameters so the problem is how to handle the return. I have some example C code which calls the function which I liked to recreate in C#. As I understand it the return type is a pointer to a function pointer, is this correct? The return from the function should also later be passed back to other functions in the dll.
Any help is greatly appreciated :)
/* C code */
typedef const struct simModel* (*ModelFunc)(void);
int ret=0;
HINSTANCE hInst = 0;
ModelFunc f=0;
const struct simModel*model =0;
if (!(hInst=LoadLibrary("model.dll"))) {
return 1;
}
if (!(f=(ModelFunc)GetProcAddress(hInst,"simModelFunctions"))) {
ret=1;
} else if (!(model=f())) {
ret=1;
} else {
/* Do stuff */
}
The simModelFunctions function returns a pointer to simModel structure (a data type).
The code you show calls the function by finding its address dynamically, which is why it has a function pointer. This pointer does not come from the function itself.
In C# you can simply declare it with DllImport from model.dll. E.g.
[DllImport("model.dll", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
private static IntPtr simModelFunctions();
Then you can use Marshal.PtrToStructure if you need to examine the contents of the structure, or just pass the returned IntPtr to other functions without bothering what's inside.
I am trying to create a C++/CLI wrapper for passing class objects from unmanaged C++ DLL into managed C# code (which subsequently displays the content of the objects on web pages). I have this function in the unmanaged C++ code:
ProbeState _cdecl ManagerAPI::getProbeState()
{
ProbeState ps = psdao.getLastProbeStateByProbeId(1);
return ps;
}
I call the function in the C++/CLI wrapper:
using namespace System;
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "../ManagerApp/ProbeState.h"
typedef ProbeState(*PSFunc)(void);
public ref class ManagerAPIWrapper
{
private:
HINSTANCE managerApp;
public:
ManagerAPIWrapper()
{
managerApp = LoadLibrary(L"ManagerApp.dll");
}
System::String^ testFunc()
{
PSFunc psFunc = (PSFunc)GetProcAddress(managerApp, "?getProbeState#ManagerAPI##QAA?AVProbeState##XZ");
ProbeState *ps = new ProbeState(psFunc());
System::String ^s = gcnew System::String(ps->getName().c_str());
delete ps;
return s;
}
};
And finally I call the wrapper from my C# controller:
ManagerAPIWrapper.ManagerAPIWrapper wrapper = new ManagerAPIWrapper.ManagerAPIWrapper();
ViewBag.DllMessage = wrapper.testFunc();
It always throws an exception on the line ProbeState *ps = new ProbeState(psFunc());
Strange thing, though, is when I compile the C++/CLI wrapper as a console application with added main function:
int _tmain(int argc, _TCHAR* argv[])
{
ManagerAPIWrapper::ManagerAPIWrapper wrapper;
System::Console::WriteLine(wrapper.testFunc());
getchar();
return 0;
}
This code works just fine and prints out the name of the state retrieved from the database by the C++ DLL. How come the C++/CLI works in console app and throws an exception when called from C#?
P.S.: The wrapper is compiled with /clr option. When I compiled the wrapper with /clr:pure, the exception was the same as with the C# call. Does it mean that when the wrapper is compiled within and called from C# app, it takes the pure option?
The wrapper is meant to convert the data between C++ and C#, so according to my opinion it should not be compiled with more strict options in the C# app. Is there any way to tell the C# compiler that this assembly contains mixed code?
OK, I finally got through this. After many hours spent with try&fail way of finding a solution, I tried to call a function from the unmanaged DLL directly from the C# code first, and then called a constructor of the wrapper, which succeeded in the LoadLibrary call. Code in the C# controller now looks like this:
[DllImport("C:\\ManagerApp.dll", CharSet = CharSet.Unicode,
EntryPoint = "?initFunc#ManagerAPI##QAEHXZ")]
private static extern int initFunc();
public ActionResult APITest()
{
ViewBag.Message = "API output test page.";
if (initFunc() == 0)
{
ViewBag.Error = "Could not initialize the library.";
return View();
}
ManagerAPIWrapper.ManagerAPIWrapper wrapper = new ManagerAPIWrapper.ManagerAPIWrapper();
ViewBag.DllMessage = wrapper.testFunc();
return View();
}
I am thinking it might help to add a dependency to the wrapper DLL on the unmanaged DLL and therefore get rid of the necessity of calling the initFunc.
On the Windows Platform there's the possibility to create a COM wrapper around a managed object that might be used from unmanaged code.
Since I'm just dealing with a problem where I would like to pass a managed System.IO.Stream reference from managed code to a legacy C library function (its not even Objective-C), I'm curious if there's any chance at all to get this to work?
No, you can't pass a managed reference like this to C code in iOS.
But you can do reverse P/Invoke calls: you give native code a delegate, and you can call that delegate from C as a function pointer.
Here is some (untested) sample code that should get you on the right track:
delegate long GetLengthCallback (IntPtr handle);
// Xamarin.iOS needs to the MonoPInvokeCallback attribute
// so that the AOT compiler can emit a method
// that can be called directly from native code.
[MonoPInvokeCallback (typeof (GetLengthCallback)]
static long GetLengthFromStream (IntPtr handle)
{
var stream = (Stream) GCHandle.FromIntPtr (handle).Target;
return stream.Length;
}
static List<object> delegates = new List<object> ();
static void SetCallbacks (Stream stream)
{
NativeMethods.SetStreamObject (new GCHandle (stream).ToIntPtr ());
var delGetLength = new GetLengthCallback (GetLengthFromStream);
// This is required so that the GC doesn't free the delegate
delegates.Add (delGetLength);
NativeMethods.SetStreamGetLengthCallback (delGetLength);
// ...
}