免注册调用COM组件的两种办法

文章介绍了两种无须注册即可调用COM组件的方法:一是通过VC++实现的DllGetClassObject函数调用DLL,二是利用Manifest清单文件。第一种方法适用于自开发或通用类库,不支持含自定义类型参数。第二种方法适合接口稳定且需处理事件的DLL或OCX。文章提供相关源码下载和学习资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        最近放假了,闲来没事,总结一下免注册调用COM组件的两种办法。虽然是老古董的东西,但是对经常需要用VB/VC做一些小工具的我来说还是很有用的。

        一、调用DLL的DllGetClassObject函数

        下面是VC++实现的代码,原理很简单,直接看代码就明白了,代码面前毫无秘密。

HRESULT WINAPI GetClassIID(LPCTSTR lpszDllFileName, LPCTSTR lpszClassName, REFIID classIID)
{
	ITypeLib* lpTypeLib = NULL;

	HRESULT hr = LoadTypeLibEx(lpszDllFileName, REGKIND_NONE, &lpTypeLib);

	if (FAILED(hr))return hr;

	CComPtr<ITypeLib> pTypeLib(lpTypeLib);

	UINT nTypeInfoCount = pTypeLib->GetTypeInfoCount();

	for (UINT i = 0 ; i < nTypeInfoCount; i++)
	{
		ITypeInfo* lpTypeInfo = NULL;

		hr = pTypeLib->GetTypeInfo(i, &lpTypeInfo);

		if (SUCCEEDED(hr))
		{	
			CComPtr<ITypeInfo> pTypeInfo(lpTypeInfo);

			TYPEATTR* lpTypeAttr = NULL;

			hr = lpTypeInfo->GetTypeAttr(&lpTypeAttr);

			if (SUCCEEDED(hr))
			{
				if (lpTypeAttr->typekind == TKIND_COCLASS)
				{			
					_bstr_t strTmp;
					hr = pTypeLib->GetDocumentation(i, strTmp.GetAddress(), NULL, NULL, NULL);

					if (SUCCEEDED(hr))
					{
						if (strTmp == _bstr_t(lpszClassName))
						{
							CopyMemory((void*)&classIID, &(lpTypeAttr->guid), sizeof IID);

							pTypeInfo->ReleaseTypeAttr(lpTypeAttr);

							return S_OK;
						}
					}
				}

				pTypeInfo->ReleaseTypeAttr(lpTypeAttr);
			}
		}

	}

	return S_FALSE;
}


HRESULT WINAPI CreateDllObjectW(LPCTSTR lpszDllFileName, LPCTSTR lpszClassName, IDispatch **ppvObject)
{
	IID classIID = {0};

	HRESULT hr = GetClassIID(lpszDllFileName, lpszClassName, classIID);

	if (FAILED(hr)) return hr;

	HINSTANCE hDllInst = GetModuleHandle(lpszDllFileName);

	if (!hDllInst) hDllInst = LoadLibrary(lpszDllFileName);
		
	if (!hDllInst) return S_FALSE;

	typedef HRESULT (__stdcall* pfnDllGetClassObject)(REFCLSID, REFIID, void**);
	pfnDllGetClassObject fnDllGetClassObject = (pfnDllGetClassObject)GetProcAddress(hDllInst, "DllGetClassObject");

	if (!fnDllGetClassObject)
	{
		FreeLibrary(hDllInst);
		return S_FALSE;
	}

	IClassFactoryPtr lpClassFactory = NULL;

	hr = (fnDllGetClassObject)(classIID, IID_IClassFactory, (void**)&lpClassFactory);

	if (SUCCEEDED(hr)) 
	{ 
		hr = lpClassFactory->CreateInstance(NULL, IID_IDispatch, (void**)ppvObject);

		if (SUCCEEDED(hr)) return S_OK;
	}

	FreeLibrary(hDllInst);

	return S_FALSE;
};


