我想一个简单的例的出口的一个函数从C++windows DLL。

我想看到的头,加拿大养恤金计划文件,并def文件(如果绝对必需的)。

我想出名 未装饰.我想使用的大多数标准的呼吁《公约》(__的?).我想用 声明影响(dllexport) 并不需要使用一个清晰的文件。

例如:

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

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

我试图避免的接头添加了下划线和/或号码(字节计数?) 的名称。

我确定不支持dllimport和dllexport使用同样的标题。我不想要任何信息的出口C++类方法,只要c式的全球职能。

更新

不包括呼吁公约》(和使用外部"C")给我出名字,因为我喜欢,但是这是什么意思?为什么默认的呼吁《公约》,我得到什么pinvoke(.净额),声明(维生素b6),并GetProcAddress会期待什么呢?(我猜GetProcAddress它将取决于功能的指针的呼叫者创建)。

我想这DLL可以使用没有标题的文件,所以我真的不需要很多花哨#定义做的头使用一个来电。

我确定一个答案是,我必须使用一个清晰的文件。

有帮助吗?

解决方案

如果你想纯C出口,使用C项目不是C ++。 C ++的DLL依靠名称重整为所有C ++主义(命名空间等)。您可以通过进入下C / C ++项目设置编译代码为C - >高级,有其cooresponds编译器开关选项“编译为” / TP和/ TC

导出/ VC中导入DLL利布斯++

你真正想做的是定义将被包括在所有的源文件在您的DLL项目中的头一个条件宏:

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

然后在要导出您使用LIBRARY_API功能:

LIBRARY_API int GetCoolInteger();

在您的库构建的项目创建一个定义LIBRARY_EXPORTS这将导致出口为您的DLL构建的功能。

由于LIBRARY_EXPORTS不会在项目消耗DLL,当项目包括您的库中的所有的功能的报头文件将被代替进口来限定。

如果你的库是跨平台的,你可以定义LIBRARY_API如无物时不能在Windows上:

#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的是出两者的推荐方法。

从C导出未重整功能++ DLL用于调用LoadLibrary / PInvoke的

如果您需要此使用LoadLibrary和GetProcAddress的,也许从.NET可以使用extern "C"在线与您DLLEXPORT做的PInvoke。而且,由于我们使用的,而不是dllimport的GetProcAddress的,我们不需要从上面做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 /出口:

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

其他提示

C++:

我只是面临相同的问题,我认为这是值得一提的一个问题是,当一个使用两个 __stdcall (或 WINAPI) extern "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" 是因为失去的符号是装饰(与_@字节)

注意这个 发生x86结构,因为 的 __stdcall 《公约》被忽略,在64(msdn : 在64架构,通过《公约》的论点是通过注册可能时,以及随后的参数是通过对栈.).

这是特别棘手的如果你的目标x86和64平台。


两个解决方案

  1. 使用定义的文件。但是,这迫使你保持国家的清文件。

  2. 最简单的方式:定义的宏(见 msdn) :

#define出的评论(接头,"/出口:"__功能__"=" __FUNCDNAME__)

然后包括以下说明在功能机构:

#pragma EXPORT

充满例子:

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

这将出口的功能未装饰用于x86和64目标,同时保留 __stdcall 《公约》x86。的 __declspec(dllexport) 是不是 需要在这种情况。

我完全相同的问题,我的溶液使用定义模块文件(.def),而不是的 __declspec(dllexport) 定义出口(http://msdn.microsoft.com/en-us/library/d91k01sh.aspx).我不知道为什么这一工作,但它不会

我觉得_naked可能会得到你想要的东西,但它也可以防止编译器生成的函数堆栈管理代码。为extern“C”导致空调风格名称修饰。删除这应该摆脱你_的的。链接器不会添加下划线,编译器。 STDCALL导致要附加参数堆栈大小。

有关详情,请参见: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

在更大的问题是,为什么你要这么做?有什么不对的错位的名字呢?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top