gpt4 book ai didi

c++ - 使用消息处理程序将 c++ dll 调用转换为 delphi

转载 作者:行者123 更新时间:2023-11-30 01:56:57 26 4
gpt4 key购买 nike

我需要在我的 delphi XE3 应用程序中使用一个 DLL,我收到了一个用 c++ 编写的演示应用程序,它展示了如何调用 DLL。
我已成功调用 DLL 和 DLL 的 Initialize 方法,但我没有从 DLL 收到任何消息。
这是 C++ 源代码:
创建消息处理程序:

#define WM_POSSTATE  WM_APP+1
#define ON_WM_POSSTATE() \
{ WM_POSSTATE, 0, 0, 0, AfxSig_vwl, \
(AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(UINT, LPARAM))&OnPOS },

初始化方法的定义:

typedef int (INITIALIZE)( char * cPort , UINT Msg, HWND *hWnd_p );
INITIALIZE *Initialize;

HMODULE hPosDll;

加载动态链接库:

if( (hPosDll = LoadLibrary( "posdll.dll" ) ) == NULL )
{
MessageBox( "Error: can not open posdll.dll",NULL,MB_OK);
exit(1);
}

if( (::Initialize = (INITIALIZE*)GetProcAddress( hPosDll, "Initialize" )) == NULL )
{
MessageBox( "Error: can not find function",NULL,MB_OK);
FreeLibrary( hPosDll );
exit(1);
}

调用初始化方法:

res=::Initialize('com3', WM_POSSTATE , &m_hWnd);

if( res )
{
MessageBox( "Error opening comms",NULL,MB_OK);
FreeLibrary( hPosDll );
exit(1);
}

Initialize 调用后,从 DLL 到应用程序的消息由 OnPos 方法处理:

void CPosDemoDlg::OnPOS(UINT Result, LPARAM Param )
{
DoStuff;
}

到目前为止,我在 Delphi 中取得了以下成就:

unit UFrmMain;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, MCPOSDLL;

const
WM_POSSTATE = WM_APP + 1;
MCDLL = 'posdll.dll';

type
TInitialize = function(cport: PAnsiChar; Msg: Integer; Handle: HWND):Integer; stdcall;

TFrmMain = class(TForm)
EdCOMPort: TEdit;
BtnConnect: TButton;
LblCOMPort: TLabel;
procedure ON_WM_POSSTATE(var Msg: TMessage); message WM_POSSTATE;
procedure BtnConnectClick(Sender: TObject);
private
DLLHandle: THandle;
public
{ Public declarations }
end;

var
FrmMain: TFrmMain;

implementation

{$R *.dfm}

{-------------------------------------------------------------------------------}
procedure TFrmMain.BtnConnectClick(Sender: TObject);
var
MCInitialize: TInitialize;
Res: Integer;
begin
DLLHandle := LoadLibrary(PChar(MCDLL));

if DLLHandle <> 0 then
begin
@MCInitialize := getProcAddress(DLLHandle, 'Initialize');

if @MCInitialize <> NIL then
begin
Res := MCInitialize(PAnsiChar('com3'), WM_POSSTATE, Self.Handle);

if Res <> 0 then
begin
MessageDlg('Error opening comms', mtWarning, [mbOK], 0);
end;
end;
end
else
begin
MessageDlg('posdll.dll could not be located.', mtWarning, [mbOK], 0);
end;
end;

{-------------------------------------------------------------------------------}
procedure TFrmMain.ON_WM_POSSTATE(var Msg: TMessage);
begin
showmessage('Message received');
end;

end.

使用此解决方案,我能够激活连接到 com3 的设备,但从未触发消息处理程序。
我认为在 C++ 中使用 Initialize 方法发送的 &m_hWnd 与我在 Delphi 中发送的 Self.Handle 不同。
谁能帮我吗?提前致谢。

最佳答案

C++ 函数声明为:

typedef int (INITIALIZE)( char * cPort , UINT Msg, HWND *hWnd_p );

您的 Delphi 等价物声明为:

TInitialize = function(cport: PAnsiChar; Msg: Integer; 
Handle: HWND): Integer; stdcall;

我可以在您的 Delphi 声明中看到以下差异:

  1. Msg 参数是无符号的,但 Delphi 翻译是有符号的。
  2. hWnd_p 参数是指向HWND 的指针。在 Delphi 中,您按值传递窗口句柄。
  3. C++ 代码的调用约定是cdecl,但您将Delphi 代码声明为stdcall

所以在 Delphi 中声明应该是:

TInitialize = function(cport: PAnsiChar; Msg: Cardinal; 
Handle: PHWND): Integer; cdecl;

其中 PHWND 是声明为 ^HWND 的类型。我怀疑这种类型是在 Windows 单元中声明的,但如果没有,那么您可以轻松地声明它。

或者更简单的翻译是:

TInitialize = function(cport: PAnsiChar; Msg: Cardinal; 
var Handle: HWND): Integer; cdecl;

当然,您在转录 C++ 代码时省略了调用约定是有道理的。也许该函数确实是 stdcall,即使您在问题中放置的声明没有这样说。

除此之外,您的代码还使用窗体的窗口句柄。这可能有风险。在某些情况下,VCL 会重新创建窗口。这将导致您传递给 DLL 的句柄被销毁。 DLL 将继续向该窗口发送消息,但您的表单将停止接收它们,因为它的窗口已更改。

解决这个问题的方法是使用 VCL 不会重新创建的窗口句柄。通过调用 AllocateHwnd 获取其中之一。

调用Initialize 时要小心。您传递 PAnsiChar('com3') 作为端口名称。您需要确保文字 'com3' 确实是 ANSI 编码的。理想情况下,您应该将 'com3' 直接传递给 Initialize。如果那没有编译(我不确定是否会编译)然后传递 PAnsiChar(AnsiString('com3'))

关于c++ - 使用消息处理程序将 c++ dll 调用转换为 delphi,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19266481/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com