Mixed mode woes (hopefully I simply dont get it )

  • Thread starter Robert Ginsburg
  • Start date
R

Robert Ginsburg

I have a mixed mode C++ dll, mostly it is unmanaged code that currently
communicates with a remote server over DCOM. I am trying to plug in the new
IPCChannel remoting provider to replace the DCOM (the replacment server is
in C#). (I cant CLR enable the whole dll, and just use managed classes due
to an ATL framework error/bug that I posted a question on previously).

I have created a new unmanaged class in the project and clr enabled that
class. It has to be an unmanaged class so that the existing unmanaged
classes can use it and include it's header. Well all of this works fine if
I connect and call the channel on every method, but I want to keep a
persistant reference to the remote object in an instance of the class. I
cant declare the managed instance variable in the header because it is
included in the unmanaged code and the compiler wont let me . I have tried
to declare an void pointer and then pin it up using the GCHandle::Alloc .. ,
this compiles but throws an error since the remote reference is
"non-blittable".

Any thoughts or help is appreciated

Robert
 
R

Robert Ginsburg

My understanding is that the gcroot template requies managed support, so how
would I declare an instance var that used gcroot in the header used by
unmanaged classes ?

Nishant Sivakumar said:
Not sure if this is useful, but have you looked at using gcroot?

--
Regards,
Nish [VC++ MVP]


Robert Ginsburg said:
I have a mixed mode C++ dll, mostly it is unmanaged code that currently
communicates with a remote server over DCOM. I am trying to plug in the
new IPCChannel remoting provider to replace the DCOM (the replacment
server is in C#). (I cant CLR enable the whole dll, and just use managed
classes due to an ATL framework error/bug that I posted a question on
previously).

I have created a new unmanaged class in the project and clr enabled that
class. It has to be an unmanaged class so that the existing unmanaged
classes can use it and include it's header. Well all of this works fine
if I connect and call the channel on every method, but I want to keep a
persistant reference to the remote object in an instance of the class. I
cant declare the managed instance variable in the header because it is
included in the unmanaged code and the compiler wont let me . I have
tried to declare an void pointer and then pin it up using the
GCHandle::Alloc .. , this compiles but throws an error since the remote
reference is "non-blittable".

Any thoughts or help is appreciated

Robert
 
N

Nishant Sivakumar

Hello Robert,

The following code compiles :-

#include <vcclr.h>

using namespace System;

#pragma unmanaged
class Native
{
gcroot<String^> m_str;
};

#pragma managed
int main()
{
return 0;
}

That's a major simplification of your scenario, but isn't that basically
what you want to do?

--
Regards,
Nish [VC++ MVP]


Robert Ginsburg said:
My understanding is that the gcroot template requies managed support, so
how would I declare an instance var that used gcroot in the header used
by unmanaged classes ?

Nishant Sivakumar said:
Not sure if this is useful, but have you looked at using gcroot?

--
Regards,
Nish [VC++ MVP]


Robert Ginsburg said:
I have a mixed mode C++ dll, mostly it is unmanaged code that currently
communicates with a remote server over DCOM. I am trying to plug in the
new IPCChannel remoting provider to replace the DCOM (the replacment
server is in C#). (I cant CLR enable the whole dll, and just use managed
classes due to an ATL framework error/bug that I posted a question on
previously).

I have created a new unmanaged class in the project and clr enabled that
class. It has to be an unmanaged class so that the existing unmanaged
classes can use it and include it's header. Well all of this works fine
if I connect and call the channel on every method, but I want to keep a
persistant reference to the remote object in an instance of the class. I
cant declare the managed instance variable in the header because it is
included in the unmanaged code and the compiler wont let me . I have
tried to declare an void pointer and then pin it up using the
GCHandle::Alloc .. , this compiles but throws an error since the remote
reference is "non-blittable".

Any thoughts or help is appreciated

Robert
 
N

Nishant Sivakumar

Oh btw, you'd have to remove the "#pragma unmanaged" to be able to do
anything useful. But I guess that's not an issue for you.

--
Regards,
Nish [VC++ MVP]


Nishant Sivakumar said:
Hello Robert,

The following code compiles :-

#include <vcclr.h>

using namespace System;

#pragma unmanaged
class Native
{
gcroot<String^> m_str;
};

#pragma managed
int main()
{
return 0;
}

That's a major simplification of your scenario, but isn't that basically
what you want to do?

--
Regards,
Nish [VC++ MVP]


Robert Ginsburg said:
My understanding is that the gcroot template requies managed support, so
how would I declare an instance var that used gcroot in the header used
by unmanaged classes ?

Nishant Sivakumar said:
Not sure if this is useful, but have you looked at using gcroot?

--
Regards,
Nish [VC++ MVP]


I have a mixed mode C++ dll, mostly it is unmanaged code that currently
communicates with a remote server over DCOM. I am trying to plug in the
new IPCChannel remoting provider to replace the DCOM (the replacment
server is in C#). (I cant CLR enable the whole dll, and just use managed
classes due to an ATL framework error/bug that I posted a question on
previously).

I have created a new unmanaged class in the project and clr enabled
that class. It has to be an unmanaged class so that the existing
unmanaged classes can use it and include it's header. Well all of this
works fine if I connect and call the channel on every method, but I
want to keep a persistant reference to the remote object in an instance
of the class. I cant declare the managed instance variable in the
header because it is included in the unmanaged code and the compiler
wont let me . I have tried to declare an void pointer and then pin it
up using the GCHandle::Alloc .. , this compiles but throws an error
since the remote reference is "non-blittable".

