COM 구성 요소의 Registration-Free 활성화: 연습
스티브 화이트
개발자를 위한 프리미어 지원, Microsoft UK
레슬리 뮬러
글로벌 IT 리서치 & 개발, 크레디트 스위스 퍼스트 보스턴
2005년 7월
요약: Microsoft Platform SDK는 격리된 애플리케이션 및 병렬 어셈블리항목을 문서화하는 훌륭한 작업을 수행합니다. 그러나 모든 사용자가 이 항목을 COM 구성 요소의 등록 없는 활성화와 동일시하는 것은 아닙니다. 등록이 없는 COM은 잠긴 서버와 공유 인프라에서 격리된 애플리케이션이 있는 기업에 큰 관심을 갖는 플랫폼 기능입니다. 이 문서에서는 네이티브 클라이언트 및 COM interop을 통해 관리되는 클라이언트에서 네이티브 COM 구성 요소를 등록하지 않은 활성화의 작업 예제를 안내합니다. (인쇄된 페이지 18개)
적용 대상:
Microsoft Windows Server 2003
Microsoft Windows XP
Microsoft .NET Framework 버전 1.1
Microsoft Visual Studio .NET 2003
Microsoft Visual Studio 6.0
이 문서와 함께 제공되는 샘플을 다운로드합니다. MSDNRegFreeCOM.msi.
목차
소개
Registration-Free COM 용어
샘플 실행
Visual C++ COM 서버 빌드
C++/.NET 클라이언트 빌드
Registration-Free 활성화
Visual Basic 6.0 COM 서버 및 클라이언트
호환되지 않는 아파트
활성화 컨텍스트 API 사용
문제 해결
결론
추가 읽기
소개
등록이 없는 COM은 Microsoft Windows XP(SP2 for .)에서 사용할 수 있는 메커니즘입니다. NET 기반 구성 요소) 및 Microsoft Windows Server 2003 플랫폼. 이름에서 알 수 있듯이 이 메커니즘을 사용하면 COM 구성 요소를 등록할 필요 없이 컴퓨터에 쉽게 배포할 수 있습니다(예: XCOPY 사용).
대상 플랫폼에서 프로세스 및 종속 모듈을 초기화하는 단계 중 하나는 연결된 매니페스트 파일을활성화 컨텍스트메모리 구조로 로드하는 것입니다. 해당 레지스트리 항목이 없는 경우 COM 런타임에 필요한 바인딩 및 활성화 정보를 제공하는 활성화 컨텍스트입니다. 활성화 컨텍스트 API사용하여 직접 활성화 컨텍스트를 빌드하여 파일 사용을 중단하도록 선택하지 않는 한 COM 서버 또는 클라이언트에는 특별한 코드가 필요하지 않습니다.
이 연습에서는 간단한 네이티브 COM 구성 요소를 빌드하고 네이티브 및 관리되는 클라이언트에서 등록 및 등록되지 않은 구성 요소를 사용합니다. 구성 요소와 네이티브 클라이언트는 Visual C++ 및 Visual Basic 6.0에 모두 표시됩니다. 관리되는 클라이언트는 C# 및 Visual Basic .NET에 모두 표시됩니다. 소스 코드와 샘플을 다운로드하여 즉시 작동 중인 것을 확인하거나 연습과 함께 따라 단계별로 빌드할 수 있습니다.
Registration-Free COM 용어
.NET Framework 기술에 익숙한 사용자는 집합을 정의하는 매니페스트 포함하는 하나의 모듈을 사용하여 단위로 배포, 명명 및 버전이 지정된 하나 이상의 모듈 집합을 나타내는 어셈블리용어에 익숙할 것입니다. 등록이 없는 COM에서 어셈블리 및
등록이 없는 COM은 어셈블리 사용하여 하나 이상의 PE 모듈(예: 네이티브 또는 관리됨) 집합을 하나의 단위로 배포, 명명 및 버전 관리됨을 의미합니다. 등록이 없는 COM은 매니페스트 사용하여 XML을 포함하는 .manifest 확장이 있는 텍스트 파일을 참조합니다. 이 파일은 클래스의 바인딩 및 활성화 세부 정보와 함께 어셈블리(어셈블리 매니페스트)의 ID를 정의하거나 하나 이상의 어셈블리 ID 참조와 함께 애플리케이션(애플리케이션 매니페스트)의 ID를 정의합니다. 어셈블리 매니페스트 파일의 이름은 어셈블리이고 애플리케이션 매니페스트 파일의 이름은 애플리케이션에 지정됩니다.
샘플 실행
샘플 코드를 다운로드하고 추출한 후 \deployed
Visual C++ COM 서버 빌드
1단계
첫 번째 단계는 COM 서버를 빌드하는 것입니다. Visual Studio에서 새 Visual C++ ATL 프로젝트를 만들고 SideBySide
솔루션 탐색기에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭하고 |을 선택합니다. 클래스 추가.... ATL Simple Object 선택하고 열기선택합니다. 클래스에 SideBySideClass 짧은 이름을 지정하고 마침클릭합니다.
클래스 뷰에서 ISideBySideClass 노드를 마우스 오른쪽 단추로 클릭하고 추가 | 선택 메서드 추가.... 메서드 추가 마법사에서 버전 메서드 이름으로 입력하고, BSTR*의 매개 변수 형식을 선택하고, pVer 매개 변수 이름으로 입력하고, 유효성 재검사 확인란을 선택한 다음, 추가한 다음 마침클릭합니다.
클래스 뷰에서 CSideBySideClass 노드를 확장하고 Version 메서드를 두 번 클릭합니다. //TODO 줄을 다음으로 바꿉다.
*pVer = SysAllocString(L"1.0.0-CPP");
릴리스 빌드를 생성하고
C++/.NET 클라이언트 빌드
다음 단계는 클라이언트를 빌드하는 것입니다. 연습의 이 부분에서는 Visual C++ COM 서버에 대한 Visual C++ 또는 .NET 클라이언트를 빌드할 수 있는 옵션이 있습니다. 말할 필요도 없이 Visual C++, Visual Basic 6.0 및 .NET으로 작성된 클라이언트와 서버를 혼합하고 일치시킬 수 있습니다. 이렇게 하려면 샘플이 함께 작동하도록 수정하는 간단한 샘플을 찾을 수 있습니다. 클라이언트 및 서버 집합은 as-is작동하는 코드를 표시하기 위해 이 연습에서와 같이 구성됩니다.
2단계(옵션 A: Visual C++)
SideBySide 프로젝트의 폴더를 기준으로 형제 폴더에 클라이언트라는 새 Visual C++ Win32 콘솔 프로젝트를 만듭니다. Win32 애플리케이션 마법사의 애플리케이션 설정 탭에서 ATL 지원 추가 확인란을 선택합니다.
stdafx.h 편집하고 파일 맨 위에 다음 줄을 #pragma once
바로 다음에 추가합니다.
#define _WIN32_DCOM
또한 stdafx.h 파일 아래쪽에 다음 줄을 추가합니다.
#import "..\deployed\SideBySide.dll" no_namespace
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;
}
릴리스 빌드를 생성하고
2단계(옵션 B: .NET Framework)
Visual Studio .NET 2003에서는 SideBySide 프로젝트 폴더를 기준으로 형제 폴더에 클라이언트라는 새 C# 또는 Visual Basic .NET 콘솔 애플리케이션을 만듭니다. 참조 추가 대화 상자의 COM 탭에서 SideBySide 1.0 형식 라이브러리 대한 참조를 추가합니다.
Main 메서드 내에 다음 코드를 붙여넣습니다.
C# 코드
SideBySideLib.ISideBySideClass obj =
new SideBySideLib.SideBySideClassClass();
Console.WriteLine(obj.Version());
Console.ReadLine();
Visual Basic .NET 코드
Dim obj As SideBySideLib.ISideBySideClass =
New SideBySideLib.SideBySideClassClass
Console.WriteLine(obj.Version())
Console.ReadLine()
릴리스 빌드를 생성하고
3단계
현재 \deployed 폴더는 일부 중간 파일을 제외하고 client.exe 및 SideBySide.dll포함해야 하며, 후자는 빌드 프로세스에 의해 등록됩니다. 이러한 정상적인 상황에서 서버와 클라이언트가 함께 작동하는지 확인하려면 \deployed\client.exe 실행하고 예상 출력 "1.0.0-CPP"를 확인합니다.
4단계
이 연습은 등록이 없는 COM에 관한 것이므로 이제 SideBySide 어셈블리의 등록을 취소해야 합니다. 명령 프롬프트에서 \deployed 폴더로
5단계
이전 단계의 영향을 확인하려면 \deployed\client.exe 다시 실행하면 "클래스가 등록되지 않았습니다."라는 메시지가 표시됩니다. 이 단계에서는 COM 런타임이 레지스트리에서 필요한 정보를 찾지 못해 좌절했지만 대체 방법으로 정보를 사용할 수 있도록 아직 지정하지 않았습니다. 다음 단계에서 이를 해결할 것입니다.
Registration-Free 활성화
6단계
\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.X"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>
7단계
\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="SideBySide.X"
version="1.0.0.0" />
<file name = "SideBySide.dll">
<comClass
clsid="{[CLSID_SideBySideClass]}"
threadingModel = "Apartment" />
<typelib tlbid="{[LIBID_SideBySide]}"
version="1.0" helpdir=""/>
</file>
<comInterfaceExternalProxyStub
name="ISideBySideClass"
iid="{[IID_ISideBySideClass]}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
baseInterface="{00000000-0000-0000-C000-000000000046}"
tlbid = "{[LIBID_SideBySide]}" />
</assembly>
프로젝트에 특정할 GUID 값을 자리 표시자 형태로 작성했습니다. 이러한 자리 표시자의 각 값은 SideBySide 프로젝트의 SideBySide.idl 파일에서 또는 OLE/COM ObjectViewer(Oleview.exe) 도구에서 SideBySide.dll 열어 다음과 같이 찾을 수 있습니다.
[
object,
uuid([IID_ISideBySideClass]),
dual,
nonextensible,
helpstring("ISideBySideClass Interface"),
pointer_default(unique)
]
interface ISideBySideClass : IDispatch{
[id(1), helpstring("method Version")] HRESULT
Version([out,retval] BSTR* pVer);
};
[
uuid([LIBID_SideBySide]),
version(1.0),
helpstring("SideBySide 1.0 Type Library")
]
library SideBySideLib
{
importlib("stdole2.tlb");
[
uuid([CLSID_SideBySideClass]),
helpstring("SideBySideClass Class")
]
coclass SideBySideClass
{
[default] interface ISideBySideClass;
};
};
8단계
이 시점에서 어셈블리 매니페스트 파일을 Win32 리소스로 포함하는 주제를 브로치해야 합니다. 개발자가 COM 구성 요소를 다시 작성할 수 있고 기꺼이 다시 빌드할 수 있는 경우 이전 단계에서 만든 것과 같은 어셈블리 매니페스트가 com DLL에 형식 RT_MANIFEST Win32 리소스(windows.h정의됨)로 포함되는 것이 좋습니다. 이것이 불가능한 경우 어셈블리(결과적으로 어셈블리 매니페스트)에 COM DLL의 파일 이름과 다른 이름을 지정해야 합니다. 따라서 위의 경우 COM DLL은 sideBySide
9단계
매니페스트 파일의 제공으로 클라이언트가 다시 한 번 SideBySideClass 클래스를 활성화하고, \deployed\client.exe 실행하고, 예상 출력 "1.0.0-CPP"를 확인할 수 있는지 확인합니다.
Visual Basic 6.0 COM 서버 및 클라이언트
1단계
첫 번째 단계는 COM 서버를 빌드하는 것입니다. 새 Visual Basic 6.0 ActiveX DLL 프로젝트를 만듭니다. 프로젝트 탐색기에서 Project1 노드를 선택하고 속성 창이름을 SideBySide변경합니다. 프로젝트 탐색기에서 Class1 노드를 선택하고 속성 창에서 해당 이름을 SideBySideClass변경합니다.
다음 서브루틴을 코드 창에 붙여넣습니다.
Public Function Version()
Version = "1.0.0-VB6"
End Function
파일 선택 | SideBySide.dll...\deployed 폴더로 이동한 다음 확인클릭합니다. dll을 만들 때마다 새 GUID가 생성되지 않도록 하려면 Project를 선택합니다. | SideBySide 속성...구성 요소 탭을 클릭하고 버전 호환성 그룹에서 이진 호환성 라디오 단추를 선택합니다.
2단계
새 Visual Basic 6.0 Standard EXE 프로젝트를 만듭니다. 프로젝트 탐색기에서 Project1 노드를 선택하고 속성 창에서 해당 이름을 클라이언트변경합니다. 파일 선택 | Project As 저장하고 양식 파일과 프로젝트 파일을 SideBySide 프로젝트 폴더를 기준으로 형제 폴더에 저장합니다. 프로젝트 선택 |참조하고 SideBySide옆의 확인란을 선택하고 확인클릭합니다.
양식 디자이너에서 기본 양식을 두 번 클릭하고 Sub Form_Load()내부에 다음 코드를 붙여넣습니다.
Dim obj As New SideBySideClass
MsgBox obj.Version()
3단계
현재 \deployed 폴더에는 일부 중간 파일을 제외하고 client.exe 및 SideBySide.dll; 후자는 빌드 프로세스에 의해 등록됩니다. 이러한 정상적인 상황에서 서버와 클라이언트가 함께 작동하는지 확인하려면 \deployed\client.exe 실행하고 예상 출력 "1.0.0-VB6"을 기록해 둡니다.
4단계
이 연습은 등록이 없는 COM에 관한 것이므로 이제 SideBySide 어셈블리의 등록을 취소해야 합니다. 명령 프롬프트에서 \deployed 폴더로
5단계
이전 단계의 영향을 확인하려면 \deployed\client.exe 다시 실행하면 "런타임 오류 '429': ActiveX 구성 요소가 개체를 만들 수 없습니다."라는 메시지가 표시됩니다. 이 단계에서는 COM 런타임이 레지스트리에서 필요한 정보를 찾지 못해 좌절했지만, 아직 대체 방법으로 정보를 사용할 수 있도록 하지 않았습니다. 다음 단계에서 이를 해결할 것입니다.
6단계
\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.X"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>
7단계
\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="SideBySide.X"
version="1.0.0.0" />
<file name = "SideBySide.dll">
<comClass
clsid="{[CLSID_SideBySideClass]}"
threadingModel = "Apartment" />
<typelib tlbid="{[LIBID_SideBySide]}"
version="1.0" helpdir=""/>
</file>
<comInterfaceExternalProxyStub
name="_SideBySideClass"
iid="{[IID__SideBySideClass]}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
baseInterface="{00000000-0000-0000-C000-000000000046}"
tlbid = "{[LIBID_SideBySide]}" />
</assembly>
프로젝트에 특정할 GUID 값을 자리 표시자 형태로 작성했습니다. 이러한 자리 표시자의 각 값은 OLE/COM ObjectViewer(Oleview.exe) 도구에서 SideBySide.dll 열어 찾을 수 있습니다.
[
uuid([LIBID_SideBySide]),
version(1.0),
custom(50867B00-BB69-11D0-A8FF-00A0C9110059, 8169)
]
library SideBySide
{
// TLib : // TLib : OLE Automation : {00020430-0000-0000-
C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
interface _SideBySideClass;
[
odl,
uuid([IID__SideBySideClass]),
version(1.0),
hidden,
dual,
nonextensible,
oleautomation
]
interface _SideBySideClass : IDispatch {
[id(0x60030000)]
HRESULT Version([out, retval] VARIANT* );
};
[
uuid([CLSID_SideBySideClass]),
version(1.0)
]
coclass SideBySideClass {
[default] interface _SideBySideClass;
};
};
8단계
매니페스트 파일의 제공을 위해 클라이언트가 다시 한 번 SideBySideClass 클래스를 활성화하고, \deployed\client.exe 실행하고, 예상 출력 "1.0.0-VB6"을 기록할 수 있는지 확인합니다.
호환되지 않는 아파트
이 연습의 모든 COM 서버는 Single-Threaded Apartment(즉, STA 또는 아파트 스레드 구성 요소)에서 실행되도록 빌드되었습니다. 모든 클라이언트는 MTA(스레드가 다중 스레드 아파트에서 실행됨)인 C++ 클라이언트를 제외한 STA입니다. 따라서 클라이언트와 서버가 호환되지 않는 아파트에 살고 있으며, 이 경우 COM 호출의 아파트 간 마샬링이 프록시와 스텁 간에 이루어져야 합니다. 이 경우 어셈블리 매니페스트 파일의 다음 섹션을 사용합니다.
...
<typelib tlbid="{[LIBID_SideBySide]}"
version="1.0" helpdir=""/>
</file>
<comInterfaceExternalProxyStub
name="ISideBySideClass"
iid="{[IID_ISideBySideClass]}"
proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
baseInterface="{00000000-0000-0000-C000-000000000046}"
tlbid = "{[LIBID_SideBySide]}" />
...
이러한 요소는 레지스트리에 있는 정보를 제공합니다.
comInterfaceExternalProxyStub 요소는 형식 라이브러리 마샬링 수행하기에 충분한 정보를 제공하며 IDispatch에서 파생되는 COM 인터페이스(모든 Automation 인터페이스 포함)에 적합합니다. 이러한 경우
사용자 지정 인터페이스는 좀 더 드물기 때문에 좀 더 많은 작업을 수행해야 합니다.
IUnknown 직접 파생되고 자동화와 호환되지 않는 ISxSCustom이라는 인터페이스를 고려합니다.
SideBySideClassISxSCustom구현하고 클라이언트가 등록 없는 시나리오에서 해당 메서드를 호출하려면 comInterfaceProxyStub 요소를 어셈블리 매니페스트에 추가해야 합니다. 요소 이름에서 제안한 대로 이번에는 proxy-stub가 외부로
<file name = "SideBySide.dll">
...
<comInterfaceProxyStub
name="ISxSCustom"
iid="{[IID_ISxSCustom]}" />
</file>
그렇지 않으면 proxy-stub dll을 선언하는 파일 요소에
<file name = "SideBySide.dll"> ... </file>
<file name = "SideBySidePS.dll">
<comInterfaceProxyStub
name="ISxSCustom"
iid="{[IID_ISxSCustom]}" />
</file>
위에서 설명한 요소를 설명할 필요가 없었다면 클라이언트의 MTA에서 coclasse가 활성화되도록 두 스레드
활성화 컨텍스트 API 사용
소개 섹션에서 이 문서가 적용되는 플랫폼에서 애플리케이션 프로세스를 초기화하는 단계 중 하나는 애플리케이션 매니페스트 파일을 찾는 것이라고 언급했습니다. 애플리케이션 매니페스트 파일에는 애플리케이션에 종속성이 있는
애플리케이션이 수명 동안 직접 또는 간접적으로 활성화될 잠재적인 coclass 집합을 사전
stdafx.h 편집하고 _WIN32_DCOM
정의 바로 다음에 다음 줄을 추가합니다.
#define _WIN32_FUSION 0x0100 // this causes activation context
structs and APIs to be included.
client.cppcom 초기화 및 초기화 해제 호출 사이에 _tmain 함수를 살펴보면 SideBySideClass활성화하고 호출하는 복합 문이 표시됩니다. 다음과 같이 활성화 컨텍스트를 초기화하는 코드의 새 섹션을 내부
ACTCTX actCtx;
memset((void*)&actCtx, 0, sizeof(ACTCTX));
actCtx.cbSize = sizeof(ACTCTX);
actCtx.lpSource = "SideBySide.X.manifest";
HANDLE hCtx = ::CreateActCtx(&actCtx);
if (hCtx == INVALID_HANDLE_VALUE)
cout << "CreateActCtx returned: INVALID_HANDLE_VALUE"
<< endl;
else
{
ULONG_PTR cookie;
if (::ActivateActCtx(hCtx, &cookie))
{
// previous compound statement goes here...
::DeactivateActCtx(0, cookie);
}
}
위의 코드는 coclass가 활성화되기 전에 실행됩니다. 코드는 단순히 어셈블리 매니페스트 파일을 읽습니다(이 예제에서는 이름이 하드 코딩되지만 동적으로 로드하려는 어셈블리에 해당해야 합니다). 그런 다음 활성화되는 활성화 컨텍스트(즉, 현재로 설정)에 해당합니다. 이 시점부터 코클래스의 활성화는 이전과 같이 발생합니다. 이제 .manifest
직접 정품 인증 컨텍스트 API 대신 Windows Server 2003에서만 사용할 수 있는 Microsoft.Windows.ActCtx 개체입니다.
말할 필요도 없이 활성화 컨텍스트 API에는 앞에서 설명한 것보다 훨씬 더 많은 것이 있으며 추가 읽기 섹션에서 전체 API 설명서에 대한 링크를 찾을 수 있습니다.
문제 해결
앞에서 살펴본 것처럼 COM 구성 요소의 등록 없는 활성화에는 서버 또는 클라이언트에서 특별한 코드가 필요하지 않습니다. 일치하는 매니페스트 파일 쌍만 있으면 됩니다.
이 연습과 같은 방식으로 등록이 없는 개발에 접근하는 것이 좋습니다. 특히: 먼저 클라이언트가 등록된 서버로 작업하는 것을 확인하여 알려진 상태로 이동합니다. 그런 다음 서버 등록을 취소하고 오류 메시지가 예상한 것인지 확인합니다. 마지막으로 매니페스트 파일을 만들고 배포하여 상황을 해결합니다. 이렇게 하면 등록이 없는 활성화와 관련된 문제 해결 작업이 매니페스트 파일의 구조(및 이를 선택하는 경우 어셈블리 매니페스트의 올바른 포함)로 제한됩니다.
등록이 없는 COM 문제를 해결할 때 Windows Server 2003의 이벤트 뷰어는 친구입니다. Windows XP 또는 Windows Server 2003에서 구성 오류를 감지하면 일반적으로 시작한 애플리케이션에 대한 오류 메시지 상자와 "애플리케이션 구성이 올바르지 않아 이 응용 프로그램을 시작하지 못했습니다. 애플리케이션을 다시 설치하면 이 문제가 해결 될 수 있습니다." 이 메시지가 표시되면 Windows Server 2003에서 문제를 재현할 때마다 시스템 이벤트 로그를 참조하고 SideBySide 원본에서 이벤트를 찾는 것이 좋습니다. 이러한 경우 Windows XP 이벤트 로그를 살펴보지 않는 이유는 "[path]\[application filename]에 대한 활성화 컨텍스트 생성 실패"와 같은 메시지가 변함없이 포함되기 때문입니다. 나타나다. 참조 오류 메시지: 작업이 성공적으로 완료되었습니다." 이는 문제를 식별하는 데 도움이 되지 않습니다.
다양한 매니페스트 파일의 스키마는 매니페스트 파일 참조
등록이 없는 COM 의미에서 어셈블리어셈블리 매니페스트 파일의 내용을 통해 하나 이상의 물리적 파일을 연결하는 추상적인 아이디어입니다. 어셈블리의 이름은 세 곳에 나타나며 각각 동일해야 합니다. 어셈블리 매니페스트 파일의 assemblyIdentity 요소의 이름 특성에서 애플리케이션 매니페스트 파일의 dependentAssembly/assemblyIdentity 요소의 이름 특성 및 .manifest 확장명을 제외한 어셈블리 매니페스트 파일 자체의 이름입니다. 매니페스트 파일 이름이 애플리케이션 매니페스트의 이름 일치하지 않으면 Windows Server 2003 시스템 이벤트 로그에 다음 메시지가 표시됩니다. "종속 어셈블리 [애플리케이션 매니페스트의 이름 특성 값]을 찾을 수 없으며 마지막 오류로 인해 참조된 어셈블리가 시스템에 설치되지 않았습니다." 어셈블리 매니페스트의 이름 요소가 올바르지 않으면 Windows Server 2003 시스템 이벤트 로그에 "매니페스트에 있는 구성 요소 ID가 요청된 구성 요소의 ID와 일치하지 않습니다."라는 메시지가 표시됩니다.
SideBySide.dll .NET Framework 기반 구성 요소인 경우 어셈블리 매니페스트 파일을 SideBySide 어셈블리에 Win32 리소스로 포함해야 했습니다( 그리고 .NET 어셈블리의 이름을 .NET 어셈블리, 즉 SideBySide.manifest)의 이름을 따서 명명했을 것입니다. 그러나 어셈블리 로더의 검색 순서로 인해 네이티브 COM 구성 요소의 경우 매니페스트를 모듈에 포함하는 선택적
그러나
assemblyIdentity 요소는 어셈블리ID를 정의합니다. 네이티브 COM 구성 요소의 경우 이름버전 특성이 실제 파일과 일치하지 않아도 됩니다. 하지만 어떤 종류의 일관성을 적용하는 것이 좋습니다.
파일 요소는 comClass, typelib, 및 comInterfaceProxyStub 요소의 부모입니다. 그 목적은 어셈블리구성하는 물리적 파일을 찾는 것입니다. 파일 요소의 이름 특성이 파일 시스템의 파일을 올바르게 참조하지 않는 경우 CoCreateInstance "등록되지 않은 클래스" 또는 "지정된 모듈을 찾을 수 없습니다"에 해당하는 HRESULT를 반환합니다. 다른 폴더에 다른 버전의 COM 구성 요소를 설치할 수 있도록 이름 특성에 경로가 포함될 수 있습니다. Windows XP SP2에서 경로는 상대 또는 절대 경로일 수 있으며 파일 시스템의 어느 위치에서나 폴더를 참조할 수 있습니다. Windows Server 2003에는 애플리케이션 루트 또는 자식 폴더를 참조하는 경로가 필요하며 이 규칙을 위반하려고 하면 Windows Server 2003 시스템 이벤트 로그에 다음 메시지가 표시됩니다. "매니페스트 또는 정책 파일의 구문 오류 [어셈블리 매니페스트 파일 이름] [...] 값 [...]이(가) 잘못되었습니다."
comClass 요소에는 clsid하나의 필수 특성만 있습니다. 애플리케이션에서 CLSID가 어셈블리 매니페스트의 comClass 요소에 나열되지 않은 등록되지 않은 coclass를 활성화하려고 하면 CoCreateInstance 값 REGDB_E_CLASSNOTREG(0x80040154)가 있는 HRESULT를 반환합니다.
내가 말했듯이, 클라이언트와 서버가 다른 아파트에 존재하는 경우 typelib 및
comInterface[External]ProxyStub 요소가 필요하므로 이러한 요소가 처리될 때만 다음 오류를 볼 수 있습니다. 이러한 요소의 구성 오류로 인해 CoCreateInstance "라이브러리가 등록되지 않음", "형식 라이브러리/DLL 로드 오류" 또는 "지원되는 인터페이스 없음" 메시지에 해당하는 HRESULT를 반환합니다. 이러한 메시지가 표시되면 GUID를 다시 확인하고 모든 필수 특성이 있는지 확인합니다. 플랫폼 SDK에서 매니페스트 파일 스키마를 찾을 수 있습니다.
이제 애플리케이션 매니페스트 파일에 주의를 기울이겠습니다. 예를 들어 6단계를 다시 살펴보세요. 애플리케이션 매니페스트 [application filename].manifest 형식으로 이름을 합니다. 따라서 연습에서는 client.exe 프로세스에 로드될 때마다 읽어야 하므로 .manifest client.exe이름이 지정되었습니다. 올바르게 수행되지 않으면 CoCreateInstance는 "클래스가 등록되지 않음"인 메시지 텍스트인 REGDB_E_CLASSNOTREG(0x80040154) 값이 있는 HRESULT를 반환합니다.
애플리케이션 매니페스트에서 가장 중요한 요소는 dependentAssembly/assemblyIdentity 요소입니다. 이 요소는 어셈블리 매니페스트의 해당 요소에 대한 참조이며 두 요소는 정확히
결론
등록이 없는 COM은 WINDOWS 레지스트리에 대한 종속성에서 COM 구성 요소를 해제하고 따라서 해당 구성 요소를 사용하는 애플리케이션이 전용 서버를 요구하지 않도록 하는 기술입니다. 이를 통해 동일한 COM 구성 요소의 여러 버전에 종속된 애플리케이션이 인프라를 공유하고 이러한 다양한 COM 구성 요소 버전을 .NET Framework 버전 관리 및 배포 메커니즘의 에코에 나란히 로드할 수 있습니다.
이 문서에서는 Visual C++ 및 Visual Basic 6.0 및 관리되는 클라이언트로 작성된 네이티브 클라이언트 애플리케이션에서 네이티브 COM 구성 요소의 등록이 없는 활성화에 대한 데모를 안내합니다. 메커니즘이 작동하는 방법 중 일부를 설명하고 몇 가지 가능한 구성 오류와 문제를 해결하는 방법에 밑줄을 그어 줍니다.
추가 읽기
- 의 Registration-Free 활성화NET-Based 구성 요소: 연습
- 격리된 애플리케이션 및 side-by-side 어셈블리
- 매니페스트 파일 스키마
- 활성화 컨텍스트 API 사용하여
작성자 정보
Steve White Microsoft UK의 프리미어 개발자 지원 팀에서 일하는 애플리케이션 개발 컨설턴트입니다. Visual C#, Windows Forms 및 ASP.NET 사용하여 개발하는 고객을 지원합니다. 그의 블로그 음악, 시각화 및 프로그래밍에 대한 그의 관심사에 대한 자세한 정보를 제공합니다.
레슬리 뮬러 신용 스위스 퍼스트 보스턴에서 연구 & 개발 팀과 기술자입니다. Leslie는 금융 서비스, 기술 신생 기업, 산업 자동화 및 방어와 같은 환경에서 일하면서 개발자 및 기술 설계자로서 12 년의 경험을 가지고 있습니다. 프로그래밍을 하거나 연구를 하지 않을 때 그는 스키, 아이스 하키를 즐기고, 가능하면 아이슬란드나 로키산과 같은 극단적인 환경에서 전동 차량으로 약간 미친 짓을 합니다.