如何建立filter屬性頁。
下面通過一個例子說明屬性頁的建立方法
- Step 1. Define a Mechanism for Setting the Property
- Step 2. Implement ISpecifyPropertyPages
- Step 3. Support QueryInterface
- Step 4. Create the Property Page
- Step 5. Store a Pointer to the Filter
- Step 6. Initialize the Dialog
- Step 7. Handle Window Messages
- Step 8. Apply Property Changes
- Step 9. Disconnect the Property Page
- Step 10. Support COM Registration
1.定義設置屬性的機制
- Expose a custom COM interface.
- Support Automation properties, through IDispatch.
- Expose the IPropertyBag interface and define a set of named properties.
這裏以實現COM接口爲例將此過程:
// Always create new GUIDs! Never copy a GUID from an example.
DEFINE_GUID(IID_ISaturation, 0x19412d6e, 0x6401,
0x475c, 0xb0, 0x48, 0x7a, 0xd2, 0x96, 0xe1, 0x6a, 0x19);
interface ISaturation : public IUnknown
{
STDMETHOD(GetSaturation)(long *plSat) = 0;
STDMETHOD(SetSaturation)(long lSat) = 0;
};
class CGrayFilter : public ISaturation, /* Other inherited classes. */
{
private:
CCritSec m_csShared; // Protects shared data.
long m_lSaturation; // Saturation level.
public:
STDMETHODIMP GetSaturation(long *plSat)
{
if (!plSat) return E_POINTER;
CAutoLock lock(&m_csShared);
*plSat = m_lSaturation;
return S_OK;
}
STDMETHODIMP SetSaturation(long lSat)
{
if (lSat < SATURATION_MIN || lSat > SATURATION_MAX)
{
return E_INVALIDARG;
}
CAutoLock lock(&m_csShared);
m_lSaturation = lSat;
return S_OK;
}
};
2.實現IspecifyPropertyPages
在自己的filter類中實現IspecifyPropertyPages接口,該接口只有一個方法GetPages,返回filter支持的所有屬性頁的CLSID數組。首先應該在頭文件中聲明屬性頁的CLSID。
// Always create new GUIDs! Never copy a GUID from an example.
DEFINE_GUID(CLSID_SaturationProp, 0xa9bd4eb, 0xded5,
0x4df0, 0xba, 0xf6, 0x2c, 0xea, 0x23, 0xf5, 0x72, 0x61);
接着實現GetPages方法:
class CGrayFilter : public ISaturation,
public ISpecifyPropertyPages,
/* Other inherited classes. */
{
public:
STDMETHODIMP GetPages(CAUUID *pPages)
{
if (pPages == NULL) return E_POINTER;
pPages->cElems = 1;
pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID));
if (pPages->pElems == NULL)
{
return E_OUTOFMEMORY;
}
pPages->pElems[0] = CLSID_SaturationProp;
return S_OK;
}
};
/* ... */
}
3.支持QueryInterface
可以通過下面的步驟暴露新的接口:
- Include the DECLARE_IUNKNOWN macro in the public declaration section of your filter:
public:
DECLARE_IUNKNOWN;
·
OverrideCUnknown::NonDelegatingQueryInterface
to check for the IIDs of the two interfaces:STDMETHODIMP CGrayFilter::NonDelegatingQueryInterface(REFIID riid,
void **ppv)
{
if (riid == IID_ISpecifyPropertyPages)
{
return GetInterface(static_cast<ISpecifyPropertyPages*>(this),
ppv);
}
if (riid == IID_ISaturation)
{
return GetInterface(static_cast<IYuvGray*>(this), ppv);
}
return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}
4.創建屬性頁
到此已經完成了filter屬性頁所需的所有支持,接下來要正式實現屬性頁了。首先從CbasePropertyPage繼承一個新類。
class CGrayProp : public CBasePropertyPage
{
private:
ISaturation *m_pGray; // Pointer to the filter's custom interface.
long m_lVal // Store the old value, so we can revert.
long m_lNewVal; // New value.
public:
/* ... */
};
接着,創建相應的對話框資源和字符串資源,其中字符串將出現在屬性頁的tab中。這兩個資源的ID就是CbasePropertyPage構造函數的參數:
CGrayProp::CGrayProp(IUnknown *pUnk) :
CBasePropertyPage(NAME("GrayProp"), pUnk, IDD_PROPPAGE, IDS_PROPPAGE_TITLE),
m_pGray(0)
{ }
- OnConnect is called when the client creates the property page. It sets the IUnknown pointer to the filter.
- OnActivate is called when the dialog is created.
- OnReceiveMessage is called when the dialog receives a window message.
- OnApplyChanges is called when the user commits the property changes by clicking the OK or Apply button.
- OnDisconnect is called when the user dismisses the property sheet.
5.保存指向Filter的指針。
HRESULT CGrayProp::OnConnect(IUnknown *pUnk)
{
if (pUnk == NULL)
{
return E_POINTER;
}
ASSERT(m_pGray == NULL);
return pUnk->QueryInterface(IID_ISaturation,
reinterpret_cast<void**>(&m_pGray));
}
6.初始化對話框
HRESULT CGrayProp::OnActivate(void)
{
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = ICC_BAR_CLASSES;
if (InitCommonControlsEx(&icc) == FALSE)
{
return E_FAIL;
}
ASSERT(m_pGray != NULL);
HRESULT hr = m_pGray->GetSaturation(&m_lVal);
if (SUCCEEDED(hr))
{
SendDlgItemMessage(m_Dlg, IDC_SLIDER1, TBM_SETRANGE, 0,
MAKELONG(SATURATION_MIN, SATURATION_MAX));
SendDlgItemMessage(m_Dlg, IDC_SLIDER1, TBM_SETTICFREQ,
(SATURATION_MAX - SATURATION_MIN) / 10, 0);
SendDlgItemMessage(m_Dlg, IDC_SLIDER1, TBM_SETPOS, 1, m_lVal);
}
return hr;
}
SendDlgItemMessage
是一個消息傳遞函數,與之類似的還有
SendMessage
,用於控制相應的控件,傳遞消息。
Step 7. Handle Window Messages7.處理window消息
- Set the m_bDirty variable of the property page to TRUE.
- Call the IPropertyPageSite::OnStatusChange method of the property frame with the PROPPAGESTATUS_DIRTY flag. This flag informs the property frame that it should enable the Apply button. The CBasePropertyPage::m_pPageSite member holds a pointer to the IPropertyPageSite interface.
private:
void SetDirty()
{
m_bDirty = TRUE;
if (m_pPageSite)
{
m_pPageSite->OnStatusChange(PROPPAGESTATUS_DIRTY);
}
}
BOOL CGrayProp::OnReceiveMessage(HWND hwnd,
UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
if (LOWORD(wParam) == IDC_DEFAULT)
{
// User clicked the 'Revert to Default' button.
m_lNewVal = SATURATION_DEFAULT;
m_pGray->SetSaturation(m_lNewVal);
// Update the slider control.
SendDlgItemMessage(m_Dlg, IDC_SLIDER1, TBM_SETPOS, 1,
m_lNewVal);
SetDirty();
return (LRESULT) 1;
}
break;
case WM_HSCROLL:
{
// User moved the slider.
switch(LOWORD(wParam))
{
case TB_PAGEDOWN:
case SB_THUMBTRACK:
case TB_PAGEUP:
m_lNewVal = SendDlgItemMessage(m_Dlg, IDC_SLIDER1,
TBM_GETPOS, 0, 0);
m_pGray->SetSaturation(m_lNewVal);
SetDirty();
}
return (LRESULT) 1;
}
} // Switch.
// Let the parent class handle the message.
return CBasePropertyPage::OnReceiveMessage(hwnd,uMsg,wParam,lParam);
}
8.生效屬性的改變
HRESULT CGrayProp::OnApplyChanges(void)
{
m_lVal = m_lNewVal;
return S_OK;
}
9.斷開屬性頁連接
HRESULT CGrayProp::OnDisconnect(void)
{
if (m_pGray)
{
// If the user clicked OK, m_lVal holds the new value.
// Otherwise, if the user clicked Cancel, m_lVal is the old value.
m_pGray->SetSaturation(m_lVal);
m_pGray->Release();
m_pGray = NULL;
}
return S_OK;
}
10.支持COM組件註冊
const AMOVIESETUP_FILTER FilterSetupData =
{
/* Not shown ... */
};
CFactoryTemplate g_Templates[] =
{
// This entry is for the filter.
{
wszName,
&CLSID_GrayFilter,
CGrayFilter::CreateInstance,
NULL,
&FilterSetupData
},
// This entry is for the property page.
{
L"Saturation Props",
&CLSID_SaturationProp,
CGrayProp::CreateInstance,
NULL, NULL
}
};
int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);
static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CGrayProp *pNewObject = new CGrayProp(pUnk);
if (pNewObject == NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pNewObject;
}