/*************************************************************************
                    Copyright Microsoft Corp. 1992-1996
                        Remote Machine strout sample

  FILE      :   client.c

  USAGE     :   client  -n network_address
                        -p protocol_sequence
                        -e endpoint
                        -o options

  PURPOSE   :   Client side of the RPC distributed application strout.

  COMMENTS  :   This program shows how to call remote procedures that
                allocate memory for a two dimensional array (an array of
                character pointers). It calls the server that allocates 
                memory to store all the environment strings in, and copies
                the environment variables to this memory. The client then 
                displays all the data on the client machine.

                Since this program uses the implicit binding method, some 
                of the binding handling must be done at the client side
*************************************************************************/

#include "strout.h"     /* Generated by the midl compiler               */
#include "common.h"     /* Definitions that are common to all files	    */


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/*  Procedure   :   void Usage(_TUCHAR *)                               */
/*  Desc        :   This procedure prints out an error message if the   */
/*                  command line arguments are wrong                    */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void Usage(_TUCHAR * pszProgramName)
{
    _tprintf(TEXT("USAGE : %s [-option]\n"), pszProgramName);
    _tprintf(TEXT("Options : -n Network Address\n"));
    _tprintf(TEXT("          -p Protocol Sequence\n"));  
    _tprintf(TEXT("          -e Endpoint\n"));  
    _tprintf(TEXT("          -o Options\n"));  
    exit(EXECUTION_FAILED);
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* The client main program                                              */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int main(int argc, char *argv[])
{
    RPC_STATUS nStatus;     /* Return value from the RPC calls          */
    unsigned int
        nIdx,               /* Counter in loops                         */
        nNumArgs;           /* Number of commandline arguments          */
    unsigned long 
        nNumLines = 0;      /* Number of lines in the environment block */
    str	*pEnvBlock;         /* Pointer to an array of string pointers   */
    
    // These variables are used for the implicit binding
    _TUCHAR	*pszUuid            = NULL;
    _TUCHAR	*pszProtocolSequence= PROTOCOL_SEQUENCE;
    _TUCHAR	*pszNetworkAddress  = NULL;	
    _TUCHAR	*pszEndpoint        = END_POINT;
    _TUCHAR	*pszOptions         = NULL;
    _TUCHAR	*pszStringBinding   = NULL;
	
    /* Get a common handle on the command line arguments for both       */
    /* UNICODE and ASCII                                                */
#ifdef _UNICODE
    LPWSTR	*szArglist = CommandLineToArgvW(GetCommandLine(), &nNumArgs);
    if (NULL == szArglist)
    {
        _tprintf(TEXT("SERVER.C : CommandLineToArgW failed"));
        exit(EXECUTION_FAILED);
    }
#else
    char **szArglist= argv;
    nNumArgs = argc;
#endif

    /* Allow the user to override settings with commandline switches    */
    for (nIdx = 1; nIdx < nNumArgs; nIdx++) 
    {
        if ((_tcscmp(szArglist[nIdx], TEXT("-n")) == 0) || 
            (_tcscmp(szArglist[nIdx], TEXT("-N")) == 0))
        {
            pszNetworkAddress = szArglist[++nIdx];
        }
        else if((_tcscmp(szArglist[nIdx], TEXT("-p")) == 0) || 
            (_tcscmp(szArglist[nIdx], TEXT("-P")) == 0))
        {
            pszProtocolSequence = szArglist[++nIdx];
        }
        else if((_tcscmp(szArglist[nIdx], TEXT("-e")) == 0) || 
                (_tcscmp(szArglist[nIdx], TEXT("-e")) == 0))
        {
            pszEndpoint = szArglist[++nIdx];
        }
        else if((_tcscmp(szArglist[nIdx], TEXT("-o")) == 0) || 
                (_tcscmp(szArglist[nIdx], TEXT("-O")) == 0))
        {
            pszOptions = szArglist[++nIdx];
        }
        else 
        {
            Usage(szArglist[0]);
        }
    }
            

    /* Since we are using implicit binding, we need to do some binding  */
    /* from the client side as well.                                    */
    /* Use a function to concatenate the elements of the string         */
    /* binding into the proper sequence                                 */
    nStatus = RpcStringBindingCompose(	
        pszUuid,							
        pszProtocolSequence,
        pszNetworkAddress,
        pszEndpoint,
        pszOptions,
        &pszStringBinding);
    EXIT_IF_FAIL(nStatus, "RpcStringBindingCompose");

    /* Set the binding handle that will be used to bind to the server   */
    nStatus = RpcBindingFromStringBinding(	
        pszStringBinding,					
        &global_strout_sample_handle);      /* The global handle used   */
    EXIT_IF_FAIL(nStatus, "RpcBindingFromStringBinding");

    /* Initialize the pointer to NULL */
    pEnvBlock = NULL;
	
    RpcTryExcept                /* Catch any exception that occurs      */
    {
        /* Call the remote procedure */
        _tprintf(TEXT("Calling the remote procedure \'GetRemoteEnv\' \n"));
        GetRemoteEnv(&nNumLines, &pEnvBlock);
    }
    RpcExcept(DO_EXCEPTION)
    {
        _tprintf(TEXT("Run-time exception %08X = %d in %s\n"), 
            RpcExceptionCode(), RpcExceptionCode(), TEXT(__FILE__));
        exit(EXECUTION_FAILED);
    }
    RpcEndExcept


    /* Print out the result */
    _tprintf(TEXT("There are %d environment variables\n"), nNumLines);
    _tprintf(TEXT("They are:\n"));
    for (nIdx = 0; nIdx < nNumLines; nIdx++)
    {
        _tprintf(TEXT("\t%s\n"), pEnvBlock[nIdx]);
    }
	
	
    // Deallocate all the memory used for the EnvBlock
    for (nIdx = 0; nIdx < nNumLines; nIdx++)
    {
        midl_user_free(pEnvBlock[nIdx]);
    }
    midl_user_free(pEnvBlock);

    // Deallocate the memory used for the ARGLIST if using UNICODE
#ifdef _UNICODE
    if (NULL != szArglist)
        free(szArglist);
#endif

    /* When the call is done, shut down the server application */
    ShutDown();

    return (EXECUTION_OK);
}



/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Procedure    :   midl_user_allocate() and midl_user_free()           */
/* Desc.        :   These procedure are declared in the header file     */
/*                  generated by the midl compiler. These procedures    */
/*                  should be used for all memory allocation and        */
/*                  deallocation.                                       */
/*                  These procedures are also called by the stub code to*/
/*                  allocate and free memory.                           */
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void __RPC_FAR * __RPC_API midl_user_allocate(size_t nLen)
{
    return (malloc(nLen));
}

void __RPC_API midl_user_free(void __RPC_FAR * lpvPointer)
{
    if (lpvPointer != NULL)
        free (lpvPointer);
}
