🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.nativeapi
6 messages
6 total messages Started by Dennis Jones Wed, 31 May 2006 00:50
Handle of MessageBox
#3571
Author: Dennis Jones
Date: Wed, 31 May 2006 00:50
23 lines
1668 bytes
Hi,

I need the ability to programmatically close a message box.  However, I only
want to close it if it was opened as a result of calling MessageBox or
Application->MessageBox from a specific form (which is also open).  To do
so, it would seem that I need to know a couple of things:

1) If a message box is currently open
2) If the message box was opened in the context of a specific form
3) The handle of the message box

Is it possible to obtain these 3 pieces of information?

This requirement comes from the need to close a form programatically, which
includes closing any forms opened by (owned by) that form, which also
includes (potentially) message boxes.  I have been able to handle closing
TForm and TCommonDialog descendants, but I'm stuck on message boxes.

Any suggestions would be welcome.

Thanks,

- Dennis
Re: Handle of MessageBox
#3572
Author: Ed Mulroy
Date: Wed, 31 May 2006 01:07
28 lines
2107 bytes
You are going at it the hard way.  Make a window that you use as a message 
box.  Make the button on the form open that window instead of a regular 
message box.  You can then supply a function which closes the window.

.  Ed

> Dennis Jones wrote in message
> news:447ce85d$1@newsgroups.borland.com...
>
> I need the ability to programmatically close a message box.  However, I 
> only
> want to close it if it was opened as a result of calling MessageBox or
> Application->MessageBox from a specific form (which is also open).  To do
> so, it would seem that I need to know a couple of things:
>
> 1) If a message box is currently open
> 2) If the message box was opened in the context of a specific form
> 3) The handle of the message box
>
> Is it possible to obtain these 3 pieces of information?
>
> This requirement comes from the need to close a form programatically, 
> which
> includes closing any forms opened by (owned by) that form, which also
> includes (potentially) message boxes.  I have been able to handle closing
> TForm and TCommonDialog descendants, but I'm stuck on message boxes.
>
> Any suggestions would be welcome.
Re: Handle of MessageBox
#3573
Author: Remy Lebeau (TeamB)
Date: Wed, 31 May 2006 01:12
65 lines
3842 bytes
"Dennis Jones" <nospam@nospam.com> wrote in message
news:447ce85d$1@newsgroups.borland.com...

> I need the ability to programmatically close a message box.

From where exactly?  MessageBox() shows a modal dialog, so you can't close
it from the context of the thread that is displaying it (without some
low-level hooks, that is).

> However, I only want to close it if it was opened as a result of calling
> MessageBox or Application->MessageBox from a specific form
> (which is also open).

That is going to be very tricky.  Sure, you can detect whether the form is
open.  But you can't really detect if MessageBox() was called from any
particular form.  The only identifying feature of a MessageBox dialog in
regards to its caller is the Owner HWND that is provided as a parameter to
MessageBox().  Most of the time, that is NULL when calling MessageBox()
directly.  And when not NULL, there is no guarantee that it is the calling
form.  When calling TApplication::MessageBox(), the Owner is always the
TApplication::Handle, never any form.

> To do so, it would seem that I need to know a couple of things:
>
> 1) If a message box is currently open
> 2) If the message box was opened in the context of a specific form
> 3) The handle of the message box
>
> Is it possible to obtain these 3 pieces of information?

#1 is obtained by simply using FindWindow() and similar functions to check
for the existance of a dialog box.  The class name is "#32770".  You can
then use GetWindowThreadProcessId() to make sure the HWND belongs to your
target application.

Do note, however, that other Win32 API dialogs might reuse that same dialog
class, so you will likely have to analyze the window a bit to make sure it
really is a MessageBox dialog.

#2 is almost, if not completely, impossible to obtain.  Especially if you
are trying to do all of this outside of that form class.

#3 is obtainable from the result of #1.  Alternatively, the code that is
calling MessageBox() can obtain the HWND directly by installing a
thread-local WH_CBT hook via SetWindowHookEx() before calling MessageBox().
The HCBT_ACTIVATE notification contains the HWND.  Using a WH_CBT hook is a
good way to customize a standard MessageBox dialgo with extra controls, for
example.

> This requirement comes from the need to close a form programatically,
> which includes closing any forms opened by (owned by) that form, which
> also includes (potentially) message boxes.  I have been able to handle
closing
> TForm and TCommonDialog descendants, but I'm stuck on message boxes.

