Archive for the ‘COM’ Category
tagVARIANT CComVariant源码剖析
星期四, 15 11 月, 2012ATL碎语CAtlModule CAtlBaseModule
星期二, 23 10 月, 2012// 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
星期日, 9 10 月, 2011浏览器与ActiveX控件交互时会弹出警告,去掉它必须实现IObjectSafety接口。当一个ActiveX实现了该接口时就是声明了它是安全的,那么用户因为使用此控件造成的损失应该由此控件厂商承担,所以还是谨慎的好。
关于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接口实现浏览器窗口
星期五, 9 9 月, 2011花了两天时间终于简单地实现了利用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)和容器窗口交互、通信。下面是实现存档:
另外,可以通过CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (LPVOID *)&m_pIWB2);再调用IWebBrowser2的Navigate2来用IE打开指定网页。
COM笔记(二)
星期二, 6 9 月, 2011自注册进程内组件必须实现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组件。