// 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 (C) 1995-1996  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(15cd3850-28ca-11ce-a4e8-00aa006116cb),
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,
              [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
                  );
 
}
