42

In a project using a server.dll and a client.exe, I have dllexported a server symbol from the server dll, and not dllimported it into the client exe.

Still, the application links, and starts, without any problem. Is dllimport not needed, then???

Details:

I have this 'server' dll:

// server.h
#ifdef SERVER_EXPORTS
  #define SERVER_API __declspec(dllexport)
#else
  #define SERVER_API // =====> not using dllimport!
#endif
class  SERVER_API CServer {
   static long s;
   public:
   CServer();
};

// server.cpp
CServer::CServer(){}

long CServer::s;

and this client executable:

#include <server.h>
int main() {
   CServer s;
}

The server command line:

cl.exe /Od  /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" 
 /D "SERVER_EXPORTS" /D "_UNICODE" /D "UNICODE" /D "_WINDLL" 
 /Gm /EHsc /RTC1 /MDd /Yu"stdafx.h" 
 /Fp"Debug\server.pch" /Fo"Debug\\" /Fd"Debug\vc80.pdb" 
 /W3 /nologo /c /Wp64 /ZI /TP /errorReport:prompt

cl.exe /OUT:"U:\libs\Debug\server.dll" /INCREMENTAL:NO /NOLOGO /DLL 
/MANIFEST /MANIFESTFILE:"Debug\server.dll.intermediate.manifest" 
/DEBUG /PDB:"u:\libs\Debug\server.pdb" 
/SUBSYSTEM:WINDOWS /MACHINE:X86 /ERRORREPORT:PROMPT 
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib 
shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib

Client command line:

cl.exe /Od /I "..\server" 
 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" 
 /Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc80.pdb" /W3 /c /Wp64 /ZI /TP 
 .\client.cpp

cl.exe /OUT:"U:\libs\Debug\Debug\client.exe" /INCREMENTAL 
/LIBPATH:"U:\libs\Debug" 
/MANIFEST /MANIFESTFILE:"Debug\client.exe.intermediate.manifest" 
/DEBUG /PDB:"u:\libs\debug\debug\client.pdb" 
/SUBSYSTEM:CONSOLE /MACHINE:X86 
server.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib 
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
xtofl
  • 39,598
  • 12
  • 100
  • 188
  • @OrangeDog: right: copy-paste-replace error. Corrected that. – xtofl Dec 20 '10 at 12:13
  • 1
    Good question actually. the MSDN Docs --- http://msdn.microsoft.com/en-us/library/3y1sfaz2(VS.80).aspx --- didn't enlighten me if there's any benefit over using `extern` (with correct calling convention and name mangling) and specifying an import library. – peterchen Dec 20 '10 at 14:31
  • 3
    `__declspec(dllexport)` on classes and class members is very, **very** *fragile*. What is the purpose of the separate server.dll? Really the only thing `__declspec(dllexport)` on a class does well is reducing process startup I/O, when it is paired with `/delayload:server.dll`. Any other perceived advantages (e.g. imagined ability to patch DLL logic without recompiling the application) are actually violations of the One-Definition-Rule and unreliable. – Ben Voigt Dec 20 '10 at 14:38
  • @Ben Voigt: you surprise me. That's a different discussion, really. But the intent here is to decouple code into a gazillion of libraries, an not all 'server' libraries are needed by all 'client' libraries. – xtofl Dec 20 '10 at 14:56
  • 3
    @xtofl: Decoupling is good, and the source code may in fact be decoupled. But `__declspec(dllexport)` on classes and class members causes the *binaries* to be closely coupled. In other words, you'd have the same level of coupling, with much less deployment burden, by using static libraries and no `__declspec(dllexport)` anywhere. – Ben Voigt Dec 20 '10 at 14:58
  • @Ben Voigt, what about memory footprint if your library is large and is used by 7 different applications running together? Not to mention that such really large library as Qt actually exports classes and evolves while preserving complete binary compatibility (not to say it's easy). – Sergei Tachenov Dec 20 '10 at 15:30
  • 3
    @Sergey: You'd be better off by having all code within a single .DLL module, exporting only plain C functions corresponding to the `main` function for each of the 7 applications (or even arguments to a single .exe, ala *busybox*). On Windows at least, which is the platform we're discussing here, Qt does not provide binary compatibility. You have to build the Qt library yourself using the particular compiler and command-line options used by your application, in order to avoid violating ODR. In which case you again might as well be using a static library. – Ben Voigt Dec 20 '10 at 15:57
  • I really hate this hate talk about windows dll, and violating one def rule bullshit. This isnt academic java or c++ by maniac Strauss. Instead it is highly efficientized and flexible windows os specific developed. Windows can do a bunch of stuff c++ or linux can't. And now in past years because of your complaining and sense the founding fathers of winxp/nt have moved on you people are gaining leverage and changing it to yet another Linux. Like all this smart pointer nonsense and the new c++ standards. Windows doesnt have to conform to the srandards, and it not doing so has lead to inovation – marshal craft Jul 25 '17 at 13:14
  • Which has bebefited everyone willing to use them. You never had to Close shit or delete non class things cause the os specific compiler could handle that, but now because strauss and his c++ bullshit have changed that in recent years and now I have memory leaks everywhere. I suppose you say that's the way it's always been but it hasnt. – marshal craft Jul 25 '17 at 13:17
  • 1
    @marshalcraft this is not a blog - save your rants for elsewhere. Please :). – xtofl Jul 26 '17 at 13:32
  • @xtofl, and saying how dlls are bad etc, isnt ranting? Obviously they aren't. – marshal craft Jul 26 '17 at 19:20

2 Answers2

55

It isn't required. It is an optimization, a hint to the compiler that the DLL is going to export the function pointer directly rather than just an entry in the IAT of the DLL. The exported function pointer for a function named foo() will be __imp_foo. Which allows it to generate better code, saving a function pointer load from the IAT and an indirect jump. It is a time optimization, not space.

This blog post has the details.

Hans Passant
  • 897,808
  • 140
  • 1,634
  • 2,455
  • 5
    From the linked article: For data, it is required for correctness. – Ben Voigt Dec 20 '10 at 14:43
  • Thanks! You pointed to the right blog post. Your phrasing is a bit confusing, though - I thought that the _importing_ source would result in a call to the `__imp_foo` thunk in the _importing_ code. – xtofl Dec 20 '10 at 14:45
0

I was wondering about this too. I also removed the __declspec(dllimport) instruction and was very surprised to see that a dll (gmodule) relying on functions in another dll (glib) compiled and ran (in wireshark in particular) without problems. Here's a quote by MS:

__declspec(dllimport) is ALWAYS required to access exported DLL data.

No idea why MS says this, because on other pages they state the instruction is not necessary. Regardless, not only does my library run without dllimport, but I haven't seen an "__imp" symbol in ages, while formerly I was constantly stumbling upon it (or it on me). What happened to it? The answer is here:

That's why using __declspec(dllimport) is better: because the linker doesn't generate a thunk if it's not required. There's no thunk and no jmp instruction, so the code is smaller and faster. You can also get the same effect WITHOUT __declspec(dllimport) by using whole program optimization. For more information, see /GL (Whole Program Optimization).

Now it makes sense. I am using /GL (+ /LTCG) on all projects. So that's the answer to the topic question

when is __declspec( dllimport ) not needed?

When whole program optimization is utilised.

WRFan
  • 73
  • 1
  • 2