I thought it was clear, no ? He declares his function as
STATUS PackOutputBuffer(
PUCHAR puOutBuf_o,
PUINT32 pu32NumBytes_o,
PVOID ArgumentList_i,
… )
His code does this:
Argument = ArgumentList_i; //first argument
u32OutStatus = *((PUINT32)Argument);
RtlCopyMemory ((puOutBuf_o + u32CurBuffPos),&u32OutStatus,STATUS_SIZE);
Meaning, the first argument must be a pointer. Now he does a va_arg() to get
the second argument, which is a length, and he tests it for NULL. Meaning,
his argument list must be of the form
pointer, length, pointer, length, pointer, length, …, …, pointer, 0
because he tests every *second* element of his list for null.
So, the minimum number of arguments to be passed is 2, not 1, and he must
pass parameters in pairs, never an odd number of them. He calls his function
this way:
PackOutputBuffer(pu8OutBuf, &u32NumBytes, (PVOID)&u32BlstStatus );
when he should rather call it this way:
PackOutputBuffer(pu8OutBuf, &u32NumBytes, (PVOID)&u32BlstStatus, 0 );
because the way he coded things, in pairs, precludes passing an odd number
of parameters to his function. I don’t know, I would declare a structure
such as
typedef struct { int len; char *ptr; } myStruct;
and pass a single list of structures to the function. If nothing else,
provides for cleaner code.
Alberto.
-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of J. J. Farrell
Sent: Wednesday, April 28, 2004 3:48 PM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] Variable Number of Argument function in WDM
I confess I’m losing track of this discussion. I described what the OP’s
code does. Why should he change it (unless he wants it to do something
else)? Unless my eyesight or brain is failing, your handling of unnamed
parameters is identical to his except that his expects pairs of unnamed
parameters followed by a null pointer whereas yours expects singles.
“Moreira, Alberto” wrote in message
news:xxxxx@ntdev…
> If the OP wants to pass zero or more parameters followed by a NULL
pointer,
> it’s simple enough to do it the way I suggest, which is the same way shown
> in Microsoft’s MSDN description of va_arg(). That is, define the function
as
> follows:
>
> void myfunc(foo bar, char* parmList, …);
> {
> va_list vaList;
> char* ptr = parmList;
> va_start(vaList, parmList);
> setupWhateverElseNeedsToBeSetUp();
> while (ptr != NULL)
> {
> handleThisArg(ptr);
> ptr=va_arg(valist,char*);
> }
> doWhateverElseIsNeeded();
> }
>
> and he will be able to pass zero, one or more parameters as long as
they’re
> followed by a NULL.
>
>
> Alberto.
>
>
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com]On Behalf Of J. J. Farrell
> Sent: Wednesday, April 28, 2004 3:02 PM
> To: Windows System Software Devs Interest List
> Subject: Re:[ntdev] Variable Number of Argument function in WDM
>
>
> I think you’re making it seem more complicated than it is. It’s perhaps
> easier to think in these terms: the call to va_start must specify the
> last parameter that is explicitly declared (the last “named parameter”),
> the first call to va_arg gives the first parameter that is not explicitly
> declared (the first “unnamed parameter”), subsequent calls to va_arg
> retrieve subsequent unnamed parameters. There are ways to do fancier
> things, but that’s the basics.
>
> The original poster’s code expects zero or more pairs of unnamed
> parameters followed by a null pointer. If it gets that it should be
> happy, unless he has problems elsewhere.
>
> This functionality is standard C - there’s nothing MS-specific here.
>
> “Moreira, Alberto” wrote in message
> news:xxxxx@ntdev…
> > Ok, I believe I found the reason why I always get the second parameter
the
> > first time I call va_arg(). The MSDN documentation states that
va_start()
> is
> > called as follows:
> >
> > va_start(arg_ptr, prev_param)
> >
> > where “prev_param” is the parameter ONE BEFORE the first element of the
> list
> > ! To quote the MSDN documentation,
> >
> > ====================================
> > va_start sets arg_ptr to the first optional argument in the list of
> > arguments passed to the function. The argument arg_ptr must have va_list
> > type. The argument prev_param is the name of the required parameter
> > immediately preceding the first optional argument in the argument list.
If
> > prev_param is declared with the register storage class, the macro’s
> behavior
> > is undefined. va_start must be used before va_arg is used for the first
> > time.
> > ====================================
> >
> > So, if I call va_start(valist, myList), this is stating that myList is
the
> > “one before” parameter, therefore the first element I get when I call
> > va_arg() is actually the SECOND argument in the list.
> >
> > Somehow I think the Unix way was more sensible, but hey, this is how the
> > ANSI standard works.
> >
> >
> > Alberto.
> >
> >
> >
> > -----Original Message-----
> > From: xxxxx@lists.osr.com
> > [mailto:xxxxx@lists.osr.com]On Behalf Of Moreira, Alberto
> > Sent: Wednesday, April 28, 2004 11:24 AM
> > To: Windows System Software Devs Interest List
> > Subject: RE: [ntdev] Variable Number of Argument function in WDM
> >
> >
> > I got it to work the following way. Note a few caveats:
> >
> > 1. The variable argument list passed to the procedure must have your
own
> > end marker. I use NULL.
> > 2. The first call to va_arg() gives me the second argument. Don’t
ask
> me
> > why.
> > 3. To get the first argument, you just use an “arg=parameter” line.
> >
> > If you go to the MSDN Library and ask for va_arg, they have a source
> program
> > that explains it pretty decently. Hope this helps !
> >
> > Alberto.
> >
> > =============
> >
> > #include <string.h>
> >
> > void poBuffer(char *aList, …)
> > {
> > va_list valist;
> > va_start(valist,aList);
> > char arg = aList;
> >
> > int count=0;
> >
> > while (arg!=NULL)
> > {
> > printf(“%d. %s\n”, count, arg);
> > arg = va_arg(valist,char);
> > count++;
> > }
> > }
> >
> >
> > main()
> > {
> > char *p = “hello”;
> > char *q = “there”;
> > poBuffer(p, NULL);
> > printf(“=====================\n”);
> > poBuffer(p, q, NULL);
> > return 0;
> > }
> >
> >
> >
> >
> > -----Original Message-----
> > From: xxxxx@lists.osr.com
> > [mailto:xxxxx@lists.osr.com]On Behalf Of J. J. Farrell
> > Sent: Tuesday, April 27, 2004 10:32 PM
> > To: Windows System Software Devs Interest List
> > Subject: Re:[ntdev] Variable Number of Argument function in WDM
> >
> >
> >
> > “Ray Trent” wrote in message
> > news:xxxxx@ntdev…
> > >
> > > Use a debugger, and look at the return values of va_arg at each call
> > > when only 1 argument is passed.
> > >
> > > The first time, it’s ArgumentList_i,
> >
> > I haven’t used a debugger. If what you say is true then it
> > looks like there’s a major problem with the implementation.
> > The first call to va_arg should return the value of the
> > first unnamed parameter.
> >
> > > the second time it’s null,
> >
> > If only one unnamed parameter is passed, then a second call
> > to va_arg results in C’s ‘undefined behaviour’. At that
> > point all bets are off and anything can happen.
> >
> > > and the
> > > third time you call it, it’s completely undefined. It might be a
> > > reasonable value, it might not.
> > >
> > > That third call needs to be inside the if for the second one. (at
> > > least… I haven’t really thought much about how to design this
better,
> > > though I’m pretty sure it can be).
> >
> > The ‘variable arguments’ aspects of this code should be fine
> > as long as there is an odd number of unnamed parameters and
> > the last one is a PVOID with value NULL. If there is a single
> > unnamed parameter that’s a NULL PVOID, then the contents of
> > the while loop should never be executed.
> >
> > If the calls to this function meet these conditions but the
> > while loop doesn’t behave, then something else is screwing
> > things up.
> >
> > > J. J. Farrell wrote:
> > >
> > > > “SUJA JAMES” wrote in message
> > news:xxxxx@ntdev…
> > > >
> > > >>I have a variable list of argument function which copies
> > > >>all the specified buffer content into a single buffer.
> > > >>I am listing the source code of this function. In this
> > > >>function even if I pass a single variable in the variable
> > > >>argument list, while loop in this function is getting
> > > >>executed. I tested this code in User mode and is working
> > > >>fine.
> > > >
> > > >
> > > > It looks like this ought to work for any odd number of unnamed
> > > > arguments as long as the last argument is PVOID with value NULL.
> > > > Calling it with an even number of unnamed parameters, or with the
> > > > last one not a NULL PVOID, results in C’s ‘undefined behavior’.
> > > >
> > > > If you are meeting these conditions and seeing problems, I’d check
> > > > your copies to make sure you’re not corrupting yourself somewhere.
> > > >
> > > >
> > > >>STATUS
> > > >>PackOutputBuffer(
> > > >> PUCHAR puOutBuf_o, //output buffer to be filled
> > > >> PUINT32 pu32NumBytes_o, //Number of bytes copied in
> > > >>out buf
> > > >> PVOID ArgumentList_i, //variable list of arguments
> > > >>… //Variable number of arguments
> > > >>)
> > > >>{
> > > >>
> > > >>va_list valist;
> > > >>PVOID Argument = NULL;
> > > >>UINT32 u32OutStatus =0;
> > > >>UINT32 u32CurBuffPos = ZERO;
> > > >>UINT8 uArgLen = ZERO;
> > > >>UINT8 puArg = NULL;
> > > >>
> > > >> if ( NULL == ArgumentList_i )
> > > >>return INVALIDPARAM;
> > > >>
> > > >>if ( ( NULL == puOutBuf_o ) || ( NULL ==
> > > >>pu32NumBytes_o))
> > > >>return INVALIDPARAM;
> > > >>
> > > >>Argument = ArgumentList_i; //first argument
> > > >>
> > > >>//first element is always status with 4 bytes length
> > > >>u32OutStatus = *((PUINT32)Argument);
> > > >>RtlCopyMemory ((puOutBuf_o +
> > > >>u32CurBuffPos),&u32OutStatus,
> > > >>STATUS_SIZE);
> > > >>u32CurBuffPos += STATUS_SIZE;
> > > >>
> > > >>//Initialize variable arguments
> > > >>va_start(valist,ArgumentList_i);
> > > >>
> > > >>//go throught the list until no more aruguments
> > > >>Argument = va_arg( valist, PVOID);
> > > >>
> > > >>while( NULL != Argument )
> > > >>{
> > > >>// Now onwards first argument is length, next is
> > > >>buffer
> > > >> uArgLen = *((PUINT8)Argument);
> > > >> //get the buffer
> > > >> Argument = va_arg( valist, PVOID);
> > > >> if ( NULL != Argument)
> > > >> {
> > > >>//copy this to the output buffer
> > > >>RtlCopyMemory ((puOutBuf_o +
> > > >>u32CurBuffPos),Argument, uArgLen);
> > > >>u32CurBuffPos += uArgLen;
> > > >> }
> > > >> //get next one
> > > >>Argument = va_arg( valist, PVOID);
> > > >>} // end of while () completed the list
> > > >>
> > > >>//Reset variable arguments
> > > >>va_end( valist );
> > > >>//copy the number of bytes copied information
> > > >>*pu32NumBytes_o = u32CurBuffPos;
> > > >>}
> > > >>
> > > >> ***** When I invoke this function with only one
> > > >>argument in this
> > > >>varaibel argument list, that while loop is getting
> > > >>executed twice.
> > > >>WHY??? It is supposed to omit the while loop… But
> > > >>not…
> > > >>
> > > >>PackOutputBuffer(pu8OutBuf,
> > > >>&u32NumBytes,(PVOID)&u32BlstStatus );
—
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
You are currently subscribed to ntdev as: xxxxx@compuware.com
To unsubscribe send a blank email to xxxxx@lists.osr.com
The contents of this e-mail are intended for the named addressee only. It
contains information that may be confidential. Unless you are the named
addressee or an authorized designee, you may not copy or use it, or disclose
it to anyone else. If you received it in error please notify us immediately
and then destroy it.</string.h>