Delphi记录和C结构体

3

任务:

Delphi编写的应用程序接受三个字段的结构体(Delphi术语中的record)。我可以使用SendMessage(Win32 API)函数发送此结构的指针。

因此,问题是:

如何在Delphi中维护某个结构的内存表示?

它具有类型

PWPModPostData = ^ TWPModPostData;
TWPModPostData = record
   DataType: Integer;
   Data: PChar;
   Next: PWPModPostData;
end;

如何在C语言中定义它?我的意思是,Delphi结构体中是否有任何隐藏或服务字段?

一个警告:根据使用的 Delphi 版本 (<= 2007 或 >= 2009),PChar 被定义为 PAnsiChar 或 PWideChar。更好的方法是:通过使用指针类型 PAnsiChar / PWideChar 指定您要使用的字符类型。 - Ritsaert Hornstra
2个回答

9

不,没有隐藏字段,Delphi记录和C结构可以一一映射,但需要注意以下几点:

  • 不要使用C不理解的任何数据类型。这包括对象、动态数组和Delphi字符串。

  • C和Delphi有时对字段的字节对齐方式有不同的想法。测试您的记录并验证它们在C端是否有效。如果无效,请尝试使用packed record而不是record

  • 当从C传递指向记录的指针到Delphi或反之亦然时,请确保接收方不会尝试释放或重新分配内存。它属于创建它的内存管理器。


谢谢。关于第二点,是否可以在C语言中使用类似于打包记录(未打包记录)的东西。Delphi应用程序应该关闭编辑甚至查看。 - Vasiliy Stavenko
我不确定在C语言中你的结构体打包选项是什么。尝试查看你的编译器文档。 - Mason Wheeler
Delphi编译器和C编译器都有各种选项和指示,用于控制记录或结构中的数据字段如何对齐。因此,为了实现互操作性,通常需要在代码中显式添加(在C代码中是作为一个指示,在Delphi中则是打包记录)。否则,我们将一直猜测使用哪些对齐规则。 - Ritsaert Hornstra

4
请注意,虽然您可以将此类结构的地址作为 SendMessage()LPARAM 发送到其他应用程序中,但很可能不起作用。原因是当在另一个带有自己地址范围的应用程序中使用时,同一指针通常不会指向相同的物理内存位置。
它适用于一些 Windows 消息,如 WM_GETTEXT,在这些情况下操作系统会在幕后做必要的映射,以便接收应用程序可以将数据复制到调用应用程序分配的缓冲区,并且地址在两个应用程序中指向相同的物理内存块。
可以通过使用旨在在两个应用程序之间进行数据交换时执行必要内存编组的 WM_COPYDATA 消息来实现相同的效果。
但是,在您的问题中,该结构具有另一个问题,因为它包含指向内存的指针。 WM_COPYDATA 文档明确指出不能这样做。虽然整个内存块的地址将被修改为在接收应用程序中有效,但系统无法知道内存块的哪些部分是指针并需要映射。因此,所有包含的指针将保持不变并且很可能无效。您的单向链表将被破坏,并且 PChar 元素也将无法访问。 编辑: 关于您的评论:上述观点仅在尝试从其他应用程序发送消息时才重要;如果您从 DLL 中执行此操作,则可以正常工作,因为 DLL 共享加载到其中的进程的地址空间,因此在应用程序或任何已加载的 DLL 中使用的指针将始终指向相同的内存位置。对于可能导致混淆的任何困惑,我感到抱歉,但是从您的问题中我无法确定数据交换发生在一个应用程序内部。

类似的程序,如果用Delphi编写,也能够正常工作。当我编译我的C应用程序(它是一个DLL)时,是否有任何内存管理限制标志可以使用?正如我在较高的帖子中所述,即使是查看Delphi应用程序的源代码也是不可用的。 - Vasiliy Stavenko
顺便问一下,你所写的有关从目标应用程序加载 DLL 并调用函数时不同内存分配的内容是否正确? - Vasiliy Stavenko
无论如何,您提供的信息都非常有用。非常感谢您指出这个问题。 - Vasiliy Stavenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接