Posted on 2010-02-16 15:43
S.l.e!ep.¢% 阅读(1421)
评论(0) 编辑 收藏 引用 所属分类:
COM
手工加载未注册的 COM 组件
二 14, 2010
有时候我们运行程序的时候, 可能某个组件在系统内并不存在, 所以我们自己将这个组件打包在我们的安装包内, 但并不将其注册进系统. 这样做的目的就是尽量少的影响原有的系统. 组件只是在我们的应用程序需要的时候才加载进去. 不用的时候将其卸载.
用这种途径创建组件实例的主要思路就是, 调用组件 DLL 导出的 DllGetClassObject 函数, 创建类厂 IClassFactory 的实例, 然后用 IClassFactory::CreateInstance 函数创建目标接口指针的实例.
以下是用法:
1. 将某个组件加载进程序
1
|
TCHAR
szXmlPath[MAX_PATH] = { 0 };
|
2
|
GetModuleFileName(NULL, szXmlPath, _countof(szXmlPath));
|
3
|
PathRemoveFileSpec(szXmlPath);
|
4
|
PathAppend(szXmlPath, _T(
"msxml4.dll"
));
|
5
|
TinyInitComLibrary(szXmlPath, __uuidof(DOMDocument40));
|
2. 使用组件
1
|
CComPtr<IXMLDOMDocument2> spXMLDoc;
|
2
|
hr = spXMLDoc.CoCreateInstance(__uuidof(DOMDocument40));
|
4
|
hr = TinyCoCreateInstance(__uuidof(DOMDocument40), NULL, CLSCTX_ALL,
|
5
|
__uuidof(IXMLDOMDocument2), (
void
**)&spXMLDoc);
|
3. 将所有强制加载的组件卸载
1
|
TinyReleaseAllComLibrary();
|
以下是实现的源代码:
001
|
#ifndef __TINY_CREATE_COM_OBJ_H__
|
002
|
#define __TINY_CREATE_COM_OBJ_H__ 1
|
004
|
typedef
HRESULT
(WINAPI * PFN_DllCanUnloadNow)(
void
);
|
005
|
typedef
HRESULT
(WINAPI * PFN_DllGetClassObject)(REFCLSID rclsid, REFIID riid,
LPVOID
* ppv);
|
010
|
typedef
struct
COM_OBJ_DLL_CONTAINER
|
014
|
} COM_OBJ_DLL_CONTAINER ;
|
016
|
typedef
std::vector<COM_OBJ_DLL_CONTAINER> COM_LIB_ARR_TYPE;
|
018
|
__declspec
(
selectany
) COM_LIB_ARR_TYPE * g_vecComLib = NULL;
|
020
|
__inline
HRESULT
WINAPI TinyInitComLibrary(
LPCTSTR
lpszObjHostPath, REFCLSID rclsid)
|
022
|
if
(NULL == g_vecComLib) {
|
023
|
g_vecComLib =
new
COM_LIB_ARR_TYPE();
|
027
|
COM_OBJ_DLL_CONTAINER tmp = { 0 };
|
028
|
tmp.hDllInst = LoadLibrary(lpszObjHostPath);
|
031
|
tmp.clsObject = rclsid;
|
032
|
g_vecComLib->push_back(tmp);
|
038
|
__inline
HRESULT
WINAPI TinyReleaseComLibrary(REFCLSID rclsid)
|
041
|
if
(NULL == g_vecComLib) {
|
045
|
COM_LIB_ARR_TYPE::iterator it;
|
046
|
for
(it=g_vecComLib->begin(); it!=g_vecComLib->end(); it++)
|
048
|
if
(IsEqualCLSID(it->clsObject, rclsid))
|
050
|
BOOL
bCanUnload = TRUE;
|
051
|
PFN_DllCanUnloadNow pfn_DllCanUnloadNow = NULL;
|
052
|
pfn_DllCanUnloadNow = (PFN_DllCanUnloadNow) GetProcAddress(it->hDllInst,
"DllCanUnloadNow"
);
|
053
|
if
(pfn_DllCanUnloadNow && S_OK != pfn_DllCanUnloadNow()) {
|
058
|
FreeLibrary(it->hDllInst);
|
059
|
g_vecComLib->erase(it);
|
066
|
if
(0 == g_vecComLib->size()) {
|
074
|
__inline
HRESULT
WINAPI TinyReleaseAllComLibrary(
void
)
|
077
|
if
(NULL == g_vecComLib) {
|
081
|
COM_LIB_ARR_TYPE::iterator it;
|
082
|
for
(it=g_vecComLib->begin(); it!=g_vecComLib->end(); it++)
|
084
|
FreeLibrary(it->hDllInst);
|
086
|
g_vecComLib->clear();
|
092
|
__inline
HRESULT
WINAPI TinyCoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter,
|
093
|
IN
DWORD
dwClsContext, IN REFIID riid, OUT
LPVOID
FAR* ppv)
|
097
|
if
(g_vecComLib==NULL)
|
103
|
COM_LIB_ARR_TYPE::iterator it;
|
105
|
for
(it=g_vecComLib->begin(); it!=g_vecComLib->end(); it++)
|
107
|
if
(IsEqualCLSID(it->clsObject, rclsid))
|
109
|
PFN_DllGetClassObject pfn_DllGetClassObject = NULL;
|
110
|
pfn_DllGetClassObject = (PFN_DllGetClassObject) GetProcAddress(it->hDllInst,
"DllGetClassObject"
);
|
111
|
if
(pfn_DllGetClassObject) {
|
112
|
CComQIPtr<IClassFactory> spClsFact;
|
113
|
hr = pfn_DllGetClassObject(rclsid, __uuidof(IClassFactory), (
void
**)&spClsFact);
|
116
|
hr = spClsFact->CreateInstance(NULL, riid, ppv);
|
125
|
#endif // __TINY_CREATE_COM_OBJ_H__
|
by
free2000fly | Categories:
技术心得 | Tagged:
加载 COM 组件 |