Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
373 lines
10 KiB
C++
373 lines
10 KiB
C++
//==========================================================================;
|
|
//
|
|
// 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 - 1998 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)
|
|
{
|
|
// 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.
|
|
//
|
|
// control parent bit crashes USER on win9x from graphedt's use of
|
|
// property pages.
|
|
//
|
|
// since these global variables should be zeroed when they are
|
|
// faulted in, g_amPlatform shouldn't be uninitialized (and zero
|
|
// is VER_PLATFORM_WIN32s). you must call our dll entry point (or
|
|
// set this variable yourself).
|
|
//
|
|
ASSERT(g_amPlatform != 0);
|
|
|
|
if(g_amPlatform == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
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);
|
|
}
|
|
|