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.

Was it helpful?

Solution

Keep PChar, and initialize StOutput to a non-empty string (of a sufficient length) before the call.

OTHER TIPS

  1. Are you sure about stdcall convention? If there are no clear instructions in C++ text (like WINAPI, __stdcall etc), then use cdecl.

  2. 'const' before Data is not needed

  3. 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top