我试图从Delphi调用C ++代码。我是初学者。我一直收到访问冲突错误,虽然它是间歇性的(但非常常见)。
只有在执行ConfigccDLL
或PriorTran
时才会出现这种情况。从我读过的内容可能是调用约定不匹配,但我的印象是我在两者中使用stdcall
代码库。我已经使用Dependency Walker创建了我创建的DLL,它将函数显示为_functionName。我不确定我是否应该使用前导下划线来呼叫它们。
我想尽可能少地更改Delphi代码,因为最终使用dll的代码我无法改变(我会说我根本无法改变它但我已经不得不更改PAnsiChar并添加AnsiStrings以便Delphi编译)。
德尔福代码:
unit dllTest;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, AnsiStrings;
procedure CloseDLL; stdcall; external 'cccontrol.dll';
procedure ConfigccDLL(Variables: PAnsiChar); stdcall; external 'cccontrol.dll';
procedure PrepareDLL; stdcall; external 'cccontrol.dll';
procedure PriorTran(Variables: PAnsiChar); stdcall; external 'cccontrol.dll';
type
TdllTestForm = class(TForm)
PrepareBtn: TBitBtn;
Label1: TLabel;
ConfigccDLLbtn: TBitBtn;
TranTypeEntry: TEdit;
TranAmountEntry: TEdit;
Label2: TLabel;
PriorTranBtn: TBitBtn;
TranIDEntry: TEdit;
Label3: TLabel;
CloseDLLBtn: TBitBtn;
Label4: TLabel;
Memo1: TMemo;
BitBtn1: TBitBtn;
procedure CloseDLLBtnClick(Sender: TObject);
procedure PriorTranBtnClick(Sender: TObject);
procedure ConfigccDLLbtnClick(Sender: TObject);
procedure PrepareBtnClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
dllTestForm: TdllTestForm;
implementation
{$R *.dfm}
procedure TdllTestForm.PrepareBtnClick(Sender: TObject);
var
AppHandle: HWND;
begin
AppHandle := Application.Handle;
PrepareDLL;
end;
procedure TdllTestForm.ConfigccDLLbtnClick(Sender: TObject);
var
Variables: AnsiString;
TransID, TransType, TranAmt: string;
begin
TransType := TranTypeEntry.Text;
TranAmt := TranAmountEntry.Text;
Variables := TransType + '^' + TranAmt + '^';
ConfigccDLL(PAnsiChar(Variables));
end;
procedure TdllTestForm.PriorTranBtnClick(Sender: TObject);
var
Variables: AnsiString;
TransID, TransType, TranAmt: string;
begin
TransID := TranIDEntry.Text;
Variables := TransID;
PriorTran(PAnsiChar(Variables));
end;
procedure TdllTestForm.CloseDLLBtnClick(Sender: TObject);
begin
CloseDLL;
end;
end.
C ++代码如下:
标题文件:
#pragma once
#ifndef ccControl
#define ccControl
#include <iostream>
#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif
extern "C" {
DECLDIR void __stdcall PrepareDLL();
DECLDIR void __stdcall ConfigccDLL(char* pcharVar);
DECLDIR void __stdcall PriorTran(char* pcharVar);
DECLDIR void __stdcall CloseDLL();
}
#endif
Cpp文件:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <Winuser.h>
#include <stdexcept>
#define DLL_EXPORT
#include "ccControl.h"
#pragma warning( disable : 4996 )
using namespace std;
extern "C" {
DECLDIR void __stdcall PrepareDLL()
{
}
DECLDIR void __stdcall ConfigccDLL(char* pcharVar)
{
}
DECLDIR void __stdcall PriorTran(char* pcharVar)
{
}
DECLDIR void __stdcall CloseDLL()
{
}
}
从依赖性walker
中看到的DllDependency Walker在打开dll时也会出现这些错误
答案 0 :(得分:1)
我认为很明显,您没有调用您认为正在调用的DLL。如果你那时你的程序将无法启动,因为导出的函数名称不匹配。您在Dependency Walker中显示的DLL具有装饰名称。您不会在Delphi代码中使用修饰的名称。你的程序执行。您好,您正在链接到另一个DLL。至于你为什么会遇到访问冲突,我们当然不能说,因为我们对该DLL一无所知。
一旦对它进行了排序,以便调用正确的DLL(将DLL放在与可执行文件相同的目录中),我们就可以查看问题中的代码。互操作很好,无论如何你的DLL函数什么都不做。但Delphi代码并不好。请考虑以下代码:
Variables := AnsiStrAlloc(50);
AnsiStrings.StrPCopy(Variables, TransID);
在这里你分配一个长度为50的数组,并将一串长度的数据复制到其中,谁知道什么。如果您的源字符串太长,您将超出缓冲区。
如果必须使用动态分配,那么您需要采取措施确保缓冲区足够长。而且你还需要解除分配。您的代码目前像筛子一样泄漏。
但手动动态分配容易出错,而且很乏味。不要满足于单调乏味的生活。让编译器为您完成工作。在AnsiString
类型的变量中构建文本。当您需要将其传递给C ++代码时,请使用PAnsiChar(...)
强制转换。
var
Variables: AnsiString;
....
Variables := TransType + '^' + TranAmt + '^';
ConfigccDLL(PAnsiChar(Variables));