Lazarus

Programming => General => Topic started by: boreas on July 23, 2015, 09:41:29 am

Title: How can i run application in the panel ?
Post by: boreas on July 23, 2015, 09:41:29 am
Hi,
i work a os. project. I wantto add application in my project like a plugin. I search into plugin directory and add button for all aplication that in the directory. It's ok from here. But i coudn't run application in the panel. Application can write any programming language, os is linux and windows. So how can i do that :)

Sorry for my bad english.
Title: Re: How can i run application in the panel ?
Post by: Zoran on July 23, 2015, 10:11:09 am
If I understand what you want, you expect your panel to behave like desktop enviroment and host a graphical application? I do not believe that it is possible.
However, you can start the application and comunicate with it - see http://wiki.freepascal.org/Executing_External_Programs#TProcess
Title: Re: How can i run application in the panel ?
Post by: boreas on July 23, 2015, 10:19:24 am
Thank u for answer. I saw that page and i can communicate application. I can do with dll that i want but anybody dont want write to dll this is hard way. Actually if i can run external pascal script may be i can set parent to my panel ?
Title: Re: How can i run application in the panel ?
Post by: rvk on July 23, 2015, 10:43:27 am
If I understand what you want, you expect your panel to behave like desktop enviroment and host a graphical application? I do not believe that it is possible.
However, you can start the application and comunicate with it - see http://wiki.freepascal.org/Executing_External_Programs#TProcess
It is possible. (for Windows OS at least)

Look at the following video: https://www.youtube.com/watch?v=N6GWgxEvibE
You just have to use SetParent to attach the window-handle to another control.

You can also find an example here:
http://www.lazarusforum.de/viewtopic.php?f=10&t=3256

I tried to create an example. The only problem I had was getting the correct handle from the Calculator-window. It seems the handle TProcess returns is not the correct one. So I had to do FindWindow to find the window with the title Calculator and attach that to the panel.

Code: [Select]
uses Process, Windows;

// https://www.youtube.com/watch?v=N6GWgxEvibE
// http://www.lazarusforum.de/viewtopic.php?f=10&t=3256

procedure TForm1.Button1Click(Sender: TObject);

  function FindWindowByTitle(WindowTitle: string): Hwnd;
  var
    NextHandle: Hwnd;
    NextTitle: array[0..260] of char;
  begin
    // Get the first window
    NextHandle := GetWindow(Application.Mainform.Handle, GW_HWNDFIRST);
    while NextHandle > 0 do
    begin
      // retrieve its text
      GetWindowText(NextHandle, NextTitle, 255);
      if Pos(WindowTitle, StrPas(NextTitle)) <> 0 then
      begin
        Result := NextHandle;
        Exit;
      end
      else
        // Get the next window
        NextHandle := GetWindow(NextHandle, GW_HWNDNEXT);
    end;
    Result := 0;
  end;

  procedure Attach2Control(aWnd: Hwnd; aControl: TWinControl);
  var
    WPM: WINDOWPLACEMENT;
  begin
    Windows.SetParent(aWnd, aControl.Handle);
    SetWindowLong(aWnd, GWL_STYLE, GetWindowLong(aWnd, GWL_STYLE) and not WS_CAPTION);
    WPM.Length := SizeOf(WPM);
    GetWindowPlacement(aWnd, @WPM);
    WPM.ShowCmd := SW_ShowMaximized;
    WPM.rcNormalPosition := Classes.Rect(0, 0, aControl.Width, aControl.Height);
    SetWindowPlacement(aWnd, @WPM);
  end;

var
  xWnd: HWND;
  aProcess: TProcess;
begin

  aProcess := TProcess.Create(nil);
  aProcess.CommandLine := 'calc.exe';
  aProcess.Options := aProcess.Options - [poWaitOnExit];
  aProcess.Execute;

  Sleep(100);
  xWnd := FindWindowByTitle('Calculator');
  Attach2Control(xWnd, Panel1);

  aProcess.Free;

end;
(screenshot attached)

If you leave the windowplacement and SetWindowLong lines out, and just only leave the SetParent-line you can even keep the title-bar as in screenshot #2.
Code: [Select]
    Windows.SetParent(aWnd, aControl.Handle);
    //SetWindowLong(aWnd, GWL_STYLE, GetWindowLong(aWnd, GWL_STYLE) and not WS_CAPTION);
    //WPM.Length := SizeOf(WPM);
    //GetWindowPlacement(aWnd, @WPM);
    //WPM.ShowCmd := SW_ShowMaximized;
    //WPM.rcNormalPosition := Classes.Rect(0, 0, aControl.Width, aControl.Height);
    //SetWindowPlacement(aWnd, @WPM);
(But then it could be that your application is "out of sight" so you need to maximize your panel to see it and drag it back in sight)

