我的目標是從純C++本機Windows API級程序(不是託管的C++或C++/CLI)顯示.NET Windows窗體消息框。以編程方式查找完全限定的.NET程序集名稱(從簡單名稱,對於給定的.NET版本)?
即,用於學習目的,我想實現在下面的評論中所示的C#代碼,純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;
}
該計劃,具有加載的組件,進行到MessageBox
類並調用Show
。但這可能是一個錯誤的做法。所以我同樣滿意的答案顯示如何做到這一點,沒有找到程序集的完全限定的名稱(當然,沒有硬編碼完全合格的名稱!)。
的gacutil
效用顯然是能夠找到完全合格的名稱:
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> _
然而,如前所述,我不想硬編碼任何東西:在C++代碼硬編碼了.NET的信息不應該超過在頂部註釋中顯示的C#源代碼中,加上支持的最低.NET版本。
TIA,
這是一個非常有趣的運算符>>用法。 – 2010-10-23 04:52:51
絕對看看這[提案](http://area51.stackexchange.com/proposals/11464/code-review?referrer = aWNm_PdciyFqjFW8CUacGw2「代碼評論」)。它幾乎在那裏,只需要一點點支持。 – greatwolf 2011-01-17 22:53:09