Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2014-07

DLL call works on FPC 2.6.4 but not with D7

15 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Paul Breneman

Below is code from a C program (that works).

 From the ".h" files:
typedef uint32_t PICO_INFO;
typedef uint32_t PICO_STATUS;

PREF0 PREF1 PICO_STATUS PREF2 PREF3 (ps5000aGetUnitInfo) (
int16_t handle,
int8_t * string,
int16_t stringLength,
int16_t *requiredSize,
PICO_INFO info
);

 From a ".c" program:
	int16_t i = 0;
	int16_t requiredSize = 0;
	int8_t line [10];
	PICO_STATUS status = PICO_OK;
status = ps5000aGetUnitInfo(unit->handle, line, sizeof (line),
&requiredSize, i);

**************

Here is the dll call I'm having trouble with:
function ps5000aGetUnitInfo
          (handle : smallInt;
           var str : Pchar;
           stringLength : smallInt;
           var requiredSize : smallInt;
           info : integer
           ) : integer;
{$IFDEF WIN32} stdcall; external 'ps5000a.dll';{$ENDIF}

I have two console programs that are almost identical.

Here is my FPC 2.6.4 call (that works):
       Status := ps5000aGetUnitInfo( ps5000a_handle, MyReturnStr,
StringLen, requiredSize, RInfo);
Here is my D7 call (that doesn't work):
       Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr,
StringLen, requiredSize, RInfo);

In D7 I have to add "@" on "MyReturnStr or the program crashes. With the "@" added the program doesn't crash, but things still don't work.

Any suggestions on what to look at?

Reply by email

Paul Breneman
to Paul Breneman
Paul Breneman wrote 49 lines
Below is code from a C program (that works). From the ".h" files: typedef uint32_t PICO_INFO; typedef uint32_t PICO_STATUS; PREF0 PREF1 PICO_STATUS PREF2 PREF3 (ps5000aGetUnitInfo) ( int16_t handle, int8_t * string, int16_t stringLength, int16_t *requiredSize, PICO_INFO info ); From a ".c" program: int16_t i = 0; int16_t requiredSize = 0; int8_t line [10]; PICO_STATUS status = PICO_OK; status = ps5000aGetUnitInfo(unit->handle, line, sizeof (line), &requiredSize, i); ************** Here is the dll call I'm having trouble with: function ps5000aGetUnitInfo (handle : smallInt; var str : Pchar; stringLength : smallInt; var requiredSize : smallInt; info : integer ) : integer; {$IFDEF WIN32} stdcall; external 'ps5000a.dll';{$ENDIF} I have two console programs that are almost identical. Here is my FPC 2.6.4 call (that works): Status := ps5000aGetUnitInfo( ps5000a_handle, MyReturnStr, StringLen, requiredSize, RInfo); Here is my D7 call (that doesn't work): Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr, StringLen, requiredSize, RInfo); In D7 I have to add "@" on "MyReturnStr or the program crashes. With the "@" added the program doesn't crash, but things still don't work. Any suggestions on what to look at?

Sorry, but after I sent the email above I realized that I was editing a file in the wrong folder. Free Pascal doesn't work with "var" on the line below:

   var str : Pchar;
This is what works on FPC 2.6.4:
function ps5000aGetUnitInfo
          (handle : smallInt;
           Str : Pchar;
           stringLength : smallInt;
           var requiredSize : smallInt;
           info : integer
           ) : integer;
{$IFDEF WIN32} stdcall; external 'ps5000a.dll';{$ENDIF}

Reply by email

Jonas Maebe
to Paul Breneman
Paul Breneman wrote 14 lines
Sorry, but after I sent the email above I realized that I was editing a file in the wrong folder. Free Pascal doesn't work with "var" on the line below: var str : Pchar; This is what works on FPC 2.6.4: function ps5000aGetUnitInfo (handle : smallInt; Str : Pchar; stringLength : smallInt; var requiredSize : smallInt; info : integer ) : integer; {$IFDEF WIN32} stdcall; external 'ps5000a.dll';{$ENDIF}

It will work in both FPC and Delphi if you pass @MyReturnStr[1], provided that the length of MyReturnStr is sufficiently large. When dealing with addresses to strings/arrays, always explicitly specify the first element you want to use rather than the entire string/array. That will always work regardless of the string or array type (static/dynamic/open/... array, ansi/short/wide/..., and even pchar).

Jonas

Reply by email

