Click here to Skip to main content
11,412,516 members (70,691 online)
Click here to Skip to main content

Extending Microsoft's Terminal Services Client To Provide Seamless Windows

, 14 Apr 2005 GPL3
Rate this:
Please Sign up or sign in to vote.
An article that describes a possible approach to extending Microsoft's Terminal Services/Remote Desktop Client to use seamless windows.

Overview and Background

Microsoft's terminal services client (also called 'Remote Desktop Connection') has one main thing against it. Remote applications do not appear as if they are running on the local desktop, instead they appear in a separate window which represents the server's desktop. This is fine if you just want to work exclusively on the server, but can be a pain if you want to switch between applications on the server and the local desktop or want to run applications on different servers. What is needed is a way to display the remoted applications as 'Seamless Windows' on the client.

Commercial products have been written to achieve this in a Windows environment, the most well known would be Citrix. Citrix uses its own protocol (ICA) to publish applications to the client. Others have used Microsoft's protocol called RDP (Remote Desktop Protocol) with additional software to achieve the same effect (the most notable of these is Tarentalla's Canaveral IQ – I suspect they use a similar, but more sophisticated, method to the one presented in this article).

While these products provide a lot more than just seamless windows, they are also quite expensive. It would be nice to have this feature in a regular RDP client without having to buy a whole application publishing product.

This article provides a possible solution to this problem by extending Microsoft's RDP client using virtual channels to communicate between the server and the client. This option has been chosen over writing or extending an existing open source RDP client (such as rdesktop) because we will still be able to take advantage of all the features in Microsoft's client (and presumably all new features they add in the future). Also, an advantage to using Microsoft's client is that we can get some rudimentary application publishing over a web page since their terminal services client has an ActiveX component to do this.

Concept And Approach

Introduction

The RDP protocol does not provide any information about the open windows, all it does is send a bitmap of the server screen down to the client and route mouse and key presses back to the server. To make it appear that applications are running on the local machine, we need to 'clip' away the server desktop on the client.

To do this, it is quite obvious that we are going to need to know what windows are on the server and where they are. For this, we can use global hooks to find out what is happening in the server session (windows opening, closing, minimizing etc.). Next, we need to communicate this information back to the client, this is where virtual channels come in. They are Microsoft's mechanism for two way communication between a server and client when a terminal services session is open. They are mainly used for transferring files and printing but we can use it to send window information back to the client. Once the client has this information, it can then use it to 'clip' the server desktop to just show the applications running on the server.

Hooking into Window Messages On The Server

At this point, I must give credit to Markus Rollmann. I have used his Code Project article as a basis to write this part of the software. This part of the application runs on the server and opens the server side of the virtual channel. To use global hooks, there is a separate DLL (called 'hookdll.dll'). This DLL monitors what is happening to the windows on the server and sends the appropriate string messages down the virtual channel which can then be interpreted by the client code.

An interesting thing I learnt here is that you can't get WH_SHELL notifications from global hooks if there is no registered shell. Normally, 'explorer.exe' is running as a shell, but in a terminal services session, you usually run just the application without the shell. To get round this (and it took me a long time to figure out why I wasn't getting these notifications), you need to register your application as the shell to replace 'explorer.exe' (see the code on how to do this).

Our application on the server ('clipper.exe') is now also our shell. When we launch our session from the client, we set the starting application as 'clipper.exe'. This ensures all the global hooks are setup before any applications are launched on the server. One of the parameters to 'clipper.exe' is the path of the application to start, which 'clipper.exe' launches as a new process. In addition, it will monitor this process so that when the process has exited, 'clipper.exe' can also close. This will then result in the session logging off as shell application has closed.

Responding to the messages on the client

Virtual channels work by having an executable on the server sending information back to the client. On the client side, there is a DLL that is loaded by the terminal services client when it loads which can listen for the information coming down the virtual channels ('TswindowClipper.dll' – this is loaded by setting a key ("Name" = "TSWindowClipper.dll") in the registry at: HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns\TSWindowClipper). Our client DLL code maintains a hashtable which contains the location of all the windows on the server and their state. The client DLL code is then able to calculate a region that matches the windows on the server and 'clip' the terminal services client window appropriately (the client DLL gets a handle to the terminal services client window when it starts). When windows are moved, resized, opened, closed, minimized or maximized on the server, a message gets sent to the client DLL which is then able to recalculate this region and clip the window accordingly. Another thing the client does is to create dummy taskbar items that represent the windows open on the server.

