Solved

VB Calling Delphi

Posted on 2001-07-31
24
283 Views
Last Modified: 2010-04-06
I have a VB DLL that is calling a Delphi DLL to retrieve a string. It seems to work fine with short strings but every once and a while with a longer string (> 255) I get an exception and the VB app crashes.

The Delphi function is defined as follows:
function WebSessionStatus(pSession, D: string): string; stdcall;

It returns the string as follows:
S := S + '~#@#@'
p := StrAlloc(length(S) + 1);
Result := StrPCopy(P,S);

Is it the definition of string that is causing my problem?
How can this be done so that the function works correctly every time?
0
Comment
Question by:trgrieb
  • 9
  • 8
  • 2
  • +3
24 Comments
 
LVL 5

Expert Comment

by:scrapdog
ID: 6339245
Did you write the Delphi DLL?  If you can change the Delphi DLL, you will to do so.

You have two choices:

1.

DLLs in Delphi are not very friendly with strings, unless you include the ShareMem unit in your uses clause (as the first unit listed).  If you do this, you will also have to distribute BORLANDMM.DLL with your application.  Somehow VB will have to use this DLL as well (I am not sure how you do this).

If you can be certain that the strings are going to be short strings, you do not need to do this.


2.

An alternative is to redeclare your function to accept and return "PChar" rather than string.  If you do this, you won't be directly working with strings and do not need to include ShareMem and BORLANDMM.DLL.

However, you do have to go through the tedium of converting PChars to strings and vice versa.
0
 
LVL 5

Expert Comment

by:scrapdog
ID: 6339247
>you will to do so

I mean, you will have to do so
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6339362
I don't think you can make VB use borlndmm.dll correctly. The usual way to make your Delphi dll work with other languages is to use pchar, like scrapdog already pointer out. But please note, that you have to care about who allocated and who frees the pchar strings. Look how Windows APIs solve this problem. E.g. when calling GetWindowText or GetComputerName or GetUserName or most other string returning functions, you must give a buffer, in that the API then copies the string characters. Most of the time the maximal buffer size is either predefined or you have a possibility to ask which size is needed. E.g. when calling RegQueryValueEx you can ask how big the buffer has to be.
Then there are some APIs (only a few) which allocate a buffer for you. E.g. some of the NT network related APIs. In that case you need to free the buffer later by calling NetApiBufferFree.
A third approach would be that you allocate the buffer with LocalAlloc and that the caller needs to free it with LocalFree again.

You can use either approach, but you have to make it clear, so the VB programmer knows what to do.

Regards, Madshi.
0
Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

 
LVL 21

Expert Comment

by:ziolko
ID: 6339421
In "Delphi DLL" use WideString not string, then You will have no problems with length of string and no problem with allocateing/deallocateing buffers.
ziolko.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6339809
Hi ziolko,

I don't think so. Why should a wideString work better than a normal string? I see no reason for that.

Regards, Madshi.
0
 

Expert Comment

by:Zereter
ID: 6340725
The WideString is defined as "WideStrings are dynamically allocated with a maximum length limited only by available memory" (quoted from Delphi 5 help) Wouldn't that take care of the string limitation. Also Delphi has a AnsiString or LongString which is basicly a pointer.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6341955
The type "string" that is used in the original question text is the same as an AnsiString or LongString, these types are all identical (except if you have set very strange Delphi options). A wideString is basically the same as a "string/AnsiString/LongString", except that it uses 2 bytes per character, not one. So neither wideString, nor AnsiString nor LongString really makes a difference to what was used in the original question text. All those types are not compatible with any other language. They're purely Delphi contructs, which furthermore need that ugly "borlndmm.dll" if you use a Delphi application/dll combo, which wants to use strings/wideStrings. So all this stuff is really not the correct solution here, at least IMHO...   :-/

