COM 和 OLE 的关系非常类似于微积分和物理的关系.
COM 是用来解决诸如如何将一个电子表格嵌入到字处理程序之类的问题. 此类问题的解决方案正是OLE.
运行时动态链接(动态改变组件) + 信息封装
一种开发与语言无关的组件库的方法.
DLL 的接口是它所输出的那些函数.
C++类的接口则是该类的一个成员函数集。
COM接口是一个包含一个函数指针数组的内存结构。
COM接口在C++中是用纯抽象基类实现的。
可以提供多个接口, 组件用类来实现,实现接口的所有成员。
__stdcall 标准调用约定, 函数将在返回到调用者之前将参数从栈中删除, 也就是Pascal调用。VB . All COM interface use __stdcall.
__cdecl 常规C/C++调用约定, 栈的清理工作由调用者完成.带变参函数.
定义一个纯抽象基类就是定义了相应的内存结构.但此结构只是在派生类中实现此抽象基类时才会被分配.派生类继承一个抽象基类时, 它将继承此内存结构.
不同实例共享同一 vtbl, 其中的元素指向虚拟成员函数的同一实现。各对象有不同的实例数据。 < 指向接口的指针指向vtbl>
interface IUnknown
{
virtual HRESULT _stdcall QueryInterface(const IID& iid, void** ppv) =0;
virtual ULONG _stdcall AddRef() = 0;
virtual ULONG _stdcall Release() = 0;
}

IUnknow* pI ...
IX* pIX = NULL;
HRESULT hr =pI->QueryInterface(IID_IX,(void**)&pIX);
if (SUCCEEDED(hr))
pIX->DoSomthing();

非虚拟方式继承IUnknown(?)

HRESULT _stdcall QueryInterface(cosnt IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
*ppv = static_cast<IX*>(this); // Not IUnknown*, multi-inheritance
else if(iid == IID_IX)
*ppv = static_cast<IX*>(this);
else if (iid == IID_IY)
*ppy = static_cast<IY*>(this);
else
{*ppv = null; return E_NONINTERFACE;}

static_cast<IUnknow*>(*ppv)->AddRef();
return S_OK;
}
继承两个接口将有两个对应的vtbl指针.
1. Initialize pointer pIX = NULL is encouraged.
2. Code Sample:
interface IX: IUnKnown {
virtual void _stdcall Fx() = 0;
}

interface IY: IUnKnown {
virtual void _stdcall Fy() = 0;
}

class CA: public IX, public IY {
//IUnKnown implementation
virtual HRESULT _stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG _stdcall AddRef() {return 0;}
virtual ULONG _stdcall Release() {return 0;}

// IX implementation
vitual void _stdcall Fx() {cout << "FX" << endl;}

// IY implementation
vitual void _stdcall Fy() {cout << "FY" << endl;}
}

IUnKnown* CreateInstance(){
IUnKnown* pI = static_cast<IX*> (new CA);
pI->AddRef();
return pI;
}

static const IID IID_IX = { 0x??, ....}
static const IID IID_IY = { 0x??, ....}

int main()
{
HRESULT hr;

IUnknown* pIUnknown = CreateInstance();

IX* pIX = NULL;
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if (SUCCEEDED(hr)){
pIX->Fx();
}

IY* pIY = NULL;
hr = pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
if (SUCCEEDED(hr)){
pIY->Fy();
}

}
3. The samilar Interface ---> IUnknown
// To determine whether the two interface point the same component.
BOOL IsSameComponent(IX* pIX; IY* pIY){
IUnknown* px1 = NULL;
IUnknown* py1 = NULL;

pIX->QueryInterface(IID_IUnknown, (void**)&px1);
pIY->QueryInterface(IID_IUnknown, (void**)&py1);

return px1 == py1 ;
}
4. Copy a pointer need to perform AddRef()
ULONG _stdcall AddRef() {
return ++m_cRef;
}

ULONG _stdcall Release() {
if (--m_cRef == 0){
delete this;
return 0;
}
return m_cRef;
}
Local interface pointer doesn't need AddRef()
5. Put the Component into DLL, DLL is simply a kind of style to publish Component, it is a component server.
6. Put extern "C" ahead of functions which are used to export can avoid adding type information by compiler.
?CreateInstance@@YAPAUUnknown@@XZ
dumpbin -exports Cmpt1.dll
DEF file
;
; Component1 module-definition file.
;

LIBRARY Compnt1.dll
DESCRIPTION 'Paco'
Exports
CreateInstance @1 PRIVATE
t
ypedef IUnknown* (*CREATEFUNCPTR)()

HINSTANCE hComponent = ::LoadLibrary(name);
if (hComponent == NULL ){
....
return NULL;
}
CREATEFUNCPTR CreateInstance = (CREATEFUNCPTR)::GetProcAddress(hComponent,"CreateInstance");

if (CreateInstance == NULL ){
....
return NULL;
}

