[Webinar] Streamline your web hosting managementRegister Today

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1110
  • Last Modified:

DECIMALs & Delphi

Hi

Quickly put: I need to use the VarDecFromStr function in oleaut32.dll (Actually I need to use all of the VarDec* functions) and Delphi
doesn't know about it.

Now the long version:

I'm having a few problems using Decimals in Delphi 4 (SP 3). I've got a COM
object written in C++ (MS) that passes a decimal inside a variant.

I eventually figured out how to get the decimal out on the Delphi side but
now I'm trying to create a decimal myself. I'm trying to use VarDecFromStr,
but Delphi 4 (and 5) does not have a header for this function. It's got headers for just about every other variant function in the OLE API but just about nothing related to decimals and variants.

So I went through the source files and found the declaration for VarBstrFromDec (the exact opposite of what I want, although I do use this
one also). So I copied that and changed it to VarDecFromStr (I made the right changes). Amazingly this actually worked.. well sort of. I've debuged
my code (at ASM level) and I definately know that VarDecFromStr is being
called. But as soon as my function (the one that makes the call to VarDecFromStr) exits I get an access violation. I've debugged this also and
it seems that when my function exists it pops the registers off the stack
(as one would expect), but something seems to go a bit wrong and the
execution point ends up at 0x00000000.. obviously a really bad thing.

So... has anyone ever used this before?? Or does anyone know of a header
file that has a delphi conversion of this routine?? Or has anyone got any
ideas??

Thanks
Greg
0
gnagel
Asked:
gnagel
  • 7
  • 7
1 Solution
 
LischkeCommented:
Mmmh, this sounds very like a wrong calling convention. How's the declaration on the Delphi side? Does it contain the stdcall directive?

Ciao, Mike
0
 
gnagelAuthor Commented:
Yup, it's stdcall, I tried all 5 of them, safecall, cdecl, register, etc... no luck. Maybe there's a reason Delphi doesn't have headers for any of the VarDecFrom* functions...
0
 
LischkeCommented:
Yes, this could be true. I'm not sure for what you need those functions and I'm also not sure if you can use them this way at all, as they use datatypes which may not be compatible with Delphi (e.g. what is DECIMAL?).

And even MSDN is very silent about those functions (VarDecFromStr is only mentioned two times, without nearer explanation or an example).

Ciao, Mike
0
[Webinar] Improve your customer journey

A positive customer journey is important in attracting and retaining business. To improve this experience, you can use Google Maps APIs to increase checkout conversions, boost user engagement, and optimize order fulfillment. Learn how in this webinar presented by Dito.

 
gnagelAuthor Commented:
Well Delphi does at least know about a decimal, it's got the definitions for it.

My problem is that I'm using an SDK that we've written and some of the data members are decimals. I've managed to get the decimals out of it, but at the moment I've got no way to put/update it. That's why I need the VarDecFrom* functions, that way I can at least put something back into it.

We've got testers in VB and they handle it fine, ASP doesn't have a problem... at least not yet, and of course C++ works fine. It's just Delphi...

Oh, VarBstrFromDec uses the same parameter types as VarDecFromStr (just in a different order) and it works fine, in Delphi.
0
 
LischkeCommented:
Ah yes, I see there's TDecimal in ActiveX.pas (but no entry in the help file :-/). I'd say your problem has nothing to do with datatypes as you are using the same in both mentioned functions. So it seems there's something different wrong. Read this statement form MSDN:

Remarks
Passing into this function any invalid and, under some circumstances, NULL pointers will result in unexpected termination of the application.
--- end of quote

Strange enough VarDecFromStr is not declared (even in D5), so you must have declared them yourself. Please post the declaration here. Another point I wonder about is that WideStrings are used as parameters, not PWideChars. This is very uncommon!

Ciao, Mike
0
 
gnagelAuthor Commented:
// HEre's Delphi's VarBStrFromDec
//function VarBStrFromDec(pdecIn: PDecimal; lcid: TLCID; dwFlags: Longint; out bstrOut: WideString): HResult; stdcall;

// Here's my VarDecFromStr
{$EXTERNALSYM VarDecFromStr}
function VarDecFromStr(bstrIn: WideString; lcid: TLCID; dwFlags: Longint; out pdecOut: PDecimal): HResult; stdcall;


// Here's the C++ declaration
{
HRESULT VarDecFromStr(
  OLECHAR*  strln,
  LCID  lcid,
  unsigned long  dwFlags,
  DECIMAL *  pdecOut
);
}

const
   oleaut32 = 'oleaut32.dll';

// Here's my VarDecFromStr
function VarDecFromStr; external oleaut32 name 'VarDecFromStr';

// Here's Delphi's VarBstrFromDec
function VarBstrFromDec;                external oleaut32 name 'VarBstrFromDec';

