Native classes in managed class interfaces

G

Guest

Dear VS Team,

using the Beta 2 of VS 2005 I've encontered the following problem.

Let's assume threre are three Dll's, one unmanaged and two managed. In the
unmanaged we put a simple unmanged struct "A" which is exported in the usual
way.

The first managed assembly defines a managed class "B" using the unmanaged
class "A" defined in the unmanaged Dll. This class "B" has got a public
member variable "a" of type "A*" and a function "get" returning "a".

The second managed assembly defines a managed class "C" having a member "b"
of type "B^". See the code below.

// Unamanaged DLL

struct A
{
int data;
};

// First Managed DLL (references unmanaged dll)

public ref class B
{
public:
A* a;

B()
{
a = new A();
}

A* get()
{
return a;
}
};

// Second Managed DLL (references unmanaged dll and first managed dll)

public ref class C
{
private:
B^ b;

public:
C()
{
b = gcnew B();

A* a0 = b->a;
A* a1 = b->get();
}
};

Compiling this code in VS 2003 (with the corresponding syntax changes of
course), everything goes well. In VS 2005 I get the following errror messages:

'B::a' : cannot access private member declared in class 'B'

and

'B::get': candidate function(s) not accessible

Does this mean, that a managed class can not have a function returning a
pointer to an unmanaged class??

Does the compiler declare the public member "a" in the managed class "B"
private on its own in order to make acessing to it from outside the assembly
impossible??

Best regards,

Martin Zenkel
 
K

Kapil Khosla [MSFT]

--
This posting is provided "AS IS" with no warranties, and confers no
rights."Use of included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm"

Martin Zenkel said:
Dear VS Team,

using the Beta 2 of VS 2005 I've encontered the following problem.

Let's assume threre are three Dll's, one unmanaged and two managed. In the
unmanaged we put a simple unmanged struct "A" which is exported in the
usual
way.

The first managed assembly defines a managed class "B" using the unmanaged
class "A" defined in the unmanaged Dll. This class "B" has got a public
member variable "a" of type "A*" and a function "get" returning "a".

The second managed assembly defines a managed class "C" having a member
"b"
of type "B^". See the code below.

// Unamanaged DLL

struct A
{
int data;
};

// First Managed DLL (references unmanaged dll)

public ref class B
{
public:
A* a;

B()
{
a = new A();
}

A* get()
{
return a;
}
};

// Second Managed DLL (references unmanaged dll and first managed dll)

public ref class C
{
private:
B^ b;

public:
C()
{
b = gcnew B();

A* a0 = b->a;
A* a1 = b->get();
}
};

Compiling this code in VS 2003 (with the corresponding syntax changes of
course), everything goes well. In VS 2005 I get the following errror
messages:

'B::a' : cannot access private member declared in class 'B'

and

'B::get': candidate function(s) not accessible

Does this mean, that a managed class can not have a function returning a
pointer to an unmanaged class??

Does the compiler declare the public member "a" in the managed class "B"
private on its own in order to make acessing to it from outside the
assembly
impossible??

Best regards,

Martin Zenkel



Thanks for the very clear post. We do allow a managed class to have a
function returning a pointer to an unmanaged class. The only thing
disallowed is embedding native
types in managed types. You are missing __declspec(dllexport) and
__declspec(dllimport) on your class declarations. I have copied the correct
working code.
cl /EHsc /LD native.cpp
cl /clr m.cpp /link native.lib

///////////////// native.cpp

struct __declspec(dllexport) A
{
int data;
};

///////////////// m.cpp

using namespace System;
struct __declspec(dllimport) A
{
int data;
};

public ref class B
{
public:
A* a;

B()
{
a = new A();
a->data = 4;
}
A* get() // returning a pointer to a native struct.
{
return a;
}
};

int main()
{
B obj;
A* a = obj.get();
Console::WriteLine(a->data);
}



Does that help?
Thanks,
Kapil
 
T

Tamas Demjen

I think Martin meant that a managed dll can't export an unmanaged member
pointer, such as:

///////////////// native.h (a native DLL project)

struct __declspec(dllexport) A
{
int data;
};

///////////////// managed1.h (a managed DLL project)

struct __declspec(dllimport) A
{
int data;
};

public ref class B
{
public:
B()
{
a = new A();
a->data = 4;
}
A* get() // returning a pointer to a native struct.
{
return a;
}
private:
A* a;
};

///////////////// managed2.h (another managed .exe or DLL project)

#using "managed1.dll"

void test()
{
B b;
b.get(); // error: 'B::get' candidate function(s) not accessible
}

So a managed assembly (DLL) doesn't seem to be able to export unmanaged
pointers. There are two choices:
1. You either #include "managed1.h" and add managed1.cpp to the second
project, and then get() is accessible and is working, or
2. you are #using "managed1.dll" and the get() function simply can't be
called. I couldn't mix #using and #include.

Sometimes it would be nice to have access from one assembly to unmanaged
members in another assembly. Just like Graphics::GetHdc(), which returns
the underlying HDC handle. Similarly, it would be nice to add a get()
function to my managed classes that wrap an underlying native C/C++ API.
Sometimes it's inevitable, that's why WinForms has GetHdc too. As I see
it, Graphics::GetHdc returns a managed type called IntPtr, so that's how
it works internally. I don't think a managed assembly is able to return
pointers to unmanaged C++ types, but if it's possible, I would really
like to know how.

Perhaps returning IntPtr and casting it to our native C++ type is the
only way. I actually tried it and it worked:

///////////////// managed1.h

public ref class B
{
[...]
IntPtr get() { return static_cast<IntPtr>(a); }
[...]
};

///////////////// managed2.h

A* a = reinterpret_cast<A*>(static_cast<void*>(b.get()));

This is a little bit nasty, in my opinion, if it's correct at all. I
wish there was a more user friendly way of doing this, with better
unmanaged type safety.

Any comments? I'm still in the early experimenting phase with Beta 2.

Tom
 

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