Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Anyone know how to convert C++ multi parameters to Delphi?

416 views
Skip to first unread message

rod

unread,
May 15, 2001, 11:09:05 AM5/15/01
to

I don't remember the true name of it, but in C++ you can define a function with a variable number of parameters. a declaration looks like:
void fn ( int i, ... );

meaning fn accepts an integer, followed by any number of additional parameters, so the following would all be good calls:

fn( 5, "joe" );
fn( 10 );
fn( i, 5, j, 54, 'm' );

My problem is that the PGP SDK takes advantage of this fact and I have to convert the .h files to be used in Delphi. Following is one of the declarations in pgpUserInterface.h

PGPError PGPDecryptionPassphraseDialog(
PGPContextRef context,
PGPKeySetRef recipientKeys,
PGPUInt32 keyIDCount,
const PGPKeyID keyIDList[],
PGPKeyRef *decryptionKey,
PGPOptionListRef firstOption, ... );

Can anyone help???

rod

Barry Kelly

unread,
May 15, 2001, 1:21:09 PM5/15/01
to
"rod" <star...@dailydatainc.com> wrote in message
news:3b014691$1_2@dnews...

> I don't remember the true name of it,

varargs; either ANSI C, or UNIX SysV. #include <stdarg.h> in C, <cstdarg> in
C++ for ANSI standard. #include <varargs.h> for SysV compatibility.

Using the C calling sequence, parameters are passed on the stack, pushed
from right to left, and the caller cleans up. This means that the variable
arguments are pushed first, and the first argument is pushed last. Because
of this, the function will be able to access its fixed arguments. The fixed
arguments must provide enough information about the following variable
parameters for the function to correctly read them off the stack. The
va_start, va_arg & va_end macros are used to implement this functionality in
C. Fundamentally, these macros have got to look further down the stack (and
consequently to higher addresses, since the stack grows downwards) to get
their arguments.

Here's the declarations in stdarg.h (ANSI standard C) from Borland's free
C++ compiler:
http://www.borland.com/bcppbuilder/freecompiler
These macros are used by C functions to access their variable parameter
lists.
///////////////////
typedef void _FAR *va_list;
#define __size(x) ((sizeof(x)+sizeof(int)-1) & ~(sizeof(int)-1))
#define va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR
*)(&parmN)+__size(parmN))))
#define va_arg(ap, type) (*(type _FAR *)(((*(char _FAR *_FAR
*)&(ap))+=__size(type))-(__size(type))))
#define va_end(ap) ((void)0)
///////////////////

Let's try to reverse engineer these macros, to see what they do.

typedef void _FAR *va_list;

va_list is a pointer.

#define __size(x) ((sizeof(x)+sizeof(int)-1) & ~(sizeof(int)-1))

This rounds up the size of X to the nearest boundary of the system's int
size. So, on a 32-bit system, it will give 4 bytes for sizes 1, 2, 3 & 4. It
will give 8 bytes for sizes 5, 6, 7 & 8. Etc.

---------

#define va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR
*)(&parmN)+__size(parmN))))

Let's break this down.

#define va_start(ap, parmN)

A macro that takes two parameters - 'ap', and 'parmN'

(void) (ap) = (va_list)((char _FAR *)(&parmN)+__size(parmN))

The macro without the parentheses around it, becomes a cast of an
assignment, to void.

ap = (va_list) ( (char _FAR *)(&parmN)+__size(parmN) )

The assignment is a cast of an expression to the 'va_list' type.

(char _FAR *)(&parmN) + __size(parmN)

This converts the address of parmN to a pointer, and adds the rounded up
size of parmN to this value.

So, what has va_start() done in the end? In the C Runtime help file, it
says:

***
void va_start(va_list ap, lastfix);
type va_arg(va_list ap, type);
void va_end(va_list ap);

[...]

va_list: This array holds information needed by va_arg and va_end. When a
called function takes a variable argument list, it declares a variable ap of
type va_list.

va_start: This routine (implemented as a macro) sets ap to point to the
first of the variable arguments being passed to the function. va_start must
be used before the first call to va_arg or va_end.

va_start takes two parameters: ap and lastfix. (ap is explained under
va_list in the preceding paragraph; lastfix is the name of the last fixed
parameter being passed to the called function.)
***

va_start has added the size of the last argument (rounded up to the nearest
int-sized boundary, typically 32 bits) to the address of the last argument
(which will be on the stack). Because it added this, it is looking further
down the stack. 'ap' (the variable of type va_list declared in the
implementation C function) will now point at the first variable argument.

---------

#define va_arg(ap, type) (*(type _FAR *)(((*(char _FAR *_FAR
*)&(ap))+=__size(type))-(__size(type))))

Breaking it down:

#define va_arg(ap, type)

The macro declaration. 'type' should be the expected type of this argument;
this information must be provided to the function in some other means.
Typically, it is passed in the printf style with formatting flags like %d,
%s etc in an auxilliary string.

