com기술내막-독서노트(3)
이 장에서 고객이 구성 요소에 지원하는 인터페이스, 구성 요소가 어떻게 대답하는지, 그리고 이런 요청 응답 방식의 결과를 토론했다.
고객과 구성 요소의 상호작용은 모두 인터페이스를 통해 이루어진다.클라이언트 프로그램이 구성 요소의 다른 인터페이스를 조회할 때도 인터페이스를 통해 완성되기 때문에 모든COM 구성 요소는 클라이언트 프로그램과 구성 요소가 통신할 수 있도록 공통된 인터페이스를 실현해야 한다.
이 커넥터가 바로 아이언노우입니다.IUnknown의 정의는 Win32 SDK의 UNKNWN입니다.H-헤드 파일의 정의는 다음과 같습니다.
interface IUnknown
{
virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv) = 0;
virtual ULONG __stdcall AddRef() = 0;
virtual ULONG __stdcall Release() = 0;
}
모든COM 인터페이스는 IUnknown 인터페이스를 계승하고 실현해야 합니다. 모든COM 인터페이스의 앞의 세 함수는QueryInterface,AddRef,Release입니다. 그렇지 않으면 COM 인터페이스가 아닙니다.인터페이스 때문에
모두COM 구성 요소 내부에서 이루어지기 때문에 클라이언트 프로그램은 어떤 인터페이스의QueryInterface 함수를 사용하여 구성 요소가 지원하는 다른 인터페이스를 얻을 수 있습니다. 예를 들어 IX 인터페이스를 통해 같은 구성 요소가 실현하는 IY 인터페이스를 얻을 수 있습니다.
IX 인터페이스의 메모리 다이어그램
QueryInterface의 첫 번째 파라미터는 인터페이스 식별자 IID이고 두 번째 파라미터는 검색한 인터페이스 바늘을 되돌려주는 데 사용되며 HRESULT 되돌려주는 값은 SUCCEEDED 또는FAILED 매크로로 성공 여부를 검증합니다.
이 장에서 저자는 클라이언트에서 IUnknown *CreateInstance () 함수를 사용하여 구성 요소를 만들고 가져오는 IUnkown 인터페이스 바늘을 가져옵니다.이것은 결코 COM 구성 요소를 만드는 진정한 방법이 아니다. 6,7장에서 소개할 것이다.이 장의 예는 세 부분으로 나뉘는데 그것이 바로 구성 요소의 인터페이스 정의, 구성 요소의 실현,main 함수 고객 부분이다.
//IUnkown.cpp
//use:cl IUnkown.cpp UUID.lib
//
#include <iostream>
#include <string>
#include <objbase.h>
using namespace std;
void trace(string msg)
{
cout<<msg<<endl;
}
//Interfaces
interface IX:IUnknown
{
virtual void __stdcall Fx() = 0;
};
interface IY:IUnknown
{
virtual void __stdcall Fy() = 0;
};
interface IZ:IUnknown
{
virtual void __stdcall Fz() = 0;
};
extern const IID IID_IX ;
extern const IID IID_IY ;
extern const IID IID_IZ ;
//Component
class CA:public IX, public IY
{
virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv);
virtual ULONG __stdcall AddRef()
{
return 0;
}
virtual ULONG __stdcall Release()
{
return 0;
}
virtual void __stdcall Fx()
{
cout<<"Fx"<<endl;
}
virtual void __stdcall Fy()
{
cout<<"Fy"<<endl;
}
};
HRESULT __stdcall CA::QueryInterface(const IID &iid, void **ppv)
{
if(iid == IID_IUnknown)
{
trace("Return pointer to IUnkown");
*ppv = static_cast<IX*>(this);
}
else if(iid == IID_IX)
{
trace("pointer to IX");
*ppv = static_cast<IX*>(this);
}
else if(iid == IID_IY)
{
trace("return pointer to IY");
*ppv = static_cast<IY*>(this);
}
else
{
trace("Interface not supported");
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK;
}
//Create function
IUnknown *CreateInstance()
{
IUnknown *pI = static_cast<IX*>(new CA);
pI->AddRef();
return pI;
}
// IIDs
// {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IY = {0x32bb8321, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// {32bb8322-b41b-11cf-a6bb-0080c7b2d682}
static const IID IID_IZ = {0x32bb8322, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
///////////////////////////////////////////////////////
//Client
///////////////////////////////////////////////////////
int main(void)
{
HRESULT hr;
trace("Client: Get Iunkown pointer");
IUnknown *pIunknown = CreateInstance();
trace("Client: Get interface IX");
IX *pIx = NULL;
hr = pIunknown->QueryInterface(IID_IX, (void**)&pIx);
if(SUCCEEDED(hr))
{
trace("Client:Succeeded get IX");
pIx->Fx();
}
trace("Client: Get interface IY");
IY *pIy = NULL;
hr = pIunknown->QueryInterface(IID_IY, (void**)&pIy);
if(SUCCEEDED(hr))
{
trace("Client: Succeeded get IY");
pIy->Fy();
}
trace("Client: Ask for an unsupported interface");
IZ *pIz = NULL;
hr = pIunknown->QueryInterface(IID_IZ, (void**)&pIz);
if(SUCCEEDED(hr))
{
trace("Client: Succeeded get IZ");
pIz->Fz();
}
else
{
trace("Client: Could not get interface IZ");
}
trace("Client: Get interface IUnkown from IY");
IY *pIyFromIx = NULL;
hr = pIx->QueryInterface(IID_IY, (void**)&pIyFromIx);
if(SUCCEEDED(hr))
{
trace("Client: Succeeded get Iy");
pIyFromIx->Fy();
}
IUnknown *pIunknownFromIy = NULL;
hr = pIy->QueryInterface(IID_IUnknown, (void**)&pIunknownFromIy);
if(SUCCEEDED(hr))
{
if(pIunknownFromIy == pIunknown)
{
cout<<"pIupIunkownFromIy == pIunkown"<<endl;
}
else
{
cout<<"pIupIunkownFromIy != pIunkown"<<endl;
}
}
delete pIunknown;
return 0;
}
실행 결과:
이 장에는 몇 가지 주의해야 할 문제가 있다.
1.class CA: public IX, public IY
이것은 인터페이스의 메모리 구조를 파괴하기 때문에 가상 다중 계승 방식을 사용할 수 없다.동시staticcast
CA의 메모리 구조는 다음과 같습니다.
이 안에는 C++ 클래스의 메모리 레이아웃이 관련되어 있으며 vtbl 바늘은 클래스의 메모리에서 가장 앞에 있습니다.그림에서도 IX 인터페이스의 IUnknown과 IY 인터페이스를 계승하는 IUnknown의 주소가 다르다는 것을 알 수 있다.staticcast
2. 인터페이스 집합의 문제를 되돌려줍니다
고객에게 필요한 구성 요소 인터페이스에만 관심을 가져야 하며, 구성 요소가 지원하는 모든 인터페이스를 되돌릴 필요는 없다.그러나QueryInterface의 하나하나 조회는 시간이 많이 걸린다. 이를 위해 하나의 구성 요소 종류로 인터페이스 집합을 표시할 수 있다. 6장에서 상세하게 논의할 것이다.
3. 인터페이스 업그레이드 문제
하나의 IID는 인터페이스에 대응합니다. 오래된 인터페이스에 함수를 추가하거나 변경할 필요가 있으면 인터페이스를 다시 정의하고 새로운 IID를 지정해야 합니다. 오래된 인터페이스에 함수를 추가하지 않고 새 인터페이스는 오래된 인터페이스를 계승할 수 있습니다.새 인터페이스의 이름은 오래된 인터페이스 이름 뒤에 숫자를 붙이는 것이 가장 좋다. 예를 들어 IFly, 새 인터페이스는 IFly2이다.
4.QueryInterface에는 몇 가지 규칙이 있는데 한번 보셔야 합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.