If the TForm owns the MessageBox dialog, meaning that the TForm::Handle was
specified when calling MessageBox(), then the message should close
automatically when iwns Owner TForm is closed.  If, on the other hand, a
NULL owner was specified (which is usually the case), then your operation is
going to have a very hard time figuring out whether the dialog belongs to
the TForm or not.


Gambit
Re: Handle of MessageBox
#3574
Author: Dennis Jones
Date: Wed, 31 May 2006 01:25
16 lines
1653 bytes
"Ed Mulroy" <dont_email_me@bitbuc.ket> wrote in message
news:447cec43$1@newsgroups.borland.com...
> You are going at it the hard way.  Make a window that you use as a message
> box.  Make the button on the form open that window instead of a regular
> message box.  You can then supply a function which closes the window.

When adding enhancements to a working application, I generally like to make
as few changes as possible (for obvious reasons), so creating another dialog
and injecting it into my code (in who knows how many places) was something I
was hoping to avoid.  However, given the relative ease of implementation, I
suppose it is a more reasonable alternative, comparatively speaking.

Thanks,

- Dennis
Re: Handle of MessageBox
#3575
Author: Dennis Jones
Date: Wed, 31 May 2006 01:44
21 lines
1653 bytes
"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message
news:447cee05$1@newsgroups.borland.com...

> From where exactly?  MessageBox() shows a modal dialog, so you can't close
> it from the context of the thread that is displaying it (without some
> low-level hooks, that is).

Right.  In my case, the process is kicked off by a TTimer::OnTimer event
handler on the application's main form and uses PostMessage calls to close
the windows in question.

The rest of your message pretty much falls in line with what I was
expecting.  Fortunately, Ed's suggestion is a better (and simpler!)
alternative to implementing a complex solution that may or may not even
work!  By creating and using a custom message box class, the solution
becomes trivial.

Thanks,

- Dennis
Re: Handle of MessageBox
#3576
Author: Remy Lebeau (TeamB)
Date: Wed, 31 May 2006 02:02
66 lines
2816 bytes
"Dennis Jones" <nospam@nospam.com> wrote in message
news:447cf4e6$1@newsgroups.borland.com...

> Right.  In my case, the process is kicked off by a TTimer::OnTimer event
> handler on the application's main form and uses PostMessage calls to close
> the windows in question.

One thing to try is to have each form that shows a MessageBox grab the HWND,
like I mentioned earlier, and store it in a member of itself.  Then your
TTimer can close the active MessageBox of any form it wants.  For example
(untested):

    class TForm1 : public TForm
    {
    private:
        HWND hMsgBoxWnd;
        HHOOK hMsgBoxHook;
        static LRESULT CALLBACK MsgBoxCBTProc(int nCode, WPARAM wParam,
LPARAM lParam);
    public:
        int __fastcall ShowMsgBox(const AnsiString &Msg, const AnsiString
&Title, int Flags);
        void __fastcall CloseMsgBox();
    };


    LRESULT CALLBACK TForm1::MsgBoxCBTProc(int nCode, WPARAM wParam, LPARAM
lParam)
    {
        if( nCode == HCBT_ACTIVATE )
            Form1->hMsgBoxWnd = reinterpret_cast<HWND>(wParam);

        return ::CallNextHookEx(Form1->hMsgBoxHook);
    }

    int __fastcall TForm1::ShowMsgBox(const AnsiString &Msg, const
AnsiString &Title, int Flags)
    {
        hMsgBoxHook = ::SetWindowsHookEx(WH_CBT, (HOOKPROC) MsgBoxCBTProc,
NULL, GetCurrentThreadId());
        if( !hMsgBoxHook )
            return 0;

        int iRet = ::MessageBox(NULL, Msg.c_str(), Title.c_str(), Flags);
        hMsgBoxWnd = NULL;

        ::UnhookWindowsHookEx(hMsgBoxHook);
        hMsgBoxHook = NULL;

        return iRet;
    }

    void __fastcall TForm1::CloseMsgBox()
    {
        if( hMsgBoxWnd )
            ::EndDialog(hMsgBoxWnd, IDABORT);
    }

    void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
        Form1->CloseMsgBox();
    }


Gambit
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads