I'm writing clone DLL's, and needing them to be drop in replacements for programs which already are linked. I do not wish programs linked against my replacement DLL/.Lib to be forced to import by ordinal; however, I do want programs which are already linked against the original DLL to be able to import by ordinal and not be broken by my replacement. -- therefore, I need to export my functions by name but preserve a mapping of ordinals.
How can I do this?
If I create a .def file like this (Interface.def):
LIBRARY Interface
EXPORTS
??0Interface@@QAE@ABV0@@Z @1
??0Interface@@QAE@XZ @2
??1Interface@@MAE@XZ @3
??4Interface@@QAEAAV0@ABV0@@Z @4
??_7Interface@@6B@ @5
?bIsBluetoothAddress@Interface@@SA_NABV?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@@Z @6
?bIsUSBAddress@Interface@@SA_NABV?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@@Z @7
?bIsWiFiAddress@Interface@@SA_NABV?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@@Z @8
?getBluetoothAddressFromResource@Interface@@SAXABV?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@AAV23@@Z @9
?getFantomLoadStatus@Interface@@SA?AW4TFantomLoadStatus@@XZ @10
?getFriendlyNameFromResourceString@Interface@@SA_NABV?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@AAV23@@Z @11
?pzSambaAddress@Interface@@2PBDB @12
allocateNxtInterface @13
bIsExecutableFileType @14
bIsPairedBluetoothName @15
destroyInterface @16
and, in the header file for Interface.h, I made sure to put:
#ifndef __INTERFACE_H__
#ifndef __INTERFACE_EXPORT__
#define __INTERFACE_EXPORT__ __declspec( dllimport )
#endif
class __INTERFACE_EXPORT__ Interface { /* definitions omitted in this example. */
}
extern "C" {
Interface* allocateInterface( void );
void destroyInterface( Interface * );
bool bIsExecutableFileType( Interface * );
bool bIsPairedBluetoothName( Interface * );
}
But, even so -- When I use it under Visual Studios 2008 (version 9) any program linked to the .Lib it creates will try to import by ordinals strictly -- which is NOT what I want. I thought NONAME was required in the .def to get the bad behavior -- but somehow it's happening even without the switch....( see .def file above )
This is how I do the build of the dll, and the test program as a batch file from the command line....
cl /nologo /Zi /EHsc /c Interface.cpp
rem TO make the .def file from the original .dll, with closest mangled names in obj file.
rem uncomment this line: python dll2def.py Interface.obj InterfaceA.dll
link /nologo /debug /DLL /def:Interface.def Interface.obj /NODEFAULTLIB:LIBCMT msvcrt.lib user32.lib atls.lib
cl /nologo /Zi /EHsc /c test.cpp
link /nologo /debug /map /mapinfo:exports test.obj Interface.lib
Yet, after I run the buld.bat script, shown above, test.exe shows ordinals: Which is NOT what I wanted.
dumpbin.exe /imports
Dump of file test.exe
File Type: EXECUTABLE IMAGE
Section contains the following imports:
Interface.dll
4303E0 Import Address Table
4301F4 Import Name Table
0 time date stamp
0 Index of first forwarder reference
Ordinal 13
Ordinal 12
KERNEL32.dll
430228 Import Address Table
43003C Import Name Table
0 time date stamp
0 Index of first forwarder reference
266 GetTickCount
3D0 SetEnvironmentVariableA
55 CompareStringW
D9 EnterCriticalSection
...
So: How do I explicitly get cl.exe or link to use the NAME even when ordinals are available?
Your .def file exports the function by both name and ordinal. Which is what you want for your DLL. So, the DLL that is produced is as you desire.
The problem is in the generated .lib file. The toolchain creates a .lib file that prefers to import by ordinal rather than name. That's not unreasonable since it is faster to do so. Given the choice of importing by ordinal or name, it picks the more efficient one.
So, your solution is to take charge of the creation of the .lib file. Call lib directly, after the main build, and pass it a modified .def file. Use the /def option of lib. The modified .def file removes the ordinals. This is the version of the .lib file that you wish to use when linking new code against the library.