HRESULT WINAPI CreateDllObjectA(LPCSTR lpszDllFileName, LPCSTR lpszClassName, IDispatch **ppvObject)
{
	return CreateDllObjectW(CA2T(lpszDllFileName), CA2T(lpszClassName), ppvObject);
}

        我把上面代码编译成一个DLL,方便给VB使用,文章最后有源码的下载链接。如果要用纯VB代码实现上面的功能,就比较费劲。但也是可以实现的,有兴趣的可以自己去试试,这样就不用多带一个DLL文件。

        在VB中还有一种变通的办法,详细可以看我之前写的另外一个例子。

        VB调用JMail发邮件(无需注册JMail.dll)

二、利用Manifest清单文件

        关于Manifest清单文件的详细介绍,可以到微软的网站看一下。

        https://learn.microsoft.com/zh-cn/windows/win32/sbscs/manifest-files-reference

        下面是一个免注册调用COMDLG32.OCX和TLBINF32.DL的清单文件,里面的每一项在微软的网站都有详细的介绍。

<?xml version="1.0" encoding="utf-8"?>
<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="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*" />
    </dependentAssembly>
  </dependency>
  <file name="COMDLG32.OCX">
    <comClass description="CommonDialog" clsid="{F9043C85-F6F2-101A-A3C9-08002B2F49FB}" />
  </file>
  <comInterfaceExternalProxyStub name="ICommonDialog" iid="{083039C2-13F4-11D1-8B7E-0000F8754DA1}" />
  <file name="TLBINF32.DLL">
    <comClass description="SearchHelper" clsid="{8B217752-717D-11CE-AB5B-D41203C10000}" />
    <comClass description="TypeLibInfo" clsid="{8B217746-717D-11CE-AB5B-D41203C10000}" />
    <comClass description="TLIApplication" clsid="{8B21775E-717D-11CE-AB5B-D41203C10000}" />
  </file>
  <comInterfaceExternalProxyStub name="_SearchHelper" iid="{8B217751-717D-11CE-AB5B-D41203C10000}" />
  <comInterfaceExternalProxyStub name="_TypeLibInfo" iid="{8B217745-717D-11CE-AB5B-D41203C10000}" />
  <comInterfaceExternalProxyStub name="_TLIApplication" iid="{8B21775D-717D-11CE-AB5B-D41203C10000}" />
</assembly>

        我做了一个小工具用来生成Manifest清单文件,这个小工具同时也是一个Manifest清单文件应用的例子。文章最后有源码的下载链接。

三、两种方法的比较

        方法一:

        一般用于调用自己开发的,可能经常需要更改的COM类库,也可以用于调用一些通用的类库,但是函数参数中不能含有自定义类型的参数,比如结构体类型的参数。

        方法二:

        一般用于调用接口稳定的DLL类库,或者OCX等需要处理事件的组件。用这个办法,开发软件和以前一样,只是发布的时候增加一个清单文件即可,或者直接把清单文件嵌入资源里面。

        两种方法可以结合在一起同时使用,怎么方便怎么来。

四、源码下载以及学习资源

免注册调用COM组件方法一-DllGetClassObject

https://download.csdn.net/download/Zezese/87394537

免注册调用COM组件方法二-AssemblyManifests

https://download.csdn.net/download/Zezese/12269960

清单文件参考 - Win32 apps | Microsoft Learn

https://learn.microsoft.com/zh-cn/windows/win32/sbscs/manifest-files-reference

Isolated Applications and Side-by-side Assemblies - Win32 apps | Microsoft Learn

https://learn.microsoft.com/en-us/windows/win32/sbscs/isolated-applications-and-side-by-side-assemblies-portal

Building C/C++ Isolated Applications and Side-by-side Assemblies | Microsoft Learn

https://learn.microsoft.com/zh-tw/previous-versions/visualstudio/visual-studio-2013/ms235532(v=vs.120)

Registration-Free Activation of COM Components: A Walkthrough | Microsoft Learn

https://learn.microsoft.com/en-us/previous-versions/dotnet/articles/ms973913(v=msdn.10)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值