//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1991, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of class TApplication. This defines the basic behavior
/// for ObjectWindows applications.
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/applicat.h>
#include <owl/framewin.h>
#include <owl/docmanag.h>
#include <owl/appdict.h>
#include <owl/messageb.h>
#include <owl/window.rh>
#include <owl/tooltip.h>
#include "tracewnd.h"
#include <vector>
#if defined(OWL_SUPPORT_BWCC)
# include <owl/private/bwcc.h>
#endif
#if defined(BI_MULTI_THREAD_RTL)
# include <owl/thread.h>
#endif
using namespace std;
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable "Condition is always true/false"
# pragma option -w-inl // Disable warning in standard library.
#endif
namespace owl {
OWL_DIAGINFO;
} // OWL namespace
namespace owl {
/// \addtogroup internal_group
/// @{
/////////////////////////////////////////////////////
/// global definitions for both modules if sectioning
struct TEnumInfo {
HWND ModalWnd; ///< The window being made modal if needed
short Count; ///< Count of windows in Wnds below
HWND* Wnds; ///< list of windows that were disabled
WNDPROC* PrevWndProc;//
};
//////////////////////////////////////////////////////////////////////////////////
// Multithread support
//
class TWaitHook{
public:
TWaitHook();
~TWaitHook();
void SetCursor(TCursor* cursor, TAutoDelete = AutoDelete);
private:
void FreeCursors();
void SetWaitCursor();
private:
TEnumInfo Subclass;
TEnumInfo* LastStackTop;
uint Count;
uint HideCaretCount;
TCursor* Cursor;
bool DeleteOnClose;
TResult WaitWndMethod(HWND, TMsgId, TParam1, TParam2);
TResult DefWndProc(HWND, TMsgId, TParam1, TParam2);
public:
static LRESULT CALLBACK WaitWndProc(HWND, UINT, WPARAM, LPARAM);
};
//
struct TEnumInfoStr
#if defined(BI_MULTI_THREAD_RTL)
: public TLocalObject
#endif
{
TEnumInfoStr():Info(0),Hook(0),Top(0)
{
}
~TEnumInfoStr()
{
}
TEnumInfo* GetInfo() { return Info; }
void SetInfo(TEnumInfo* info) { Info = info; }
TEnumInfo* Info;
TWaitHook* Hook;
TWaitCursor* Top;
#if defined(BI_MULTI_THREAD_RTL)
TMRSWSection Lock;
#endif
};
//
//
static TEnumInfoStr& GetEnumInfo();
//
//
//
#if !defined(BI_MULTI_THREAD_RTL)
struct TApplicatData {
#else
struct TApplicatData : public TLocalObject {
#endif
TApplicatData();
~TApplicatData();
TMessageBox OwlMsgBox;
#if defined(BI_MULTI_THREAD_RTL)
TMRSWSection Lock;
#endif
};
//
static TApplicatData& GetApplicatData();
//
//
//
#if defined(BI_MULTI_THREAD_RTL) //TMRSWSection::TLock lock(GetEnumInfo().Lock);
#define LOCKENUMINFO(l,s) TMRSWSection::TLock __lock(l,s)
#else
#define LOCKENUMINFO(l,s)
#endif
//
//
//
#if defined(BI_MULTI_THREAD_RTL) //GetApplicatData().Lock,true
#define LOCKAPPLDATA(l,s) TMRSWSection::TLock __lock(l,s)
#else
#define LOCKAPPLDATA(l,s)
#endif
/// @}
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlApp, 1, 0);
// System Menu command "Diagnostic Window".
// This system command is present in debug builds only, i.e. when either of the symbols __TRACE and
// __WARN is defined. For more details, see EvSysCommand where the ScmTrace command is handled.
//
const auto ScmTrace = 0xFEC0;
// -----------------------------------------------------------------------------
static int
OWLDefaultMsgBox(HWND wnd, LPCTSTR text, LPCTSTR caption, uint type)
{
TApplication* app = OWLGetAppDictionary().GetApplication(0);
return ::MessageBoxEx(wnd, text, caption, type, app ? app->GetLangId() : LangNeutral);
}
// -----------------------------------------------------------------------------
TApplicatData::TApplicatData()
: OwlMsgBox(OWLDefaultMsgBox)
{
}
// -----------------------------------------------------------------------------
TApplicatData::~TApplicatData()
{
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// multithread support
//
static
TApplicatData& GetApplicatData()
{
//#if defined(BI_MULTI_THREAD_RTL)
// static TProcessContainer<TApplicatData> __ApplData;
//#else
static TApplicatData __ApplData;
//#endif
return __ApplData;
}
//
static
TEnumInfoStr& GetEnumInfo()
{
//#if defined(BI_MULTI_THREAD_RTL)
// static TProcessContainer<TEnumInfoStr> __EnumInfo;
//#else
static TEnumInfoStr __EnumInfo;
//#endif
return __EnumInfo;
}
// -----------------------------------------------------------------------------
//
// Static members for initialization of app prior to initial construction
//
HINSTANCE TApplication::InitHInstance;
HINSTANCE TApplication::InitHPrevInstance;
int TApplication::InitCmdShow;
// -----------------------------------------------------------------------------
_OWLFUNC(TMessageBox)
SetDefMessageBox(TMessageBox newMsgBox)
{
TApplicatData& data = GetApplicatData();
LOCKAPPLDATA(data.Lock,true);
TMessageBox msgBox = data.OwlMsgBox;
data.OwlMsgBox = newMsgBox;
return msgBox;
}
// -----------------------------------------------------------------------------
_OWLFUNC(int)
OWLMessageBox(HWND wnd, const tstring& text, const tstring& caption, uint type)
{
return OWLMessageBox(wnd, text.c_str(), caption.c_str(), type);
}
// -----------------------------------------------------------------------------
_OWLFUNC(int)
OWLMessageBox(HWND wnd, LPCTSTR text, LPCTSTR caption, uint type)
{
// If no parent is supplied need to use task modal to disable all toplevel
// windows in this task.
//
if (!wnd && !(type & MB_SYSTEMMODAL))
type |= MB_TASKMODAL;
LPCTSTR _caption = caption; // Older compilers like Borland C++ 5.5 do not allow assigning new value to caption
if (_caption == 0)
_caption = OWLGetAppDictionary().GetApplication(0)->GetName();
return (GetApplicatData().OwlMsgBox)(wnd, text, _caption, type);
}
// -----------------------------------------------------------------------------
_OWLFUNC(int)
OWLMessageBox(TWindow* wnd, TResId resId, const tstring& caption, uint type, TModule* module)
{
return OWLMessageBox(wnd, resId, caption.c_str(), type, module);
}
// -----------------------------------------------------------------------------
_OWLFUNC(int)
OWLMessageBox(TWindow* wnd, TResId resId, LPCTSTR caption, uint type, TModule* module)
{
TModule& m = module ? *module : wnd && wnd->GetModule() ? *wnd->GetModule() : GetGlobalModule();
tstring text = m.LoadString(resId.GetInt());
LPCTSTR _caption = caption; // Older compilers like Borland C++ 5.5 do not allow assigning new value to caption
if (_caption == 0 && wnd && wnd->GetApplication())
_caption = wnd->GetApplication()->GetName();
HWND h = wnd ? wnd->GetHandle() : static_cast<HWND>(0);
return OWLMessageBox(h, text, _caption, type);
}
// -----------------------------------------------------------------------------
//
/// Gets WinMain's 3rd param.
//
tstring&
TApplication::GetInitCmdLine()
{
static tstring InitCmdLine;
return InitCmdLine;
};
//
/// Constructor for use in OwlMain(). Gets members from statics set earlier by
/// a call to InitWinMainParams() in Owl's WinMain.
//
/// Creates a new TApplication object named name. You can use owl::Module to specify the
/// global module pointer that points to this application. The appDict parameter
/// specifies which dictionary this application will insert itself into. To override
/// the default ObjectWindows TAppDictionary object, pass a pointer to a
/// user-supplied appDict object.
//
TApplication::TApplication(LPCTSTR name, TModule*& module, TAppDictionary* appDict)
:
TModule(name, InitHInstance, GetInitCmdLine()),
TMsgThread(TMsgThread::Current),
// Copy over values that were stashed in static members before this instance
// was constructed.
//
hPrevInstance(InitHPrevInstance), nCmdShow(InitCmdShow),
DocManager(0), MainWindow(0),
LangId(LangUserDefault),
Tooltip(0),
CmdLine(GetInitCmdLine()),
WaitCount(0),
WaitHandles(NULL),
#if defined(OWL_SUPPORT_BWCC)
BWCCOn(false),BWCCModule(0),
#endif
#if defined(OWL_SUPPORT_CTL3D)
Ctl3dOn(false),Ctl3dModule(0),
#endif
CurrentEvent(),
CurrentException(),
CondemnedWindows(0),
Dictionary(appDict ? appDict : &(OWLGetAppDictionary()))
{
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructing @") << (void*)this);
Dictionary->Add(this);
module = this;
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructed @") << (void*)this);
}
//
/// String-aware overload
//
TApplication::TApplication(const tstring& name, TModule*& module, TAppDictionary* appDict)
:
TModule(name, InitHInstance, GetInitCmdLine()),
TMsgThread(TMsgThread::Current),
// Copy over values that were stashed in static members before this instance
// was constructed.
//
hPrevInstance(InitHPrevInstance), nCmdShow(InitCmdShow),
DocManager(0), MainWindow(0),
LangId(LangUserDefault),
Tooltip(0),
CmdLine(GetInitCmdLine()),
WaitCount(0),
WaitHandles(NULL),
#if defined(OWL_SUPPORT_BWCC)
BWCCOn(false), BWCCModule(0),
#endif
#if defined(OWL_SUPPORT_CTL3D)
Ctl3dOn(false), Ctl3dModule(0),
#endif
CurrentEvent(),
CurrentException(),
CondemnedWindows(0),
Dictionary(appDict ? appDict : &(OWLGetAppDictionary()))
{
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructing @") << (void*)this);
Dictionary->Add(this);
module = this;
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructed @") << (void*)this);
}
//
/// Constructor for use in user defined WinMain() when all the args are
/// available
//
/// Creates a TApplication object with the application name (name), the application
/// instance handle (instance), the previous application instance handle
/// (prevInstance), the command line invoked (cmdLine), and the main window show
/// flag (cmdShow). The appDict parameter specifies which dictionary this
/// application will insert itself into. To override the default ObjectWindows
/// TAppDictionary object, pass a pointer to a user-supplied appDict object.
///
/// If you want to create your own WinMain, use this constructor because it provides
/// access to the various arguments provided by WinMain. You can use module to to
/// specify the global module pointer that points to this application.
//
TApplication::TApplication
(
LPCTSTR name,
HINSTANCE instance,
HINSTANCE prevInstance,
const tstring& cmdLine,
int cmdShow,
TModule*& module,
TAppDictionary* appDict
)
:
TModule(name, instance, cmdLine),
TMsgThread(TMsgThread::Current),
hPrevInstance(prevInstance), nCmdShow(cmdShow),
DocManager(0), MainWindow(0),
LangId(LangUserDefault),
Tooltip(0),
CmdLine(cmdLine),
WaitCount(0),
WaitHandles(NULL),
#if defined(OWL_SUPPORT_BWCC)
BWCCOn(false),BWCCModule(0),
#endif
#if defined(OWL_SUPPORT_CTL3D)
Ctl3dOn(false),Ctl3dModule(0),
#endif
CurrentEvent(),
CurrentException(),
CondemnedWindows(0),
Dictionary(appDict ? appDict : &(OWLGetAppDictionary()))
{
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructing @") << (void*)this);
Dictionary->Add(this);
module = this;
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructed @") << (void*)this);
}
//
/// String-aware overload
//
TApplication::TApplication
(
const tstring& name,
HINSTANCE instance,
HINSTANCE prevInstance,
const tstring& cmdLine,
int cmdShow,
TModule*& module,
TAppDictionary* appDict
)
:
TModule(name, instance, cmdLine),
TMsgThread(TMsgThread::Current),
hPrevInstance(prevInstance), nCmdShow(cmdShow),
DocManager(0), MainWindow(0),
LangId(LangUserDefault),
Tooltip(0),
CmdLine(cmdLine),
WaitCount(0),
WaitHandles(NULL),
#if defined(OWL_SUPPORT_BWCC)
BWCCOn(false), BWCCModule(0),
#endif
#if defined(OWL_SUPPORT_CTL3D)
Ctl3dOn(false), Ctl3dModule(0),
#endif
CurrentEvent(),
CurrentException(),
CondemnedWindows(0),
Dictionary(appDict ? appDict : &(OWLGetAppDictionary()))
{
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructing @") << (void*)this);
Dictionary->Add(this);
module = this;
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication constructed @") << (void*)this);
}
//
/// ~TApplication destroys the TApplication object.
//
TApplication::~TApplication()
{
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication destructing @") << (void*)this);
DeleteCondemned();
#if defined(OWL_SUPPORT_CTL3D)
// Unregister ourselves from the Ctl3d DLL if it is loaded.
//
if (Ctl3dModule) {
Ctl3dModule->Unregister(*this);
delete Ctl3dModule;
}
#endif
#if defined(OWL_SUPPORT_BWCC)
// Unregister ourselves from the BWCC DLL if it is loaded.
if (BWCCModule) {
BWCCModule->IntlTerm();
delete BWCCModule;
}
#endif
// Delete the main window if still present, may be destroyed but not deleted
// Set MainWindow to 0 first to prevent it from calling ::PostQuitMessage
//
TWindow* mainWindow = SetMainWindow(0);
if (mainWindow) {
mainWindow->Destroy();
delete mainWindow;
delete Tooltip; // if SetMainWindow(0) need manually delete Tooltip
}
delete DocManager;
// Remove this app from the application dictionary that it is in
//
Dictionary->Remove(this);
TRACEX(OwlApp, OWL_CDLEVEL, _T("TApplication destructed @") << (void*)this);
}
//
/// Open a modal message box, Under WIN32 the language id setting is used.
//
int
TApplication::MessageBox(HWND wnd, LPCTSTR text, LPCTSTR caption, uint type) const
{
// Default caption to this application's name
//
if (caption == 0)
caption = GetName();
// If no parent is supplied need to use task modal to disable all toplevel
// windows in this task.
//
if (!wnd && !(type & MB_SYSTEMMODAL))
type |= MB_TASKMODAL;
#if defined(OWL_SUPPORT_BWCC)
// Use the BWCC message box if BWCC is enabled
//
if (BWCCEnabled() && GetBWCCModule()) {
return GetBWCCModule()->MessageBox( wnd, text, caption, type);
}
else
#endif
// Otherwise, 3d-ize the message box if ctl3d is enabled
//
#if defined(OWL_SUPPORT_CTL3D)
{
EnableCtl3dAutosubclass(true);
int retValue = (GetApplicatData().OwlMsgBox)(wnd, text, caption, type);
EnableCtl3dAutosubclass(false);
return retValue;
}
#else
return (GetApplicatData().OwlMsgBox)(wnd, text, caption, type);
#endif
}
//
/// Handle initialization for the first executing instance of the OWL
/// application. Under Win32, every app instance is treated as the first.
//
/// Derived classes can override this to perform app initialization, or they
/// can use the derived class constructor.
//
/// The following sample program calls InitApplication the first time an instance of
/// the program begins.
/// \code
/// class TTestApp : public TApplication {
/// public:
/// TTestApp(): TApplication("Instance Tester")
/// { strcpy(WindowTitle, "Additional Instance");}
/// protected:
/// char WindowTitle[20];
/// void InitApplication() { strcpy(WindowTitle, "First Instance"); }
/// void InitMainWindow() { MainWindow = new TFrameWindow(0, WindowTitle); }
/// };
/// static TTestApp App;
/// \endcode
//
void
TApplication::InitApplication()
{
TRACEX(OwlApp, 1, _T("TApplication::InitApplication() called @") << (void*)this);
}
//
/// Performs each instance initialization necessary for the application. Unlike
/// InitApplication(), which is called for the first instance of an application,
/// InitInstance is called whether or not there are other executing instances of the
/// application. InitInstance calls InitMainWindow(), and then creates and shows the
/// main window element by TWindow::Create and TWindow::Show. If the main window
/// cannot be created, a TXInvalidMainWindow exception is thrown.
//
/// \note If you redefine this member function, be sure to explicitly call
/// TApplication::InitInstance.
//
void
TApplication::InitInstance()
{
TMsgThread::InitInstance();
TRACEX(OwlApp, 1, _T("TApplication::InitInstance() called @") << (void*)this);
InitMainWindow();
if (MainWindow) {
MainWindow->SetFlag(wfMainWindow);
MainWindow->Create();
#if defined(__TRACE) || defined(__WARN)
TSystemMenu sysMenu{MainWindow->GetHandle()};
if (sysMenu.IsOK())
{
sysMenu.AppendMenu(MF_SEPARATOR);
sysMenu.AppendMenu(MF_STRING, ScmTrace, _T("Diagnostic Window"));
}
#endif
MainWindow->ShowWindow(nCmdShow);
}
else
TXInvalidMainWindow::Raise();
}
//
/// Initialize the application's main window. Derived classes should override
/// this to construct, initialize and set the main window using SetMainWindow().
//
/// By default, InitMainWindow constructs a generic TFrameWindow object with the
/// name of the application as its caption. You can redefine InitMainWindow to
/// construct a useful main window object of TFrameWindow (or a class derived from
/// TFrameWindow) and store it in MainWindow. The main window must be a top-level
/// window; that is, it must be derived from TFrameWindow. A typical use is
/// \code
/// virtual void TMyApp_InitMainWindow(){
/// SetMainWindow(TMyWindow(NULL, Caption));
/// }
/// \endcode
/// InitMainWindow can be overridden to create your own custom window.
//
void
TApplication::InitMainWindow()
{
SetMainWindow(new TFrameWindow(0, GetName()));
}
//
/// Handle termination for each executing instance of the application. Called
/// at the end of a Run() with the final return status.
//
int
TApplication::TermInstance(int status)
{
TRACEX(OwlApp, 1, _T("TApplication::TermInstance() called @") << (void*)this);
#if defined(__TRACE) || defined(__WARN)
// If open, destroy the Diagnostic Window.
// See ProcessAppMsg, where the window is created.
//
if (TTraceWindow::GetInstance())
TTraceWindow::DestroyInstance();
#endif
return TMsgThread::TermInstance(status);
}
//
/// Set (or reset) the main window. Return, but do not destroy the previous
/// main window.
//
TFrameWindow*
TApplication::SetMainWindow(TFrameWindow* window)
{
if (MainWindow) {
MainWindow->ClearFlag(wfMainWindow);
uint32 style = MainWindow->GetExStyle();
if (style & WS_EX_APPWINDOW)
MainWindow->SetExStyle(style & ~WS_EX_APPWINDOW);
if(Tooltip && Tooltip->GetParentO()==MainWindow)
Tooltip->SetParent(0);
}
TFrameWindow* oldMainWindow = MainWindow;
MainWindow = window;
if (MainWindow) {
MainWindow->SetFlag(wfMainWindow);
uint32 style = MainWindow->GetExStyle();
if (!(style & WS_EX_APPWINDOW))
MainWindow->SetExStyle(style | WS_EX_APPWINDOW);
// set new parent only if MainWindow created
if(Tooltip && Tooltip->GetParentO()==0 && MainWindow->GetHandle())
Tooltip->SetParent(MainWindow);
}
return oldMainWindow;
}
//
/// Smart-pointer-aware overload.
//
auto TApplication::SetMainWindow(std::unique_ptr<TFrameWindow> f) -> std::unique_ptr<TFrameWindow>
{
auto old = std::unique_ptr<TFrameWindow>{SetMainWindow(f.get())};
f.release(); // We took ownership.
return old;
}
//
/// Set (or resets) the document manager, return the previous one if present
//
TDocManager*
TApplication::SetDocManager(TDocManager* docManager)
{
TDocManager* oldDocManager = DocManager;
DocManager = docManager;
return oldDocManager;
}
//
/// Smart-pointer-aware overload.
//
auto TApplication::SetDocManager(std::unique_ptr<TDocManager> d) -> std::unique_ptr<TDocManager>
{
auto old = std::unique_ptr<TDocManager>{SetDocManager(d.get())};
d.release(); // We took ownership.
return old;
}
#if defined(BI_MULTI_THREAD_RTL)
//
/// BI_MULTI_THREAD_RTL only: Overrides TEventHandler::Dispatch() to handle
/// multi-thread synchonization.
//
TResult TApplication::Dispatch(TEventInfo& info, TParam1 p1, TParam2 p2)
{
TApplication::TQueueLock lock(*this);
return TEventHandler::Dispatch(info, p1, p2);
}
#endif
//
/// Run this application, return when application terminates
//
/// Initialize instances, create and display their main window (calls
/// InitApplication for the first executing instance and calls InitInstance for
/// all instances). Run the application's message loop. Each of the virtual
/// functions called are expected to throw an exception if there is an error.
///
/// Exceptions are propagated out of this function, but the message queue is still
/// flushed and TermInstance called in the event of an exception.
//
int
TApplication::Run()
{
try
{
if (!MainWindow)
{
if (!hPrevInstance)
InitApplication();
InitInstance();
}
LoopRunning = true;
int status = MessageLoop();
FlushQueue();
LoopRunning = false;
return TermInstance(status);
}
catch (...)
{
FlushQueue();
LoopRunning = false;
TermInstance(-1);
throw;
}
}
//
/// Start this application and return immediately. Used for component DLLs
//
/// Initializes instances, creating and displaying their main window (calls
/// InitApplication for the first executing instance and calls InitInstance for
/// all instances). Each of the virtual functions called are expected to throw
/// an exception if there is an error. Any exceptions are handled and converted
/// to an error code which is then returned. Returns 0 on success.
/// Does not run message loop.
//
int
TApplication::Start() noexcept
{
int status = 0;
try {
if (!hPrevInstance)
InitApplication();
InitInstance();
}
catch (TXOwl& x) {status = x.Unhandled(this, 0);}
catch (TXBase& x) {status = Error(x, 0);}
catch (...) {status = -1;}
return status;
}
//
/// Operates the application's message loop, which runs during the lifetime of the
/// application. MessageLoop queries for messages. If one is received, it processes
/// it by calling ProcessAppMsg. If the query returns without a message, MessageLoop
/// calls IdleAction to perform some processing during the idle time.
///
/// MessageLoop calls PumpWaitingMessages to get and dispatch waiting messages.
/// MessageLoop can be broken if BreakMessageLoop is set by EndModal.
//
int
TApplication::MessageLoop()
{
long idleCount = 0;
MessageLoopResult = 0;
while (!BreakMessageLoop)
{
try
{
if (!IdleAction(idleCount++))
{
DWORD r = MsgWaitForMultipleObjects(WaitCount, WaitHandles, FALSE, INFINITE, QS_ALLINPUT);
if (r >= WAIT_OBJECT_0 && r < WAIT_OBJECT_0 + WaitCount)
ObjectSignaled(WaitHandles[r - WAIT_OBJECT_0], false);
else if (r >= WAIT_ABANDONED_0 && r < WAIT_ABANDONED_0 + WaitCount)
ObjectSignaled(WaitHandles[r - WAIT_ABANDONED_0], true);
}
if (PumpWaitingMessages())
idleCount = 0;
ResumeThrow();
}
catch (...)
{
BreakMessageLoop = true;
MessageLoopResult = -1;
throw;
}
}
BreakMessageLoop = false;
return MessageLoopResult;
}
//
/// Called each time there are no messages in the queue. Idle count is
/// incremented each time, & zeroed when messages are pumped. Return
/// whether or not more processing needs to be done.
//
/// Default behavior is to give the main window an opportunity to do idle
/// processing by invoking its IdleAction() member function when
/// "idleCount" is 0
//
bool
TApplication::IdleAction(long idleCount)
{
TRACEX(OwlApp, 1, _T("TApplication::IdleAction() called @") << (void*)this <<
_T(" idleCount ") << idleCount);
bool more = false;
if (MainWindow)
more = MainWindow->IdleAction(idleCount);
#if defined(__TRACE) || defined(__WARN)
// If open, let the Diagnostic Window process diagnostics.
// See TApplication::ProcessAppMsg, where the window is opened (or closed).
//
const auto diagIdleAction = [](long idleCount)
{
LOCKAPPLDATA(GetApplicatData().Lock, true);
bool more = false;
const auto t = TTraceWindow::GetInstance();
if (t && t->IdleAction(idleCount))
more = true;
return more;
};
if (diagIdleAction(idleCount))
more = true;
#endif
return more;
}
//
/// Called for each message that is pulled from the queue, to perform all
/// translation & dispatching.
///
/// Return true to drop out of pump
//
bool
TApplication::ProcessMsg(MSG& msg)
{
// Let the app preprocess the message. If it is not eaten, then translate
// it, & dispatch it. If no HWND, then first find/dispatch it directly
// to the app (for PostAppMessage() functionality)
//
if (!ProcessAppMsg(msg)) {
::TranslateMessage(&msg);
if (!msg.hwnd) {
TEventInfo cmdEventInfo(msg.message, static_cast<uint>(msg.wParam));
if (Find(cmdEventInfo)) {
Dispatch(cmdEventInfo, msg.wParam, msg.lParam);
return true;
}
else {
TEventInfo eventInfo(msg.message);
if (Find(eventInfo)) {
Dispatch(eventInfo, msg.wParam, msg.lParam);
return true;
}
}
}
::DispatchMessage(&msg);
DeleteCondemned();
ResumeThrow();
}
return false;
}
//
/// Called after each message is pulled from the queue, and before it is
/// dispatched. Return true if the message was handled completely here.
//
/// Checks for any special processing that is required for modeless dialog box,
/// accelerator, and MDI accelerator messages. Calls the virtual
/// TWindow::PreProcessMsg function of the window receiving the message. If your
/// application does not create modeless dialog boxes, does not respond to
/// accelerators, and is not an MDI application, you can improve performance by
/// overriding this member function to return false.
//
bool
TApplication::ProcessAppMsg(MSG& msg)
{
// Check if this message might be worth relaying to the tooltip window
//
if (Tooltip && Tooltip->IsWindow()) {
if (msg.hwnd == *MainWindow || MainWindow->IsChild(msg.hwnd)) {
if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) {
Tooltip->RelayEvent(msg);
}
}
}
// Start with the window that the event was destined for and allow it
// and its parent (and its parent...) an opportunity to preprocess the
// event
//
for (HWND hWnd = msg.hwnd; hWnd; hWnd = ::GetParent(hWnd)) {
// NT seems very picky about calls to ::GetWindowThreadProcessId
// with the HWND of the desktop. Hence we'll abort this loop
// when encountering the desktop. Specially useful when dealing with
// DropDown[List] ComboBoxes thunked by OWL when hit the ComboLBox
// window which is parented to the Desktop.
//
static HWND deskTopHwnd = ::GetDesktopWindow();
if (hWnd == deskTopHwnd)
break;
TWindow* win = GetWindowPtr(hWnd);
if (win && win->PreProcessMsg(msg))
return true;
}
return false;
}
void TApplication::WaitOnObject(HANDLE handle, bool wait)
{
bool exists = false;
int index;
if (WaitHandles)
{
for (int i = 0; i < static_cast<int>(WaitCount); i++) //JJH added static_cast
if (WaitHandles[i] == handle)
{
exists = true;
index = i;
}
}
if (wait)
{
if (!exists)
{
LPHANDLE newHandles = new HANDLE[WaitCount + 1];
for (int i = 0; i < static_cast<int>(WaitCount); i++) //JJH added static_cast
newHandles[i] = WaitHandles[i];
delete[] WaitHandles;
WaitHandles = newHandles;
WaitHandles[WaitCount] = handle;
WaitCount++;
}
}
else
{
if (exists)
{
if (WaitCount == 1)
{
delete[] WaitHandles;
WaitHandles = NULL;
WaitCount = 0;
}
else
{
LPHANDLE newHandles = new HANDLE[WaitCount - 1];
int i;
for (i = 0; i < index; i++)
newHandles[i] = WaitHandles[i];
for (i = index + 1; i < static_cast<int>(WaitCount); i++) //JJH added static_cast
newHandles[i-1] = WaitHandles[i];
delete[] WaitHandles;
WaitHandles = newHandles;
WaitCount--;
}
}
}
}
//
/// Stores the given exception so that it can be rethrown later by a call to ResumeThrow.
/// Calls PostQuitMessage to break the application message loop, thus ensuring that the
/// application will not linger in a corrupt state.
//
void
TApplication::SuspendThrow(exception_ptr e)
{
TRACEX(OwlApp, 0, _T("TApplication::SuspendThrow: Suspending exception and posting quit-message."));
CurrentException = e;
::PostQuitMessage(-1);
}
//
/// Rethrows the suspended exception stored by a previous call to SuspendThrow.
/// Otherwise, if no exception has been suspended, does nothing.
//
void
TApplication::ResumeThrow()
{
if (CurrentException == 0) return;
TRACEX(OwlApp, 0, _T("TApplication::ResumeThrow: Rethrowing suspended exception."));
exception_ptr e = CurrentException;
CurrentException = exception_ptr(); // clear
rethrow_exception(e);
}
//
/// If TApplication's message loop is not used, this function should be called after
/// each message is dispatched
//
void
TApplication::PostDispatchAction()
{
DeleteCondemned();
ResumeThrow();
MSG msg;
if (!::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
IdleAction(0);
}
//
//
//
void
TApplication::EnableTooltip(bool enable)
{
if (!Tooltip) {
// To circumvent this scenario, we'll look for a window which is fairly
// stable/rooted as owner of the tooltip. Ideally, we'll get the
// application's main window.
//
TWindow* tipParent = MainWindow;
if(!MainWindow->GetHandle())
tipParent = 0;
// Create and initialize tooltip
//
SetTooltip(new TTooltip(tipParent));
}
else {
if (Tooltip->GetHandle())
Tooltip->Activate(enable);
}
}
//
/// Set tooltip . Assume we now own the ToolTip
//
void
TApplication::SetTooltip(TTooltip* tooltip)
{
// Cleanup; via Condemned list if tooltip was created
//
if (Tooltip) {
if (Tooltip->GetHandle())
Tooltip->SendMessage(WM_CLOSE);
else
delete Tooltip;
}
// Store new tooltip and create if necessary
// Create only if MainWindows already created
Tooltip = tooltip;
if (Tooltip && !Tooltip->GetHandle() &&
MainWindow && MainWindow->GetHandle()) {
if(!Tooltip->GetParentO())
Tooltip->SetParent(MainWindow);
// Make sure tooltip is disabled so it does not take input focus
Tooltip->ModifyStyle(0,WS_DISABLED);
Tooltip->Create();
}
}
//
/// Does internal processing of system menu messages.
/// In particular, it handles the command "Diagnostic Window" on the system menu in debug builds.
//
void TApplication::EvSysCommand(uint cmd, const TPoint&)
{
#if defined(__TRACE) || defined(__WARN)
// If the user selects ScmTrace ("Diagnostic Window") from the main window's system menu,
// then create the Diagnostic Window, if it does not already exist, or destroy it, if it does.
// See InitInstance, where the menu item is created for the debug build.
// See IdleAction, where diagnostic messages are processed.
// See TermInstance, where the window is closed on exit.
//
switch (cmd & 0xFFF0)
{
case ScmTrace:
{
LOCKAPPLDATA(GetApplicatData().Lock, false);
if (TTraceWindow::GetInstance())
TTraceWindow::DestroyInstance();
else
{
const auto t = TTraceWindow::GetInstance(true);
t->Create();
t->ShowWindow(SW_SHOWNORMAL);
}
return;
}
}
// Update the checkmark on the system menu command "Diagnostic Window".
//
if (cmd & (SC_KEYMENU | SC_MOUSEMENU))
if (const auto w = GetMainWindow())
if (const auto h = w->GetHandle())
{
const auto c = TTraceWindow::GetInstance() ? MF_CHECKED : MF_UNCHECKED;
TSystemMenu{h}.CheckMenuItem(ScmTrace, MF_BYCOMMAND | c);
}
#endif
if (const auto m = GetMainWindow())
m->DefaultProcessing();
}
//
/// Close down main window if application receives a CM_EXIT command.
//
void
TApplication::CmExit()
{
TFrameWindow* frame = GetMainWindow();
if (frame) {
frame->SendMessage(WM_CLOSE);
DeleteCondemned();
}
}
//
/// Overrides TEventHandler::Find.
/// If a DocManager has been installed, TDocManager::Find is called first to give it an opportunity
/// to handle the event.
///
/// \note Since TApplication needs a custom implementation of Find, the common implementation
/// provided by the response table macros can not be used. For that reason, the response table for
/// TApplication is implemented explicitly within this function.
//
auto TApplication::Find(TEventInfo& eventInfo, TEqualOperator equal) -> bool
{
const auto r = DocManager ? DocManager->Find(eventInfo, equal) : false;
if (r) return true;
#if OWL_NEW_RESPONSE_TABLE
using TEntry = TResponseTableEntry;
#else
using TEntry = TResponseTableEntry<TApplication>;
using TMyPMF = TResponseTableEntry<TApplication>::PMF; // Needed for the reponse table macros.
#endif
using TMyClass = TApplication; // Needed for the reponse table macros.
static const TEntry entries[] =
{
EV_WM_SYSCOMMAND,
EV_COMMAND(CM_EXIT, CmExit),
{} // Sentinel is required.
};
eventInfo.Object = reinterpret_cast<TGeneric*>(this);
return SearchEntries(reinterpret_cast<const TGenericTableEntry*>(entries), eventInfo, equal) ||
TEventHandler::Find(eventInfo, equal);
}
//
/// Determine whether the application can be closed.
/// Makes sure the MainWindow can close & doc manager can close.
//
/// Returns true if it is OK for the application to close. By default, CanClose
/// calls the CanClose member function of its main window and returns true if both
/// the main window and the document manager (TDocManager) can be closed. If any of
/// the CanClose functions return false, the application does not close.
///
/// This member function is seldom redefined; closing behavior is usually redefined
/// in the main window's CanClose member function, if needed.
//
bool
TApplication::CanClose()
{
TEventInfo eventInfo(WM_OWLCANCLOSE);
return (!MainWindow || MainWindow->CanClose())
&& (!DocManager ||!DocManager->Find(eventInfo)
|| DocManager->Dispatch(eventInfo, 0, 0));
}
//
/// Called by the main window to provide an oportunity to preprocess the main
/// window's menubar before it is installed.
/// Normally delegated to the doc manager to install a file menu as needed
//
void
TApplication::PreProcessMenu(HMENU hMenubar)
{
TEventInfo eventInfo(WM_OWLPREPROCMENU);
if (DocManager && DocManager->Find(eventInfo)) {
DocManager->Dispatch(eventInfo, TParam1(hMenubar), 0);
MainWindow->DrawMenuBar();
}
}
//
/// Condemns the given window to be deleted the at the next available safe time.
///
/// Appends the window to the list of condemned windows.
///
/// \note Condemned windows should be removed (see TApplication::Uncondemn) if they are destructed
/// in the mean time through some other mechanism (i.e. stack, aggregate, etc).
///
/// \note It is assumed that the condemned window was constructed using `new`. If it was
/// constructed by other means, do not pass it to this function. Instead ensure it is destructed in
/// the appropriate way.
///
/// \note While it in previous versions of OWLNext was unsafe for a window in the process of
/// destruction to condemn other windows (e.g. child or buddy), it is now safe to do so.
//
void
TApplication::Condemn(TWindow* win)
{
PRECONDITION(win);
TRACEX(OwlApp, 1, _T("Condemning window @") << (void*)win << *win);
win->SetParent(0);
// Insert the new window to be deleted at the end of the list.
//
win->SetNext(0);
if (CondemnedWindows)
{
TWindow* eol;
for (eol = CondemnedWindows; eol->Next(); eol = eol->Next())
if (eol==win)
{
CHECK(!"Double condemn is not nice!");
return; //already condemned
}
eol->SetNext(win);
}
else{
CondemnedWindows = win;
}
}
//
/// Removes the given window from the list of condemned windows.
/// If the given window is not in the list of condemned windows, the function does nothing.
//
void
TApplication::Uncondemn(TWindow* win)
{
if (win && CondemnedWindows) {
TWindow* w = 0;
if (CondemnedWindows != win)
for (w = CondemnedWindows; w->Next() != win; w = w->Next())
if (!w->Next())
return;
TRACEX(OwlApp, 1, _T("Uncondemning window @") << (void*)win << *win);
if (w)
w->SetNext(win->Next());
else
CondemnedWindows = win->Next();
}
}
//
/// Deletes all entries in the list of condemned windows.
///
/// If new additions to the list of condemned windows are made in the process of deleting the
/// condemned windows, these additions are also deleted, and so on, until the list of condemned
/// windows is empty.
///
/// \note It is assumed that the condemned windows were constructed using `new`, as each entry is
/// destructed using `delete`.
//
void
TApplication::DeleteCondemned()
{
// Note that deleting a condemned window will cause its destructor to be called, which may call
// TApplication::Condemn as part of the destruction (e.g. condemning its children or a buddy).
// The original code did not support this, as it simply walked the linked list while deleting the
// nodes, thereby possibly crashing or ignoring additions to the list while traversing it. For
// more robust code, we now copy the condemned windows into a temporary vector, then clear the
// list (ready for additions), and finally delete the condemned windows collected in the vector.
// In case there were additions while deleting, we repeat this sequence until the condemned list
// is empty.
//
do
{
auto c = vector<TWindow*>{};
while (CondemnedWindows)
{
const auto next = CondemnedWindows->Next();
c.push_back(CondemnedWindows);
CondemnedWindows = next;
}
for (const auto w : c)
{
TRACEX(OwlApp, 1, _T("Deleting condemned window @") << w << *w);
delete w;
}
}
while (CondemnedWindows);
}
//
/// Constructs a TXInvalidMainWindow object with a default IDS_INVALIDMAINWINDOW
//
TXInvalidMainWindow::TXInvalidMainWindow()
:
TXOwl(IDS_INVALIDMAINWINDOW)
{
}
TXInvalidMainWindow*
TXInvalidMainWindow::Clone()
{
return new TXInvalidMainWindow(*this);
}
//
/// Throws the exception object. Throw must be implemented in any class derived from
/// TXOwl.
//
void
TXInvalidMainWindow::Throw()
{
throw *this;
}
//
/// Throws a TXInvalidMainWindow exception.
//
void
TXInvalidMainWindow::Raise()
{
TXInvalidMainWindow().Throw();
}
//
/// Enum[Thread/Task]Windows callback. Counts or disables given window based on
/// whether or not window list has been allocated yet.
//
static bool CALLBACK
disableWnds(HWND hWnd, TEnumInfo * ei)
{
if (!(::GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD)) {
if (hWnd != ei->ModalWnd && ::IsWindowEnabled(hWnd)) {
if (!ei->Wnds) {
ei->Count++; // no buffer yet, we are just counting
}
else {
*(ei->Wnds++) = hWnd;
::EnableWindow(hWnd, false);
}
}
}
return true;
}
//
/// Terminate the modal state initiated by BeginModal. Needs topmost ei block,
/// and cleans the block up as needed inorder to be safe to be called twice.
//
static void termModal(TEnumInfo& ei)
{
// Re-enable window(s) that are disabled in BeginModal()
//
if (ei.Wnds) {
for (HWND* hWnd = ei.Wnds; *hWnd; hWnd++)
::EnableWindow(*hWnd, true);
delete[] ei.Wnds;
ei.Wnds = 0;
}
else {
if (ei.ModalWnd && IsWindow(ei.ModalWnd)) {
::EnableWindow(ei.ModalWnd, true);
ei.ModalWnd = 0;
}
}
}
//
/// Called to begin a modal window's modal message loop. After determining which
/// window to disable, BeginModal saves the current status of the window, disables
/// the window, calls MessageLoop, and then reenables the window when the message
/// loop is finished. The flags determine how BeginModal treats the window. flags
/// can be one of the following values:
///
/// - \c \b MB_APPLMODAL The window to be disabled (which is usually an ancestor of the
/// modal window) is identified by window. If window is 0, no window is disabled.
/// - \c \b MB_SYSTEMMODAL The window to become system modal is identified by window.
/// - \c \b MB_TASKMODAL All top-level windows are disabled, and window is ignored.
///
/// BeginModal returns -1 if an error occurs.
//
int
TApplication::BeginModal(TWindow* window, int flags)
{
// lock enuminfo if multithreading
TEnumInfo ei = { 0, 0, 0, 0};
TEnumInfo* lastStackTop;
{
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, false); // Y.B. do we have do lock here ?????????
lastStackTop = data.GetInfo(); // Keep last stackTop to restore later
data.SetInfo(&ei); // Point stackTop to topmost ei
}
// The concept of SYSTEM MODAL applies only to the 16-bit environment of
// Windows. The semantics of TASKMODAL is the closest to SYSMODAL in
// 32-bit - specially in relation to the meaning of the 'window' parameter.
// So we'll coerce SYSTEM MODAL to TASK MODAL
//
if (flags & MB_SYSTEMMODAL) {
flags &= ~MB_SYSTEMMODAL;
flags |= MB_TASKMODAL;
}
// Check modal state
//
if (flags & MB_TASKMODAL) {
LOCKENUMINFO(GetEnumInfo().Lock, false); // lock data
// Save the window to make modal
//
if (window)
ei.ModalWnd = window->GetHandle();
// Count windows to disable
//
if (!EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)disableWnds,
TParam2((TEnumInfo *)&ei)))
return -1;
// Allocate list of windows to disable, disable windows that are
// enabled and then stuff them into the list.
//
HWND* hWnds = ei.Wnds = new HWND[ei.Count + 1];
memset(ei.Wnds, 0, sizeof(TModule::THandle)*(ei.Count + 1));
EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)disableWnds,
TParam2((TEnumInfo *)&ei));
ei.Wnds = hWnds; // Restore alloc'd pointer since enumerator bumps it
}
else if (window) {
// In MB_APPMODAL mode, we simply disable the window specified
//
ei.ModalWnd = window->GetHandle(); // Remember who to re-enable later
CHECK(ei.ModalWnd);
window->EnableWindow(false);
}
// Enter message loop, saving & restoring the current status & getting the
// returned result.
//
int result;
try {
result = MessageLoop();
}
catch (...) {
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, false);
termModal(ei);
data.SetInfo(lastStackTop);
throw;
}
{
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, false);
data.SetInfo(lastStackTop);
termModal(ei); // Just in case termModal was missed in EndModal
}
// Return the result from the modal window's EndModal call
//
return result;
}
//
/// Cause the current modal message loop to break and have it return a result
/// Re-enable the disabled windows here, if the EnumInfo is available.
//
void
TApplication::EndModal(int result)
{
MessageLoopResult = result;
BreakMessageLoop = true;
TEnumInfoStr& data = GetEnumInfo();
if (data.GetInfo()){
LOCKENUMINFO(data.Lock, false);
termModal(*data.GetInfo());
}
}
//----------------------------------------------------------------------------
#if defined(OWL_SUPPORT_BWCC)
#if !defined(BWCCVERSION) // solely foe WARNX
#define BWCCVERSION 0x0200 // version 2.00
#endif
//
/// Loads and registers either BWCC.DLL if you are running 16-bit applications or
/// BWCC32.DLL if you are running 32-bit applications.
/// To disable BWCC, set enable to false.
/// Library is not free'd on disable to reduce re-loads if enabling on the fly
/// \note BWCC is now obsolete and should be used only for backward compatibility
void
TApplication::EnableBWCC(bool enable, uint language)
{
if (enable) {
if (!BWCCModule) {
try {
BWCCModule = new TBwccDll();
BWCCModule->IntlInit(language);
BWCCModule->Register(GetHandle());
WARNX(OwlApp, BWCCModule->GetVersion() < BWCCVERSION, 0, \
_T("Old version of BWCC DLL found"));
}
catch (...) {
TRACEX(OwlApp, 0, _T("Unable to create instance of TBwccDll"));
return;
}
}
}
BWCCOn = enable;
}
#endif //#if defined(OWL_SUPPORT_BWCC)
//----------------------------------------------------------------------------
#if defined(OWL_SUPPORT_CTL3D)
//
/// Enables or disables the use of the CTL3D DLL. If enable is true, EnableCtl3d
/// loads and registers the CTL3D.DLL if it is not already enabled.
/// \note Usage of Ctl3d is now obsolete and should be used only for backward compatibility
//
void
TApplication::EnableCtl3d(bool enable)
{
// As per Article Q125684 of Microsoft Development Library:
// "If major version is 4 or greater, the application should not
// implement CTL3D".
// 'How to Use CTL3D Under the Windows 95 Operating System'
//
if (TSystem::GetMajorVersion() >= 4)
return;
// Load the Ctl3d DLL if needed & register our instance
//
if (enable) {
if (!Ctl3dModule) {
try {
Ctl3dModule = new TCtl3dDll();
Ctl3dModule->Register(*this);
}
catch (...) {
TRACEX(OwlApp, 0, _T("Unable to create instance of TCtl3dDll"));
return;
}
}
}
Ctl3dOn = enable;
}
//
/// Enable or disable Ctl3d's use of auto-subclassing.
//
/// Caller should turn on autosubclassing before creating a non-owl dialog to
/// make it 3d, & turn it off immediatly after.
///
/// Enables or disables CTL3D's use of autosubclassing if CTL3D is already enabled
/// using Ctl3dEnabled. If autosubclassing is enabled, any non-ObjectWindows dialog
/// boxes have a 3-D effect. The common dialog classes and TDocManager use this
/// function both to turn on autosubclassing before creating a non-ObjectWindows
/// dialog box to make it three-dimensional and to turn off autosubclassing
/// immediately after the dialog box is destroyed.
//
void
TApplication::EnableCtl3dAutosubclass(bool enable) const
{
if (Ctl3dEnabled()) {
if (enable) {
Ctl3dModule->Register(*this);
Ctl3dModule->AutoSubclass(*this);
}
else {
Ctl3dModule->Unregister(*this);
}
}
}
#endif //#if defined(OWL_SUPPORT_CTL3D)
//----------------------------------------------------------------------------
#if defined(OWL_SUPPORT_BWCC)
//
/// Predefined DLLs that TApplication knows how to find.
//
const tchar BwccDllName[] = _T("BWCC32.DLL");
//
/// Load the BWCC DLL dynamically.
/// Bind the member functions to the exported functions.
//
/// This is how TApplication::EnableBWCC uses TBwccDll:
/// \code
/// if (!BWCCModule) {
/// try {
/// BWCCModule = new TBwccDll();
/// BWCCModule->IntlInit(language);
/// BWCCModule->Register(GetHandle());
///
/// WARNX(OwlApp, BWCCModule->GetVersion() < BWCCVERSION, 0, \\
/// _T("Old version of BWCC DLL found"));
/// }
/// catch (...) {
/// TRACEX(OwlApp, 0, _T("Unable to create instance of TBwccDll"));
/// return;
/// }
/// \endcode
//
TBwccDll::TBwccDll()
:
TModule(BwccDllName, true, true, false), // shouldLoad, mustLoad and !addToList
IntlInit(*this, "BWCCIntlInit"),
Register(*this, "BWCCRegister"),
IntlTerm(*this, "BWCCIntlTerm"),
SpecialLoadDialog(*this, "SpecialLoadDialog"),
MangleDialog(*this, "MangleDialog"),
DefDlgProc(*this, "BWCCDefDlgProc"),
DefGrayDlgProc(*this, "BWCCDefGrayDlgProc"),
DefWindowProc(*this, "BWCCDefWindowProc"),
DefMDIChildProc(*this, "BWCCDefMDIChildProc"),
MessageBox(*this, "BWCCMessageBox"),
GetPattern(*this, "BWCCGetPattern"),
GetVersion(*this, "BWCCGetVersion")
{
}
#endif //#if defined(OWL_SUPPORT_BWCC)
//----------------------------------------------------------------------------
#if defined(OWL_SUPPORT_CTL3D)
//
/// Predefined DLLs that TApplication knows how to find.
//
const tchar Ctl3dDllName[] = _T("CTL3D32.DLL");
//
/// Load the Ctl3d DLL dynamically.
/// Bind the member functions to the exported functions.
//
TCtl3dDll::TCtl3dDll()
:
TModule(Ctl3dDllName, true, true, false), // shouldLoad, mustLoad and !addToList
Register(*this, "Ctl3dRegister"),
Unregister(*this, "Ctl3dUnregister"),
AutoSubclass(*this, "Ctl3dAutoSubclass"),
CtlColorEx(*this, "Ctl3dCtlColorEx"),
SubclassDlg(*this, "Ctl3dSubclassDlg"),
SubclassDlgEx(*this, "Ctl3dSubclassDlgEx"),
GetVer(*this, "Ctl3dGetVer"),
Enabled(*this, "Ctl3dEnabled"),
ColorChange(*this, "Ctl3dColorChange"),
SubclassCtl(*this, "Ctl3dSubclassCtl"),
DlgFramePaint(*this, "Ctl3dDlgFramePaint"),
WinIniChange(*this, "Ctl3dWinIniChange")
{
}
#endif //#if defined(OWL_SUPPORT_CTL3D)
//----------------------------------------------------------------------------
#if OWL_PERSISTENT_STREAMS
// Broken apart: IMPLEMENT_STREAMABLE1(TApplication, TModule);
// to replace the ctor
//
IMPLEMENT_STREAMABLE_CLASS(TApplication);
IMPLEMENT_STREAMER(TApplication);
IMPLEMENT_STREAMABLE_POINTER(TApplication)
//
// IMPLEMENT_STREAMABLE_CTOR1(TApplication, TModule), plus TMsgThread init
//
TApplication::TApplication(StreamableInit)
:
TModule(streamableInit),
TMsgThread(TMsgThread::Current)
{
}
//
//
//
void*
TApplication::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
TApplication* o = GetObject();
if (o != owl::Module)
is >> *owl::Module; // set reference to OWL module
return o;
}
//
//
//
void
TApplication::Streamer::Write(opstream& os) const
{
TApplication* o = GetObject();
if (o != owl::Module)
os << *owl::Module; // write out reference to OWL module, no data written
}
#else
IMPLEMENT_STREAMABLE1(TApplication, TModule);
#endif
//----------------------------------------------------------------------------
// TWaitCursor data
inline bool FilterWindow (HWND hWnd){
return !::IsWindowEnabled (hWnd) || !::IsWindowVisible (hWnd);
}
//
/// Enum[Thread/Task]Windows callback. Counts or subclasses given window based on
/// whether or not window list has been allocated yet.
//
static bool CALLBACK
subclassWnds(HWND hWnd, TEnumInfo * ei)
{
if (!FilterWindow (hWnd)) {
if (!ei->Wnds) {
ei->Count++; // no buffer yet, we are just counting
}
else {
*(ei->Wnds++) = hWnd;
*(ei->PrevWndProc++) = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)TWaitHook::WaitWndProc);
}
}
return true;
}
//
enum{
WM_NCMOUSEFIRST = WM_NCMOUSEMOVE,
WM_NCMOUSELAST = WM_NCMBUTTONDBLCLK
};
//
TWaitHook::TWaitHook()
:
LastStackTop(0),
HideCaretCount(0),
Cursor(0),
DeleteOnClose(false)
{
memset(&Subclass,0,sizeof(Subclass));
TEnumInfoStr& data = GetEnumInfo();
LastStackTop = data.GetInfo(); // Keep last stackTop to restore later
data.SetInfo(&Subclass); // Point stackTop to topmost ei
// Count windows to subclass
//
if (!::EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)subclassWnds,
TParam2((TEnumInfo *)&Subclass)))
return;
// Allocate list of windows to disable, disable windows that are
// enabled and then stuff them into the list.
//
HWND* hWnds = Subclass.Wnds = new HWND[Subclass.Count + 1];
WNDPROC* fProc = Subclass.PrevWndProc = new WNDPROC[Subclass.Count + 1];
memset(Subclass.Wnds, 0, sizeof(HWND)*(Subclass.Count + 1));
memset(Subclass.PrevWndProc, 0, sizeof(WNDPROC)*(Subclass.Count + 1));
EnumThreadWindows(GetCurrentThreadId(), (WNDENUMPROC)subclassWnds,
TParam2((TEnumInfo *)&Subclass));
Subclass.Wnds = hWnds; // Restore alloc'd pointer since enumerator bumps it
Subclass.PrevWndProc = fProc; // Restore alloc'd pointer
HideCaret(0);
HideCaretCount = 1;
Cursor = new TCursor(::LoadCursor (0, IDC_WAIT));
DeleteOnClose = true;
SetWaitCursor();
}
//
TWaitHook::~TWaitHook()
{
for (int i = 0; i < Subclass.Count; i++)
::SetWindowLongPtr(Subclass.Wnds[i], GWLP_WNDPROC, (LONG_PTR)Subclass.PrevWndProc[i]);
delete [] Subclass.Wnds;
delete [] Subclass.PrevWndProc;
while(HideCaretCount--)
ShowCaret(0);
TPoint pt;
::GetCursorPos(&pt);
::SetCursorPos(pt.x, pt.y);
GetEnumInfo().SetInfo(LastStackTop); // Restore stackttop
FreeCursors();
}
//
void TWaitHook::FreeCursors()
{
if(DeleteOnClose)
delete Cursor;
Cursor = 0;
}
//
void TWaitHook::SetCursor(TCursor* cursor, TAutoDelete del)
{
FreeCursors();
Cursor = cursor;
DeleteOnClose = del == AutoDelete;
}
//
void TWaitHook::SetWaitCursor()
{
::SetCursor(*Cursor);
}
//
LRESULT CALLBACK TWaitHook::WaitWndProc(HWND wnd, UINT msg, WPARAM param1, LPARAM param2)
{
return GetEnumInfo().Hook->WaitWndMethod(wnd, msg, param1, param2);
}
//
TResult TWaitHook::WaitWndMethod(HWND wnd, TMsgId msg, TParam1 param1, TParam2 param2)
{
HWND hTopMostWindow;
switch (msg){
case WM_SETCURSOR:
SetWaitCursor();
return TRUE;
case WM_MOUSEACTIVATE:
hTopMostWindow = (HWND)param1;
if (hTopMostWindow == wnd)
return MA_ACTIVATEANDEAT;
return ::DefWindowProc(wnd, msg, param1, param2);
case WM_SETFOCUS:
DefWndProc (wnd, msg, param1, param2);
HideCaret(0);
++HideCaretCount;
return 0;
}
if ((msg >= WM_KEYFIRST && msg <= WM_KEYLAST) ||
(msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) ||
(msg >= WM_NCMOUSEFIRST && msg <= WM_NCMOUSELAST))
{
return 0; // ::DefWindowProc (wnd, msg, param1, param2);
}
return DefWndProc (wnd, msg, param1, param2);
}
//
TResult TWaitHook::DefWndProc(HWND wnd, TMsgId msg, TParam1 param1, TParam2 param2)
{
for(int i = 0; i < (int)Subclass.Count; i++){
if (Subclass.Wnds[i] == wnd)
return CallWindowProc(Subclass.PrevWndProc[i], wnd, msg, param1, param2);
}
PRECONDITION(0);
return 0;
}
//----------------------------------------------------------------------------
//
/// Changes the cursor to cursor. If TAutoDelete is set to AutoDelete the cursor
/// resource is deleted when the wait cursor is destoryed.
//
void TWaitCursor::SetCursor(TCursor* cursor, TAutoDelete del)
{
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, false);
if(data.Hook)
data.Hook->SetCursor(cursor,del);
}
//----------------------------------------------------------------------------
//
/// Called by the constructors to add this cursor into the applications chain.
//
void TWaitCursor::Init()
{
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, false);
Next = data.Top;
data.Top = this;
if(!Next){
PRECONDITION(data.Hook == 0);
data.Hook = new TWaitHook;
}
}
//
/// Restores the previous cursor.
//
TWaitCursor::~TWaitCursor()
{
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, false);
const auto ok = data.Top == this; // Must be destructed in reverse order.
WARN(!ok, _T("TWaitCursor::~TWaitCursor: Terminating due to failed precondition."));
if (!ok) terminate();
if(data.Top){
data.Top = Next;
if(!Next){
delete data.Hook;
data.Hook = 0;
}
}
}
//
/// Restores old state of cursor.
//
void TWaitCursor::Restore()
{
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, false);
delete data.Hook;
data.Hook = 0;
data.Top = 0;
}
//----------------------------------------------------------------------------
//
/// Sends text to the applications TMessageBar::SetHintText function if it has one.
//
void TWaitCursor::Message(const tstring& msg)
{
TEnumInfoStr& data = GetEnumInfo();
LOCKENUMINFO(data.Lock, true);
if(data.Top == this && data.Hook){
TApplication* app = OWLGetAppDictionary().GetApplication(0);
if(!app)
return;
TFrameWindow* frame= app->GetMainWindow();
if (frame){
TMessageBar* messageBar =
TYPESAFE_DOWNCAST(frame->ChildWithId(IDW_STATUSBAR), TMessageBar);
if(messageBar){
messageBar->SetHintText(msg);
messageBar->UpdateWindow();
}
}
}
}
//-----------------------------------------------------------------------------
//
TLangModule::TLangModule(const tstring& prefix, const TApplication& appl)
:
Prefix(prefix),
Module(0),
Application(&(TApplication&)appl),
LangId(static_cast<unsigned short>(-1)) //JJH added static_cast
{
SetLanguage(appl.GetLangId());
}
//-----------------------------------------------------------------------------
TLangModule::~TLangModule()
{
if(Module && Module != Application)
delete Module;
}
//-----------------------------------------------------------------------------
void TLangModule::SetLanguage(const TLangId& langId)
{
tstring mname = Prefix;
tchar szLocName[10];
int retval = ::GetLocaleInfo(langId,LOCALE_SABBREVLANGNAME, szLocName, 10);
if(retval)
mname += szLocName;
else
mname += _T("ENU");
mname += _T(".DLL");
TModule* module = new TModule(mname.c_str(),true, false, true); // shouldLoad, !mustLoad and addToList
if(module->GetHandle() <= HINSTANCE(HINSTANCE_ERROR)){
delete module;
tstring locname = Prefix;
locname += _T("ENU.DLL");
module = new TModule(locname.c_str(),true, false, true); // shouldLoad, !mustLoad and addToList
if(module->GetHandle() > HINSTANCE(HINSTANCE_ERROR))
mname = locname;
else{
delete module;
module = Application;
}
}
if(Module && Module != Application)
delete Module;
Module = module;
// init LangId
InitLanguage pProc = (InitLanguage)Module->GetProcAddress("InitLanguage");
if(pProc)
pProc();
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
} // OWL namespace
//===============================================================================
↑ V1004 The 'win' pointer was used unsafely after it was verified against nullptr. Check lines: 1258, 1260.
↑ V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: Count.
↑ V1004 The 'WaitHandles' pointer was used unsafely after it was verified against nullptr. Check lines: 959, 975.
↑ V1004 The 'win' pointer was used unsafely after it was verified against nullptr. Check lines: 1258, 1259.
↑ V522 There might be dereferencing of a potential null pointer '_caption'.
↑ V820 The 'locname' variable is not used after copying. Copying can be replaced with move/swap for optimization.
↑ V820 The 'e' variable is not used after copying. Copying can be replaced with move/swap for optimization.