Title: Re: How can i run application in the panel ?
Post by: boreas on July 23, 2015, 10:56:20 am
Ok. Perffect example :) I'll try that. But my guess its not work on linux  only windows.  True ?
Title: Re: How can i run application in the panel ?
Post by: rvk on July 23, 2015, 10:58:28 am
But my guess its not work on linux  only windows.  True ?
Well, Windows.SetParent is, of course, a Windows API call.

But maybe there is something similar for Linux.
(I'm not an expert on Linux, yet :))

Maybe something like gdk_window_reparent_ (http://www.purebasic.fr/english/viewtopic.php?f=12&t=49558) ??
Title: Re: How can i run application in the panel ?
Post by: boreas on July 23, 2015, 11:03:24 am
Thnk u so much. Again :) If i found resolve for linux, i ll share here :)
Title: Re: How can i run application in the panel ?
Post by: rvk on July 23, 2015, 11:03:54 am
Maybe SetParent even works on Linux???
It's implemented in TQtWidgetSet.SetParent.
Title: Re: How can i run application in the panel ?
Post by: boreas on July 23, 2015, 11:14:03 am
I think it's change according to widget set. QT,gtk, wx or tk. But maybe i do block windows manager, maybe i can enter between xwindow and application. I will try that.
Title: Re: How can i run application in the panel ?
Post by: Moombas on May 13, 2022, 03:11:40 pm
Hi,
is there a way to do that still?
Tryied the code above but didn't worked. The program (even tried with calc.exe) is just opened and not put into the panel. Also i would prefer to do it via shellexecute instead of process because maybe i need to provide some parameters.

