391 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			391 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //------------------------------------------------------------------------------
 | |
| // File: CProp.cpp
 | |
| //
 | |
| // Desc: DirectShow base classes - implements CBasePropertyPage class.
 | |
| //
 | |
| // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| #undef NOMINMAX
 | |
| #include <streams.h>
 | |
| 
 | |
| #ifndef max
 | |
| #define max(a, b) (((a) > (b)) ? (a) : (b))
 | |
| #endif
 | |
| 
 | |
| #ifndef min
 | |
| #define min(a, b) (((a) < (b)) ? (a) : (b))
 | |
| #endif
 | |
| 
 | |
| // 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 = (CBasePropertyPage *) GetWindowLongPtr(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 = (CBasePropertyPage *) GetWindowLongPtr(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);
 | |
| }
 | |
| 
 |