为什么/何时不需要 __declspec( dllimport )?
在使用 server.dll 和 client.exe 的项目中,我从服务器 dll 中 dllexport
导出了服务器符号,并且没有 dllimport
将其编辑到客户端 exe 中。
尽管如此,应用程序仍然可以链接并启动,没有任何问题。那么是不是就不需要dllimport
了???
详细信息:
我有这个“服务器”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;
和这个客户端可执行文件:
#include <server.h>
int main() {
CServer s;
}
服务器命令行:
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
客户端命令行:
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
In a project using a server.dll and a client.exe, I have dllexport
ed a server symbol from the server dll, and not dllimport
ed 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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
__declspec(dllimport)
是一个客户端 MSVC 属性,可以为导入的代码和数据指定。代码不需要它。这是一种优化;客户端编译器提示函数调用不是直接的而是导入的。名为
foo()
的函数的导入函数指针将为__imp_foo
。如果没有提示,则会创建一个 thunk 来加载__imp_foo
中的地址并跳转到该地址。通过提示,将跳过 thunk,并生成通过 IAT1 条目的间接调用,即内联 thunk。这是时间优化,而不是空间优化。从 DLL 导入的数据需要它。
这个 博客文章有详细信息。
1:程序导入地址表
__declspec(dllimport)
is a client-side MSVC attribute that can be specified for imported code and data.It isn't required for code. It is an optimization; a client-side compiler hint that a function call isn't direct but imported. The imported function pointer for a function named
foo()
will be__imp_foo
. Without the hint, a thunk is created to load the address in__imp_foo
and jump to it. With the hint the thunk is skipped and an indirect call through the IAT1 entry is generated i.e. the thunk is inlined. It is a time optimization, not space.It's required for data that's imported from a DLL.
This blog post has the details.
1: Import Address Table of a program
我也想知道这个问题。我还删除了 __declspec(dllimport) 指令,并且非常惊讶地发现依赖于另一个 dll (glib) 中的函数的 dll (gmodule) 编译并运行(特别是在wireshark 中)没有问题。这是 MS 的引用:
不知道为什么 MS 这么说,因为在其他页面上他们声明该指令是不必要的。无论如何,我的库不仅在没有 dllimport 的情况下运行,而且我已经很多年没有看到“__imp”符号了,而以前我经常偶然发现它(或者它在我身上)。这是怎么回事?答案就在这里:
现在说得通了。我在所有项目中都使用 /GL (+ /LTCG)。 的答案。
这就是主题问题“当使用整个程序优化时”
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:
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:
Now it makes sense. I am using /GL (+ /LTCG) on all projects. So that's the answer to the topic question
When whole program optimization is utilised.