WindowsXP/base/fs/utils/dfrg/vwindowappcore.cpp
2025-04-27 07:49:33 -04:00

564 lines
15 KiB
C++

#include "stdafx.h"
#include "vApplication.hpp"
#include "vWindow.hpp"
// If VWCL_WRAP_WINDOWS_ONLY is defined, there is no need to register window classes
#ifdef VWCL_WRAP_WINDOWS_ONLY
#ifndef VWCL_NO_REGISTER_CLASSES
#define VWCL_NO_REGISTER_CLASSES
#endif
#endif
#ifndef VWCL_NO_GLOBAL_APP_OBJECT
// The one and only VApplication object
VApplication VTheApp;
// Access function
VWCL_API VApplication* VGetApp()
{ return &VTheApp; }
#endif
// Return a static string buffer to the applications title, or name
LPCTSTR VGetAppTitle()
{ return VGetApp()->AppTitle(); }
// Return the show command (ShowWindow() SW_xxx constant passed on command line)
int VGetCommandShow()
{ return VGetApp()->GetCommandShow(); }
// Return the global instance handle of the application or DLL
HINSTANCE VGetInstanceHandle()
{ return VGetApp()->GetInstanceHandle(); }
// Return the instance handle where resources are held
HINSTANCE VGetResourceHandle()
{ return VGetApp()->ResourceHandle(); }
// ***** Global Function to translate dialog messages *****
#ifndef VWCL_WRAP_WINDOWS_ONLY
VWCL_API BOOL VTranslateDialogMessage(LPMSG lpMsg)
{
HWND hWndTop = lpMsg->hwnd;
// Obtain the top level window. All dialogs are typically defined as top level popups
while ( hWndTop )
{
if ( GetWindowLong(hWndTop, GWL_STYLE) & WS_CHILD )
hWndTop = GetParent(hWndTop);
else
break;
}
// Obtain the associated window pointer (if a VWCL window)
VWindow* pWindow = (hWndTop) ? VGetApp()->VWindowFromHandle(hWndTop) : NULL;
if ( !pWindow )
return FALSE;
BOOL bResult = FALSE;
if ( pWindow->IsVDialogType() )
bResult = IsDialogMessage(hWndTop, lpMsg);
else if ( pWindow->RTTI() == VWindow::VWCL_RTTI_PROPERTY_SHEET )
{
if ( PropSheet_GetCurrentPageHwnd(hWndTop) )
bResult = PropSheet_IsDialogMessage(hWndTop, lpMsg);
else
pWindow->DestroyWindow();
}
// Return result.
return bResult;
}
#endif
// ***** VWindow *****
#ifndef VWCL_WRAP_WINDOWS_ONLY
BOOL VWindow::Attach(HWND hWnd)
{ assert(hWnd && ::IsWindow(hWnd)); return VGetApp()->Attach(this, hWnd); }
BOOL VWindow::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, LPRECT lpRect, HWND hWndParent, UINT nIDorMenu, BOOL bDontCallPostCreateWindow)
{
// Attemting to create a window for a VWindow object that already has a window attached to it!
assert(!GetSafeWindow());
CREATESTRUCT cs;
ZeroMemory(&cs, sizeof(cs));
cs.lpszClass = (lpszClassName) ? lpszClassName : VWINDOWCLASS;
cs.lpszName = lpszWindowName;
cs.style = dwStyle;
cs.hMenu = (HMENU)IntToPtr(nIDorMenu);
cs.hwndParent = hWndParent;
if ( lpRect )
{
cs.x = lpRect->left;
cs.y = lpRect->top;
cs.cx = lpRect->right - lpRect->left;
cs.cy = lpRect->bottom - lpRect->top;
}
else
cs.x = cs.y = cs.cx = cs.cy = CW_USEDEFAULT;
return (VGetApp()->VCreateWindow(this, &cs, bDontCallPostCreateWindow)) ? TRUE : FALSE;
}
void VWindow::Detach()
{ VGetApp()->Detach(this); }
LRESULT VWindow::WindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
// Implement support for base class message overrides
LRESULT lResult = 1;
switch ( nMessage )
{
case WM_CLOSE:
OnClose();
return 0;
case WM_COMMAND:
lResult = OnCommand(HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
break;
case WM_CREATE:
if ( OnCreate((LPCREATESTRUCT)lParam) == -1 )
{
if ( GetSafeWindow() )
{
DestroyWindow();
m_hWindow = NULL;
}
return -1;
}
return 0;
case WM_DESTROY:
lResult = OnDestroy();
break;
case WM_NOTIFY:
{
LPNMHDR lpNMHDR = (LPNMHDR)lParam;
// Support for reflected WM_NOTIFY messages. Derived class must
// return 0 is message was handled, -1 if handled and parent should
// NOT be notified, or 1 if message was not handled and parent should
// be notified. If -1 is returned, derived classes must also set
// the pointer in lpLParam to the return value expected by the common control
VWindow* pChildWnd = VGetApp()->VWindowFromHandle(lpNMHDR->hwndFrom);
LPARAM lCommonControlResult;
if ( pChildWnd )
lResult = pChildWnd->OnReflectedNotify(lpNMHDR, lCommonControlResult);
// Return result code immediatly to common control if message
// should not be sent to the parent and a return value is expected
// by the common control
if ( lResult == -1 )
return lCommonControlResult;
else
lResult = OnNotify((int)wParam, (LPNMHDR)lParam);
break;
}
case WM_PAINT:
lResult = OnPaint();
break;
case WM_SIZE:
lResult = OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
break;
}
// If lResult is 0 skip next check
if ( lResult == 0 )
return 0;
// If intended for a dialog box, lResult should be 0
if ( IsVDialogType() )
return 0;
// Call was not handled in any derived classes. If subclassed, call original WndProc
return (m_lpfnOldWndProc) ? CallWindowProc(m_lpfnOldWndProc, m_hWindow, nMessage, wParam, lParam) : DefWindowProc(m_hWindow, nMessage, wParam, lParam);
}
#endif // VWCL_WRAP_WINDOWS_ONLY
// ***** VApplication *****
#ifndef VWCL_WRAP_WINDOWS_ONLY
LPVWCL_WINDOW_MAP VApplication::AllocWindowMap(VWindow* pWindow, HWND hWnd)
{
// This one must be known. hWnd is optional
assert(pWindow);
// Allocate new map
LPVWCL_WINDOW_MAP lpMap = new VWCL_WINDOW_MAP;
// Add to list of maps and return pMap
if ( lpMap && m_listWindowMaps.Add(lpMap) != -1 )
{
// Initialize map
lpMap->pWindow = pWindow;
lpMap->hWnd = hWnd;
}
else
{
delete lpMap;
lpMap = NULL;
}
return lpMap;
}
BOOL VApplication::Attach(VWindow* pWindow, HWND hWnd)
{
// pWindow and hWnd must be known and valid
assert(pWindow && hWnd && ::IsWindow(hWnd));
// If window proc is our own, Attach() was not needed
// Return success if this is the case
if ( GetWindowLongPtr(hWnd, GWLP_WNDPROC) == (LONG_PTR)&WindowProc )
return TRUE;
// Does a map entry for this object already exist? If not,
// allocate one now
int nIndex = m_listWindowMaps.Find(pWindow);
LPVWCL_WINDOW_MAP lpMap = (nIndex == -1) ? AllocWindowMap(pWindow, hWnd) : (LPVWCL_WINDOW_MAP)m_listWindowMaps[nIndex];
if ( lpMap )
{
// Verify handles in objects. This will have been already
// set if we owned the WndProc, but not set yet if not
// because the subclass has yet to come
lpMap->hWnd = hWnd;
lpMap->pWindow = pWindow;
pWindow->m_hWindow = hWnd;
// Subclass window
pWindow->m_lpfnOldWndProc = (WNDPROC)pWindow->SetWindowLongPtr(GWLP_WNDPROC, (LONG_PTR)WindowProc);
// Call PostAttachWindow()
pWindow->PostAttachWindow();
}
return (lpMap) ? TRUE : FALSE;
}
LPCTSTR VApplication::CurrentFile(LPCTSTR lpszFileName, BOOL bUpdateCaption)
{
// Save current filename string
m_strCurrentFile.String(lpszFileName);
#ifndef _CONSOLE
if ( bUpdateCaption )
{
// The main window pointer and name must be known
assert(MainWindow() && AppTitle());
LPCTSTR lpszTitle = (lpszFileName) ? lpszFileName : _T("Untitled");
// Allocate string large enough for app title, doc title, and dash
VSimpleString s;
if ( s.String(AppTitle(), lstrlen(lpszTitle) + 3) )
{
lstrcat(s, _T(" - "));
lstrcat(s, lpszTitle);
MainWindow()->SetWindowText(s);
}
else
MainWindow()->SetWindowText(AppTitle());
}
#endif
return m_strCurrentFile.String();
}
void VApplication::Detach(VWindow* pWindow)
{
// Must be known
assert(pWindow && pWindow->GetSafeWindow());
// If window is subclassed, VWindow::m_lpfnOldWndProc will be non-NULL
// so we need to set this value back in the window object
if ( pWindow->m_lpfnOldWndProc )
SetWindowLongPtr(pWindow->m_hWindow, GWLP_WNDPROC, (LONG_PTR)pWindow->m_lpfnOldWndProc);
// Find map and remove it
int nSize = m_listWindowMaps.Size();
for ( int i = 0; i < nSize; i++ )
{
LPVWCL_WINDOW_MAP lpMap = (LPVWCL_WINDOW_MAP)m_listWindowMaps[i];
if ( lpMap->pWindow == pWindow )
{
FreeWindowMap(lpMap);
break;
}
}
}
void VApplication::FreeWindowMap(LPVWCL_WINDOW_MAP lpMap)
{
// Must be known
assert(lpMap);
int nIndex = m_listWindowMaps.Find(lpMap);
if ( nIndex != -1 )
{
m_listWindowMaps.RemoveAt(nIndex);
delete lpMap;
}
}
LRESULT VApplication::HandleMessage(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{
// Set current message struct items
m_CurrentMessage.hwnd = hWnd;
m_CurrentMessage.message = nMessage;
m_CurrentMessage.wParam = wParam;
m_CurrentMessage.lParam = lParam;
LRESULT lResult = 0;
LPVWCL_WINDOW_MAP lpMap = NULL;
// As an optimization, look at last known index into map to see if we get
// a hit. Since windows messages usually come by the hundreds, don't waste
// time looking them up in a map if we can get a hit here
if ( m_nLastKnownMapIndex != - 1 && m_nLastKnownMapIndex < m_listWindowMaps.Size() )
{
LPVWCL_WINDOW_MAP lpThisMap = (LPVWCL_WINDOW_MAP)m_listWindowMaps[m_nLastKnownMapIndex];
assert(lpThisMap);
if ( lpThisMap->hWnd == hWnd )
lpMap = lpThisMap;
}
if ( !lpMap )
{
// Lookup hWnd in map to find VWindow object and call object window procedure
// There may be a window pointer but no HWND when a window is
// being created, so if this is found assume the VWindow object
// is valid, but that the hWnd is not
int nSize = m_listWindowMaps.Size();
for ( int i = 0; i < nSize; i++ )
{
LPVWCL_WINDOW_MAP lpThisMap = (LPVWCL_WINDOW_MAP)m_listWindowMaps[i];
assert(lpThisMap);
if ( lpThisMap->hWnd == hWnd || (lpThisMap->pWindow && !lpThisMap->hWnd) )
{
lpMap = lpThisMap;
m_nLastKnownMapIndex = i;
break;
}
}
}
if ( lpMap )
{
// Verify map and object settings
lpMap->hWnd = hWnd;
lpMap->pWindow->m_hWindow = hWnd;
lResult = lpMap->pWindow->WindowProc(hWnd, nMessage, wParam, lParam);
// If window destroyed, remove from map
if ( nMessage == WM_DESTROY )
{
VWindow* pWindow = lpMap->pWindow;
// Remove from list and free map memory
FreeWindowMap(lpMap);
// No more known index
m_nLastKnownMapIndex = -1;
// Set window handle in object to NULL
pWindow->m_hWindow = NULL;
// Possibly call PostNcDestroy() in derived object
pWindow->PostNcDestroy();
}
}
return lResult;
}
#endif // VWCL_WRAP_WINDOWS_ONLY
BOOL VApplication::Initialize(HINSTANCE hInstance, int nCommandShow, UINT nIDMenu, UINT nIDIcon, HBRUSH hBackgroundBrush)
{
assert(hInstance);
// Global application object should be uninitialized, you are walking on it!
assert(m_hInstance == NULL);
m_hInstance = hInstance;
// If resource handle was not previous set, set to same as application
if ( !m_hResource )
m_hResource = hInstance;
// Initialize Component Object Model
#ifdef VWCL_INIT_OLE
m_hrOleInitialize = OleInitialize(NULL);
if ( FAILED(m_hrOleInitialize) )
return FALSE;
#endif
// Icon is loaded from application instance in almost all cases
if ( nIDIcon )
{
Icon(LoadIcon(m_hInstance, MAKEINTRESOURCE(nIDIcon)));
// If icon was not found in instance handle, try resources
if ( !Icon() )
Icon(LoadIcon(m_hResource, MAKEINTRESOURCE(nIDIcon)));
// Icon was specified but not loaded!
assert(Icon());
}
m_nCommandShow = nCommandShow;
// Initialize common controls
#ifdef VWCL_INIT_COMMON_CONTROLS
InitCommonControls();
#endif
#ifndef VWCL_NO_REGISTER_CLASSES
// Register window classes
WNDCLASS wc;
wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
assert(wc.hCursor);
wc.hbrBackground = hBackgroundBrush;
// Main window frame
wc.hIcon = Icon();
wc.lpszMenuName = (nIDMenu) ? MAKEINTRESOURCE(nIDMenu) : NULL;
wc.lpszClassName = VMAINWINDOWCLASS;
if ( RegisterClass(&wc) == 0 )
return FALSE;
// Register standard window
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = VWINDOWCLASS;
if ( RegisterClass(&wc) != 0 )
return TRUE;
return FALSE;
#endif // VWCL_NO_REGISTER_CLASSES
return TRUE;
}
#ifndef VWCL_WRAP_WINDOWS_ONLY
BOOL VApplication::VCreateWindow(VWindow* pWindow, LPCREATESTRUCT lpCreateStruct, BOOL bDontCallPostCreateWindow)
{
// These must be known
assert(pWindow && lpCreateStruct);
// You have not called VApplication::Initialize() before creating window objects!");
assert(m_hInstance && m_hResource);
LPVWCL_WINDOW_MAP lpMap = AllocWindowMap(pWindow);
// Possibly call derived class PreCreateWindow
if ( lpMap && pWindow->PreCreateWindow(lpCreateStruct) )
{
#ifdef _DEBUG
SetLastError(0);
#endif
// Create the window
HWND hWnd = CreateWindowEx( lpCreateStruct->dwExStyle,
lpCreateStruct->lpszClass,
lpCreateStruct->lpszName,
lpCreateStruct->style,
lpCreateStruct->x,
lpCreateStruct->y,
lpCreateStruct->cx,
lpCreateStruct->cy,
lpCreateStruct->hwndParent,
lpCreateStruct->hMenu,
m_hInstance,
lpCreateStruct->lpCreateParams);
#ifdef _DEBUG
if ( hWnd == NULL || ::IsWindow(hWnd) == FALSE )
VShowLastErrorMessage(NULL);
#endif
if ( hWnd && ::IsWindow(hWnd) )
{
// Verify map and window objects are initialized
lpMap->hWnd = hWnd;
lpMap->pWindow = pWindow;
pWindow->m_hWindow = hWnd;
// Make sure window is subclassed
if ( Attach(pWindow, hWnd) )
{
// Call PostCreateWindow() and destroy window if FALSE is returned
if ( bDontCallPostCreateWindow || pWindow->PostCreateWindow() )
return TRUE;
}
}
}
// If we made it this far, an error occurred
// If pWindow->m_hWindow is valid, destroy it
// Make sure handle in VWindow is NULL
pWindow->DestroyWindow();
pWindow->m_hWindow = NULL;
// Window creation failed. Since our shared WndProc may not
// have been called, and WM_DESTROY caught, we may need
// to remove the map ourselves
if ( lpMap )
FreeWindowMap(lpMap);
return FALSE;
}
VWindow* VApplication::VWindowFromHandle(HWND hWnd)
{
VWindow* pWindow = NULL;
if ( hWnd && IsWindow(hWnd) )
{
// Find hWnd in window list and return VWindow object pointer
int nSize = m_listWindowMaps.Size();
for ( int i = 0; i < nSize; i++ )
{
LPVWCL_WINDOW_MAP lpMap = (LPVWCL_WINDOW_MAP)m_listWindowMaps[i];
assert(lpMap);
if ( lpMap->hWnd == hWnd )
{
pWindow = lpMap->pWindow;
break;
}
}
}
return pWindow;
}
LRESULT CALLBACK VApplication:: WindowProc(HWND hWnd, UINT nMessage, WPARAM wParam, LPARAM lParam)
{ assert(VGetApp()); return VGetApp()->HandleMessage(hWnd, nMessage, wParam, lParam); }
#endif // VWCL_WRAP_WINDOWS_ONLY