传统的COM程序一直都需要Windows注册表的支持,如果卸载时程序没有把对应的注册表项清理干净, 可能会导致下次安装程序时出错, 同时, 如果多个程序共享一个COM Server, 一旦其中的一个程序更新了COM Server, 可能会导致其他程序不能正常运行, 也就是所谓的Dll地狱。
所幸的是, 微软早已意识到这个问题, 自Window XP开始, 微软提供了一种称之为Side-by-Side(WinSxs)的技术, 使得COM终于可以脱离注册表的束缚, 而我们的程序也可以以简单的X-Copy方式部署.
本文讨论如何创建和使用基于.NET的免注册COM Server.
首先,我们需要创建一个基于.NET的COM Server, 以Visual Studio (VS) 2010 + .NET4.0为例:
1. 打开VS, 新建一个Class Library (C#) 工程CSComServer4, 将Class1.cs改名为CSComServer4.cs并加入以下代码
namespace CSComServer4 { [Guid("F07BB298-1465-4773-8376-464446588049")] // IID [ComVisible(true)] public interface ICSComServer4 { string Version(); } [ClassInterface(ClassInterfaceType.None)] [Guid("5E6C6A71-1AF3-4169-BE2B-3E1D6C595333")] // CLSID [ComVisible(true)] public class CSComServer4 : ICSComServer4 { public string Version() { return ".NET 4.0"; } } }
你可以使用VS提供的小工具(Tools->Create GUID)来创建新的Guid.
2. Build这个Class Library工程, 将生成的CSComServer4.dll拷贝到一个单独的文件夹, 比如:”D:/demo/”.
3. 点击开始 -> 所有程序 -> Microsoft Visual Studio 2010 -> Visual Studio Tools -> 右键点击Visual Studio Command Prompt (2010) -> 选择 “以管理员身份运行” (Run as administrator).
4. 在Visual Studio Command Prompt (2010) 窗口中输入命令 “cd /d d:/demo” 切换到demo文件夹.
5. 输入命令”regasm /tlb CSComServer4.dll”把CSComServer4.dll注册成为一个真正的COM Server, 至此, 一个基于.NET的COM Server创建完成, 任何一个COM Client都可以使用这个COM Server, 但是该COM Server还不是免注册的.
这里的/tlb开关会在demo文件夹生成一个CSComServer4.tlb文件,后面在创建C++ COM Client的时候我们会用到这个它.
下面, 我们创建一个C++的COM Client来使用刚刚注册的COM Server:
1. 打开VS, 创建一个Win32 (VC++)工程, 命名为client, 在向导中选择”控制台程序”.
2. 打开头文件stdafx.h, 在”#pragma once”下面加入一行”#define _WIN32_DCOM”; 在最后一行加入” #import "D://demo//CSComServer4.tlb" no_namespace”.
3. 打开client.cpp, 删除所有内容并插入以下代码:
#include "stdafx.h" #include <iostream> using namespace std; void InvokeComServer() { CoInitializeEx(0, COINIT_MULTITHREADED); try { ICSComServer4Ptr ptr; HRESULT hr = ptr.CreateInstance(__uuidof(CSComServer4)); if (SUCCEEDED(hr)) { cout << ptr->Version() << endl; } else { printf("0x%8x", hr); } } catch (_com_error &err) { wprintf(L"The server throws the error: %s/n", err.ErrorMessage()); wprintf(L"Description: %s/n", (PCWSTR) err.Description()); } CoUninitialize(); } int _tmain(int argc, _TCHAR* argv[]) { InvokeComServer(); char c; cin >> c; return 0; }
4. Build这个C++工程, 双击生成的client.exe, 程序输出”.NET 4.0”, 说明对COM Server的调用成功.
然而此时的COM Server并非免注册, 回到Visual Studio Command Prompt (2010) 窗口, 输入” regasm /u CSComServer4.dll”把CSComServer4的注册信息从注册表中移除, 再次运行client.exe, 程序输出” 0x80040154”, 这个错误码表示”类型未注册” (class not registered).
下面, 我们来创建一个真正的免注册COM Server.
1. 在demo文件夹创建一个txt文件, 把文件改名为CSComServer4.manifest 并输入以下内容:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="CSComServer4"
version="1.0.0.0"
processorArchitecture="MSIL" />
<clrClass
clsid="{5E6C6A71-1AF3-4169-BE2B-3E1D6C595333}"
progid="CSComServer4.CSComServer4"
threadingModel="Both"
name="CSComServer4.CSComServer4"
runtimeVersion="v4.0.30319">
</clrClass>
<file name="CSComServer4.dll">
</file>
</assembly>
2. 打开刚才创建的client工程, 在解决方案窗口, 右键点击工程 -> 选择’属性’ -> 链接器(Linker) -> 清单文件(Manifest File) -> 清单依赖 (Additional Manifest Dependencies) -> 输入以下内容:
type='win32' name='CSComServer4' version='1.0.0.0' processorArchitecture='MSIL'
3. 清空client工程的输出文件夹并重新build client工程, 把生成的client.exe拷贝到demo文件.
4. 此时, demo文件夹下包含4个文件: client.exe, CSComServer4.dll, CSComServer4.manifest 和CSComServer4.tlb. 双击client.exe, 程序输出”.NET 4.0”, 一个简单的免注册COM创建成功!