Any thoughts or help is appreciated

Robert
 
T

Tamas Demjen

Robert said:
My understanding is that the gcroot template requies managed support, so how
would I declare an instance var that used gcroot in the header used by
unmanaged classes ?

This is a very good question, and we had such an interesting discussion
back then in October:

http://tinyurl.com/8r9bs

The conclusion was to use a void* in unmanaged mode, and gcroot if the
compiler knows about the managed extensions:

class Native
{

private:
#ifdef _MANAGED
gcroot<Managed^> pimpl;
#else
void* not_your_business;
#endif

};

Here is an article that explains everything:
http://msdn.microsoft.com/msdnmag/issues/05/04/C/

The bottom line is that sizeof(gcroot<Managed^>) == sizeof(void*), and
it's really none of the business of the client your private members are
implemented internally. As long as you can ensure that sizeof(YourClass)
is same in C++/CLI and in ISO C++, you're fine.

Tom
 
N

Nishant Sivakumar

Hello Tamas,

If I understood it right, Robert has /clr compiled his DLL, so he probably
wouldn't need to resort to that. He can use gcroot directly (unless he
intends to use #pragma unmanaged on his native classes)
 
R

Robert Ginsburg

Actually no the DLL is not globally clr enabled., due to a problem I have
with the ATL templates and /CLR enabling an ATL inherited class(posted
previously) I have only CLR enabled the single class file, not the entire
DLL. I had however stumbled accross the void pointer solution. I think my
problem was that I thought I had to pin the GCHandle to make it work, and
that was throwing an error at runtime (non-blittable). I have since
discovered that I don't need to pin the GCHandle unless I am going to use
the object for some type of native mode call, since I only need access to
the managed objects inside the class methods I can reconstitute them by
casting the GCHandle Target.

So it appears to work with a Normal GCHandle and a void pointer in the
native class to store, what i dont know for sure is if am doing it
correctly, or if I am making too much work of it. Here is a sample of my
header ,constructor and one of the methods.. (simplified). Realizing that
this is mostly opinion, does this make sense to you ?

Thanks

-Robert

// header file included by unmanaged classes
class CCLRProxy
{
private:
void* lpvRemoteObjectGCHandle;
void* lpvRemoteChannelGCHandle;

public:
CCLRProxy(void);
~CCLRProxy(void);

CString IPAddressToHostName(CString& IPAddress);
};

// cpp file with /clr


// the actual class constructor
CCLRProxy::CCLRProxy(void)
{

lpvRemoteObjectGCHandle = NULL;
lpvRemoteChannelGCHandle = NULL;

IpcChannel^ ipcChan = gcnew IpcChannel(CHANNEL_NAME);
ChannelServices::RegisterChannel(ipcChan,false);

System::Type^ m_EAType = Version3::TM2Engine::IEAEngineClient::typeid;
String^ sIPCAddress =
Version3::TM2Engine::Constants::IPC_CLIENT_CONNECT_URI;

Version3::TM2Engine::IEAEngineClient^ rmEngine =
(IEAEngineClient^)Activator::GetObject(m_EAType,sIPCAddress);

GCHandle gcIPCChannel = GCHandle::Alloc( ipcChan, GCHandleType::Normal );
GCHandle gcEAEngine = GCHandle::Alloc( rmEngine, GCHandleType::Normal );

System::IntPtr ipChannel =
System::Runtime::InteropServices::GCHandle::ToIntPtr(gcIPCChannel);
System::IntPtr ipObject =
System::Runtime::InteropServices::GCHandle::ToIntPtr(gcEAEngine);

// now store the handles in native format so
// we can reconstitue the object on the next calls
lpvRemoteChannelGCHandle = ipChannel.ToPointer();
lpvRemoteObjectGCHandle = ipObject.ToPointer();

}

CString CCLRProxy::IPAddressToHostName(CString& IPAddress)
{
CString sReturn(DEFAULT_RETURN_NAME)
if (lpvRemoteObjectGCHandle)
{
GCHandle gcEAEngine = (GCHandle) IntPtr(lpvRemoteObjectGCHandle);
Version3::TM2Engine::IEAEngineClient^ rmEngine = (IEAEngineClient^)
gcEAEngine.Target;

String^ gcIPAddress = gcnew String(IPAddress);
String^ gcHostName = String::Empty;
Exception^ exResult = rmEngine->LookupIPAddress(gcIPAddress, gcHostName);
if (nullptr != exResult) throw exResult;
sReturn = gcHostName;
}
return sReturn;
}



Nishant Sivakumar said:
Hello Tamas,

If I understood it right, Robert has /clr compiled his DLL, so he probably
wouldn't need to resort to that. He can use gcroot directly (unless he
intends to use #pragma unmanaged on his native classes)

--
Regards,
Nish [VC++ MVP]


Tamas Demjen said:
This is a very good question, and we had such an interesting discussion
back then in October:

http://tinyurl.com/8r9bs

The conclusion was to use a void* in unmanaged mode, and gcroot if the
compiler knows about the managed extensions:

class Native
{

private:
#ifdef _MANAGED
gcroot<Managed^> pimpl;
#else
void* not_your_business;
#endif

};

Here is an article that explains everything:
http://msdn.microsoft.com/msdnmag/issues/05/04/C/

The bottom line is that sizeof(gcroot<Managed^>) == sizeof(void*), and
it's really none of the business of the client your private members are
implemented internally. As long as you can ensure that sizeof(YourClass)
is same in C++/CLI and in ISO C++, you're fine.

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