BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Help with CBuilder typedef for Delphi DLL function

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (ActiveX)
View previous topic :: View next topic  
Author Message
Kevin Buckle
Guest





PostPosted: Wed Jun 23, 2004 3:26 am    Post subject: Help with CBuilder typedef for Delphi DLL function Reply with quote



Hi all

I have to use functions from a third-party DLL in a CBuilder application. I
presume the DLL is written in Delphi - all I have is a list of the function
declarations within the DLL. I can successfully use most of the functions
but one is proving to be a real problem. The function in question is
defined as:

function GetNewValue(ID,Start,End:PChar; var Value:TBStr):Integer

What should I use for the TBStr data-type? My typedef currently looks like
this:

typedef int (__stdcall *pDLL_GetNewValue) (char*,char*,char*,AnsiString*);

I'm sure I shouldn't be using an AnsiString here (should I?) but it's the
only way it works. I've had no success using WideString, BSTR or char*
instead but I may be doing it incorrectly.

Unfortunately, after several calls to this function I get an AV on the call.
It is the only DLL call which causes a problem and it is the only one with a
TBStr parameter.

I'm using:
...
pDLL_GetNewValue DLL_GetNewValue;
...
result = DLL_GetNewValue(szID,szStart,szEnd,&asValue);

for the function call.

Is anyone able to offer any help?

Many thanks

Kevin


Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Jun 23, 2004 7:57 am    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote




"Kevin Buckle" <kevin.buckle (AT) nospam (DOT) co.nz> wrote


Quote:
What should I use for the TBStr data-type?

BSTR, except in this case the original parameter is declared using 'var' so
it would be BSTR* instead, ie:

typedef int (__stdcall *pDL_GetNewValue)(char*, char*, char*, BSTR*);

Quote:
I've had no success using WideString, BSTR or char*
instead but I may be doing it incorrectly.

Please show the actual code you have tried using WideString or BSTR which
did not work for you.

Quote:
Unfortunately, after several calls to this function I get an AV on the
call.


Again, please show your actual code. Also, is the original function
actually declared using 'stdcall'? If not, then you need to use __fastcall
instead of ___stdcall in your typedef.

Quote:
result = DLL_GetNewValue(szID,szStart,szEnd,&asValue);

What is asValue declared as? Your naming convention suggests an AnsiString.


Gambit



Back to top
Kevin Buckle
Guest





PostPosted: Thu Jun 24, 2004 1:44 am    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote



Yes - I originally used the declaration you suggested using BSTR*. This
didn't produce any AVs but I was unable to decipher the returned value. See
the example below. Unfortunately I have no access to the DLL function code
to check the actual function declarations. I tried __fastcall originally
and that gave an AV every time any of the functions were called. All the
other functions from the DLL work fine using __stdcall so I stuck with this.
Yes again, asValue is declared as an AnsiString in the example I gave in the
original post.

This is an example of a test attempt using BSTR* and WideString:

typedef int (__stdcall *pDLL_GetNewValue)(char*, char*, char*, BSTR*);
....
EDLL_Result Result; // enumerated type for DLL integer return
codes
WideString wsValue; // time of maximum value in period (in form
"hh:nn")
bool Finished=false;

while (!Finished)
{
// loop forever until AV
Result = DLL_GetNewValue("temperature","12:45","15:00",&wsValue);
// display wsValue - how?
Sleep(300);
}