Paul Breneman
to Jonas Maebe
Jonas Maebe wrote 22 lines
On 01/07/14 17:27, Paul Breneman wrote: > Sorry, but after I sent the email above I realized that I was editing a > file in the wrong folder. Free Pascal doesn't work with "var" on the > line below: > var str : Pchar; > > This is what works on FPC 2.6.4: > function ps5000aGetUnitInfo > (handle : smallInt; > Str : Pchar; > stringLength : smallInt; > var requiredSize : smallInt; > info : integer > ) : integer; > {$IFDEF WIN32} stdcall; external 'ps5000a.dll';{$ENDIF} It will work in both FPC and Delphi if you pass @MyReturnStr[1], provided that the length of MyReturnStr is sufficiently large. When dealing with addresses to strings/arrays, always explicitly specify the first element you want to use rather than the entire string/array. That will always work regardless of the string or array type (static/dynamic/open/... array, ansi/short/wide/..., and even pchar).
Thanks Jonas for the help!  This now works for me in FPC (MyReturnStr is
PChar):
       Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0],
StringLen, requiredSize, RInfo);

But in D7 using "@MyReturnStr[ 0]" gives an Access violation exception in the dll. The address the DLL is trying to write is about the same as in FPC so I still don't understand why FPC works but D7 doesn't.

Reply by email

Jonas Maebe
to Paul Breneman
Paul Breneman wrote 8 lines
Thanks Jonas for the help! This now works for me in FPC (MyReturnStr is PChar): Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], StringLen, requiredSize, RInfo); But in D7 using "@MyReturnStr[ 0]" gives an Access violation exception in the dll. The address the DLL is trying to write is about the same as in FPC so I still don't understand why FPC works but D7 doesn't.

How are you allocating space for MyReturnStr?

Jonas

Reply by email

Paul Breneman
to Jonas Maebe
Jonas Maebe wrote 11 lines
On 01/07/14 19:06, Paul Breneman wrote: > Thanks Jonas for the help! This now works for me in FPC (MyReturnStr is > PChar): > Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], > StringLen, requiredSize, RInfo); > > But in D7 using "@MyReturnStr[ 0]" gives an Access violation exception > in the dll. The address the DLL is trying to write is about the same as > in FPC so I still don't understand why FPC works but D7 doesn't. How are you allocating space for MyReturnStr?
I'm doing the same thing in FPC and D7:
       StringLen := 14;
       MyReturnStr := 'test1234567890';
       Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0],
StringLen, requiredSize, RInfo);

Reply by email

Jonas Maebe
to Paul Breneman
Paul Breneman wrote 5 lines
I'm doing the same thing in FPC and D7: StringLen := 14; MyReturnStr := 'test1234567890'; Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], StringLen, requiredSize, RInfo);

It wrong in both FPC and D7 (and it will also crash on all platforms in the next version of FPC; in the current version, it will only crash on OS X). You are assigning a string constant to a pchar, and then telling the DLL to overwrite it.

In current release versions of FPC (where it doesn't crash), that will result in the data of that string constant getting overwritten. This means that if you assign 'test1234567890' somewhere else to a string, that string will actually get the value with which this string was overwritten the last time.

Use getmem to allocate writeable memory.

Jonas

Reply by email

Paul Breneman
to Jonas Maebe
Jonas Maebe wrote 19 lines
On 01/07/14 19:42, Paul Breneman wrote: > I'm doing the same thing in FPC and D7: > StringLen := 14; > MyReturnStr := 'test1234567890'; > Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], > StringLen, requiredSize, RInfo); It wrong in both FPC and D7 (and it will also crash on all platforms in the next version of FPC; in the current version, it will only crash on OS X). You are assigning a string constant to a pchar, and then telling the DLL to overwrite it. In current release versions of FPC (where it doesn't crash), that will result in the data of that string constant getting overwritten. This means that if you assign 'test1234567890' somewhere else to a string, that string will actually get the value with which this string was overwritten the last time. Use getmem to allocate writeable memory.

Thanks Jonas! That got things working!

Reply by email

Sven Barth
to Jonas Maebe: It wrong in both FPC and D7 (and it will also crash on all platforms in the next version…
"Jonas Maebe" wrote 11 lines
On 01/07/14 19:42, Paul Breneman wrote: > > I'm doing the same thing in FPC and D7: > StringLen := 14; > MyReturnStr := 'test1234567890'; > Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], > StringLen, requiredSize, RInfo); It wrong in both FPC and D7 (and it will also crash on all platforms in

the next version of FPC; in the current version, it will only crash on OS X). You are assigning a string constant to a pchar, and then telling the DLL to overwrite it.

In current release versions of FPC (where it doesn't crash), that will

result in the data of that string constant getting overwritten. This means that if you assign 'test1234567890' somewhere else to a string, that string will actually get the value with which this string was overwritten the last time.

Use getmem to allocate writeable memory.

In case MyReturnStr is a Ansi-, Wide- or UnicodeString shouldn't "SetLength(MyReturnStr, StringLen)" work as well?

Regards,
Sven

Reply by email

Jonas Maebe
to Virgo Pärna
Virgo Pärna wrote 10 lines
On Tue, 01 Jul 2014 13:42:52 -0400, Paul Breneman < > wrote: > Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], > StringLen, requiredSize, RInfo); > Also, first character of string is 1'st, not 0'th. When passing string as PChar like that would cause overwriting internal string structures AFAIK.