I didn't pick up that MSDN quote, I'll check it out and see if I'm passing through some invalid stuff.

Greg

0
 
gnagelAuthor Commented:
// HEre's Delphi's VarBStrFromDec
//function VarBStrFromDec(pdecIn: PDecimal; lcid: TLCID; dwFlags: Longint; out bstrOut: WideString): HResult; stdcall;

// Here's my VarDecFromStr
{$EXTERNALSYM VarDecFromStr}
function VarDecFromStr(bstrIn: WideString; lcid: TLCID; dwFlags: Longint; out pdecOut: PDecimal): HResult; stdcall;


// Here's the C++ declaration
{
HRESULT VarDecFromStr(
  OLECHAR*  strln,
  LCID  lcid,
  unsigned long  dwFlags,
  DECIMAL *  pdecOut
);
}

const
   oleaut32 = 'oleaut32.dll';

// Here's my VarDecFromStr
function VarDecFromStr; external oleaut32 name 'VarDecFromStr';

// Here's Delphi's VarBstrFromDec
function VarBstrFromDec;                external oleaut32 name 'VarBstrFromDec';

I didn't pick up that MSDN quote, I'll check it out and see if I'm passing through some invalid stuff.

Greg

0
 
gnagelAuthor Commented:
// HEre's Delphi's VarBStrFromDec
//function VarBStrFromDec(pdecIn: PDecimal; lcid: TLCID; dwFlags: Longint; out bstrOut: WideString): HResult; stdcall;

// Here's my VarDecFromStr
{$EXTERNALSYM VarDecFromStr}
function VarDecFromStr(bstrIn: WideString; lcid: TLCID; dwFlags: Longint; out pdecOut: PDecimal): HResult; stdcall;


// Here's the C++ declaration
{
HRESULT VarDecFromStr(
  OLECHAR*  strln,
  LCID  lcid,
  unsigned long  dwFlags,
  DECIMAL *  pdecOut
);
}

const
   oleaut32 = 'oleaut32.dll';

// Here's my VarDecFromStr
function VarDecFromStr; external oleaut32 name 'VarDecFromStr';

// Here's Delphi's VarBstrFromDec
function VarBstrFromDec;                external oleaut32 name 'VarBstrFromDec';

I didn't pick up that MSDN quote, I'll check it out and see if I'm passing through some invalid stuff.

Greg

0
 
LischkeCommented:
Mmmh, seems all fine. I ran now out of ideas. Have you tried to vary the VarDecFromStr declaration? E.g. take out the "out" keyword or use "out pdecOut: TDecimal". If you can make a small demo program then send it to me and I debug it here (public@lischke-online.de).

Ciao, Mike
0
 
gnagelAuthor Commented:
I'll do a bit of fiddleling this afternoon and see if I can anything, also get a demo program for you.

Thanks
Greg
0
 
LischkeCommented:
Hi Greg, I think I found it. After fiddling with calling conventions againa and a bit low level debugging I found out the stack is overwritten partially when calling VarDecFromStr. After thinking another while I came to the conclusion that the out keyword is wrong in the function declaration (as is the safecall convention). Better said: it isn't wrong but you need to consider that it is to your parameter as would you set "var" instead of "out". You can actually use "out", but it is used for interfaces not for normal structures. Anyway, pick one of both correct solutions:

function VarDecFromStr(bstrIn: WideString; lcid: TLCID; dwFlags: Longint; var pdecOut: TDecimal): HResult; stdcall;

function VarDecFromStr(bstrIn: WideString; lcid: TLCID; dwFlags: Longint; out pdecOut: TDecimal): HResult; stdcall;

Ciao, Mike
0
 
LischkeCommented:
After reading again what I wrote in my last comment, I realized that I haven't mentioned the most important fact (but I believe you saw it already in the provided solution).

Using "var" with a structure is the same (seen from the view of parameter passing) as using no modifier and passing a pointer to the structure. So if you write "out pdecOut: PDecimal" your are passing a pointer to a pointer to a structure.

Ciao, Mike
0
 
gnagelAuthor Commented:
IT WORKED!!

The final code is:
function VarDecFromStr(bstrIn: WideString; lcid: TLCID; dwFlags: Longint; out pdecOut: TDecimal): HResult; stdcall;

Var
   apDecimal : PDecimal;
begin
   VariantInit(Data);  // Initialize variant
   apDecimal := PDecimal(@Data);
   VarDecFromStr(aString, LOCALE_SYSTEM_DEFAULT, 0, apDecimal^);

Changing the out param to TDecimal fixed everything.

Thanks alot for the assistance Mike, I really appreciate it.

Greg
0
 
LischkeCommented:
Glad to help you :-))

Ciao, Mike
0

Featured Post

[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

  • 7
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now