Export functions from a DLL using dllexport

I need a simple example of exporting a function from a C ++ windows dll.

I would like to see the header, cpp file and def file (if absolutely necessary).

I would like the exported name to be undecorated . I would like to use the most standard calling convention (__stdcall?). I would like to use __ declspec (dllexport) and not use the DEF file.

For example:

//header extern "C" { __declspec(dllexport) int __stdcall foo(long bar); } //cpp int __stdcall foo(long bar) { return 0; } 

I am trying to avoid the linker of the added underscores and / or numbers (bytes?) In the name.

I'm fine, not supporting dllimport and dllexport using the same header. I do not need information about exporting C ++ class methods, as well as global c-style functions.

UPDATE

Not including the calling convention (and using extern "C") gives me the export names as I like, but what does that mean? Is any default convention by default I get what pinvoke (.NET), declare (vb6) and GetProcAddress will expect? (I think for GetProcAddress this will depend on the function pointer created by the caller).

I want this DLL to be used without a header file, so I really don't need a lot of fantastic #defines for the header to be used by the caller.

I am fine with the answer that I need to use a DEF file.

+72
dll visual-c ++ winapi
Feb 11 '09 at 18:28
source share
4 answers

If you need a simple C export, use a C project, not C ++. C ++ DLLs rely on name processing for all CMS names (namespaces, etc.). You can compile your code as C by going to your project settings in the C / C ++ → Advanced section, there is the “Compile As” option, which coordinates the compiler keys / TP and / TC.

Export / Import DLLs in VC ++

What you really want to do is define a conditional macro in the header that will be included in all the source files in your DLL project:

 #ifdef LIBRARY_EXPORTS # define LIBRARY_API __declspec(dllexport) #else # define LIBRARY_API __declspec(dllimport) #endif 

Then for the function you want to export, you use LIBRARY_API :

 LIBRARY_API int GetCoolInteger(); 

In the library assembly project, create define LIBRARY_EXPORTS , this will cause your functions to be exported for your DLL assembly.

Since LIBRARY_EXPORTS will not be defined in a project using the DLL when this project includes your library header file, all functions will be imported instead.

If your library needs to be cross-platform, you can define LIBRARY_API as nothing if not on Windows:

 #ifdef _WIN32 # ifdef LIBRARY_EXPORTS # define LIBRARY_API __declspec(dllexport) # else # define LIBRARY_API __declspec(dllimport) # endif #elif # define LIBRARY_API #endif 

When using dllexport / dllimport you do not need to use DEF files, if you use DEF files you do not need to use dllexport / dllimport. The two methods perform the same task in different ways, I think dllexport / dllimport is the recommended method of the two.

Export non-confused functions from C ++ DLL for LoadLibrary / PInvoke

If you need to use LoadLibrary and GetProcAddress, or possibly make PInvoke from .NET, you can use the extern "C" inline with your dllexport. And since we use GetProcAddress instead of dllimport, we do not need to make an ifdef tank on top, just a simple dllexport:

The code:

 #define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport) EXTERN_DLL_EXPORT int getEngineVersion() { return 1; } EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) { K.getGraphicsServer().addGraphicsDriver( auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver()) ); } 

And this is what export looks like with Dumpbin / exports:

  Dump of file opengl_plugin.dll File Type: DLL Section contains the following exports for opengl_plugin.dll 00000000 characteristics 49866068 time date stamp Sun Feb 01 19:54:32 2009 0.00 version 1 ordinal base 2 number of functions 2 number of names ordinal hint RVA name 1 0 0001110E getEngineVersion = @ILT+265(_getEngineVersion) 2 1 00011028 registerPlugin = @ILT+35(_registerPlugin) 

So this code works fine:

 m_hDLL = ::LoadLibrary(T"opengl_plugin.dll"); m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>( ::GetProcAddress(m_hDLL, "getEngineVersion") ); m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>( ::GetProcAddress(m_hDLL, "registerPlugin") ); 
+103
Feb 11 '09 at 18:39
source share

For C ++:

I ran into the same problem and I think it's worth mentioning that the problem occurs when you use both __stdcall (or WINAPI ) and extern "C" :

As you know, extern "C" removes the decor so that instead of:

 __declspec(dllexport) int Test(void) --> dumpbin : ?Test@@YaHXZ 

you will get the unecorated symbol name:

 extern "C" __declspec(dllexport) int Test(void) --> dumpbin : Test 

However, _stdcall (= the WINAPI macro, which changes the calling convention) also decorates the names, so if we use both, we get:

  extern "C" __declspec(dllexport) int WINAPI Test(void) --> dumpbin : _Test@0 

and the extern "C" advantage is lost because the character is decorated (using _ @bytes)

Note that this only happens for the x86 architecture, because the __stdcall ignored on x64 ( msdn : by convention x64, by convention, arguments are passed to registers whenever possible, and subsequent arguments are passed to the stack.).

This is especially difficult if you focus on x86 and x64 platforms.




Two solutions

  • Use the definition file. But it makes you maintain the state of the def file.

  • The easiest way: define a macro (see msdn ):

#define Comment EXPORT (linker, "/ EXPORT:" __FUNCTION__ "=" __FUNCDNAME __)

and then include the following pragma in the function body:

 #pragma EXPORT 

Full example:

  int WINAPI Test(void) { #pragma EXPORT return 1; } 

This will export the unecorated function for x86 and x64 targets, while maintaining the __stdcall for x86. In this case, __declspec(dllexport) not required.

+11
Jan 28 '17 at 13:40
source share

I had exactly the same problem, my solution was to use a file definition file (.def) instead of __declspec(dllexport) to determine the export ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). I don't know why this works, but he does

+3
Sep 23 '13 at 14:34
source share

I think _naked may get what you want, but it also prevents the compiler from generating stack control code for this function. extern "C" causes the decoding of the style name C. Remove this and this should get rid of your _. The compiler does not add underscores. stdcall causes the size of the argument stack to be added.

For more details see http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

The big question is why do you want to do this? What happened to the distorted names?

-one
Feb 11 '09 at 18:40
source share



All Articles