Ps.: Yes i know that the thread is very old but it's exactly the topic i look for.
I found a way now which works (tested on W10):

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   Rec: TShellExecuteInfo;
  4.   fNotepadHandle : HWND;
  5.   WPM: WINDOWPLACEMENT;
  6. const
  7.   AVerb = 'open';
  8.   AParams = '';
  9.   AFileName = 'Notepad.exe';
  10.   ADir = '';
  11. begin
  12.   FillChar(Rec, SizeOf(Rec), #0);
  13.  
  14.   Rec.cbSize       := SizeOf(Rec);
  15.   Rec.fMask        := SEE_MASK_NOCLOSEPROCESS;
  16.   Rec.lpVerb       := PChar( AVerb );
  17.   Rec.lpFile       := PChar( AfileName );
  18.   Rec.lpParameters := PChar( AParams );
  19.   Rec.lpDirectory  := PChar( Adir );
  20.   Rec.nShow        := SW_HIDE;
  21.  
  22.   ShellExecuteExA(@Rec);
  23.   WaitForInputIdle(Rec.hProcess, 5000);
  24.  
  25.   fNotepadHandle := Windows.FindWindow( 'Notepad', nil );
  26.   Windows.SetParent( fNotepadHandle, Panel1.Handle );
  27.   SetWindowLong(fNotepadHandle, GWL_STYLE, GetWindowLong(fNotepadHandle, GWL_STYLE) and not WS_CAPTION);
  28.   WPM.Length := SizeOf(WPM);
  29.   GetWindowPlacement(fNotepadHandle, @WPM);
  30.   WPM.ShowCmd := SW_ShowMaximized;
  31.   WPM.rcNormalPosition := Classes.Rect(0, 0, Panel1.Width, Panel1.Height);
  32.   SetWindowPlacement(fNotepadHandle, @WPM);
  33.  
  34.   Resize;
  35.   ShowWindow(fNotepadHandle, SW_SHOW);
  36. end;
Title: Re: How can i run application in the panel ?
Post by: Moombas on May 17, 2022, 08:13:57 am
Even it works with Notepad for example, some other applications seem not be able to be catched.
Someone here who can explain me why this could be possible?
Title: Re: How can i run application in the panel ?
Post by: rvk on May 17, 2022, 08:22:38 am
Even it works with Notepad for example, some other applications seem not be able to be catched.
Someone here who can explain me why this could be possible?
Could be that that application creates multiple windows of which you only catch the (hidden) main one. Hard to tell without knowing the application.

Try to use a Window spy program (like the one which comes with AutoHotkey) to see if you can find more windows and examine their properties.
Title: Re: How can i run application in the panel ?
Post by: Moombas on May 17, 2022, 10:13:09 am
Hi rvk,

i tried with WinBox which is a management tool for Mikrotik routers.
I can see the program in the taskmanager assigned to my test program but it's not visible in the panel.

You can find it here: https://mikrotik.com/download
Title: Re: How can i run application in the panel ?
Post by: rvk on May 17, 2022, 02:42:57 pm
Maybe it's some timing issue because the code below works fine.
(note I used the classname of the window, not the window-name)

Without the showmessage delay I get a flickering window and it disappears.
A myDelay of 1000 ms works too BTW.
So, the WaitForInputIdle() is too soon for this program.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   Rec: TShellExecuteInfo;
  4.   fHandle: HWND;
  5. const
  6.   AVerb = 'open';
  7.   AParams = '';
  8.   AFileName = ' path to exe \winbox64.exe';
  9.   ADir = '';
  10.   wndClass = 'routeros_connect';
  11. begin
  12.  
  13.   fHandle := FindWindow(pChar(wndClass), nil);
  14.   if fHandle <> 0 then
  15.   begin
  16.     ShowMessage('We found a window already, kill it first');
  17.     exit;
  18.   end;
  19.  
  20.   FillChar(Rec, SizeOf(Rec), #0);
  21.   Rec.cbSize := SizeOf(Rec);
  22.   Rec.fMask := SEE_MASK_NOCLOSEPROCESS;
  23.   Rec.lpVerb := PChar(AVerb);
  24.   Rec.lpFile := PChar(AfileName);
  25.   Rec.lpParameters := PChar(AParams);
  26.   Rec.lpDirectory := PChar(Adir);
  27.   Rec.nShow := SW_HIDE;
  28.  
  29.   if not ShellExecuteExA(@Rec) then;
  30.   WaitForInputIdle(Rec.hProcess, 5000);
  31.  
  32.   ShowMessage('Wait 1 second and press Ok');
  33.   // myDelay(1000); // works too
  34.  
  35.   fHandle := FindWindow(pChar(wndClass), nil);
  36.   if fHandle <> 0 then
  37.   begin
  38.     Windows.SetParent(fHandle, Panel1.Handle);
  39.     SendMessage(fHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0); // you can change this back to your own code
  40.   end
  41.   else
  42.     ShowMessage('Window not found');
  43.  
  44. end;
Title: Re: How can i run application in the panel ?
Post by: Moombas on May 18, 2022, 08:14:42 am
Thanks, the delay did it.  8-)
How did you get the classname? I was searching for that but maybe i searched for the wrong thing
Title: Re: How can i run application in the panel ?
Post by: rvk on May 18, 2022, 08:26:25 am
How did you get the classname?
Like I said earlier, with a Windows spy program.

I used WinSpy.
https://www.autohotkey.com/boards/viewtopic.php?f=6&t=28220
Title: Re: How can i run application in the panel ?
Post by: Moombas on May 18, 2022, 10:25:09 am
Ah, sorry missed that.
Hmm, it seem that all Lazarus Programs have "Window" as class name, is there a (easy) way to change that for the own program?
Title: Re: How can i run application in the panel ?
Post by: SymbolicFrank on May 18, 2022, 10:30:57 am
You can enumerate them as well, with the following functions (in unit Windows):

Code: Pascal  [Select][+][-]
  1. function EnumWindows(lpEnumFunc:ENUMWINDOWSPROC; lParam:LPARAM):WINBOOL; external 'user32' name 'EnumWindows';
  2. function GetWindowThreadProcessId(hWnd:HWND; lpdwProcessId:LPDWORD):DWORD; external 'user32' name 'GetWindowThreadProcessId';
  3.  
Title: Re: How can i run application in the panel ?
Post by: rvk on May 18, 2022, 10:50:55 am
Hmm, it seem that all Lazarus Programs have "Window" as class name, is there a (easy) way to change that for the own program?
Yes, Lazarus always uses "Window" as Class Name

(In Delphi it does have the same Class Name you used in your code)

The discussion about that is here:
https://forum.lazarus.freepascal.org/index.php/topic,15941.0.html
Title: Re: How can i run application in the panel ?
Post by: Moombas on May 18, 2022, 03:37:13 pm
Thanks for that, I'll take a look which way i go now.
I don't have so many LAzarus-applications here where this could be interessting now.

And regarding the Winbox i got fucked up because when it's connecting to a device it opens a completely new window which then appears outside of the application with the panel...
Title: Re: How can i run application in the panel ?
Post by: rvk on May 18, 2022, 03:42:58 pm
And regarding the Winbox i got fucked up because when it's connecting to a device it opens a completely new window which then appears outside of the application with the panel...
Yeah, it's hard to contain program's that do that.

You could build in a timer which draws in every window with that classname.
If there are multiples you could put them in a TTabsheet for example.

And don't forget... if you end your program without closing the started app, the app will stay invisible in memory (so you would need to kill that too).
Title: Re: How can i run application in the panel ?
Post by: Moombas on May 19, 2022, 08:12:46 am
Yes, still noticed that and build in something to close the app (Form.Close/Form.Destroy/before i open an other Program).
Yeah a Timer could be a possible way to do that, I'll look out if maybe the classname is different or the same. But still a big thanks to you. I never would have tried just a simple "delay" to get it to work  %)
TinyPortal © 2005-2018