Board index » cppbuilder » Hosting the CLR (COM)

Hosting the CLR (COM)


2005-01-12 11:24:16 PM
cppbuilder64
I am trying to Host the CLR in a BCB application. I have tried two ways so
far with no success. One of the ways I have tried is by using COM. I have
posted that code below. Can anyone see anything wrong? An EOleSysError
exception is being thrown saying "Not implemented" on the OlePropertyGet
function.
HRESULT hr;
ICorRuntimeHost* pCorRuntimeHost = NULL;
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_CorRuntimeHost, NULL, CLSCTX_INPROC_SERVER,
IID_ICorRuntimeHost, (void**) &pCorRuntimeHost);
if (SUCCEEDED(hr))
{
cout << "ICorRuntimeHost retrieved" << endl;
hr = pCorRuntimeHost->Start();
if (SUCCEEDED(hr))
{
cout << "Runtime started" << endl;
IUnknown* pAppDomainUnk = NULL;
IDispatch* pAppDomainDis = NULL;
hr = pCorRuntimeHost->GetDefaultDomain(&pAppDomainUnk);
if (SUCCEEDED(hr))
{
cout << "Default AppDomain(IUnknown) retrieved" << endl;
hr = pAppDomainUnk->QueryInterface(IID_AppDomain, (void**)
&pAppDomainDis);
if (SUCCEEDED(hr))
{
cout << "Default AppDomain(IDispatch) retrieved" << endl;
Variant AppDomain = pAppDomainDis;
AnsiString BaseDirectory =
AppDomain.OlePropertyGet("BaseDirectory");
cout << BaseDirectory.c_str() << endl;
pAppDomainDis->Release();
}
pAppDomainUnk->Release();
}
hr = pCorRuntimeHost->Stop();
if (SUCCEEDED(hr))
cout << "Runtime stopped" << endl;
}
pCorRuntimeHost->Release();
}
CoUninitialize();
}
 
 

Re:Hosting the CLR (COM)

"Mike King" < XXXX@XXXXX.COM >wrote in message
Quote
An EOleSysError exception is being thrown saying "Not implemented"
on the OlePropertyGet function.
The error is self-explanatory - you are trying to invoke a feature that is
not implemented.
Quote
hr = CoCreateInstance(CLSID_CorRuntimeHost, NULL,
CLSCTX_INPROC_SERVER, IID_ICorRuntimeHost, (void**)
&pCorRuntimeHost);
To load a .NET interface, you are supposed to use the CorBindToRuntimeEx()
function instead of CoCreateInstance()
Quote
Variant AppDomain = pAppDomainDis;
AnsiString BaseDirectory =
AppDomain.OlePropertyGet("BaseDirectory");
Why are you using a Variant like that? When you call QueryInterface(),
rather than using IDispatch*, use _AppDomain* instead. Then you will have
direct access to the AppDomain interface, and can call its BaseDirectory as
a real COM property, not an OLE IDispatch property.
Gambit
 

Re:Hosting the CLR (COM)

