同處理序並存執行

注意

本文專屬於 .NET Framework。 其不適用於較新的 .NET 實作,包括 .NET 6 和更新版本。

從 .NET Framework 4 開始,您可以使用同處理序並存裝載,在單一處理序中執行多個 Common Language Runtime (CLR) 版本。 根據預設,Managed COM 元件會與建置它們的 .NET Framework 版本一起執行,不論針對程序所載入的 .NET Framework 版本為何。

背景

.NET Framework 一律會提供受控碼應用程式的並存裝載,但在 .NET Framework 4 之前,並未針對受控 COM 元件提供該功能。 過去,載入至程序的 Managed 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)。

  • Managed COM 元件開發人員。 過去,會使用電腦上所安裝的最新執行階段版本來自動執行 Managed COM 元件。 您現在可以針對建置它們的執行階段版本執行 COM 元件。

    如下表所示,使用 .NET Framework 1.1 版所建置的元件可以與第 4 版元件並存執行,但它們無法與 2.0、3.0 或 3.5 版元件一起執行,因為這些版本無法使用並存裝載。

    .NET Framework 版本 1.1 2.0 - 3.5 4
    1.1 不適用 No Yes
    2.0 - 3.5 No 不適用 Yes
    4 Yes 不適用

注意

.NET Framework 3.0 和 3.5 版是根據 2.0 版透過累加方式所建置,不需要並存執行。 這些本質上是相同的版本。

常見並存裝載案例

  • 情節 1:使用舊版 .NET Framework 所建置之 COM 元件的原生應用程式。

    已安裝的 .NET Framework 版本:.NET Framework 4 以及 COM 元件所使用的所有其他 .NET Framework 版本。

    處理方式:在此情節中,不執行任何動作。 COM 元件會與註冊它們的 .NET Framework 版本一起執行。

  • 情節 2:您想透過 .NET Framework 2.0 執行使用 .NET Framework 2.0 SP1 建置的受控應用程式,但也願意在 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> 項目與設為 trueuseLegacyV2RuntimeActivationPolicy 屬性以及設定如下的 <supportedRuntime> 項目:

    <configuration>
      <startup useLegacyV2RuntimeActivationPolicy="true">
        <supportedRuntime version="v4.0" />
      </startup>
    </configuration>
    

範例

下列範例示範執行 Managed COM 元件的 Unmanaged COM 主機,方法是使用編譯元件使用的 .NET Framework 版本。

若要執行下列範例,請編譯並註冊下列使用 .NET Framework 3.5 的受控 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;
}

另請參閱