As has been mentioned earler in the thread, MyReturnStr itself is a pchar.

Jonas

Reply by email

Virgo Pärna
to Jonas Maebe
Jonas Maebe wrote
As has been mentioned earler in the thread, MyReturnStr itself is a pchar.

Sorry, I had to recheck thred multiple times before I found it. Initially he did not mention the , if variable is of type PChar, then there is not reason to take an address of first element to pass it to PChar. Passing wariable itselt is much clearer.
And for ansistring MyReturnStr casting it to PChar would have worked also. After setting it to required length with SetLength.

Virgo Pärna

Reply by email

Paul Breneman
to Paul Breneman: Thanks Jonas! That got things working!
Paul Breneman wrote 22 lines
On 07/01/2014 02:58 PM, Jonas Maebe wrote: > On 01/07/14 19:42, Paul Breneman wrote: >> I'm doing the same thing in FPC and D7: >> StringLen := 14; >> MyReturnStr := 'test1234567890'; >> Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], >> StringLen, requiredSize, RInfo); > > It wrong in both FPC and D7 (and it will also crash on all platforms in > the next version of FPC; in the current version, it will only crash on > OS X). You are assigning a string constant to a pchar, and then telling > the DLL to overwrite it. > > In current release versions of FPC (where it doesn't crash), that will > result in the data of that string constant getting overwritten. This > means that if you assign 'test1234567890' somewhere else to a string, > that string will actually get the value with which this string was > overwritten the last time. > > Use getmem to allocate writeable memory. Thanks Jonas! That got things working!

There is a 1.2 MB zip file here with the working source code: http://ctrlpascal.com/picoscope.htm

Reply by email

Jonas Maebe
to Virgo Pärna: Sorry, I had to recheck thred multiple times before I found it. Initially he did not…
Virgo Pärna wrote 9 lines
On Wed, 2 Jul 2014 11:23:33 +0200, Jonas Maebe < > wrote: > > As has been mentioned earler in the thread, MyReturnStr itself is a > pchar. Sorry, I had to recheck thred multiple times before I found it. Initially he did not mention the know, that's why I initially also wrongly assumed that it was an

ansistring and hence also proposed @MyReturnStr[1] in my first reply.

Show quoted text 5 lines
Anyway, if variable is of type PChar, then there is not reason to take an address of first element to pass it to PChar. Passing wariable itselt is much clearer.

I disagree. People make mistakes all the time with dynamic data structures, forgetting that they are implicit pointers (or getting run time errors when they change the type of a variable from a static into a dynamic one). Passing the address of the first element is however always correct. The only downside is that the index of the first element may change, although for strings it won't (unless you switch to {$zerobasedstrings}) and for arrays you could solve that with @MyReturnStr[low(MyReturnStr)] (in case you often replace arrays with one using a different lower bound -- but in that case, other code may break too).

Jonas

Reply by email

Paul Breneman
to Paul Breneman: There is a 1.2 MB zip file here with the working source code:…
Paul Breneman wrote 26 lines
On 07/01/2014 04:24 PM, Paul Breneman wrote: > On 07/01/2014 02:58 PM, Jonas Maebe wrote: >> On 01/07/14 19:42, Paul Breneman wrote: >>> I'm doing the same thing in FPC and D7: >>> StringLen := 14; >>> MyReturnStr := 'test1234567890'; >>> Status := ps5000aGetUnitInfo( ps5000a_handle, @MyReturnStr[ 0], >>> StringLen, requiredSize, RInfo); >> >> It wrong in both FPC and D7 (and it will also crash on all platforms in >> the next version of FPC; in the current version, it will only crash on >> OS X). You are assigning a string constant to a pchar, and then telling >> the DLL to overwrite it. >> >> In current release versions of FPC (where it doesn't crash), that will >> result in the data of that string constant getting overwritten. This >> means that if you assign 'test1234567890' somewhere else to a string, >> that string will actually get the value with which this string was >> overwritten the last time. >> >> Use getmem to allocate writeable memory. > > Thanks Jonas! That got things working! There is a 1.2 MB zip file here with the working source code: http://ctrlpascal.com/picoscope.htm

Just thought I should share (here) what I started sharing several other places...

There are simple tools (free and open source) and code for C and Pascal (Python hopefully soon) on the new page mentioned above.

If you are an experienced programmer then this probably doesn't apply to you. But if you or someone you know is just starting out, maybe these types of projects can be a valuable resource. These folks have been doing something similar (demonstrating simple tools) since 1998: http://software-carpentry.org/

Reply by email