使用清单Manifest免注册调用COM组件

前言

虽然ActiveX已被淘汰,但是又没有新的解决方案来替代ActiveX,好多公司都会使用ActiveX解决网页调用本地资源。ActiveX最容易注册出现问题,所以我们接上一篇关于微软的Manifest的那些事,我们谈下如何运用清单Manifest,来实现免注册调用COM组件,也就是调用ActiveX。

准备工作

首先准备一个工具regsvr42.exe,用来提取com组件的注册信息,在命令行中输入

1
regsvr42 JITCertActiveX.dll

然后就生成了一个JITCertActiveX.sxs.manifest文件。

文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity
type="win32"
name="JITCertActiveX.sxs"
version="1.0.0.0" />

<file name="JITCertActiveX.dll">

<comClass
description="SZZSCertInfo Class"
clsid="{6FA144DC-ADDC-45EE-B5D5-7F8888F92C36}"
threadingModel="Apartment"
progid="JITCertActiveX.SZZSCertInfo"
tlbid="{32360567-7CEB-4F08-BC6C-178BD488885F}" />

</file>

</assembly>

内容理解可以参考上一篇程序集清单

再次准备exe的清单文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity
type="win32"
name="testAssembly.sxs"
version="1.0.0.0" processorArchitecture="x86"/>

<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="JITCertActiveX.sxs"
version="1.0.0.0" processorArchitecture="x86"/>
</dependentAssembly>
</dependency>

</assembly>

内容理解可以参考上一篇应用清单

编写测试程序

测试程序我们采用import导入的方法加上智能指针,详细不多说,看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <atlbase.h>
#include <iostream>
#include <Windows.h>
// 导入com组件,第一次编译后会生成tlh和tli
#import "JITCertActiveX.dll"
// 根据生成的tlh,使用该命名空间
using namespace JITCertActiveXLib;

class TA
{
public:
TA() {
CoInitialize(NULL);
// CertInfo 替换成tlh里面的内容
HRESULT hr = pJitVCTK.CoCreateInstance(__uuidof(CertInfo)); //创建COM对象
if (FAILED(hr))
{
return;
}

}
_bstr_t getVersion() {
//com方法看你自己调用的com组件方法
return pJitVCTK->GetOCXVersion();
}
~TA() {
pJitVCTK.Release();
CoUninitialize();
}
private:
//IJITCertInfo改成你自己的tlh里面的内容
CComQIPtr<IJITCertInfo> pJitVCTK;
};

int main()
{
TA t;
_bstr_t version = t.getVersion();

std::cout << "Hello World!\n";
}

方法和接口以及实现类不要照抄,重在理解。这种调用com组件是不支持窗口事件的,如果想支持窗口事件请采用窗口模式(根据框架不同,方式也不同,比如MFC和wxWidgets方法就不一样)。

追加嵌入exe清单

在VS的解决方案TestAssembly中点击属性,在项目属性页中选择清单工具,选择输入和输出,选择附加清单文件,将你的exe清单文件附加到这里。

问题

试着运行,然后我发现exe启动不了。后来发现是exe的清单文件少了一个processorArchitecture属性。遇到这个问题不要慌,一般启动不了是激活上下文找不到依赖的程序集。

激活上下文

这个很重要,Windows为什么能识别你的清单呢?不管是内置的还是独立的清单文件,靠的就是激活上下文。激活上下文参考微软文档使用激活上下文API。我现在用不到,所以就不看了。

跟踪激活上下文

采用sxstrace可以根据激活上下文的动作,进而判断哪里出现了问题。sxstrace跟踪激活上下文

评论