Winforms:在Winforms中应用Inproc-SxS
1. Inproc-SxS简介
InProc-SxS是.Net 4.0新推出的功能。在.Net 2.0中,一个进程中只能运行一个版本的.Net的运行时(Runtime)。在.Net 4.0中,我们可以在一个进程中运行多个不同版本的.Net运行时。也就是说在.Net 4.0,我们可以把进程的一部分的运行在.Net 4.0上,而另一部分运行在.Net 2.0上。我们可以把进程、运行时和程序域(AppDomain)用一个图来表示:
引入Inproc-SxS,给我们构建应用程序带来了很大的灵活性。在很多大型软件中,都允许第三方开发商添加插件(Add-in)。有了Inproc-SxS之后,不同的插件就可以运行在不同的.Net运行时上了。
比如一个软件开发商推出了一个基于.Net 4.0的软件,另一第三方软件开发商开发了该软件的一个插件。该插件的开发商还没有升级到.Net 4.0,仍然基于.Net 2.0开发软件,因此他们的插件还没有在4.0上做过任何测试。如果没有Inproc-SxS,该插件和它的宿主(Host)软件一样,都运行在.Net 4.0。由于插件并没有在4.0下测试过,运行在4.0运行时中就可能会有问题。现在有了Inproc-SxS,我们可以把宿主软件运行在.Net 4.0上,而插件运行在.Net 2.0上。
可能有人会问:.Net应该做到向下兼容,那基于.Net 2.0开发的插件在4.0上运行怎么会有问题呢?的确,微软的.Net 相应的开发团队在向下兼容性方面做了大量的工作。但100%的向下兼容只可能是一个理论上的目标。实际上在推出一个新版本的时候,总会对上一个版本会有若干不兼容的改动。如果用户在某一特定功能上仍然需要上一个版本,他可以利用Inproc-SxS把该功能单独运行在上一个版本的.Net中。
2. Inproc-SxS实例
下面通过一个实例来讨论如何在Winforms中应用Inproc-SxS。这个实例分为三部分:第一部分是Winforms插件,第二部分负责把插件在某一特定版本的.Net中运行,第三部分是一个宿主应用程序。
2.1 Winforms插件
如下图所示,我们在一个UserControl(class名为CLRVersionControl)里添加一个GroupBox,一个Label和一个PropertyGrid:
为了演示需要,我们在Load的事件处理器(Event Handler)中,把GroupBox的Text设为当前程序域的名字,而把Label的Text设为当前.Net运行时的版本:
private void CLRVersionControl_Load(object sender, EventArgs e)
{
groupBox1.Text = AppDomain.CurrentDomain.FriendlyName;
label1.Text = "CLR version: " + Environment.Version.ToString();
}
同时,我们添加一个函数,用来生成该插件的一个实例,并返回该插件的句柄(Handle)。它的宿主应用程序可以通过该函数创建一个插件,并把该插件添加到宿主中。
public static IntPtr CreateCLRVersionControl()
{
Control control = new CLRVersionControl();
return control.Handle;
}
2.2 运行某版本的.Net
这一部分的功能分为两部分:首先我们要创建某一版本的.Net运行时;接着我们在.Net运行时中创建一个程序域的实例,并在该程序域中创建一个插件的实例。
.Net提供了接口ICorRuntimeHost、ICLRMetaHost和 ICLRRuntimeInfo来运行某一版本的.Net。下面是一段代码范例。读者可以查阅MSDN对应的帮助文档,我在此不再详细介绍这些API。
CComPtr<ICorRuntimeHost> LoadRunTime(LPCWSTR strVersion)
{
CComPtr<ICorRuntimeHost> runtimeHost = NULL;
CComPtr<ICLRMetaHost> metahost;
CComPtr<ICLRRuntimeInfo> rtInfo;
HMODULE hmscoree = LoadLibrary(L"mscoree.dll");
if(hmscoree == NULL) return NULL;
PGETCLRMETAHOST getClrMetaHost = (PGETCLRMETAHOST)GetProcAddress(hmscoree,
"GetCLRMetaHost");
if(getClrMetaHost == NULL) return NULL;
HRESULT hr = getClrMetaHost(__uuidof(ICLRMetaHost), (LPVOID*)&metahost);
if(SUCCEEDED(hr))
{
hr = metahost->GetRuntime(strVersion,
IID_ICLRRuntimeInfo,
(LPVOID*)&rtInfo);
if(SUCCEEDED(hr))
{
hr = rtInfo->GetInterface(CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(LPVOID*)&runtimeHost);
if(SUCCEEDED(hr))
{
hr = runtimeHost->Start();
if(FAILED(hr)) runtimeHost.Release();
}
}
}
if(hmscoree) FreeLibrary(hmscoree);
if(FAILED(hr))
{
MessageBox(NULL, L"CLR Load Failed", L"WinFormsSxSTest", MB_OK);
}
return runtimeHost;
}
我们在上述代码中输入某一个.Net的版本号,就能得到该版本号对应的.Net运行时。接下来我们在一个.Net运行时里创建一个程序域,并创建一个Winforms插件的实例:
int CreateControl(CComPtr<ICorRuntimeHost> runtimeHost,
LPCWSTR strAppDomainName,
LPCWSTR strAssemblyName,
LPCWSTR strTypeName,
LPCWSTR strMethodName)
{
CComPtr<IUnknown> punkAD;
HRESULT hr = runtimeHost->CreateDomain(strAppDomainName, NULL, &punkAD);
int retValue = 0;
if(SUCCEEDED(hr))
{
CComPtr<mscorlib::_AppDomain> srpAD;
hr = punkAD.QueryInterface(&srpAD);
if(SUCCEEDED(hr))
{
long hashCode = 0;
srpAD->raw_GetHashCode(&hashCode);
}
if(SUCCEEDED(hr))
{
CComPtr<mscorlib::_Assembly> srpAsm;
CComBSTR asmName = strAssemblyName;
hr = srpAD->raw_Load_2(asmName, &srpAsm);
if(SUCCEEDED(hr))
{
CComPtr<mscorlib::_Type> srpType;
CComBSTR typeName = strTypeName;
hr = srpAsm->raw_GetType_2(typeName, &srpType);
if(SUCCEEDED(hr) && srpType != NULL)
{
CComBSTR methodName = strMethodName;
CComVariant varEmpty, varRet;
hr = srpType->raw_InvokeMember(methodName,
(mscorlib::BindingFlags)
(mscorlib::BindingFlags_InvokeMethod |
mscorlib::BindingFlags_Public |
mscorlib::BindingFlags_Static),
NULL, varEmpty, NULL, NULL, NULL, NULL, &varRet);
retValue = varRet.llVal;
}
}
}
}
if(FAILED(hr))
{
MessageBox(NULL, L"WinForm Load Failed", L"Error", MB_OK);
}
return retValue;
}
上述代码用调用ICorRuntimeHost::CreateDomain在某版本的.Net运行时中创建一个程序域,让后在该该程序域中调用CLRVersionControl.CreateCLRVersionControl创建Winforms插件CLRVersionControl的一个实例。
有了前面的准备,我们就可以在一个特定的运行时里创建运行CLRVersionControl的实例:
extern "C" __declspec (dllexport) int __stdcall CreateCLRVersionControl
(
LPCWSTR strVersion,
LPCWSTR strAppDomainName,
LPCWSTR strAssemblyName,
LPCWSTR strTypeName,
LPCWSTR strMethodName
)
{
CComPtr<ICorRuntimeHost> runtimeHost = LoadRunTime(strVersion);
return CreateControl(runtimeHost,
strAppDomainName,
strAssemblyName,
strTypeName,
strMethodName);
}
2.3宿主应用程序
创建一个基于对话框的MFC项目,在该对话框上添加两个Button,如下图所示:
为第一个button的click添加响应函数:
CWnd* pWndNET2Controls;
void CApplicationHostDlg::OnBnClickedButton1()
{
if(pWndNET2Controls != NULL)
return;
int handle = CreateCLRVersionControl(L"v2.0.50727",
L"AppDomain A",
L"WindowsFormsControlLibrary1",
L"InProcSxSDemo.CLRVersionControl",
L"CreateCLRVersionControl");
pWndNET2Controls = new CWnd();
pWndNET2Controls->Attach((HWND)handle);
pWndNET2Controls->SetParent(this);
// set size and position
……
}
在上述代码中,v2.0.50727是.Net 2.0的版本号。我们根据返回的插件句柄创建一个窗口,并将该插件的窗口作为子窗口添加到对话框中。
同样我们也为第二个button添加click的响应函数:
CWnd* pWndNET4Controls;
void CApplicationHostDlg::OnBnClickedButton2()
{
if(pWndNET4Controls != NULL)
return;
int handle = CreateCLRVersionControl(L"v4.0.21002",
L"AppDomain B",
L"WindowsFormsControlLibrary1",
L"InProcSxSDemo.CLRVersionControl",
L"CreateCLRVersionControl");
pWndNET4Controls = new CWnd();
pWndNET4Controls->Attach((HWND)handle);
pWndNET4Controls->SetParent(this);
// set size and position
……
}
V4.0.21002是.Net 4.0 Beta2的版本号。读者安装了的.Net 4.0的版本号可能会有所不同,请做相应修改。和前面一样,我们也将插件的窗口作为子窗口添加到对话框中。
现在我们运行我们宿主软件,并先后点击两个button,得到如下效果:
通过上面的截图,我们可以看出来,左边的插件时运行在.Net 2.0中,而右边插件运行在.Net 4.0中。如果仔细观察,我们还能发现在两个插件的PropertyGrid中略有不同:左边的PropertyGrid用+或者-来表示树状结点的打开或者收拢的状态,而右边的PropertyGrid用风格的三角形来表述树状结点的状态。这是因为在.Net 4.0中,Winforms对PropertyGrid做了一点改动,使PropertyGrid的树状结构和Vista、Windows 7的风格保持一致。
Winforms:在Winforms中应用Inproc-SxS相关推荐
- web.config中的InProc模式 与 StateServer模式[转]
开发asp.net应用时,修改web.config中的SessionState节点. stateserver模式: <sessionState mode="StateServer&qu ...
- .NET Core 3.0中的WinForms创建集中式拉取请求中心
Windows 窗体(或简称 WinForms),多年来被用于开发具有丰富和交互式界面的基于 Windows 的强大应用程序. 各类企业对这些桌面应用程序的投入量非常巨大,每月有大约 240 万开发人 ...
- 解决vs2019中暂时无法为.net core WinForms使用 Designer 的临时方法
以下方法来自于微软github开源项目WinForms: dotnet/winforms - Using the Classic WinForms Designer in WinForms Core, ...
- DevExpress v19.1新版亮点——WinForms篇(五)
行业领先的.NET界面控件DevExpress v19.1终于正式发布,本站将以连载的形式介绍各版本新增内容.在本系列文章中将为大家介绍DevExpress WinForms v19.1中新增的一些控 ...
- DevExpress WinForms使用教程:图表控件 - 内置深入查询
[DevExpress WinForms v18.2下载] 在最新发布的DevExpress WinForms v18.2中,DevExpress WinForms和ASP.NET图表控件引入嵌套系列 ...
- DevExpress WinForms Controls v22.1 beta版来袭,上车
DevExpress v22.1 beta版本已经上线,让我们一起先睹为快,看看将会有哪些内容更新? 新的WXI皮肤 我们的新WXI皮肤(主题)基于Windows 11.WXI皮肤附带五种调色板:& ...
- DevExpress WinForms — 2021 产品路线图
DevExpress 官方提供的2021年产品路线图计划,让我们一起来预览一下吧. DevExpress预计在 2021 年发布的新的控件和性能增强功能外,我们希望分配大量资源,帮助缩小 WinFor ...
- DevExpress WinForms使用教程:WinForms Fluent Design和Acrylic Effects
在先前的版本发布中,宣布支持Fluent Design Form和Acrylic effects--旨在复制Microsoft下一代UI metaphor的新功能.本文主要介绍如何实现此功能,并明确说 ...
- GOA WinForms 系列
介绍一个来至比利时的公司的免费产品,GOA WINFORMS. 有时一些其他的应用需求,让人头疼(比如Flash).而现在可以专注于C#,一样能完成Flash的需求. 该公司还有提供第三方的Silve ...
- 整合.NET WebAPI和 Vuejs——在.NET单体应用中使用 Vuejs 和 ElementUI
.NET简介 .NET 是一种用于构建多种应用的免费开源开发平台,例如: Web 应用.Web API 和微服务 云中的无服务器函数 云原生应用 移动应用 桌面应用 1). Windows WPF 2 ...
最新文章
- linux c 获取文件行数
- 802.11n标准简介
- ioread32函数有关知识
- headfirstjava最新版本下载_读过HeadFirstJava的大神进来看看
- mysql gtid模式主键主突_Mysql基于GTID主从复制
- SDN第5次上机作业
- Google 发布其非 Linux 系操作系统 Fuchsia 说明书!
- 10-20C#基础---一维、二维数组冒泡排序
- 没有基础的人可以学python吗-没有任何基础的人,该如何学习Python?「附具体步骤」...
- C++程序设计(三:可视化)
- HTML5 Web Storage
- ns.ajax,UIWebView使用NSURLProtocol(拦截),ajax加载失败的问题
- 节奏大师服务器不稳定,节奏大师无法登陆的原因及解决方法
- UML 用例图符号含义
- 【Docker 那些事儿】如何安全地停止、删除容器
- 随机产生四位,任意位或者范围数字方法
- Python基础教程(第三版)
- CAST和CONVERT
- Delphi 函数使用技巧
- windows开启远程桌面,防火墙拦截:只允许特定IP远程