Pointers btwn C# and C++

G

Guest

I have a native C++ pointer object which I need to hold in a C# environment,
initialize in the C++ environment and the pass between the C# and C++
environments. Which is the data structure to use? I have tried to use an
IntPtr in C#, send it through C++/CLI as a System::IntPtr and convert it to a
pointer of my class in the end, but that gives compilation errors. What I
guess I need is som C# equivalence to a void* to keep in the C# environment.
But I have no clue how to do it...
 
M

Mattias Sjögren

I have tried to use an
IntPtr in C#, send it through C++/CLI as a System::IntPtr and convert it to a
pointer of my class in the end, but that gives compilation errors.

Can you post the errors and your code? Using IntPtr should work
nicely. You can also use an actual void* in C# if you enable unsafe
code.


Mattias
 
B

Ben Voigt

Joachim said:
I have a native C++ pointer object which I need to hold in a C#
environment,
initialize in the C++ environment and the pass between the C# and C++
environments. Which is the data structure to use? I have tried to use an
IntPtr in C#, send it through C++/CLI as a System::IntPtr and convert it
to a
pointer of my class in the end, but that gives compilation errors. What I
guess I need is som C# equivalence to a void* to keep in the C#
environment.
But I have no clue how to do it...

An IntPtr is the right thing to use, as long as this is a native pointer,
i.e. not a pointer into a garbage collected object. Use the ToPointer()
method to get the native pointer back.
 
G

Guest

The C# app:

IntPtr m_DVPSDK_ptr;

[DllImport(g_wrapper_dll_path)]
static extern int Initialize(
out IntPtr class_ptr,
ref int[] devices_ids,
Int32 encoder_id);

[DllImport(g_wrapper_dll_path)]
static extern string GetLastError(
IntPtr class_ptr,
Int32 encoder_id);

void Initialize()
{
int[] l_devs_ids = new int[g_max_devices];
int l_nr_of_devices = Initialize(
out m_DVPSDK_ptr,
ref l_devs_ids,
m_settings.EncoderId);

if (l_nr_of_devices == 0)
{
//TODO: throw error?
}
}


The C++/CLI code:

extern "C" int Initialize(
System::IntPtr class_ptr,
array<int>^ devices_ids,
int encoder_id)
{
return Impl::Initialize(
(DVP1412DLL*) class_ptr, //ERROR 2 BELOW
devices_ids,
encoder_id);
}

Error 2 error C2440: 'type cast' : cannot convert from 'System::IntPtr' to
'DVP1412DLL *'

extern "C" const System::String^ GetLastError(
System::IntPtr class_ptr,
int encoder_id)
{
return Impl::GetLastError(
(DVP1412DLL*) class_ptr, //ERROR 12 BELOW
encoder_id);
}


Error 12 error C2440: 'type cast' : cannot convert from 'System::IntPtr' to
'DVP1412DLL *'
 
G

Guest

Only declaring an IntPtr (IntPtr myPtr;) in C# and passing it as an out
parameter to the C++ dll should work just fine then?
 
G

Guest

Seemed like it had to do with that I declared the functions as

__declspec(dllexport)

However, even though it compiles, the value of the IntPtr is not changed in
C# even though it is in C++

Joachim said:
The C# app:

IntPtr m_DVPSDK_ptr;

[DllImport(g_wrapper_dll_path)]
static extern int Initialize(
out IntPtr class_ptr,
ref int[] devices_ids,
Int32 encoder_id);

[DllImport(g_wrapper_dll_path)]
static extern string GetLastError(
IntPtr class_ptr,
Int32 encoder_id);

void Initialize()
{
int[] l_devs_ids = new int[g_max_devices];
int l_nr_of_devices = Initialize(
out m_DVPSDK_ptr,
ref l_devs_ids,
m_settings.EncoderId);

if (l_nr_of_devices == 0)
{
//TODO: throw error?
}
}


The C++/CLI code:

extern "C" int Initialize(
System::IntPtr class_ptr,
array<int>^ devices_ids,
int encoder_id)
{
return Impl::Initialize(
(DVP1412DLL*) class_ptr, //ERROR 2 BELOW
devices_ids,
encoder_id);
}

Error 2 error C2440: 'type cast' : cannot convert from 'System::IntPtr' to
'DVP1412DLL *'

extern "C" const System::String^ GetLastError(
System::IntPtr class_ptr,
int encoder_id)
{
return Impl::GetLastError(
(DVP1412DLL*) class_ptr, //ERROR 12 BELOW
encoder_id);
}


Error 12 error C2440: 'type cast' : cannot convert from 'System::IntPtr' to
'DVP1412DLL *'


Mattias Sjögren said:
Can you post the errors and your code? Using IntPtr should work
nicely. You can also use an actual void* in C# if you enable unsafe
code.


Mattias
 
B

Ben Voigt

Joachim said:
Seemed like it had to do with that I declared the functions as

__declspec(dllexport)

However, even though it compiles, the value of the IntPtr is not changed
in
C# even though it is in C++

a C# ref or out parameter must be declared in C++/CLI as a reference
parameter.
Joachim said:
The C# app:

IntPtr m_DVPSDK_ptr;

[DllImport(g_wrapper_dll_path)]
static extern int Initialize(
out IntPtr class_ptr,
ref int[] devices_ids,
Int32 encoder_id);

Don't do this. To use C++/CLI functions from C#, add a reference to the
generated DLL.
[DllImport(g_wrapper_dll_path)]
static extern string GetLastError(
IntPtr class_ptr,
Int32 encoder_id);

void Initialize()
{
int[] l_devs_ids = new int[g_max_devices];
int l_nr_of_devices = Initialize(
out m_DVPSDK_ptr,
ref l_devs_ids,
m_settings.EncoderId);

if (l_nr_of_devices == 0)
{
//TODO: throw error?
}
}


The C++/CLI code:

extern "C" int Initialize(
System::IntPtr class_ptr,
array<int>^ devices_ids,
int encoder_id)
{
return Impl::Initialize(
(DVP1412DLL*) class_ptr, //ERROR 2 BELOW

Should be class_ptr->ToPointer(), but see below...

The compiler shouldn't even allow what you're doing... you have managed
types as parameters, and those are limited to member methods of managed
types. Create a ref class and make these functions static methods within
that class. Or, make them instance methods, so you don't have to pass
around class_ptr.

You're also missing a level of indirection all over the place here. You
want Impl::Initialize to fill in the pointer, right?

Then:

int Initialize( System::IntPtr% class_ptr, array<int>^ devices_ids, int
encoder_id)
{
DVP1412DLL objectPointer;
int retval = Impl::Initialize(&objectPointer, devices_ids, encoder_id);
class_ptr = gcnew System::IntPtr(objectPointer);
return retval;
}
 

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