Publishing Applications On the Web

It is possible to launch a seamless terminal services session from a web page using the remote desktop ActiveX control. To do this, we need to tell it to use our client side Virtual channel DLL. This is how we do it:

MsRdpClient.SecuredSettings.StartProgram = "c:\tswinclipper\clipper.exe notepad.exe"
MsRdpClient.AdvancedSettings.PluginDlls = "tswindowclipper.dll"
MsRdpClient.FullScreen = TRUE
MsRdpClient.Width = screen.width
MsRdpClient.Height = screen.height

We need to set the 'StartProgram' to the correct path for 'clipper.exe' and the application we want to launch on the server. Here is an example HTML file (your will need to get the 'msrdp.cab' file for the ActiveX control from here and put it in the same directory as this HTML page):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>

<head>
<title>Remote Desktop Web Connection</title>
<meta content="JavaScript" name="vs_defaultClientScript">
</head>

<body>

<script language="vbscript">

sub BtnConnect

MsRdpClient.server = "<%YOUR SERVER%>"
MsRdpClient.UserName = "<%YOUR USERNAME%>"
MsRdpClient.AdvancedSettings.ClearTextPassword="<%YOUR PASSWORD%>"
MsRdpClient.Domain = "<%YOUR DOMAIN%>"

MsRdpClient.SecuredSettings.StartProgram = "c:\tswinclipper\clipper.exe notepad.exe"

MsRdpClient.AdvancedSettings.PluginDlls = "tswindowclipper.dll"

MsRdpClient.FullScreen = TRUE
MsRdpClient.Width = screen.width
MsRdpClient.Height = screen.height

'These 2 do not work from the activeX control

'MsRdpClient.AdvancedSettings2.DisplayConnectionBar = FALSE
'MsRdpClient.AdvancedSettings2.PinConnectionBar = TRUE

'Device redirection options

MsRdpClient.AdvancedSettings2.RedirectDrives = FALSE
MsRdpClient.AdvancedSettings2.RedirectPrinters = TRUE
MsRdpClient.AdvancedSettings2.RedirectPorts = FALSE
MsRdpClient.AdvancedSettings2.RedirectSmartCards = FALSE

'Connect

MsRdpClient.Connect

end sub

sub MsRdpClient_OnDisconnected(disconnectCode)

'goback to the page that called this one

history.go(-1)

end sub

</script>

<br>
<object language="vbscript" id="MsRdpClient" onreadystatechange="BtnConnect" 
        codebase="msrdp.cab#version=5,1,2600,1050" 
        classid="CLSID:9059f30f-4eb1-4bd2-9fdc-36f43a218f4a">
</object>
<br>

</body>
</html>

How To Install And Run

Here are the main things to do:

  1. Run 'setup.exe' on the server and client. Then run the terminal services client or remote desktop connection on the client.
  2. Resolution must be set to full screen and the connection bar must not be displayed.
  3. The start program shell must be the full path to 'clipper.exe' followed by one parameter which is the application on the server you want to launch seamlessly.
  4. 'Show contents of window while dragging' must be turned on in the connection setting, otherwise moving or sizing windows will not work.
  5. It is also important to note that the 'Show contents of window while dragging' also has to be enabled on the server as well.
  6. It is also a good idea to turn the desktop background off to save bandwidth, as we will be clipping the desktop anyway.

There is a PDF called 'windowclipper.pdf' that is installed with the client setup. Have a look at that if you have any problems.

Limitations

  • Certain types of windows are not clipped (DOS windows and child windows such as the open/save file dialogs are the most obvious). This is because I have not found a way to detect these windows using the global hooks.
  • Minimize and maximize hasn't been fully implemented.
  • Resolutions on the client screen have to be supported on the server (some resolutions exhibit the black bars on the left/right of the screen).
  • Connecting to a disconnected session will not restore the clipping since the data about the open windows was stored in the client's memory and is lost when the remote desktop client is closed.
  • Clicking on the dummy taskbar items does nothing (should sent a message back to the server, currently communication is only from the server to the client).

