帮助在 Delphi 中为 C 构建一个 Dll

Posted

技术标签:

【中文标题】帮助在 Delphi 中为 C 构建一个 Dll【英文标题】:Help building a Dll for C in Delphi 【发布时间】:2010-10-04 14:41:36 【问题描述】:

我之前曾向 another questions 询问过关于构建我的 dll 的问题,但它看起来像是朝着错误的方向 :) 所以我重新制定并解释了更多她。

所以我试图构建的是一个 dll,它将作为我的 delphi 程序和其他人的 C 程序之间的接口。

这个 dll 必须做的是从 C 程序接收一个字符串,然后将它发送到 delphi 程序,在那里它将与一些数据组合并存储在我程序的当前用户下。

如何在我的 Delphi 程序(运行程序)中调用方法来存储来自 dll 的消息?

我正在使用 Delphi 5。 这是我到目前为止得到的:

DLL:

//Parent application: MyDelphiApp   
library MyDllLink; 

uses
  ShareMem,
  SysUtils,
  Classes,
  Dialogs,
  Main;// Main is a form from my delphi app. This is not allowed/recomended ?

$R *.RES


procedure Transfer(sMessage: PChar); stdcall;
begin
    try
        //If including Main in the uses clause, then this will also be wrong:
        MainForm.StoreDllMessage(sMessage);
    except
        showmessage('Error');
    end;    
end;

exports
Transfer;

end.

德尔福应用:

procedure TMainForm.StoreDllMessage(sMessage: String);
begin
    //StoreMessage just stores it in a DB
    StoreMessage(sMessage +' '+sCurrentUserName);
end;

【问题讨论】:

【参考方案1】:

我可能理解错了,但您似乎希望 C 程序和 Delphi 程序同时加载相同的 DLL 副本。你不能做到这一点,只能通过涉及进程间通信的大量工作来真正实现它。应用程序将具有单独的进程空间和内存。

我会建议一种稍微不同的方法。在 DLL 中有一个名为 SendStringFromCApp 的函数和一个名为 GetStringIntoDelphiApp 的函数(或其他合适的)。

C 程序将正常加载 DLL 的副本并调用 SendStringFromCApp 函数。该函数会将传入的数据以一些常见的中间格式(例如简单的数据库)进行存储。它将存储视为一种队列,并简单地将数据添加到该队列中。数据库是最明显的选择,但它可以像普通目录一样简单,并且数据存储为小文本文件,文件名是递增的整数。

Delphi 程序将加载它自己的 DLL 副本并调用 GetStringIntoDelphiApp,它将从队列/内部存储中读取第一项并根据需要对其进行处理,然后将其从存储中删除。然后它将读取下一个等。

这样做的好处是 C 和 Delphi 应用程序都可以独立运行。只有 DLL 需要一个通用配置,即使 Delphi 应用程序没有运行,C 程序也可以继续工作,反之亦然。

它基本上是一个用于不同进程的生产者-消费者排队系统。

就像我说的,我可能误解了要求!

【讨论】:

它需要“立即”发生,所以这种方法对我根本不起作用。 C 应用程序发送的信息需要存储在数据库中的哪个位置,经常变化,因此这种延迟会导致数据存储在错误的位置。 很公平。在这种情况下,我会考虑使用来自 C 应用程序(或通过 DLL)的 Windows WM_COPYDATA 消息发布到您的 Delphi 应用程序。在这种情况下,只有 C 应用程序需要访问 DLL。尝试在进程之间共享 DLL 是行不通的。【参考方案2】:

对于最简单的 IPC,请尝试使用 PostMessage 或 SendMessage 的 WM_COPYDATA 微软文档:http://msdn.microsoft.com/en-us/library/ms649011%28VS.85%29.aspx

微软示例:http://msdn.microsoft.com/en-us/library/ms649009%28v=VS.85%29.aspx

还有更多关于谷歌的信息:http://www.google.com/search?q=WM_COPYDATA&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:pt-BR:official&client=firefox-a

【讨论】:

