在Delphi中编写64位接口

时间:2014-10-16 08:31:15

标签: delphi interface 32bit-64bit

我在Delphi中写了.pas 32bit DLL接口,如下所示:

的用途:

 {$IFDEF WIN32}
 Windows;
 {$ELSE}
 Wintypes, WinProcs;
 {$ENIF}

接口:

function PI_InterfaceSetupDlg(const szRegKeyName: PChar): LongInt cdecl  {$IFDEF WIN32} stdcall {$ENDIF}; 

实现:

function PI_InterfaceSetupDlg; external 'PI_GCS2_DLL.DLL';

它可以在32位Widnows上运行,但是我必须为64位写这样的东西,我有64位dll,但我不知道它必须使用哪些Windows组件以及如何为64位声明函数。 64位Windows是否使用stdcall?我必须使用什么样的变量?

对不起混乱的帖子,我是Stack的新手。

1 个答案:

答案 0 :(得分:8)

tl; dr 您的主要问题是您将16位文本传递给期望8位文本的函数,因为您已升级Delphi并且PChar的含义已更改。 / p>


首先,您可以忘记WinTypesWinProcs。这些可以追溯到16位Delphi。您肯定没有在Delphi 1上进行编译,因此请将第一个代码块更改为:

uses
  Windows;

在32位Windows上,有多种可用的调用约定。 Delphi支持stdcallcdeclregistersafecall。其中safecall用于COM,register是基于Delphi特定寄存器的调用约定。因此,对于互操作,选择归结为stdcallcdecl

在64位Windows上,只有一个调用约定,编译器只是忽略了您调用约定的任何规范。如果您的32位代码使用cdecl,则该函数的声明应为:

function PI_InterfaceSetupDlg(szRegKeyName: PChar): LongInt; cdecl;

此声明可用于32位和64位版本。编译64位时,编译器会忽略cdecl

同样,如果32位代码使用stdcall,则声明应为:

function PI_InterfaceSetupDlg(szRegKeyName: PChar): LongInt; stdcall;

您应该记住的一个目标是,您应该努力不需要条件代码来切换32位和64位之间的行为。 64位Windows和Delphi 64位编译器的设计经过深思熟虑,这个目标是可以实现的。

绝大多数数据类型在32位和64位上完全相同。例如,Integer是两个平台上的带符号32位整数。指针明显不同,但语义完全相同。因此,如果在32位上使用PChar,则在64位上也使用PChar

不同平台之间差异很大的一种类型是NativeInt。它在32位上为32位宽,在64位上为64位宽。其无符号对应NativeUInt的行为方式相同。这些类型名称很差。它们实际上只是指针大小的整数,在我看来,应该命名为IntPtrUIntPtr。这些类型通常用于声明句柄。这是表示不透明指针的整数类型。您可能会发现NativeInt用于Windows句柄类型。这不是声明这些类型的唯一方法,而且很容易认为type Pointer会是更好的选择。

如果您想了解互操作如何与32位和64位平台进行交互,请阅读Windows单元。你会在那里找到很少的条件代码。


PI_InterfaceSetupDlg的网络搜索显示了这一点:

long PI_FUNC_DECL PI_InterfaceSetupDlg(const char* szRegKeyName);

这意味着该函数接受8位文本。在您的Delphi版本(包含64位编译器的版本)中,PCharPWideChar的别名。这是16位文本。所以你需要明确并使用PAnsiChar。因此,尽管您声明您的代码在32位下运行,但事实并非如此。我的猜测是你最初在旧版本的Delphi上开发了代码,其中PCharPAnsiChar的别名。

至于调用约定,您需要了解PI_FUNC_DECL如何扩展。它在这里定义:

#ifdef WIN32
    #undef PI_FUNC_DECL
    #ifdef PI_GCS2_DLL_STATIC
        #define PI_FUNC_DECL WINAPI
    #else
        #ifdef PI_DLL_EXPORTS
            #ifndef UNKNOWN_GCS_DLL
                #define PI_FUNC_DECL __declspec(dllexport) WINAPI
            #else
                #define PI_FUNC_DECL WINAPI
            #endif
        #else
            #define PI_FUNC_DECL __declspec(dllimport) WINAPI
        #endif
    #endif
#else
    #define PI_FUNC_DECL
#endif

可以看出,在Windows上,调用约定为WINAPI,这是一个扩展为__stdcall的宏。因此,最终的Delphi声明是:

function PI_InterfaceSetupDlg(szRegKeyName: PAnsiChar): Longint; stdcall;

现在您的主要问题是让您的代码与您要迁移到的Delphi的Unicode感知版本一起使用。您面临的主要问题是您的代码尚未移植到Unicode Delphi。在32位编译器下执行此操作。一旦你有了这个工作,切换到64位应该是微不足道的,并且根本不涉及代码更改。