Recent

Author Topic: Making Windows Screen come to the front.  (Read 8059 times)

dsr100

  • New Member
  • *
  • Posts: 17
Making Windows Screen come to the front.
« on: October 24, 2017, 04:08:50 am »
I have a lazarus app that works perfectly when run from the IDE, when it detects a clipboard change, it does a  bring to front windows call on a third party windows exe by handle and brings it to the front.
When NOT running my app from the IDE, it does NOT bring the other window to the front.
Now I will post my code etc here but the first and obvious question, the IDE builds and compiles and then runs the EXE, how does that produce a different result from running the EXE alone?
I tried a sleep(100) before and after, application.processmessages before and after.
This sort of anomaly has come up before.... in unrelated functions...
So before we get to what my code call looks like and etc... yeah, that's the question, how is ME running the exe different to the IDE running it?

balazsszekely

  • Guest
Re: Making Windows Screen come to the front.
« Reply #1 on: October 24, 2017, 06:43:50 am »
By "bring to front" you mean receive input focus or change the z order of the window(foreground/background)? There is a slight difference, namely a window may be on top without currently getting input focus. With windows7+(at least in theory) you cannot steal input focus, in other words window A can only give window B input focus if window A already has input focus.
If you know the handle of the window, just send a message(SendMessage/PostMessage), upon receive just set the FormStyle to fsSystemStayOnTop then back to fsNormal. This will give the impression that window came to the foreground. Alternatively you can use the SetWindowPos api like this:
Code: Pascal  [Select][+][-]
  1. SetWindowPos(wHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
If you also want the window to get input focus do the following:
1. Make sure window is on top(see above)
2. Get the windows position/size with GetWindowRect
3. Click the window title using LazMouseAndKeyboard package, unit MouseAndKeyInput, method: MouseInput.Click(...)

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #2 on: October 24, 2017, 12:08:24 pm »
Firstly, thank you for the reply and detail.
Yes, I am doing just as you outline... and when I launch my app from the IDE.... it DOES bring the target window to the front... as expected. It works perfect, time and time again.
If I then close the IDE and double click the exe, it does NOT bring the target window to the front.
The question was why/how that could be different>?
This is NOT a once off... running my app from the IDE, it works, running the exe it does not... (just this part ALL the rest of the app is normal)
I thank you for your answer though!
kind regards
DavidR

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #3 on: October 24, 2017, 12:12:42 pm »
The code that I am using if that helps in this.
Again to note though, this works perfectly and consistantly when the app is run from the IDE, but double clicking the exe it does not...

I apologise in advance, parts of this are from a couple of years ago and I don't know whom to credit for some of it...

{bring "some window caption" to the front}

JD := FindWindowExtd('some window caption');
BringWindowToTop(JD);
SetForegroundWindow(JD);
SetWindowPos(JD, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOACTIVATE);
application.processmessages;     



function FindWindowExtd(partialTitle: string): HWND;
var
  hWndTemp: hWnd;
  iLenText: Integer;
  cTitletemp: array [0..254] of Char;
  sTitleTemp: string;
begin
  hWndTemp := FindWindow(nil, nil);
  while hWndTemp <> 0 do begin
    iLenText := GetWindowText(hWndTemp, cTitletemp, 255);
    sTitleTemp := cTitletemp;
    sTitleTemp := UpperCase(copy( sTitleTemp, 1, iLenText));
    partialTitle := UpperCase(partialTitle);
    if pos( partialTitle, sTitleTemp ) <> 0 then
      Break;
    hWndTemp := GetWindow(hWndTemp, GW_HWNDNEXT);
  end;
  result := hWndTemp;
end;   

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #4 on: October 24, 2017, 12:16:55 pm »
Does this help???
If I open the IDE and then compile build the app, it launches and works PERFECTLY!
ok so leaving the app running if I close the IDE, the app suddenly doesn't working (in this one particular way).
So that instance of the app, that WAS working, suddenly stops working then the IDE is closed.
Isn't that really peculiar?

balazsszekely

  • Guest
Re: Making Windows Screen come to the front.
« Reply #5 on: October 24, 2017, 12:19:46 pm »
Most likely the exe is blocked by AV. Disable AV or add the exe to the white list. If that does not help, please try the following code:
http://forum.lazarus.freepascal.org/index.php/topic,33618.msg218145.html#msg218145 (you have to adapt a little bit)

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #6 on: October 24, 2017, 12:31:27 pm »
Thank you for the thought... I disable the AV, same results.

I do note again... that when the IDE is open, the app works perfectly again and again and again and again.
IDE closed, the same instance of the same app, doesn't work properly at ALL.

But that you for the thought, I welcome all thoughts... I have no idea what could cause this effect.

 

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #7 on: October 24, 2017, 01:10:59 pm »
To make it seem stranger...
If I open the IDE, run the app... the app works PERFECTLY.
If I close the IDE LEAVING the app running... the app stops working (in this way).
With the same instance of the app running, if I open the IDE, it stays NOT working.

Isn't that odd... and getting odder the more I experiment...

balazsszekely

  • Guest
Re: Making Windows Screen come to the front.
« Reply #8 on: October 24, 2017, 01:20:37 pm »
Yes it is strange. I have no idea why your code works while debugging and not outside the IDE. Did you try my code? Please check the attached project:
1. Open notepad. You can even minimize it if you like
2. Start the project(with or without the IDE)
3. Click Button1

Now all you have to to is replace "notepad.exe" to "whateveryourprojectnameis.exe" in line 51.
Code: Pascal  [Select][+][-]
  1. uses LCLIntf, JwaWindows, jwatlhelp32, MouseAndKeyInput;
  2.  
  3. function FindProcessByName(const ProcName: string): DWORD;
  4. var
  5.   Proc: TPROCESSENTRY32W;
  6.   hSnap: HWND;
  7.   Looper: BOOL;
  8. begin
  9.   Result := 0;
  10.   Proc.dwSize := SizeOf(Proc);
  11.   hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
  12.   Looper := Process32FirstW(hSnap, Proc);
  13.   while Integer(Looper) <> 0 do
  14.   begin
  15.     if UpperCase(ExtractFileName(string(proc.szExeFile))) = UpperCase(ProcName) then
  16.     begin
  17.       Result:=proc.th32ProcessID;
  18.       Break;
  19.     end;
  20.     Looper := Process32NextW(hSnap, Proc);
  21.   end;
  22.   CloseHandle(hSnap);
  23. end;
  24.  
  25. function GetProcessMainWindow(const PID: DWORD; const wFirstHandle: HWND): HWND;
  26. var
  27.   wHandle: HWND;
  28.   ProcID: DWord;
  29. begin
  30.   Result := 0;
  31.   wHandle := GetWindow(wFirstHandle, GW_HWNDFIRST);
  32.   while wHandle > 0 do
  33.   begin
  34.     GetWindowThreadProcessID(wHandle, @ProcID);
  35.     if (ProcID = PID) and (IsWindowVisible(wHandle)) then
  36.     begin
  37.       Result := wHandle;
  38.       Break;
  39.     end;
  40.     wHandle := GetWindow(wHandle, GW_HWNDNEXT);
  41.   end;
  42. end;
  43.  
  44. procedure TForm1.Button1Click(Sender: TObject);
  45. var
  46.   PID: DWord;
  47.   wHandle: THandle;
  48.   R: TRect;
  49.   P: TPoint;
  50. begin
  51.   PID := FindProcessByName('notepad.exe');
  52.   if PID > 0 then
  53.   begin
  54.     wHandle := GetProcessMainWindow(PID, Self.Handle);
  55.     if wHandle > 0 then
  56.     begin
  57.       ShowWindow(wHandle, SW_SHOWDEFAULT);
  58.       SetWindowPos(wHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);
  59.       GetWindowRect(wHandle, R);
  60.       P.x := R.Left + 50;
  61.       P.Y := R.Top + 10;
  62.       MouseInput.Click(mbLeft, [], P.x, P.y);
  63.     end;
  64.   end;
  65. end;

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #9 on: October 24, 2017, 10:59:34 pm »
good morning, I first wanted to say, wow, thanks so much for ALL the effort... wow! How VERY kind.

I think the comment you said, yes, my app executes differently when in debug run mode, than normal.

It will take me a little while to integrate your code into my app and test and advise, but I wanted to say thank you asap. Secondly, your app works on my computer under IDE debug and normally. So your example is normal.

I hadn't added a further complexity until now, as I was focused on the question, WHY is debug mode different to normal execution. Anyway... much as you have, to first try to come to grips with this anomaly, I shifted my bring to front code to a button press which works, then in the two trigger zones, I just put button.click. In debug works, in native exe it doesn't. Please know that I checked the onclick event occurs... like put a showmessage in there....

So to be clearer... in debug mode in my app press the bring notepad to the front button, notepad jumps to the front. Have an event that triggers the bring notepad to the front button, note pad jumps to the front.
Now run the app normally,  press the bring notepad to the front button, notepad jumps to the front. Have an event that triggers the bring notepad to the front button, note pad DOES NOT jump to the front.

Only other thing to note, I have those couple of IDE changes to make exe small, other than that IDE and compiler etc are stock settings.

Anyway, thank you so much for your help and listening, your code is BETTER and moves the mouse to the zone which is neat. So I will move your code to a button event and test and advise.


Thank you so much for your kind efforts so far!!!!   Fingers crossed.


dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #10 on: October 25, 2017, 12:06:29 am »
In trying to incorporate your kind suggestion I've hit a beginners snag.
In adding JwaWindows it creates a compile error "  Error: Incomatible type for arg no.2: Got "TPoint", expected "tagPOINT" "
in other sections of code, I have mouse over awareness in my code already.

I am asking as I wonder if this Jedi unit is more option explicit and is highlighting weaknesses in my code that could contribute to the observed error....

This is an example of existing code that works normally, but with the jwawindows use produces that error... in the p variable. Error: Incomatible type for arg no.2: Got "TPoint", expected "tagPOINT" "

function IsCoordinateOverControl(screenCoordinate: TPoint; control: TControl): Boolean;
var
p: TPoint;
  r: TRect;
begin
  Result := False;
  p := control.ScreenToClient(screenCoordinate);
  r := classes.Rect(0, 0, control.Width, control.Height);
  if PtInRect(r, p) then
    Result := True;
end;

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #11 on: October 25, 2017, 01:44:51 am »
SO I thought I would press on, perhaps adding the mouse click event would help, in case my program pulled a window to the front and it disappeared to the back to quick for the eye to see.

SO I added, just the mouse click part. I added lazmouseandkeyinput into the project inspector and added, the (simplied)
mouseinput.click (mbleft, [], 100,100);
I get an error similar to the other,
Error: Incompatible type for arg no.1: Got "Tmousebtntype, expected "Tmousebutton"

Interestingly I stripped your example to just adding the uses mouseandkeyinput and this one action and it works.
Adding just the uses and action to a fresh button on my app does not.

I assume, just as I have a unit with conflicting variable definition and type for the same type in windows get handle calls, I too have the same conflict in a unit I am using for mouse/key stuff.

I am using, classes, sysutils, fileutils, strutils, forms, controls, graphics, dialogs, stdctrls, clipbrd, windows, messages, extctrls, shellcontrls, inifiles, shellapi, filectrl, msearch

As the program has quite a few other and varied functions etc...

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Making Windows Screen come to the front.
« Reply #12 on: October 25, 2017, 02:52:38 am »

Maybe I missed something but, looking at your original code it looks like you may have made a mistake ?

function FindWindowExtd(partialTitle: string): HWND;
var
  hWndTemp: hWnd;
  iLenText: Integer;
  cTitletemp: array [0..254] of Char;
  sTitleTemp: string;
begin
  hWndTemp := FindWindow(nil, nil);
  while hWndTemp <> 0 do begin
    iLenText := GetWindowText(hWndTemp, cTitletemp, 255);
    sTitleTemp := cTitletemp;
    sTitleTemp := UpperCase(copy( sTitleTemp, 1, iLenText));
    partialTitle := UpperCase(partialTitle);
    if pos( partialTitle, sTitleTemp ) <> 0 then    {<<< here, shouldn't you be testing for 0?}
      Break;
    hWndTemp := GetWindow(hWndTemp, GW_HWNDNEXT);
  end;
  result := hWndTemp;

---
 IF pos(partialTitle, aTitleTemp) = 0 Then ....

POS returns 0 if substring isn't found.
The only true wisdom is knowing you know nothing

dsr100

  • New Member
  • *
  • Posts: 17
Re: Making Windows Screen come to the front.
« Reply #13 on: October 25, 2017, 03:03:51 am »
lol.... ok, thank you, I'm sure your right.

I can't remember why I even did it that way, I know the exact title of the external app and indeed it comes straight to the front beautifully in debug mode.

It's always worth a look though, I should simply all that, as it's an UNneeded complexity...  I think it originally it was to cope with Ext Program V1.01 becoming Ext Program V1.02.

Shouldn't effect the outcome though should it.

Thank you all for your continued attention and fresh eyes do spot this odd little things!

balazsszekely

  • Guest
Re: Making Windows Screen come to the front.
« Reply #14 on: October 25, 2017, 05:38:46 am »
@dsr100

Quote
This is an example of existing code that works normally, but with the jwawindows use produces that error... in the p variable. Error: Incomatible type for arg no.2: Got "TPoint", expected "tagPOINT" "

function IsCoordinateOverControl(screenCoordinate: TPoint; control: TControl): Boolean;
var
p: TPoint;
  r: TRect;
begin
  Result := False;
  p := control.ScreenToClient(screenCoordinate);
  r := classes.Rect(0, 0, control.Width, control.Height);
  if PtInRect(r, p) then
    Result := True;
end;
Just change it to LCLIntf.PtInRect(r, p) and add LCLIntf to the uses clause. Please attach a simple, compilable project otherwise we just shoot in the dark. You should also specify your Lazarus/FPC version.

 

TinyPortal © 2005-2018