Solved

passing (short) strings to a DLL

Posted on 1997-11-18
11
252 Views
Last Modified: 2010-04-04
Can someone tell me how i can pass a couple of short strings and a record type containing a few more short strings from my delphi program to my delphi DLL ?

i know all about using ShareMem and DelphiMM DLLs with long strings.

i want to pass shortstrings (and preferably as value parameters)


The following is not working (an under statement: it crashes win 95 quite often !)
record type var is not in these funcs.

Any comments ?
===========================
in the DLL:

function AddCRToLF(Caller:HWND; infile, outfile: ShortString):boolean;

begin
//do all i want
end;

exports AddCRToLF index 1;

============================
in the calling program

function calldll(caller:HWND; s1,s2:shortstring);

var  h : THandle;
     f : function(Caller:HWND; infile, outfile: ShortString):boolean;stdcall;

begin
h := LoadLibrary('MyDLL.DLL');
if h <> 0 then
try
   @f := GetProcAddress(h, 'AddCRToLF');
   if @f <> nil then
      AddCRToLF := f(Caller, s1, s2);//<======crashes here !
finally
   FreeLibrary(h);      // Free the library...
   end;
end;
0
Comment
Question by:DelphiOnly
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
11 Comments
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1350888
Hi

I tried the following, and it works fine.

In exe:
type
  TRec = record
    RecInt: Integer;
    RecDescrip: ShortString;
  end;

procedure DoSomething(s: ShortString; ARec: TRec); external 'TestDll.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
  Rec: TRec;
begin
  Rec.RecInt := 5;
  Rec.RecDescrip := 'Record Description';
  DoSomething('Hello', Rec);
end;


In dll:
type
  TRec = record
    RecInt: Integer;
    RecDescrip: ShortString;
  end;

procedure DoSomething(s: ShortString; ARec: TRec);
begin
  ShowMessage(s);
  ShowMessage(ARec.RecDescrip);
  ShowMessage(IntToStr(ARec.RecInt));
end;

exports
  DoSomething;


I am using Delphi 3.

I noticed in your example that when you declared the functon in your DLL you did NOT use "stdcall", but when you declared the function type in your EXE you did use "stdcall".  You should use it or NOT use it in both places.

Regards,
JB
0
 

Expert Comment

by:kimfriis
ID: 1350889
As JB mentioned, I also don't think that you should declare the function as stdcall!!
0
 
LVL 3

Expert Comment

by:Pegasus100397
ID: 1350890
All the above +
...
Might also want to modify the function in the DLL as:

function AddCRToLF(Caller:HWND; infile, outfile: ShortString):boolean;  EXPORT;

to make it callable outside of the .DLL. Also check to see if your using SHAREMEM in your uses clause.

Good luck with your project!
Pegasus
0
[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

 
LVL 5

Expert Comment

by:JimBob091197
ID: 1350891
You may notice that in my original comment (!!) I put "exports DoSomething" at the bottom of my DLL section, which allows the call to be seen outside of the DLL.  Notice too that in the original question, DelphiOnly IS exporting AddCRToLF!  

One more thing:  You do NOT need ShareMem in your uses clause when passing ShortStrings, which is what DelphiOnly specifically mentioned.

JB
0
 

Author Comment

by:DelphiOnly
ID: 1350892
Jim Bob,
Thanks for pointing out my stupid mistake ('stdcall' in one proc).

yes after removing the stdcall, i can get the string to be passed on. But i'm still having problems with getting my record variable. i'll follow up with a detailed comment.

But a housekeeping comment first :-)
Pegasus, Sharemem/DelphiMM are needed only for large strings and JBs comment is the answer.

i want to give credit to to JimBob for the answer: so yours get rejected.

now how do i go about declaring the comment as an answer ?

0
 

Author Comment

by:DelphiOnly
ID: 1350893
for your comments, guys. (i assume :-)

My record var is TTeam defined as follows:
===========================================================
TName   = Record
          first : string;
          last  : string;
          end;
TScore  = Record
          GP,pp,sh,gw,gt,pim,shots: integer;
          ppgame  : real;
          end;
TPlayer = Record
          name  : TName;
          score : TScore;
          end;
TTeam   = Record
          ID       : string[03];
          Name     : string;
          FileName : string;
          HTTPAddr : string;
          Player   : array[0..35] of TPlayer ;
          end;

===================
in the DLL

function ParseFile(Caller:HWND; var T:TTeam):boolean;


note : T is a var parameter: i'm passing in a fielname with data
and having the DLL to fill in the array player[0..35];

in program:
     f : function(Caller:HWND; var team:TTeam):boolean;
======================================================

Well, everything works fine the first time i call the function.
The second call.


Would any of you like to comment on passing such a "large" record via stack ? i guess, since var params only pass the address of a variable, it is ok.

Is there a better way to do this ? (Is  passing the address of the variable and dereferencing in DLL is better ? Will it work)


0
 

Author Comment

by:DelphiOnly
ID: 1350894
btw, another weird thing is that if i do a freelibrary, then the record variable loses all it's string values !!

vat T is declared in main proc.
i call f(handle, T)
f return values for T.Name.last (say 'john')

now if i free library then T.Name.last becomes null !
Why ? ... why ?..... Why ???????


(talking to myself)
looks like i'm asking too many things. i should increase the points, oops i have got only 10 pts available. wth, something is better than nothing. so points increased!
0
 

Author Comment

by:DelphiOnly
ID: 1350895
Another observation:

if i remove the 'var' in declaring the function then everything works fine (well, except ofcourse i don't get back the reqd. data).

Also if i use a seperate record type variable, each time, it works. i.e

This works:

f(Caller, team1);
f(Caller, team2);

but this doesn't !
f(Caller, team1);
f(Caller, team1); <====== crash here !

Looks like passing as var parameter fiddles with the memory space somehow ??

(team1, team2 are type TTeam and passed as var parameters)

Does this ring any bells ?
0
 
LVL 5

Accepted Solution

by:
JimBob091197 earned 210 total points
ID: 1350896
Hehe...  Change all your "string"s (in TName you have First and Last, & in TTeam you have Name, FileName and HTTPAddr) to "ShortString"s and it should be fine.  (You can leave "ID : string[03]", because by fixing the length to 3 it's automatically a Short String.)

I'm making this an answer because of the "stdcall" thing, but if you have any more questions...

JB
0
 

Author Comment

by:DelphiOnly
ID: 1350897
JimBob,

actually i have turned off the huge strings by using
{$LONGSTRINGS OFF }. that should work i guess.


and remember that the first time i call my func in the dll, i get all proper values.

i consider the stdcall thing an "excellent" point by the way, but i'll grade your answers once i get some more insight into this.
0
 

Author Comment

by:DelphiOnly
ID: 1350898
OK. i learnt a couple of things :-)

1. compiler options {$H-} are local ! (holy grace, they were global in TP)

2.  {$A-} is needed when passing records to DLLs

Thx for all your comments.
0

Featured Post

[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
Suggested Courses
Course of the Month4 days, 13 hours left to enroll

635 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question