Cocotron and Third-Party DLLs

As you might have noticed, Touchsmart TUIO uses the amazing Cocotron in order to use parts of my Cocoa tracker code on the HP Touchsmart PC, which runs (yuck!) Windows Vista.

While Cocotron has its quirks and is far from a full-fledged drop-in replacement for Apple's frameworks at the moment, one issue that drove me particularly nuts was not a missing class or method, but the way the Cocotron toolchain links Nextwindow's API in.

I'm really not an expert on Windows internals, let alone their DLL library format. Nevertheless, I understand that in order to link the DLL properly, you do not link directly to it, but rather to LIB file, which seems to contain symbol addresses (or something) for the DLL.

Annoyingly, I couldn't get this to work with Cocotron's toolchain at all. No matter what I linked in (either the DLL or any of the multiple LIB files bundled with the API), the linker would happily succeed, but the application would crash on launch when calling a DLL function. Firing up GDB only told me that my code tried to call a function at a garbage address.

Now, I don't really have any ideas what's going wrong here. I already find the idea of cross-compiling a Windows app on a Mac pretty amazing. To come to the point, there's a pretty simple solution: Determine the address at which a DLL function is loaded dynamically at run-time, using Windows' GetProcAddress function.

Here's a simple code snippet to show you how this is being done rather elegantly in Touchsmart TUIO (explanation below).

static HMODULE _dllHandle = NULL;

#define NWAPI(funcName, ...)    ((GetProcAddress(_dllHandle, (funcName)))(__VA_ARGS__))

void initDll() {
    if (NULL == _dllHandle)
            _dllHandle = LoadLibrary("NWMultiTouch.dll");

    if (NULL == _dllHandle)
        fprintf(stderr, "DLL fail.\n");
}

void sampleDllCall() {
    NWAPI("GetConnectedDisplayInfo", 1, NULL);
}

Even though most devs will get the idea from the code alone, here's a quick run-down. First, we define a static variable to hold the DLL handle. It's static because we don't need the handle to be visible outside this source file.

Second, we define a macro that takes a function name and an arbitrary amount of arguments. The macro will expand to a code block that dynamically determines the function address and funnels all the arguments into a call to this address. Sweet. Third, we need to define an init method that has to be called when our app launches (actually, just before the first use of our macro). If you want to get fancy, you could a check whether the DLL is already loaded into the macro, so you wouldn't have to think about calling the init function explicity.

Fourth, we simply have a demo DLL call here, which shows you how to use the API. Of course, I don't know how expensive a call to GetProcAddress is, so you might want to cache function addresses for functions that you call repeatedly or that are in the critical path of your application.

Nevertheless, I think this is a somewhat elegant solution if you're having the same issue with Cocotron.