Click here to Skip to main content
15,065,328 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi
I have an unmanaged c++ class library dll which I'm using within a c++/cli environment.

Everything is fine until I start passing an object pointer by reference, at which point I get:
An unhandled exception of type 'System.AccessViolationException' occurred in...

... Additional information: Attempted to read or write protected memory. ...
error.


Here's a very basic example of what I'm trying to achieve:

On the c++/cli side I have this:
...

NativeWorkerObject  *nativeWorkerObj = new NativeWorkerObject();
NativeResultsObject *nativeResultsObj;

nativeWorkerObj->DoSomeWork( &nativeResultsObj ); 

// display the results...


In the native c++ dll is something like this:

bool NativeWorkerObject::DoSomeWork( NativeResultsObject **nativeResultsObj )
{
   // carry out some processing and if there are no issues create the
   // results to be returned

    *nativeResultsObj = new NativeResultsObject()

   // populate results

    return( true );
}



The error occurs at the point you try to access the *nativeResultsObj within the native dll.

This all works fine in an application that is completely native, I only get the issue in a managed environment (VS2010 .NET4)


Can anyone help with this, I assume it's something to do with pin_ptr but I have not been able to make it work


Thanks in advance
Simon
Posted
Comments
Richard MacCutchan 16-Jun-10 11:06am
   
You cannot pin a native object. In this type of application your managed code needs to pin some memory which will be accessed by the native code.
smea 16-Jun-10 14:35pm
   
Thanks for your help Richard, it got me thinking a bit differently and I have found this to try:
http://stackoverflow.com/questions/1850488/pinning-an-updateble-struct-before-passing-to-unmanaged-code

Will let you know how I get on, thanks

Again thanks Richard for making me think differently :-D

Here's the solution for anyone else:

On the c++/cli side:
...
NativeWorkerObject  *nativeWorkerObj = new NativeWorkerObject();

IntPtr managedResultsPointer = Marshal::AllocHGlobal( sizeof( NativeResultsObject * ) );

NativeResultsObject *nativeResultsPointer = ( NativeResultsObject * )managedResultsPointer.ToPointer();


nativeWorkerObj->DoSomeWork( &nativeResultsObj ); 

// display the results...

// clean up resources
Marshal::FreeHGlobal( managedResultsPointer );
delete nativeWorkerObj;



No change required on the native side.

===========================================================


The Marshal::AllocHGlobal() allocates memory from the unmanaged memory which is locked in place i.e. the garbage collector can't touch it. This gives you the safe memory for your native pointer.

The IntPtr.ToPointer() returns a good old void * allowing you to cast the pointer accordingly for your needs.

Don't forget to release any resources used after use :)
   
You cannot do this directly between managed and unmanaged code, as the memory models do not match. You will need to use pinned memory as described here[^].
   
Comments
smea 16-Jun-10 9:05am
   
Problem is GCHHandle only allows you to pin a Managed object, I need to pin a Native object i.e. * rather than ^

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900