I'm having focus problems with my application in Delphi. It's complicated and uses Word_TLB, which is where the problem form is launched from. It's mainly a problem on PC's running Office 2003 for some reason and barely affects PC's running Office 2000.
I try to set focus on modal forms, as Delphi doesn't always set focus to them correctly for some reason. Sometimes it just keeps focus on the main application, which won't respond as it's waiting for the modal form to close. The only way to get focus onto the modal window is to alt+tab round a few times until the child window gains focus.
I have tried various solutions including one which tries various methods depending on which file is in the root, it tries this every 1.5 seconds:
procedure TSenWPFileNameFrm.Timer1Ti
mer(Sender
: TObject);
begin
If ((Application.Active)or(m_
shown<2)) then
begin
Inc(m_shown);
If FileExists('c:\focus.a') then
begin
SetForegroundWindow(handle
);
SetActiveWindow(handle);
Invalidate;
end
Else
begin
If FileExists('c:\focus.b') then
begin
Application.BringToFront;
end
Else
begin
If FileExists('c:\focus.c') then
Self.SetFocusOnForm
Else
if GetForegroundWindow<>Self.
handle then
ForceForegroundWindow(Self
.handle);
end;
end;
end;
end;
function ForceForegroundWindow(hwnd
: THandle): boolean;
const
SPI_GETFOREGROUNDLOCKTIMEO
UT = $2000;
SPI_SETFOREGROUNDLOCKTIMEO
UT = $2001;
var
ForegroundThreadID: DWORD;
ThisThreadID : DWORD;
timeout : DWORD;
begin
if IsIconic(hwnd) then ShowWindow(hwnd, SW_RESTORE);
if GetForegroundWindow = hwnd then Result := true
else begin
// Windows 98/2000 doesn't want to foreground a window when some other
// window has keyboard focus
if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion > 4))
or
((Win32Platform = VER_PLATFORM_WIN32_WINDOWS
) and
((Win32MajorVersion > 4) or ((Win32MajorVersion = 4) and
(Win32MinorVersion > 0)))) then
begin
// Code from Karl E. Peterson,
www.mvps.org/vb/sample.htm
// Converted to Delphi by Ray Lischner
// Published in The Delphi Magazine 55, page 16
Result := false;
ForegroundThreadID :=
GetWindowThreadProcessID(G
etForegrou
ndWindow,n
il);
ThisThreadID := GetWindowThreadPRocessId(h
wnd,nil);
if AttachThreadInput(ThisThre
adID, ForegroundThreadID, true) then
begin
BringWindowToTop(hwnd); // IE 5.5 related hack
SetForegroundWindow(hwnd);
AttachThreadInput(ThisThre
adID, ForegroundThreadID, false);
Result := (GetForegroundWindow = hwnd);
end;
if not Result then begin
// Code by Daniel P. Stasinski
SystemParametersInfo(SPI_G
ETFOREGROU
NDLOCKTIME
OUT, 0, @timeout, 0);
SystemParametersInfo(SPI_S
ETFOREGROU
NDLOCKTIME
OUT, 0, TObject(0),
SPIF_SENDCHANGE);
BringWindowToTop(hwnd); // IE 5.5 related hack
SetForegroundWindow(hWnd);
SystemParametersInfo(SPI_S
ETFOREGROU
NDLOCKTIME
OUT, 0,
TObject(timeout), SPIF_SENDCHANGE);
end;
end
else begin
BringWindowToTop(hwnd); // IE 5.5 related hack
SetForegroundWindow(hwnd);
end;
Result := (GetForegroundWindow = hwnd);
end;
end; { ForceForegroundWindow }
Any help would be greatly appreciated. Thanks.
We also had some problems with forums showing behind main window. But we solved that with calling someform.BringToFront.
And another problem we had was when showing some messages. We solved that with use of following routines.
Procedure msgError (Const S: String);
begin
Application.NormalizeAllTo
Application.MessageBox ( PChar ( S ) , PChar ('Error') , mb_OK Or mb_IconError ) ;
Application.RestoreTopMost
// DebugLog.Writeln ( '' , S ) ;
end;
Procedure msgWarOK (Const S: String);
begin
Application.NormalizeAllTo
Application.MessageBox ( PChar ( S ) , PChar ('Warning'), mb_OK Or mb_IconWarning ) ;
Application.RestoreTopMost
end;
Procedure msgWarOK (Const S, Caption: String);
begin
Application.NormalizeAllTo
Application.MessageBox ( PChar ( S ) , PChar (Caption), mb_OK Or mb_IconWarning ) ;
Application.RestoreTopMost
end;
function msgWarYN ( Const S : String ) : Boolean;
begin
Application.NormalizeAllTo
Result := Application.MessageBox ( PChar ( S ) , 'Warning' , mb_YesNo Or mb_IconWarning ) = id_Yes ;
Application.RestoreTopMost
end;
function msgWarYN ( Const S, Caption : String; Options: Integer = 0) : Boolean;
begin
Application.NormalizeAllTo
Result := Application.MessageBox ( PChar (S) , PChar (Caption), mb_YesNo Or mb_IconWarning Or Options ) = id_Yes ;
Application.RestoreTopMost
end;
function msgWarYNC (Const S: String) : Integer;
begin
Application.NormalizeAllTo
Result := Application.MessageBox ( PChar (S) , 'Warning', mb_YesNoCancel Or mb_IconWarning);
Application.RestoreTopMost
end;
function msgWarYNC (Const S, Caption: String) : Integer;
begin
Application.NormalizeAllTo
Result := Application.MessageBox ( PChar (S) , PChar (Caption), mb_YesNoCancel Or mb_IconWarning);
Application.RestoreTopMost
end;
Maybe this will help you with your problem.
Regards Aleš