Thread View: borland.public.cppbuilder.nativeapi
12 messages
12 total messages
Started by Jyrki Holopainen
Mon, 17 Sep 2007 18:43
How to bring window (TForm) front
Author: Jyrki Holopainen
Date: Mon, 17 Sep 2007 18:43
Date: Mon, 17 Sep 2007 18:43
61 lines
2861 bytes
2861 bytes
I have an application that is divided into two separate executable
files. The first one writes data to a file and starts the second one.
When the second exe starts, it reads the data from a file and displays
it. During the startup the second exe must check if the program is
already running. In that case it sends a command to the running program
which reads the data and displays it. The running program must bring
it's window to the front, but that seems to be difficult under Windows XP.
The following function calls (called from TForm context) do not have
(any) effect:
VCL:
Show();
Visible = true;
BringToFront();
Application->BringToFront(); //Flashes the status bar icon three times?
SetFocus();
Windows API:
BringWindowToTop(Handle);
SetForegroundWindow(Handle);
EnableWindow(Handle, TRUE);
SetActiveWindow(Handle);
::SetFocus(Handle);
The following works, but the look and feel is bad especially if window
open/close animation is turned on (which is the default setting in Windows).
Application->Minimize();
Application->Restore();
The following is the best solution that I have managed to make. The
problem is that if the window is not in a minimized state, it is not
activated, but the focus stays in the original application. The
'minimized' is a boolean member that is updated in the Application event
handlers OnMinimize and OnRestore.
if (minimized)
{
Application->Restore();
}
else
{
SetWindowPos(Handle,
HWND_TOPMOST,
0,0,0,0, // Dummy size & position
SWP_NOSIZE | SWP_NOMOVE);
SetWindowPos(Handle,
HWND_NOTOPMOST,
0,0,0,0,
SWP_NOSIZE | SWP_NOMOVE);
}
How can this be so difficult, or am I missing something completely trivial?
/Jyrki Holopainen
Re: How to bring window (TForm) front
Author: Vladimir Stefanovic
Date: Mon, 17 Sep 2007 19:34
Date: Mon, 17 Sep 2007 19:34
84 lines
3429 bytes
3429 bytes
> [...] The running program must bring it's window to the
> front, but that seems to be difficult under Windows XP.
I know exactly what you are talking about, becasue I've
developed similar software few years ago. I experienced
the very same issues. Every single code which worked in
one scenariio faild in other and vice versa.
Now, I've looked in the code which I beleave was a solution
in my case. You can try and check if it can help in your case.
I tried everything, and stopped with this silly code.
--- Service EXE which calls other EXE ---
// function C(...) is my internal, and it returns just an AnsiString
// from crypted resource file.
// Just use simple "...some appropriate text ..." instead
// ...
HANDLE lanmsg = FindWindow(
C(IDS_SER_MAIN_NT_SERVICE_INVOKING_CLASS).c_str(), NULL );
if ( lanmsg != NULL )
{
// These three lines helped.
// Of course I could bundle all this in just one call but then
// things just didn't work (flickering in status bar)
PostMessage ( lanmsg, WM_USER + 1010, 0, 0 );
PostMessage ( lanmsg, WM_USER + 1011, 0, 0 );
PostMessage ( lanmsg, WM_USER + 1012, 0, 0 );
}
else
{
AnsiString Exe = ExtractFilePath( ParamStr(0) ) +
C(IDS_SER_MAIN_NT_SERVICE_INVOKING_EXE_FILE);
STARTUPINFO StartInfo;
PROCESS_INFORMATION ProcInfo;
memset(&ProcInfo, 0, sizeof(ProcInfo));
memset(&StartInfo, 0 , sizeof(StartInfo));
StartInfo.cb = sizeof(StartInfo);
if ( ! CreateProcess( Exe.c_str(),NULL, NULL, NULL, NULL, NULL, NULL,
NULL,
&StartInfo, &ProcInfo ) )
{
SystemOk = false;
GoSendMessageToLog( SERVICE_CREATE_PROCESS_FAILED );
}
}
// ...
--- EXE which is called ---
(btw, it was FormStyle = fsStayOnTop)
void __fastcall TLanMsgMainForm::WndProc( TMessage &Msg )
{
switch ( Msg.Msg )
{
// ...
case WM_USER + 1010:
ReloadView(); //<--- Data to be shown in TreeView
break;
case WM_USER + 1011:
Application->Restore();
break;
case WM_USER + 1012:
Application->BringToFront();
break;
// ...
}
TForm::WndProc( Msg );
}
All this tels me that some Application->ProcessMessages()
placed in appropriate place could help in preventing flashing
app in status bar, but never had time to investigate further.
--
Best Regards,
Vladimir Stefanovic
Re: How to bring window (TForm) front
Author: Dennis Jones
Date: Mon, 17 Sep 2007 19:37
Date: Mon, 17 Sep 2007 19:37
53 lines
3441 bytes
3441 bytes
"Jyrki Holopainen" <New.Address@spammers.com> wrote in message
news:46eecb19@newsgroups.borland.com...
>
> I have an application that is divided into two separate executable files.
> The first one writes data to a file and starts the second one. When the
> second exe starts, it reads the data from a file and displays it. During
> the startup the second exe must check if the program is already running.
> In that case it sends a command to the running program which reads the
> data and displays it. The running program must bring it's window to the
> front, but that seems to be difficult under Windows XP.
>
> How can this be so difficult, or am I missing something completely
> trivial?
It's not difficult, but there is a trick to it. Once you know that there is
another instance already running (and it sounds like you've already solved
that part of it, so I won't give an explanation here), then you just need to
know how to correctly access the running instance's main window. The
following code is pulled directly from one of my applications (written in
BCB6, runs on XP). The key to doing this is knowing that the main form in a
VCL app is *not* the same as the main window of a Windows application:
// The main "form" in a C++Builder/Delphi application is not the
// application's main window (as far as Windows is concerned).
// TApplication creates a hidden window that acts as the true main
// window for the application. Thus, whenever we want to refer to
the
// application's main window, we must use the handle of the window
// created by TApplication, not the handle of the main "form". The
// TApplication's window handle is the parent window handle for the
// main form, so it is easy to find:
// get the window handle of the other instance's main form
(according to its class name)
HWND MainFormHWnd = FindWindow( "TMyMainForm", NULL );
// get the main form's parent window handle (we'll assume
MainFormHWnd
// is not NULL, since we wouldn't even be here unless another
instance
// of the application were actually running)
HWND hAppWnd = (HWND)GetWindowLong( MainFormHWnd, GWL_HWNDPARENT );
if ( IsIconic( hAppWnd ) )
{
ShowWindow( hAppWnd, SW_RESTORE );
}
SetForegroundWindow( hAppWnd );
HTH,
- Dennis
Re: How to bring window (TForm) front
Author: Dennis Jones
Date: Mon, 17 Sep 2007 19:40
Date: Mon, 17 Sep 2007 19:40
21 lines
1612 bytes
1612 bytes
"Vladimir Stefanovic" <antivari@sbb.co.yu> wrote in message news:46eed6a9$1@newsgroups.borland.com... >> [...] The running program must bring it's window to the >> front, but that seems to be difficult under Windows XP. > > I know exactly what you are talking about, becasue I've > developed similar software few years ago. I experienced > the very same issues. Every single code which worked in > one scenariio faild in other and vice versa. > > Now, I've looked in the code which I beleave was a solution > in my case. You can try and check if it can help in your case. > > I tried everything, and stopped with this silly code. > <snipped> Ouch! :-) See my (simple!) reply to the OP. - Dennis
Re: How to bring window (TForm) front
Author: Vladimir Stefanovic
Date: Mon, 17 Sep 2007 19:51
Date: Mon, 17 Sep 2007 19:51
18 lines
1427 bytes
1427 bytes
> if ( IsIconic( hAppWnd ) )
> {
> ShowWindow( hAppWnd, SW_RESTORE );
> }
> SetForegroundWindow( hAppWnd );
I hope this works ;)
(saved in my archives anyway, and will test once in real
working software)
But I think that there was some reason why I moved
bring-to-front code to local app side.
--
Best Regards,
Vladimir Stefanovic
Re: How to bring window (TForm) front
Author: << Wiljo >>
Date: Tue, 18 Sep 2007 11:32
Date: Tue, 18 Sep 2007 11:32
30 lines
2035 bytes
2035 bytes
Vladimir Stefanovic schreef:
>> if ( IsIconic( hAppWnd ) )
>> {
>> ShowWindow( hAppWnd, SW_RESTORE );
>> }
>> SetForegroundWindow( hAppWnd );
>
> I hope this works ;)
> (saved in my archives anyway, and will test once in real
> working software)
>
> But I think that there was some reason why I moved
> bring-to-front code to local app side.
>
We had the same problem here as well. And we were finally using the
Minimize and Restore option described in the original post as well. Not
really nice, but it did the job. I have just tried this new approach,
and I must say that it works like a charm. Never thought the Application
itself was a window, albeit hidden from view. We use it on the local
application side that is being restoredas well. It gets an IPC message
anyway, so we can now write:
if( IsIconic( Application->Handle ))
{
ShowWindow( Application->Handle, SW_RESTORE );
}
SetForegroundWindow( Application->Handle );
Many thanks for this simple solution.
Wiljo.
Re: How to bring window (TForm) front
Author: Jyrki Holopainen
Date: Tue, 18 Sep 2007 16:43
Date: Tue, 18 Sep 2007 16:43
30 lines
2427 bytes
2427 bytes
Dennis Jones wrote:
> HWND MainFormHWnd = FindWindow( "TMyMainForm", NULL );
>
> // get the main form's parent window handle (we'll assume
> MainFormHWnd
> // is not NULL, since we wouldn't even be here unless another
> instance
> // of the application were actually running)
> HWND hAppWnd = (HWND)GetWindowLong( MainFormHWnd, GWL_HWNDPARENT );
>
> if ( IsIconic( hAppWnd ) )
> {
> ShowWindow( hAppWnd, SW_RESTORE );
> }
> SetForegroundWindow( hAppWnd );
My problem was that under Windows XP a process cannot necessarily move
it's own window to foreground. The Win-API documentation that comes with
BCB6 does not mention this. This is described for example in
http://msdn2.microsoft.com/en-us/library/ms633539.aspx.
The code above works well if it is run at the program that gives
commands to program that is already running. Since these are two
separate processes, the SetForegroundWindow() function works. I had the
respective code at the part that was already running (logical place),
and that was the reason why it did not work.
Thanks everybody for the help!
/Jyrki
Re: How to bring window (TForm) front
Author: Richard Kavanagh
Date: Mon, 24 Sep 2007 10:38
Date: Mon, 24 Sep 2007 10:38
3 lines
1038 bytes
1038 bytes
Does anybody have a solution when the previous instance is running in the system tray? Richard Kavanagh
Re: How to bring window (TForm) front
Author: Dennis Jones
Date: Mon, 24 Sep 2007 16:48
Date: Mon, 24 Sep 2007 16:48
12 lines
1454 bytes
1454 bytes
"Richard Kavanagh" <dd.foldhill[at]googlemail.com> wrote in message news:46f793b2$1@newsgroups.borland.com... > Does anybody have a solution when the previous instance is running in the > system tray? > Richard Kavanagh Well, my application, which is often in the system tray, gets restored to the desktop when the second instance executes the code I posted earlier. Does it not work for you? How are you minimizing your app to the tray? - Dennis
Re: How to bring window (TForm) front
Author: Richard Kavanagh
Date: Mon, 24 Sep 2007 18:35
Date: Mon, 24 Sep 2007 18:35
19 lines
1768 bytes
1768 bytes
> Well, my application, which is often in the system tray, gets restored to
> the desktop when the second instance executes the code I posted earlier.
> Does it not work for you? How are you minimizing your app to the tray?
> - Dennis
Dennis, I modified a TrayIcon component I found, (Apologies to the writer -
I did not save your name) I think thev relevant function is:-
void __fastcall TrkTrayIcon::MainFormVisible(bool AVisible)
{
// Do not change at Designtime...
if(!ComponentState.Contains(csDesigning))
{
if((Application->MainForm != NULL) &&
Application->MainForm->HandleAllocated())
Application->MainForm->Visible = AVisible;
}
}
Re: How to bring window (TForm) front
Author: Dennis Jones
Date: Mon, 24 Sep 2007 20:28
Date: Mon, 24 Sep 2007 20:28
58 lines
2912 bytes
2912 bytes
"Richard Kavanagh" <dd.foldhill[at]googlemail.com> wrote in message
news:46f80367@newsgroups.borland.com...
>> Well, my application, which is often in the system tray, gets restored to
>> the desktop when the second instance executes the code I posted earlier.
>> Does it not work for you? How are you minimizing your app to the tray?
>> - Dennis
>
> Dennis, I modified a TrayIcon component I found, (Apologies to the
> writer - I did not save your name) I think thev relevant function is:-
>
>
> void __fastcall TrkTrayIcon::MainFormVisible(bool AVisible)
> {
> // Do not change at Designtime...
> if(!ComponentState.Contains(csDesigning))
> {
> if((Application->MainForm != NULL) &&
> Application->MainForm->HandleAllocated())
> Application->MainForm->Visible = AVisible;
> }
> }
Okay. When I send my application to the tray, I do something similar:
void __fastcall TMyMainForm::MinimizeToTray(TObject* /*Sender*/)
{
ShowWindow(Application->Handle,SW_HIDE);
}
In my case,
if ( IsIconic( hAppWnd ) )
{
ShowWindow( hAppWnd, SW_RESTORE );
}
is sufficient to bring the application out of the tray and put it back onto
the desktop. So, you might try hiding the form with ShowWindow() instead of
using MainForm->Visible=false (I am not sure, but I think the two methods
work differently). Or, if you don't want to do that, you may be able to set
Visible=true in an OnRestore handler:
TMyMainForm::TMyMainForm(TComponent* Owner)
: TForm(Owner)
{
// call RestoreFromTray if the GUI is restored from a minimized/iconized
state
Application->OnRestore = RestoreFromTray;
}
void __fastcall TMyMainForm::RestoreFromTray(TObject* /*Sender*/)
{
Application->MainForm->Visible = true;
}
- Dennis
Re: How to bring window (TForm) front
Author: Richard Kavanagh
Date: Tue, 25 Sep 2007 09:29
Date: Tue, 25 Sep 2007 09:29
26 lines
2053 bytes
2053 bytes
Dennis,
Many thanks. I solved the problem by adding a PostMessage() command - see
below.
Richard.
// get the window handle of the other instance's main form
//(according to its class name)
HWND mainFormHWnd = ::FindWindow( "TMyMainForm", NULL );
// added the following line to show main form if running in tray
::PostMessage(mainFormHWnd, WM_SYSCOMMAND, SC_RESTORE, 0);
// still need the rest if program running 'normally'
// get the main form's parent window handle (we'll assume mainFormHWnd
// is not NULL, since we wouldn't even be here unless another instance
// of the application were actually running)
HWND hAppWnd = (HWND)::GetWindowLong( mainFormHWnd, GWL_HWNDPARENT );
if(::IsIconic( hAppWnd ) )
{
::ShowWindow( hAppWnd, SW_RESTORE );
}
::SetForegroundWindow( hAppWnd );
return 0;
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