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

        最近放假了,闲来没事,总结一下免注册调用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 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 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的清单文件,里面的每一项在微软的网站都有详细的介绍。



  
  
    
      
    
  
  
    
  
  
  
    
    
    
  
  
  
  

        我做了一个小工具用来生成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)

你可能感兴趣的:(VC/MFC,microsoft)