This all works fine (no AV's after thousands of repeated calls) except I
have been unable to decipher the returned text in the wsValue parameter.
Maybe this is my real problem? I tried AnsiString(wsValue) but I just get
question marks in the string. Using AnsiString* in the typedef and passing
in a &AnsiString I get "13:00" returned in the AnsiString (which is the
correct result). I guess there must be something I have to do with the
returned WideString before I can read it and display it?

Passing a WideString into a function expecting a BSTR works fine: in the
function I can convert the passed value back into a WideString and then
straight into an AnsiString for display in a TLabel. It's reading the
return value from a BSTR* parameter that's the problem. I'm going to do
some work on this and will post a small sample of code with my findings.

Thanks for your help, it's much appreciated.

Kevin

"Remy Lebeau (TeamB)" <gambit47.no.spam (AT) no (DOT) spam.yahoo.com> wrote

Quote:

"Kevin Buckle" <kevin.buckle (AT) nospam (DOT) co.nz> wrote in message
news:40d8f8db$1 (AT) newsgroups (DOT) borland.com...

What should I use for the TBStr data-type?

BSTR, except in this case the original parameter is declared using 'var'
so
it would be BSTR* instead, ie:

typedef int (__stdcall *pDL_GetNewValue)(char*, char*, char*, BSTR*);

I've had no success using WideString, BSTR or char*
instead but I may be doing it incorrectly.

Please show the actual code you have tried using WideString or BSTR which
did not work for you.

Unfortunately, after several calls to this function I get an AV on the
call.

Again, please show your actual code. Also, is the original function
actually declared using 'stdcall'? If not, then you need to use
__fastcall
instead of ___stdcall in your typedef.

result = DLL_GetNewValue(szID,szStart,szEnd,&asValue);

What is asValue declared as? Your naming convention suggests an
AnsiString.


Gambit





Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Thu Jun 24, 2004 2:11 am    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote


"Kevin Buckle" <kevin.buckle (AT) nospam (DOT) co.nz> wrote


Quote:
Unfortunately I have no access to the DLL function code to check the
actual function declarations.


I suggest you find a way to getaccess, because that seems to be the root of
the problem - you are obviously mangling something up somewhere. Where did
you get the original Delphi declarations from?

Quote:
Yes again, asValue is declared as an AnsiString in
the example I gave in the original post.

You did not show the actual declaration for asValue in your original
posting, hense my earlier comments.

Quote:
WideString wsValue; // time of maximum value in period (in form

You are declaring the WideString outside of the while() loop.

Quote:
Result = DLL_GetNewValue("temperature","12:45","15:00",&wsValue);

You are then retreiving a value from the function into the WideString, but
you are not clearing the previous WideString value first. You are going to
leak memory that way since the BSTR stored inside the WideString won't get
freed properly. You should either move the WideString into the loop so that
it goes out of scope each time and is freed automatically, or else call the
WideString's Empty() method before than calling the DLL function.

Quote:
// display wsValue - how?

WideString can be used pretty much anywhere that expects an AnsiString.
Thus you can use it for ShowMessage(), MessageDlg(), component captions,
etc. just like you would with AnsiString. AnsiString has a conversion
constructor that accepts WideString and will convert the BSTR data into
char* data accordingly.

Quote:
Using AnsiString* in the typedef and passing in a &AnsiString
I get "13:00" returned in the AnsiString (which is the correct result).

That suggests then that the function is actually returning a char* string
even though it is declared to return a BSTR string instead. The two are not
the same thing, so the function behavior is in contradiction to its
declaration.

Quote:
It's reading the return value from a BSTR* parameter
that's the problem.

Please show a more complete code snippet that shows exactly what you are
doing.


Gambit



Back to top
Kevin Buckle
Guest





PostPosted: Thu Jun 24, 2004 3:33 am    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote


"Remy Lebeau (TeamB)" <gambit47.no.spam (AT) no (DOT) spam.yahoo.com> wrote


Quote:
I suggest you find a way to getaccess, because that seems to be the root
of
the problem - you are obviously mangling something up somewhere. Where
did
you get the original Delphi declarations from?

Working on that - original declarations listed in an htlm help file included
in the application folder where the DLL sits. The DLL is shipped with a
large, complex application that uses a proprietary database for data
storage. The DLL is intended to provide third-party access to the data.
Have contacted the application vendor for assistance.

Quote:
You are declaring the WideString outside of the while() loop.


Yes - this was just a quick test I set up and I overlooked that. Doesn't
affect the result though (apart from the obvious memory leak).

Quote:
WideString can be used pretty much anywhere that expects an AnsiString.
Thus you can use it for ShowMessage(), MessageDlg(), component captions,
etc. just like you would with AnsiString. AnsiString has a conversion
constructor that accepts WideString and will convert the BSTR data into
char* data accordingly.

Unfortunately I'm already familiar with this which leads to your next
comment ...

Quote:
That suggests then that the function is actually returning a char* string
even though it is declared to return a BSTR string instead. The two are
not
the same thing, so the function behavior is in contradiction to its
declaration.

That's more or less what I had concluded - hence my original post. I should
have been more clear at the outset.

Quote:
Please show a more complete code snippet that shows exactly what you are
doing.

For the moment I'm just trying to read the returned WideString parameter
into a label. It's about as simple as I can make it.

The following displays "???" in the label:

typedef int (__stdcall *pDLL_GetNewValue) (char*,char*,char*,BSTR*);
pDLL_GetNewValue DLL_GetNewValue;

WideString wsValue;
DLL_GetNewValue("temperature","12:45","15:00",&wsValue);
lblReturnedText->Caption = AnsiString(wsValue);


And this displays "13:00" in the label.

typedef int (__stdcall *pDLL_GetNewValue)
(char*,char*,char*,AnsiString*);
pDLL_GetNewValue DLL_GetNewValue;

AnsiString asValue;
DLL_GetNewValue("temperature","12:45","15:00",&asValue);
lblReturnedText->Caption = asValue;

I assumed that I couldn't use BSTR* for the TBSTR parameter due to the
results I had in the test code above or that I had a fundamental
misunderstanding of BSTR and WideString.

I may just have to wait for some info from the DLL author(s).

Once again, thanks for your time and assistance.

Kevin



Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Thu Jun 24, 2004 7:34 am    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote


"Kevin Buckle" <kevin.buckle (AT) nospam (DOT) co.nz> wrote


Quote:
typedef int (__stdcall *pDLL_GetNewValue) (char*,char*,char*,BSTR*);
pDLL_GetNewValue DLL_GetNewValue;

WideString wsValue;
DLL_GetNewValue("temperature","12:45","15:00",&wsValue);
lblReturnedText->Caption = AnsiString(wsValue);

There is nothing wrong with that code, assuming the DLL function actually
returns a BSTR to begin with.

Quote:
AnsiString asValue;
DLL_GetNewValue("temperature","12:45","15:00",&asValue);

That is dangerous code. AnsiString has specific requiremenets for how its
memory is handled internally. You can't just allocate a character array and
then assign it to the AnsiString's internals directly. The only way that
code could be safe is if the DLL function is returning an actual AnsiString,
not a raw char* string.

Quote:
I assumed that I couldn't use BSTR* for the TBSTR
parameter due to the results I had in the test code above

var TBStr = BSTR*


Gambit



Back to top
Kevin Buckle
Guest





PostPosted: Thu Jun 24, 2004 9:07 pm    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote

"Remy Lebeau (TeamB)" <gambit47.no.spam (AT) no (DOT) spam.yahoo.com> wrote


Quote:
AnsiString asValue;
DLL_GetNewValue("temperature","12:45","15:00",&asValue);

That is dangerous code. AnsiString has specific requiremenets for how its
memory is handled internally. You can't just allocate a character array
and
then assign it to the AnsiString's internals directly. The only way that
code could be safe is if the DLL function is returning an actual
AnsiString,
not a raw char* string.

Agreed! The AV's and memory leakage experienced using this version suggest
that the DLL is *not* returning an AnsiString.

Quote:
var TBStr = BSTR*

I found this definition of TBStr on the MSDN site - concerning .NET
framework class library (the only place on the web I could find any
reference to a TBStr).

"TBStr (Supported by the .NET Compact Framework)
- A length-prefixed, platform-dependent char string. ANSI on Windows 98,
Unicode on Windows NT.
- You rarely use this BSTR-like member."

Is this a completely different data type with a coincidentally identical
name? It seems to explain the behaviour I'm seeing. It's a char string
(rather than a widestring) but it's length prefixed. I'm passing in a
(pointer to) BSTR (wchar based) which the DLL treats as char based and
returns a (pointer to) length-prefixed char string, which seems to keep the
memory management happy but obviously it's not a "real" BSTR so the
conversion back to an AnsiString in my app gives rubbish? Does that make
any sense? I'm not really sure what I mean myself - I'll have to give it
some more thought Smile If so, maybe I can extract the correct string from the
returned BSTR?

The definition from the MSDN site suggests that I shouldn't be using a BSTR
in place of the TBStr parameter. This seems odd anyway - why wouldn't the
function just use BStr* rather than TBStr* (there is a BStr type in Delphi
isn't there?).



Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Thu Jun 24, 2004 9:18 pm    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote

"Kevin Buckle" <kevin.buckle (AT) nospam (DOT) co.nz> wrote


Quote:
Agreed! The AV's and memory leakage experienced
using this version suggest that the DLL is *not*
returning an AnsiString.

If it is an ActiveX DLL, then it should be returning a BSTR. Your earlier
observations suggest otherwise, though.

Quote:
I found this definition of TBStr on the MSDN site

All of Microsoft's stuff applies to C++, not Pascal. In any case, TBStr is
declared in the VCL's ole2 unit as the following:

POleStr = PWideChar;
TBStr = POleStr;

Which translates to the following in ole2.hpp for C++:

typedef wchar_t *TBStr;

For most intents and purposes, that is correct (BSTR is slightly more
complicated than just being a simple wchar_t* string, though).

Quote:
Is this a completely different data type with a
coincidentally identical name? It seems to explain
the behaviour I'm seeing.

Is the DLL in question designed for use with .NET? Which OS are you
actually running your code under at the time the string returns gibberish
when treated as BSTR?


Gambit



Back to top
Alan Bellingham
Guest





PostPosted: Thu Jun 24, 2004 11:18 pm    Post subject: Re: Help with CBuilder typedef for Delphi DLL function Reply with quote

"Remy Lebeau (TeamB)" <gambit47.no.spam (AT) no (DOT) spam.yahoo.com> wrote:

Quote:
For most intents and purposes, that is correct (BSTR is slightly more
complicated than just being a simple wchar_t* string, though).

This may bear expanding.

A BSTR is indeed a wchar_t* pointer. However, it doesn't point at the
start of the memory that was allocated, but along a bit, at the start of
the wide character data itself. Before that is a length count:

---------------------------------------------------------
Quote:
Len | ch | ch | ch | ch | ...
---------------------------------------------------------

^ ^
Quote:
|
`-- what the user sees as the start

What the underlying code knows is the start


So, when SysAllocString is called, memory is allocated from the OS. The
pointer is then incremented before being returned. When SysFreeString is
called, the reverse happens - the pointer is decremented before the
memory is released to the OS.

When SysStringLen is called by a client to discover the string length,
it just looks at the place before the string data to find the answer.
This means that BSTRs do not have to use null terminators to get things
right - they may have embedded nulls if desired.

The outcome of this is that passing a raw wchar_t* into a routine that
wants a BSTR may work, or it may not. It will blow up in very bad ways
if the routine does SysStringLen to find out how long the string
actually is. Since this is a pretty sensible thing for the client to
want to do, beware.

Alan Bellingham
--
Team Thai Kingdom
<url:http://www.borland.com/newsgroups/> Borland newsgroup descriptions
<url:http://www.borland.com/newsgroups/netiquette.html> netiquette

Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (ActiveX) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.