의 Registration-Free 활성화NET-Based 구성 요소: 연습
스티브 화이트
개발자를 위한 프리미어 지원, Microsoft UK
레슬리 뮬러
글로벌 IT 리서치 & 개발, 크레디트 스위스 퍼스트 보스턴
2005년 7월
요약: Microsoft Platform SDK는 격리된 애플리케이션 및 병렬 어셈블리항목을 문서화하는 훌륭한 작업을 수행합니다. 그러나 모든 사용자가 이 항목을 COM 구성 요소의 등록 없는 활성화와 동일시하는 것은 아닙니다. 등록이 없는 COM은 잠긴 서버와 공유 인프라에서 격리된 애플리케이션이 있는 기업에 큰 관심을 갖는 플랫폼 기능입니다. 이 문서에서는 COM interop을 통해 네이티브 클라이언트가 .NET Framework 기반 구성 요소를 등록하지 않은 활성화의 작업 예제를 안내합니다. (11페이지 인쇄)
적용 대상:
Microsoft Windows Server 2003
Microsoft Windows XP 서비스 팩 2
Microsoft .NET Framework 버전 1.1
Microsoft Visual Studio .NET 2003
Microsoft Visual Basic 6.0
이 문서와 함께 제공되는 샘플을 다운로드합니다. MSDNRegFreeNet.msi.
콘텐츠
소개
Registration-Free COM 용어
샘플 실행
COM 서버로 .NET 어셈블리 빌드
클라이언트 빌드
Registration-Free 활성화
문제 해결
결론
추가 읽기
소개
등록이 없는 COM은 Microsoft Windows XP(.NET Framework 기반 구성 요소용 SP2) 및 Microsoft Windows Server 2003 플랫폼에서 사용할 수 있는 메커니즘입니다. 이름에서 알 수 있듯이 이 메커니즘을 사용하면 COM 구성 요소를 등록할 필요 없이 컴퓨터에 쉽게(예: XCOPY) 배포할 수 있습니다.
대상 플랫폼에서 프로세스 및 종속 모듈을 초기화하는 단계 중 하나는 연결된 매니페스트 파일을활성화 컨텍스트메모리 구조로 로드하는 것입니다. 해당 레지스트리 항목이 없는 경우 COM 런타임에 필요한 바인딩 및 활성화 정보를 제공하는 활성화 컨텍스트입니다. 활성화 컨텍스트 API사용하여 직접 활성화 컨텍스트를 빌드하여 파일 사용을 중단하도록 선택하지 않는 한 COM 서버 또는 클라이언트에는 특별한 코드가 필요하지 않습니다.
이 연습에서는 간단한 .NET 어셈블리를 빌드하고 Visual C++ 및 Visual Basic 6.0으로 작성된 네이티브 COM 클라이언트에서 등록 및 등록되지 않은 어셈블리를 사용합니다. 소스 코드와 샘플을 다운로드하여 즉시 작동 중인 것을 확인하거나 연습과 함께 따라 단계별로 빌드할 수 있습니다.
Registration-Free COM 용어
.NET 기술에 익숙한 사용자는 어셈블리라는 용어에 익숙할, 집합을 정의하는 매니페스트 포함하는 하나의 모듈을 사용하여 하나의 모듈로 배포되고 명명되고 버전이 지정된 하나 이상의 모듈 집합을 의미합니다. 등록이 없는 COM에서 어셈블리 및
등록이 없는 COM은 어셈블리 사용하여 하나 이상의 PE 모듈(예: 네이티브 또는 관리됨) 집합을 하나의 단위로 배포, 명명 및 버전을 지정합니다. 등록이 없는 COM은 매니페스트 사용하여 XML이 포함된 .manifest 확장명의 텍스트 파일을 참조합니다. 이 파일은 클래스의 바인딩 및 활성화 세부 정보와 함께 어셈블리(어셈블리 매니페스트)의 ID를 정의하거나 하나 이상의 어셈블리 ID 참조와 함께 애플리케이션(애플리케이션 매니페스트)의 ID를 정의합니다. 어셈블리 매니페스트 파일의 이름은 어셈블리이고 애플리케이션 매니페스트 파일의 이름은 애플리케이션에 지정됩니다.
샘플 실행
샘플 코드를 다운로드하고 추출한 후 \deployed
COM 서버로 .NET 어셈블리 빌드
1단계
C# 코드
using System;
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: Guid("[LIBID_SideBySide]")]
namespace SideBySide
{
[Guid("[IID_ISideBySideClass]")]
public interface ISideBySideClass
{
string Version();
}
[Guid("[CLSID_SideBySideClass]")]
public class SideBySideClass : ISideBySideClass
{
public string Version()
{
return "1.0.0-C#";
}
}
}
Visual Basic .NET 코드
Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: Guid("[LIBID_SideBySide]")>
<Guid("[IID_ISideBySideClass]")> _
Public Interface ISideBySideClass
Function Version() As String
End Interface
<Guid("[CLSID_SideBySideClass]")> _
Public Class SideBySideClass
Implements ISideBySideClass
Function Version() As String Implements ISideBySideClass.Version
Version = "1.0.0-VB.NET"
End Function
End Class
프로젝트에 특정할 GUID 값을 자리 표시자 형태로 작성했습니다. guidgen 도구를 사용하여 이후에 자리 표시자를 사용할 때 의도할 각 값이 되는 고유한 GUID를 생성해야 합니다.
2단계
형식 라이브러리가 생성되고 빌드 시 등록되도록 프로젝트의 COM Interop 등록 설정을 true로 설정합니다.
3단계
릴리스 빌드를 생성하고
클라이언트 빌드
다음 단계는 클라이언트를 빌드하는 것이며 이 연습에서는 Visual C++ 또는 Visual Basic 6.0 클라이언트를 빌드할 수 있습니다.
4단계(옵션 A: Visual C++)
SideBySide 프로젝트 폴더를 기준으로 형제 폴더에 클라이언트라는 새 Visual C++ Win32 콘솔 프로젝트 만듭니다. Win32 애플리케이션 마법사애플리케이션 설정 탭에서 ATL 지원 추가 확인란을 선택합니다.
stdafx.h 편집하고 파일 맨 위에 다음 줄을 #pragma once
바로 다음에 추가합니다.
#define _WIN32_DCOM
또한 stdafx.h 파일 아래쪽에 다음 줄을 추가합니다.
import "[path]\SideBySide.tlb" no_namespace
여기서 [path]SideBySide 어셈블리를 빌드할 때 생성된 형식 라이브러리의 상대 경로여야 합니다. 이 경로는 일반적으로 1단계에서 C# 또는 Visual Basic .NET 프로젝트를 선택했는지에 따라 달라집니다.
client.cpp 내용을 다음 코드로 바꿉니다.
#include "stdafx.h"
#include <iostream>
using namespace std;
void ErrorDescription(HRESULT hr)
{
TCHAR* szErrMsg;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&szErrMsg, 0, NULL) != 0)
{
cout << szErrMsg << endl;
LocalFree(szErrMsg);
}
else
cout << "Could not find a description for error 0x"
<< hex << hr << dec << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitializeEx(0, COINIT_MULTITHREADED);
{
ISideBySideClassPtr ptr;
HRESULT hr =
ptr.CreateInstance(__uuidof(SideBySideClass));
if (SUCCEEDED(hr))
{
cout << ptr->Version() << endl;
}
ErrorDescription(hr);
char c;
cin >> c;
}
CoUninitialize();
return 0;
}
릴리스 빌드를 생성하고
4단계(옵션 B: Visual Basic 6.0)
새 Visual Basic 6.0 Standard EXE 프로젝트를 만듭니다.
프로젝트 탐색기에서Project1 노드를 선택하고 속성 창이름을 클라이언트변경합니다.
파일 선택 | Project As 저장하고 양식 파일과 프로젝트 파일을 SideBySide 프로젝트 폴더를 기준으로 형제 폴더에 저장합니다.
양식 디자이너에서 기본 양식을 두 번 클릭하고 Sub Form_Load()내부에 다음 코드를 붙여넣습니다.
Dim obj As New SideBySideClass
Dim isxs As SideBySide.ISideBySideClass
Set isxs = obj
MsgBox isxs.Version()
5단계
현재 \deployed 폴더에는 일부 중간 파일을 제외하고 client.exe 및 SideBySide.dll; 후자는 빌드 프로세스에 의해 등록됩니다. 이러한 정상적인 상황에서 서버와 클라이언트가 함께 작동하는지 확인하려면 \deployed\client.exe 실행하고 예상 출력 "1.0.0-C#" 또는 "1.0.0-VB.NET"을 기록해 둡니다.
6단계
이 연습은 등록이 없는 COM에 관한 것이므로 이제 SideBySide 어셈블리의 등록을 취소해야 합니다. Visual Studio 2003 명령 프롬프트에서 \deployed 폴더로 이동하여 regasm /u SideBySide.dll
명령을 실행합니다.
7단계
이전 단계의 영향을 확인하려면 \deployed\client.exe 다시 실행하면 "클래스가 등록되지 않음" 또는 "런타임 오류 '429': ActiveX 구성 요소가 개체를 만들 수 없습니다."라는 메시지가 표시됩니다. 이 단계에서는 COM 런타임이 레지스트리에서 필요한 정보를 찾지 못해 좌절했지만 대체 방법으로 정보를 사용할 수 있도록 아직 지정하지 않았습니다. 다음 단계에서 이를 해결할 것입니다.
Registration-Free 활성화
8단계
\deployed
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type = "win32"
name = "client"
version = "1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="SideBySide"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>
9단계
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type="win32"
name=" SideBySide"
version="1.0.0.0" />
<clrClass
clsid="{[CLSID_SideBySideClass]}"
progid="SideBySide.SideBySide"
threadingModel="Both"
name="SideBySide.SideBySideClass" >
</clrClass>
</assembly>
다음 작업은 위의 어셈블리 매니페스트 파일을 SideBySide 어셈블리에 Win32 리소스로 포함하는 것입니다. 작성 당시에는 Windows XP에 필수이지만 Windows Server 2003에는 필수가 아닙니다. Windows Server 2003에서는 어셈블리와 함께 어셈블리 매니페스트 파일을 배포하기만 하면
10단계
#include <windows.h>
#define MANIFEST_RESOURCE_ID 1
MANIFEST_RESOURCE_ID RT_MANIFEST SideBySide.manifest
windows.h 파일 및 종속성은 플랫폼 SDK(Core SDK 섹션) 또는 Visual C++를 설치할 때 사용할 수 있습니다. 여기에 필요한 windows.h 부분은 정의입니다.
#define RT_MANIFEST 24
따라서 SideBySide.rc의 내용은 다음으로 확인될 있습니다.
1 24 SideBySide.manifest
그러나 매크로 정의를 지시대로 사용하는 것이 더 명확하고 일반적입니다.
11단계
SideBySide 프로젝트의 폴더에서 빌드 명령 파일(텍스트 파일)을 만들고 build.cmd호출합니다. 다음을 파일에 붙여넣습니다.
C#을 빌드하려면:
rc SideBySide.rc
csc /t:library /out:..\deployed\SideBySide.dll
/win32res:SideBySide.res Class1.cs
Visual Basic .NET을 빌드하려면:
rc SideBySide.rc
vbc /t:library /out:..\deployed\SideBySide.dll
/win32resource:SideBySide.res /rootnamespace:SideBySide Class1.vb
이러한 명령은 먼저 플랫폼 SDK(rc.exe)에서 Microsoft Windows 리소스 컴파일러 도구를 호출하여 10단계의 리소스 정의 스크립트를 SideBySide.res컴파일된 리소스 파일로 컴파일하는 것입니다. 다음으로, C# 또는 Visual Basic .NET 컴파일러를 호출하여 소스 코드 파일을 어셈블리에 빌드하고 컴파일된 리소스 파일을 Win32 리소스로 포함합니다. 컴파일된 어셈블리는
12단계
Visual Studio 2003 명령 프롬프트에서 SideBySide 프로젝트의 폴더로 이동하여 build
명령을 실행합니다.
13단계
매니페스트 파일의 제공으로 클라이언트가 COM interop을 통해 SideBySideClass 클래스를 다시 한 번 활성화하고, \deployed\client.exe 실행하고, 예상 출력 "1.0.0-C#" 또는 "1.0.0-VB.NET"을 확인할 수 있습니다.
문제 해결
앞에서 살펴본 것처럼 .NET Framework 기반 구성 요소의 등록 없는 활성화에는 서버 또는 클라이언트에 특별한 코드가 필요하지 않습니다. 일치하는 매니페스트 파일 쌍만 있으면 됩니다. 그 중 하나는 RT_MANIFEST 형식의 Win32 리소스로 .NET 어셈블리에 포함됩니다.
이 연습과 같은 방식으로 등록이 없는 개발에 접근하는 것이 좋습니다. 특히: 먼저 클라이언트가 등록된 서버로 작업하는 것을 확인하여 알려진 상태로 이동합니다. 그런 다음 서버 등록을 취소하고 오류 메시지가 예상한 것인지 확인합니다. 마지막으로 매니페스트 파일을 만들고 배포하여 상황을 해결합니다. 이렇게 하면 등록이 없는 활성화와 관련된 문제 해결 작업이 매니페스트 파일의 구조와 어셈블리 매니페스트의 올바른 포함으로 제한됩니다.
등록이 없는 COM 문제를 해결할 때 Windows Server 2003의 이벤트 뷰어는 친구입니다. Windows XP 또는 Windows Server 2003에서 구성 오류를 감지하면 일반적으로 시작한 애플리케이션에 대한 오류 메시지 상자와 "애플리케이션 구성이 올바르지 않아 이 응용 프로그램을 시작하지 못했습니다. 애플리케이션을 다시 설치하면 이 문제가 해결 될 수 있습니다." 이 메시지가 표시되면 Windows Server 2003에서 문제를 재현할 때마다 시스템 이벤트 로그를 참조하고 SideBySide 원본에서 이벤트를 찾는 것이 좋습니다. 이러한 경우 XP의 이벤트 로그를 살펴보지 않는 이유는 "[path]\[application filename]에 대한 활성화 컨텍스트 생성 실패"와 같은 메시지가 변함없이 포함되기 때문입니다. 나타나다. 참조 오류 메시지: 작업이 성공적으로 완료되었습니다." 이는 문제를 식별하는 데 도움이 되지 않습니다.
매니페스트 파일의 구조로 이동하기 전에 Win32 리소스에 대해 살펴보겠습니다. 위에서 설명한 것처럼 windows.h RT_MANIFEST 기호를 24 값으로 정의합니다. 이는 운영 체제가 포함된 매니페스트 파일로 인식할 값입니다. 리소스 정의 스크립트(.rc 파일)에 windows.h 포함하는 것을 잊어버린 경우 빌드는 여전히 성공하며 매니페스트 파일은 여전히 리소스로 포함되지만 올바른 형식은 아닙니다. 매니페스트를 올바르게 포함했는지 확인하려면 Visual Studio에서 SideBySide.dll 엽니다(파일 | |열기 파일...). 모듈 내의 리소스를 보여 주는 트리 보기가 표시됩니다. 루트 노드 아래에는 매니페스트 리소스의 리소스 번호를 보여 주는 다른 노드(연습의 1)여야 하는 RT_MANIFEST 노드가 있어야 합니다. 이 마지막 노드를 두 번 클릭하여 이진 보기에서 데이터를 보고 XML 매니페스트 파일과 유사한지 빠르게 확인합니다. 이진이지만 ASCII 범위의 문자는 분명합니다. 이진 데이터가 없거나 올바르지 않은 경우 리소스 정의 스크립트(.rc 파일)가 매니페스트 파일을 참조하는지 확인합니다. RT_MANIFEST 노드의 텍스트가 따옴표로 묶인 경우 리소스 정의 스크립트(.rc 파일)에 windows.h 포함하는 것을 잊어버렸을 수 있습니다.
방금 언급한 각 오류는 Windows Server 2003 시스템 이벤트 로그에 "종속 어셈블리 [이름]을 찾을 수 없으며 마지막 오류가 참조된 어셈블리가 시스템에 설치되지 않았습니다."라는 메시지와 함께 보고됩니다.
다양한 매니페스트 파일의 스키마는 매니페스트 파일 참조
등록이 없는 COM 의미에서 어셈블리어셈블리 매니페스트 파일의 내용을 통해 하나 이상의 물리적 파일을 연결하는 추상적인 아이디어입니다.
assemblyIdentity 요소는 어셈블리ID를 정의합니다. 때문에. NET 기반 구성 요소의 이름 특성은 .NET 어셈블리의 이름과 일치해야 하므로 파일 이름과 일치해야 합니다. 그렇지 않으면 Windows Server 2003 시스템 이벤트 로그에 다음 메시지가 표시됩니다. "종속 어셈블리 [이름 특성 값]을 찾을 수 없으며 마지막 오류는 참조된 어셈블리가 시스템에 설치되지 않았습니다." 그러나 버전 특성은 .NET 어셈블리의 AssemblyVersion및 AssemblyFileVersion일치하지 않아도 되지만, 일관성을 적용하는 것이 좋습니다.
clrClass 요소에는 이름 및 clsid두 개의 필수 특성만 있습니다. 이름 특성 활성화되는 CLR 클래스의 결합된 네임스페이스 및 클래스 이름과 일치해야 합니다. 그렇지 않은 경우 CoCreateInstance는 값이 COR_E_TYPELOAD(0x80131522)인 HRESULT를 반환합니다. 그러면 형식 로더가 .NET 어셈블리에서 요청된 CLR 형식을 찾지 못할 때 System.TypeLoadException이 throw됩니다. .NET 어셈블리가 Visual Basic .NET으로 작성된 경우 주의해야 할 한 가지 사항은 명령줄의 /rootnamespace 스위치를 Visual Basic .NET 컴파일러(vbc.exe)에 제공하는 것입니다. clsid 특성 guidAttribute를 통해 활성화되는 CLR 클래스에 할당된 CLSID와 일치해야 합니다. 그렇지 않은 경우 CoCreateInstance는 "클래스가 등록되지 않음"인 메시지 텍스트인 REGDB_E_CLASSNOTREG(0x80040154) 값이 있는 HRESULT를 반환합니다.
이제 애플리케이션 매니페스트 파일에 주의를 기울이겠습니다. 예를 들어 8단계를 다시 살펴보세요. 애플리케이션 매니페스트
애플리케이션 매니페스트에서 가장 중요한 요소는 dependentAssembly/assemblyIdentity 요소입니다. 이 요소는 어셈블리 매니페스트에 있는 동일한 요소에 대한 참조이며 두 요소는 정확히
결론
등록이 없는 COM은 WINDOWS 레지스트리에 대한 종속성에서 COM 구성 요소를 해제하고 따라서 해당 구성 요소를 사용하는 애플리케이션이 전용 서버를 요구하지 않도록 하는 기술입니다. 이를 통해 동일한 COM 구성 요소의 여러 버전에 종속된 애플리케이션이 인프라를 공유하고 이러한 다양한 COM 구성 요소 버전을 .NET 버전 관리 및 배포 메커니즘의 에코에 나란히 로드할 수 있습니다.
이 문서에서는 Visual C++ 및 Visual Basic 6.0으로 작성된 네이티브 클라이언트 애플리케이션에서 .NET Framework 기반 구성 요소의 등록이 없는 활성화에 대한 데모를 안내했습니다. 메커니즘이 작동하는 방법 중 일부를 설명하고 몇 가지 가능한 구성 오류와 문제를 해결하는 방법에 밑줄을 그어 줍니다.
추가 읽기
- COM 구성 요소의 Registration-Free 활성화: 연습
- 격리된 애플리케이션 및 side-by-side 어셈블리
- 매니페스트 파일 스키마
- 활성화 컨텍스트 API 사용하여
작성자 정보
Steve White Microsoft UK의 프리미어 개발자 지원 팀에서 일하는 애플리케이션 개발 컨설턴트입니다. Visual C#, Windows Forms 및 ASP.NET 사용하여 개발하는 고객을 지원합니다. 그의 블로그 음악, 시각화 및 프로그래밍에 대한 그의 관심사에 대한 자세한 정보를 제공합니다.
레슬리 뮬러 신용 스위스 퍼스트 보스턴에서 연구 & 개발 팀과 기술자입니다. Leslie는 금융 서비스, 기술 신생 기업, 산업 자동화 및 방어와 같은 환경에서 일하면서 개발자 및 기술 설계자로서 12 년의 경험을 가지고 있습니다. 프로그래밍을 하거나 연구를 하지 않을 때 그는 스키, 아이스 하키를 즐기고, 가능하면 아이슬란드나 로키산과 같은 극단적인 환경에서 전동 차량으로 약간 미친 짓을 합니다.