//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1991, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of class TDialog. TDialogs are the base for any type of
/// modal or modeless window that loads itself from resource.
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/dialog.h>
#include <owl/applicat.h>
#include <owl/commctrl.h>
#include <owl/appdict.h>
#include <string.h>
#if defined(OWL_SUPPORT_BWCC)
# include <owl/private/bwcc.h>
#endif
#include <owl/winres.rh> // Defines RT_DLGINIT etc.
namespace owl {
/// \class TDialog
/// Typically used to obtain information from a user, a dialog box is a window
/// inside of which other controls such as buttons and scroll bars can appear.
/// Unlike actual child windows which can only be displayed in the parent window's
/// client area, dialog boxes can be moved anywhere on the screen. TDialog objects
/// represent both modal and modeless dialog box interface elements. (A modal dialog
/// box disables operations in its parent window while it is open, and, thus, lets
/// you function in only one window "mode.")
///
/// A TDialog object has a corresponding resource definition that describes the
/// placement and appearance of its controls. The identifier of this resource
/// definition is supplied to the constructor of the TDialog object. A TDialog
/// object is associated with a modal interface element by calling its Execute
/// member function and with a modeless interface element by calling its Create
/// member function.
///
/// You can use TDialog to build an application that uses a dialog as its main
/// window by constructing your dialog as a TDialog and passing it as the client of
/// a TFrameWindow. Your code might look something like this:
/// \code
/// SetMainWindow(new TFrameWindow(0, "title" new TDialog(0, IDD_MYDIALOG)));
/// \endcode
/// TDialog is a streamable class.
///
/// ObjectWindows also encapsulates common dialog boxes that let the user select
/// font, file name, color, print options, and so on. TCommonDialog is the parent
/// class for this group of common dialog box classes.
OWL_DIAGINFO;
DIAG_DECLARE_GROUP(OwlMsg); // diagnostic group for message tracing
DIAG_DECLARE_GROUP(OwlWin); // diagnostic group for windows
#define dfTmplMask 0x0f0000 // template mask
#define dfTmplDelMask 0x0a0000 // delete mask
//
// Global message id for GetWindowPtr call defined in owl.cpp
//
extern _OWLDATA(uint) GetWindowPtrMsgId;
//----------------------------------------------------------------------------
//
// Public so derived classes can create // !CQ make a static, protected member?
//
//JJH
#if defined(WINELIB)
static
#endif
_OWLDATA(TDialog*) DlgCreationWindow = 0;
DEFINE_RESPONSE_TABLE1(TDialog, TWindow)
EV_WM_CLOSE,
EV_WM_PAINT,
EV_DM_GETDEFID,
EV_DM_SETDEFID,
EV_DM_REPOSITION,
EV_COMMAND(IDOK, CmOk),
EV_COMMAND(IDCANCEL, CmCancel),
END_RESPONSE_TABLE;
//
/// Constructor for a TDialog object
//
/// Takes an TResId for its template name or numeric Id
//
/// Invokes a TWindow constructor, passing parent and module, and calls
/// DisableAutoCreate to prevent TDialog from being automatically created and
/// displayed along with its parent. TDialog then initializes the caption to 0 and sets
/// TDialogAttr.Name using the dialog box's integer or string resource
/// identifier which must correspond to a dialog resource definition in the resource
/// file. Note that resId may be 0, e.g. when TDialog encapsulates a common dialog.
///
/// Finally, it initializes TDialogAttr.Param to 0 and clear the flag dfIsModal, and
/// if OWL5_COMPAT is defined IsModal is set to false.
//
TDialog::TDialog(TWindow* parent, TResId resId, TModule* module)
{
// Initialize virtual base, in case the derived-most used default ctor
//
Init(parent, 0, module);
DialogAttr.Name = resId.IsString() ? strnewdup(resId) : const_cast<LPTSTR>(static_cast<LPCTSTR>(resId));
}
//
/// Takes an pointer to dialog template
//
/// Invokes a TWindow constructor, passing parent and module, and calls
/// DisableAutoCreate to prevent TDialog from being automatically created and
/// displayed along with its parent. TDialog then initializes the caption to 0 and sets
/// TDialogAttr.Name using DLGTEMPLATE*.
///
/// Finally, it initializes TDialogAttr.Param to 0 and clear the flag dfIsModal, and
/// if OWL5_COMPAT is defined IsModal is set to false.
//
TDialog::TDialog(TWindow* parent, const DLGTEMPLATE& dlgTemplate, TAutoDelete del, TModule* module)
{
Init(parent, 0, module);
DialogAttr.Name = (LPTSTR)&dlgTemplate;
SetFlag(del == AutoDelete ? dfDeleteTemplate : dfNoDeleteTemplate);
}
//
/// Invokes a TWindow constructor, passing parent and module, and calls
/// DisableAutoCreate to prevent TDialog from being automatically created and
/// displayed along with its parent. TDialog then initializes the caption to 0 and sets
/// TDialogAttr.Name using DLGTEMPLATE*.
///
/// Finally, it initializes TDialogAttr.Param to 0 and clear the flag dfIsModal, and
/// if OWL5_COMPAT is defined IsModal is set to false.
//
TDialog::TDialog(HGLOBAL hTemplate, TWindow* parent, TAutoDelete del, TModule* module)
{
PRECONDITION(hTemplate);
Init(parent, 0, module);
DialogAttr.Name = (LPTSTR)GlobalLock(hTemplate);
SetFlag(del == AutoDelete ? dfDeleteHandle : dfNoDeleteHandle);
}
//
/// Common initialization in constructoe
//
void
TDialog::Init(TWindow* parent, LPCTSTR /*title*/, TModule* module)
{
#if defined(OWL5_COMPAT)
IsModal = false;
#endif
// Initialize virtual base, in case the derived-most used default ctor
//
TWindow::Init(parent, 0, module);
DisableAutoCreate();
// NB! Previously (<= 6.30) TWindow::Title was here set to 0x0000FFFF as a flag.
// This "don't-change" flag was then detected in SetCaption to disable title updates.
// It seems the only reason for this was to avoid that the SetCaption call in SetupWindow
// overwrote the title of the window loaded from the resource.
//
// Now, the caption is simply set to 0 here. We use the flag wfFromResource to detect that
// we need to sync the caption from the loaded resource later (see SetupWindow).
SetFlag(wfFromResource);
ClearFlag(wfDeleteOnClose);
DialogAttr.Param = 0;
DialogAttr.Name = 0;
}
//
/// Destructor for a TDialog
//
/// If DialogAttr.Name is a string and not an integer resource identifier, this destructor
/// frees memory allocated to DialogAttr.Name, which holds the name of the dialog box.
//
TDialog::~TDialog()
{
if(!IsFlagSet(dfTmplMask)){
if (TResId(DialogAttr.Name).IsString())
delete[] DialogAttr.Name;
}
else if(IsFlagSet(dfTmplDelMask))
{
if(IsFlagSet(dfDeleteHandle)) // Is DialogAttr.Name a handle to memory that should be deleted?
::GlobalFree(::GlobalHandle(DialogAttr.Name)); // Free it.
else if(IsFlagSet(dfNoDeleteHandle)) // Is DialogAttr.Name a handle to memory that should not be deleted?
::GlobalUnlock(::GlobalHandle(DialogAttr.Name)); // Just unlock it then.
}
// If DlgCreationWindow still points to this object, zero it, as the object is no longer valid
if (DlgCreationWindow == this)
{
DlgCreationWindow = 0;
}
}
//
/// Preprocess posted messages to provide various accelerator translations.
//
/// Overrides the virtual function defined by TWindow in order to perform
/// preprocessing of window messages. If the child window has requested keyboard
/// navigation, PreProcessMsg handles any accelerator key messages and then
/// processes any other keyboard messages.
//
bool
TDialog::PreProcessMsg(MSG& msg)
{
// Processed any accelerators associated with this window
//
if (TWindow::PreProcessMsg(msg))
return true;
// See if we are in an mdi child, & try mdi accelerator translation if so
//
THandle child;
THandle client;
if ((child = GetParentH()) != 0 &&
(client = ::GetParent(child)) != 0 &&
child == (THandle)::SendMessage(client, WM_MDIGETACTIVE, 0, 0) &&
::TranslateMDISysAccel(client, &msg))
return true;
// Do dialog accelerator translation last, since it tends to eat other
// accelerators
//
return ::IsDialogMessage(GetHandle(), &msg);
}
//
/// Overrides the virtual function defined in TWindow and returns the name of the
/// dialog box's default Windows class, which must be used for a modal dialog box.
/// For a modeless dialog box, GetWindowClassName returns the name of the default TWindow.
//
auto TDialog::GetWindowClassName() -> TWindowClassName
{
#if defined(OWL_SUPPORT_BWCC)
if (GetApplication()->BWCCEnabled())
return TWindowClassName{BORDLGCLASS};
else
#endif
return TWindowClassName{WC_DIALOG};
}
//
/// Overrides the virtual function defined in TWindow. Fills WndClass with TDialog
/// registration attributes obtained from an existing TDialog window
///
/// If the class style is registered with CS_GLOBALCLASS, you must unregister the
/// class style. You can do this by turning off the style bit. For example:
/// \code
/// {
/// baseclass::GetWindowClass(wndClass);
/// ....
/// WndClass.style &= ~CS_GLOBALCLASS:
/// ...
/// }
/// \endcode
//
void
TDialog::GetWindowClass(WNDCLASS& wndClass)
{
#if defined(OWL_SUPPORT_BWCC)
const auto a = GetApplication(); CHECK(a);
const auto b = a->BWCCEnabled();
if (b)
a->GetBWCCModule()->Register(*GetModule());
const auto dlgClass = b ? TWindowClassName{BORDLGCLASS} : TWindowClassName{WC_DIALOG};
#else
const auto dlgClass = TWindowClassName{WC_DIALOG};
#endif
if (!TUser::GetClassInfo(0, dlgClass.GetPointerRepresentation(), &wndClass))
GetModule()->GetClassInfo(dlgClass, &wndClass);
wndClass.lpszClassName = GetWindowClassName().GetPointerRepresentation();
wndClass.hInstance = *GetModule(); // !CQ Win32 only? (B50.26561)
}
//
/// Handler for WM_PAINT. Rerout this message back to the underlying dialog to
/// keep TWindow::EvPaint from eating it.
//
/// EvPaint calls TWindow's general-purpose default processing function,
/// DefaultProcessing, for Windows-supplied painting.
//
void
TDialog::EvPaint()
{
DefaultProcessing();
}
//
/// Return the default Id.
/// High word must be DC_HASDEFID.
//
/// Calls the DefaultProcessing() function. Returns the result.
//
uint
TDialog::EvGetDefId()
{
return static_cast<uint>(DefaultProcessing());
}
//
/// Set the pushbutton with identifier id the default button for the dialog.
///
/// Calls the DefaultProcessing function. Returns the result (type cast to boolean).
//
bool
TDialog::EvSetDefId(int /*id*/)
{
return static_cast<bool>(DefaultProcessing());
}
//
/// Reposition the dialog so that it fits within the desktop area
//
void
TDialog::EvReposition()
{
DefaultProcessing();
}
//
/// The default dialog function. Handles the two mesages, WM_INITDIALOG and
/// WM_SETFONT that may be passed to us without sending, or sent before we get
/// a chance to thunk DIALOG's window proc.
//
/// EvInitDialog() is called as a virtual function, while EvSetFont() is dispatched
/// to.
//
/// To process messages within the dialog function, your application must override
/// this function. DialogFunction returns true if the message is handled and false
/// if the message is not handled.
//
INT_PTR
TDialog::DialogFunction(TMsgId msg, TParam1 param1, TParam2 param2)
{
TRACEX(OwlMsg, 2, TMsgName(msg) << _T("(DlgFcn)=> ") << *this);
switch (msg) {
// 'Dispatch' WM_INITDIALOG by making a virtual call--no response table
// used. This is not generally overriden, and only arrives once.
//
case WM_INITDIALOG:
return EvInitDialog((THandle)param1);
// Dispatch WM_SETFONT only for the first, non-sent occurance. Subsequent
// WM_SETFONTs will be dispatched normally in TWindow.
//
case WM_SETFONT:
{
struct TEventGuard
{
TCurrentEvent& Current;
TCurrentEvent Previous;
TEventGuard(TCurrentEvent& ce, TWindow* win, TMsgId msg, TParam1 param1, TParam2 param2)
: Current{ce}, Previous{ce}
{
Current.Win = win;
Current.Message = msg;
Current.Param1 = param1;
Current.Param2 = param2;
}
~TEventGuard() { Current = Previous; }
auto IsRecursive()
{
// Event handlers may call TWindow::DefaultProcessing, which may cause a recursive call.
// We assume this is the case if the current event matches the previous.
//
return Current.Win == Previous.Win &&
Current.Message == Previous.Message &&
Current.Param1 == Previous.Param1 &&
Current.Param2 == Previous.Param2;
}
}
event{GetCurrentEvent(), this, msg, param1, param2};
auto wasHandled = TResult{FALSE};
if (!IsFlagSet(wfFullyCreated) && !event.IsRecursive())
{
auto eventInfo = TEventInfo{msg};
if (Find(eventInfo))
{
Dispatch(eventInfo, param1, param2);
wasHandled = TRUE;
}
}
return wasHandled;
}
#if defined(OWL_SUPPORT_CTL3D)
// Catch these few messages here & forward to the ctrl3d dll if it is
// loaded and enabled.
//
case WM_SETTEXT:
case WM_NCPAINT:
case WM_NCACTIVATE:
if (GetApplication()->Ctl3dEnabled()) {
SetMsgResult(GetApplication()->GetCtl3dModule()->
DlgFramePaint(GetHandle(), msg, param1, param2));
}
break;
#endif
}
return false; // Not handled
}
//
/// Handles messages that come from the window procedure of dialogs (WC_DIALOG's
/// wndProc). If DlgCreationWindow is not 0, then msg is destined for
/// DlgCreationWindow. When StdDlgProc first receives a message, it checks to see if
/// it needs to associate the global C++ variable DlgCreationWindow with the one
/// passed in HWND. If it needs to do that, it will then subclass the window
/// procedure. It calls the virtual DialogFunction() to handle specific messages,
/// mostly for the startup sequence.
/// Any exception within this function is suspended by TApplication::SuspendThrow.
//
INT_PTR CALLBACK
TDialog::StdDlgProc(HWND hDlg, UINT msg, WPARAM param1, LPARAM param2) noexcept
{
try
{
// Retrieve the TDialog pointer.
//
if (msg == GetWindowPtrMsgId) return false;
TDialog* dlg = dynamic_cast<TDialog*>(owl::GetWindowPtr(hDlg));
if (DlgCreationWindow && !dlg && msg != WM_CANCELMODE && msg != WM_ENABLE)
{
dlg = DlgCreationWindow;
dlg->SetHandle(hDlg);
dlg->SubclassWindowFunction();
DlgCreationWindow = 0;
}
if (!dlg) return false;
// Dispatch the message to the DialogFunction virtual function.
//
return dlg->DialogFunction(msg, param1, param2);
}
catch (...)
{
TRACEX(OwlWin, 0, _T("TDialog::StdDlgProc: Suspending unhandled exception for message: ") << msg);
OWLGetAppDictionary().GetApplication()->SuspendThrow(std::current_exception());
}
return false; // If we get here, an error occurred.
}
//
/// Register all the dialog's child objects (for custom control support)
//
void
TDialog::RegisterChildObjects()
{
for (auto& w : GetChildren())
if (!w.Register())
throw TXWindow(this, IDS_CLASSREGISTERFAIL);
}
//
/// Creates a modeless dialog box interface element associated with the TDialog
/// object. Registers all the dialog's child windows for custom control support.
/// Calls PerformCreate to perform the actual creation of the dialog box. Create
/// returns true if successful. If unsuccessful, Create throws a TXInvalidWindow
/// exception.
//
bool
TDialog::Create()
{
PRECONDITION(GetHandle() == 0);
#if defined(OWL5_COMPAT)
IsModal = false;
#endif
ClearFlag(dfIsModal);
if (!Register())
TXWindow::Raise(this, IDS_CLASSREGISTERFAIL);
DlgCreationWindow = this;
LoadAcceleratorTable();
// Register all the dialog's child objects (for custom control support)
//
RegisterChildObjects();
CHECK(!GetHandle()); // Ensure handle is NULL in case of exceptions.
// In the new API, PerformCreate takes no arguments.
// Also PerformCreate now returns the handle instead of calling SetHandle.
//
SetHandle(PerformCreate());
GetApplication()->ResumeThrow();
WARNX(OwlWin, !GetHandle(), 0, _T("TDialog::Create failed"));
if (!GetHandle())
TXWindow::Raise(this, IDS_WINDOWCREATEFAIL);
GetHWndState();
return true;
}
//
/// Called from Create to perform the final step in creating an Windows interface
/// element to be associated with a TWindow. Creates the dialgo using either a
/// resource id or dialog template.
//
// TODO: Store the DLGTEMPLATE in a separate parameter instead of multiplexing it
// into DialogAttr.Name and make DialogAttr.Name a TResId.
//
TWindow::THandle
TDialog::PerformCreate()
{
PRECONDITION(GetModule());
typedef const DLGTEMPLATE* TTemplate;
THandle h = !IsFlagSet(dfTmplMask) ?
::CreateDialogParam (
*GetModule(),
DialogAttr.Name,
GetParentO() ? GetParentO()->GetHandle() : 0,
reinterpret_cast<DLGPROC>(StdDlgProc),
DialogAttr.Param
) :
::CreateDialogIndirectParam(
*GetModule(),
reinterpret_cast<TTemplate>(DialogAttr.Name),
GetParentO() ? GetParentO()->GetHandle() : 0,
reinterpret_cast<DLGPROC>(StdDlgProc),
DialogAttr.Param
);
return h;
}
//
/// Creates and executes a modal dialog box interface element associated with the TDialog object.
/// If the element is successfully associated, Execute does not return until the TDialog is closed.
///
/// Execute performs the following tasks:
///
/// -# Registers this dialog's window class and all of the dialog's child windows.
/// -# Calls TDialog::DoExecute to execute the dialog box.
///
/// Execute returns an integer value that indicates how the user closed the modal dialog box. This
/// will normally be IDOK or IDCANCEL, but the value may be customized by derived dialog classes.
///
/// If the dialog class cannot be registered (TWindow::Register returns false), or the execution of
/// the dialog fails (TDialog::DoExecute returns -1), then Execute throws the TXWindow exception.
///
/// \note Derived dialog classes may need to communicate errors apart from window creation failure.
/// The derived class may throw other exceptions, return other error codes, or set custom error
/// states. For example, the classes TFileOpenDialog and TFileSaveDialog will set the associated
/// TOpenSaveDialog::TData::Error state to indicate any errors, such as buffer overflow. In
/// general, client code should be aware of any error handling defined by the derived class. Do not
/// assume that a return value of IDOK means success.
///
/// For example:
///
/// \code
/// TOpenSaveDialog::TData data{...};
/// TFileOpenDialog dlg{this, data};
/// const auto r = dlg.Execute();
/// if (data.Error != 0)
/// {
/// // ...Handle error...
/// }
/// else if (r == IDOK)
/// {
/// // ...Open file...
/// }
/// \endcode
//
int
TDialog::Execute()
{
PRECONDITION(GetHandle() == 0);
#if defined(OWL5_COMPAT)
IsModal = true;
#endif
SetFlag(dfIsModal);
if (!Register())
TXWindow::Raise(this, IDS_CLASSREGISTERFAIL);
DlgCreationWindow = this;
// Register all the dialog's child objects (for custom control support)
//
RegisterChildObjects();
int retValue = DoExecute();
GetApplication()->ResumeThrow();
// DoExecute returns -1 if it could not create the dialog box
//
if (retValue == -1)
TXWindow::Raise(this, IDS_WINDOWEXECUTEFAIL);
return retValue;
}
//
//
/// Overriden TWindow virtual to modaly execute this dialog & return the result.
///
/// DoExecute is called by Execute() to perform the actual execution of a modal dialog
/// box. If enabled Emulation of ModalDialog it calls TWindow::DoExecute().
//
int
TDialog::DoExecute()
{
if (IsFlagSet(dfModalWindow))
return TWindow::DoExecute();
TModule::THandle m = GetModule()->GetHandle();
TWindow::THandle p = GetParent() ? GetParent()->GetHandle() : 0;
LPCDLGTEMPLATE t = reinterpret_cast<LPCDLGTEMPLATE>(DialogAttr.Name);
INT_PTR r = IsFlagSet(dfTmplMask) ?
::DialogBoxIndirectParam(m, t, p, StdDlgProc, DialogAttr.Param) :
::DialogBoxParam(m, DialogAttr.Name, p, StdDlgProc, DialogAttr.Param);
WARN(r > INT_MAX, _T("TDialog::DoExecute: EndDialog 64-bit result truncated to 32 bits."));
return static_cast<int>(r);
}
//
/// Performs resource-directed initialization of controls. Uses the DLGINIT
/// resource with an id matching this dialog's as structured message packets
/// to send to controls.
//
/// Initializes the dialog box controls with the contents of DLGINIT, the dialog
/// box resource identifier, which describes the appearance and location of the
/// controls (buttons, group boxes, and so on). Returns true if successful,
/// or no DLGINIT resource was found; otherwise returns false.
//
bool
TDialog::PerformDlgInit()
{
if (!DialogAttr.Name) return true; // Move along; nothing to see here.
// Try to retrieve a pointer to RT_DLGINIT resource data.
//
char* res = 0;
if (IsFlagSet(dfTmplMask))
res = reinterpret_cast<char*>(DialogAttr.Name); // Should point to DLGINIT resource data.
else
{
HRSRC hRes = GetModule()->FindResourceEx(DialogAttr.Name, RT_DLGINIT, GetApplication()->GetLangId());
if (!hRes) hRes = GetModule()->FindResource(DialogAttr.Name, RT_DLGINIT);
if (hRes)
{
HGLOBAL hDat = GetModule()->LoadResource(hRes);
if (!hDat) return false;
res = static_cast<char*>(::LockResource(hDat));
if (!res) return false;
}
}
if (!res) return true; // No DLGINIT, but that's fine.
// Now pick up message packets from the DLGINIT resource and send them.
// A null-terminator indicates the end.
//
while (*res)
{
// Decode the message packet header (idc, msg, len).
//
WORD idc = *reinterpret_cast<WORD*>(res); res += sizeof(idc);
WORD msg = *reinterpret_cast<WORD*>(res); res += sizeof(msg);
DWORD len = *reinterpret_cast<DWORD*>(res); res += sizeof(len);
void* data = res;
// Send the message.
// Handle old MFC custom messages and the OWL DLGINIT messages specially.
// These messages carry ANSI strings, so we convert to wide string as needed.
// We check for the null-terminator to catch mal-formed strings.
//
switch (msg)
{
case 0x0401: // LB_ADDSTRING alias (data is ANSI text)
{
_USES_CONVERSION;
if (res[len - 1] != '\0') return false;
LPCTSTR text = _A2W(static_cast<LPCSTR>(data));
LRESULT r = SendDlgItemMessage(idc, LB_ADDSTRING, 0, TParam2(text));
if (r == LB_ERR || r == LB_ERRSPACE) return false;
break;
}
case 0x0403: // CB_ADDSTRING alias (data is ANSI text)
{
_USES_CONVERSION;
if (res[len - 1] != '\0') return false;
LPCTSTR text = _A2W(static_cast<LPCSTR>(data));
LRESULT r = SendDlgItemMessage(idc, CB_ADDSTRING, 0, TParam2(text));
if (r == CB_ERR || r == CB_ERRSPACE) return false;
break;
}
case 0x1234: // CBEM_INSERTSTRING alias (data is ANSI text)
{
_USES_CONVERSION;
if (res[len - 1] != '\0') return false;
COMBOBOXEXITEM item;
item.mask = CBEIF_TEXT;
item.iItem = -1;
item.pszText = _A2W(static_cast<LPSTR>(data));
LRESULT r = SendDlgItemMessage(idc, CBEM_INSERTITEM, 0, TParam2(&item));
if (r == -1) return false;
break;
}
case OWL_DLGINIT_COMMAND: // TODO: Move the code in this block to its own function.
{
// There should be no data with this message.
//
if (len != 0)
{
TRACE(_T("Corrupt OWL_DLGINIT_COMMAND in DLGINIT. Expected data size 0, but size was ") << len << _T(".\n"));
return false;
}
// There should be an initialisation command in the static text of the given control.
// We load the static text of the given control, which should be in the format "{<command>}".
// We then execute "<command>". Currently, the only command supported is "LoadString <id>",
// which specifies that we should load the title of the control from resource string <id>.
//
using namespace std;
IFDIAG(static const tchar error[] = _T("Either correct the command in the control title, or remove the OWL_DLGINIT_COMMAND message in DLGINIT.");)
tstring title = GetDlgItemText(idc);
tistringstream in(title);
in.setf(ios::skipws);
tchar openingBrace;
tstring cmd;
in >> openingBrace >> cmd;
if (!in.good() || openingBrace != _T('{'))
{
TRACE(_T("PerformDlgInit expected {<command>} in the title of control #") << idc
<< _T(", but found \"") << title << _T("\".\n") << error);
return false;
}
if (cmd == _T("LoadString"))
{
int id;
tchar closingBrace;
in >> id >> closingBrace;
if (!in.good() || closingBrace != _T('}'))
{
TRACE(_T("PerformDlgInit found a syntax error in the title of control #") << idc
<< _T(": \"") << title << _T("\".\n") << error);
return false;
}
SetDlgItemText(idc, id);
}
else
{
TRACE(_T("PerformDlgInit didn't recognize the command in the title of control #") << idc
<< _T(": \"") << cmd << _T("\".\n") << error);
return false;
}
break;
}
default: // Send any other message type and hope it goes well (there is no consistent way to detect failure).
{
WARNX(OwlMsg, true, 1, _T("Default DLGINIT item handler sent message #") << msg << _T(" to control #") << idc << _T(" with no error handling."));
SendDlgItemMessage(idc, msg, 0, TParam2(data));
break;
}
}
// Move the pointer to the next packet.
//
res = static_cast<char*>(data) + len;
}
GetApplication()->ResumeThrow();
return true;
}
//
/// Virtual handler for WM_INITDIALOG message, called from DialogFunction() just
/// before the dialog box is displayed. Performs any setup
/// required for the dialog box or its controls.
//
bool
TDialog::EvInitDialog(THandle /*hFocus*/)
{
GetHWndState();
if (DialogAttr.Name) // Resource to initialize?
{
bool r = PerformDlgInit();
if (!r) TXWindow::Raise(this, IDS_DLGINITFAIL);
}
PerformSetupAndTransfer();
return true; // have Windows set focus to "hFocus"
}
//
/// Overrides the virtual function defined in TWindow. Sets up the dialog box by
/// calling SetCaption and TWindow::SetupWindow.
///
/// Calling SetCaption here allows us to override the dialog caption
/// (specified in the dialog resource) by calling SetCaption prior to this point.
/// If the caption is not yet initialised, and the dialog is created from a
/// resource, we sync the caption with the window text title.
//
void
TDialog::SetupWindow()
{
#if defined(OWL_SUPPORT_CTL3D)
// If this app is using Ctl3d, tell it to explicitly subclass this dialog's
// controls (CTL3D_ALL). Its better to do this here than enable
// autosubclassing since that requires a CBT hook set all the time which
// slows the app considerably.
//
if (GetApplication()->Ctl3dEnabled())
GetApplication()->GetCtl3dModule()->SubclassDlg(*this, 0xFFFF);
#endif
TWindow::SetupWindow();
if (!GetCaption() && IsFlagSet(wfFromResource))
GetWindowTextTitle();
else
SetCaption(GetCaption());
}
//
/// Overrides the virtual function defined by TWindow and conditionally shuts down
/// the dialog box. If the dialog box is modeless, it calls TWindow::CloseWindow(), passing retValue.
///
/// If the dialog box is modal, it calls CanClose(). If CanClose() returns true,
/// CloseWindow() calls TransferData() to transfer dialog box data, and shuts down, passing retValue.
/// \note The default value of retValue is IDCANCEL.
//
void
TDialog::CloseWindow(int retValue)
{
if (IsFlagSet(dfIsModal))
{
try
{
if (CanClose())
{
TransferData(tdGetData);
Destroy(retValue);
}
}
catch (...)
{
// Jogy - an exception throw in either CacClose() or TransferData() can leave the dialog and it's message loop
// hanging around, leaving the application in an unusable state. To avoid this, call unconditionally Destroy,
// and then rethrow the exception to a higher-level handler
Destroy(retValue);
throw;
}
}
else
TWindow::CloseWindow(retValue);
}
//
/// Destroys the interface element associated with the TDialog object. If the
/// element is a modeless dialog box or enabled Emulation of ModlaDialog , Destroy
/// calls TWindow::Destroy. If the element is a modal dialog box, Destroy calls
/// EnableAutoCreate on all child windows. Then Destroy calls the Windows function
/// ::&EndDialog, passing retValue as the value returned to indicate the result of
/// the dialog's execution. The default retValue is IDCANCEL.
//
void
TDialog::Destroy(int retValue)
{
if (!IsFlagSet(dfModalWindow) && IsFlagSet(dfIsModal) && GetHandle())
{
for (auto& w : GetChildren())
if (w.GetHandle())
w.EnableAutoCreate();
::EndDialog(GetHandle(), retValue);
}
else
TWindow::Destroy(retValue);
}
// Section is empty. It used to be occupied by a SetCaption override, that is no
// longer needed.
//
/// Responds to a click on the dialog box's OK button with the identifier IDOK.
/// Calls CloseWindow, passing IDOK.
//
void
TDialog::CmOk()
{
CloseWindow(IDOK);
if (!IsFlagSet(dfIsModal) && !GetHandle() && IsFlagSet(wfDeleteOnClose))
GetApplication()->Condemn(this);
}
//
/// Responds to an incoming notification message from a button with
/// an Id equal to IDCANCEL. Unconditionally destroys the window.
//
void
TDialog::CmCancel()
{
EvClose();
}
//
/// Message response function for WM_CLOSE by unconditionally closing
/// the window.
//
void
TDialog::EvClose()
{
if (IsFlagSet(wfAlias))
DefaultProcessing();//if this line is missing, when subclassing dialogs, (e.g. messagebox), they do not close
else
{
Destroy(IDCANCEL);
if (!IsFlagSet(dfIsModal) && !GetHandle() && IsFlagSet(wfDeleteOnClose))
GetApplication()->Condemn(this);
}
}
//
/// Constructor. Initializes the base class.
//
TControlEnabler::TControlEnabler(uint id, HWND hWndReceiver)
:
TCommandEnabler(id, hWndReceiver)
{
}
//
/// Enables/disables the control.
//
void
TControlEnabler::Enable(bool enable)
{
if(ToBool(::IsWindowEnabled(GetReceiver())) != enable)
::EnableWindow(GetReceiver(), enable);
TCommandEnabler::Enable(enable);
}
//
/// Set the text of the control
//
void
TControlEnabler::SetText(LPCTSTR text)
{
TTmpBuffer<tchar> buffer(MAX_PATH);
::GetWindowText(GetReceiver(),buffer,MAX_PATH);
if(_tcscmp(buffer, text) != 0)
::SetWindowText(GetReceiver(), text);
}
//
/// Use with only buttons!
//
void
TControlEnabler::SetCheck(int check)
{
if(::SendMessage(GetReceiver(), BM_GETCHECK,0,0) != check)
::SendMessage(GetReceiver(), BM_SETCHECK, check, 0);
}
//
/// If idleCount is 0, iterates over each child control and routes the command
/// enabler. Does not rely on an OWL interface object to work. Returns false.
//
bool
TDialog::IdleAction(long idleCount)
{
TWindow::IdleAction(idleCount);
if (idleCount == 0) {
HWND child = GetWindow(GW_CHILD);
while (::IsWindow(child)) {
int id = ::GetWindowLong(child, GWL_ID);
TControlEnabler ce(id, child);
RouteCommandEnable(*this, ce);
child = ::GetWindow(child, GW_HWNDNEXT);
}
}
return false;
}
//
/// Returns the rect, specified in screen coordinates, corresponding to the given rect, specified
/// in dialog coordinates.
/// Throws TXOWl on failure.
//
auto TDialog::MapDialogRectToScreen(const TRect& rDialog) const -> TRect
{
auto rScreen = rDialog;
auto r = MapDialogRect(rScreen);
if (!r) throw TXOwl{_T("TDialog::MapDialogRectToScreen failed")};
return rScreen;
}
//
/// Sets focus within a dialog to a specific control.
//
void
TDialog::SetControlFocus(HWND hwnd)
{
CHECK(hwnd);
SendMessage(WM_NEXTDLGCTL, TParam1(hwnd), 1);
}
//
/// Sets the focus to either the previous control with WS_TABSTOP, or the next
/// control with WS_TABSTOP.
//
void
TDialog::SetControlFocus(THow how)
{
SendMessage(WM_NEXTDLGCTL, (how == Next) ? 1 : 0, 0);
}
IMPLEMENT_STREAMABLE1(TDialog, TWindow);
#if OWL_PERSISTENT_STREAMS
//
// Reads an instance of TDialog from the passed ipstream
//
void*
TDialog::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
ReadBaseObject((TWindow*)GetObject(), is);
is >> (TResId&)GetObject()->DialogAttr.Name;
bool isModal;
is >> isModal;
isModal ? GetObject()->SetFlag(dfIsModal) : GetObject()->ClearFlag(dfIsModal);
return GetObject();
}
//
// Writes the TDialog to the passed opstream
//
void
TDialog::Streamer::Write(opstream& os) const
{
WriteBaseObject((TWindow*)GetObject(), os);
os << TResId(GetObject()->DialogAttr.Name);
os << (bool)GetObject()->IsFlagSet(dfIsModal);
}
#endif
} // OWL namespace
↑ V1051 Consider checking for misprints. It's possible that the 'dlgClass' should be used inside 'TUser::GetClassInfoA' function.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'false' value is implicitly cast to the integer type.
↑ V601 The 'false' value is implicitly cast to the integer type.