*(type *) (((*(char * *)&(ap))+=__size(type))-(__size(type)))

I've stripped away the external parentheses and the _FAR specifiers. Here,
we have a dereference of a cast to the expected type. The bit on the right
is expected to yield the address of the of the argument.

(*(char * *)&(ap)) += __size(type)) - __size(type)

Here, we have two bits; an operator-assignment, and a subtraction.

*(char * *)&(ap)) += __size(type)

Here's the operator-assignment: in essence, it adds the size of the type
(rounded up to the nearest int-sized boundary) to 'ap' - the va_list
variable declared in the C function. The assignment will return the final
value of 'ap', as a char *.

(modified ap) - __size(type)

The subtraction bit subtracts what was just added to ap.

In essence, this function moves the 'current argument' pointer forward (and
so down the stack) by the rounded-up size of the argument, and then
temporarily moves it back so that it can read that argument from the stack.

---------

#define va_end(ap) ((void)0)

This does nothing, and is probably here to allow possible cleaning up if
that is necessary for portability reasons.

***

To write this stuff properly you'll need to use BASM, Delphi's built in
assembler, and code the call sequence in asm. Hopefully you've got a good
idea of what you need to do. Perhaps a post in the .basm group will help if
you get stuck.

-- Barry
--
Project JEDI: http://www.delphi-jedi.org
NNQ - Quoting Style in Newsgroup Postings
http://web.infoave.net/~dcalhoun/nnq/nquote.html

Rudy Velthuis (TeamB)

unread,
May 15, 2001, 1:33:29 PM5/15/01
to
In article <3b014691$1_2@dnews>, rod says...

> My problem is that the PGP SDK takes advantage of this fact and I have to
> convert the .h files to be used in Delphi. Following is one of the
> declarations in pgpUserInterface.h
>
> PGPError PGPDecryptionPassphraseDialog(
> PGPContextRef context,
> PGPKeySetRef recipientKeys,
> PGPUInt32 keyIDCount,
> const PGPKeyID keyIDList[],
> PGPKeyRef *decryptionKey,
> PGPOptionListRef firstOption, ... );
>
> Can anyone help???

You can either omit anything past the last typed parameter, or write an
assembler wrapper that accepts an "array of const" and maps that, and the
other parameters to stack parameters, also clearing the stack after the
call.

You can of course also define a set of overloaded functions with a
different number of extra parameters (up to the maximum number of extra
parameters you expect), and all map them to the same DLL function.

Or you define one function with the maximum expected number of extra
parameters (you can make them untyped, or Integer).

The last two solutions require a little typecasting from the user though.

Be sure to declare all of them cdecl!
--
Rudy Velthuis (TeamB)

Knoppen

unread,
May 15, 2001, 9:03:50 PM5/15/01
to
Why not use a Pointer

function fn( nbParams: Integer; P: Pinter );

As you do with Argv and Argc in C.

Or even better from Delphi 4 you can override functions.

function foo( I: Integer ): Boolean; override;
function foo( I: Integer; S: String ): Boolean; override;
function foo( I: Integer; P: Pointer ): Boolean; override;
function foo( I: Integer; const Cp: PChar ): Boolean; override;


--
Lars Rosenberg
CEO of Rosoft Engineering, Karlstad - Sweden
Email: La...@RosoftEngineering.com
Homepage: http://www.RosoftEngineering.com/

------------------------------------------------
This email is subject to copyright and is intended only for the person(s)
named. You may not disclose the contents of this email to other person(s)
or take copies of it without the permission of the author.
"Barry Kelly" <barry_...@hotmail.com> wrote in message
news:3b01659d_1@dnews...

Rob

unread,
May 16, 2001, 5:00:55 AM5/16/01
to
I have converted it already, save yourself the hassle and mail me, I'll send
it to you. Assuming that you are using the 1.7.2 SDK??

To answer your question, I declared a delphi function which takes an open
array of PGPOptionListRef, and pushes them onto the stack.

--

rob at fitsy dot com


"rod" <star...@dailydatainc.com> wrote in message
news:3b014691$1_2@dnews...
>

> My problem is that the PGP SDK takes advantage of this fact and I have to

Rudy Velthuis (TeamB)

unread,
May 16, 2001, 6:03:27 AM5/16/01
to
In article <3b0241a3_2@dnews>, Rob says...

> I have converted it already, save yourself the hassle and mail me, I'll send
> it to you. Assuming that you are using the 1.7.2 SDK??

Would you mind donating it to JEDI (http://delphi-jedi.org)?

If so, please contact me. I can make it Borland and JEDI compliant, and
have it put on our website.
--
Rudy Velthuis (TeamB)

Rob

unread,
May 16, 2001, 9:33:45 AM5/16/01
to
Sure, I'll mail you when I get home tonight.

--

rob at fitsy dot com


"Rudy Velthuis (TeamB)"

0 new messages