Page 1 of 1

Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by synergyfocus >> Tue, 10 Jun 2003 1:10:09 GMT

Hi,
I am trying to get a Jade form to get the focus, when it is not the Jade application that currently has the focus.

We have a messenger type utility within our app to allow users to send messages to each other. If they are working within the app, then the messenger window comes to the front. However if they are not working in the app, say in Outlook, then the messenger window does not come to the top, in stays as a new window in the background.
The setFocus and zOrder only work if another Jade window is the currently active window. So can can I get a Jade window to have the focus, when another Jade window is not the currently active window on my desktop?


I put this Jade Support, and got the foloowing reply:
W2K and XP deliberately make it difficult for a thread to activate its windows if it is not in the foreground (it is considered rude to do so). SetFocus and SetActiveWindow will not cause a thread in the background to become a foreground window. This is not a JADE problem. JADE only responds to what Window's tells it to do. However, there maybe a combination of Windows API calls that will enable this to be done.

Does anyone have any ideas?!?

Thanks
Stephen Persson

Re: Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by michaelj >> Tue, 10 Jun 2003 8:17:53 GMT

Stephen ,

I also encountered that same problem, The following should do the job.

Define an external function as below.

setForegroundWindow(
hWnd : Integer // handle to destination window ):Boolean is SetForegroundWindow in user32;

usage should be something like;

vars
form : Form;
.....

call setForegroundWindow( form.hwnd() );


Michael.

Re: Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by brendan1 >> Wed, 11 Jun 2003 20:20:19 GMT

Stephen,
This is a well-known problem for Windows 2000, 98 etc. and particularly for COM object writers since they always want to force the window of another app to the foreground. There are many long laments and moans on various newsgroups on the web.

Unfortunately setForegroundWindow does not work on W2K. However, there are nasty ways round this which I have found on various newgroups and tested in JADE. The following code works on W2K and Windows NT. You may be able to remove the restriction on process.getOSPlatform(versionOS, archOS) = Node.OSWindowsEnterprise and extend it to Windows 98 and XP. I didn't have 98 or XP to test it on. Please let me know how it gpoes if you can.

External function calls (all on user32) required are

attachThreadInput(idAttach : Integer; idAttachTo : Integer; fAttach : Integer): Integer is AttachThreadInput in user32;
// if fAttach is TRUE, attaches thread idAttach to thread idAttachTo
// if fAttach is FALSE, detaches thread idAttach from thread idAttachTo

bringWindowToTop(hwnd : Integer): Integer is BringWindowToTop in user32; // Attempts to put window hwnd to top of window list

getForegroundWindow(): Integer is GetForegroundWindow in user32;
// Returns a handle to the current foreground window

getWindowThreadProcessId(hWnd, lpdwProcessId : Integer): Integer is GetWindowThreadProcessId in user32;
// returns thread corresponding to window with handle hWnd. Set lpdwProcessId = 0

setForegroundWindow(hwnd : Integer): Integer is SetForegroundWindow in user32;
// Attempts to set the foregrond window to hwnd

getSystemParametersInfo(uAction:Integer;uParam:Integer;lpvParam:Integer io;fuWinIni:Integer):Integer is SystemParametersInfoA in user32;
// Has many different functions, mainly to do with getting values in registry normally viewed via ControlPanel

setSystemParametersInfo(uAction:Integer;uParam:Integer;lpvParam:Integer;fuWi nIni:Integer):Integer is SystemParametersInfoA in user32;
// Has many different functions, mainly to do with setting values in registry normally set via ControlPanel

The following method will return true if the required window is forced to the foreground.

forceForegroundWindow(pForm : Form): Boolean;
// Forces pForm to be the foreground window.
// Returns true if successful, false otherwise.
constants
TRUE : Integer = 1;
FALSE : Integer = 0;
SPI_GETFOREGROUNDLOCKTIMEOUT : Integer = #2000;
SPI_SETFOREGROUNDLOCKTIMEOUT : Integer = #2001;
SPIF_SENDCHANGE : Integer = 2;

vars
formHandle : Integer;
currentForegroundWindow : Integer;
saveTimeout : Integer;
foregroundThreadId : Integer;
formThreadId : Integer;
versionOS : String;
archOS : Integer;
begin

formHandle := pForm.hwnd;
// Check to see if it already is the foreground window
if call getForegroundWindow() = formHandle then
return true;
endif;
// Try using BringWindowToFront etc without any fiddling
call bringWindowToTop(formHandle);
call setForegroundWindow(formHandle);
if call getForegroundWindow() = formHandle then
return true;
endif;
// That didn't work so try setting foregroundLockTimeout to zero
call getSystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, saveTimeout, 0);
if saveTimeout <> 0 then
call setSystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_SENDCHANGE);
call bringWindowToTop(formHandle);
call setForegroundWindow(formHandle);
call setSystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, saveTimeout, SPIF_SENDCHANGE);
if call getForegroundWindow() = formHandle then
return true;
endif;
endif;
// That didn't work so, as a last resort, try the attach thread method
if process.getOSPlatform(versionOS, archOS) = Node.OSWindowsEnterprise then
// May be able to relax this restriction and use on any OS. Will need testing
// Tested for W2K and NT
foregroundThreadId := call getWindowThreadProcessId(call getForegroundWindow(), 0);
formThreadId := call getWindowThreadProcessId(formHandle, 0);
if call attachThreadInput(formThreadId, foregroundThreadId, TRUE) <> 0 then // successfully attached
call bringWindowToTop(formHandle);
call setForegroundWindow(formHandle);
call attachThreadInput(formThreadId, foregroundThreadId, FALSE); // hopefully detached
endif;
endif;
return call getForegroundWindow() = formHandle;
end;

