CPROP.CPP

//==========================================================================; 
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992 - 1997 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(TCHAR *pName, // Debug only name
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)
{
}


// 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

if (InterlockedDecrement(&m_cRef) == 0) {
m_cRef++;
SetPageSite(NULL);
SetObjects(0,NULL);
delete this;
return ULONG(0);
} else {
return max(ULONG(m_cRef),1ul);
}
}


// Expose our IPropertyPage interface

STDMETHODIMP
CBasePropertyPage::NonDelegatingQueryInterface(REFIID riid,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(LPPROPPAGEINFO pPageInfo)
{
CheckPointer(pPageInfo,E_POINTER);
WCHAR wszTitle[STR_MAX_LENGTH];
WideStringFromResource(wszTitle,m_TitleId);
int Length = (lstrlenW(wszTitle) + 1) * sizeof(WCHAR);

// Allocate dynamic memory for the property page title

LPOLESTR pszTitle = (LPOLESTR) QzTaskMemAlloc(Length);
if (pszTitle == NULL) {
NOTE("No caption memory");
return E_OUTOFMEMORY;
}

CopyMemory(pszTitle,wszTitle,Length);

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,(DLGPROC) DialogProc,0L,&pPageInfo->size);
return NOERROR;
}


// Handles the messages for our property window

BOOL CALLBACK CBasePropertyPage::DialogProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
CBasePropertyPage *pPropertyPage;

switch (uMsg) {

case WM_INITDIALOG:

SetWindowLong(hwnd, DWL_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 *) GetWindowLong(hwnd, DWL_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,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;
}

// Parent should control us so the user can tab out of property page

DWORD dwStyle = GetWindowLong(m_hwnd, GWL_EXSTYLE);
dwStyle = dwStyle | WS_EX_CONTROLPARENT;
SetWindowLong(m_hwnd, GWL_EXSTYLE, dwStyle);

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);
SetWindowLong(m_hwnd, GWL_EXSTYLE, dwStyle);

OnDeactivate();

// Destroy the dialog window

DestroyWindow(m_hwnd);
m_hwnd = NULL;
return NOERROR;
}


// Tells the application property page site

STDMETHODIMP CBasePropertyPage::SetPageSite(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

BOOL CBasePropertyPage::OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}