手工加载未注册的 COM 组件
http://www.cppblog.com/sleepwom/archive/2010/02/16/107921.html
二 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 组件 |