비고
이 문서는 .NET Framework에만 적용됩니다. .NET 6 이상 버전을 포함하여 .NET의 최신 구현에는 적용되지 않습니다.
.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의 런타임을 계속 사용합니다. 지원하려는 모든 버전의 .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 버전: .NET Framework 4 및 COM 구성 요소에서 사용하는 .NET Framework의 다른 모든 버전.
수행할 작업: 이 시나리오에서는 아무 작업도 수행하지 않습니다. COM 구성 요소는 등록된 .NET Framework 버전으로 실행됩니다.
시나리오 2: .NET Framework 2.0으로 실행하는 것이 좋지만 버전 2.0이 없는 경우 .NET Framework 4에서 실행하려는 .NET Framework 2.0 SP1을 사용하여 빌드된 관리되는 애플리케이션입니다.
설치된 .NET Framework 버전: 이전 버전의 .NET Framework 및 .NET Framework 4.
수행할 작업: 애플리케이션 디렉터리의 애플리케이션 구성 파일에서 시작< 요소와 supportedRuntime 요소를 다음과 같이 사용합니다>.<>
<configuration> <startup > <supportedRuntime version="v2.0.50727" /> <supportedRuntime version="v4.0" /> </startup> </configuration>
시나리오 3: .NET Framework 4로 실행하려는 이전 버전의 .NET Framework로 빌드된 COM 구성 요소를 사용하는 네이티브 애플리케이션입니다.
설치된 .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를 사용하여 다음 관리되는 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);
}
}
}
다음 관리되지 않는 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;
}
참고하십시오
.NET