Sunday, 25 April 2010

Terminal Services Programming and RDP Virtual Channels...

This is a work in progress. Lately, I've spent
more than a few hours on the subject looking for information. TS developement is an interesting subject but documentation is scarce, to say the least.

The problem.

I have an application (several of them) running, in many cases, in a Terminal Server (aka Remote Desktop Services) environment. The application, running remotely on the server, needs to communicate with some hw/sw concoction "running" on the client (typically a XP/Seven PC running MSTSC.EXE, the Remote Desktop Client).

How do you let server and client speak? You could think of the following..

- Use some form of messaging on the wire, think of NT mailslots on the network for example

- Use some sql database tables as an exchange point

- Use something on a network drive (think of an Access mdb file)

- Use some form of RPC with a dedicated server (think of web services)
- Use the client file sharing feature provided by the latest RDP protocol iterations.

Well, beside being awkward, with the exception of the latter option all these 'solutions' have a problem. You cannot be sure to have the practical possibility of implementing them. Mailslots are often disabled for security reasons, tcp ports for sql and www are often disabled and with good reason. The only thing you can be reasonably sure to have is a reasonably recent RDP server/client combination and the RDP port open on the wire.

But of course it is possible to exchange something other thank keystrokes and mouse clicks and window redraws over RDP. Think of file and printer redirection: think of 3d party printing solutions like Uniprint. One should be definitely able to implement a custom 'pipeline' to let the RDP client interact with the remote application on the Terminal Server.

Well, of course you can, it's just not that terribly simple to implement.

Enter WTSAPI and Virtual Channels.

The only real API provided by Windows for TS programming is WTSAPI - It come in the form of a Win32 DLL (WTSAPI32.DLL), your typical sandwich of system functions. In a nutshell it provides two kinds of APIs. Therea are APIs to query the terminal server about information (number of sessions, client IP and such) and to control it, with some limitations. These APIs are relatively straightforward.

Virtual Channel APIs are much more interesting. A VC is a bidirectional communication link between the remote app and the remote RDP Client Application - MSTSC.EXE namely. It's the 'transport' over which Uniprint, printer and file redirection, etc. are implemented.

An RDP VC is initiated by the server application using some WTSAPI calls, directly from the app itself. The client part is a bit trickier: VC data must be handled by a custom DLL exporting a single function handling what is basically a table of pointers to other standard functions to open/read/write/close the channel. The DLL must be copied somewhere and referenced in a registry key read by MSTSC. Next time the RDP Client is run if all goes well it will call the client DLL and be able to read and write from/to the server. The communication is based on chunks of data (raw packets if you) and this must be handled by the developer. Not terribly complex of course, but not really high level. There also a couple of activex controls (mstscax.dll and MSRDP.OCX which is being phased out)

That's just what I needed! I wanna know more.

Me too. This M$ Webcast is a rather good introduction. There is the MSDN reference of course. And this old MSJ article. Oh, this official M$ blog too. It's not that much really... There's a dearth of reliable sample code (see below)

I am ashamed to ask, but I want to use VB6

If you just want to use WTSAPI function to check you ip, etc, it's possible. If you want to implement a full VC client/server application, bear in mind that you will need to:

- translate the API definitions and structure into VB (noone has still done it completely as far as I know)

- you will have to create a DLL (not an ActiveX dll) with exported functions. Possible, but not out of the box with VB6

- you will have (almost surely) to multithread. Possible, but not out of the box with VB6

- if your client is 64 bit, you're out of luck (64 bit windows MSTSC needs a 64 bit VC 3d party client DLL)

There are, though, 3d party components to ease the life of the VB6 developer. Look here, here and here. Of course 3d party libraries can be a problem, and I don't mean only the license costs.

I want to use C/C++

That's good, since WTSAPI is designed for this language. The so called samples available in MSDN are in C++. There are some samples available in the Windows SDK (aka Platform SDK) in samples\winbase\wtsapi. These samples are more than 11 years old. Even though they come with the SDK, you CANNOT compile 'em with ONLY the SDK. You need to use SDK tools and VS integration. For now, I've had luck only with VS2005, in 32 bit mode, and not with TsSysInf, the RDP VC Sample, which I suspect to be completely obsolete. This Codeproject entry uses RDP VC with C++.

I want to use Delphi.

I'd love, but now I can't look too much into it. Probably the best all around Windows developement tool, if it wasn't for Borland.. Well, I've seen there is even a WTSAPI wrapper from JEDI...

I want to use .NET

It works - one has to use WTSAPI P/Invoke, and in 64 bit too. Even though you should consider this KB note from Microsoft telling you not to use managed code for this kind of things.
But, in the limited tests I've run, it works rather good. There is a great code sample in Codeproject to demonstrate it. With a few tweaks, it really seems to work, and on 64 bit windows too.


Oh, these are just some reorganized notes I've posted here thinking they might benefit the occasional search engine user hitting these pages (and yours truly - blog are wonderful notes to ourselves). If I'll have the time, I'd like to further explore and elaborate on the subject.

1 comment:

  1. hi, i'm one of search engine users :), did you manage to make a working code on x64 clients/servers ? if u have some more informations, code of links please send to me :)

    i prefer c#