使用dllexport从DLL导出函数

2024-03-29 13:43:45 发布

您现在位置:Python中文网/ 问答频道 /正文

<>我想从C++ Window DLL导出函数的一个简单例子。

我想查看头文件、.cpp文件和.def文件(如果绝对需要)

我希望导出的名称是未修饰的。我想使用最标准的调用约定(__stdcall?)。我希望使用__declspec(dllexport),而不必使用.def文件

例如:

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

  //cpp
  int __stdcall foo(long bar)
  {
    return 0;
  }

我试图避免链接器在名称中添加下划线和/或数字(字节计数?)

我同意不支持使用相同的头的dllimportdllexport。我不想导出任何关于C++类方法的信息,只是C风格的全局函数。

更新

不包括调用约定(并使用extern "C")会给我提供我喜欢的导出名称,但这意味着什么?我得到的默认调用约定是pinvoke(.NET)、declare(vb6)和GetProcAddress所期望的吗?(我猜对于GetProcAddress,它将取决于调用方创建的函数指针)

我希望这个DLL不用头文件就可以使用,所以我不需要太多花哨的#defines来使调用程序可以使用头文件

我同意的答案是我必须使用*.def文件


Tags: 文件函数名称foo头文件defbarextern
3条回答
< > >强> C++:< /强>

我刚刚遇到了同样的问题,我认为值得一提的是,当同时使用__stdcall(或WINAPIextern "C"时,会出现一个问题:

如您所知extern "C"移除装饰,以代替:

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

您将获得一个未装饰的符号名称:

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

但是_stdcall(=宏WINAPI,它改变了调用约定)也修饰了名称,因此如果我们同时使用这两个名称,我们可以获得:

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

而且extern "C"的好处也失去了,因为符号被修饰(用@bytes)

Note that this only occurs for x86 architecture because the __stdcall convention is ignored on x64 (msdn : on x64 architectures, by convention, arguments are passed in registers when possible, and subsequent arguments are passed on the stack.).

如果同时针对x86和x64平台,这一点尤其棘手


两种解决方案

  1. 使用定义文件。但这会迫使您维护def文件的状态

  2. 最简单的方法:定义宏(请参见msdn):

#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)

然后在函数体中包含以下pragma:

#pragma EXPORT

完整示例:

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

这将导出x86和x64目标的未修饰函数,同时保留x86的__stdcall约定。在这种情况下__declspec(dllexport)不是必需的

如果您想要纯C导出,请使用C项目而不是C++。C++ DLL依赖于所有C++(命名空间等)的名称篡改。通过进入C/C++->;下的项目设置,可以将代码编译为C;高级,有一个选项“compileas”,它对应于编译器开关/TP和/TC

如果你仍然想用C++来编写你的LIB内部,但是导出一些未被使用的函数,以供C++使用,请参阅下面的第二部分。p>

在VC中导出/导入DLL库++

您真正想要做的是在头中定义一个条件宏,该头将包含在DLL项目中的所有源文件中:

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

然后在要导出的函数上使用LIBRARY_API

LIBRARY_API int GetCoolInteger();

在库构建项目中,创建一个defineLIBRARY_EXPORTS,这将导致为DLL构建导出函数

由于LIBRARY_EXPORTS不会在使用DLL的项目中定义,因此当该项目包含库的头文件时,将导入所有函数

如果您的库是跨平台的,您可以在不在Windows上时将库API定义为“无”:

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

使用dllexport/dllimport时不需要使用DEF文件,如果使用DEF文件,则不需要使用dllexport/dllimport。这两种方法以不同的方式完成相同的任务,我相信dllexport/dllimport是这两种方法中推荐的方法

< H2>从C++ DLL导出未加载的函数,用于LoopReals/pPoECKE/H2>

如果您需要使用LoadLibrary和GETPROCEDURE,或者可能从另一种语言(即,PInvoke .NET,或Python /R中的FFI)导入,则可以使用与您的DLExcel内联的^ {CD4>}来告诉C++编译器不要修改名称。由于我们使用的是GetProcAddress而不是dllimport,因此不需要从上面跳ifdef舞,只需一个简单的dllexport:

守则:

#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())
  );
}

下面是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)

因此,这段代码可以很好地工作:

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")
);

我遇到了完全相同的问题,我的解决方案是使用模块定义文件(.def)而不是__declspec(dllexport)来定义导出(http://msdn.microsoft.com/en-us/library/d91k01sh.aspx)。我不知道为什么会这样,但确实如此

相关问题 更多 >