Quote
To load a .NET interface, you are supposed to use the CorBindToRuntimeEx()
function instead of CoCreateInstance()
I tried that first but I could not get it to work. See code at the bottom
of post. It sounds like you have done this before. If so, could you please
post some code. I want to add some scripting capable to my application
using a .NET language.
Quote
Why are you using a Variant like that? When you call QueryInterface(),
rather than using IDispatch*, use _AppDomain* instead. Then you will have
direct access to the AppDomain interface, and can call its BaseDirectory
as
a real COM property, not an OLE IDispatch property.
I'm having a problem importing the Type Library so I'm trying late-binding
using IDispatch. Please read previous post about importing problem
(groups-beta.google.com/group/borland.public.cppbuilder.activex/browse_thread/thread/45982560faa477d1/520f4f7cfe2c67df&&d#520f4f7cfe2c67df).
HRESULT hr;
//hr = CoInitialize(NULL);
OleInitialize(NULL);
LPWSTR pwszVersion = NULL;//L"v1.1.4322"; // Version
LPWSTR pwszBuildFlavor = NULL; //L"wks"; // Workstation
DWORD flags = NULL; // default
ICorRuntimeHost *pHost = NULL;
hr = CorBindToRuntimeEx(pwszVersion,
pwszBuildFlavor,
flags,
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(void **)&pHost);
if (SUCCEEDED(hr))
{
cout << "ICorRuntimeHost retrieved" << endl;
WCHAR buf[255];
DWORD buf_size = sizeof(buf) / sizeof(WCHAR);
DWORD length;
GetCORVersion(buf, buf_size, &length);
WideString CORVersion(buf, length);
cout << AnsiString(CORVersion).c_str() << endl;
hr = pHost->Start();
if (SUCCEEDED(hr))
{
cout << "Runtime has started" << endl;
IUnknown *pAppDomainPunk = NULL;
IDispatch *pAppDomainDis = NULL;
Variant vAppDomain;
hr = pHost->GetDefaultDomain(&pAppDomainPunk);
hr = pAppDomainPunk->QueryInterface(IID__AppDomain, (void
**)&pAppDomainDis);
if (FAILED(hr)) cout << SysErrorMessage(hr).c_str() << endl;
vAppDomain = pAppDomainDis;
AnsiString BaseDirectory = vAppDomain.OlePropertyGet("BaseDirectory");
cout << BaseDirectory.c_str() << endl;
pAppDomainDis->Release();
pAppDomainPunk->Release();
hr = pHost->Stop();
if (SUCCEEDED(hr))
cout << "Runtime has stopped" << endl;
}
else
cout << "The runtime cannot be started" << endl;
pHost->Release();
}
//CoUninitialize();
OleUninitialize();
 

{smallsort}

Re:Hosting the CLR (COM)

"Mike King" < XXXX@XXXXX.COM >wrote in message
Quote
I tried that first but I could not get it to work.
Why not? You need to provide specific details.
Quote
It sounds like you have done this before.
I have never done it before, nor have I even heard of hosting the CLR in an
unmanged environment before. It was a simple matter to look up the
information at MSDN and view a few examples, though.
Quote
I'm having a problem importing the Type Library so I'm trying
late-binding using IDispatch.
Why import the type library at all? You can access COM interfaces without a
type library, as long as you have the interface definitions and the
IID/CLSID values, such as from a header file. If you do not have a suitable
header file provided by the .NET SDK, you can generate one from the type
library without actually including the type library in the project.
Quote
IUnknown *pAppDomainPunk = NULL;
IDispatch *pAppDomainDis = NULL;
Variant vAppDomain;
Again, get rid of the Variant and use the _AppDomain interface directly:
IUnknown *pUnk = NULL;
_AppDomain *pAppDomain = NULL;
hr = pHost->GetDefaultDomain(&pUnk);
if (SUCCEEDED(hr))
{
hr = pUnk->QueryInterface(IID__AppDomain, (void**)&pAppDomain);
pUnk->Release();
}
if (pAppDomain != NULL)
{
WideString BaseDirectory;
pAppDomain->get_BaseDirectory(&BaseDirectory);
pAppDomain->Release();
cout << AnsiString(BaseDirectory).c_str() << endl;
}
else
cout << SysErrorMessage(hr).c_str() << endl;
Gambit
 

Re:Hosting the CLR (COM)

Quote
>I'm having a problem importing the Type Library so I'm trying
>late-binding using IDispatch.

Why import the type library at all? You can access COM interfaces without
a
type library, as long as you have the interface definitions and the
IID/CLSID values, such as from a header file. If you do not have a
suitable
header file provided by the .NET SDK, you can generate one from the type
library without actually including the type library in the project.

>IUnknown *pAppDomainPunk = NULL;
>IDispatch *pAppDomainDis = NULL;
>Variant vAppDomain;

Again, get rid of the Variant and use the _AppDomain interface directly:
I tried including the mscorlib.h header file which is where _AppDomain is
defined, but I get numerous errors when I do. So I got rid of the include
and started to copy&paste the GUIDs of IID__AppDomain and
IID_ICorRuntimeHost as so on. The definition of _AppDomain uses other types
that are defined in mscorlib.h. So I don't want to recursively pull out all
of the definitions of all the types in mscorlib.h file just to get my
application to compile. IDispatch seems a lot simpler. What's wrong with
Variant and IDispatch?
Build
[C++ Error] mscorlib.h(2510): E2447 'TypeCode' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(2645): E2447 'FileSystemAttributes' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(2726): E2447 'FileMode' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(2730): E2447 'FileAccess' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(2740): E2447 'FileShare' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(3013): E2447 'MemberTypes' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(3065): E2447 'MethodImplAttributes' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(3069): E2447 'MethodAttributes' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(3169): E2447 'BindingFlags' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(3635): E2447 'ProcessorID' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(3645): E2447 'AssemblyNameFlags' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(3649): E2447 'AssemblyHashAlgorithm' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(3792): E2447 'FormatterTopObjectStyle' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(3796): E2447 'FormatterTypeStyle' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(3917): E2447 'CipherMode' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(3919): E2447 'PaddingMode' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(4156): E2447 'ParameterAttributes' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(5028): E2447 'ResourceAttributes' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(5883): E2447 'PropertyAttributes' must be a
previously defined enumeration tag
[C++ Error] mscorlib.h(6785): E2447 'EventAttributes' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(6927): E2447 'SecurityZone' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(7688): E2447 'TypeAttributes' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(9845): E2447 'PInvokeMap' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(9875): E2447 'FieldAttributes' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(9918): E2447 'SecurityAction' must be a previously
defined enumeration tag
[C++ Error] mscorlib.h(9918): E2228 Too many error or warning messages
 

Re:Hosting the CLR (COM)

"Mike King" < XXXX@XXXXX.COM >wrote in message
Quote
What's wrong with Variant and IDispatch?
Well, for one thing, it didn't work for you when you actually tried it.
Second, _AppDomain does not derive from IDispatch to begin with, so you
cannot call QueryInterface() using IID__AppDomain and store the interface
into an IDispatch* pointer. To get IDispatch*, you need to use
IID_IDispatch when calling QueryInterface().
Gambit
 

Re:Hosting the CLR (COM)

Quote
>What's wrong with Variant and IDispatch?

Well, for one thing, it didn't work for you when you actually tried it.

Second, _AppDomain does not derive from IDispatch to begin with, so you
cannot call QueryInterface() using IID__AppDomain and store the interface
into an IDispatch* pointer. To get IDispatch*, you need to use
IID_IDispatch when calling QueryInterface().


Gambit

First, thank you for the your response.
I believe _AppDomain does derive from IDispatch. The following came from
the .NET SDK documentation.
[CLSCompliant(false)]
[Guid("05F696DC-2B29-3663-AD8B-C4389CF2A713")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface _AppDomain
I have also tried querying for IID_IDispatch with the same result (I get a
message saying "No such interface supported" when I try to get the value of
the property BaseDirectory as described earlier.)
I have an example of using an IDispatch* on a .NET object, but the API
(ClrCreateManagedInstance) I am using isn't documented and probably isn't
supported. It works for now, but I'm afraid of using it in production code
because there is no guarantee that it will always work in the future.
HRESULT hr;
IDispatch* dStack = NULL;
hr = ClrCreateManagedInstance(L"System.Collections.Stack, mscorlib,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
IID_IDispatch,
reinterpret_cast<void**>(&dStack));
if (SUCCEEDED(hr))
{
cout << "Object created" << endl;
Variant vStack = dStack;
dStack->Release();
vStack.OleFunction("Push", "1");
vStack.OleFunction("Push", "2");
cout << ((AnsiString)vStack.OleFunction("Pop")).c_str() << endl;
cout << ((AnsiString)vStack.OleFunction("Pop")).c_str() << endl;
}
else
cout << "Couldn't create object" << endl;
 

Re:Hosting the CLR (COM)

"Mike King" < XXXX@XXXXX.COM >wrote in message
Quote
I have also tried querying for IID_IDispatch with the same result (I
get a message saying "No such interface supported" when I try to
get the value of the property BaseDirectory as described earlier.)
Well, if querying IID_IDispatch reports an error, then IDispatch is not
actually implemented to begin with.
Quote
I have an example of using an IDispatch* on a .NET object, but
the API (ClrCreateManagedInstance) I am using isn't documented
and probably isn't supported. It works for now, but I'm afraid of
using it in production code because there is no guarantee that it will
always work in the future.
That code has nothing to do with your earlier AppDomain code.
Gambit
 

Re:Hosting the CLR (COM)

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"Mike King" < XXXX@XXXXX.COM >wrote in message
news:41f14eb6$ XXXX@XXXXX.COM ...

>I have also tried querying for IID_IDispatch with the same result (I
>get a message saying "No such interface supported" when I try to
>get the value of the property BaseDirectory as described earlier.)

Well, if querying IID_IDispatch reports an error, then IDispatch is not
actually implemented to begin with.
No, I said when I queried for the BaseDirectory property. I didn't said when
querying for the interface.
Quote
>I have an example of using an IDispatch* on a .NET object, but
>the API (ClrCreateManagedInstance) I am using isn't documented
>and probably isn't supported. It works for now, but I'm afraid of
>using it in production code because there is no guarantee that it will
>always work in the future.

That code has nothing to do with your earlier AppDomain code.
I know. It just shows I can use IDispatch with a .NET object.
 

Re:Hosting the CLR (COM)

"Mike King" < XXXX@XXXXX.COM >wrote in message
Quote
No, I said when I queried for the BaseDirectory property. I
didn't said when querying for the interface.
Please show the actual code you are using.
Gambit
 

Re:Hosting the CLR (COM)

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"Mike King" < XXXX@XXXXX.COM >wrote in message
news:41f15b7b$ XXXX@XXXXX.COM ...

>No, I said when I queried for the BaseDirectory property. I
>didn't said when querying for the interface.

Please show the actual code you are using.


Gambit

void LoadDLLWay ( )
{
HRESULT hr;
hr = CoInitialize(NULL);
LPWSTR pwszVersion = NULL;//L"v1.1.4322"; // Version
LPWSTR pwszBuildFlavor = NULL; //L"wks"; // Workstation
DWORD flags = NULL; // default
ICorRuntimeHost *pHost = NULL;
hr = CorBindToRuntimeEx(pwszVersion,
pwszBuildFlavor,
flags,
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(void **)&pHost);
if (SUCCEEDED(hr))
{
cout << "ICorRuntimeHost retrieved" << endl;
hr = pHost->Start();
if (SUCCEEDED(hr))
{
cout << "Runtime has started" << endl;
IUnknown *pAppDomainPunk = NULL;
IDispatch *pAppDomainDis = NULL;
hr = pHost->GetDefaultDomain(&pAppDomainPunk);
if (SUCCEEDED(hr))
{
hr = pAppDomainPunk->QueryInterface(IID_IDispatch,
reinterpret_cast<void**>(&pAppDomainDis));
if (FAILED(hr)) cout << SysErrorMessage(hr).c_str() << endl;
if (SUCCEEDED(hr))
{
Variant vAppDomain = pAppDomainDis;
AnsiString BaseDirectory =
vAppDomain.OlePropertyGet("BaseDirectory");
cout << BaseDirectory.c_str() << endl;
pAppDomainDis->Release();
}
pAppDomainPunk->Release();
}
hr = pHost->Stop();
if (SUCCEEDED(hr))
cout << "Runtime has stopped" << endl;
}
else
cout << "The runtime cannot be started" << endl;
pHost->Release();
}
CoUninitialize();
}
 

Re:Hosting the CLR (COM)

"Mike King" < XXXX@XXXXX.COM >wrote in message
Quote
IUnknown *pAppDomainPunk = NULL;
IDispatch *pAppDomainDis = NULL;

hr = pHost->GetDefaultDomain(&pAppDomainPunk);
if (SUCCEEDED(hr))
{
hr = pAppDomainPunk->QueryInterface(IID_IDispatch,
reinterpret_cast<void**>(&pAppDomainDis));
Does the QueryInterface() fail or succeed? If it fails, then you won't be
able to access the BaseDirectory via IDispatch.
Quote
Variant vAppDomain = pAppDomainDis;

AnsiString BaseDirectory =
vAppDomain.OlePropertyGet("BaseDirectory");
cout << BaseDirectory.c_str() << endl;
You don't need to use Variant in order to access the Directory property.
Use can call IDispatch::Invoke() directly.
I still recommend that you just use the _AppDomain interface directly, as I
showed you earlier. Then you can get rid of both Variant and IDispatch
altogether. The fact that you are getting errors in the header files
suggest to me that you are not using the header files properly. Fix that
issue, and then you can use the _AppDomain interface as it was intended to
be used.
Gambit
 

Re:Hosting the CLR (COM)

Quote
I still recommend that you just use the _AppDomain interface directly, as
I
showed you earlier. Then you can get rid of both Variant and IDispatch
altogether. The fact that you are getting errors in the header files
suggest to me that you are not using the header files properly. Fix that
issue, and then you can use the _AppDomain interface as it was intended to
be used.


Gambit
Thanks!!! It's working now.
I found a modified version of mscorlib.h, which I still had to modify a
little more to get it compile.
Now, since I'm working with raw interfaces, how do I wrap-up BSTR so I will
not forget to release the memory?
 

Re:Hosting the CLR (COM)

"Mike King" < XXXX@XXXXX.COM >wrote in message
Quote
Now, since I'm working with raw interfaces, how do I wrap-up
BSTR so I will not forget to release the memory?
Use the VCL's WideString class. It already does what you are asking for.
Gambit
 

Re:Hosting the CLR (COM)

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote

"Mike King" < XXXX@XXXXX.COM >wrote in message
news:41f17621$ XXXX@XXXXX.COM ...

>Now, since I'm working with raw interfaces, how do I wrap-up
>BSTR so I will not forget to release the memory?

Use the VCL's WideString class. It already does what you are asking for.


Gambit
Does the Attach function transfer responsible to WideString to release the
memory? The help file didn't say it exactly, but got the feeling it does.