Using C++ DLL in Delphi 6
Question
I have to use an encoding function from an external C++ DLL in Delphi 6. Following is the declaration provided :
long <Function Name> (char *Data, long &Apply, char *ReturnVal, long &Size)
Data is the input value, Apply is a boolean value (default : FALSE), ReturnVal is the return value from the DLL and Size is the length of the ReturnVal.
To use this in Delphi 6, I wrote following Code:
implementation
const
EncoderDLL = '<DLL NAME>';
FunctionName = 'FUNCTION NAME';
var
_TEST : function(const Data : PChar; Apply : PInteger;stOutput : Pchar;
iSize : PInteger) : integer; stdcall;
.....
.....
var
stInput,stOutput : string;
iLength,i1,iResult : integer;
hnd : THandle;
begin
iLength := 0;
i1 := 0;
stInput := Trim(edtInput.Text);
hnd := SafeLoadLibrary(EncoderDLL);
if hnd > 0 then
begin
@_TEST := GetProcAddress(hnd,FunctionName);
if @_TEST <> nil then
begin
iResult := _TEST(PChar(stInput),@i1,PChar(StOutput),@iLength); // ERROR
end;
end;
FreeLibrary(hnd);
end;
I am getting Access Violation in the line having 'ERROR' as comments.
If I replace PChar in the function declaration with string, then the access violation does not come at the same line. It comes while freeing the library. Also, the value of the iLength parameter is populated correctly.
Can anyone please provide pointers to resolve this issue.
Solution
Keep PChar, and initialize StOutput to a non-empty string (of a sufficient length) before the call.
OTHER TIPS
Are you sure about stdcall convention? If there are no clear instructions in C++ text (like WINAPI, __stdcall etc), then use cdecl.
'const' before Data is not needed
allocate memory for StOutput
I'm assuming ReturnVal
is an output parameter (the function fills it in). You should reserve memory for this string in your code. But how much memory should you reserve? There's a common pattern for such functions. You call the function twice.
In the first call you set ReturnVal
to nil
and the function fills in what size it needs in the Size
parameter.
You then reserve that much memory in your StOutput
buffer and call the function again. This time you get the result.
iResult := _TEST(PChar(stInput),@i1,nil,@iLength); // First call
SetLength( stOutput, iLength ); // reserve memory
iResult := _TEST(PChar(stInput),@i1,PChar(stOutput),@iLength); // Second call
Note that this function may or may not follow this convention. But if it doesn't, there's really no way to tell how much memory you should reserve for the output parameter.
Another thing to note is the calling convention. C And C++ functions default to cdecl
and the declaration you've shown doesn't say otherwise. You've declared it as stdcall
in Pascal. They should match.