I am trying to call C++ code from Delphi. I am a beginner. I keep getting an access violation error, although it is intermittent (but very common).
This only occurs when executing ConfigccDLL
or PriorTran
From what I've read it might be a calling convention mismatch, but I'm under the impression I am using stdcall
in both codebases. I have walked the dll I create with Dependency Walker and its showing the functions as _functionName. I'm not sure if I should be calling them with the leading underscore.
I'd like to change the Delphi code as little as possible because the code that will end up using the dll I cannot change (I was going to say I can't change it at all but I've already had to change the PAnsiChar and add AnsiStrings in order to get the Delphi to compile).
Delphi code:
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.
The C++ code is as follows:
Header file:
#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 file:
#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()
{
}
}
Dll as seen from dependency walker
Dependency Walker also gives these errors when opening the dll
_PriorTran@4
, notPriorTran
as your Delphi code is stating. If you want "clean" exported names in your DLL, you need to build your DLL using a Module Definition File – PaulMcKenzie