【问题标题】:Creating a DLL from existing (but old) sample code从现有(但旧的)示例代码创建 DLL
【发布时间】:2018-05-31 14:41:50
【问题描述】:

我对创建 DLL(或编译器设置)的代码有疑问。

我正在尝试创建一个 DLL,作为在 Windows 64 下运行的软件包 (ZEMAX) 的扩展 - 尽管该软件是旧的 (2005) - 升级它的成本 > 5000 美元,而且它工作正常,所以它值得尝试。

软件 (ZEMAX) 使用 dll 文件来扩展它的功能,并期望这些 DLL 具有给定的函数,这些函数接受给定的参数并返回给定的值。给出了示例代码,我可以将其编译为 DLL,但软件找不到函数。

示例代码由 ZEMAX 提供,我对其进行了少量修改。我想创建four_angle.dll。示例代码中的关键行(全部在 C# 中,我不想全部重写)是:

int __declspec(dllexport) APIENTRY UserParamSourceDefinition(double *data);
int __declspec(dllexport) APIENTRY UserParamNames(char *data);

BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
    return TRUE;
}

以后

int __declspec(dllexport) APIENTRY UserParamNames(char *data)
{
    strcpy_s(data[1],16,'hello');
}

int __declspec(dllexport) APIENTRY UserSourceDefinition(double *data)
{
    data[30] = (double)data[2] + 1.0;
}

Visual Studio 编译时没有错误。在运行时加载 DLL 的软件是否无法调用这些函数?我是制作 dll 的新手,所以我不知道 DLLMain 的这些定义语句和选项是如何工作的。

PS - 我注意到 Visual Studio 还创建了一个 DLLmain,我将其注释掉,因为您不能定义两次。同样,我只知道它是如何工作的,以及我是否打算填写一些案例陈述。

#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

PPS 我一直按照这里的说明进行操作 - 但没有运气:http://customers.zemax.com/os/resources/learn/knowledgebase/how-to-compile-a-user-defined-surface.aspx

【问题讨论】:

  • 它是特定于操作系统的。你可能需要一些winapiwindows 标签
  • APIENTRY 是如何定义的?什么是编译器/链接器选项?你检查调用约定吗?
  • 您可以使用dependency walker查看函数是如何导出的,并与现有的Zemax插件进行比较
  • 作为 DLL 新手,我不确定调用过程如何在 Windows 上工作。至于 APIENTRY,我想我遇到了一些说它是 WINAPI 的别名
  • 至于编译器选项,我可能错过了很多(作为一个 gui 系统),但我按照网页下方的步骤进行操作,我放了一个链接:

标签: c dll compilation


【解决方案1】:

考虑到:

  • WINAPIAPIENTRY 都只是 #defines 到 __stdcall
  • 根据Dependency WalkerUserParamNames函数由.dll版本导出:
    • 作品:_UserParamNames@4
    • 不起作用:如?UserParamNames@@YGHPAD@Z

以下结论出现:

  • 代码被编译(和函数导出)为C++(检查[MSDN]: Decorated Names
  • 目标架构是 32 位(Win32x86

我只是在这里推测,但很可能您将函数定义放在 .cpp 文件中(默认编译为 C++)。

为了解决您的问题,请将您的函数导出为 C。您的 1st 代码 sn-p 已修改(您必须对每个有此问题的函数执行相同操作)。您可以按照以下方式进行操作,也可以为每个功能单独添加extern "C"

#if defined(__cplusplus)
extern "C" {
#endif

    __declspec(dllexport) int APIENTRY UserParamSourceDefinition(double *data);
    __declspec(dllexport) int APIENTRY UserParamNames(char *data);

#if defined(__cplusplus)
}
#endif

有关更多详细信息(信息、代码、资源),请查看:

【讨论】:

  • 非常感谢所有提供帮助的人,dependancy walker 非常了解 - 将 Visual Studio 中的文件名更改为以 .c 而不是 .cpp 结尾是关键 - 仍然存在一些运行时错误但我想我已经有了这些,我也选择了 win32(sys) 作为构建选项(而不是 win32)
  • 是的,这是一个选项,并在第三个 URL(我刚刚添加)中进行了解释,您可以在那里查看您可以在不更改文件名的情况下更改编译标志,但是 extern "C"变体无论如何都可以工作(这是最通用的)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 2023-03-29
  • 1970-01-01
  • 2017-10-25
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多