Jump to content
David Schwartz

How to make app with tabbed set of VNC windows

Recommended Posts

Not sure where this fits, but we have a dozen servers we connect to via VNC and I’d like to have them all stuffed into one tabbed window like multiple browser tabs, instead of a dozen separate VNC windows. Suggestions?

Share this post


Link to post

the app we're running is Microsoft's mstsc.exe that says it's Remote Desktop Connection.

 

EDIT: Ahh, it looks like the Terminals app you pointed to (that's been moved here: https://github.com/terminals-Origin/Terminals ) is exactly what I'm looking for:

 

  The project started from the need of controlling multiple connections simultaneously. It is a complete replacement for the mstsc.exe (Terminal Services) client.

 

I'm thinking I could build a simple tabbed form in Delphi that allows this to be embedded in each tab, or just find an app with a tabbed interface that already does it.

 

I searched Google and didn't find much about embedding apps into Delphi's panels or forms.

Edited by David Schwartz

Share this post


Link to post

Cross process UI is fraught with complications. I wouldn't dream of trying to parent a window from one process into another process. 

Share this post


Link to post

@David Schwartz

Have you guys tried https://remotedesktopmanager.com/ ? 

It is freaking awesome for managing a large server park!  We have literally hundreds of servers and would be lost without it. 

 

It supports pretty much every remoting protocol you can think of: https://remotedesktopmanager.com/features/remote-connection-management
You can have the windows tabbed, cascaded, tiled vertically or horizontally.

You can lock the Windows hotkeys so that you have to use the mouse to get out of the context of the remote view. I.e. Alt-Tab happens within the focused remote connection.


There is a free version for personal use, but if you have a team, you want the enterprise version.

  • Like 1

Share this post


Link to post

If the need is simply parallel remote control like starting/stopping scripts/apps or services - you would do much better by using PowerShell.

Share this post


Link to post

hmm

I played with TightVNC as a test.
Get the window handle (FindwindowW (..)) from the VNC and then used the following:

 

var
  VNCHandle : HWND;

..

  VNCHandle := FindwindowW(nil, PWideChar(WindowCaption));

  if VNCHandle <> 0 then
  begin
    Windows.SetParent(VNCHandle,Panel1.Handle);

    WPM.Length:=SizeOf(WPM);
    GetWindowPlacement(VNCHandle,@WPM);
    Rect.Top :=0;
    Rect.Left :=0;
    Rect.Right :=Panel1.Width;
    Rect.Bottom:=Panel1.Height;
    wpm.rcNormalPosition:=Rect;
    SetWindowPlacement(VNCHandle,@WPM);
  end;

 

This shows the VNC window in the panel.
Do this several times, each with its own panel and you can then manipulate the panels with the VNC windows as you like.

  • Like 1

Share this post


Link to post
8 hours ago, Lars Fosdal said:

If the need is simply parallel remote control like starting/stopping scripts/apps or services - you would do much better by using PowerShell.

We need a GUI interface to interact with apps that run 24/7 inside of VMs.

Share this post


Link to post
14 hours ago, David Schwartz said:

We need a GUI interface to interact with apps that run 24/7 inside of VMs.

In that case, Remote Desktop Manager is the way to go.  

Share this post


Link to post

Would you like to watch it on multiple screens? Or.
If you want to run remote connection and remote script.


My projects.

https://www.deskgate.com/
There are 2 projects here, maybe someone can meet their needs.
Ask for the license issue. I grant free license to people on this site.

Share this post


Link to post
7 hours ago, Turan Can said:

Would you like to watch it on multiple screens? Or.
If you want to run remote connection and remote script.

 

Thanks,  but I'm just looking for a tabbed interface that collects them into one window instead of a dozen separate windows.

Share this post


Link to post

Back in the days when I was a sysadmin we chose mRemote and nothing served us better. The developement stopped but then was forked and continued as mRemoteNG.

At the end I just wrote my own tabbed application using TMsRDPClient9NotSafeForScripting for RDP, and for everything else launching the external application and docking it to the tabsheet.

 

I also expanded TPageControl with drag-and-drop rearrangement with tab picture, close buttons, middle-click tab closing and full VCL styling support for the above. Let me know if interested, I can share the code.

Share this post


Link to post

it would be fun to play with and see what you did, if nothing else. 🙂

 

I did find something called Terminals, but found it really clunky and glitchy.

 

Not to mention, some of these are on VMs running WinXP in a smaller console window, while some are on the other end of the spectrum with Win10 on an HD-size console. 

 

Not sure what can be done about that if they're all running inside a window with the same dimensions for all consoles. Of course, RDP scales to the console size that's needed.

Share this post


Link to post

Docking is easy. _puttyhandle is a THandle, value comes from FindWindow. _owner should be a TWinControl, where you want your external application to be docked. I docked Putty, but Notepad also works fine 🙂

procedure TSSHConnection.Dock;
var
 WindowStyle : Integer;
 FAppThreadID: Cardinal;
begin
 WindowStyle := GetWindowLong(_puttyhandle, GWL_STYLE);
 WindowStyle := WindowStyle - WS_CAPTION - WS_BORDER - WS_OVERLAPPED - WS_THICKFRAME;
 SetWindowLong(_puttyhandle,GWL_STYLE,WindowStyle);

 /// Attach container app input thread to the running app input thread, so that the running app receives user input.
 FAppThreadID := GetWindowThreadProcessId(_puttyhandle, nil);
 AttachThreadInput(GetCurrentThreadId, FAppThreadID, True);

 /// Changing parent of the running app to our provided container control
 Windows.SetParent(_puttyhandle, TWinControl(_owner).Handle);
 SendMessage(TWinControl(_owner).Handle, WM_UPDATEUISTATE, UIS_INITIALIZE, 0);
 UpdateWindow(_puttyhandle);

 /// This prevents the parent control to redraw on the area of its child windows (the running app)
 SetWindowLong(TWinControl(_owner).Handle, GWL_STYLE, GetWindowLong(TWinControl(_owner).Handle,GWL_STYLE) or WS_CLIPCHILDREN);

 /// Make the running app to fill all the client area of the container

 SetWindowPos(_puttyhandle,0,0,0,TWinControl(_owner).ClientWidth,TWinControl(_owner).ClientHeight,SWP_NOZORDER);
// SetForegroundWindow(WindowHandle);
// SetFocus(WindowHandle);
end;

Importing MSTSCAX as a VCL component is tricky, but I found a solution a couple of years ago which still works. I don't have the link anymore, so I don't know who to credit for it 😞

- Component -> Import Component -> Import ActiveX Control -> Select Terminal Services (mstscax.dll)
- Palette page: MsTSC, unit dir name: Delphi Lib folder, Search path: empty. Check Generate component wrappers
- Install to New package
- Enter the same name (MsTSCLib_TLB.dproj) under Delphi Lib folder
- Try to build package just to fail
- Change Property type of ConnectWithEndpoint to "OleVariant", build package again
- Right-click on MsTSCLib_TLB.bpl in Project manager and select "Install"

 

As for the modified PageControl, you can check it out at https://www.aecentral.org/index.php?post/35. Idk why I used a global variable as the OnClose event... feel free to change it, you can even add a Register procedure to have a VCL component.

Share this post


Link to post
16 hours ago, David Heffernan said:

Nope. It's an HWND. A THandle is quite different. 

 

Also, https://devblogs.microsoft.com/oldnewthing/20130412-00/?p=4683

Hmm, seems I messed up the declarations all along:

 TSSHConnection = Class(TConnection)
 strict private
  _puttyhandle: THandle;

At the end of the day Delphi considers them the same, this is why my code works:

WinApi.Windows.THandle = System.THandle = System.NativeUInt

WinApi.Windows.HWND = WinApi.Windows.UINT_PTR = System.UIntPtr = System.NativeUInt

 

I'll correct it anyway 🙂 Thanks for the heads-up!

Share this post


Link to post

It makes no difference to the operation of the code, its just worth being aware of the difference between THandle, which is a handle to a kernel object, and HWND which is a window handle. The Delphi rtl has been a little sloppy over the years distinguishing different handle types so it's not surprising that some of the rubs off. 

Share this post


Link to post

Isn't window a kernel object?

THandle is generic indeed, WinAPI has different typedefs for each object. OTOH, using WinAPI typedefs means sticking to Win platform only, which is less actual now as language becomes x-platform

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×