Creating a Remote Desktop Plugin Using Delphi - Part 1

I have recently found myself in a situation where I need to have an application running on a server using remote desktop interact with files and devices on the user’s local workstation.  Specifically, I need to be able to use a scanner to scan documents and / or retrieve files containing documents that have already been scanned. I found several commercial plugins that would drive the scanner but I couldn’t find anything that would allow me to interact with the user to allow her to import documents from a file.

Knowing that there are commercial plugins available, I know that it is possible to write a plugin for remote desktop.  So, I’m thinking; “How hard can it be?”.  Since we are virtually a pure Delphi shop I started looking for examples of Delphi plugins.  Surprisingly, I didn’t find any.  It is difficult to believe that no one else has done this, but I seem to be a pioneer. So, in this and the next few articles, I am going to create a remote desktop plugin using Delphi and remote desktop virtual channels and I am going to document the process here.

It looks like there are two ways (at least) to create a remote desktop plugin.  You can use the remote desktop API or you can using something called dynamic virtual channels which involves working with COM.  Since I detest COM in all its forms, I have decided to use the remote desktop API.

Creating the plugin is simplicity itself.  You just create a DLL that exports a single function named VirtualChannelEntry.  This functions needs to accept a single parameter, which is a pointer to a table of callbacks that you will use to talk to the remote desktop cleint, and it must return True if you managed to successfully initialize a virtual channel or false if you did not.  Even though this sounds incredibly simple (and it is) there is quite a bit of up front work to do because, as nearly as I can tell, Delphi does not define any of the data types required by the API.  So I had to manually recreate the structures, function prototypes and enums required.

Once all that was done the body of VirtualChannelEntry was straight forward.


function VirtualChannelEntry(const pEntryPoints: TChannelEntryPoints): Boolean; stdcall;
// This is the main (and only) entry point to the DLL.  This gets called when
// the remote desktop client tries to load this DLL to initialize the virtual
// channel.
const
  myChannels: array [0..0] of TChannelDef = (
    (name: 'AurScan'; options: 0)
  );
var
  stat: UINT;
begin
  MessageBox(0, 'Entering VirtualChannelEntry', '', MB_OK or MB_APPLMODAL);
  gEntryPoints := pEntryPoints;
  stat := gEntryPoints.pVirtualChannelInit(gHandle,
            @myChannels[0],
            1,
            VIRTUAL_CHANNEL_VERSION_WIN2000,
            VirtualChannelInitEvent);
  Result := (TChannelReturnCodes(stat) = crOk);
  MessageBox(0, PChar(Format('Init status = %d', [stat])), '', MB_OK or MB_APPLMODAL);
  if ((myChannels[0].options and CO_INITIALIZED) = 0) then
  begin
    MessageBox(0, 'Channel not initialized', '', MB_OK or MB_APPLMODAL);
    Result := False;
  end;
end;


Once you have gotten this far you need to register you shiny, new DLL so that remote desktop can find it.  This is done by adding a new key to HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default\AddIns.  You can name this key anything you like.  Under this new key add a string value named ‘Name’.  Set the value of this to the FULL PATH to your dll.  According the everything I can find on the subject, this is all you need to do.

Imaging my consternation when I did all this, fired up the remote desktop client and nothing happened.  Turns out, I am running 64-bit Windows and I had compiled the DLL for 32-bit.  A quick change of the build target and everything worked.  The DLL doesn’t do anything yet except initialize a virtual channel and display a bunch of message boxes telling me what it is doing, but it’s a start.

You can find the Microsoft documentation for the API here.

You can download the source code for the plugin as it stands so far here.

2 Responses to “Creating a Remote Desktop Plugin Using Delphi - Part 1”

  1. William Meyer Says:

    I think your search has been hampered by the fact that a plug-in framework was built some years ago, and built so well (by UIL) that it sort of eliminated the need. It is now owned by TMS, as you probably know, and is here:
    http://www.tmssoftware.com/site/tpf.asp

    I also found a project on SourceForge, though it has been over three years since it was updated.

    In addition, there may be something on the TechVanguards site, but that site apparently expired just yesterday. ;)

  2. admin Says:

    The TMS stuff is for creating a plugin driven Delphi application, not for creating a plugin for the Windows remote desktop client. A completely different animal.

    I can’t find anything on SourceForge related to remote desktop plugins. Maybe I’m just using the wrong search terms.

Leave a Reply