I have the following managed C++ function (VC++ 2005 (C++/CLI)
System::Array^ ManagedCppClass::GetData()
{
BYTE* pData;
int len;
m_pureNativeCPPObj->GetData(pData, len); // Get the data buffer from
unmanaged class.
array<byte>^ Arr = gcnew array<byte>(len);
System::Runtime::InteropServices::Marshal::Copy((IntPtr)pAScan, Arr, 0,
len);
return Arr;
}
I think this function works.
But is there a better way to that (maybe without doing the copy) ?
-------
Thanks
Sharon
Mattias Sjögren - 24 Jun 2007 19:47 GMT
>But is there a better way to that (maybe without doing the copy) ?
No you need to make a copy if you want return a managed array.
But if you know that you'll return a byte array, why not make the
return type array<byte> instead of System::Array?
Mattias

Signature
Mattias Sjögren [C# MVP] mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.
Sharon - 24 Jun 2007 20:36 GMT
>"Mattias Sjögren" wrote:
> But if you know that you'll return a byte array, why not make the
> return type array<byte> instead of System::Array?
Will it change the code of the function, and how, if the function will
return array<byte> instead of System::Array ?

Signature
Thanks
Sharon
Ben Voigt [C++ MVP] - 25 Jun 2007 06:42 GMT
>I have the following managed C++ function (VC++ 2005 (C++/CLI)
>
[quoted text clipped - 4 lines]
> m_pureNativeCPPObj->GetData(pData, len); // Get the data buffer from
> unmanaged class.
What is the prototype for GetData? That looks like you should supply the
buffer, but pData wasn't initialized.
> array<byte>^ Arr = gcnew array<byte>(len);
> System::Runtime::InteropServices::Marshal::Copy((IntPtr)pAScan, Arr, 0,
[quoted text clipped - 8 lines]
> Thanks
> Sharon
Sharon - 25 Jun 2007 08:11 GMT
> What is the prototype for GetData? That looks like you should supply the
> buffer, but pData wasn't initialized.
The prototype is:
GetData(OUT BYTE*& pData, OUT int& nLength);
It allocates the buffer for the pData and should free is myself.

Signature
Thanks
Sharon
adebaene@club-internet.fr - 25 Jun 2007 11:01 GMT
> I have the following managed C++ function (VC++ 2005 (C++/CLI)
>
[quoted text clipped - 14 lines]
> I think this function works.
> But is there a better way to that (maybe without doing the copy) ?
If your native API allows you to get the data size without retrieveing
the actual data, AND to use a user-supplied buffer, you could :
- get the data size from native API.
- Allocate a managed array of the correct size.
- Pin that array (using pin_ptr).
- Pass the pinned pointer to the native API, so that it fills directly
the managed array.
- Return the managed array.
This may be more efficient if the data is big (if the data is small,
it won't make any difference - it may even make performance worst
because it means having 2 managed/native transitions instead of one).
Also, it requires that you change the unmanaged API, but this may be a
good idea anyway, since it will make your API more similar to Win32
API.
Arnaud
MVP - VC
Sharon - 25 Jun 2007 12:29 GMT
> If your native API allows you to get the data size without retrieveing
> the actual data, AND to use a user-supplied buffer, you could :
[quoted text clipped - 4 lines]
> the managed array.
> - Return the managed array.
It sounds like a good idea.
I know hot to do that in C# using unsafe and fixed.
But I can find the way to do that in managed C++ (VC++ 2005 (C++/CLI).
Maybe you can post a sample showing how it should be done?

Signature
Thanks
Sharon
Sharon - 25 Jun 2007 13:13 GMT
I think I found the way to do it:
int len = m_pureNativeCPPObj->GetDataSize();
array<byte>^ managedArray= gcnew array<byte>(len);
System::Runtime::InteropServices::GCHandle arrHandle =
System::Runtime::InteropServices::GCHandle::Alloc(managedArray);
IntPtr pData =
System::Runtime::InteropServices::Marshal::UnsafeAddrOfPinnedArrayElement(managedArray, 0);
m_pureNativeCPPObj->GetData((BYTE*)pData.ToPointer(), len);
arrHandle.Free();
return managedArray;
What do you think?
-------
Regards
Sharon
Ben Voigt [C++ MVP] - 25 Jun 2007 14:27 GMT
>I think I found the way to do it:
>
[quoted text clipped - 10 lines]
>
> What do you think?
Yuck! :)
try:
pin_ptr<char> pData = &managedArray[0];
> -------
> Regards
> Sharon
Sharon - 25 Jun 2007 15:14 GMT
Yuck...
Ok... so I guess this is the nice way (-:
it should be like that:
int len = m_pureNativeCPPObj->GetDataSize();
array<byte>^ managedArray = gcnew array<byte>(len);
pin_ptr<byte> pinManagedArray = &managedArray[0];
byte* pManagedArray = pinManagedArray;
m_pureNativeCPPObj->GetData(scanLine, pixel, pManagedArray , len);
return managedArray;
No need to free nothing?

Signature
Thanks
Sharon
Ben Voigt [C++ MVP] - 25 Jun 2007 18:09 GMT
> Yuck...
>
[quoted text clipped - 6 lines]
> pin_ptr<byte> pinManagedArray = &managedArray[0];
> byte* pManagedArray = pinManagedArray;
This line wasn't needed, and is actually dangerous, if the native pointer
outlives the pinning pointer.
> m_pureNativeCPPObj->GetData(scanLine, pixel, pManagedArray , len);
> return managedArray;
>
> No need to free nothing?
No, the only allocation you did was a garbage collected array. It
automatically unpins when the pin_ptr goes out of scope.
Sharon - 25 Jun 2007 19:36 GMT
Ok, that is great.
So I'm assuming that the way to do it is the awy I have just posted...

Signature
Thanks a lot
Sharon
Sharon - 25 Jun 2007 19:41 GMT
>"Ben Voigt [C++ MVP]" wrote:
> > int len = m_pureNativeCPPObj->GetDataSize();
[quoted text clipped - 3 lines]
> This line wasn't needed, and is actually dangerous, if the native pointer
> outlives the pinning pointer.
Sorry, I didn't notice your remark about the unnecessary line.
So I can simply skeep the line:
byte* pManagedArray = pinManagedArray;
And leave it like that ? :
int len = m_pureNativeCPPObj->GetDataSize();
array<byte>^ managedArray = gcnew array<byte>(len);
pin_ptr<byte> pinManagedArray = &managedArray[0];
m_pureNativeCPPObj->GetData(scanLine, pixel, pinManagedArray, len);
return managedArray;
--------
Thanks again
Sharon
Ben Voigt [C++ MVP] - 26 Jun 2007 01:39 GMT
> >"Ben Voigt [C++ MVP]" wrote:
>> > int len = m_pureNativeCPPObj->GetDataSize();
[quoted text clipped - 16 lines]
> m_pureNativeCPPObj->GetData(scanLine, pixel, pinManagedArray, len);
> return managedArray;
Yup, that's exactly how pin_ptr is meant to be used.
> --------
> Thanks again
> Sharon