Mon objectif est d'afficher une boîte de message Windows Forms .NET à partir d'un programme de niveau API Windows C++ pur (non géré C++ ou C++/CLI).Trouvez un nom complet de l'assembly .NET par programme (à partir du nom simple, pour la version .NET donnée)?
C'est, à des fins d'apprentissage, je veux mettre en œuvre le code C# indiqué dans le commentaire ci-dessous, dans le plus pur C++:
/*
// C# code that this C++ program should implement:
using System.Windows.Forms;
namespace hello
{
class Startup
{
static void Main(string[] args)
{
MessageBox.Show(
"Hello, world!",
".NET app:",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
}
}
}
*/
#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); // ICorRuntimeHostPtr
// #import is an MS extension, generates a header file. Will be replaced with #include.
#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", // LPWSTR pwszVersion, // RELEVANT .NET VERSION.
L"wks", // LPWSTR pwszBuildFlavor, // "wks" or "svr"
0, // DWORD flags,
CLSID_CorRuntimeHost, // REFCLSID rclsid,
IID_ICorRuntimeHost, // REFIID riid,
reinterpret_cast<void**>(&pCorRuntimeHost)
)
>> Is<HrSuccess>()
|| throwX("CorBindToRuntimeEx failed");
pCorRuntimeHost->Start() // Without this GetDefaultDomain fails.
>> 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");
// This fails because Load requires a fully qualified assembly name.
// I want to load the assembly given only name below + relevant .NET version.
AssemblyPtr pFormsAssembly;
pAppDomain->Load_2(_bstr_t("System.Windows.Forms"), &pFormsAssembly)
>> Is<HrSuccess>()
|| throwX("Loading System.Windows.Forms assembly failed");
// ... more code here, not yet written.
}
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch(std::exception const& x)
{
std::cerr << "!" << x.what() << std::endl;
}
return EXIT_FAILURE;
}
Le plan est, après avoir chargé l'assemblée, procéder à MessageBox
classe et invoquez Show
. Mais cela peut être une fausse façon de le faire. Donc, je suis également heureux avec une réponse montrant comment faire cela sans trouver le nom qualifié complet de l'assemblée (bien sûr, sans coder en dur ce nom qualifié complet!).
L'utilitaire gacutil
est évidemment en mesure de trouver des noms qualifiés:
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> _
Cependant, comme mentionné, je ne veux pas hardcode quoi que ce soit: l'info .NET hardcoded dans le code C++ ne devrait pas être plus dans le code source C# affiché dans le commentaire en haut, plus la version minimale .NET pris en charge.
TIA.,
C'est une utilisation très intéressante de 'operator >>'. –
définitivement vérifier cette [proposition] (http://area51.stackexchange.com/proposals/11464/code-review?referrer = aWNm_PdciyFqjFW8CUacGw2 "revue de code"). Il est presque là, a juste besoin d'un peu plus de soutien. – greatwolf