Template Class for Dynamic Linking

Dynamic linking (or runtime linking) is the method of finding and calling a function in a DLL at runtime. The most common use for it is when you can’t be certain that the DLL or function will exist. For example, if you calling a new WINAPI function which only exists in Vista, but you want your application to still run on XP, you will need to use dynamic linking.

The process is simple: load the DLL, get the address of the function and make the call. You need just 3 WNAPI calls to get the job done. Of course, there is error checking too, so a typical function call requires several lines of code, and if you want to save the pointer for use later, you still have worry about keeping track of the handle to the DLL and releasing it when you are done.

So I made a template class to encapsulate the entire process, creating essentially a smart pointer for dynamic functions.

template <typename FunctionPtr> class CDynamicFunction
{
public:
    // Constructor automatically binds the function.
    CDynamicFunction(CString dllName, CString procName)
    {
        _module = ::LoadLibrary(dllName);
        if (_module == NULL)
        {
            // error, DLL probably doesn't exist
            _procAddress = NULL;
        }
        else
        {
            // Get the function pointer - this will be NULL if the function doesn't exist.
            _procAddress = (FunctionPtr)(::GetProcAddress(_module,procName));
        }
    }

    // Destructor automatically releases the DLL.
    virtual ~CDynamicFunction(void)
    {
        if (_module != NULL)
        {
            ::FreeLibrary(_module);
            _module = NULL;
        }
    }

    // Use this method like a regular function. Check for NULL first, in case the function
    // couldn't be linked.
    virtual operator FunctionPtr()
    {
        return _procAddress;
    }

private:
    HMODULE     _module;
    FunctionPtr _procAddress;
};

To use the template class do the following:

1. Typedef a pointer to the function you want to import. The syntax below is for a Windows API call, but you can define it as needed.

typedef LONG (WINAPI *pMyEntryPoint) (HWND hwnd, int xyz);

2. Instantiate the class either in a local stack frame, or in another class. The DLL is loaded upon instantiation and it will be automatically unloaded when the class goes out of scope.

CDynamicFunction<pMyEntryPoint> myEntryPoint("blah.dll", "MyEntryPoint");

3. Check the result of the class and call your function:

if(myEntryPoint == NULL)
{
    // handle error
}
else
{
    LONG result = myEntryPoint(hwnd, x);
}

Simple and reliable, and it avoids the common errors that come from writing the same code in many different places.

Dealing with Vista’s Low Cookies

Vista with Internet Explorer 7 introduced a new security level called protected mode. Among other things, this mode stores cookies in a separate cache, which is inaccessible to normal mode processes. This "feature" caused me a bit of a problem with a Windows application I support.

Users download this application from a web site. When the application runs, it makes additional requests to the web site. The web site keeps track of these requests with cookies. The problem is that a typical user with default settings is going to hit the download in protected mode, thus leaving the cookie in the low integrity cache. But, the application runs in normal mode, so when it makes requests to the web site, the web site is unable to read the original cookie it left. There is no way for the normal mode application to get at this quarantined cookie. No easy way at least.

I should point out that this app is using automation to open Internet Explorer and download additional content. Even though it’s accessing the same web site, because the app is running in normal mode, the site is now accessed in normal mode as well. If you’re downloading files using wininet, you’ll get the same result. Web site sees the normal cache and can’t get the cookie it left the first time.

The solution I came up with is to run a low integrity process to read the cookie from the low cache and write it to a place where the application can read it, and then save it as a normal cookie. For the low integrity process, I run another copy of the application so there’s no extra baggage; it’s all self contained.

Step by step, here is the process:

1. Check if we’re running on Vista. You could also check if the browser is in protected mode, but finding or not finding the cookie is pretty much the same.

2. Run a new copy of the app in low integrity mode (you could have a separate app for this). What I do is pass a command line parameter to tell the app it needs to find the low cookie. Basically just get the filename for the current process using GetModuleFileName and use this sample code to start the new process.

Also note that since this app needs to run on all versions of windows, entry points to new Vista functions need to be dynamically loaded.

In the command line, I also pass the location where the cookie is to be written. You’ll need a location that both low and normal processes can access. Luckily Microsoft does provide such a thing. You can call SHGetKnownFolderPath with FOLDERID_LocalAppDataLow to get a folder that both processes can read and write.

3. When the low integrity process runs, it uses InternetGetCookie to read the cookie from the low cache. Because the process is low integrity, it automatically reads from the low cache.

Reading cookies in a C++ app is not as simple as you would think. I could make another post on that. In short, what you get back from InternetGetCookie is a string with all cookies for a given url separated by semicolons. Each cookie in the string is in the format name=data. So I ended up with some convoluted parsing routines. Well, maybe your cookies are written differently, but this is what I had to deal with. Anyway…

4. After finding the right cookie, the low integrity process writes it to a text file.

5. The main process, after waiting for the low process to finish, reads back the cookie data and uses InternetSetCookie to write the cookie to the normal cache. One caveat I found is that you have to append an expiration to the cookie string:

"; expires = Fri, 01-Jan-2038 00:00:00 GMT"

And that’s it. Now the web site can read the cookie it left on the initial download. Pretty big hoop for a basic operation that used to work all by itself for years. Thanks Microsoft!