return CreateInstance();
every exe application is performed in an individual process whch occupies 4GB address space.
6. HRESULT (Here's the RESULT)
3 Fields
32 bit
S_OK 0
S_FALSE 1
E_FAIL
....
if (hr == S_OK) ----****----- WRONG
if (SUCCEED(hr))
if (FAILED(hr))
7. GUID
128bit (16 byte)
UUIDGEN.EXE
Class/Component ---- CLSID
Interface ---- IID
Parameter --- Pass by Reference
8. Windows Registry
Component CLSID register in Registry.
HKEY_CLASSES_ROOT/CLSID/{0x..-0x..-.....}
/InprocServer32 ---- data(filename)
/ProgID ---- Name to remember easily <Program>.<Component>.<Version>
CLSIDFromProgID()
ProgIDFromCLSID()
Register itself <#define STDAPI extern "c" HRESULT _stdcall>
STDAPI DLLRegisterServer()
STDAPI DLLUnregisterServer()
Regsvr32.exe
9 COM library Functions <in EXE other than DLL>
OLE32.dll
HRESULT CoInitalize(void* reserved);
void CoUninitialize();
10.
HRESULT _stdcall CoCreateInstance(
const CLSID& clsid,
IUnknown* pIUnknownOuter, // Aggretion
DWORD dwClsContext, // Server Context.. In-proc
const IID& iid,
void** ppv
)
IX* pIX = NULL;
HRESULT hr = ::CoCreateInstance( CLSID_Component1,
NULL,
CLSCTX_INPROC_SERVER,
IID_IX,
(void**)&pIX);
if (SUCCEEDED(hr)){
pIX->Fx();
pIX->Release();
}
11. Factory
HRESULT _stdcall CoGetClassObject (
const CLSID& clsid,
DWORD dwClsContext,
COSERVER INFO* pServerInfo,
const IID& iid, // IID_IClassFactory
void** ppv // Pointer in a factory other than in component in CoCreateInstance()
)

CoGetClassObject() will call DLLGetClassObject() which should be implemented in DLL


interface IClassFactory: IUnknown
...{
HRESULT _stdcall CreateInstance (IUnknown* pUnknownOuter, const IID& iid, void** ppv);
HRESULT _stdcall LockServer(BOOL bLock);
}

So in fact, CoCreateInstance() is implemented by CoGetClassObject()

class CFactory : public IClassFactory
...{
CreateInstance () ...{ .... new CA;}
}

// Exports
STDAPI DLLGetClassObject() ...{... new CFactory...}
DLLMain () ...{ dwReason == DLL_PROCESS_ATTACH g_hModule = hModule;}

//***/**
DLLCanUnloadNow()
1. COM doesn't support implementation inheritance but support Interface inheritance.
2. Outer component consits the pointer of inner component.
3. 外部组件将调用转发给内部组件。--- 包容
聚合 , 包容的一个特例。
Boss (外部组件)
Veteran employee (内部组件) 聚合 --- 实现类似于c++的--> 操作符重载 class CA : IX{m_pIUnknown; } 返回接口指针 <代理IUnknown>
Novice employee (内部组件) 包容 --- 实现类似于c++的包含.class CA : IX, IY {m_pIY; }
COM 是用来解决诸如如何将一个电子表格嵌入到字处理程序之类的问题. 此类问题的解决方案正是OLE.
运行时动态链接(动态改变组件) + 信息封装
一种开发与语言无关的组件库的方法.
DLL 的接口是它所输出的那些函数.
C++类的接口则是该类的一个成员函数集。
COM接口是一个包含一个函数指针数组的内存结构。
COM接口在C++中是用纯抽象基类实现的。
可以提供多个接口, 组件用类来实现,实现接口的所有成员。
__stdcall 标准调用约定, 函数将在返回到调用者之前将参数从栈中删除, 也就是Pascal调用。VB . All COM interface use __stdcall.
__cdecl 常规C/C++调用约定, 栈的清理工作由调用者完成.带变参函数.
定义一个纯抽象基类就是定义了相应的内存结构.但此结构只是在派生类中实现此抽象基类时才会被分配.派生类继承一个抽象基类时, 它将继承此内存结构.
不同实例共享同一 vtbl, 其中的元素指向虚拟成员函数的同一实现。各对象有不同的实例数据。 < 指向接口的指针指向vtbl>






























继承两个接口将有两个对应的vtbl指针.
1. Initialize pointer pIX = NULL is encouraged.
2. Code Sample:

















































3. The samilar Interface ---> IUnknown
// To determine whether the two interface point the same component.









4. Copy a pointer need to perform AddRef()











Local interface pointer doesn't need AddRef()
5. Put the Component into DLL, DLL is simply a kind of style to publish Component, it is a component server.
6. Put extern "C" ahead of functions which are used to export can avoid adding type information by compiler.
?CreateInstance@@YAPAUUnknown@@XZ
dumpbin -exports Cmpt1.dll
DEF file








t















every exe application is performed in an individual process whch occupies 4GB address space.
6. HRESULT (Here's the RESULT)
3 Fields
32 bit
S_OK 0
S_FALSE 1
E_FAIL
....
if (hr == S_OK) ----****----- WRONG
if (SUCCEED(hr))
if (FAILED(hr))
7. GUID
128bit (16 byte)
UUIDGEN.EXE
Class/Component ---- CLSID
Interface ---- IID
Parameter --- Pass by Reference
8. Windows Registry
Component CLSID register in Registry.
HKEY_CLASSES_ROOT/CLSID/{0x..-0x..-.....}
/InprocServer32 ---- data(filename)
/ProgID ---- Name to remember easily <Program>.<Component>.<Version>
CLSIDFromProgID()
ProgIDFromCLSID()
Register itself <#define STDAPI extern "c" HRESULT _stdcall>
STDAPI DLLRegisterServer()
STDAPI DLLUnregisterServer()
Regsvr32.exe
9 COM library Functions <in EXE other than DLL>
OLE32.dll
HRESULT CoInitalize(void* reserved);
void CoUninitialize();
10.



















11. Factory






























1. COM doesn't support implementation inheritance but support Interface inheritance.
2. Outer component consits the pointer of inner component.
3. 外部组件将调用转发给内部组件。--- 包容
聚合 , 包容的一个特例。
Boss (外部组件)
Veteran employee (内部组件) 聚合 --- 实现类似于c++的--> 操作符重载 class CA : IX{m_pIUnknown; } 返回接口指针 <代理IUnknown>
Novice employee (内部组件) 包容 --- 实现类似于c++的包含.class CA : IX, IY {m_pIY; }