A reader recently asked me the following:
“What do you need to do exactly to change the legacy namespace of an existing driver? I have a serial port driver (for an expansion card with 4 serial ports) which works and uses the COM-prefix, but I want to change the COM-prefix to something else, so that it's easier to distinguish between onboard COM-ports and the ports on the expansion card...
I've changed the prefix in the registry and also in the .def-files. But when I try to compile it, I get LNK2001-errors (Unresolved external symbol). The driver that I'm working with is a MDD/PDD-driver.”
I found this to be an interesting question on a few levels; why does the linker error happen and what needs to happen to change the prefix? I gave him a short answer in the comments, but thought that it deserves a more prominent answer as a separate article.
Why does the linker error happen?
To understand the linker error we need to understand what the DEF file does.   The DEF file tells the linker that it should find a set of functions and expose those functions to the outside world. The functions are exposed outside of the DLL so that when an application or another DLL loads this DLL it can call the function(s). With that we know that by changing the set of functions to be functions that don’t exist, we should get linker errors, why because the functions don’t exist and we told the linker that they do.
What needs to happen to change the prefix?
I know you are sitting there thinking that the answer is obvious, and certainly one answer is obvious. I came up with three solutions:
1.       The obvious answer is to change the functions in the driver to match the DEF file. Done, simple and quick – but wait, what if the functions aren’t in the code because the driver is made up of an MDD and PDD? Now it gets more complicated, we could clone the MDD just to be able to change the prefix. Not a real good reason to go to that effort and then need to maintain the MDD.
2.       We could create wrapper functions in the driver to call the original functions. Something like:
DWORD NEW_Init(ULONG   RegistryPath)
{
return XXX_Init( RegistryPath );
}
Repeat for each function and I suppose you could even expose both sets of functions, the XXX_ and the NEW_ functions.
3.       We can use the DEF file to rename the functions. 
LIBRARY       Sample Driver
 
EXPORTS NEW_Init=XXX_Init
                NEW_Deinit=XXX_Deinit
                NEW_Open=XXX_Open
                NEW_Close=XXX_Close
                NEW_Read=XXX_Read
                NEW_Write=XXX_Write
                NEW_Seek=XXX_Seek
                NEW_IOControl=XXX_IOControl
This exports the NEW_ functions which refer to the XXX_ functions when called.  This solution is similar to solution #2, but without needing to write code to do it. With this we can do very little work and expose the functions with new prefixes without needing to clone the MDD. Try this then run “Dumpbin /EXPORTS MyDriver.dll” to see the names of the exported functions.
 
Copyright © 2010 – Bruce Eitman
All Rights Reserved