Recent

Author Topic: Access violation calling stdcall external C DLL  (Read 23069 times)

lero

  • New member
  • *
  • Posts: 7
Access violation calling stdcall external C DLL
« on: March 16, 2011, 03:48:33 pm »
Hello,

I'm very very new to Lazarus, but work with Delphi for years. I didn't know this IDE, and I'm more and more amazed day by day with the possibilities Lazarus brought to me since I've discovered I can make my code platform independent.
My first approach have happened when I came across a specific need to compile 64 bit code. Lazarus saved my life!!
Now I've a Delphi project ported to Lazarus and I'm having a problem when calling a specific function from a external C DLL.

Here is the C DLL call
Code: [Select]
typedef struct _c_typedef {
wchar_t text[128];
int     number;
} c_typedef;
int c_function(c_typedef *var1, c_typedef *var2)

In my unit I use a wrapper and I call it this way:

Declaration
Code: [Select]
function c_function(var1:Pointer;var2:Pointer):integer;stdcall;external 'C.dll';
Wrapper
Code: [Select]
type c_typedef = record
  text:array[0..MAX_PASSWORD] of WideChar;
  number:DWORD;
end;

function StrToCtypedef(str:String):c_typedef;
var
  i:integer;
begin
  if (Length(str) > 126) then Str := leftstr(Str,126);
  Result.number := Length(str);
  StringToWideChar(str,@Result.text[0],Result.number +1 );
  Result.number := Result.number * 2;
end;

function c_function_wrapper(var1:String; var2:String):integer;
var
  newvar1:c_typedef;
  newvar2:c_typedef;
begin
  newvar1:= StrToCtypedef(var1);
  newvar2:= StrToCtypedef(var2);
  result :=c_function(@newvar1,@newvar2);
end;

Calling from my application
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  var1, var2: string;
begin
   var1 := (InputBox('Vars', 'var1', ''));
   var2 := (InputBox('Vars', 'var2', ''));
   c_function_wrapper(var1, var2);
end;

The problem arrives when my wrapper passes the Pointers. I'm getting an Access Violation error. In Delphi the code is exactly the same and the call works fine. In fact calling from Delphi I don't even need the wrapper.
I've the full source of everything, so if I need to change something in C to adequate to Lazarus there is no problem at all.
I've tried changing most of compiling parameters in FPC, but the error continues. Any hint about this?

Thank you guys.

Dibo

  • Hero Member
  • *****
  • Posts: 1048
Re: Access violation calling stdcall external C DLL
« Reply #1 on: March 16, 2011, 04:00:00 pm »
Host application is 64 bit? Pointer in 64bit lazarus have 8 bytes. Maybe C library expecting 4 byte pointer. Try some casting DWORD()

lero

  • New member
  • *
  • Posts: 7
Re: Access violation calling stdcall external C DLL
« Reply #2 on: March 16, 2011, 04:37:03 pm »
Actually I'm doing all with the 32bit version. Everything is in 32 bit.
Anyway I've done what you say but no luck. The error is the same.
I've tryed the casting in Delphi and it works also.  %)

Here is the casting I've tried:

Wrapper result
Code: [Select]
result :=c_function([b]DWORD(@newvar1),DWORD(@newvar2)[/b]);

C function declaration
Code: [Select]
function c_function(var1:[b]DWORD[/b];var2:[b]DWORD[/b]):integer;stdcall;external 'C.dll';

lero

  • New member
  • *
  • Posts: 7
Re: Access violation calling stdcall external C DLL
« Reply #3 on: March 16, 2011, 05:03:27 pm »
I just noticed that when I declare:

Code: [Select]
function c_function(VAR var1:C_TYPEDEF;VAR var2:C_TYPEDEF):integer;stdcall;external 'C.dll';
It works. I mean, the DLL function executes, but the Access Violation happens after the execution. In the first code I got Access Violation before function execution, now I get it right after the execution.
For sure I have some progress but I still need to solve this problem.
Any idea what's going on?

lero

  • New member
  • *
  • Posts: 7
Re: Access violation calling stdcall external C DLL
« Reply #4 on: March 17, 2011, 02:04:45 pm »
Just as an information for the ones who might someday fall in this very same problem.
As I didn't find a answer for dealing with this problem and I really need to get the job done, I had to do a workaround rather than finding the right answer.
As I've found that passing the parameters with VAR instead of using Pointer makes possible to call the methods from my DLL I've made wrappers as procedures for every single function. Now I'm getting the results from var parameters while preventing the leakage after my wrapper execution with try/except blocks.
It's very dirty I know, so if anyone know the right way to overcome this problem I would really appreciate.

Here is the way I did:
Code: [Select]
procedure c_function_wrapper(var1:String; var2:String; var RESULT: Integer);

procedure TForm1.Button1Click(Sender: TObject);
var
  var1, var2: string;
  result: Integer;
