My goal is to display the message box of .NET Windows forms from pure C ++, a native program at the Windows API level (not managed by C ++ or C ++ / CLI).
That is, for educational purposes, I want to implement the C # code shown in the comment below in pure C ++:
#include <stdexcept>
#include <string>
#include <iostream>
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
#undef UNICODE
#define UNICODE
#include <windows.h>
#include <Mscoree.h>
#include <comdef.h>
_COM_SMARTPTR_TYPEDEF( ICorRuntimeHost, IID_ICorRuntimeHost );
#import "C:\\WINDOWS\\Microsoft.NET\\Framework\\v1.1.4322\\mscorlib.tlb" \
raw_interfaces_only rename( "ReportEvent", "reportEvent" )
typedef mscorlib::_AppDomainPtr AppDomainPtr;
typedef mscorlib::_ObjectHandlePtr ObjectHandlePtr;
typedef mscorlib::_AssemblyPtr AssemblyPtr;
bool throwX( std::string const& s ) { throw std::runtime_error( s ); }
template< class Predicate >
struct Is: Predicate
{};
template< class Type, class Predicate >
bool operator>>( Type const& v, Is< Predicate > const& check )
{
return check( v );
}
struct HrSuccess
{
bool operator()( HRESULT hr ) const
{
::SetLastError( hr );
return SUCCEEDED( hr );
}
};
void cppMain()
{
ICorRuntimeHostPtr pCorRuntimeHost;
CorBindToRuntimeEx(
L"v1.1.4322",
L"wks",
0,
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
reinterpret_cast<void**>( &pCorRuntimeHost )
)
>> Is< HrSuccess >()
|| throwX( "CorBindToRuntimeEx failed" );
pCorRuntimeHost->Start()
>> Is< HrSuccess >()
|| throwX( "CorRuntimeHost::Start failed" );
IUnknownPtr pAppDomainIUnknown;
pCorRuntimeHost->GetDefaultDomain( &pAppDomainIUnknown )
>> Is< HrSuccess >()
|| throwX( "CorRuntimeHost::GetDefaultDomain failed" );
AppDomainPtr pAppDomain = pAppDomainIUnknown;
(pAppDomain != 0)
|| throwX( "Obtaining _AppDomain interface failed" );
AssemblyPtr pFormsAssembly;
pAppDomain->Load_2( _bstr_t( "System.Windows.Forms" ), &pFormsAssembly )
>> Is< HrSuccess >()
|| throwX( "Loading System.Windows.Forms assembly failed" );
}
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
}
return EXIT_FAILURE;
}
Plan, after loading the assembly, go to the class MessageBoxand call Show. But this may be the wrong way to do it. Therefore, I am equally satisfied with the answer showing how to do this without finding the full name of the assembly (of course, without hard coding, this is the full name!).
The utility gacutilcan obviously find fully qualified names:
C: \ test> gacutil / l System.Windows.Forms
Microsoft (R) .NET Global Assembly Cache Utility. Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.
The Global Assembly Cache contains the following assemblies:
System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL
System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL
Number of items = 4
C:\test> _
, , : .NET, ++, , #, , .NET .
.