Regards, Madshi.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6344816
Useing string causes access violation errors, WideString not. Also COM/DCOM DLLs use WideString, I supose WideString is more "friendly" for Windows (don't ask me why)
ziolko.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6345203
>> Useing string causes access violation errors, WideString not.

I don't believe that. Both cause access violation when used improperly.

>> Also COM/DCOM DLLs use WideString

Heh? COM DLLs use PWideChar, not WideString!!!

>> I supose WideString is more "friendly" for Windows (don't ask me why)

Windows doesn't know Delphi's WideString format, Windows just knows a zero-terminated wideChar array -> PWideChar.

Regards, Madshi.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6350400
Madshi maybe You are right I don't know, all I know is that when I use WideString I don't have problems like when useing string.(of course the best way is to use PChar but WideString is easier, You don't have to worry about allocateing/deallocateing memory)
ziolko.  
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6351175
Maybe, but the problem is that if you do this in Delphi:

function GiveMeAString : WideString;
begin
  result := ...;
end;

exports GiveMeAString;

And then declare this function differently in C++ or VB, then Delphi's reference counting gets confused. The function "GiveMeAString" increments the reference counter, and the caller of this function normally decrements it again, if it is not needed anymore. But since C++ and VB don't know Delphi's string logic, they never decrement the reference counter. As a result the string is never freed anymore. So you not only have to worry about allocating/freeing, you can't even prevent memory leaks when using WideString/String like this.
Maybe you won't even get crashes, maybe it *seems* to run fine. But believe me: at least you have a built in memory leak, everytime C++ or VB calls your function...   :-(

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6351194
Hmmm... If I tried calling the GiveMeAString function as if it would be "PWideChar", I get an exception. ziolko, how are you declaring the function in C++ or VB? Which string type do you use? I don't understand why you don't get an exception... Hmmm... Strange...
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6355570
Madshi >> Which string type do you use?
Please give me couple of days to check it out, all my VB projects are back in office (I don't write in VB very often so I need look into source code) and right now I have my vacation.
ziolko.
0
 

Author Comment

by:trgrieb
ID: 6359787
I have gotten this to work with the following code.

Similar to the techniques used in calling the Windows API, the VB calling function needs to set up a buffer for the string and then pass a pointer to that buffer. You can do this in VB by using ByVal in the call. The Delphi module then fills that buffer rather than returning a result.

The VB code looks like this:
Declare Function CallDelphi Lib "thedll.dll" (Byval parm as string, byval returnbuffer as string) as long

Dim resultbuffer as string
Dim returncode as long

resultbuffer = string$(2000, " ")
returncode = CallDelphi("parm string", resultbuffer)

The Delphi code looks like this:
function CallDelphi(parm: ansistring; resultbuffer pchar): integer
s: string;

Note that if I defined parm as string, it blew up. Ansistring solved that.

Then you just fill the buffer

s := "Some string to return. Limited to the 2000 character buffer size";
StrPCopy(resultbuffer, s);
Result := 0;

And everything works fine.

Thanks for all the input.
0
 
LVL 20

Accepted Solution

by:
Madshi earned 200 total points
ID: 6359819
>> The Delphi code looks like this:
>> function CallDelphi(parm: ansistring; resultbuffer pchar): integer
>> Note that if I defined parm as string, it blew up. Ansistring solved that.

That is quite suspiscous. Why are you using AnsiString there at all? As I said, even if you get no exceptions, the reference counting will get confused. Please use pchar instead.

Delphi's help says, that string and AnsiString are identical, if the compiler check {$H+} is set (this is the default). Only if you set {$H-}, string and AnsiString are different. But that is not the default.

Regards, Madshi.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6361388
Damn!! Madshi You are right!!! even if I get no exceptions, there are memory leaks!!!.
ziolko.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6361688
:-)  How did you test that? Were you able to reproduce the leaks? I'm just asking for my personal interest...
0
 

Author Comment

by:trgrieb
ID: 6361911
Well I certainly don't want any memory leaks.

I don't understand why it began working when the only change I made was from string to ansistring. I don't even know how to change the default setting.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6362757
Don't understand the ansistring<->string, either. Please just try it with pchar. It should work, too. And you won't have any memory leaks this way...
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6363321
Madshi > WinNT's TaskManager shows it clearly
ziolko.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6363326
Madshi > WinNT's TaskManager shows it clearly
ziolko.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 8730082
Is this Q still open?
ziolko.
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 8735078
No comment has been added lately, so it's time to clean up this TA.
I will leave a recommendation in the Cleanup topic area that this question is:

Accept madshi's comment as answer

Please leave any comments here within the next seven days.
 
PLEASE DO NOT ACCEPT THIS COMMENT AS AN ANSWER!
 
Thank you,
Russell

EE Cleanup Volunteer
0

Featured Post

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Delphi : could not find program, '...exe' 2 168
how to center only a line in richedit? 4 57
SUM 2 INTEGER ARRAYS INTO 1 10 100
Twebbrowser add css to the header 3 25
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

776 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