備註
本文專屬於 .NET Framework。 它不適用於較新的 .NET 實作,包括 .NET 6 和更新版本。
從 .NET Framework 4 開始,您可以使用同進程並存裝載,在單一進程中執行多個版本的 Common Language Runtime (CLR)。 根據預設,不論為進程載入的 .NET Framework 版本為何,Managed COM 元件都會使用其建置的 .NET Framework 版本來執行。
背景
.NET Framework 一律會為 Managed 程式代碼應用程式提供並存裝載,但在 .NET Framework 4 之前,它並未為 Managed COM 元件提供該功能。 在過去,載入至進程的受控 COM元件會以已載入的執行階段版本或最新安裝的 .NET Framework 版本執行。 如果這個版本與 COM 元件不相容,元件將會失敗。
.NET Framework 4 提供並存裝載的新方法,可確保下列各項:
安裝新版本的 .NET Framework 不會影響現有的應用程式。
應用程式會針對其所建置的 .NET Framework 版本執行。 除非明確指示要這麼做,否則它們不會使用新版本的 .NET Framework。 不過,應用程式更容易轉換至使用新版本的 .NET Framework。
對使用者和開發人員的影響
終端使用者和系統管理員。 這些用戶現在可以更有信心地知道,當他們獨立安裝新版本的運行環境或與應用程式一起安裝時,它不會對他們的電腦產生影響。 現有的應用程式會如先前一樣繼續執行。
應用程式開發人員。 側邊裝載幾乎不會影響應用程式開發人員。 根據預設,應用程式一律會針對其建置的 .NET Framework 版本執行;這尚未變更。 不過,開發人員可以覆寫此行為,並指示應用程式在較新版本的 .NET Framework 下執行(請參閱 案例 2)。
程式庫開發人員和使用者。 並排託管無法解決程式庫開發人員面臨的相容性問題。 應用程式直接載入的程式庫,不論是透過直接參考或是呼叫 Assembly.Load,都會繼續使用它所載入環境的 AppDomain 執行階段。 您應該針對所有您想要支援的 .NET Framework 版本測試程式庫。 如果使用 .NET Framework 4 運行時間編譯應用程式,但包含使用舊版運行時間建置的連結庫,該連結庫也會使用 .NET Framework 4 運行時間。 不過,如果您有使用舊版運行時間建置的應用程式,以及使用 .NET Framework 4 建置的連結庫,則必須強制應用程式也使用 .NET Framework 4 (請參閱 案例 3)。
管理型 COM 元件開發人員。 在過去,受控 COM 元件會自動使用計算機上安裝的最新版本執行階段運行。 您現在可以針對其所建置的運行時間版本執行 COM 元件。
如下表所示,使用 .NET Framework 1.1 版建置的元件可以與 4 版元件並存執行,但無法搭配 2.0、3.0 或 3.5 版元件執行,因為這些版本無法使用並存裝載。
.NET Framework 版本 1.1 2.0 - 3.5 4 1.1 不適用 否 是的 2.0 - 3.5 否 不適用 是的 4 是的 是的 不適用
備註
.NET Framework 3.0 和 3.5 版是以累加方式建置在 2.0 版上,不需要並存執行。 這些本質上是相同的版本。
常見的併排主機情境
案例 1: 使用以舊版 .NET Framework 建置的 COM 元件的原生應用程式。
已安裝 .NET Framework 版本:COM 元件所使用的 .NET Framework 4 和其他所有 .NET Framework 版本。
該怎麼辦:在此案例中,不執行任何動作。 COM 元件將會使用註冊的 .NET Framework 版本來執行。
案例 2:使用 .NET Framework 2.0 SP1 建置的受控應用程式,您想要使用 .NET Framework 2.0 執行,但如果 2.0 版不存在,則願意在 .NET Framework 4 上執行。
已安裝 .NET Framework 版本:舊版 .NET Framework 和 .NET Framework 4。
該怎麼做:在應用程式 目錄的應用程式設定檔 中,使用
<startup>元素 和<supportedRuntime>元素 集合如下:<configuration> <startup > <supportedRuntime version="v2.0.50727" /> <supportedRuntime version="v4.0" /> </startup> </configuration>案例 3: 使用以舊版 .NET Framework 建置的 COM 元件的原生應用程式,您想要使用 .NET Framework 4 執行。
已安裝 .NET Framework 版本:.NET Framework 4。
作法:在應用程式目錄中的應用程式組態檔中,使用
<startup>元素,其useLegacyV2RuntimeActivationPolicy屬性設定為true,以及以下設定的<supportedRuntime>元素:<configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" /> </startup> </configuration>
範例
以下範例展示如何使用元件編譯時所用的 .NET Framework 版本,讓一個非管理的 COM 主機運行管理的 COM 元件。
若要執行下列範例,請使用 .NET Framework 3.5 編譯並註冊下列 Managed COM 元件。 若要註冊元件,請按兩下 [ 專案 ] 功能表上的 [ 屬性],按兩下 [ 建 置] 索引標籤,然後選取 [ 註冊 COM Interop ] 複選框。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace BasicComObject
{
[ComVisible(true), Guid("9C99C4B5-CA54-4c58-8988-49B6811BA53B")]
public class MyObject : SimpleObjectModel.IPrintInfo
{
public MyObject()
{
}
public void PrintInfo()
{
Console.WriteLine("MyObject was activated in {0} runtime in:\n\tAppDomain {1}:{2}", System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion(), AppDomain.CurrentDomain.Id, AppDomain.CurrentDomain.FriendlyName);
}
}
}
編譯下列 Unmanaged C++應用程式,以啟動上一個範例所建立的 COM 物件。
#include "stdafx.h"
#include <string>
#include <iostream>
#include <objbase.h>
#include <string.h>
#include <process.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
char input;
CoInitialize(NULL) ;
CLSID clsid;
HRESULT hr;
HRESULT clsidhr = CLSIDFromString(L"{9C99C4B5-CA54-4c58-8988-49B6811BA53B}",&clsid);
hr = -1;
if (FAILED(clsidhr))
{
printf("Failed to construct CLSID from String\n");
}
UUID id = __uuidof(IUnknown);
IUnknown * pUnk = NULL;
hr = ::CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,id,(void **) &pUnk);
if (FAILED(hr))
{
printf("Failed CoCreateInstance\n");
}else
{
pUnk->AddRef();
printf("Succeeded\n");
}
DISPID dispid;
IDispatch* pPrintInfo;
pUnk->QueryInterface(IID_IDispatch, (void**)&pPrintInfo);
OLECHAR FAR* szMethod[1];
szMethod[0]=OLESTR("PrintInfo");
hr = pPrintInfo->GetIDsOfNames(IID_NULL,szMethod, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
DISPPARAMS dispparams;
dispparams.cNamedArgs = 0;
dispparams.cArgs = 0;
VARIANTARG* pvarg = NULL;
EXCEPINFO * pexcepinfo = NULL;
WORD wFlags = DISPATCH_METHOD ;
;
LPVARIANT pvRet = NULL;
UINT * pnArgErr = NULL;
hr = pPrintInfo->Invoke(dispid,IID_NULL, LOCALE_USER_DEFAULT, wFlags,
&dispparams, pvRet, pexcepinfo, pnArgErr);
printf("Press Enter to exit");
scanf_s("%c",&input);
CoUninitialize();
return 0;
}