Archive for the ‘COM’ Category

tagVARIANT CComVariant源码剖析

tagVARIANT CComVariant

ATL碎语CAtlModule CAtlBaseModule

// CAtlModule模块基类
__declspec(selectany) CAtlModule* _pAtlModule = NULL; // 全局变量, 代表一个模块

struct _ATL_MODULE70
{
 UINT cbSize;
 LONG m_nLockCnt;
 _ATL_TERMFUNC_ELEM* m_pTermFuncs;
 CComCriticalSection m_csStaticDataInitAndTypeInfo;
};
typedef _ATL_MODULE70 _ATL_MODULE;

class ATL_NO_VTABLE CAtlModule : public _ATL_MODULE
{
 CAtlModule() throw()
 {
  // Should have only one instance of a class
  // derived from CAtlModule in a project.
  // 一个工程中仅有一个CAtlModule子类的实例
  // 其一般也是一个全局变量, 因为它会被赋值给_pAtlModule
  ATLASSERT(_pAtlModule == NULL);
  // _ATL_MODULE中的变量初始化
  cbSize = 0;
  m_nLockCnt = 0;
  m_pTermFuncs = NULL;
  
  _pAtlModule = this; // 赋值给_pAtlModule
  
  m_pGIT = NULL;

  if (FAILED(m_csStaticDataInitAndTypeInfo.Init()))
  {
   // 注意此if块中返回时, _pAtlModule已被赋值一个失败初始化的对象
   ATLTRACE(atlTraceGeneral, 0, _T("ERROR : Unable to initialize critical section in CAtlModule\n"));
   ATLASSERT(0);
   CAtlBaseModule::m_bInitFailed = true;
   return;
  }

  // Set cbSize on success.
  cbSize = sizeof(_ATL_MODULE);
 }
};

// CAtlBaseModule的定义和实现分别在VC\atlmfc\include\atlcore.h和VC\atlmfc\src\atl\atls\atlbase.cpp中
// atlbase.cpp定义了其一个全局变量_AtlBaseModule
#pragma init_seg( lib )
CAtlBaseModule _AtlBaseModule;
extern CAtlWinModule _AtlWinModule = CAtlWinModule();

struct _ATL_BASE_MODULE70
{
 UINT cbSize;
 HINSTANCE m_hInst;
 HINSTANCE m_hInstResource;
 bool m_bNT5orWin98;
 DWORD dwAtlBuildVer;
 const GUID* pguidVer;
 CComCriticalSection m_csResource;
 CSimpleArray<HINSTANCE> m_rgResourceInstance;
};
typedef _ATL_BASE_MODULE70 _ATL_BASE_MODULE;

