Unmanaged to managed return value

G

Guest

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) ?
 
M

Mattias Sjögren

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
 
G

Guest

Mattias Sjögren said:
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 ?
 
B

Ben Voigt [C++ MVP]

Sharon said:
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.

What is the prototype for GetData? That looks like you should supply the
buffer, but pData wasn't initialized.
 
G

Guest

Ben Voigt said:
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.
 
A

adebaene

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) ?

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
 
G

Guest

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.

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?
 
G

Guest

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?
 
B

Ben Voigt [C++ MVP]

Sharon said:
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?

Yuck! :)

try:
 
G

Guest

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?
 
B

Ben Voigt [C++ MVP]

Sharon said:
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;
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.
 
G

Guest

Ok, that is great.
So I'm assuming that the way to do it is the awy I have just posted...
 
G

Guest

Ben Voigt said:
int len = m_pureNativeCPPObj->GetDataSize();
array<byte>^ managedArray = gcnew array<byte>(len);
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.

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;
 
B

Ben Voigt [C++ MVP]

Sharon said:
Ben Voigt said:
int len = m_pureNativeCPPObj->GetDataSize();
array<byte>^ managedArray = gcnew array<byte>(len);
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.

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;

Yup, that's exactly how pin_ptr is meant to be used.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top