Archive for the ‘Programming’ Category

Creating a Remote Desktop Plugin Using Delphi - Errata

Wednesday, January 9th, 2013

After I had implemented my plugin and it was just going into production, I discovered a rather ugly truth.  WTSVirtualChannelOpen will succeed even if the plugin is not installed on the client side.  You don’t find out about the problem until the first time you try to write to the channel, whereupon you get an obscure error.  Something about an “invalid function”.

It appears as though the only solution to this problem is to implement a “ping” function in the plugin. Then, on the server side, you need to open the virtual channel and ping the client.  If both of these succeed then the plugin exists, otherwise it does not.

You would think that Microsoft would at least check to see if the client has registered the virtual channel before returning a handle for it.

Creating a Remote Desktop Plugin Using Delphi - Part 5

Tuesday, December 4th, 2012

The last thing that I need to do to my remote desktop plugin is add the code required to send data from the client to the server.
(more…)

Creating a Remote Desktop Plugin Using Delphi - Part 4

Monday, December 3rd, 2012

Now that we have the client side ready to receive data from the server we need to look at programming the server side.  This actually seems to be quite a bit simpler that the client side.  There are just four functions; WTSVirtualChannelOpen, WTSVirtualChannelClose, WTSVirtualChannelRead and WTSVirtualWrite.  Actually, there are a few more, but these are the ones that you need to get by. (more…)

Creating a Remote Desktop Plugin Using Delphi - Part 2

Thursday, November 29th, 2012

In part 1 of this series I set about creating a remote desktop plugin using Delphi. It didn’t do anything except initialize itself and display a few message boxes indicating its progress.  Not very useful.

In order for this whole thing to work the way I want it to, the plugin is going to have to interact with the user on the remote workstation.  This means displaying a form that will have to be on top of the remote desktop window.  I had some vague misgivings that remote desktop in full screen mode would be an “always on top” window that would interfere with the interaction that I need. So, as the next step in the process, I changed the plugin to create a form, make it an “always on top” window and display my status messages in a TMemo contained in the form.  Surprisingly enough this actually works quite well.

(more…)

Creating a Remote Desktop Plugin Using Delphi - Part 1

Saturday, November 17th, 2012

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.

(more…)

Delphi Class Completion (Ctl-Shft-C) Stops Working

Sunday, March 18th, 2012

Suddenly, pressing Ctl-Shft-C in the Delphi XE2 IDE stopped working.  You could press that magic key combination all day and nothing would happen.  It took hours to figure out what the problem was.

I had installed update 4 for Delphi XE2, which contained, among other things, something called AQTime.  This appears to be some kind of application profiler.  Anyway, it was AQTime that was interfering with class completion.  A quick trip to Control Panel to uninstall the offending bit of software and everything went back to normal.

Never build package %s must be recompiled

Sunday, March 18th, 2012

I was recompiling my application they other day, switching everything from Debug to Release.  Suddenly I started getting “Never build package %s must be recompiled” errors.  I couldn’t understand this, since the previous step in the recompile had just finished compiling the package in question.

It finally turned out to be caused by recompiling the Release packages into a different directory than the Debug packages.  The Debug packages went into Delphi’s default DCP and BPL directories while the Release packages went into the projects ($Platform)\($Config) directory.  I did this because the packages in question contain Delphi components that appear in the component toolbar and I want to be able to step into the source for those packages while debugging.  I thought that compiling the Release packages to a different directory would solve all kinds of problems related to debugging.   And it did, but it created these errors when compiling for Release.  It was the order of directories on Delphi’s search path that caused the problem.  The Delphi wide options specify the default package directory early on in the search path.  Even though I had the Release directory on the project’s search path, the Release DCPs were never found, because the Debug DCPs were found first.  Since I was compiling the Release packages to ..\$(Platform)\($Config) all I had to do was add that to the Delphi wide search path before the default DCP directory and the problem was solved.

Delphi, Firebird, IBObjects and Transaction Management

Thursday, November 17th, 2011

I recently had reason to revisit transaction management in our application.  The application makes extensive use of data aware grids (TDBGrid) and, as I am sure everyone is aware, it is impossible to explicitly manage transactions when you are displaying data in a grid.

Fortunately, IBObjects provides the means to automatically clean up transactions left hanging by TDBGrid.  Unfortunately, this isn’t as well documented or as straightforward as I would like.  So, after much research using the programmer’s secret weapon (Google) and a few questions posted to the IBObjects support group (thanks Jason) I think I finally understand how it works. (more…)

The Mystery of the Disappearing Icon

Thursday, November 3rd, 2011

I just finished creating a new custom control for Delphi.  I’ve done this dozens of times in the past and never had a problem until now.  This time the control’s icon simply would not appear in the tool palette.  No matter what I did, all I got was the default icon.

It turns out, that the first time I installed the component I had a problem with the DCR file that held the icon, so Delphi installed the control with the default icon.  Perfectly reasonable.  However, Delphi keeps a cache of custom controls that have been installed and, apparently, no matter how many times you uninstall and reinstall, it remembers certain settings (like the icon) from the cache.  To fix this problem, you need to manually edit the registry and remove the offending cache items.  To do this:

  1. Uninstall your custom control from the Delphi IDE.
  2. Open the registry editor (regedit.exe).
  3. Browse to HKEY_CURRENT_USER\Software\Embarcadero\DBS\9.0\Package Cache.  Where 9.0 is the version number for Delphi XE2.  Your version number may vary.
  4. Delete the key MyCustomControl.bpl where MyCustomControl is the name of your custom control’s package.
  5. Browse to HKEY_CURRENT_USER\Software\Embarcadero\DBS\9.0\Palette\Cache.
  6. Delete the key MyCustomControl.bpl where MyCustomControl is the name of your custom control’s package.
  7. Reinstall your custom control as your normally would.

Hopefully, the proper icon will now appear in the tool palette.

Delphi Compiler Versions

Tuesday, October 25th, 2011

If you ever need it, here is the list of Delphi compiler version numbers:

Compiler CompilerVersion Defined Symbol
Delphi XE5 26 VER260
Delphi XE4 25 VER250
Delphi XE3 24 VER240
Delphi XE2 23 VER230
Delphi XE 22 VER220
Delphi 2010 21 VER210
Delphi 2009 20 VER200
Delphi 2007 18.5 VER185
Delphi 2006 18 VER180
Delphi 2005 17 VER170
Delphi 8 16 VER160
Delphi 7 15 VER150
Delphi 6 14 VER140
Delphi 5 13 VER130
Delphi 4 12 VER120
Delphi 3 10 VER100
Delphi 2 9 VER90
Delphi 1 8 VER80

To make use of this information in a Delphi program you can define conditionally compiled bits, like this:

{$if CompilerVersion >= 20} // Delphi2010 or later

{$ifend}

OR

{$ifdef VER200} // Delphi2010

{$endif}