CUnknown 사용
[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드가 DirectShow 대신 Media Foundation에서 MediaPlayer, IMFMediaEngine 및 오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]
DirectShow는 CUnknown 이라는 기본 클래스에서 IUnknown을 구현합니다. CUnknown을 사용하여 다른 클래스를 파생하고 구성 요소 간에 변경되는 메서드만 재정의할 수 있습니다. DirectShow의 다른 기본 클래스 대부분은 CUnknown에서 파생되므로 구성 요소는 CUnknown 또는 다른 기본 클래스에서 직접 상속할 수 있습니다.
INonDelegatingUnknown
CUnknown은INonDelegatingUnknown을 구현합니다. 내부적으로 참조 수를 관리하며, 대부분의 경우 파생 클래스는 변경 없이 두 개의 참조 계산 메서드를 상속할 수 있습니다. 참조 수가 0으로 떨어지면 CUnknown 이 자체적으로 삭제됩니다. 반면에 기본 클래스의 메서드는 IID_IUnknown 이외의 IID를 받으면 E_NOINTERFACE 반환하므로 CUnknown::NonDelegatingQueryInterface를 재정의해야 합니다. 파생 클래스에서 다음 예제와 같이 지원하는 인터페이스의 IID를 테스트합니다.
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
if (riid == IID_ISomeInterface)
{
return GetInterface((ISomeInterface*)this, ppv);
}
// Default: Call parent class method.
// The CUnknown class must be in the inheritance chain.
return CParentClass::NonDelegatingQueryInterface(riid, ppv);
}
유틸리티 함수 GetInterface ( COM 도우미 함수 참조)는 포인터를 설정하고, 스레드로부터 안전한 방식으로 참조 횟수를 증가시키고, S_OK 반환합니다. 기본 사례에서 기본 클래스 메서드를 호출하고 결과를 반환합니다. 다른 기본 클래스에서 파생되는 경우 대신 NonDelegatingQueryInterface 메서드를 호출합니다. 이렇게 하면 부모 클래스에서 지원하는 모든 인터페이스를 지원할 수 있습니다.
IUnknown
앞에서 설명한 대로 IUnknown의 위임 버전은 모든 구성 요소에 대해 동일합니다. 이는 위임되지 않은 버전의 올바른 instance 호출하는 것 이상의 작업을 수행하지 않기 때문입니다. 편의를 위해 헤더 파일 Combase.h에는 세 가지 위임 메서드를 인라인 메서드로 선언하는 매크로 DECLARE_IUNKNOWN 포함되어 있습니다. 다음 코드로 확장됩니다.
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) {
return GetOwner()->QueryInterface(riid,ppv);
};
STDMETHODIMP_(ULONG) AddRef() {
return GetOwner()->AddRef();
};
STDMETHODIMP_(ULONG) Release() {
return GetOwner()->Release();
};
유틸리티 함수 CUnknown::GetOwner 는 이 구성 요소를 소유하는 구성 요소의 IUnknown 인터페이스에 대한 포인터를 검색합니다. 집계된 구성 요소의 경우 소유자는 외부 구성 요소입니다. 그렇지 않으면 구성 요소가 자체 소유합니다. 클래스 정의의 public 섹션에 DECLARE_IUNKNOWN 매크로를 포함합니다.
클래스 생성자
클래스 생성자는 클래스와 관련된 모든 작업에 더해 부모 클래스에 대한 생성자 메서드를 호출해야 합니다. 다음 예제는 일반적인 생성자 메서드입니다.
CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr)
: CUnknown(tszName, pUnk, phr)
{
/* Other initializations */
};
메서드는 CUnknown 생성자 메서드에 직접 전달하는 다음 매개 변수를 사용합니다.
- tszName 은 구성 요소의 이름을 지정합니다.
- pUnk 는 집계 IUnknown에 대한 포인터입니다.
- pHr 은 메서드의 성공 또는 실패를 나타내는 HRESULT 값에 대한 포인터입니다.
요약
다음 예제에서는 IUnknown 을 지원하는 파생 클래스와 ISomeInterface라는 가상 인터페이스를 보여 줍니다.
class CMyComponent : public CUnknown, public ISomeInterface
{
public:
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
if( riid == IID_ISomeInterface )
{
return GetInterface((ISomeInterface*)this, ppv);
}
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
}
CMyComponent(TCHAR *tszName, LPUNKNOWN pUnk, HRESULT *phr)
: CUnknown(tszName, pUnk, phr)
{
/* Other initializations */
};
// More declarations will be added later.
};
이 예제에서는 다음 사항을 보여 줍니다.
- CUnknown 클래스는 IUnknown 인터페이스를 구현합니다. 새 구성 요소는 CUnknown 및 구성 요소가 지원하는 모든 인터페이스에서 상속됩니다. 구성 요소는 CUnknown에서 상속되는 다른 기본 클래스에서 파생할 수 있습니다.
- DECLARE_IUNKNOWN 매크로는 위임된 IUnknown 메서드를 인라인 메서드로 선언합니다.
- CUnknown 클래스는 INonDelegatingUnknown에 대한 구현을 제공합니다.
- IUnknown 이외의 인터페이스를 지원하려면 파생 클래스가 NonDelegatingQueryInterface 메서드를 재정의하고 새 인터페이스의 IID를 테스트해야 합니다.
- 클래스 생성자는 CUnknown에 대한 생성자 메서드를 호출합니다.
필터를 작성하는 다음 단계는 애플리케이션이 구성 요소의 새 인스턴스를 만들 수 있도록 하는 것입니다. 이를 위해서는 DLL과 클래스 팩터리 및 클래스 생성자 메서드에 대한 관계를 이해해야 합니다. 자세한 내용은 DirectShow 필터 DLL을 만드는 방법을 참조하세요.
관련 항목