begin
   var1 := (InputBox('Vars', 'var1', ''));
   var2 := (InputBox('Vars', 'var2', ''));
   try
     c_function_wrapper(var1, var2, result);
   except
      // The execution from DLL function is fine,
      // we got the Access Violation in the completion of the procedure
      // so this is a dirty workaround
   end;
   ShowMessage('Execution result: ' + StrToInt(result));
end;
« Last Edit: March 17, 2011, 02:32:07 pm by lero »

Leledumbo

  • Hero Member
  • *****
  • Posts: 8747
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Access violation calling stdcall external C DLL
« Reply #5 on: March 17, 2011, 05:53:16 pm »
Hmm... I can't really see the problem here. Perhaps we should go a little wild and see the generated assembly (-a on FPC, -alnrt for full information) between FPC and Delphi. Please post the result here.

A.S.

  • Jr. Member
  • **
  • Posts: 76
Re: Access violation calling stdcall external C DLL
« Reply #6 on: March 17, 2011, 07:23:57 pm »
Why do you so simple convert string to the pointer to some structure, that contains 128 widechar's and an Integer? It's very strange. Not all AnsiStrings have the same size as you structures.

lero

  • New member
  • *
  • Posts: 7
Re: Access violation calling stdcall external C DLL
« Reply #7 on: March 17, 2011, 08:37:10 pm »
@Leledumbo
Hello,
I've done the assembler, but from what I know there is no way to generate it from Delphi. How would I compare?
Despite of this, I couldn't manage to compile the .pas file which calls the DLL since the compiler dies with the error Error: Identifier not found "Result" in all functions.

@A.S.
It's simple the way it is. I don't know if I catch your idea. Anyway the C code heavly depends on this structure and it's better to keep this way than refactoring.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8747
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Access violation calling stdcall external C DLL
« Reply #8 on: March 18, 2011, 06:32:48 am »
Quote
Despite of this, I couldn't manage to compile the .pas file which calls the DLL since the compiler dies with the error Error: Identifier not found "Result" in all functions.
add
Code: [Select]
{$mode delphi}to the source, or use -Sd to set it globally from command line (note that source directive has higher precedence than command line).

A.S.

  • Jr. Member
  • **
  • Posts: 76
Re: Access violation calling stdcall external C DLL
« Reply #9 on: March 18, 2011, 10:40:34 am »
lero, do you know the internal structure of ansistring FreePascal datatype? It is not fit with structures you mentioned above. Your code is wrong, but it seams, that if the length of strings you send to c_function_wrapper would be greater then sizeof(_c_typedef) then AV error will not appear.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11384
  • FPC developer.
Re: Access violation calling stdcall external C DLL
« Reply #10 on: March 18, 2011, 12:32:28 pm »
How sure are you that the DLL actually uses stdcall, and not CDECL ?

lero

  • New member
  • *
  • Posts: 7
Re: Access violation calling stdcall external C DLL
« Reply #11 on: March 18, 2011, 07:24:39 pm »
@Leledumbo
I generate the .s files, but from what I could see I've not found anything that could help to solve this specific problem. To me it seems it's a problema from the compiler. How would you compare without the Delphi compilation?

@A.S.
I still don't get your point. I've read this link http://www.freepascal.org/docs-html/ref/refsu10.html and besides the fact it's quite different from Delphi the code seems OK to me. Could you evidence where is the error and what is the better solution for it?

@marcov
I'm pretty sure. I stated above I've full source code from the C DLL. Everything is working with Delphi. The problem arises when the function (that's now a procedure) c_function_wrapper finishes execution. It looks like there is something being released that are not properly handled.

Leledumbo

  • Hero Member
  • *****
  • Posts: 8747
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Access violation calling stdcall external C DLL
« Reply #12 on: March 19, 2011, 08:47:11 am »
I don't know how, too. I don't have Delphi. Assuming your C function really uses stdcall, please post the .s here (or attach). I'm gonna check whether the generated assembly is correct.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11384
  • FPC developer.
Re: Access violation calling stdcall external C DLL
« Reply #13 on: March 19, 2011, 12:20:27 pm »
@marcov
I'm pretty sure. I stated above I've full source code from the C DLL.

So, where is the stdcall specified? I don't see it in the fragment.

Quote
Everything is working with Delphi.

Could be pure luck. (memory layout, nothing crucial allocated nearby)

Quote
The problem arises when the function (that's now a procedure) c_function_wrapper finishes execution. It looks like there is something being released that are not properly handled.

If the DLL tries to free Free Pascal allocations then that could be it too. Though that would be awfully bad DLL code then. 

Leledumbo

  • Hero Member
  • *****
  • Posts: 8747
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: Access violation calling stdcall external C DLL
« Reply #14 on: March 19, 2011, 04:43:21 pm »
Quote
So, where is the stdcall specified? I don't see it in the fragment.
Yeah, neither do I. Most C compilers use cdecl as default calling convention, even MSVC.

 

TinyPortal © 2005-2018