| 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
|
| 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
|