Click to See Complete Forum and Search --> : Pinning an array
TFobear
August 11th, 2010, 02:35 PM
I am having problems pinning an array to pass to a Native function as a reference.
here is the native code:
typedef HANDLE HDIB
int LoadArrayFromFilename(HDIB ahdib[], int nMax, const char* pszFile);
Now here is my managed to unmanaged bridge function:
int Toolkit::Dib::LoadArrayFromFilename(array<IntPtr>^% ahdib, int nMax, String^ pzFileName)
{
pin_ptr<IntPtr> p = &ahdib[0];
HDIB * native = (HDIB*)p->ToPointer();
return ::DIB_LoadArrayFromFilename(native, nMax, (char*)SystemStringToCSTR(pzFileName));
}
once inside the native DIB_LoadArrayFromFilename, the pointer 'native' is null, and the clr throws an AccessViolationException ("Trying to read or write protected memory").
Here is example VB code passing an array to be filled out:
Dim pages(100) As IntPtr
Toolkit.Dib.LoadArrayFromFilename(pages, 100, szFileName)
So, does anyone know what is wrong with my managed bridge function?
Alex F
August 12th, 2010, 12:20 AM
I see here two strange points, though I am not sure that this is the reason on the failure:
1) array<IntPtr>^%
% is not necessary in this case, since you don't change the reference in this function.
2) array<IntPtr> in mapped to the HANDLE array. Are you sure that IntPtr structure has the same size as HANDLE? Possibly it is, but this is dangerous. pin_ptr should be applied only to simple types like integer.
If performance is not critical, create int array (long for x64), copy every IntPtr to it in the managed code, and then call DIB_LoadArrayFromFilename with pinned int array.
mani3355
August 12th, 2010, 01:21 AM
hi,
performance is not critical, create int array (long for x64), copy every IntPtr to it in the managed code, and then call DIB_LoadArrayFromFilename with pinned int array.
regards,
phe9oxis,
http://www.guidebuddha.com
TFobear
August 12th, 2010, 08:50 AM
Thanks guys this helps but I need to investigate further. I might not have been specific enough, ahdib is an array getting passed to DIB_LoadArrayFromFilename where pages from a file are getting loaded into the array. when all is said and done the ahdib parameter needs to get returned, hence the tracking reference. Maybe you are telling me I dont need to because I am pinning it? I would have posted the definition for the native function but I am not sure I am allowed to.
When I was using P/Invoke IntPtr mapped to handle when declaring functions in the client. I can assume the clr does some implicit conversion with IntPtr when using P/Invoke. Intellisense tells me IntPtr is "a platform-specific type that is used to represent a pointer or a handle".
I can say, in the native function the access violation occurs here:
// parameter: HDIB ahdib[]
memset(ahdib, 0, count*sizeof ahdib[0]); // throws the AccessViolationException
before the above code is executed, in visual studio's debugger it shows ahdib is 0x00000000 hes the access violation
Alex F
August 12th, 2010, 08:59 AM
You don't need % because array itself is passed by reference. % means that array reference is passed by reference. For example, in C++ you can pass array as char*:
void SomeDunction(char* ptr)
{
p[0] = 0; // this change is visible to caller
}
% is like: char** ptr - not necessary in this case, unless you want to change ptr itself.
However, this is not critical. But I would not used pinned array for anything except simple types like int.
TFobear
August 12th, 2010, 09:44 AM
Despite type issues, I dont believe the memory is even getting to the native code.
in general terms, how does one convert a c++/cli array to c++ pointer to be passed to a native function.
I am sorry if you all are getting frustrated with me. There is very little documentation out there, so I appretiate this.
TFobear
August 12th, 2010, 10:24 AM
Basically, In a native C++ environment I would call the function like this:
HANDLE arrOfDibs[100];
int numPagesLoaded = DIB_LoadArrayFromFilename(arrOfDibs, 100, "foo.tif");
if (numPagesLoaded > 4)
{
DIB_RandomProcessingFunc(arrOfDibs[3]);
}
for (int i = 0; i < numPagesLoaded; i++)
{
DIB_Free(arrOfDibs[i]); // Each Dib is created with windows GlobalAlloc function, so it needs to be freed
}
I have wrapped the other DIB_*** functions all fine and dandy, but I am having a hard time wrapping DIB_LoadArrayFromFilename! I cant seem to get the array of handles assigned to an (VB.Net or C#) array of IntPtr, which is how I was representing them when using P/Invoke.
TFobear
August 12th, 2010, 11:29 AM
This might be resolved, heres what I did:
int Toolkit::Dib::LoadArrayFromFilename(array<IntPtr>^ ahdib, int nMax, System::String^ pzFileName)
{
const int size = ahdib->Length;
HDIB * arr = new HDIB[size];
int num = ::DIB_LoadArrayFromFilename( arr, nMax, (char*)SystemStringToCSTR(pzFileName));
Marshal::Copy(IntPtr(static_cast<void*>(arr)), ahdib, 0, size);
delete arr;
return num;
}
to bypass the pin_ptr issue i allocate memory on the native heap, then copy the data to my managed array. I suppose this method is a bit slower but not enough to make a difference.
If anyone sees anything wrong with the above code I appretiate the input.
otherwise, thanks everyone who replied!
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.