[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference decwet::nt-developers

Title:MS Windows NT Developers
Notice:See note 1222 for MS bug reporting info
Moderator:TARKIN::LINEIBER
Created:Mon Nov 11 1991
Last Modified:Tue Jun 03 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3247
Total number of notes:15633

3196.0. "RPC on WNT - Beginner's question" by AZUR::MASSON () Wed Feb 26 1997 08:04

Hello,

I want the following procedure

  void GetBuffer( int * BufferLength, BYTE * Buffer );

to be served by a RPC Server, to get the length and contents
of an array of bytes.

The problem is that, according what I read from doc, it seems
that the RPC Client has to provide memory allocation on the
array of bytes (and by the way it means that it has to know 
the size of buffer to ask for) before calling the RPC.

Is there a way to make the call with a NULL Buffer, then make 
the RPC Server allocate memory on its side before filling the buffer and 
then get back the allocated/filled buffer on RPC Client side?

Thanks,
Sylvain
T.RTitleUserPersonal
Name
DateLines
3196.1not so simpleSTAR::RICODick AnnicchiaricoFri Feb 28 1997 14:0282
Actually, your question is not that beginner-ish.  Pointers and dynamic
arrays in RPC get very tricky.  Let's see if I can still get this right...

First of all, I assume you are talking either DCE RPC or MS RPC.
Both use C calling standards.  Remember that in C, everything is passed
by value.  The function signature you reference

  void GetBuffer( int * BufferLength, BYTE * Buffer );

does not give you the opportunity to pass back a buffer address, it just
allows you to write to that address.  I.e., as a pure C API (ignoring RPC),
the storage for the buffer is owned by the *caller*, not the *callee*.
C functions like this exist all over creation, but they are inadequate in
that the caller has to allocate enough storage to anticipate the largest
result the callee will need to write, and often-times the API isn't
documented well enough to state whether BufferLength is just an output
parameter or an input-output parameter.  If it's just an output parameter,
the callee is going to assume the buffer is big enough, and just write
to it, possibly overstepping its bounds, then return how much it wrote
in BufferLength.  If it's an input-output parameter, the caller should
pass in the maximum size of the buffer and the callee can return the
actual size written.

The purist's correct way to do this in RPC is:

void GetBuffer([in] long BufferSize, [in,out] long * BufferLength,
	[out,size_is(BufferSize),length_is(*BufferLength)] byte * Buffer);

Buffer is what is termed a "conformant-varying array"; it is conformant
because its bounds are determined at runtime, and it is varying because
the actual amount of elements of the array that contain data is also
determined at runtime.  You would call this something like:

	long bs, bl;
	byte buf[80];   //could be dymanically allocated
	bs = 80;	//also might be determined dynamically
	GetBuffer(bs, &bl, buf);
	// bl contains the number of bytes returned in buf

But if you can get away with static bounds (which is probably what the
corresponding C-only API does anyway), this should work:

void GetBuffer([out] long * BufferLength,
	[out,length_is(*BufferLength)] byte Buffer[80]);

Buffer is now just a "varying array"; its bounds are fixed but the amount
of actual data elements is determined at runtime, obviously by the callee,
because BufferLength is an output-only parameter.  A sample call:

	long bl;
	byte buf[80];
	GetBuffer(&bl, buf);
        // bl contains the number of bytes returned in buf

Dick


                       <<< Note 3196.0 by AZUR::MASSON >>>
                     -< RPC on WNT - Beginner's question >-


Hello,

I want the following procedure

  void GetBuffer( int * BufferLength, BYTE * Buffer );

to be served by a RPC Server, to get the length and contents
of an array of bytes.

The problem is that, according what I read from doc, it seems
that the RPC Client has to provide memory allocation on the
array of bytes (and by the way it means that it has to know 
the size of buffer to ask for) before calling the RPC.

Is there a way to make the call with a NULL Buffer, then make 
the RPC Server allocate memory on its side before filling the buffer and 
then get back the allocated/filled buffer on RPC Client side?

Thanks,
Sylvain

3196.2Thanks a lotAZUR::MASSONTue Mar 04 1997 03:2022
Thanks a lot Dick for your technical and 
precise answer ! :-)

If I got it well, there's no way
to bypass the boundary specification on the 
client side before calling RPC...

I implemented the following RPC:

void GetBuffer([in] long BufferSize,
	       [in, out, size_is(BufferSize)] byte * Buffer),
               [out] long * BufferLength,
               [out] long * RealBufferSize);

On the client side I make two consecutive calls:
One call with BufferSize == 0 ; I get back effective buffer size
into RealBufferSize ; then, on the client side, I allocate 
RealBufferSize memory for Buffer and I make a second call 
with BufferSize equal to RealBufferSize.

Sylvain