class CAtlBaseModule : public _ATL_BASE_MODULE
{
 CAtlBaseModule::CAtlBaseModule() throw()
 {
  cbSize = sizeof(_ATL_BASE_MODULE);

  m_hInst = m_hInstResource = reinterpret_cast<HINSTANCE>(&__ImageBase);

  m_bNT5orWin98 = false;
  OSVERSIONINFO version;
  memset(&version, 0, sizeof(version));
  version.dwOSVersionInfoSize = sizeof(version);
  ::GetVersionEx(&version);
  if(version.dwPlatformId == VER_PLATFORM_WIN32_NT)
  {
   if(version.dwMajorVersion >= 5)
   {
    m_bNT5orWin98 = true;
   }
  }
  else if(version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  {
   if((version.dwMajorVersion > 4) || ((version.dwMajorVersion == 4) &&
    (version.dwMinorVersion > 0)))
   {
    m_bNT5orWin98 = true;
   }
  }

  dwAtlBuildVer = _ATL_VER;
  pguidVer = &GUID_ATLVer70;

  if (FAILED(m_csResource.Init()))
  {
   ATLTRACE(atlTraceGeneral, 0, _T("ERROR : Unable to initialize critical section in CAtlBaseModule\n"));
   ATLASSERT(0);
   CAtlBaseModule::m_bInitFailed = true;
  }
 }
}

IObjectSafety IObjectSafetyImpl

浏览器与ActiveX控件交互时会弹出警告,去掉它必须实现IObjectSafety接口。当一个ActiveX实现了该接口时就是声明了它是安全的,那么用户因为使用此控件造成的损失应该由此控件厂商承担,所以还是谨慎的好。

关于IObjectSafety的更多资料,参考:

再谈IObjectSafety

ATL中实现IObjectSafety接口,只需要继承IObjectSafetyImpl即可,详细资料参考:

如何为初始化 IObjectSafety 标记 ATL 控件安全

这篇参考资料的ATL版本比较低,但大体是对的,在新的ATL中有如下地方需要改动:

继承时使用:public IObjectSafetyImpl<CXLSafeEditWrap, INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA>

COM MAP中使用:COM_INTERFACE_ENTRY(IObjectSafety)

IE接口实现浏览器窗口

花了两天时间终于简单地实现了利用IE接口实现自己的浏览器窗口。

关于IE接口的MSDN文档太多了,使用IWebBrowser2接口转到URL、加载HTML、解析HTML这些功能一般都会从各种途径知道。但是如何使用自己的窗口来显示网页的资料少之又少。下面是些参考资料:

微软示例代码(里面的htmldlg.exe有用到MSHTML.DLL的ShowHTMLDialog导出函数)

Embed an HTML control in your own window using plain C(讲解详细,很好的参考资料)

Display a Web Page in a Plain C Win32 Application(和上一篇差不多,就没仔细看了)

要想通过自己的窗口来展示网页,必须实现三个接口IOleClientSite、IOleInPlaceFrame、IOleInPlaceSite。这三个接口用于OLE对象(即这里的CLSID_WebBrowser)和容器窗口交互、通信。下面是实现存档:

IEInstance.h

IEInstance.cpp

WinMain.cpp

另外,可以通过CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (LPVOID *)&m_pIWB2);再调用IWebBrowser2的Navigate2来用IE打开指定网页。

COM笔记(二)

自注册进程内组件必须实现DllRegisterServer和DllUnregisterServer,通过regsvr32.exe实现注册表的注册与卸载。

自注册进程外组件必须处理命令行参数/RegServer和/UnregServer,通过它实现注册表的注册与卸载。

进程外组件模型与进程和ntdll.dll的模型类似,只和存根打交道,由存根通过LPC/RPC完成交互。

参数列集:参数及调用等信息打包传递的过程;散集:解包过程。

为什么要用注册表?为了实现组件位置透明!由COM库负责读取并创建组件(对象)。

COM规定,每一个COM对象应该有一个相应的类厂对象。为什么要有类厂这层间接性?

DllGetClassObject(类厂对象标识, IID_IClassFactory, 类厂接口指针)

类厂的LockServer函数引入锁计数是为了防止组件的所有对象都已释放,但仍需保留类厂接口指针用以在不确定的时候再创建对象。

CoGetClassObject(COM库)--->位置透明性--->DllGetClassObject(组件实现并导出)--->创建类厂并获得其指针接口--->

CoGetClassObject(COM库)--->位置透明性--->启动进程外组件进程--->CoRegisterClassObject(自注册类厂)--->返回类厂信息--->

CoCreateInstance是对CoGetClassObject的封装,不需要直接和类厂打交道了,直接获得对象的接口指针。CoCreateInstanceEx用于创建远程机器上的COM对象。

聚合模型不仅需要外包对象的支持,还需要被聚合对象的支持。因为外包对象会直接返回被聚合对象的接口指针给客户,通过该接口指针QueryInterface IUnkown接口及外包对象的接口时必须满足COM的要求。

要实现聚合外包对象需把自己的IUnkown接口指针传递给被聚合对象保存;被聚合对象实现IUnkown(即委托的IUnkown)和非委托的IUnkown两个IUnkown接口,根据是否有外包对象传入的IUnkown接口指针来调用外包对象的接口或自己的非委托IUnkown。

COM线程类型:与UI线程相对应,有消息循环的叫套件线程;与辅助线程对应,没有消息循环的叫自由线程。COM的线程特征是针对COM对象的,而非COM组件。

无觅相关文章插件,快速提升流量