//------------------------------------------------------------------------------
// 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);
	UNREFERENCED_PARAMETER(lRef);
    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);
}
 

V303 The function 'GetWindowLong' is deprecated in the Win64 system. It is safer to use the 'GetWindowLongPtr' function.

V303 The function 'SetWindowLong' is deprecated in the Win64 system. It is safer to use the 'SetWindowLongPtr' function.