Cheers, Brendan

Re: Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by jcampbell >> Thu, 12 Jun 2003 1:16:36 GMT

Seems like an awful lot of work when

SetForegroundWindow( hwnd ) ;
SetActiveWindow( hwnd ) ;
SetFocus( hwnd ) ;
ShowWindow( hwnd, SW_RESTORE);

should achieve the desired result. So all you should have to do is to provide wrappers for these in jade as per the way Brendan has done below and use this.

You can actually use things like EnumWindows to find any window and then cause it to become 'active'.

Re: Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by michaelj >> Thu, 12 Jun 2003 8:39:24 GMT

Brendan,
Is it only a particular configuration of W2K this does not work on? It just it seems to be working fine here and we develop and test solely on W2K.

Thanks
MJ

Re: Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by michaelj >> Thu, 12 Jun 2003 9:15:04 GMT

p.s. We are only displaying a message box and
- do not want to return focus to the main app afterwards.
- If the user is actively interacting with the window i.e dragging and droppping or windows menu expanded.. etc then the message box window should not force itself into focus, that is rude and damn annoying...

Re: Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by brendan1 >> Thu, 12 Jun 2003 9:49:28 GMT

Michael,

Yes, it does depend on the configuration.

In the Windows registry (on W2K at least), the key HKEY_USERS/.DEFAULT/Control Panel/Desktop/ForegroundLockTimeout is the deciding factor. If this is zero then the straightforward approach both you and John mentioned will work. However, if this is non-zero it won't.

The calls to setSystemParametersInfo etc are an attempt to change this setting to zero temporarily to allow the switch. However, Microsoft then clamped down on that in subsequent releases of W2K and 98 and the only way round the problem after that (that I could find on the newsgroups at any rate) was to make use of the fact that the currently active thread WAS allowed to switch to the top window. This is what attachThreadInput is doing, though it is a pretty horrible way round this problem.

I agree with John that it is a lot of work but Microsoft have put a lot of effort into not allowing an app to force its way to being the top window. Most of the time this is a reasonable restriction but there are times when it is useful.

Cheers, Brendan

Re: Setting focus to a window

Posted: Fri Aug 07, 2009 2:43 pm
by ConvertFromOldNGs
by michaelj >> Thu, 12 Jun 2003 14:00:45 GMT

Okay, I have checked that against our local settings. From what you have written and documentation ive managed to find (attached below ), I would expect it not to work on our system. However for some strange reason it does.

Perhaps this limitation only applies to old windows? We are creating a new message box and displaying that.

Thanks for the feedback, I'll definitely have to revisit that code when I next get the chance.
MJ



--------------------------------------------------------------------------- ----------------
When a window that doesn't have the focus (in the background) is updated by its program, Win2K by default prevents it from becoming the topmost window. Instead it flashes the taskbar button. This is governed by these DWORD [REG_DWORD] Values:


ForegroundLockTimeout :
Value 200000 [Decimal]: background window not allowed to grab the focus (default behaviour).
Value 0 [Decimal or DWORD]: allows the background window to grab the focus (become topmost/foreground).