4
votes

I have some code which is working on Unix (Linux and Solaris) and Windows (7 to be exact) but doesn't work on Windows CE. This code implements a plug-in framework and requires exporting symbols from the executable into the loaded plug-ins. I am unable to get the loaded plug-ins (DLLs) to resolve symbols from the main executable.

I have reduced the interface to a single function in the main executable which is defined as such:

extern "C" __declspec( dllexport )
const char * translate_name( const char *key ) {
   ...
}

If I run Dumpbin /EXPORTS on the executable I see this as one of the exported symbols:

81   50 00001474 translate_name = @ILT+1135(_translate_name)

The plug-ins are required to export two functions xxxLoadPlugin and xxxUnloadPlugin which the main executable will call after loading to allow them to interconnect. The xxx is replaced with an agreed upon name prefix (usually the dll or .so name). I have a test project which creates:

extern "C" __declspec( dllexport ) int testRegisterLibrary( ) {
   return 0;
}

extern "C" __declspec( dllexport ) int testUnregisterLibrary( ) {
   return 0;
}

If I compile and run this module everything will work as expected. I can load the dll, and walk through the functions in my debugger.

If I add code which references translate_name, such as:

extern "C" __declspec( dllimport ) const char * translate_name( const char *key );

extern "C" __declspec( dllexport ) int testRegisterLibrary( ) {
   translate_name("test");
   return 0;
}

extern "C" __declspec( dllexport ) int testUnregisterLibrary( ) {
   return 0;
}

the DLL will now fail to load. Checking the created DLL with dumpbin /IMPORTS I see:

50 translate_name

translate_name is the only symbol imported from my main executable. If I try using GetProcAddress instead of relying on the linker, like this:

extern "C" __declspec( dllexport ) int testRegisterLibrary( ) {
   HMODULE mainModule = GetModuleHandle(NULL);   //handle for main executable
   void *ptr = (void *)GetProcAddress(L"translate_name");
   return 0;
}

extern "C" __declspec( dllexport ) int testUnregisterLibrary( ) {
   return 0;
}

The DLL loads, but the value of 'ptr' is NULL (checked inside a debugger). I've also tried GetProcAddressA("translate_name"), and using "_translate_name" with the same results.

Given this it seems that the symbols that were exported by the executable are not retained after the initial loader pass in windows CE. Again, this works in any normal windows environment. Is there some setting I'm missing for windows CE? Why can GetProcAddress not find a symbol in the executable which dumpbin says is exported? Are the symbols being hidden or dropped by the windows CE loader?

1

1 Answers

3
votes

Just to confirm your findings, this doesn't work. It is difficult to find hard evidence in the MSDN docs that this is not supported, other than that GetProcAddress() is adamant that the symbol must be exported by a DLL. You can't get the DLL loaded, it will fail with ERROR_BAD_EXE_FORMAT when it contains the import from the EXE. GetProcAddress() will always fail with ERROR_INVALID_HANDLE, even if you force the module handle to the EXE load address.

There's no strong evidence that the loader intentionally strips the export table of the EXE, it is resident in memory when you look with the debugger. It just categorically refuses to look at it.

You'll need to punt this problem and tackle this a different way. Beyond spinning off the helper functions in a separate DLL, an obvious workaround is that you provide the xxxLoadPlugin() entrypoint with an argument, a pointer to table of function pointers to the helper functions. The common IServiceProvider interface used in COM is a good approach.