/****************************************************************************
                   Microsoft RPC Version 2.0
           Copyright Microsoft Corp. 1992, 1993, 1994
                      rpcssm Example

    FILE:       rpcssmc.c
    
    USAGE:      rpcssmc  -n network_address
                         -p protocol_sequence
                         -e endpoint
                         -o options

    PURPOSE:    Client side of RPC distributed application
    
    FUNCTIONS:  main() - binds to server and calls remote procedure
    
    COMMENTS:   This distributed application uses the rpcssm package.

****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include "rpcssm.h"    // header file generated by MIDL compiler


#define PURPOSE \
"This Microsoft RPC Version 2.0 sample program demonstrates\n\
the use of the [context_handle] attribute. For more information\n\
about attributes and RPC API functions, see the RPC programming\n\
guide and reference.\n\n"

void AllocateSmList( PBOX * ppBox, short sListSize );
void AllocateList( PBOX * ppBox, short sListSize );
void InitList( PBOX  pBox, long lStartValue );
void FreeList( PBOX  pBox );
void PrintList( PBOX pBox );


void Usage(char * pszProgramName)
{
    fprintf(stderr, "%s", PURPOSE);
    fprintf(stderr, "Usage:  %s\n", pszProgramName);
    fprintf(stderr, " -p protocol_sequence\n");
    fprintf(stderr, " -n network_address\n");
    fprintf(stderr, " -e endpoint\n");
    fprintf(stderr, " -o options\n");
    exit(1);
}

void _CRTAPI1 main(int argc, char **argv)
{
    RPC_STATUS status;
    PBOX       pBox = NULL;

    unsigned char * pszUuid             = NULL;
    unsigned char * pszProtocolSequence = "ncacn_np";
    unsigned char * pszNetworkAddress   = NULL;
    unsigned char * pszEndpoint         = "\\pipe\\rpcssm";
    unsigned char * pszOptions          = NULL;
    unsigned char * pszStringBinding    = NULL;
    int i;

    /* allow the user to override settings with command line switches */
    for (i = 1; i < argc; i++) {
        if ((*argv[i] == '-') || (*argv[i] == '/')) {
            switch (tolower(*(argv[i]+1))) {
            case 'p':  // protocol sequence
                pszProtocolSequence = argv[++i];
                break;
            case 'n':  // network address
                pszNetworkAddress = argv[++i];
                break;
            case 'e':
                pszEndpoint = argv[++i];
                break;
            case 'o':
                pszOptions = argv[++i];
                break;
            case 'h':
            case '?':
            default:
                Usage(argv[0]);
            }
        }
        else
            Usage(argv[0]);
    }

    RpcTryExcept {

        /* Use a convenience function to concatenate the elements of  */
        /* the string binding into the proper sequence.               */
        status = RpcStringBindingCompose(pszUuid,
                                         pszProtocolSequence,
                                         pszNetworkAddress,
                                         pszEndpoint,
                                         pszOptions,
                                         &pszStringBinding);
        printf("RpcStringBindingCompose returned 0x%x\n", status);
        printf("pszStringBinding = %s\n", pszStringBinding);
        if (status) {
            exit(status);
        }
    
        /* Set the binding handle that will be used to bind to the server. */
        status = RpcBindingFromStringBinding(pszStringBinding,
                                             &hStarter);
        printf("RpcBindingFromStringBinding returned 0x%x\n", status);
        if (status) {
            exit(status);
        }
    
        /* Now a different case: a client stub is in an enabled environment */
    
        status = RpcSmEnableAllocate();
        printf("RpcSmEnableAllocate returned 0x%x\n", status);
        if (status) {
            exit(status);
        }
    
        pBox = NULL;
        AllocateSmList( &pBox, 4 );
        InitList( pBox, 0xabcd0000 );
        PrintList( pBox );
    
        printf("Calling the remote procedure InOutList\n");
        InOutList( &pBox );
        PrintList( pBox );
    
        /* No need to free the memory allocated with RpcSmAllocate,
           RpcSmDisableAllocate would free it.
        */
    
        status = RpcSmDisableAllocate();
        printf("RpcSmDisableAllocate returned 0x%x\n", status);
        if (status) {
            exit(status);
        }
    
        printf(" All nodes from this case freed by RpcSmDisableAllocate().\n" );
        printf(" Client with memory environment done.\n\n" );
    
        Shutdown();
    
        /*  Free the string binding */
        status = RpcStringFree(&pszStringBinding); 
        printf("RpcStringFree returned 0x%x\n", status);
        if (status) {
            exit(status);
        }
    
        status = RpcBindingFree(&hStarter);
        printf("RpcBindingFree returned 0x%x\n", status);
        if (status) {
            exit(status);
        }
    }
    RpcExcept(1) {

        #if defined(WIN32)
            printf( "Unexpected exception: %ld\n", RpcExceptionCode() );
        #else
            printf( "Unexpected exception: %d\n", RpcExceptionCode() );
        #endif
        printf("Did you set a net address (like -n server_name etc.)?\n");
        exit(1);
    }
    RpcEndExcept;
        
    exit(0);

}  // end main()


//=====================================================================
//        List allocation/deallocation routines
//=====================================================================

void
AllocateSmList( PBOX * ppBox, short sListSize)
{
    PBOX    pBox, head;
    int     i = 0;

    //.. Allocate a list of boxes, if needed  (when *ppBox==NULL).

    if ( *ppBox == NULL ) {
    
        RPC_STATUS status;

        head = 0;
        for (i = 0; i < sListSize; i++)
        {
            pBox = (PBOX) RpcSmAllocate( sizeof(LBOX), &status);
            if ( status != RPC_S_OK )
            {
                printf("AllocateList FAILED: not enough memory\n");
                break;
            }
            pBox->next = head;
            head = pBox;
        }
        *ppBox = head;
    }
    printf("%d nodes allocated.\n", i);
}

//=====================================================================
//        Initialization and pprint routines
//=====================================================================

void  InitList( PBOX  pBox, long lStartValue )
{
    int i = 0;

    while( pBox ) {
        pBox->data = lStartValue + ++i;
        pBox = pBox->next;
    }
    printf("%d nodes inited.\n", i);
}

// --------------------------------------------------------------------

void
PrintList( PBOX  pBox )
{
    int i = 0;


    while( pBox ) {

        if ( (i % 4) != 0 )
            printf("  data[%d]= %lx", i, pBox->data);
        else
            printf( "\n  data[%d]= %lx", i, pBox->data);
        pBox = pBox->next;
        i++;
    }
    printf("\n" );
}


/* end rpcssmc.c */
