Showing posts with label COM. Show all posts
Showing posts with label COM. Show all posts

ActiveX control method name changing case out-of-the-blue?

I’m humming along working on an application when suddenly Visual Studio reports that it can’t find a certain property.

The property name, let’s call it SomeProperty, is a property of an ActiveX control that gets referenced from a Windows Forms 2.0 application.

So I do a clean or three assuming that an old AxInterop dll is lying around somewhere.  After the 2nd clean I blow away a few more library directories to guarantee that the control is both being created and imported from scratch.

Still no luck.  So I clean out my temp directory since Visual Studio uses the temp directory for some intermediate files and who knows, maybe a file somehow got locked or had its permissions changed.

Same error.  I pull up OleView to verify that SomeProperty really has become someProperty.  Sure enough, it shows up as someProperty.

It turns out that this is a known issue with the IDL compiler.  It uses the case of the first instance of an identifier that occurs in the IDL file for any subsequent occurrences of that identifier even when the identifier is later used in a totally different context!

In this case, I recently added a struct with a member name that happens to collide with a property of an interface defined later in the file.  Who knew that all identifiers needed to be globally unique? 

I’ll have to give the mapping thing mentioned in the KB article a try but for now I’ll leave a comment in the IDL and rename the struct member.

Installers, COM and Legacy

I’ve used a variety of installers over the past few years while doing Windows Client development.  InstallShield, Nullsoft Installer, Caphyon’s Advanced Installer and last, but not least, Visual Studio Setup/Deployment projects.

They’re all intended to shield the developer from the innards of Windows Installer (or the custom installer technology).  With varying degrees of success they make it easy to create the typical interaction between the user and the computer during an application install.  Or at least that’s the idea.

Try as they might, these installers can’t entirely shield you from the underlying components, tables, properties, binary files and obscenely verbose MSI logs that are the world of the Windows Installer.

One such case has bedeviled a recent project as it relates to COM components.  Whilst most of the codebase is managed code a few components (including a critical one) are still packaged as COM libraries.  Registration-free COM, as I describe in an earlier post, relieves us of the perils of system-wide, centrally registered libraries that get installed and reinstalled by separate, not-necessarily cooperating applications.

However, one of the libraries is a 3rd party library that gets installed (and uninstalled) with several different applications.  This is a problem because these applications are not always installed/uninstalled at the same time.  They’re also versioned independently.  In every case that I’ve seen installers will uninstall COM libraries when an application is uninstalled.  This breaks every other application on the machine that depends on that COM library.

It turns out that the way to prevent application A from breaking application B when application A is uninstalled (and the shared COM library is uninstalled along with it) is to mark the COM library as a Shared, Reference Counted DLL.

No matter the installer this feature is controlled by a property taken directly from the guts of Windows Installer: msidbComponentAttributesSharedDllRefCount.  This bit field determines whether or not Windows Installer will uninstall the DLL when the application is uninstalled.

The classical problem with using reference counting to track “liveness” (when a component is still in use) is the problem of circular references.  If Components A and B depend on each other then they can never be removed entirely because their reference counts can’t be reduced to zero until they’re both zero.  Fortunately this scenario hasn’t reared its head.  When it does I’ll be sure to post.

Accommodating an ActiveX Control that's Interfering with Windows Forms Events

For reasons not entirely clear to me a particular ActiveX control appears to interfere with Windows Forms events. The vendor has long since offered a purely managed implementation so they have little interest in supporting use of the ActiveX control via Runtime Callable Wrapper. Unfortunately, times being what they are, funds aren't available to take advantage of the purely managed implementation.

By interfere I mean, while this ActiveX control is performing a potentially long running operation the UI owning thread "magically" resumes event processing. I suspect this is intentional; the vendors users probably complained that their UIs froze whenever they performed this potentially long running operation. Since this 3rd party control was consumed mostly by single threaded VB6 apps the vendor may have decided to respond to these complaints in a way that causes a problem for Windows Forms apps.

I have lots of theories (e.g., there may be some interplay between the ActiveX control being free threaded while the main thread of the WinForms app runs in a single threaded apartment) but little time to investigate them. So I'm avoiding the problem by running the ActiveX control on a separate thread.

The managed ThreadPool is a wonderful place to run this code; I don't have to manage the setup or teardown of ThreadPool threads and the operation isn't so long running that it will prevent other threads from accessing the ThreadPool.

Since I'm running the ActiveX control in a separate thread to avoid interference with the UI thread, not because I want to execute concurrently, I need to wait until it's done before proceeding (and I *want* the UI to be unresponsive during this time - even have the WaitCursor showing). So a ManualResetEvent is signaled once the operation is complete.

What does this have to do with Pre 3.0 C#? Well, C# 2.0 introduced anonymous methods. These provide a way to succinctly pass short behavior (no more than a few operations) without having to declare a separate method.

So something along the lines of the following:

ThreadPool.QueueUserWorkItem(new WaitCallback(
delegate(object throwAway)
{
// do something here
myResetEvent.Set();
}));


followed by

myResetEvent.WaitOne();


does the trick!