Acknowledgments

  • Global Hooks in Windows and system tray: Thanks to Markus Rollmann for this Code Project article and code.
  • Hash table in C++: Thanks to Jerry Coffin (hash.h, hash.cpp)
  • String help class in C++: Thanks to Joe O'Leary (StdString.h)
  • Tokenizer class in C++: Thanks to Eduardo Velasquez (Tokenizer.h, Tokenizer.cpp)

Revision History

  • 16/01/2005: Added version 1.0 of article.
  • 16/01/2005: Added version 0.3 of the source code and 'setup.exe'.
  • 14/04/2005: Added version 0.3.1 of the source code and '/setup.exe/'. Updated code ZIP file to contain empty 'build' folder for post build events (was missing). Modified installer to copy dependant DLLs (msvcr70d.dll and wtsapi32.dll).

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

Share

About the Author

Martin Wickett
Software Developer (Senior)
United Kingdom United Kingdom
No Biography provided

Comments and Discussions

 
Questionproblem with some program [modified] Pin
xparef at 26-Jun-13 2:45
memberxparef26-Jun-13 2:45 
Questionstartup application through remote desktop in Windows 7 Pin
Gajendra_Sharma_1 at 15-Apr-12 9:31
memberGajendra_Sharma_115-Apr-12 9:31 
QuestionInstallation Pin
wahsup at 19-Jul-11 8:17
memberwahsup19-Jul-11 8:17 
QuestionHuge BUG - am I right? Pin
yousefk at 1-Jun-11 2:41
memberyousefk1-Jun-11 2:41 
QuestionTSWindowClipper.dll location [modified] Pin
yousefk at 26-May-11 4:28
memberyousefk26-May-11 4:28 
QuestionLicense Clarification? Pin
Nathan J Kidd at 18-Jun-10 6:30
memberNathan J Kidd18-Jun-10 6:30 
AnswerRe: License Clarification? Pin
Martin Wickett at 18-Jun-10 6:49
memberMartin Wickett18-Jun-10 6:49 
GeneralRe: License Clarification? Pin
Nathan J Kidd at 18-Jun-10 7:01
memberNathan J Kidd18-Jun-10 7:01 
QuestionProblem with Win7 [modified] Pin
smigacznr1 at 29-Mar-10 2:22
membersmigacznr129-Mar-10 2:22 
AnswerRe: Problem with Win7 [modified] Pin
Gajendra_Sharma_1 at 15-Apr-12 9:32
memberGajendra_Sharma_115-Apr-12 9:32 
GeneralWorks great but it has one flaw Pin
JustinKubicek at 13-Jun-09 19:53
memberJustinKubicek13-Jun-09 19:53 
GeneralIT farm Pin
pyromate212 at 17-May-09 12:54
memberpyromate21217-May-09 12:54 
GeneralProblem running Terminal Services Window Clipper in a seamless window Pin
vipersixtyseven at 17-Mar-09 5:08
membervipersixtyseven17-Mar-09 5:08 
GeneralRe: Problem running Terminal Services Window Clipper in a seamless window Pin
uppi53 at 17-Mar-09 8:30
memberuppi5317-Mar-09 8:30 
GeneralNewer code Pin
Member 2145303 at 31-Dec-08 9:13
memberMember 214530331-Dec-08 9:13 
GeneralRe: Newer code Pin
uppi53 at 17-Mar-09 8:45
memberuppi5317-Mar-09 8:45 
GeneralRe: Newer code Pin
Member 2288736 at 20-Apr-09 18:40
memberMember 228873620-Apr-09 18:40 
GeneralClient Limitation Pin
Member 3012384 at 18-Dec-08 19:18
memberMember 301238418-Dec-08 19:18 
GeneralRe: Client Limitation Pin
uppi53 at 17-Mar-09 8:40
memberuppi5317-Mar-09 8:40 
Questionhow to use it with visual studio c++ WITHOUT .NET???? Pin
ori kovacsi at 23-Dec-07 23:25
memberori kovacsi23-Dec-07 23:25 
QuestionDoes this work with RDP 6.0? Pin
reinux at 20-Jun-07 10:51
memberreinux20-Jun-07 10:51 
Does this work with RDP 6.0?
AnswerRe: Does this work with RDP 6.0? Pin
uppi53 at 17-Mar-09 8:46
memberuppi5317-Mar-09 8:46 
GeneralDoesn't work even with "notepad.exe" Pin
kandda at 3-Dec-06 16:16
memberkandda3-Dec-06 16:16 
QuestionError Message... Using UNC & Switches Pin
Joe Doherty at 14-Aug-06 12:27
memberJoe Doherty14-Aug-06 12:27 
GeneralClipper.exe Entry point no found Pin
cow2006 at 17-May-06 1:51
membercow200617-May-06 1:51 
GeneralRe: Clipper.exe Entry point not found Pin
cow2006 at 18-May-06 0:10
membercow200618-May-06 0:10 
Generalclipper.exe not in setup Pin
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz at 21-Apr-06 2:24
memberzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz21-Apr-06 2:24 
Generalclipper message Pin
jjmccoy at 9-Mar-06 2:17
memberjjmccoy9-Mar-06 2:17 
GeneralRe: clipper message Pin
Martin Wickett at 10-Mar-06 5:17
memberMartin Wickett10-Mar-06 5:17 
GeneralRe: clipper message Pin
Member 2145303 at 31-Dec-08 9:14
memberMember 214530331-Dec-08 9:14 
GeneralPluggable Protocol Pin
bcweis at 15-Feb-06 10:34
memberbcweis15-Feb-06 10:34 
GeneralRe: Pluggable Protocol Pin
Martin Wickett at 16-Feb-06 7:45
memberMartin Wickett16-Feb-06 7:45 
QuestionAuto logoff? Pin
Helixx at 25-Nov-05 16:56
memberHelixx25-Nov-05 16:56 
AnswerRe: Auto logoff? Pin
marrik at 20-Jan-06 13:10
membermarrik20-Jan-06 13:10 
GeneralRe: Auto logoff? Pin
Helixx at 21-Jan-06 7:28
memberHelixx21-Jan-06 7:28 
GeneralRe: Auto logoff? Pin
marrik at 21-Jan-06 10:07
membermarrik21-Jan-06 10:07 
NewsRe: Auto logoff? Pin
JoeSnuffie at 22-Aug-06 7:50
memberJoeSnuffie22-Aug-06 7:50 
AnswerRe: Auto logoff? Pin
srlopez at 5-May-09 1:57
membersrlopez5-May-09 1:57 
Questionclipper.exe not in setup Pin
Jauhara at 23-Nov-05 10:02
memberJauhara23-Nov-05 10:02 
GeneralDoesn't work on my W2k server Pin
bindev at 10-Nov-05 6:32
memberbindev10-Nov-05 6:32 
GeneralRe: Doesn't work on my W2k server Pin
sylvain2222 at 3-Jan-06 11:05
membersylvain22223-Jan-06 11:05 
GeneralRe: Doesn't work on my W2k server Pin
bindev at 10-Jan-06 6:18
memberbindev10-Jan-06 6:18 
GeneralRe: Doesn't work on my W2k server Pin
Seibernaut at 19-Mar-06 6:52
memberSeibernaut19-Mar-06 6:52 
GeneralXP Rdp Server. Pin
Ing. Gonzalo Araujo C at 27-Aug-05 8:23
memberIng. Gonzalo Araujo C27-Aug-05 8:23 
GeneralRe: XP Rdp Server. Pin
Pablo Guerra at 1-Dec-05 16:25
memberPablo Guerra1-Dec-05 16:25 
GeneralRe: XP Rdp Server. Pin
Ing. Gonzalo Araujo C at 5-Dec-05 8:11
memberIng. Gonzalo Araujo C5-Dec-05 8:11 
GeneralRe: XP Rdp Server. Pin
alexsantos at 22-May-07 1:19
memberalexsantos22-May-07 1:19 
QuestionUpdate ? Pin
Flyduck at 22-Aug-05 10:01
memberFlyduck22-Aug-05 10:01 
AnswerRe: Update ? Pin
Martin Wickett at 27-Aug-05 6:04
memberMartin Wickett27-Aug-05 6:04 
GeneralRe: Update ? Pin
Ing. Gonzalo Araujo C at 27-Aug-05 8:33
memberIng. Gonzalo Araujo C27-Aug-05 8:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150427.1 | Last Updated 15 Apr 2005
Article Copyright 2005 by Martin Wickett
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid