// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright 1995 - 1998 Microsoft Corporation. All Rights Reserved. // // MODULE: rpcsvc.idl // // PURPOSE: Simple RPC service .idl file. This defines the wire // "contract" between a client and server using this // interface. All data types and functions (methods, // operations) that go over the wire must be defined here. // // [ uuid(d69a7cc4-9aa9-4a01-990d-800e8a5e97b4), version(1.0) ] interface RpcServiceSample { error_status_t Ping( [in] handle_t Binding ); error_status_t CheckSecurity( [in] handle_t Binding ); // Sending a buffer (writing) to the server. // // BufferIn1 and BufferIn2 both use length_is() and size_is(). // This slows performance, because a larger buffer must be // allocated on the sever and the data copied into this larger // buffer. // // BufferIn2 has the most problems because it forces a 16K // allocation which may be much larger then needed and requires // and extra data copy. It also limits clients to writing 16K // at a time. // // The BufferIn3() function saves the allocation and copy // and gives the client complete control of the size. // // Notes: Avoid length_is() on [in] parameters. Usually // size_is() is all that is really needed. const unsigned long BUFFER_SIZE = 100; error_status_t BufferIn1( [in] handle_t Binding, [length_is(BufferLength), size_is(BufferSize), in ] byte Buffer[], [in] unsigned long BufferLength, [in] unsigned long BufferSize ); error_status_t BufferIn2( [in] handle_t Binding, [length_is(BufferLength), in ] byte Buffer[16*1024], [in] unsigned long BufferLength ); error_status_t BufferIn3( [in] handle_t Binding, [size_is(BufferLength), in ] byte Buffer[], [in] unsigned long BufferLength ); // Getting a buffer (reading) from the server. // // In BufferOut1 the size of the output is limited to 16K, // which will force extra round trips when more then 16K // is being returned. This requires the client to supply a // 16K buffer and the stub to allocate 16K on the server side. // // In BufferOut2 the client decides how big the buffer // should be and only as much as the client wants is // allocated in the server. Similar to BufferOut4 // which is better. // // In BufferOut3 the server allocates a buffer exactly // as large as it wants. This results in two allocations, // one in the server manager and one in the client. This // is best if the clients have no idea how much data the // server will give them. // // In BufferOut4 the client decides how big the buffer // should be. The server can shorten (this should // be uncommon) the buffer if needed. // // Notes: Consider how the client and server interact // in your application when choosing a "read" style // interface. error_status_t BufferOut1( [in] handle_t Binding, [out,length_is(*pBufferLength)] byte Buffer[16*1024], [out] unsigned long *pBufferLength ); error_status_t BufferOut2( [in] handle_t Binding, [size_is(BufferSize), length_is(*pBufferLength), out] byte Buffer[], [in] unsigned long BufferSize, [out] unsigned long *pBufferLength ); typedef struct { unsigned long BufferLength; [unique, size_is(BufferLength)] byte *Buffer; } BUFFER; error_status_t BufferOut3( [in] handle_t Binding, [out] BUFFER *pBuffer ); error_status_t BufferOut4( [in] handle_t Binding, [out, size_is(*pBufferLength)] byte Buffer[], [in, out] unsigned long *pBufferLength ); // Structures and Enums. // // Use -Zp8 (or higher). (Default on Win32 platforms) // // Make sure the structure ends on a 0 mod 4 address. // // Use [v1_enum] on all enumerated types. // // Following these rules will result in structures (and // arrays of structures) which can be memcpy()'ed to and from // the wire. Otherwise the structures will be copied // member-by-member. (ouch!) // typedef enum { A = 1, B, C, D } BAD_ENUM; typedef [v1_enum] enum { E = 5, F, G, H } GOOD_ENUM; struct BAD1 { long l; short s; // Ends on 6 % 4 = 2 byte address. }; struct BAD2 { BAD_ENUM e; // 16bits on the wire, 32bits in memory! long l; // How big is it? }; struct GOOD { GOOD_ENUM e; // v1_enum 32bits on wire and in memory. long l; long l2; // Ends on 12 % 4 = 0 byte address. }; error_status_t StructsIn1( [in] handle_t Binding, [in] struct BAD1 array[50] ); error_status_t StructsIn2( [in] handle_t Binding, [in] struct BAD2 array[50] ); error_status_t StructsIn3( [in] handle_t Binding, [in] struct GOOD array[50] ); // Linked list examples // // Follow the rules for structs when defining your linked // list nodes. // // ListIn and ListOut1 are the basic linked list functions, // ListOut1 is more expensive because each node must be copied // into nodes on the client. (In ListIn the list pointers // are fixed up in one big buffer.) // // ListOut2 is identical to ListOut1 except that it turns // on the RPC allocator in the server. // // Linked lists are not very efficient for RPC because the // often require many memory allocations. When possible, // replace linked lists with variably sized arrays of structures. // const unsigned long LIST_SIZE = 50; typedef struct LIST { [unique] struct LIST *pNext; unsigned long data; } LIST; typedef [unique] LIST *PLIST; error_status_t ListIn( [in] handle_t Binding, [in] PLIST pList ); error_status_t ListOut1( [in] handle_t Binding, [out] LIST *pListHead ); // [enable_allocate] in .acf. error_status_t ListOut2( [in] handle_t Binding, [out] LIST *pListHead ); // Unions // // Avoid using very many unions. For example, don't pass an array in // which each element contains a union with several arms. Instead, // define several different structures and define a union with several // arms each being an array of one of the different types of structures. // // Do NOT define a [default] arm for your unions. This way a future // version of the union can include new arms and still interoperate // with older versions of the interface. // // Avoid passing unions by value. // const unsigned long UNION_ARRAY_LEN = 50; typedef struct BAD_UNION { unsigned long Tag; [switch_is(Tag)] union { [case(1)] unsigned long ulData; [case(2)] unsigned hyper uhData; [default] // The default arm here prevents the addition of // another case in future versions. ; } u; } BAD_UNION; typedef struct ONE { unsigned long DataLength; [size_is(DataLength)] unsigned long *Data; } ARM_ONE; typedef struct TWO { unsigned long DataLength; [size_is(DataLength)] unsigned hyper *Data; } ARM_TWO; typedef struct { unsigned long Tag; [switch_is(Tag)] union { [case (1)] [unique] ARM_ONE *pOne; [case (2)] [unique] ARM_TWO *pTwo; // May add [case(3)] in a future version. // // When calling a down level server with Tag == 3 the // error RPC_S_INVALID_TAG will get returned. Values // 1 and 2 will continue to work. // // If there was a [default] arm this wouldn't work. } u; } GOOD_UNION; error_status_t UnionCall1( [in] handle_t Binding, [in] unsigned long Length, [in, size_is(Length)] BAD_UNION ArrayOfUnions[] ); error_status_t UnionCall2( [in] handle_t Binding, [in] GOOD_UNION *pUnionContainingArrays ); }