Внутрипроцессное параллельное выполнение

Начиная с .NET Framework 4, разработчики могут использовать внутрипроцессное параллельное размещение для запуска нескольких версий среды CLR в одном процессе. Управляемые COM-компоненты по умолчанию выполняются в той версии платформы .NET Framework, в которой они были созданы, вне зависимости от загруженной для процесса версии .NET Framework.

Общие сведения

Платформа .NET Framework всегда предоставляла возможность параллельного размещения для приложений с управляемым кодом, но до появления версии .NET Framework 4 эта функция не была доступна для управляемых 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 Нет данных No Да
    2.0 - 3.5 No Нет данных Да
    4 Да Да Неприменимо

Примечание.

Версии платформы .NET Framework 3.0 и 3.5 созданы с помощью инкрементального построения на базе версии 2.0 и не требуют параллельного запуска. По сути они представляют собой одну и ту же версию.

Общие сценарии параллельного размещения

  • Сценарий 1. Собственное приложение, которое использует COM-компоненты, созданные в более ранних версиях платформы .NET Framework.

    платформа .NET Framework версии, установленные: платформа .NET Framework 4 и все остальные версии платформа .NET Framework, используемые com-компонентами.

    Необходимые действия: в этой ситуации не следует предпринимать никаких действий. COM-компоненты будут выполняться в той версии платформы .NET Framework, в которой они были зарегистрированы.

  • Сценарий 2. Управляемое приложение, созданное с помощью платформа .NET Framework 2.0 с пакетом обновления 1 (SP1), которое вы предпочитаете запускать с платформа .NET Framework 2.0, но готовы работать на платформа .NET Framework 4, если версия 2.0 отсутствует.

    платформа .NET Framework версии, установленные: более ранняя версия платформа .NET Framework и платформа .NET Framework 4.

    Что делать: в файле конфигурации приложения в каталоге приложения используйте <элемент запуска> и поддерживаемый< набор элементовRuntime> следующим образом:

    <configuration>  
      <startup >  
        <supportedRuntime version="v2.0.50727" />  
        <supportedRuntime version="v4.0" />  
      </startup>  
    </configuration>  
    
  • Сценарий 3. Собственное приложение, использующее com-компоненты, созданные с более ранними версиями платформа .NET Framework, которые требуется запустить с помощью платформа .NET Framework 4.

    платформа .NET Framework версии, установленные: платформа .NET Framework 4.

    Необходимые действия: откройте файл конфигурации приложения в каталоге приложения и используйте элемент <startup>, атрибут useLegacyV2RuntimeActivationPolicy которого имеет значение true, и набор элементов <supportedRuntime> следующим образом:

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

Пример

В следующем примере показан неуправляемый узел COM, в котором управляемый COM-компонент выполняется с помощью версии платформы .NET Framework, для которой был предназначен данный компонент.

Чтобы выполнить следующий пример, скомпилируйте и зарегистрируйте следующий управляемый COM-компонент с помощью платформа .NET Framework 3.5. Чтобы зарегистрировать компонент, в меню Проект выберите пункт Свойства, перейдите на вкладку Сборка, а затем установите флажок Регистрация для COM-взаимодействия.

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);  
        }  
    }  
}  

Скомпилируйте следующее неуправляемое приложение 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;  
}  

См. также