S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

手工加载未注册的 COM 组件

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));
3 if (FAILED(hr)) {
4      hr = TinyCoCreateInstance(__uuidof(DOMDocument40), NULL, CLSCTX_ALL,
5          __uuidof(IXMLDOMDocument2), ( void **)&spXMLDoc);
6      if (FAILED(hr)) {
7          return E_FAIL
8      }
9 }

3. 将所有强制加载的组件卸载

1 TinyReleaseAllComLibrary();


以下是实现的源代码:

001 #ifndef __TINY_CREATE_COM_OBJ_H__
002 #define __TINY_CREATE_COM_OBJ_H__   1
003   
004 typedef HRESULT (WINAPI * PFN_DllCanUnloadNow)( void );
005 typedef HRESULT (WINAPI * PFN_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID * ppv);
006   
007 #include <vector>
008 #include <algorithm>
009   
010 typedef struct COM_OBJ_DLL_CONTAINER
011 {
012      HINSTANCE hDllInst;
013      CLSID clsObject;
014 } COM_OBJ_DLL_CONTAINER ;
015   
016 typedef std::vector<COM_OBJ_DLL_CONTAINER> COM_LIB_ARR_TYPE;
017   
018 __declspec ( selectany ) COM_LIB_ARR_TYPE * g_vecComLib = NULL;
019   
020 __inline HRESULT WINAPI TinyInitComLibrary( LPCTSTR lpszObjHostPath, REFCLSID rclsid)
021 {
022      if (NULL == g_vecComLib) {
023          g_vecComLib = new COM_LIB_ARR_TYPE();
024      }
025   
026      HRESULT hr = E_FAIL;
027      COM_OBJ_DLL_CONTAINER tmp = { 0 };
028      tmp.hDllInst = LoadLibrary(lpszObjHostPath);
029      if (tmp.hDllInst)
030      {
031          tmp.clsObject = rclsid;
032          g_vecComLib->push_back(tmp);
033          hr = S_OK;
034      }
035      return hr;
036 }
037   
038 __inline HRESULT WINAPI TinyReleaseComLibrary(REFCLSID rclsid)
039 {
040      HRESULT hr = E_FAIL;
041      if (NULL == g_vecComLib) {
042          return hr;
043      }
044   
045      COM_LIB_ARR_TYPE::iterator it;
046      for (it=g_vecComLib->begin(); it!=g_vecComLib->end(); it++)
047      {
048          if (IsEqualCLSID(it->clsObject, rclsid))
049          {
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()) {
054                  bCanUnload = FALSE;
055              }
056   
057              if (bCanUnload) {
058                  FreeLibrary(it->hDllInst);
059                  g_vecComLib->erase(it);
060                  hr = S_OK;
061              }
062              break ;
063          }
064      }
065   
066      if (0 == g_vecComLib->size()) {
067          delete g_vecComLib;
068          g_vecComLib = NULL;
069      }
070   
071      return hr;
072 }
073   
074 __inline HRESULT WINAPI TinyReleaseAllComLibrary( void )
075 {
076      HRESULT hr = S_OK;
077      if (NULL == g_vecComLib) {
078          return hr;
079      }
080   
081      COM_LIB_ARR_TYPE::iterator it;
082      for (it=g_vecComLib->begin(); it!=g_vecComLib->end(); it++)
083      {
084          FreeLibrary(it->hDllInst);
085      }
086      g_vecComLib->clear();
087      delete g_vecComLib;
088      g_vecComLib = NULL;
089      return hr;
090 }
091   
092 __inline HRESULT WINAPI TinyCoCreateInstance(IN REFCLSID rclsid, IN LPUNKNOWN pUnkOuter,
093                                            IN DWORD dwClsContext, IN REFIID riid, OUT LPVOID FAR* ppv)
094 {
095      HRESULT hr = E_FAIL;
096   
097      if (g_vecComLib==NULL)
098      {
099          __asm int 3;
100          return hr;
101      }
102   
103      COM_LIB_ARR_TYPE::iterator it;
104   
105      for (it=g_vecComLib->begin(); it!=g_vecComLib->end(); it++)
106      {
107          if (IsEqualCLSID(it->clsObject, rclsid))
108          {
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);
114                  if (SUCCEEDED(hr))
115                  {
116                      hr = spClsFact->CreateInstance(NULL, riid, ppv);
117                  }
118              }
119              break ;
120          }
121      }
122      return hr;
123 }
124   
125 #endif  // __TINY_CREATE_COM_OBJ_H__
by free2000fly | Categories: 技术心得 | Tagged: |

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理