我正在尝试使用 WM_Copydata,但在我的 delphi 应用程序中注册消息时遇到问题,所以今天晚些时候可能会弹出另一个问题 :) 好吧,你不需要注册消息,只需要找到目标HWND并发送它。 WM_COPYDATA 消息将到达目标消息队列。【参考方案3】:

尝试实现 IPC(进程间通信)。您将有 3 个独立的进程。

    Delphi exe C 程序 非窗口进程(com 服务、exe、...)

使用非窗口作为服务器,其他2个是客户端。 Delphi 中的 IPC 参见this,C 中的 IPC 参见this。有很多方法可以实现 IPC。如果你在你最喜欢的搜索引擎中寻找 IPC,我很确定你会找到一种为 C 和 Delphi 进行 IPC 的常用方法,因为它只是一些 win32 api 芭蕾。

【讨论】:

由于我不打算对 C 部分进行编程,因此使用这种方法很复杂。 还有一个由 C 程序调用的 dll 接收字符串的情况。而那个 dll 单独通过 IPC 与 Delphi 程序进行通信。在两个 delphi 进程之间,使用这些组件 'home.roadrunner.com/~rllibby/source.html' 进行 IPC 非常容易,去那里寻找 'pipes.zip'。您将拥有一个 TPipeServer 和一个 TPipeClient【参考方案4】:

正如 loursonwinny 所说,IPC 是必经之路。 您应该了解每个 DLL 都是在单个应用程序的地址空间中加载的。因此,Delphi 和 C 应用程序使用的 DLL 将在内存中存在两次。 (嗯,不完全,代码部分是共享的,DLL 中的所有数据都存在两次。)所以基本上你的 DLL 不能简单地在两个进程之间共享数据。 当然,也有例外。例如,可以在加载到 Delphi 应用程序中的单个 DLL 中创建键盘挂钩,然后将其注入到 C 进程的地址空间中。然后,DLL 可以“窥视”C 应用程序的内存空间并捕获一些信息。 (带有 KeyHooks 的键盘事件。)但是 KeyHooks 和类似的可注入 DLL 会被一般的防病毒产品视为“坏”。并且有充分的理由,因为这是计算机病毒所期望的行为。 替代 IPC 的另一种解决方案是使用memory mapped file。有几个组件可作为开源或商业使用,但您也可以使用 Windows API 来创建这些组件。 Windows API 还提供了命名管道和邮件槽等技术,它们也可用于进程间通信。它不需要是 TCP/IP,但您需要某种方式让两个进程相互通信。而且这个逻辑确实可以构建在单个 DLL 中,您只需在其中定义两个方法。一个用于服务器,一个用于客户端。不过,这是一项复杂的技术。而且 Delphi 5 有点老了,所以我不知道哪种解决方案最适合您。

【讨论】:

【参考方案5】:

DLL 必须回调到 Delphi 程序。当 Delphi 程序启动时,它会注册一个回调函数。这样 DLL 就知道当它被 C 程序调用时要调用什么。

示例: http://delphi.about.com/od/windowsshellapi/a/callback_delphi.htm 此示例使用回调来允许 Windows API 回调到您的 delphi 应用程序。这里的想法相同,但您将由您自己的 DLL 调用,而不是 Windows API。

【讨论】:

以前从未使用过回调,将研究它。如果您有任何教程,请随时链接到一些教程:) @Shunty 是对的——内存模型不起作用。即 C 程序将调用 DLL 的另一个实例,而不是附加到您的应用程序的实例。最好让 DLL 向您发送 WM 消息,写入简单的数据库,使用邮槽等。 对,每个程序都会为dll分配不同的内存空间,c程序推送数据时不会触发从Delphi注册的回调...

以上是关于帮助在 Delphi 中为 C 构建一个 Dll的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Delphi 代码调试 VC++ 中构建的 DLL 文件?

在 C# 中为 p/invoke 创建一个基本的 C++ .dll

使用 Delphi 编写 Windows 集群资源 DLL

delphi 调用 c语言 dll

delphi调用dll函数 字符串参数

Delphi 的 64 位 DLL c/c++ 接口