Thursday, October 14, 2004

madCodeHook

I'm using madCodeHook from madCollection to fix an ugly problem we (at the company I work for) have with some of the earlier versions of our products. We've been using JCL (the JEDI Code Library, an otherwise extremely useful and very well-written library), which used to have a bug in its CPU speed measuring code: it might cause a division by zero on faster computers. What makes things really bad is that this code is executed during initialization - which, if the division by zero occurs, prevents the applications from running.

The applications are running from CDs (and require the CDs to run). They have been working fine for years, because the bug does not reveal itself on slower CPUs, but now, as users start upgrading or buying new, faster computers, they find out that the applications won't run anymore (they won't even start). :-(

The fix I'm working on injects a DLL into every newly started process as soon as it's loaded (before initialization code is executed). The DLL inspects the process it has been injected into, and if (and only if) it positively identifies it as our application, it hooks the QueryPerformanceFrequency API call to return False, which solves the problem - the offending JCL routine will not attempt to measure the CPU speed in such case. The DLL will do nothing to any other process. Fortunately, we are able to identify our own applications' processes fairly easily. Also, we know that our applications never use the API function anywhere else, so this seems to be an acceptable solution. The fixup program is designed to run as a service under system account on NT-based Windows - code hooking requires administrator privileges. It works as a normal (hidden) Windows application on Windows 9x systems.

I wouldn't be able to do this without madCodeHook - madCollection is really a great library - in this case, a life saver. Thanks, Madshi, for your excellent work!

Tuesday, October 12, 2004

Delphi 2005 press release

Scotts Valley, Calif. - October 12, 2004: Borland Software (NASDAQ: NM: BORL) today announced Borland® Delphi™ 2005, previously codenamed "Diamondback" and the newest version of Borland's Rapid Application Development (RAD) environment for Windows® and .NET applications. Delphi 2005 combines Win32, .NET, Delphi and C# support all within one environment, significantly advances developer and team productivity and integrates with Borland's leading Application Lifecycle Management (ALM) solutions.

View the full press release here.

DataSnap.NET

About a week ago, I had an idea of porting the server part of DataSnap framework to .NET. Since then I've been fiddling with it in my free time, using Borland's C#Builder Personal Edition which is free for non-commercial development. Today, my first prototype of a (stateful) managed socket server is ready. So far, it's able to serve the following requests:
  • asGetAppServers: retrieve ProgIDs of installed appservers (thanks to Andrey Alifanov for this excellent article about using the COM Category Manager from .NET via interop)
  • asCreateObject: create instances of COM appservers
  • asFreeObject: release said instances
  • asInvoke: call simple methods, e.g. AS_GetProviderNames, AS_GetRecords (loading a client dataset works), as well as some simple custom methods of my test appserver.
An ASP.NET equivalent of httpsrvr.dll is also in the works (asynchronous HTTP handler, using the thread pool) but first I'd like to finish the common (transport-neutral) library which is responsible for marshalling DataSnap calls across wires via data packets.

I still have to debug and test marshalling of all possible parameter types (including multidimensional variant arrays, records, enums, byref parameters and so on). It seems to be easier to debug this code within the socket server which is a simple managed WinForms application.
A lot of my current code is, most probably, terribly inefficient, with lots of boxing and unboxing going on (first, data is read from the data packet stream into managed type variables which are then marshalled to unmanaged COM appservers, results unmarshalled to managed variables and streamed back to client). At this stage, I'm focusing purely on functionality; optimization can wait ;-).

What's the purpose of this work? Most of all, I'm doing it for my own fun and education. I'm still a beginner in .NET and this is a nice way for me to become more familiar with it. I have also acquired a bit deeper knowledge of this cool library called DataSnap.