//------------------------------------------------------------------------------ | |
// File: CProp.cpp | |
// | |
// Desc: DirectShow base classes - implements CBasePropertyPage class. | |
// | |
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. | |
//------------------------------------------------------------------------------ | |
#include <streams.h> | |
// Constructor for the base property page class. As described in the header | |
// file we must be initialised with dialog and title resource identifiers. | |
// The class supports IPropertyPage and overrides AddRef and Release calls | |
// to keep track of the reference counts. When the last count is released | |
// we call SetPageSite(NULL) and SetObjects(0,NULL) to release interfaces | |
// previously obtained by the property page when it had SetObjects called | |
CBasePropertyPage::CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name | |
__inout_opt LPUNKNOWN pUnk, // COM Delegator | |
int DialogId, // Resource ID | |
int TitleId) : // To get tital | |
CUnknown(pName,pUnk), | |
m_DialogId(DialogId), | |
m_TitleId(TitleId), | |
m_hwnd(NULL), | |
m_Dlg(NULL), | |
m_pPageSite(NULL), | |
m_bObjectSet(FALSE), | |
m_bDirty(FALSE) | |
{ | |
} | |
#ifdef UNICODE | |
CBasePropertyPage::CBasePropertyPage(__in_opt LPCSTR pName, // Debug only name | |
__inout_opt LPUNKNOWN pUnk, // COM Delegator | |
int DialogId, // Resource ID | |
int TitleId) : // To get tital | |
CUnknown(pName,pUnk), | |
m_DialogId(DialogId), | |
m_TitleId(TitleId), | |
m_hwnd(NULL), | |
m_Dlg(NULL), | |
m_pPageSite(NULL), | |
m_bObjectSet(FALSE), | |
m_bDirty(FALSE) | |
{ | |
} | |
#endif | |
// Increment our reference count | |
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingAddRef() | |
{ | |
LONG lRef = InterlockedIncrement(&m_cRef); | |
ASSERT(lRef > 0); | |
return max(ULONG(m_cRef),1ul); | |
} | |
// Release a reference count and protect against reentrancy | |
STDMETHODIMP_(ULONG) CBasePropertyPage::NonDelegatingRelease() | |
{ | |
// If the reference count drops to zero delete ourselves | |
LONG lRef = InterlockedDecrement(&m_cRef); | |
if (lRef == 0) { | |
m_cRef++; | |
SetPageSite(NULL); | |
SetObjects(0,NULL); | |
delete this; | |
return ULONG(0); | |
} else { | |
// Don't touch m_cRef again here! | |
return max(ULONG(lRef),1ul); | |
} | |
} | |
// Expose our IPropertyPage interface | |
STDMETHODIMP | |
CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,__deref_out void **ppv) | |
{ | |
if (riid == IID_IPropertyPage) { | |
return GetInterface((IPropertyPage *)this,ppv); | |
} else { | |
return CUnknown::NonDelegatingQueryInterface(riid,ppv); | |
} | |
} | |
// Get the page info so that the page site can size itself | |
STDMETHODIMP CBasePropertyPage::GetPageInfo(__out LPPROPPAGEINFO pPageInfo) | |
{ | |
CheckPointer(pPageInfo,E_POINTER); | |
WCHAR wszTitle[STR_MAX_LENGTH]; | |
WideStringFromResource(wszTitle,m_TitleId); | |
// Allocate dynamic memory for the property page title | |
LPOLESTR pszTitle; | |
HRESULT hr = AMGetWideString(wszTitle, &pszTitle); | |
if (FAILED(hr)) { | |
NOTE("No caption memory"); | |
return hr; | |
} | |
pPageInfo->cb = sizeof(PROPPAGEINFO); | |
pPageInfo->pszTitle = pszTitle; | |
pPageInfo->pszDocString = NULL; | |
pPageInfo->pszHelpFile = NULL; | |
pPageInfo->dwHelpContext = 0; | |
// Set defaults in case GetDialogSize fails | |
pPageInfo->size.cx = 340; | |
pPageInfo->size.cy = 150; | |
GetDialogSize(m_DialogId, DialogProc,0L,&pPageInfo->size); | |
return NOERROR; | |
} | |
// Handles the messages for our property window | |
INT_PTR CALLBACK CBasePropertyPage::DialogProc(HWND hwnd, | |
UINT uMsg, | |
WPARAM wParam, | |
LPARAM lParam) | |
{ | |
CBasePropertyPage *pPropertyPage; | |
switch (uMsg) { | |
case WM_INITDIALOG: | |
_SetWindowLongPtr(hwnd, DWLP_USER, lParam); | |
// This pointer may be NULL when calculating size | |
pPropertyPage = (CBasePropertyPage *) lParam; | |
if (pPropertyPage == NULL) { | |
return (LRESULT) 1; | |
} | |
pPropertyPage->m_Dlg = hwnd; | |
} | |
// This pointer may be NULL when calculating size | |
pPropertyPage = _GetWindowLongPtr<CBasePropertyPage*>(hwnd, DWLP_USER); | |
if (pPropertyPage == NULL) { | |
return (LRESULT) 1; | |
} | |
return pPropertyPage->OnReceiveMessage(hwnd,uMsg,wParam,lParam); | |
} | |
// Tells us the object that should be informed of the property changes | |
STDMETHODIMP CBasePropertyPage::SetObjects(ULONG cObjects,__in_ecount_opt(cObjects) LPUNKNOWN *ppUnk) | |
{ | |
if (cObjects == 1) { | |
if ((ppUnk == NULL) || (*ppUnk == NULL)) { | |
return E_POINTER; | |
} | |
// Set a flag to say that we have set the Object | |
m_bObjectSet = TRUE ; | |
return OnConnect(*ppUnk); | |
} else if (cObjects == 0) { | |
// Set a flag to say that we have not set the Object for the page | |
m_bObjectSet = FALSE ; | |
return OnDisconnect(); | |
} | |
DbgBreak("No support for more than one object"); | |
return E_UNEXPECTED; | |
} | |
// Create the window we will use to edit properties | |
STDMETHODIMP CBasePropertyPage::Activate(HWND hwndParent, | |
LPCRECT pRect, | |
BOOL fModal) | |
{ | |
CheckPointer(pRect,E_POINTER); | |
// Return failure if SetObject has not been called. | |
if (m_bObjectSet == FALSE) { | |
return E_UNEXPECTED; | |
} | |
if (m_hwnd) { | |
return E_UNEXPECTED; | |
} | |
m_hwnd = CreateDialogParam(g_hInst, | |
MAKEINTRESOURCE(m_DialogId), | |
hwndParent, | |
DialogProc, | |
(LPARAM) this); | |
if (m_hwnd == NULL) { | |
return E_OUTOFMEMORY; | |
} | |
OnActivate(); | |
Move(pRect); | |
return Show(SW_SHOWNORMAL); | |
} | |
// Set the position of the property page | |
STDMETHODIMP CBasePropertyPage::Move(LPCRECT pRect) | |
{ | |
CheckPointer(pRect,E_POINTER); | |
if (m_hwnd == NULL) { | |
return E_UNEXPECTED; | |
} | |
MoveWindow(m_hwnd, // Property page handle | |
pRect->left, // x coordinate | |
pRect->top, // y coordinate | |
WIDTH(pRect), // Overall window width | |
HEIGHT(pRect), // And likewise height | |
TRUE); // Should we repaint it | |
return NOERROR; | |
} | |
// Display the property dialog | |
STDMETHODIMP CBasePropertyPage::Show(UINT nCmdShow) | |
{ | |
// Have we been activated yet | |
if (m_hwnd == NULL) { | |
return E_UNEXPECTED; | |
} | |
// Ignore wrong show flags | |
if ((nCmdShow != SW_SHOW) && (nCmdShow != SW_SHOWNORMAL) && (nCmdShow != SW_HIDE)) { | |
return E_INVALIDARG; | |
} | |
ShowWindow(m_hwnd,nCmdShow); | |
InvalidateRect(m_hwnd,NULL,TRUE); | |
return NOERROR; | |
} | |
// Destroy the property page dialog | |
STDMETHODIMP CBasePropertyPage::Deactivate(void) | |
{ | |
if (m_hwnd == NULL) { | |
return E_UNEXPECTED; | |
} | |
// Remove WS_EX_CONTROLPARENT before DestroyWindow call | |
DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE); | |
dwStyle = dwStyle & (~WS_EX_CONTROLPARENT); | |
// Set m_hwnd to be NULL temporarily so the message handler | |
// for WM_STYLECHANGING doesn't add the WS_EX_CONTROLPARENT | |
// style back in | |
HWND hwnd = m_hwnd; | |
m_hwnd = NULL; | |
SetWindowLong(hwnd, GWL_EXSTYLE, dwStyle); | |
m_hwnd = hwnd; | |
OnDeactivate(); | |
// Destroy the dialog window | |
DestroyWindow(m_hwnd); | |
m_hwnd = NULL; | |
return NOERROR; | |
} | |
// Tells the application property page site | |
STDMETHODIMP CBasePropertyPage::SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite) | |
{ | |
if (pPageSite) { | |
if (m_pPageSite) { | |
return E_UNEXPECTED; | |
} | |
m_pPageSite = pPageSite; | |
m_pPageSite->AddRef(); | |
} else { | |
if (m_pPageSite == NULL) { | |
return E_UNEXPECTED; | |
} | |
m_pPageSite->Release(); | |
m_pPageSite = NULL; | |
} | |
return NOERROR; | |
} | |
// Apply any changes so far made | |
STDMETHODIMP CBasePropertyPage::Apply() | |
{ | |
// In ActiveMovie 1.0 we used to check whether we had been activated or | |
// not. This is too constrictive. Apply should be allowed as long as | |
// SetObject was called to set an object. So we will no longer check to | |
// see if we have been activated (ie., m_hWnd != NULL), but instead | |
// make sure that m_bObjectSet is TRUE (ie., SetObject has been called). | |
if (m_bObjectSet == FALSE) { | |
return E_UNEXPECTED; | |
} | |
// Must have had a site set | |
if (m_pPageSite == NULL) { | |
return E_UNEXPECTED; | |
} | |
// Has anything changed | |
if (m_bDirty == FALSE) { | |
return NOERROR; | |
} | |
// Commit derived class changes | |
HRESULT hr = OnApplyChanges(); | |
if (SUCCEEDED(hr)) { | |
m_bDirty = FALSE; | |
} | |
return hr; | |
} | |
// Base class definition for message handling | |
INT_PTR CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) | |
{ | |
// we would like the TAB key to move around the tab stops in our property | |
// page, but for some reason OleCreatePropertyFrame clears the CONTROLPARENT | |
// style behind our back, so we need to switch it back on now behind its | |
// back. Otherwise the tab key will be useless in every page. | |
// | |
CBasePropertyPage *pPropertyPage; | |
{ | |
pPropertyPage = _GetWindowLongPtr<CBasePropertyPage*>(hwnd, DWLP_USER); | |
if (pPropertyPage->m_hwnd == NULL) { | |
return 0; | |
} | |
switch (uMsg) { | |
case WM_STYLECHANGING: | |
if (wParam == GWL_EXSTYLE) { | |
LPSTYLESTRUCT lpss = (LPSTYLESTRUCT)lParam; | |
lpss->styleNew |= WS_EX_CONTROLPARENT; | |
return 0; | |
} | |
} | |
} | |
return DefWindowProc(hwnd,uMsg,wParam,lParam); | |
} | |