65.9K
CodeProject 正在变化。 阅读更多。
Home

模拟 CoCreateInstance()

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (27投票s)

2007年4月17日

1分钟阅读

viewsIcon

110255

描述如何在无需注册的情况下使用 COM 对象。

引言

不久前,我编写了一个小型实用工具,它使用 WinGraphViz.DLL COM 组件将 DOT 语法转换为图像。

然而,在运行该工具之前,让用户注册此组件并不常见,因此我开始寻找一种将 COM 组件像普通 DLL 一样使用的方法。研究表明,有很多技术可以实现这一点。

  1. 无注册 COM (适用于 XP 及更高版本)
  2. 模拟 CoCreateInstance()

要了解有关无注册 COM 的更多信息,请查看本文末尾的参考资料。

模拟 CoCreateInstance()

通常,要创建一个实例,你会执行类似的操作

hr = CoCreateInstance(CLSID_DOT, NULL, CLSCTX_ALL,
                      IID_IDOT, (LPVOID *)&pIDOT);

这将导致 OLE 从注册表中获取关联的 DLL,并调用其 DllGetClassObject() 方法来获取类工厂,然后从类工厂创建所需 IID 的实例。

因此,我们可以通过以下代码模拟 CoCreateInstance()

HRESULT __stdcall MyCoCreateInstance(
  LPCTSTR szDllName,
  IN REFCLSID rclsid,
  IUnknown* pUnkOuter,
  IN REFIID riid,
  OUT LPVOID FAR* ppv)
{
  HRESULT hr = REGDB_E_KEYMISSING;

  HMODULE hDll = ::LoadLibrary(szDllName);
  if (hDll == 0)
    return hr;

  typedef HRESULT (__stdcall *pDllGetClassObject)(IN REFCLSID rclsid, 
                   IN REFIID riid, OUT LPVOID FAR* ppv);

  pDllGetClassObject GetClassObject = 
     (pDllGetClassObject)::GetProcAddress(hDll, "DllGetClassObject");
  if (GetClassObject == 0)
  {
    ::FreeLibrary(hDll);
    return hr;
  }

  IClassFactory *pIFactory;

  hr = GetClassObject(rclsid, IID_IClassFactory, (LPVOID *)&pIFactory);

  if (!SUCCEEDED(hr))
    return hr;

  hr = pIFactory->CreateInstance(pUnkOuter, riid, ppv);
  pIFactory->Release();

  return hr;
}

请注意,此函数接受一个参数,该参数包含 DLL 的名称。

使用代码

如果 COM 已注册,则你的应用程序需要首先运行,否则你将诉诸模拟 CoCreateInstance()。你的代码可能如下所示

hr = CoCreateInstance(CLSID_DOT, NULL, CLSCTX_ALL,
     IID_IDOT, (LPVOID *)&pIDOT);

if (hr == REGDB_E_CLASSNOTREG)
{
  hr = MyCoCreateInstance(_T("WinGraphViz.dll"), CLSID_DOT, 
       NULL, IID_IDOT, (LPVOID *)&pIDOT);
}

if (FAILED(hr))
{
  cout << "CoCreateInstance Failed: " << hr 
       << "nn";
  return -1;
}

参考

以下链接在构建这个简单的代码片段时很有帮助

© . All rights reserved.