C:\CLIENTT> nmake client

To run the client of the distributed application, type the following:

C:\CLIENT> client

Application Files

Makefile contains descriptions of how the application is compiled. Use the compi lation make all to create all the executable files for the application. See Example C-l.

arith.bat is a batch file that sets the environment and executes the server. See Example C-2.

arith.idl contains the description of the constants, data types, and procedures for the interface. See Example C-3.

client.c initializes two arrays, calls the remote procedure sum_arrays, and displays the results of the returned array. See Example C-4.

manager.c is the remote procedure implementation. See Example C-5.

sewer.c initializes the server with a series of Microsoft RFC runtime calls. See Exam ple C-6.

status.h defines the CHECK_STATUS macro, which interprets error status codes that may return from Microsoft RFC runtime calls. See Example C-7.

Exa mple C-1: The Makefile for the A rith metic Application

# FILE NAME: Makefile

# Makefile for the arithmetic application #

# definitions for this make file #

APPL=arith

IDLCMD=midl

NTRPCLIBS=rpcrt4.lib rpcns4.1ib libcmt.lib kerne!32.1ib

# Include Windows NT macros !include <ntwin32.mak>

# NT c flags

cflags = -c -WO -Gz -D_X86_=1 -DWIN32 -DMT /nologo

# NT nmake inference rules

$(cc) $(cdebug) $(cflags) $(cvarsmt) $< $(cvtomf)

#

# COMPLETE BUILD of the application #

#all: local interface client server

all: lclient.exe interface client.exe server.exe

#

# INTERFACE BUILD #

interface: $(APPL).h $(APPL) _c.obj $(APPL)_s.obj

Example C-1: The Makefile for the Arithmetic Application (continued)

#

# LOCAL BUILD of the client application to test locally #

local: Iclient.exe lclient.exe: Iclient.obj Imanager.obj

$(link) $(linkdebug) $(conflags) -out:Iclient.exe -map:Iclient.map \

Iclient.obj Imanager.obj \

$(NTRPCLIBS)

#

# CLIENT BUILD #

client: client.exe

client.exe: client.obj $(APPL)_c.obj

$(link) $(linkdebug) $(conflags) -out:client.exe -map:client.map \

client.obj $(APPL)_c.obj \

$(NTRPCLIBS)

#

# SERVER BUILD #

server: server.exe

server.exe: server.obj manager.obj $(APPL)_s.obj

$(link) $(linkdebug) $(conflags) -out:server.exe -map:server.map \

server.obj manager.obj $(APPL)_s.obj \

${NrRPCLIBS)

# client and server sources client.obj: client.c $(APPL).h manager.obj: manager.c $(APPL).h server.obj: server.c $(APPL).h

# Local client sources Iclient.obj: client.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCAL /Folclient.obj client.c Imanager.obj: manager.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCAL /Folmanager.obj manager.c

# client stubs

$(APPL)_c.obj: $(APPL)_c.c $(APPL)_x.obj: $(APPL)_x.c

# compile the server stub

$ (APPL)_s.obj : $(APPL)_s.c

# generate stubs, auxiliary and header file from the IDL file $(APPL).h $(APPL)_c.c $(APPL)_x.c : $(APPL).idl

$(IDLCMD) $(APPL).idl

# clean up for fresh build clean:

del $(APPL)_?.c

del *.obj

del $(APPL).h

del *.map

Example C-1-. The Makefile for the Arithmetic Application (continued)

del *.pdb

clobber: clean

if exist client.exe del client.exe if exist lclient.exe del lclient.exe if exist server.exe del server.exe

Example C-2: The Server Batch File for the Arithmetic Application

©ECHO OFF

@KEM FILE NAME: arith.bat

set ARITHMETIC_SERVER_ENTRY=/ . : /arithmetic_serverhost

server

Example C~3: The MIDI File of the Arithmetic Application

/* FILE NAME: arith.idl */

/* This Interface Definition Language file represents a basic arithmetic */

/* procedure that a remote procedure call application can use. */

[

uuid(6AF85260-A3A4-10LA-BLAE-08002B2E5B76) , /* Universal Unique ID */

pointer_default (ref ) /* default pointer type is reference */

]

interface arith /* interface name is arith */

{

const unsigned short ARRAY_SIZE = 10; /* an unsigned integer constant */ typedef long long_array [ARRAY_SIZE] ; /* an array type of long integers */

void sum_arrays ( /* The sum_arrays procedure does not return a value */

[in] long_array a, /* 1st parameter is passed in */

[in] long_array b, /* 2nd parameter is passed in */

[out] long_array c /* 3rd parameter is passed out */

Example C-4: The Client File of the Arithmetic Application

I* FILE NAME: client. c */

/* This is the client module of the arithmetic example. */

#include <stdio.h>

# include <stdlib.h>

ttinclude "arith. h" /* header file created by IDL compiler

long_array a ={100,200,345,23,67,65,0,0,0,0}; long_array b ={4,0,2,3,1,7,5,9,6,8};

main () {

long_array result;

int i;

sum_arrays(a, b, result); /* A Remote Procedure Call

puts ("sums: ") ;

for(i =0; i < ARRAY_SIZE; i++) printf ( "%ld\n" , result [i] ) ;

Example C-4: The Client File of the Arithmetic Application (continued) /it************************************************************************/ /*** MIDL_user_allocate / MIDL_user_free ***/

void * _RPC_API MIDL_user_allocate

( size

)

size_t size; {

unsigned char * ptr; ptr = malloc( size ); return ( (void *)ptr );

void __RPC_API MIDL_user_free (

object )

void * object; {

free (object); }

Example C-5. Remote Procedure of the Arithmetic Application

I* FILE NAME: manager.c */

/* An implementation of the procedure defined in the arithmetic interface. */

#include <stdio.h>

#include "arith.h" /* header file produced by IDL compiler */

void sum_arrays(a, b, c) /* implementation of the sum_arrays procedure */ long_array a; long_array b; long_array c; {

int i;

for(i = 0; i-< ARRAY_SIZE; i++)

c[i] = a[i] + b[i]; /* array elements are each added together */

}

Example C-6: Server Initialization of the Arithmetic Application

/* FILE NAME: server.c */

#include <stdio.h>

#include "arith.h" /* header created by the idl compiler */

ttinclude "status.h" /* header with the CHECK_STATUS macro */

main ()

{

unsigned long status; /* error status */

rpc_binding_vector_t *binding_vector; /* set of binding handles */

Example C-6. Server Initialization of the Arithmetic Application (continued)

unsigned char *entry_name; /* entry name for name service */

status = /* error status */

RpcServerRegisterlf( /* register interface with the RFC runtime */

arith_vO_0_s_ifspec, /* interface specification (arith.h) */

NULL,

NULL ); CHECK_STATUS(status, "Can't register interface", ABORT);

status =

RpcServerUseAllProtseqs( /* create binding information */

RPC_C_PROTSEQ_MAX_REQS_DEFAULT, /* queue size for calls */

NULL /* no security descriptor is used */

);

CHECK_STATUS(status, "Can't create binding information", ABORT);

status =

RpcServerlnqBindings( /* obtain this server's binding information */

&binding_vector ); CHECK_STATUS(status, "Can't get binding information", ABORT);

entry_name - (unsigned char *)getenv("ARITHMETIC_SERVER_ENTRY");

status =

RpcNsBindingExport( /* export entry to name service database */

RPC_C_NS_SYNTAX_DEFAULT, /* syntax of the entry name */

entry_name, /* entry name for name service */

arith_vO_0_s_ifspec, /* interface specification (arith.h)*/

binding_vector, /* the set of server binding handles */ NULL

);

CHECK_STATUS(status, "Can't export to name service database", ABORT);

status =

RpcEpRegister( /* register endpoints in local endpoint map */

arith_vO_0_s_ifspec, /* interface specification (arith.h) */

binding_vector, /* the set of server binding handles */

NULL,

NULL ); CHECK_STATUS(status, "Can't add address to the endpoint map", ABORT);

status =

RpcBindingVectorFree( /* free set of server binding handles */

&binding_vector ); CHECK_STATUS(status, "Can't free binding handles and vector", ABORT);

puts("Listening for remote procedure calls...");

status =

RpcServerListen( /* listen for remote calls */

1, /* minimum number of threads */

RPC_C_LISTEN_MAX_CALLS_DEFAULT, /*concurrent calls to server */ NULL /* continue listening until explicitly stopped */

Example C-6: Server Initialization of the Arithmetic Application (continued)

CHECK_STATUS(status, "rpc listen failed", ABORT);

/*** MIDL_user_allocate / MIDL_user_free ***/

void * RPC API MIDL_user_allocate

size size_t size;

unsigned char * ptr; ptr = malloc( size ); return ( (void *)ptr );

}

void RPC API MIDL_user_free

ob j ect void * object;

free (object);

Example C- 7: The Check Error Status Macro

/* FILE NAME: status.h */ ttinclude <stdio.h> #include <stdlib.h>

#define RESUME 0 #define ABORT 1 #define ERROR_TEXT_SIZE 1025

#define CHECK_STATUS(input_status, comment, action) \ { \

if(input_status ! = RPC_S_OK) { \

error_stat = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM \

,NULL \

,input_status \

,0 \

,error_string \

,ERROR_TEXT_SIZE \

,NULL); \

fprintf(stderr, "%s %s\n", comment, error_string); \ if(action == ABORT) \

exit(l); \ } \

Example C- 7: The Check Error Status Macro (continued)

static int error_stat;

static unsigned char error_string[ERROR_TEXT_SIZE] ;

• How to Run the Application

• Application Files

picture36

The Inventory Application

The inventory application allows a user to inquire about, and order from, a simple inventory. Data structures are defined for the following items:

• Part number (to identify a part)

• Part name

• Part description

• Part price

• Quantity of part

• Part list

• Account number (to identify a user)

Procedures are also defined in the interface definition to do the following:

• Confirm if a part is available

• Obtain a part name

• Obtain a part description

• Obtain a part price

• Obtain the quantity of parts available

• Obtain a list of subpart numbers

• Order a part

The application demonstrates many features of Microsoft RFC application develop ment including:

• Using strings, pointers, structures, a union, and a conformant array.

157

• Allocating new memory in a remote procedure for data returned to the client using stub support routines. The get_part_description and whatare_subparts remote procedures demonstrate server allocation of a string and a conformant structure.

• Managing protocol sequences, interpreting binding information, selecting binding information, and using exception handler macros.

• Variations on a client using ACFs and the automatic, implicit, and explicit binding methods.

• Finding a server by importing from a name service database.

How to Run the Application

To run the local test of the client, type the following:

C:\> nmake local C:\> lclient.exe

To run the server of the distributed application, type the following:

C:\SERVER> nmake server C:\SERVER> server.exe

To run the client that uses the automatic binding method, type the following:

C:\CLIENT> nmake client C:\CLIENT> client.exe

To run a nondistributed local test of the implicit client, type the following in the implicit subdirectory:

C:\> nmake local C:\> lclient.exe

To run the implicit client of the distributed application using the automatic server, type the following in the implicit subdirectory:

C:\CLIENT> nmake client C:\CLIENT> client.exe

To run the explicit server of the distributed application, type the following in the explicit subdirectory:

C:\SERVER> nmake server C:\SERVER> server.exe

To run the explicit client of the distributed application using the explicit server, type the following in the explicit subdirectory:

C:\CLIENT> nmake client C:\CLIENT> client.exe

Application Files

Makefile contains descriptions of how the application is compiled. Some files depend on the header file status.h from the arithmetic application for the CHECK_STATUS macro. See Example D-l.

inv.idl contains the description of the constants, data types, and procedures for the interface. See Example D-2.

manager.c is the implementation of all the remote procedures defined in this inter face. See Example D-3.

invntry.c is the implementation of the inventory database. For simplicity, only three inventory items are included. The part numbers for these are printed when the inventory is opened. See Example D-4.

server.c initializes the server with a series of runtime calls prior to servicing remote procedure calls. In addition to the required calls, this server also selects a specific protocol sequence, uses exception handling macros, and does some basic cleanup when the server quits. See Example D-5.

client.c displays the instructions for the user and processes user input in a loop until exit is selected. Each remote procedure is exercised depending on the input from the user. See Example D-6.

implicit\Makefile contains descriptions of how the implicit client is compiled. Some files depend on the header file status.h from the arithmetic application for the CHECK_STATUS macro. See Example D-7.

implicit\inv_i.acf customizes how you use an interface. In this application it is used to select the implicit binding method. See Example D-8.

implicit\client.c imports a binding handle from the name service database. See Example D-9.

implicit\getbind.c contains the do_import_binding procedure, which shows how to import a binding handle from the name service database. See Example D-10.

implicit\intbind.c-contains the do_interpret_binding procedure, which shows how to obtain the binding information to which a binding handle refers. See Example D-ll.

The server for the implicit client is the same as the one for the automatic client.

explicit\Makefile contains descriptions of how the explicit client is compiled. The compilation depends on some files from the implicit client development. See Example D-12.

explicit\inv.idl contains the description of the constants, data types, and proce dures for the interface. All procedure declarations include a binding handle as the first parameter. See Example D-l3.

explicit\manager.c is the implementation of all the remote procedures denned in this interface. All procedure implementations include a binding handle as the first parameter. See Example D-14.

explicit\client.c imports a binding handle from the name service database. All pro cedures have a binding handle as the first parameter. See Example D-15.

The server's main program for the explicit client is the same as the one for the automatic and implicit clients.

Example D-l. The Makefile for the Inventory Application

# FILE NAME: Makefile

# Makefile for the inventory application #

# definitions for this make file #

APPL=inv

NTRPCLIBS=rpcrt4.1ib rpcns4.1ib libcmt.lib kerne!32.1ib

!include <ntwin32.mak>

## NT c flags

cflags = -c -WO -Gz -D_X86_=1 -DWIN32 -DMT /nologo

## NT nmake inference rules

$(cc) $(cdebug) $(cflags) $(cvarsmt) $< $(cvtomf)

#

# COMPLETE BUILD of the application #

all: local interface client server

#

# INTERFACE BUILD #

interface: $(APPL).h $(APPL)_c.obj $(APPL)_s.obj

#

# LOCAL BUILD of the client application to test locally #

local: lclient.exe

lclient.exe: Iclient.obj litianager.obj invntry.obj

$(link) $(linkdebug) $(conflags) -out:lclient.exe -map:lclient.map \

Iclient.obj Imanager.obj invntry.objX

$(NTRPCLIBS)

#

# CLIENT BUILD #

client: client.exe

client.exe: client.obj $(APPL)_c.obj

$(link) $(linkdebug) $(conflags) -out:client.exe -map:client.map \

client.obj $(APPL)_c.obj \

$(NTRPCLIBS)

Example D-l: The Makefile for the Inventory Application (continued)

# SERVER BUILD #

server: server.exe

server.exe: server.obj manager.obj invntry.obj $(APPL)_s.obj

$(link) $(linkdebug) $(conflags) -out:server.exe -map:server.map \

server.obj manager.obj invntry.obj $(APPL)_s.obj\

$(NTRPCLIBS)

# client and server sources client.obj: client.c $(APPL).h manager.obj: manager.c $(APPL).h server.obj: server.c $(APPL).h invntry.obj: invntry.c $(APPL).h

# Local client sources Iclient.obj: client.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCALX

/Folclient.obj client.c Imanager.obj: manager.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCAL \

/Folmanager.obj manager.c

# client stubs

$(APPL)_C.Obj: $(APPL)_C.C $(APPL)_x.obj: $(APPL)_x.c $ (APPL)_S.obj : $(APPL)_S.C

# generate stubs, auxiliary and header file from the IDL file $(APPL).h $(APPL)_c.c $(APPL)_x.c : $(APPL).idl

midl $(APPL).idl

# clean up for fresh build clean:

del $(APPL)_?.c

del *.obj

del $(APPL).h

del *.map

del *.pdb

clobber: clean

if exist client.exe del client.exe

if exist lclierit.exe del lclient.exe

if exist server.exe del server.exe

Example D-2. The MIDL File of the Inventory Application

/* FILE NAME: inv.idl */

[ /* brackets enclose attributes */

uuid(A6lE3FCO-A53F-10lA-BlAF-08002B2E5B76), /* universal unique identifier */

version(l.O), /* version of this interface */

pointer_default(unique) /* pointer default */

] interface inv /* interface name */

{

const long MAX_STRING =30; /* constant for string size */

typedef long part_num; /* inventory part number */

Example D-2. The MIDI File of the Inventory Application (continued)

typedef [string] char part_naine[MAX_STRING+l]; /* name of part */

typedef [string, unique] char *paragraph; /* description of part */

typedef enum {

ITEM, GRAM, KILOGRAM } part_units; /* units of measurement */

typedef struct part_price { /* price of part */

part_units units;

double per_unit;

} part_price;

typedef union switch(part_units units) total { /* quantity of part */

case ITEM: long int number;

case GRAM:

case KILOGRAM: double weight; } part_quantity;

typedef struct part_list{ /* list of part numbers */

long size; /* number of parts in array */

[size_is(size)] part_num numbers[*]; /* conformant array of parts */

} part_list;

typedef struct part_record { /* data for each part */

part_num number;

part_name name ;

paragraph description;

part_price price;

part_quantity quantity;

part_list subparts; } part_record;

typedef long account_num; /* user account number */

********************* Procedure Declarations *************************/

boolean is_part_available( /* return true if in inventory */

[in] part_num number /* input part number */

);

void whatis_part_name( /* get part name from inventory */

[in] part_num number, /* input part number */

[in, out] part_name name /* output part name */ );

paragraph get_part_description( /* return a pointer to a string */

[in] part_num number );

void whatis_part_price( /* get part price from inventory */

[in] part_num number,

[out] part_price *price );

void whatis_part_quantity( /* get part quantity from inventory */ [in] part_num number, [out] part_quantity *quantity

Example D-2. The MIDI File of the Inventory Application (continued)

void whatare_subparts ( /* get list of subpart numbers */

[in] part_num number, [out] part_list **subparts /* structure containing the array */

/* Order part from inventory with part number, quantity desired, and /* account number. If inventory does not have enough, output lesser

/* Order part from inventory with part number, quantity desired, and */

. , */

/* quantity ordered. Return values: l=ordered OK, */

/* -l=invalid part, -2=invalid quantity, -3=invalid account. */

long order_part ( /* order part from inventory, return OK or error code */ [in] part_num number,

[in, out] part_quantity *quantity, /* quantity ordered */

[in] account_num account ); } /* end of interface definition */

Example D-3- Remote Procedures of the Inventory Application

I* FILE NAME: manager. c */

/** Implementation of the remote procedures for the inventory application. **/

#include <stdio.h>

# include <stdlib.h>

#include "inv.h"

boolean is_part_available (number)

part_num number;

{

part_record *part; /* a pointer to a part record */

int found;

found = read_part_record( number, &part) ; if (found)

return (TRUE) ; else

return (FALSE) ;

void what is_part_name ( number, name) part_num number; part_name name; {

part_record *part; /* a pointer to a part record */

read_part_record( number, &part) ;

strncpy ( (char *)name, (char *)part->name, MAX_STRING) ;

return;

paragraph get_part_descript ion ( number )

part_num number;

{

part_record *part; /* a pointer to a part record */

Example D-3: Remote Procedures of the Inventory Application (continued)

paragraph description; int size;

if( read_part_record( number, &part) ) {

/* Allocated data that is returned to the client must be allocated */

/* with the MIDL_user_allocate stub support routine. */

size = strlen((char *) part -xJescript ion) + 1;

description = (paragraph) MIDL_user_allocate( (unsigned) size) ;

strcpy((char *) description, (char *)part->description) ; } else

description = NULL; return (description) ;

void whatis_part_price (number, price) part_num number; part_price *price; {

part_record *part; /* a pointer to a part record */

read_part_record ( number , &part ) ; price->units = part->price. units; price->per_unit = part->price.per_unit; return;

void what is_part_quantity (number, quantity) part_num number; part_quantity *quantity; {

part_record *part; /* a pointer to a part record */

read_part_record( number, &part) ; quantity->units = part -xjuantity. units; switch (quantity->units) {

case ITEM: quantity->total. number = part -xguantity. total. number; break;

case KILOGRAM:

case GRAM: quantity- >total . weight = part -xjuantity. total. weight;

break; } return;

void whatare_subparts ( number, subpart_ptr) part_num number; part_list **subpart_ptr; {

part_record *part; /* pointer to a part record */

int i; int size;

read__part_record ( number , &part ) ;

Example D- 3: Remote Procedures of the Inventory Application (continued)

I* Allocated data that is output to the client must be allocated with */

/* the MIDL_user_al locate stub support routine. Allocate for a */

/* part_list struct plus the array of subpart numbers. Remember the */

/* part_list struct already has an array with one element, hence the -1. */ size = sizeof (part_list) + (sizeof (part_num) * (part->subparts.size-l) ) ; *subpart_ptr = (part_list *)MIDL_user_allocate( (unsigned) size) ;

/* fill in the values */

(*subpart_ptr) ->size = part->subparts.size;

for(i =0; i < (*subpart_ptr) ->size; i++)

(*subpart_ptr) ->numbers[i] = part ->subparts. numbers [i ] ; return;

long int orderjpart (number, quantity, account)

part_num number;

part_quantity *quantity;

account_num account ;

{

part_record *part; /* pointer to a part record */

long error =1; /* assume no error to start */

/* Test for valid input */

if ( !read_part_record( number, &part) ) /* invalid part number input */

error = -1; else if (quantity->units == ITEM) /* invalid quantity input */

error = (quantity->total. number <= 0) ? -2 : error; else if (quantity->units == GRAM I I quantity->units == KILOGRAM)

error = (quantity->total. weight <= 0.0) ? -2 : error; /* else if () invalid account, not implemented */ /* error = -3; */

if (error < 0)

return (error) ;

/* convert input quantity & units if units are not correct for part */ if (quantity- >units != part->quantity. units) {

if (part-xjuantity. units == ITEM) /* convert weight to items */

quantity->total. number = (long int) quantity- >total. weight; else if (quantity->units == ITEM) /* convert items to weight */

quantity- >total .weight = (long float) quantity- >total. number; else if (quantity->units == GRAM && part-xjuantity. units == KILOGRAM)

quantity- >total . weight /= 1000.0; /* convert grams to kilograms */ else if (quantity->units == KILOGRAM && part -xjuantity. units == GRAM)

quantity->total. weight *= 1000.0; /* convert kilograms to grams */ quantity->units = part-xjuantity. units;

/* check if enough in inventory for this order */ switch (part-xjuantity. units) { case ITEM:

if (part-xjuantity. total. number > quantity->total. number) /* reduce quantity in inventory by amount ordered */ part -xjuantity. total. number -= quantity- >total . number; else {

Example D-3: Remote Procedures of the Inventory Application (continued)

/* order all available and reduce quantity in inventory to 0 */

quantity->total.number = part-xjuantity. total, number ;

part-xjuantity.total.number = 0; }

break;

case KILOGRAM: case GRAM:

if(part-xjuantity.total.weight > quantity->total.weight)

/* reduce quantity in inventory by amount ordered */

part-xjuantity. total, weight -= quantity->total.weight; else {

/* order all available and reduce quantity in inventory to 0.0 */

quantity->total.weight = part-xjuantity.total.weight;

part-xjuantity.total.weight = 0.0; } break;

write_part_record(part); /* update inventory */ return(1); /* order ok */

Example D-4: The Inventory Implementation

/* FILE NAME: invntry.c */

/* A sample implementation of an inventory. */

* For simplicity, a few inventory items are maintained in the inventory. */

* The valid numbers are printed when the open_inventory() procedure is */ /* called so the user knows what numbers to test. */ #include <stdio.h>

#include <stdlib.h>

ttinclude "inv.h"

#define MAX_PARTS 10 /* maximum number of parts in this inventory */

#define MAX_SUBPARTS 5 /* maximum number of subparts for a part */

static part_record *rec[MAX_PARTS]; /* array of pointers for this inventory */ static inventory_is_open =0; /* flag is reset to non-zero when open */

* Data for empty record or unknown part number */ static part_record no_part = {0,"UNKNOWN"}; static part_num no_subparts[MAX_SUBPARTS];

void open_inventory () /***** setup inventory *******************************/

int i, j; unsigned size;

/* Allocate memory for the inventory array. Each part gets the size of */ /* a part_record plus enough memory for a subpart list. Since the */ /* subpart list is already defined in the part_record as an array of 1, */

* the new array memory only needs to be MAX_SUBPARTS-1 in size. */ for(i =0; i < MAX_PARTS; i++) {

size = sizeof(part_record) + (sizeof(part_num) * (MAX_SUBPARTS-1));

rec[i] = (part_record *)malloc(size);

Example D-4. The Inventory Implementation (continued)

}

/* assign some data to the inventory array (part of an exercise machine) */

rec[0]->number = 102;

stmcpy((char *)rec[0]->name / "electronics display module", MAX_STRIN3) ;

rec[0]->description = (paragraph) malloc(1000);

strcpy((char *)rec[0]->description,

"The electronics display module is a liquid crystal display containing\n\ a timer, counter, metronome, and calorie counter."); rec[0]->price.units = ITEM; rec[0]->price.per_unit = 7.00; rec[0]->quantity.units = rec[0]->price.units; rec[0]-xjuantity.total.number = 432;

rec[0]->subparts.size = 4; /* cannot be greater than MAX_SUBPARTS */ for(i =0; i < rec[0]->subparts.size; i++) /* values used are not relevant */ rec[0]->subparts.numbers[i] = rec[0]->number + 1 + i;

rec[l]->number = 203;

strncpy ((char *)rec[l]->name, "base assembly", MAX_STRHSJG) ; rec [1]-description = (paragraph)malloc(1000); strcpy((char *)rec[l]-xiescription,

"The base assembly rests on the floor to stabilize the machine.\n\ The arm and bench assemblies are attached to it."); rec[l]->price.units = ITEM; rec[l]->price.per_unit = 85.00; recfl]-xjuantity.units = recfl]->price.units; rec[1]-xjuantity.total.number = 1078;

rec[l]->subparts.size = 5; /* cannot be greater than MAX_SUBPARTS */ forfi =0; i < rec[1]->subparts.size; i++) /* values used are not relevant */ rectl]->subparts.numbers[i] = rec[1]->number + 17 + i;

rec[2]->number = 444;

strncpy((char *)rec[2]->name, "ballast", MAX_STRIN3); rec[2]-xiescription = (paragraph)malloc(1000); strcpy((char *)rec[2]-xJescription,

"The ballast is used to counterbalance the force exerted by the user."); rec[2]->price.units = KILOGRAM; rec[2]->price.per_unit = 1.59; rec[2]-xjuantity.units = rec[2]->price.units; rec[2]-xjuantity.total.weight = 13456.2;

rec[2]->subparts.size =0; /* cannot be greater than MAX_SUBPARTS */ for(i =0; i < MAX_^UBPARTS; i++) /* zero out subpart array */

rec[2]->subparts.numbers[i] = no_subparts[i];

/* fill in rest of inventory as "empty" data */ for(i =3; i < MAX_PARTS; i++) {

rec[i] = &no_part;

for(j = 0; j < MAX_SUBPARTS; j++)

rec[i]->subparts.numbers [j] = no_subparts[j]; }

puts("Part numbers in inventory:"); for(i = 0; i < MAX_PARTS; i++)

if(rec[i]->number > 0)

printf("%ld\n", rec[i]->number); inventory_is_open = 1;

Microsoft RFC Programming Guide

Example D-4: The Inventory Implementation (continued)

return;

void close_inventory ( ) /**** close inventory

/

/* Undo whatever is done in open_inventory . Free memory and so forth. */

/* (not implemented) */

return;

int read_part_record ( number, part_ptr) /** get record for this part number **/ part_num number; part_record **part_ptr;

int i;

if (inventory_is_open == 0)

open_inventory ( ) ; *part_ptr = &no_part; for(i =0; i < MAX_PARTS; i++) if (rec[i] ->number == number) { *part_ptr = rec[i]; break;

/* initialize assuming no part */ /* search the inventory */ /* found the part */

if( (*part_ptr) ->number > 0)

return ( 1 ) ; else

return ( 0 ) ;

/* not a valid part

int write_part_record(part)

part_record *part;

{

int i;

update inventory for this part number *****

if (inventory_is_open == 0)

open_inventory ( ) ; for(i =0; i < MAX_PARTS;

if (rec[i]->number == part->number) {

rec[i] = part; /* overwrite inventory with new data */ return (1) ; } return (0) ;

/* dump the part data to the screen. static dump_part_record( index) int index; {

printf ( "number input : %ld part number : %ld\n" , number, rec [index] ->number)

printf ( "part name: %s\n" , rec [index] ->name) ;

printf ( "description : %s\n" , rec [ index] -Rescript ion) ;

printf ("price :%f per %s\n", rec [ index] ->price.per_unit,

Example D-4: The Inventory Implementation (continued)

(rectindex]->price.units == ITEM) ? "item" : "gram"); printf("quantity:"); switchfrec[index]->quantity.units) {

case ITEM: printf("%ld items\n", rec[index]->quantity.total.number); break; case GRAM: printf("%f grams\n", rec[index]-xjuantity.total.weight); break; case KILOGRAM: printf("%f kilos\n", rec[index]-xjuantity.total.weight);

break; }

print f("subparts: "); for(i =0; i < rec[index]->subparts.size; i++)

printf("%ld ", rec[index]->subparts.numbers[i]); printf("\n"); }*/

Example D-5. Server Initialization of the Inventory Application

/* FILE NAME: server.c */

tinclude <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include "inv.h" /* header created by the IDL corrpiler */

#include "status.h" /* contains the CHECK_STATUS macro */

ttdefine STRINGLEN 50

main (argc, argv)

int argc;

char *argv [ ] ;

{

error_status_t status; /* error status */

/* RFC vectors */

rpc_binding_vector_t *binding_vector; /* binding handle list */

RPC_PROTSEO_VECTOR *protseq_vector; /*protocol sequence list */

char entry_name [STRINGLEN]; /* name service entry name */ char group_name [STRINGLEN]; /* name service group name */ char annotation [STRINGLEN]; /* annotation for endpoint map */ char hostname[STRINGLEN]; /* used to store the computer name */

DWDRD hostname_size=STRINGLEN; /* required by GetComputerName */ /************************** REGISTER INTERFACE ***************************/ status = RpcServerRegisterlf(

inv_vl_0_s_ifspec, /* interface specification (inv.h) */

NULL,

NULL ); CHECK_STATUS(status, "Can't register interface:", ABORT);

/****************** CREATING SERVER BINDING INFORMATION ******************/ if(argc > 1) { status =

RpcServerUseProtseq( /* use a protocol sequence */

(unsigned char *)argv[l], /* the input protocol sequence */

RPC_C_PROTSEO_MAX_REQS_DEFAULT, /* the default number of requests*/

NULL /* security descriptor (not reqd)*/

Microsoft RFC Programming Guide

Example D-5: Server Initialization of the Inventory Application (continued)

CHECK_STATUS(status, "Can't use this protocol sequence:", ABORT); } else {

puts("You can invoke the server with a protocol sequence argument.");

status =

RpcServerUseAllProtseqs ( /* use all protocol sequences

RPC_C_PROTSEQ_MAX_REQS_DEFAULT, /* the default number of requests */ NULL /* security descriptor (not reqd) */

);

CHECK_STATUS(status, "Can't register protocol sequences:", ABORT);

}

status =

RpcServerlnqBindings ( /* get binding information for server */

&binding_vector

);

CHECK_STATUS(status, "Can't get binding information:", ABORT);

/*************************** ADVERTISE SERVER ****************************/

strcpy(entry_name, "/.:/inventory_");

GetComputerName(&hostname, &hostname_size);

strcat(entry_name, hostname);

status =

RpcNsBindingExport( /* export to a name service database */

RPC_C_NS_SYNTAX_DEFAULT, /* syntax of entry name */

(unsigned char *)entry_name, /* name of entry in name service */ inv_vl_0_s_ifspec, /* interface specification (inv.h) */ binding_vector, /* binding information */

NULL /* no object UUIDs exported */

);

CHECK_STATUS(status, "Can't export to name service database:", RESUME);

ENDPOINTS w***"*******'*'*'****'*** «••*** ^

strcpy(annotation, "Inventory interface");

status =

RpcEpRegister( /* add endpoints to local endpoint map */

inv_vl_0_s_ifspec, /* interface specification (inv.h) */ binding_vector, /* vector of server binding handles */

NULL, /* no object UUIDs to register */

(unsigned char *)annotation /* annotation supplied (not required) */

);

CHECK_STATUS(status, "Can't add endpoints to local endpoint map:", RESUME);

status =

RpcBindingVectorFree( /* free server binding handles */

&binding_vector ); CHECK_STATUS(status, "Can't free server binding handles:", RESUME);

open_inventory(); /* application specific procedure */

/******************* LISTEN FOR REMOTE PROCEDURE CALLS *******************/ RpcTryExcept /* thread exception handling macro */

Example D- 5: Server Initialization of the Inventory Application (continued)

status = RpcServerListen (

1, /* process one remote procedure call at a time */

RPC_C_LISTEN_MAX_CALLS_DEFAULT ,

NULL );

CHECK_STATUS ( status, "rpc listen failed:", RESUME); }

RpcExcept (RpcExceptionCodeO ) /* error recovery and cleanup */

{

close_inventory ( ) ; /* application specific procedure */

status =

RpcServerlnqBindings ( /* get binding information */

&binding_vector ); CHECK_STATUS( status, "Can't get binding information:", RESUME);

status =

RpcEpUnregister ( /* remove endpoints from local endpoint map */

inv_vl_0_s_ifspec, /* interface specification (inv.h) */

binding_vector, /* vector of server binding handles */

NULL /* no object UUIDs */

);

CHECK_STATUS( status, "Can't remove endpoints from endpoint map:", RESUME);

status =

RpcBindingVectorFree ( /* free server binding handles */

&binding_vector ); CHECK_STATUS( status, "Can't free server binding handles:", RESUME);

puts ( " \nServer quit ! " ) ; }

RpcEndExcept ; } /* END SERVER INITIALIZATION */

/*** MIDL_user_al locate / MIDL_user_free ***/

void * __RPC_API MIDL_user_al locate "

size_t size; {

unsigned char * ptr; ptr = malloc ( size ) ; return ( (void * ) ptr

void _RPC_API MIDL_user_free

Example D-5: Server Initialization of the Inventory Application (continued)

(

obj ect )

void * object; {

free (object); }

Example D-6: The Automatic Client File of the Inventory Application

/* FILE NAME: client.c */

/******************** client of the inventory application *******************/

#include <stdio.h>

#include <stdlib.h>

#include "inv.h" /* header file created by the IDL compiler */

char instructions[] = "Type character followed by appropriate argument(s).\n\

Is part available? a [part_number]\n\

What is part name? n [part_number]\n\

Get part description. d [part_number]\n\

What is part price? p [part_number]\n\

What is part quantity? q [part_number]\n\ What are subparts of this part? s [part_number]\n\

Order part. o part_number quantity\n\

REDISPLAY r\n\

EXIT e\n" ;

main()

{

part_record part; /* structure for all data about a part */

part_list *subparts; /* pointer to parts list data structure */ account_num account =1234; /* a user account number */

int i, num_args, done = 0;

long result;

char input[100], selection[20], quantity[20];

puts(instructions);

part.number = 0;

strcpy(quantity, "");

whileUdone) { /* user makes selections and each is processed */

printf("Selection: "); fflush(stdout); gets(input);

num_args = sscanf(input, "%s%ld%s", selection, &(part.number), quantity);

switch (tolower(selection[0])) { case 'a': if (is_part_available(part.number)) puts("available: Yes");

else

puts("available: No");

break; case 'n': whatis_part_name(part.number, part.name);

printf("name:%s\n", part.name);

break; case 'd': part.description = get_part_description(part.number);

printf("description:\n%s\n", part.description);

Appendix D: The Inventory Application

173

Example D-6: The Automatic Client File of the Inventory Application (continued)

if(part.description != NULL)

free(part.description); /* free memory allocated */ break;

case 'p': whatis_part_price(part.number, &(part.price)); printf("price:%10.2f\n", part.price.per_unit); break;

case 'q': whatis_part_quantity(part.number, &(part.quantity)); if (part, quantity, units == ITEM)

printf("total items:%ld\n", part.quantity.total.number); else if(part.quantity.units == GRAM)

printf("total grams:%10.2f\n", part.quantity.total.weight); else if(part.quantity.units == KILOGRAM)

printf("total kilos:%10.2f\n", part.quantity.total.weight); break;

case 's': whatare_subparts(part.number, &subparts); for(i =0; i < subparts->size; i++)

printf("%ld ", subparts->numbers[ i ]) ;

printf("\ntotal number of subparts:%ld\n", subparts->size); free(subparts); /* free memory for conformant struct */ break; case 'o': if(num_args < 3) {

puts("Not enough arguments"); break;

/* Assume KILOGRAM units and assign quantity input */

part.quantity.units = KILOGRAM;

part.quantity.total.weight = atof(quantity);

result = order_part(part.number, &(part.quantity), account);

if(result > 0) {

if(part.quantity.units == ITEM)

printf("order:%ld items\n", part.quantity.total.number); else if(part.quantity.units == GRAM)

printf("order:%10.2f grams\n", part.quantity.total.weight), else if(part.quantity.units == KILOGRAM)

printf("order:%10.2f kilosYn", part.quantity.total.weight),

else { /* error cases */

if(result == -1) puts("Invalid part number"); else if(result == -2) puts("Invalid quantity"); •else if(result == -3) puts("Invalid account number");

break;

case 'r': /* redisplay selection or bad input displays instructions */ default: puts(instructions); break; case 'e': done = 1; break; } /*end case */ } /* end while */ } /* end mainO */

/**** /*** /***<

MIDL_user_allocate / MIDL_user_free

****/ *** /

****/

Example D-6: The Automatic Client File of the Inventory Application (continued)

void * _RPC_API MIDL_user_allocate

size_t size; {

unsigned char * ptr; ptr = malloc ( size ) ; return ( (void *)ptr );

void __RPC_API MIDL_user_free (

ob j ect )

void * object; {

free (object) ; }

Example D- 7: The Makefile for the Implicit Client

# FILE NAME: Makefile

# Makefile for the inventory application implicit client #

# definitions for this make file #

APPL=inv

IDLCMD=midl

NTRPCLIBS=rpcrt4 . lib rpcns4.1ib libcmt.lib kerne!32.1ib

! include <ntwin32.mak>

## NT c flags

cflags = -c -WO -Gz -D_X86_=1 -DWIN32 -DMT /I. /I., /nologo

## NT nmake inference rules

$(cc) $(cdebug) $ (cflags) $(cvarsmt) $< $(cvtotnf)

#

# COMPLETE BUILD of the application #

all: lclient.exe interface client.exe

#

# INTERFACE BUILD #

interface : $ ( APPL ) . h $ ( APPL ) _c . ob j

#

# LOCAL BUILD of the client application to test locally

Example D- 7: The Makefile for the Implicit Client (continued)

#

local: lclient.exe

lclient.exe: Iclient.obj Imanager.obj invntry.obj

$(link) $(linkdebug) $(conflags) -out:lclient.exe -map:lclient.map \

Iclient.obj Imanager.obj invntry.obj \

$(NTRPCLIBS)

#

# CLIENT BUILD #

client: client.exe

client.exe: client.obj getbind.obj intbind.obj $(APPL)_c.obj

$(link) $(linkdebug) $(conflags) -out:client.exe -map:client.map \

client.obj getbind.obj intbind.obj $(APPL)_c.obj \

$(NTRPCLIBS)

# client and server sources client.obj: client.c $(APPL).h getbind.obj: getbind.c

intbind.obj: intbind.c

# Local client sources invntry.obj: ..\invntry.c

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCAL /I. /I.. \

/Foinvntry.obj ..\invntry.c Iclient.obj: client.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCAL /I. /I.. \

/Folclient.obj client.c Imanager.obj: ..\manager.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCAL /I. /I.. \ /FoImanager.obj ..\manager.c

# client stubs

$(APPL)_c.obj: $(APPL)_c.c $(APPL)_x.obj: $(APPL)_x.c

# generate stubs, auxiliary and header file from the IDL file $(APPL).h $(APPL)_i.acf $(APPL)_c.c $(APPL)_x.c : ..\$(APPL).idl

$(IDLCMD) ..\$(APPL).idl /acf $(APPL)_i.acf

# clean up for fresh build clean:

del $(APPL)_?.c del *.obj del $(APPL).h del *.map del *.pdb

clobber: clean

if exist client.exe del client.exe if exist lclient.exe del lclient.exe if exist server.exe del server.exe

Microsoft RFC Programming Guide

Example D-8: An ACF File for Implicit Binding

I* FILE NAME: inventory.acf (implicit version)*/

/* This Attribute Configuration File is used in conjunction with the */

/* associated .idl file (inventory.idl) when the IDL compiler is invoked. */

implicit_handle(handle_t global_binding_h) /* implicit binding method */

]

interface inv /* The interface name must match the .idl file. */

Example D-9: The Implicit Client of the Inventory Application

I* FILE NAME: client.c */

/******* Client of the inventory application with implicit method ***********/

#include <stdio.h>

#include <stdlib.h>

#include "inv.h" /* header file created by the IDL compiler */

#include "..\status.h"

char instructions[] = "Type character followed by appropriate argument(s).\n\

Is part available?

What is part name?

Get part description.

What is part price?

What is part quantity?

What are subparts of this part?

Order part.

REDISPLAY

EXIT

[part_number]\n\ [part_number]\n\ [part_number]\n\ [part_number]\n\ [part_number]\n\ [part_number]\n\

o part_number quantity\n\

r\n\

e\n" ;

main()

part_record part; part_list *subparts; account_num account = 1234; unsigned long status;

/* structure for all data about a part */

/* pointer to parts list data structure */

/* a user account number */

/* error status */

int i, num_args, done = 0;

long result;

char input[100], selection[20], quantity[20];

puts(instructions); part.number = 0; strcpy(quantity, "");

#ifndef LOCAL

do_import_binding(' #endif

/* find server in name service database */ &global_binding_h);

status = RpcBindingReset(global_binding_h);

CHECK_STATUS(status, "Can't reset binding handle", ABORT);

while Udone) { /* user makes selections and each is processed */

printf("Selection: "); fflush(stdout); gets(input); num_args = sscanf(input, "%s%ld%s", selection, &(part.number), quantity),

switch (tolower(selection[0])) {

Appendix D: The Inventory Application

177

Example D-9: The Implicit Client of the Inventory Application (continued)

case 'a': if (is_part_available(part.number))

puts("available: Yes"); else

puts("available: No") ; break;

case 'n': whatis_part_name(part.number, part.name); printf("name:%s\n", part.name); break;

case 'd': part.description = get_part_description(part.number); printf("description:\n%s\n", part.description); if(part.description != NULL)

free(part.description); /* free memory allocated */ break;

case 'p': whatis_part_price(part.number, &(part.price)); printf("price:%10.2f\n", part.price.per_unit),-break;

case 'q': what is_part_quantity( part, number, & (part, quantity) ); if (part, quantity, units == ITEM)

printf("total items:%ld\n", part.quantity.total.number); else if(part.quantity.units == GRAM)

printf("total grams:%10.2f\n", part.quantity.total.weight); else if(part.quantity.units == KILOGRAM)

printf("total kilos:%10.2f\n", part.quantity.total.weight); break;

case 's': whatare_subparts(part.number, &subparts); for(i = 0; i < subparts->size; i++)

printf("%ld ", subparts->numbers[ i ]) ;

printf("\ntotal number of subparts:%ld\n", subparts->size); free(subparts); /* free memory for conformant struct */ break; case 'o': if(num_args < 3) {

puts("Not enough arguments"); break;

/* Assume KILOGRAM units and assign quantity input */ part, quantity, units = KILOGRAM; part.quantity.total.weight = atof(quantity); result = order_part(part.number, &(part.quantity), account); if(result > 0) { If(part.quantity.units == ITEM)

printf("order:%ld items\n", part.quantity.total.number); else if(part.quantity.units -= GRAM)

printf("order:%10.2f grams\n", part.quantity.total.weight); else if(part.quantity.units == KILOGRAM)

printf("order:%10.2f kilos\n", part.quantity.total.weight);

else { /* error cases */

if (result == -1) puts ("Invalid part number"),-

else if(result == -2) puts("Invalid quantity");

else if(result == -3) puts("Invalid account number");

break; case 'r': /* redisplay selection or bad input displays instructions */

Microsoft RFC Programming Guide

Example D-9: The Implicit Client of the Inventory Application (continued)

default: puts ( instructions ); break; case 'e' : done = 1; break; } /*end case */ } /* end while */ } /* end main() */

^ ************************************************************************* / /*** MIDL_user_al locate / MIDL_user_free

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

void * __RPC_API MIDL user_al locate

size_t size; {

unsigned char * ptr; ptr = malloc ( size ) ; return ( (void *)ptr );

void __RPC_API MIDL_user_free (

ob j ect )

void * object; {

free (object) ;

Example D-10. The do_import_binding Procedure

/* FILE NAME: getbind.c */

/* Get binding from name service database. */

#include <stdio.h>

# include "inv.h"

#include " . . \status .h"

void do_import_binding(entry_name, binding_h)

char entry_name [ ] ; /* entry name to begin search */

rpc_binding_handle_t *binding_h; /* a binding handle */

{

unsigned long status; /* error status */

RPC_NS_HANDLE import_context ; /* required to iirport */

char protseq[20]; /* protocol sequence */

status =

RpcNsBindinglmportBegin ( /* set context to import binding handles */

RPC_C_NS_SYNTAX_DEFAULT, /* use default syntax */

(unsigned char *)entry_name, /* begin search with this name */

inv_vl_0_c_ifspec, /* interface specification (inv.h) */

NULL, /* no optional object UUID required */

Example D-10: The do_import_binding Procedure (continued)

&import_context /* import context obtained */

); CHECK_STATUS(status, "Can't begin import:", RESUME);

while(1) { status = RpcNsBindinglmportNext ( /* import a binding handle */

import_context, /* context from rpc_ns_binding_import_begin */

binding_h /* a binding handle is obtained */

); if(status != RPC_S_OK) {

CHECK_STATUS(status, "Can't import a binding handle:", RESUME);

break; }

/** application specific selection criteria (by protocol sequence) * */

do_interpret_binding(*binding_h ,protseq);

if(strcmp(protseq, "ncacn_ip_tcp") == 0) /*select connection protocol*/

break; else {

status =

RpcBindingFree( /* free binding information not selected */ binding_h

);

CHECK_STATUS(status, "Can't free binding information:", RESUME); } } /*end while */

status =

RpcNsBindinglnportDone( /* done with import context */

&import_context /* obtained from rpc_ns_binding_import_begin */ );

return; }

Example D-ll. The do_interpret_binding Procedure

/* FILE NAME: intbind.c */

/* Interpret binding information and return the protocol sequence. */

#include <stdio.h>

#include <rpc.h>

#include "..\status.h" .

void do_interpret_binding(binding, protocol_seq)

rpc_binding_handle_t binding; /* binding handle to interpret */

cnar *protocol_seq; /* protocol sequence to obtain */

{

unsigned long status; /* error status */

unsigned char *string_binding; /* string of binding information */

unsigned char *protseq; /* binding component of interest */

status =

RpcBindingToStringBinding( /* convert binding information to string */

binding, /* the binding handle to convert */

&string_binding /* the string of binding data */

Microsoft RFC Programming Guide

Example D- 11: The do_interpret_binding Procedure (continued)

);

CHECK_STATUS( status, "Can't get string binding :", RESUME);

status =

RpcStringBindingParse ( /* get components of string binding */

string_binding, /* the string of binding data */

NULL, /* an object UUID string is not obtained */

&protseq, /* a protocol sequence string IS obtained */

NULL, /* a network address string is not obtained */

NULL, /* an endpoint string is not obtained */

NULL /* a network options string is not obtained */

);

CHECK_STATUS ( status, "Can't parse string binding:", RESUME);

strcpy (protocol_seq, (char *)protseq) ;

/* free all strings allocated by other runtime routines */

status = RpcStringFree(&string_binding) ; status = RpcStringFreef&protseq ); return;

Example D- 12: The Makefile for the Explicit Client

# FILE NAME: Makefile

# Makefile for the inventory application explicit client #

# definitions for this make file #

APPL=inv

IDLCMD=midl

NTRPCLIBS=rpcrt4.1ib rpcns4.1ib libcmt.lib kerne!32.1ib

! include <ntwin32 .mak>

## NT c flags

cflags = -c -WO -Gz -D_X86_=1 -DWIN32 -DMT /nologo

## NT nmake inference rules

$(cc) $(cdebug) $ (cflags) $(cvarsmt) /I. /I.. $< $(cvtomf )

#

# COMPLETE BUILD of the application #

all: local interface client server

#

# INTERFACE BUILD #

interface: $(APPL) .h $ (APPL)_c.obj $ (APPL)_s.obj $ (APPL)_x.obj

#

# LOCAL BUILD of the client application to test locally #

local : Iclient . exe

Appendix D: The Inventory Application J81

Example D-12-. The Makefile for the Explicit Client (continued)

lclient.exe: Iclient.obj manager.obj invntry.obj

$(link) $(linkdebug) $(conflags) -out:lclient.exe -map:lclient.map \ Iclient.obj manager.obj invntry.obj \ $(NTRPCLIBS)

#

# CLIENT BUILD #

client: client.exe

client.exe: client.obj getbind.obj intbind.obj $(APPL)_c.obj $(APPL)_x.obj $(link) $(linkdebug) $(conflags) -out:client.exe -map:client.map \

client.obj getbind.obj intbind.obj $(APPL)_c.obj $(APPL)_x.obj \

$(NTRPCLIBS)

#

# SERVER BUILD #

server: server.exe

server.exe: server.obj manager.obj invntry.obj $(APPL)_s.obj $(APPL)_x.obj $(link) $(linkdebug) $(conflags) -out:server.exe -map:server.map \

server.obj manager.obj invntry.obj $(APPL)_s.obj $(APPL)_x.obj\

$(NTRPCLIBS)

# client and server sources client.obj: client.c $(APPL).h manager.obj: manager.c $(APPL).h server.obj: ..\server.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /I. /I.. \

/Foserver.obj ..\server.c getbind.obj: ..\implicit\getbind.c

$(cc) $(cdebug) $(cflags) $(cvarsmt) /I. /I.. \

/Fogetbind.obj ..\implicit\getbind.c intbind.obj: ..\implicit\intbind.c

$(cc) $(cdebug) $(cflags) $(cvarsmt) /I. /I.. \

/Fointbind.obj ..\implicit\intbind.c invntry.obj: ..\invntry.c

$(cc) $(cdebug) $(cflags) $(cvarsmt) /I. /I.. \ /Foinvntry.obj ..\invntry.c

# Local client sources Iclient.obj: client-.c $(APPL).h

$(cc) $(cdebug) $(cflags) $(cvarsmt) /DLOCAL /I. /I.. \ /Folclient.obj client.c

# client stubs

$(APPL)_c.obj: $(APPL)_c.c $(APPL)_x.obj: $(APPL)_x.c

# compile the server stub $(APPL)_s.obj : $(APPL)_s.c

# generate stubs, auxiliary and header file from the IDL file $(APPL).h $(APPL)_c.c $(APPL)_x.c $(APPL)_s.c: $(APPL).idl

$(IDLCMD) $(APPL).idl

Microsoft RFC Programming Guide

Example D-12: The Makefile for the Explicit Client (continued)

# clean up for fresh build clean:

del $(APPL)_?.c

del *.obj

del $(APPL).h

del *.map

del *.pdb

clobber: clean

if exist client.exe del client.exe if exist lclient.exe del lclient.exe if exist server.exe del server.exe

Example D-13: The MIDI File, Explicit Binding

/* FILE NAME: inv.idl */

/* brackets enclose attributes */

uuid(cbb7c850-0568-llce-b719-08002bl85ad7), /* universal unique identifier */

version(l.O), /* version of this interface */

pointer_default(unique) /* pointer default

] interface inv /* interface name */

{

const long MAX_STRING = 30; /* constant for string size */

typedef long part_num; /* inventory part number */

typedef [string] char part_name[MAX_STRING+1]; /* name of part */ typedef [string, unique] char *paragraph; /* description of part */

typedef enum {

ITEM, GRAM, KILOGRAM } part_units; /* units of measurement */

typedef struct part_price { /* price of part */

part_units units;

double per_unit; } part_price;

typedef union switch(part_units units) total { /* quantity of part */

case ITEM: long int number;

case GRAM:

case KILOGRAM: double weight; } part_quantity;

typedef struct part_list{ /* list of part numbers */

long size; /* number of parts in array */

[size_is(size)] part_num numbers[*]; /* conformant array of parts */

} part_list;

typedef struct part_record { /* data for each part */

part_num number; part_name name; paragraph description; part_price price; part_quantity quantity;

Appendix D: The Inventory Application

183

Example D-13: The MIDI File, Explicit Binding (continued)

subparts;

part_list } part_record;

typedef long account_num;

/* user account number */

/************************ procedure Declarations ************************* boolean is_part_available( /* return true if in inventory */ [in] handle_t binding_h, /* binding handle for explicit client */ [in] part_num number /* input part number */

void whatis_part_name (

[in] handle_t binding_h, [in] part_num number, [in, out] part_name name

/* get part name from inventory */ /* binding handle for explicit client */ /* input part number */

/* output part name */

paragraph get_part k _description ( [in] handle_t binding_h, [in] part_num number

/* return a pointer to a string */ binding handle for explicit client */

void whatis_part_price (

[in] handle_t binding_h, [in] part_num number, [out] part_price *price

/* get part price from inventory */ /* binding handle for explicit client */

void whatis_part_quantity (

[in] handle_t binding_h, [in] part_num number, [out] part_quantity *quantity

/* get part quantity from inventory */ /* binding handle for explicit client */

void whatare_subparts (

[in] handle_t binding_h, [in] part_num number, [out] part_list **subparts

/* get list of subpart numbers */ /* binding handle for explicit client */

/* structure containing the array */

/* Order part from inventory with part number, quantity desired, and

/* account number. If inventory does not have enough, output lesser

/* quantity ordered. Return values: l=ordered OK,

/* -l=invalid part, -2=invalid quantity, -3=invalid account.

long order_part( /* order part from inventory, return OK or error code */ [in] handle_t binding_h, /* binding handle for explicit client */ [in] part_num number,

[in,out] part_quantity *quantity, /* quantity ordered */

[in] account_num account

} /* end of interface definition */

Microsoft RPC Programming Guide

Example D- 14: Remote Procedures, Explicit Binding

/* FILE NAME: manager. c */

/** Implementation of the remote procedures for the inventory application. **/

#include <stdio.h> #include <stdlib.h> # include "inv.h"

boolean is_part_available(binding_h, number)

handle_t binding_h; /* declare a binding handle */

part_num number;

part_record *part; /* a pointer to a part record */

int found;

found = read_part_record( number, &part) ; if (found)

re turn (TRUE) ; else

re turn (FALSE) ;

void whatis_part_name(binding_h, number, name)

handle_t binding_h; /* declare a binding handle */

part_num number;

part_name name;

{

part_record *part; /* a pointer to a part record */

read_part_record(number, &part);

strncpy((char *)name, (char *)part->name, MAX_STRING);

return;

paragraph get_part_description(binding_h, number)

handle_t binding_h; /* declare a binding handle */

part_num number;

part_record *part; /* a pointer to a part record */

paragraph description; int size;

if( read_part_record(number, &part) ) {

/* Allocated data that is returned to the client must be allocated */ /* with the MIDL_user_allocate stub support routine. */

size = strlen((char *)part->description) + 1; description = (paragraph)MIDL_user_allocate((unsigned)size); strcpy((char *)description, (char *)part->description);

else

description - NULL; return(description); }

void whatis_part_price(binding_h, number, price)

handle_t binding_h; /* declare a binding handle */

Example D- 14: Remote Procedures, Explicit Binding (continued)

part_num number; partjprice *price; {

part_record *part; /* a pointer to a part record */

read_part_record ( number , &part ) ; price->units = part->price. units; price->per_unit = part->price.per_unit; return;

void whatis_part_quantity (binding_h, number, quantity)

handle_t binding_h; /* declare a binding handle */

part_num number;

part_quantity *quantity;

{

part_record *part; /* a pointer to a part record */

read_part_record ( number , &part ) ; quantity->units = part-xjuantity. units; switch ( quantity- >units) {

case ITEM: quantity->total. number = part -xjuantity. total. number; break;

case KILOGRAM:

case GRAM: quantity- >total. weight = part-xjuantity. total. weight;

break; } return;

void whatare_subparts (binding_h, number, subpart_ptr)

handle_t binding_h; /* declare a binding handle */

part_num number;

part_list **subpart_ptr;

{

part_record *part; /* pointer to a part record */

int i;

int size;

read_part_record( number, &part) ;

/* Allocated data that is output to the client must be allocated with */

/* the MIDL_user_al locate stub support routine. Allocate for a */

/* part_list struct plus the array of subpart numbers. Remember the */

/* part_list struct already has an array with one element, hence the -1. */ size = sizeof (part_list) + (sizeof (part_num) * (part->subparts.size-l) ) ; *subpart_ptr = (part_list *)MIDL_user_al locate ( (unsigned) size) ;

/* fill in the values */

(*subpart_ptr)->size = part->subparts.size; for(i = 0; i < (*subpart_ptr) ->size; i++)

(*subpart_ptr) ->numbers[i] = part ->subparts. numbers [i] ; return;

Microsoft RFC Programming Guide

Example D- 14: Remote Procedures, Explicit Binding (continued)

long int order_part (binding_h, number, quantity, account) handle_t binding_h; /* declare a binding handle */ part_num number; part_quantity *quantity; account_num account ;

{

part_record *part; /* pointer to a part record */

long error = 1; /* assume no error to start */

/* Test for valid input */

if ( !read_part_record (number, &part) ) /* invalid part number input */

error = -1; else if (quantity->units == ITEM) /* invalid quantity input

error = ( quant ity->total. number <= 0) ? -2 : error; else if (quantity->units == GRAM I I quantity->units == KILOGRAM)

error = (quantity->total. weight <= 0.0) ? -2 : error; /* else if () invalid account, not implemented */ /* error = -3; */

if (error < 0)

return (error) ;

/* convert input quantity & units if units are not correct for part */ if (quantity- >units != par t-xguantity. units) {

if (part-xjuantity. units == ITEM) /* convert weight to items */

quant ity->total. number = (long int }quantity->total. weight; else if (quantity- >units == ITEM) /* convert items to weight */

quantity- >total .weight = (long float) quantity- >total. number; else if (quantity- >units == GRAM && par t-xguantity. units == KILOGRAM)

quant ity->total. weight /= 1000.0; /* convert grams to kilograms */ else if (quantity->units == KILOGRAM && par t-xguantity. units == GRAM)

quantity- >total. weight *= 1000.0; /* convert kilograms to grams */ quantity->units = part-xguantity. units;

/* check if enough in inventory for this order */ switch (part-xguantity. units) { case ITEM:

if (part-xguantity. total. number > quantity- >total . number) /* reduce quantity in inventory by amount ordered */ part-xguantity. total. number -= quantity- >total . number; else {

/* order all available and reduce quantity in inventory to 0 */ quant ity->total. number = part-xguantity. total. number; part-xguantity. total. number = 0; }

break;

case KILOGRAM: case GRAM:

if (part-xguantity. total. weight > quantity- >total . weight) /* reduce quantity in inventory by amount ordered */ part-xjuantity. total. weight -= quantity- >total. weight; else {

/* order all available and reduce quantity in inventory to 0.0 */ quantity->total .weight = part-xjuantity . total .weight ;

Appendix D: The Inventory Application

187

Example D-14: Remote Procedures, Explicit Binding (continued)

part-xjuantity.total, weight = 0.0; } break;

write_part_record(part); /* update inventory */ return(l); /* order ok */

Example D-15: The Explicit Client of the Inventory Application

/* FILE NAME: client.c */

/******* Client of the inventory application with explicit method ***********/

#include <stdio.h>

#include <stdlib.h>

#include "inv.h" /* header file created by the IDL compiler */

# include "status.h"

char instructions[] = "Type character followed by appropriate argument(s).\n\

Is part available? a

What is part name? n

Get part description. d

What is part price? p

What is part quantity? q What are subparts of this part? s

Order part. o

REDISPLAY r\n\

EXIT e\n";

[part_number]\n\ [part_number]\n\ [part_number]\n\ [part_number]\n\ [part_number]\n\ [part_number]\n\ part_number quantity\n\

main()

part_record part; part_list *subparts; account_num account = 1234; unsigned long status;

handle_t binding_h;

/* structure for all data about a part */

/* pointer to parts list data structure */

/* a user account number */

/* error status */

/* declare a binding handle */

int i, num_args, done = 0;

long result;

char input[100],. selection[20], quantity[20]

puts(instructions); part.number = 0; strcpy(quantity, "");

Mfndef LOCAL

do_import_binding ("' #endif

/* find server in name service database */

&binding_h);

status = RpcBindingReset(binding_h);

CHECK_STATUS(status, "Can't reset binding handle", ABORT);

while(!done) {

printf("Selection:

/* user makes selections and each is processed */ fflush(stdout); gets(input);

Microsoft RFC Programming Guide

Example D-15: The Explicit Client of the Inventory Application (continued)

num_args = sscanf(input, "%s%ld%s", selection, &(part.number), quantity);

switch (tolower(selection[0])) {

case 'a': if (is_part_available(binding_h, part.number))

puts("available: Yes"); else

puts("available: No"); break;

case 'n': whatis_part_name(binding_h, part.number, part.name); printf("name:%s\n", part.name); break; case 'd': part.description =

get_part_description(binding_h, part.number); printf("description:\n%s\n", part.description); if(part.description ! = NULL)

free(part.description); /* free memory allocated */ break;

case 'p': whatis_part_price(binding_h, part.number, &(part.price)); printf("price:%10.2f\n", part.price.per_unit); break;

case 'q': whatis_part_quantity (binding_h, part.number, &( part, quantity)) ; if(part.quantity.units == ITEM)

print f("total i terns:%ld\n", part.quant i ty.total.number); else if(part.quantity.units == GRAM)

printf("total grams:%10.2f\n", part.quantity.total.weight); else if(part.quantity.units == KILOGRAM)

printf("total kilos:%10.2f\n", part.quantity.total.weight); break;

case 's': whatare_subparts(binding_h, part.number, &subparts); for(i =0; i < subparts->size; i++)

printf("%ld ", subparts->numbers[i]);

printf("\ntotal number of subparts:%ld\n", subparts->size); free(subparts); /* free memory for conformant struct */ break; case 'o': if(num_args < 3) {

puts("Not enough arguments"); break;

/* Assume KILOGRAM units and assign quantity input */ part.quantity.units = KILOGRAM; part.quantity.total.weight = atof(quantity); result =

order_part(binding_h, part.number, &(part.quantity), account) if(result > 0) {

if(part.quantity.units == ITEM)

printf("order:%ld items\n", part.quantity.total.number); else if(part.quantity.units == GRAM)

printf("order:%10.2f grams\n", part.quantity.total.weight); else if(part.quantity.units == KILOGRAM)

printf("order:%10.2f kilos\n", part.quantity.total.weight);

else { /* error cases */

if(result == -1) puts("Invalid part number");

Example D-15: The Explicit Client of the Inventory Application (continued)

else if(result == -2) puts("Invalid quantity"); else if(result == -3) puts("Invalid account number"); }

break;

case 'r': /* redisplay selection or bad input displays instructions */ default: puts(instructions); break; case 'e': done = 1; break; } /*end case */ } /* end While */ } /* end main() */

^** *********************************************************************/

/*** MIDL_user_allocate / MIDL_user_free ***/

/***************** **********************^*^^£^^^^^£^^^^£^^^£. fc . fc . fr ^. Ar . fr . fr ^^,. fc . fr . fr . fr ^.

void * RPC API MIDL_user_allocate

size_t size;

unsigned char * ptr; ptr = malloc( size ); return ( (void *)ptr

}

void __RPC_API MIDL_user_free

ob j ect void * object;

free (object);

picture37

In this Appendix: How to Run the Application Application Files

picture38

The Rflle Application

The remote file client (rfile.c) copies ASCII data from the client to the server. The source can be a data file or the standard input of the client. The target on the server system is either a file or the server standard output. The rf ile application demonstrates some advanced features of RFC application development including:

• Using a context handle with a context rundown procedure.

• Using the explicit binding method with a primitive binding handle.

• Finding a server using strings of binding information.

How to Run the Application

To run the server of the distributed application, type the following:

C:\SERVER> nmake server C:\SERVER> server

To run the client of the distributed application to transfer ASCII data, use an ASCII text file as input and a new data file on the server host as output. Type the follow ing:

C:\CLIENT> nmake client

C:\CLIENT> client input_file host output_file

You can also send ASCII data from the client keyboard (stdin) by using the follow ing client command:

C:\CLIENT> client "" host output_file

Using stdin. Type input:

data

data

Microsoft RFC Programming Guide

Application Files

Makefile contains descriptions of how the application is compiled. Some files depend on the header file status. h from the arithmetic application for the CHECK_STATUS macro. See Example E-l.

rfile.idl contains descriptions of the data types and procedures for the interface. See Example E-2.

client, c interprets the user input by calling the application-specific procedure get_args. A binding handle representing the information about a client-server rela tionship is obtained from strings of binding information. The remote procedure remote_open is called to open the server target file. A buffer is allocated for a con formant array. The application loops, reading source data and sending the data to the target with a remote procedure call to remote_send. Finally, the remote proce dure remote_close is called to close the target file. See Example E-3.

getargs.c interprets the user input to obtain the name of a local client ASCII file of source data, the server host to use, and the server target file. See Example E-4.

strbind.c contains the do_string_binding procedure that shows how to find a server from strings of binding information. A host name or network address is input, and then combined with a generated protocol sequence to create a valid binding handle, which is returned as a parameter. See Example E-5.

crndwn.c is the implementation of a context rundown procedure. The server stub calls this procedure automatically if communication breaks between a client and the server which is maintaining context for the client. For this application, the con text is a file handle of a server data file. This context rundown procedure closes the file. See Example E-6.

manager.c is the implementation of the remote procedures defined in the rfile interface. See Example E-7.

sewer. c initializes the server with a series of runtime calls prior to servicing remote procedure calls. In this application, all available protocol sequences are registered. The server is not advertised in a name service database. The server's dynamic end-points are added to the server's local endpoint map. A client finds this server by constructing a string binding containing a protocol sequence and the host name or network address. See Example E-8.

Example E-l: The Makefile for the Remote File Application

# FILE NAME: Makefile

# Makefile for the remote file application #

# definitions for this make file #

APPL=rfile IDLCMD=midl NTRPCLIBS=rpcrt4 . lib rpcns4.1ib libcmt.lib kerne!32.1ib

Appendix E: The Rflle Application

Example E- 1: The Makefile for the Remote File Application (continued)

# Include Windows NT macros ! include <ntwin32 .mak>

# NT c flags

cflags = -c -WO -Gz -D_X86_=1 -DWIN32 -DMT /nologo

# NT nmake inference rules

$(cc) $(cdebug) $ (cflags) $(cvarsmt) $< S(cvtocnf)

#

# COMPLETE BUILD of the application #

all: interface client.exe server.exe

#

# INTERFACE BUILD #

interface: $ (APPL) .h $ (APPL)_c.obj $ (APPL)_s.obj $ (APPL)_x.obj

#

# CLIENT BUILD #

client : client . exe

client.exe: client. obj getargs.obj strbind.obj $ (APPL)_c.obj $ (APPL)_x.obj $(link) $(linkdebug) $(conflags) -out: client. exe -map: client .map \

client. obj getargs.obj strbind.obj $ (APPL)_c.obj $ (APPL)_x.obj \

$(NTRPCLIBS)

#

# SERVER BUILD #

server : server . exe

server.exe: server. obj manager. obj crndwn.obj $ (APPL) _s. obj $ (APPL) _x. obj $(link) $(linkdebug) $(conflags) -out : server . exe -map: server. map \

server. obj manager. obj crndwn.obj $ (APPL) _s. obj $ (APPL) _x. obj \

$(NTRPCLIBS)

# client and server sources client. obj: client. c $(APPL).h manager . obj : manager . c $' (APPL ) . h server . obj : server . c $ (APPL ) . h crndwn.obj: crndwn.c $(APPL).h getargs . obj : getargs . c strbind . obj : strbind . c

# Local client sources Iclient.obj: client. c $(APPL).h

$(cc) $(cdebug) $ (cflags) $(cvarsmt) /DLOCAL \

/Fold ient. obj client. c Imanager . obj : manager . c $ (APPL ) . h

$(cc) $(cdebug) $ (cflags) $(cvarsmt) /DLOCAL \

/Folmanager . ob j manager. c

Example E-l: The Makefile for the Remote File Application (continued)

# client stubs $(APPL)_c.obj: $(APPL)_c.c $(APPL)_x.obj: $(APPL)_x.c

# compile the server stub $(APPL)_s.obj : $(APPL)_s.c

# generate stubs, auxiliary and header file from the IDL file $(APPL).h $(APPL)_c.c $(APPL)_x.c : $(APPL).idl

$(IDLCMD) $(APPL).idl

# clean up for fresh build clean:

del $(APPL)_?.c

del *.obj

del $(APPL).h

del *.map

del *.pdb

clobber: clean

if exist client.exe del client.exe if exist lclient.exe del lclient.exe if exist server.exe del server.exe

Example E-2: The MIDI File of the Remote File Application

/* FILE NAME: rfile.idl */ [

uuid(A6lE4024-A53F-101A-BlAF-08002B2E5B76), version(1.0), pointer_default(unique) ]

interface rfile /* file manipulation on a remote system */

{

typedef [context_handle] void *filehandle;

typedef byte buffer[];

filehandle remote_open( /* open for write */

[in] handle_t binding_h, /* explicit primitive binding handle */

[in, string] char name[], /* if name is null, use stdout in server */

[in, string] char mode[] /* values can be "r", "w", or "a" */

);

long remote_send(

[in] filehandle fh,

[in, max_is(max)] buffer buf,

[in] long max );

void remote_close(

[in,out] filehandle *fh

Example E~3: A Client File of the Remote File Application

/* FILE NAME: client. c */

Mnclude <stdio.h>

# include <stdlib.h>

#include <string.h>

#include "rfile.h"

#define MAX 200 /* maximum line length for a file */

main(argc, argv)

int argc;

char *argv [ ] ;

{

FILE *local_fh; /* file handle for client file input */

char host [100]; /* name or network address of remote host */ char remote_name[100] ; /* name of remote file */

rpc_binding_handle_t binding_h; /* binding handle */

filehandle remote_fh; /* context handle */

buffer *buf_ptr; /* buffer pointer for data sent */

int size; /* size of data buffer */

get_args(argc, argv, &local_fh, host, (char *)remote_name) ; #ifndef LOCAL

if (do_string_binding(host, &binding_h) < 0) {

fprintf (stderr, "Cannot get binding\n" ) ;

exit(l); } #endif

remote_fh = remote_open(binding_h, remote_name, (char *)"w"); if (remote_fh == NULL) {

fprintf (stderr, "Cannot open remote file\n");

exit(l) ; }

/* The buffer data type is a conformant array of bytes; */ /* memory must be allocated for a conformant array. */ buf_ptr = (buffer *)malloc( (MAX+1) * sizeof (buffer) );

while( fgets((char *)buf_ptr, MAX, local_fh) != NULL) {

size = ( int )strlen( (char *)buf_ptr); /* data sent will not include \0 */ if( remote_send(remote_fh, (*buf_ptr), size) < 1) {

fprintf (stderr, "Cannot write to remote file\n");

exit(l) ;

remote_close(&remote_fh) ; }

Example E-4-. The get_args Procedure

/* FILE NAME: getargs.c */ ttinclude <stdio.h> #include <stdlib.h> #include <string.h>

get_args(argc, argv, local_fh, host, remote_name) int argc ;

Microsoft RFC Programming Guide

Example E-4-. The get_args Procedure (continued)

char *argv[] ; FILE **local_fh; char host [ ] ; char remote_name [ ] ; {

char local_name[100] ;

switch (argc) { case 1:

case 2: printf ("Usage: %s [local_file] host [remote_f ile] \n" , argv[0]) puts ("Use \"\" for local stdin."); exit(O); break;

case 3: strcpy (local_nanie, argv[l]); /* use the same file name */ strcpy ( remote_name , local_name ) ; strcpy (host , argv [2 ] ) ; break;

default : strcpy ( local_name , argv [ 1 ] ) ; strcpy (host , argv [2 ] ) ; strcpy ( remote_name , argv [ 3 ] ) ; break; }

if (strlen(local_name) ==0) { (*local_fh) = stdin; puts ("Using stdin. Type input:"); } else

if( ( (*local_fh) = fopen(local_name, "r")) == NULL ) { puts ("Cannot open local file"); exit ( 1 ) ; } return;

Example E-5: The do_string_binding Procedure

/* FILE NAME: strbind.c */

/* Find a server binding handle from strings of binding information */

/* including protocol sequence, host address, and server process endpoint. */

ttinclude <stdio.h>

#include "rfile.h"

ttinclude " status. h" /* contains the CHECK_STATUS macro */

int do_string_binding(host, binding_h) /*return=0 if binding valid, else -1 */ char host[]; /* server host name or network address input */

rpc_binding_handle_t *binding_h; /* binding handle is output */

{

RPC_PROTSEQ_VECTOR *protseq_vector; /* protocol sequence list */ unsigned char *string_binding; /* string of binding information */ unsigned long status; /* error status */

int i , result ;

status =

RpcNetworklnqProtseqs ( /* obtain a list of valid protocol sequences */ &protseq_vector /* list of protocol sequences obtained */

Example E-5: The do_string_binding Procedure (continued)

);

CHECK_STATUS(status, "Can't get protocol sequences:", ABORT);

/* loop through protocol sequences until a binding handle is obtained */ for(i=0; i < protseq_yector->Count; i++) {

status =

RpcStringBindingCompose( /* make string binding from components */

NULL, /* no object UUIDs are required */

protseq_vector->Protseq[i], /* protocol sequence */

(unsigned char *)host, /* host name or network address */

NULL, /* no endpoint is required */

NULL, /* no network options are required */

&string_binding /* the constructed string binding */

);

CHECK_STATUS(status, "Can't compose a string binding:", RESUME);

status =

RpcBindingFromStringBinding( /* convert string to binding handle */

string_binding, /* input string binding */

binding_h /* binding handle is obtained here */

);

CHECK_STATUS(status, "Can't get binding handle from string:", RESUME); if(status != RPC_S_OK) {

result = -1;

CHECK_STATUS(status, "Can't get binding handle from string:", RESUME); } else

result = 0;

status =

RpcStringFree( /* free string binding created */

&string_binding );

CHECK_STATUS(status, "Can't free string binding:", RESUME); if(result == 0) break; /* got a valid binding */

}

status =

RpcProtseqVectorFree( /* free the list of protocol sequences */

&prot seq_vector );

CHECK_STATUS(status, "Can't free protocol sequence vector:", RESUME); return(result); }

Example E-6: The Context Rundown of the Remote File Application

/* FILE NAME: crndwn.c */ #include <stdio.h> #include "rfile.h"

void filehandle_rundown(remote_fh)

filehandle remote_fh; /* the context handle is passed in */

{

fprintf(stderr, "Server executing context rundown\n");

Example E-6: The Context Rundown of the Remote File Application (continued)

if ( (FILE *)remote_fh != stdout )

f close ( (FILE *)remote_fh ) ; /* file is closed if client is gone */ remote_fh = NULL; /* must set context handle to NULL */

return; }

Example E- 7: Remote Procedures of the Remote File Application

I* FILE NAME: manager. c */

# include <stdio.h> #include <string.h>

# include <io.h>

# include <errno.h> ttinclude "rfile.h"

filehandle remote_open(binding_h, name, mode)

rpc_binding_handle_t binding_h;

char name t ] ;

char mode [ ] ;

{

FILE *FILEh;

if (strlen( (char *)name) == 0) /* no file name given */

if (strcmp( (char *)mode, "r") == 0)

FILEh = NULL; /* cannot read nonexistent file */

else FILEh = stdout; /* use server stdout */

else if (_access ( (char *)name, 0) == 0) /* file exists */

if (strcmp( (char *)mode, "w" ) == 0)

FILEh = NULL; /* do not overwrite existing file */

else FILEh = f open ((char *)name, (char *)mode) ; /* open read/append */

else /* file does not exist */

if (strcmp( (char *)mode, "r") == 0)

FILEh = NULL; /* cannot read nonexistent file */

else FILEh = f open ( (char *)name, (char *)mode); /* open write/append */

return( (filehandle) FILEh ); /* cast FILE handle to context handle */

long int remote_send(fh, buf, max)

filehandle fh;

buffer buf;

long int max;

{

/* write data to the file (context) , which is cast as a FILE pointer */

return( fwrite(buf, max, 1, fh) ) ;

void remote_close(fh)

filehandle *fh; /* the client stub needs the changed value upon return */

{

if( (FILE *) (*fh) != stdout ) f close ( (FILE *) (*fh) );

(*fh) = NULL; /* assign NULL to the context handle to free it */

Example E- 7: Remote Procedures of the Remote File Application (continued)

return;

}

Example E-8: Server Initialization of the Remote File Application

/* FILE NAME: server.c */

ttinclude <stdio.h>

#include "rfile.h" /* header created by the idl compiler */

#include "status.h" /* contains the CHECK_STATUS macro */

main ()

{

unsigned long status; /* error status */

rpc_binding_vector_t *binding_vector; /* binding handle list */

status = /* error status */

RpcServerRegisterlf( /* register interface with the RFC runtime */

rfile_vl_0_s_ifspec, /* handle for interface specification */

NULL,

NULL ); CHECK_STATUS(status, "Can't register interface", ABORT);

status =

RpcServerUseAllProtseqs( /* establish protocol sequences */

RPC_C_PROTSEO_MAX_REQS_DEFAULT, /* queue length for remote calls */ NULL /* no security descriptor */

);

CHECK_STATUS(status, "Can't establish protocol sequences", ABORT);

status =

RpcServerlnqBindings( /* get set of this server's binding handles */

&binding_vector ); CHECK_STATUS(status, "Can't get binding handles", ABORT);

status =

RpcEpRegister( /* add endpoint to local endpoint map */

rfile_vl_0_s_ifspec, /* handle for interface specification */

binding_yector, /* vector of server binding handles */

NULL, /* no object UUIDs to register */

(unsigned char *)"remote_file server" /* annotation (not required) */

);

CHECK_STATUS(status,' "Can't add endpoints to local endpoint map:", ABORT);

puts("Listening for remote procedure calls...");

RpcTryFinally

{

status =

RpcServerListen( /* listen for remote calls */

1, /* Minimum number of threads */

RPC_C_LISTEN_MAX_CALLS_DEFAULT, /* Maximum number of threads */ NULL ); CHECK_STATUS(status, "rpc listen failed:", RESUME);

Example E- 8: Server Initialization of the Remote File Application (continued)

RpcFinally {

puts ( "Removing endpoints from local endpoint map.");

status =

RpcEpUnregister ( /* remove endpoints from local endpoint map */ rfile_vl_0_s_ifspec, /* handle for interface specification */ binding_vector, /* vector of server binding handles */

NULL /* no object UUIDs to unregister */

);

CHECK_STATUS( status, "Can't remove endpoints from endpoint map:", RESUME);

status =

RpcBindingVectorFree ( /* free set of binding handles */

&binding_vector );

CHECK_STATUS ( status , "Can't free binding handles and vector", ABORT); }

RpcEndFinally }

/*** MIDL_user_al locate / MIDL_user_free ***/

void * __RPC_API MIDL_user_al locate

size_t size; {

unsigned char * ptr; ptr = malloc ( size ) ; return ( (void *)ptr

void __RPC_API MIDL_user_free (

object )

void * object; {

free (object) ;

In this Appendix:

• How to Build and Run the Application

• Application Files

picture39

The Windows Phonebook Application

The phonebook application demonstrates a simple Windows client interface to a Microsoft RFC application. The Windows client looks up names in a phonebook database file maintained by the phonebook server (phnbkd.exe). The client does not use the Microsoft Locator name service, so you need to supply the server host name or address to a dialog box in the client interface.

How to Build and Run the Application

To build and run the server of the distributed application, type the following:

C:\SERVER> nmake phnbkd.exe C:\SERVER> phiibkd

To build and run the Windows client of the distributed application, type the fol lowing:

C:\CLIENT> nmake phnbk.exe C:\CLIENT> phnbk

Enter a hostname or address into the Server Host Name dialog box. Try the browse feature first to see some names. Then enter names into the Search String dialog box.

Application Files

Makefile contains descriptions of how the application is compiled. See Example F-l.

phnbk.idl contains descriptions of the data types and procedures for the interface. See Example F-2.

pbnbk.acf is an attribute configuration file that specifies implicit binding as the client binding method. See Example F-3.

wclient.c provides a Windows user interface to the server (phnbkd.exe). The client invokes remote procedure calls based on user actions. See Example F-4.

wpbnbk.defis a Windows module definition file. It defines the name of the appli cation, the type of image to be produced, and other attributes of the application. See Example F-5.

wphnbk.h is a header file that defines constants used in wphnbk.c and in the resource file wpbnbk.rc. See Example F-6.

wphnbk.rc is a Windows resource file. It describes the size and appearance of the Windows dialog box and of the controls (such as buttons and edit boxes) used by the application. See Example F-7.

manager, c is the implementation of the remote procedures defined in the phnbk interface. The remote procedures look up names contained in the phnbk.txt database file. See Example F-8.

server.c initializes the server with a series of runtime calls prior to servicing remote procedure calls. This application specifies to use the TCP/IP protocol sequence. The server is not advertised in a name service database. The server's dynamic end-points are added to the server's local endpoint map. A client finds this server by constructing a string binding containing a protocol sequence and the host name or network address. See Example F-9.

phnbk.txt is an ASCII file containing the database of names used by the phonebook server. We created it using a text editor. You can add your own lines to this file. Make sure lines are under 100 characters in length. See Example F-10.

Example F-l: The Makefile for the Windows Phonebook Application

# #

# Build phnbk client and server for Windows NT #

#

!INCLUDE <ntwin32.mak>

includes = -I.

all : phnbk.exe phnbkd.exe

#

# Link simple client #

phnbk.exe: wclient.obj wphnbk.obj phnbk_c.obj

$(link) $(linkdebug) $(guiflags) -out:phnbk.exe \ wclient.obj phnbk_c.obj wphnbk.obj \ rpcrt4.1ib rpcns4.1ib rpcndr.lib $(guilibs)

Example F-l: The Makefile for the Windows Phonebook Application (continued)

# Link server

#

phnbkd.exe: server.obj manager.obj phnbk_s.obj

$(link) $(linkdebug) $(conflags) -out:phnbkd.exe \

server.obj manager.obj phnbk_s.obj \

rpcrt4.1ib rpcns4.1ib rpcndr.lib $(conlibs) #

# .RES #

wphnbk.obj: wphnbk.re

re -r wphnbk.re

cvtres -$(CPU) wphnbk.res #

# Compile simple client source code

# .

wclient.obj: wclient.c phnbk.h

$(cc) $(cflags) $(cvars) $(scall) $(includes) wclient.c

#

# Compile server source code #

server.obj: server.c phnbk.h

$(cc) $(cflags) $(cvars) $(scall) $(includes) server.c

manager.obj: manager.c phnbk.h

$(cc) $(cflags) $(cvars) $(scall) $(includes) manager.c

#

# Compile client stubs #

phnbk_c.obj : phnbk_c.c phnbk.h

$(cc) $(cflags) $(cvars) $(scall) $(includes) phnbk_c.c

##

# $(cc) $(cflags) $(cvars) $(scall) $(includes) phnbk_x.c

#

# Compile server stubs #

phnbk_s.obj : phnbk_s.c

$(cc) $(cflags) $(cvars) $(scall) $(includes) phnbk_s.c

#phnbk_v.obj : phnbk_y.c

# $(cc) $(cflags) $(cvars) $(scall) $(includes) phnbk_y.c

#

# Generate stubs and header file from interface definition #

phnbk.h : phnbk.idl phnbk.acf midl phnbk.idl

#

# Clean up for fresh build

# clean :

Microsoft RFC Programming Guide

Example F-l: The Makefile for the Windows Phonebook Application (continued)

del phnbk_*.* del *.obj del phribk.h

#

# Clean up all byproducts of build

#

clobber : clean

del phnbk.exe

del phnbkd.exe

del *.res

Example F-2: The MIDI File of the Windows Phonebook Application

/*

** Interface definition file for irrplicit phnbk client

*/

uuid(F2FE85AO-OC28-1068-A726-AA0004007EFF) ,

version (1.0) ,

pointer_default (ref ) ] interface phnbk {

/*

** Constant for maximum line size */ const long LINESIZE = 100;

/*

** Flag for hitting end of phonebook file

*/

const short END = -1;

/*

** Flag for normal completion of operation

*/

const short NORMAL = 0;

/*

** Define all possible operations on phonebook file */

typedef enum {

FIRSTMATCH,

NEXTMATCH,

BROWSE,

RESET,

BROWSE_RESET } operations;

/*

** Perform some operation on the phonebook

*/

short

lookup

Example F-2: The MIDI File of the Windows Phonebook Application (continued)

(

[in] short operation,

[in,string] char search_string[LINESIZE], [out,string] char return_string[LINESIZE] ); }

Example F~3: The ACF File of the Windows Phonebook Application

[inplicit_handle (handle_t xhandle)] interface phnbk {}

Example F-4: Client File of the Windows Phonebook Application

/* **

**

** MODULE: wclient.c

** PROGRAM: Windows wphnbk application **

**

** **

*/

ttinclude <windows.h> ttinclude <stdlib.h> #include <string.h> #include <ctype.h>

Mnclude "phnbk.h" #include "wphnbk.h"

int lookup_status; /* lookup return status */

error_status_t status; /* rpc status */

unsigned char input[LINESIZE]; /* 'find' search string */

char output[LINESIZE]; /* string returned from database */

char oldmatch[LINESIZE];/* previous 'find' string */

unsigned char server[80]; /* string binding for server */

short operation; /* operation requested */

short no_handle; /* handle not initialized flag */

unsigned char hostname[32]; /* phnbk server host name */

long FAR PASCAL WndProc (HWND, WORD, WDRD, LONG) ;

int

PASCAL WinMain

(

HANDLE hlnstance,

HANDLE hPrevInstance,

LPSTR IpszCmdLine,

int nCmdShow

Microsoft RFC Programming Guide

Example F-4: Client File of the Windows Phonebook Application (continued)

char szAppName [] = "WPHNBK" HWND hwnd ;

MSG msg;

WNDCLASS wndclass ;

/*

** Initialize strings

*/

input[0]

output[0]

oldmatch[0] =

server[0] =

hostname[0] =

no_handle = TRUE;

/*

** Standard Windows stuff.

*/

if (IhPrevInstance)

wndclass wndclass wndclass wndclass wndclass . wndclass . wndclass . wndclass . wndclass . wndclass .

style

IpfnWndProc

cbClsExtra

cbWndExtra

hlnstance

hlcon

hCursor

hbrBackground

IpszMenuName

IpszClassName

CS_HREDRAW I CS_VREDRAW; (WNDPROC) WndProc ;

= 0

DLGWINDOWEXTRA ; hlnstance ;

Loadlcon (hlnstance, szAppName) ; LoadCursor ( (HINSTANCE)NULL, IDC_ARRCW) (HBRUSH) (COLORJWINDOW + 1) ; NULL ; szAppName ;

RegisterClass (&wndclass) ;

hwnd = CreateDialog (hlnstance, szAppName, 0, NULL)

ShowWindow (hwnd, nCmdShow) ;

SetFocus ( GetDlgltem (hwnd, HOSTNAMEBOX ) );

/ *

** Start accepting messages

*/

while ( GetMessage (&msg, NULL, 0, 0) )

TranslateMessage (&msg) ; DispatchMessage (&msg) ;

return msg.wParam ;

short InitHandle

HWND hwnd

Example F-4: Client File of the Windows Phonebook Application (continued)

I*

** Read server host name

*/

GetDlgltemText (hwnd, HOSTTSIAMEBOX, hostname, 16 ) ;

/*

** Warn user if they haven't specified a host name */

if (hostname [0] == '\0') {

MessageBox (

hwnd,

"Please enter server host name", "ERROR", MB_OK );

SetFocus ( GetDlgltem (hwnd, HOSTOAMEBOX) ) ; return (-1) ;

/*

** Build server string binding */

strcat (server, "ncacn_ip_tcp: " ) ; strcat (server, hostname) ; /*

** Convert the character string binding into an RFC handle */

status = RpcBindingFromStringBinding (

server,

&xhandle

if (status) { MessageBox

hwnd,

"Invalid string binding",

"ERROR",

MB_OK

exit (EXIT_FAILURE) ; }

no_handle = FALSE; return (0);

Example F-4-. Client File of the Windows Phonebook Application (continued)

void ShowResult

HWND hwnd ) {

/*

** Display lookup results, based on the context of

** the requested operation

*/

if (operation == BROWSE)

/*

** BROWSE — return next entry

*/

if (lookup_status == NORMAL)

/*

** Everything ok, display next entry

*/

SetDlgltemText (hwnd,RESULTSBOX,output); else

/*

** Otherwise, we hit end of file...

*/

SetDlgltemText (hwnd,RESULTSBOX,"");

SetDlgltemText (hwnd,INFOBOX,"No more entries");

else

/*

** Operation was a Find or Find Next. . .tailor message

** syntax to reflect the operation.

*/

if ( lookup_status == NORMAL)

{

/*

** Print results

*/

SetDlgltemText (hwnd, RESULTSBOX, output ) ;

/*

** Determine if this was first match, or subsequent match

*/

if (operation == FIRSTMATCH)

SetDlgltemText (hwnd, INFOBOX, "Match found" ) ; else

SetDlgltemText (hwnd, INFOBOX, "Another match found" ) ;

Example F- 4: Client File of the Windows Phonebook Application (continued)

else /*

** Hit end of file during search */ if (operation == FIRSTMATCH)

SetDlgltemText (hwnd, INFOBOX, "Match not found" ) ; else

SetDlgltemText (hwnd, INFOBOX, "No other matches found" ) ; }

return;

long

FAR PASCAL WndProc (

HWND hwnd, WORD message, WORD wParam, LONG iParam

/*

** We switch cursors to the hourglass during

** a lookup RPC. This is for saving the

** regular pointer.

*/

HCURSOR OldCursor;

/*

** First thing, save the match string from last time around

*/

strcpy (oldmatch, input) ;

/*

** Switch on the incoming message type (standard Windows

** programming)

*/

switch (message)

{

/*

** Got a button pushed

*/

case WM_COMMAND:

switch (wParam) {

/*

** Either a Find or a Find Next */

case FINDBUTTON: if (no_handle)

if (InitHandle(hwnd) ) break;

Example F- 4: Client File of the Windows Phonebook Application (continued)

/*

** Clear current text

*/

SetDlglterrtText (hwnd,RESULTSBOX, " " ) ;

SetDlgltemText (hwnd, HSJFOBOX, " " ) ;

/*

** Read the search string

*/

GetDlgltemText (hwnd, SEARCHBOX, input , 32 ) ;

/*

** Make sure user entered a search string */

if (input[0] == (unsigned char) '\0') {

MessageBox (

hwnd,

"Missing Search String!", "ERROR", MB_OK ); /*

** Set focus back to SEARCHBOX so user can ** enter search string */ SetFocus ( GetDlgltem (hwnd, SEARCHBOX) ) ;

else

/*

** Search string is present. Save existing

** pointer and display hourglass

*/

OldCursor = SetCursor (LoadCursor (NULL,IDC_WAIT)

ShowCursor (TRUE) ;

/*

** Determine desired operation

*/

if (strcmpfoldmatch, input) )

operation = FIRSTMATCH; else

operation = NEXTMATCH;

/*

** Perform the requested operation

*/

lookup_status = lookup

(

operation,

input ,

output

Example F-4: Client File of the Windows Phonebook Application (continued)

/*

** Restore pointer cursor

*/

ShowCursor (FALSE) ;

SetCursor ( OldCursor ) ;

/*

** Display lookup results

*/

ShowResult (hwnd) ;

break;

/*

** BROWSE — return next entry

*/

case BROWSEBUTTON:

if (no_handle)

i f ( Ini tHandle ( hwnd ) ) break ;

/*

** Clear existing text and display status

*/

SetDlgltemText (hwnd, RESULTSBOX, " " ) ;

SetDlgltemText (hwnd, SEARCHBOX, "" ) ;

SetDlgltemText (hwnd, INFOBOX, "Browsing. . . " ) ;

/*

** Switch to hourglass cursor

*/

OldCursor = SetCursor (LoadCursor (NULL,IDC_WAIT)

ShowCursor (TRUE) ;

operation = BROWSE;

/*

** Perform the requested operation

*/

lookup_status = lookup (

operation, input, output

/*

** Restore pointer cursor

*/

ShowCursor (FALSE) ;

SetCursor ( OldCursor ) ;

Example F- 4: Client File of the Windows Phonebook Application (continued)

** Display operation results

*/

ShowResult (hwnd) ;

break;

/* 1

** User has requested a RESET. This clears all

** text and rewinds the phonebook file

*/

case RESETBUTTON:

if (no_handle)

if (InitHandle(hwnd) ) break;

/*

** Clear all text

*/

SetDlgltemText (hwnd, RESULTSBOX, " " ) ;

SetDlglteinText (hwnd, INFOBOX, " " ) ;

SetDlgltemText (hwnd, SEARCHBOX, " " ) ;

input [0] = '\0'; operation = RESET;

/*

** Perform the requested operation

*/

lookup_status = lookup

(

operation,

input ,

output );

break;

return 0 ;

/*

** User has closed the application */

case WM_DESTROY: if (!no_handle) {

/*

** Free binding handle, post quit message and leave */

status = RpcBindingFree ( &xhandle

PostQuitMessage (0) ;

Example F-4: Client File of the Windows Phonebook Application (continued)

return 0 ;

/*

** Ignore other messages

*/

default :

return DefWindowProc (hwnd, message, wParam, iParam) ;

Example F-5: Window Module Definition File

; WPHNBK.DEF module definition file

NAME WPHNBK

DESCRIPTION 'Windows RFC Phonebook'

EXETYPE WINDOWS

STUB 'WINSTUB.EXE'

CODE PRELOAD FIXED DISCARDABLE

DATA PRELOAD FIXED MULTIPLE

HEAPSIZE 8192

STACKSIZE 8192

EXPORTS WndProc

Example F-6: Header File

#define SEARCHBOX 102 #define RESULTSBOX 104 #define INFOBOX 106 #define FINDBUTTON 113 #define BROWSEBUTTON 112 #define RESETBUTTON 110 ttdefine HOSTNAMEBOX 109

Example F- 7: Resource File

ttinclude <windows.h> #include "wphnbk.h"

WPHNBK DIALOG 15, 33, 315, 102

CAPTION "Windows RFC Phonebook"

STYLE WS_OVERLAPPED | WS_BORDER I WS_CAPTION I WS_SYSMENU I WS_MINIMIZEBOX

CLASS "WPHNBK"

BEGIN

CONTROL "Search String:", 100, "static", SS_LEFT I WS_CHILD, 13, 18, 47, 10

CONTROL "Input", 101, "button", BS_GROUPBOX I WS_TABSTOP I WS_CHILD,

5, 3, 173, 32

CONTROL "", 102, "edit", ES_LEFT I WS_BORDER I WSJTABSTOP I WS_CHILD,

63, 17, 108, 12

CONTROL "Search Results:", 103, "static", SS_LEFT | WS_CHILD,

6, 50, 58, 7

CONTROL "", 104, "edit", ES_LEFT | WS_BORDER | WS_TABSTOP I WS_CHILD,

64, 48, 239, 12

Example F- 7: Resource File (continued)

CONTROL "Status:", 105, "static", SS_LEFT I WS_CHILD, 6, 80, 26, 8 CONTROL "", 106, "edit", ES_LEFT I WS_BORDER I WSJTABSTOP I WS_CHILD,

30, 78, 133, 12 CONTROL "Output", 108, "button", BS_GROUPBOX I WS_TABSTOP I WS_CHILD,

4, 36, 305, 31 CONTROL "Information", 111, "button", BS_GROUPBOX I WS_TABSTOP I WS_CHILD,

4, 68, 305, 31 CONTROL "Find / Find Next", 113, "button",

BS_PUSHBUTTCN I WSJTABSTOP I WS_CHILD, 192, 6, 112, 14 CONTROL "Reset", 110, "button", BS_PUSHBUTTON I WS_TABSTOP I WS_CHILD,

192, 22, 50, 14 CONTROL "Browse", 112, "button", BS_PUSHBUTTCN I WS_TABSTOP I WS_CHILD,

258, 22, 46, 14 CONTROL "", HOSTNAMEBOX, "edit", ES_LEFT I WS_BORDER | WS_TABSTOP I WS_CHILD,

228, 78, 76, 12 CONTROL "Server Host Name:",107, "static", SS_LEFT I WS_CHILD,

166, 80, 62, 8 END

Example F-8: Remote Procedures

/* **

MODULE: manager.c

* PROGRAM: phnbk application

I **

** ** **

*/

#include <stdio.h> #include <string.h> ttinclude <malloc.h> #include <stdlib.h>

ttinclude "phnbk.h"

#ifdef WIN32 #endif

extern FILE *filehandle; /* Phonebook file filehandle */

extern short previous_operation; /* Keeps track of previous operation */

/*

**

** FUNCTION: getfileline **

** PURPOSE:

** Retrieve Lines from input file

Example F- 8: Remote Procedures (continued)

*/ int

getfileline (

line, phone )

unsigned char * line; FILE * phone; {

/*

** Each call of this routine returns a line of the

** phonebook file. On EOF, it returns -1.

*/

char ch;

while ((ch = fgetc (phone) ) != '\n' && ch != EOF) {

/*

** Tabs are unpredictable, so substitute ** three spaces if you run across a tab. . . */ if (ch == '\t')

{

*line++ = ' ' ;

*line++ = ' ' ;

*line++ = ' ' ;

} else

*line++ = ch;

*line++ = '\0' ;

if (ch == EOF)

return (END) ; else

return (NORMAL) ; }

/* **

** FUNCTION: lookup **

** PURPOSE:

Look up entries in database **

*/

short lookup (

op,

stringin,

Microsoft RFC Programming Guide

Example F-8: Remote Procedures (continued)

stringout )

short op;

unsigned char stringin[LINESIZE] ; unsigned char stringout [LUSESIZE] ; {

unsigned char buf [LINESIZE] ;

/*

** Switch on requested operation */

switch (op) { case RESET:

/*

** Reset context

*/

printf ( "Phonebook: \tRESET\n" ) ;

rewind (filehandle) ; previous_operation = FIRSTMATCH; return (NORMAL) ; break;

case FIRSTMATCH: /*

** Look for first match of a string, starting at the ** beginning of the file... */ printf ( "Phonebook: \tFIRSTMATCH\n" ) ;

rewind (filehandle) ; break;

case NEXTMATCH : /*

** Nothing special here, fall out and continue search */

printf ( "Phonebook: \tNEXTMATCH\n" ) ; break;

case BROWSE : /*

** A BROWSE operation just returns the next entry... **

** If the last operation was a BROWSE that got an EOF,

** then rewind and start cycling through again.

*/

printf ( "Phonebook: \tBROWSE\n" ) ;

if (previous_operation == BROWSE_RESET) rewind (filehandle);

Example F-8: Remote Procedures (continued)

if ((getfileline(buf,filehandle)) != -1) {

/*

** If not EOF, then just return next entry.

*/

strcpy ( ( char * ) stringout , ( char * ) buf ) ;

printf ("Phonebook: \tFound %s\n", buf); previous_operation = BROWSE;

return (NORMAL) ; }

else {

/*

** This allows the client to flag "no more entries" ** before cycling through the file again on ** another BROWSE request. */ previous_operation = BROWSE_RESET;

return (END) ;

/*

** Keep track of previous operation in p_context

*/

previous_operation = op;

/*

** Either return the line of the file that contains a string

** match, or return -1...

*/

while ( (getfileline(buf,filehandle) ) != -1) { if ( (strstrf (char *)buf, (char *)stringin)) != (char *) NULL)

{

printf ("Phonebook: \tFound %s\n" , buf);

strcpy' ( (char *) stringout, (char *)buf) ;

return (NORMAL) ;

return (END) ;

Example F-9: Server Initialization

/* **

**

** MODULE: server. c **

Example F-9: Server Initialization (continued) **

** PROGRAM: phribk application

**

**

**

**

**

*/

#include <stdio.h> #include <string.h> ttinclude <stdlib.h> #include <malloc.h>

#include "phnbk.h"

#ifdef WIN32

#define MAIN_DECL _CRTAPIl

#else

#define MAIN_DECL

#include <dce/rpcexc.h>

#endif

#define IFSPEC phnbk_vl_0_s_ifspec

FILE * filehandle; /* File handle used for phonebook file */

short previous_operation; /* Keeps track of previous phonebook operation */

int

MAIN_DECL main (

ac, av )

int ac; char *av[]; {

unsigned int i;

error_status_t status;

unsigned char *string_binding;

RPC_BINDING_VECTOR *bvec;

/*

**

** Specify TCP/IP as a protocol sequences

*/

status = RpcServerUseProtseq

(

"ncacn_ip_tcp",

5,

NULL );

if (status != RPC_S_OK)

Example F-9: Server Initialization (continued)

printf("No available protocol sequences \n ");

exit (EXIT_FAILURE) ;

}

/*

** register the server interface */

status = RpcServerRegisterlf (

IFSPEC, NULL, NULL );

if (status != RPC_S_OK) {

printf ("Can't register interface \n"); exit (EXIT_FAILURE) ;

}

/*

** find out what binding information is actually available

*/

status = RpcServerlnqBindings

( &bvec

);

if (status != RPC_S_OK) {

printf ("Can't inquire bindings \n"); exit (EXIT_FAILURE) ;

}

/*

** register with endpoint mapper */

status = RpcEpRegister (

IFSPEC,

bvec,

NULL,

(unsigned char *)"phnbk endpoint" );

if (status != RPC_S_OK) {

printf ("Can't register endpoint \n "); exit (EXIT_FAILURE) ;

** Get the string bindings and print them

*/

for (i = 0; i < bvec->Count; i++)

Example F-9: Server Initialization (continued)

** For each binding, convert it to a ** string representation */

status = RpcBindingToStringBinding (

bvec->BindingH [ i ] , &string_binding );

if (status != RPC_S_OK) {

print f ("Can't get string binding \n"); exit (EXIT_FAILURE) ; }

printf ( " %s\n" , string_binding) ; }

/*

** Open the phonebook file

*/

f ilehandle = f open ( "phnbk . txt " , " r " ) ;

/*

** Server is all ready to start listening for client

** requests. . .

*/

status = RpcServerListen

1, 2,

0

if (status != RPC_S_OK)

printf ( "Error: rpc_server_listen ( ) returned \n" ) ;

return (EXIT_FAILURE) ; } #ifdef WIN32

/*** MIDL_user_allocate / MIDL_user_free ***/

void * __RPC_API MIDL_user_allocate

size_t size; {

unsigned char * ptr;

Example F-9: Server Initialization (continued)

ptr = malloc( size ); return ( (void *)ptr );

void _RPC_API MIDL_user_free

object void * object;

free (object);

#endif

Example F-10: Sample Input Data

Mickey Mouse 555-2345

Donald Duck 555-2342

Pluto 555-4564

James T. Kirk 555-2342

Fred Flintstone 555-2342

Spider Man 555-2345

Bat Man 555-2342

George Jetson 555-2342

Peter Pan 555-4312

John Doe 555-8888

Charlie Brown 555-2374

[] (brackets) in MIDL, 30

ACF (attribute configuration file), 42-44

automatic binding, 49

binding handles, 53

binding methods, 48

controlling errors, 44

example of, 43

exceptions, 44

explicit binding, 53

implicit binding, 51, 176

separating client/server output, 42

windows phnbk application, 205

(see also binding methods) ACF attributes

autojiandle, 43, 48-49, 140

byte_count, 98

code, 44, 140

comm_status, 44, 140

context_handle, 139-140

dont_free, 98

explicit_handle, 43, 48, 53, 140

fault_status, 44, 140

implicit_handle, 43-44, 48, 51, 140

nocode, 44, 140

(see also MIDL attributes) active context handles (see context handles) address, host network, 104 advertising the server, 107-109 aliasing, pointer, 83, 87

allocating memory

buffers, 97-98

for conformant arrays, 93-94

for context handles, 135

freeing, 87

inventory application, 158

node-by-node, 96-97

(see also memory management) applications

arithmetic, 3, 149-156

distributed, 149

files, 150-156

inventory, 30, 157-189

managing, routines for, 145, 147

memory management, 96

producing and running, 21-24

rfile, 129, 191-200 arith.bat, 150 arith.idl, 150 arithmetic application, 3, 149-156

CHECK_STATUS macro, 155

client file, 153

initialization, 153

interface, 152

Makefile, 150

remote procedure, 153

server shell script, 152 array attribute, 137-138 arrays, 34, 79, 90-94, 149

conformant, 90-94, 116-117 as procedure parameters, 93 managing size of, 91-94

223

Microsoft RFC Programming Guide

arrays, conformant (cont'd)

memory allocation, 93-94

fixed, 34, 90

limiting transmission of, 34

max_is, 35

MIDI attributes of, 137-138

size_is, 35

specifying size of, 91-93

varying, 90-91

attribute configuration file (see ACF) attributes

ACF (see ACF attributes)

array, 137-138

binding methods, 48

data, 30-38, 139

dont_free, 98

header, 29, 137

interface definition, 28

MIDI (see MIDL attributes)

pointer types, 138

procedure, 139-140

structure member, 139

union case, 139 authentication, 71

binding information, 47

managing, routines for, 43, 147 authorization information, 47 automatic binding, 49-50

finding server, 122

(see also binding methods) autojiandle attribute, 43, 48-49, 140 auxiliary files, MIDL compiler, 41

bind procedure, 68-69 binding handles, 20, 45-70

bind/unbind procedures, 68-69 client, 113

context handles, 133 customized, 66-70

designing, 67 defining, 53-54 endpoints in, 59 fully bound, 59 importing, 61-63 looking up, 64 managing, 46-55

by clients, 47

routines for, 43, 144 partially bound, 59

server initialization, 112 binding information, 45-48

client authentication, 47

client, in server code, 113

context handles, 48

creating

for servers, 104-107 routines for, 43, 146

exporting, 20, 125-126

finding servers, 64-66

host network address, 104

in server entry, 123

interpreting, 60-61

inventory application, 158

NSI routines, 14

server endpoint map, 109

to name service, 108

with dynamic endpoints, 104-106, 123 binding methods, 13-17, 46-55

applying to interface(s), 47

attributes, 48

automatic, 46-50 finding server, 122 overriding, 50

choosing, 48-49

comparison of, 46

establishing, 48

explicit, 46, 52-55

implicit, 46-47, 50-52 and ACF, 51 overriding, 52

selecting with ACF, 43-44 BITFTP, xix

buffers, allocating, 97-98 byte_count attribute, 98

case keyword, 37

Cell Directory Service (CDS), 14, 121

char data type, 34

CHECK_STATUS macro, 73-74, 104, 150, 155

client files, generating, 42

/client none, MIDL compiler, 42

client.c, 150

clients

allocating buffers in, 97-98

authentication information, 47

authorization information, 47

binding handles, 113

binding information, 113

225

clients (cont'd)

interpreting, 6l managing handles, 47

building, 149

compiling, 21-23, 74-77

context handles in, 131-133

copying text to server, 129

developing

for automatic binding, 49-50 for explicit binding, 54 for implicit binding, 51-52

development, errors in, 72-74

example of, 9

exception handling, 72

finding from strings, 64-66

inventory application file, 172

linking, 21-23, 74-77

managing, routines for, 43, 145

of arithmetic application, 152

phonebook application, 205

producing, 74

protocol sequences for, 58

rfile applications, 195

server communication break, 134, 136

using discriminated unions, 38

using name service, 6l

writing, 45-77

(see also servers) close_inventory procedure, 111 code attribute, 44, 140 communication breakdown, client/server,

134, 136

comm_status attribute, 44, 140 compiler, MIDL (see MIDL compiler) compiling

clients, 21-23, 74-77

interfaces, 40-42

of interface definition, 7

servers, 21-23, 117-119 CompuServe, xvi conformant arrays, 34, 90

allocating memory, 93-94, 116-117 dynamic, 93

as procedure parameters, 93

managing size of, 91-94

MIDL attributes, 138 conformant strings, 34-35 conformant structure, 92, 94 const keyword, 33

constants, MIDL file, 33 context handles, 48, 129-136

active, 129, 134

allocating memory for, 135

establishing active, 132

freeing, 133, 135

in clients, 131-133

in interface definition, 130-131

in servers, 133-136

opaque structure, 131

with binding methods, 132

writing procedures with, 134-135 context rundown procedures, 130, 197

writing, 136 context storage, 98

context_handle attribute, 130, 139-140 contiguous server memory, 97 conventions for entry names, 23 crndwn.c, 192 customizing

binding handles, 66-70

interface with ACF, 42-44

data

describing with MIDL attributes, 28

limiting transmission, 34

marshalling, 32

privacy/integrity (see authentication)

sharing between formats, 32

structures. 101-102 data attributes, MIDL, 30-38

user-defined, 33 datatypes, 139, 150

DCE Cell Directory Service (CDS), 107, 121 debugging remote procedures, 76 DECnet, protocols with, 56 DefaultEntry, 63 directory service, 14 discriminated unions, 36-38

application code example, 37

pointers as, 89 distributed applications, 149 do_import_binding, 54, 60, 62, 159, 178 do_interpret_binding, 60, 63, 159, 179 domain controllers, 126-127 dont_free attribute, 98 do_string_binding, 64, 68, 132, 196 dynamic endpoints, 59-60, 110

exporting, 108

Microsoft RFC Programming Guide

dynamic endpoints (cont'd)

in binding information, 104-106, 123

endpoint attribute, 106, 137 endpoint map

local, 15

system, 109-110, 112 endpoints

dynamic, 104-106

exporting, 108

finding, 59-60

managing

in server, 109-110, 112 routines for, 43, 144, 146

server process, 14

well-known, 106-107

with client call requests, 100 entry names, conventions, 23 enum keyword, 35 enumerated types, 35 errors, 155

ACF control, 44

handling, 72-74

reporting, routines for, 102

(see also exceptions) error_status_t, 73, 140

data type, 31, 44 exceptions

ACF, 44

as parameters, 141

handling, 43, 72-74 routines for, 145, 147

listening for RPCs, 111-112

(see also errors) explicit binding, 52-55

inventory application, 180

MIDI file, 182

remote procedures, 184

(see also binding methods) explicitjiandle attribute, 43, 48, 53, 140 exporting

binding information, 20, 125-126

endpoints, 108

servers to name service, 147

fault_status attribute, 44, 140 filehandle_rundown procedure, 136 finding servers, 13, 55-66 with name service, 61-64

nrst_is attribute, 90, 138

fixed arrays, 34, 90

floating-point numbers (see discriminated

unions)

free routine, 113 FTP (file transfer program), xviii FTPMAIL, xix

full pointers, 33, 80, 86-90, 140 fully bound binding handle, 59

get_args, 131, 195 getargs.c, 192 getbind.c, 62

get_part_description, 115, 158 group entries, RFC, 107

handle attribute, 66, 139 handles

binding (see binding handles)

context (see context handles)

interface (see interfaces, handles) handle_t data type, 31, 43, 51, 53 handling

errors (exceptions), 72-74, 145 inventory application, 158

exceptions, 111-112 header

attributes, 137 interface, 29-30

files, 101-102

generating a, 7 header files, 102 host network address, 104

/I option, MIDL compiler, 42

IDL (Interface Definition Language), 4

(see also MIDL) if spec, 103 ignore attribute, 139 implicit binding, 50-52

ACF file for, 176

(see also binding methods) implicitjiandle, 43-44, 48, 51, 140 in attribute, 38-40, 140 indirection, multiple levels of, 84 initializing

arithmetic application, 153

context handles, 132

inventory application, 169

227

initializing (cont'd)

servers, 15, 18-19, 99-112

advertising, 107-109

creating binding information, 104-107

header files, 101-102

listening for RPCs, 110-112

managing endpoints, 109-110, 112

registering interfaces, 102-104 input parameters, pointers as, 82-84 intbind.c, 61

interface definition, 4-7, 27-44 attributes, 28 binding methods, 48 compiling, 7

declaring varying array, 90 defining conformant arrays, 91 defining context handles, 130-131 definition of, 4 explicit binding and, 52 generating UUID in, 6 inventory application, 157 language (IDL), 4 specifying array size in, 91-93 structure of, 29 template for, 6 interfaces

applying binding methods, 47

array attributes, 137

attributes of procedure parameters, 139

compiling, 40-42

customizing with ACF, 42-44

data type attributes, 139

data types, 150

defining binding handle, 54

defining strings in, 34

definition of, 2

developing

for automatic binding, 49

for explicit binding, 53-54

for implicit binding, 51 handles, 19, 103 header attributes, 29-30, 137 identifying (naming), 30, 123 information management routines, 43,

145-146

inventory application, 161 pointer type attributes, 138 procedure attributes, 140 registering, 102-104

simple, 4

specification, client call, 100

structure member attributes, 139

union case attributes, 139 international character types, 31 Internet, protocols with, 56-57 inv.h, 101 inventory application, 30, 157-189

ACF file, 176

automatic binding, 172

do_import_binding, 178

do_interpret_binding, 179

explicit binding, 183

how to run, 158

inventory implementation, 166

Makefile, 160, 174

MIDL file of, 161

remote procedures, 163, 184

server, 169 invntry.c, 159 ISO_LATIN_1, 31 ISO_MULTI_LINGUAL, 31 ISOJJCS, 31

LAN for protocol sequences, 58 last_is attribute, 90, 138 length_is attribute, 90, 138 levels of indirection, 84 libraries for Microsoft RFC, 21 linked lists, 95 linking

clients, 21-23, 74-77

servers, 21-23, 117-119 listening for RPCs, 110-112 local attribute, 137 local endpoint map, 15 local RFC (ncalrpc transport), 58 LOCAL symbol, 132 locating servers, 13, 55-66

with name service, 61-64 Locator (see Microsoft Locator) long integers (see discriminated unions)

maintaining context, 129-136

in servers, 133-136 Makefile, 150, 159-160, 192

implicit client, 174

Windows phnbk application, 202 malloc, 113, 135

Microsoft RFC Programming Guide

manager code (see remote procedures) manager, c, 150

max_is attribute, 35, 91-93, 138 memory management, 94-98 allocating

buffers, 97-98

for conformant arrays, 93-94 conformant arrays, 116-117 context handle, 135 contiguous server, 97 in remote procedures, 112-115 inventory application, 158 node-by-node allocation, 96-97 persistent storage, 98 routines for, 145, 147 Microsoft Locator, 14, 52, 126-127 group operations, 108 (see also name service) Microsoft RFC, 46

libraries, 21

Microsoft Windows NT, 97 MIDL (Microsoft Interface Definition Lan guage)

arithmetic application, 152 brackets in, 30 constants, 33 data types, 30-38

arrays, 34

denning new, 33

discriminated unions, 36-38

enumerated types, 35

international, 31

pointers, 33

strings, 34-35

structures, 35-36

void, 40

default names, 103 definition of, 4

file of, phonebook application, 204 generating template, 6 handle_t data type, 51 naming an interface, 30 /oldnames option, 103 parameter attributes, 38-40 pointers (see pointers) procedure declarations, 27, 38-40 rfile application, file of, 194 type definitions, 30-38 MIDL attributes, 28

array, 137-138

context_handle, 130, 139-140

data type, 139

endpoint, 106, 137

first_is, 90, 138

handle, 66, 139

in, 38-40, 140

interface header, 137 interface keyword, 30

last_is, 90, 138

length_is, 90, 138

local, 137

max_is, 35, 91-93, 138

out, 38-40, 140

pointer_default, 30, 137

pointer types, 138

procedure parameter, 139-140

ptr, 140

ref, 33, 138

size_is, 35, 91-93, 138

string, 34, 138, 140

structure member, 139

transmit_as, 139

union case, 139

unique, 33, 138, 140

uuid, 30, 137

version, 30, 103, 137

(see also ACF attributes) MIDL compiler, 7-21, 40-42, 141

auxiliary files, 41 client, 74

/client none option, 42

generating client/server files, 42

/I option, 42

inv.h, 101

/out option, 42

/server none option, 42

specifying ACF, 43

stub files, 41

midl_user_allocate, 19, 95, 113-115, 135 midl_user_free, 19, 95, 113-115 multi-threaded RFC, 48 multiple levels of indirection, 84

name service, 46, 50-54, 56, 121-127 advertising servers, 107 definition of, 14 entries, 122 finding servers, 61-64

229

name service (cont'd)

importing from, 61-63

independent (NSI) routines, 14

managing, routines for, 144-147

names in, 122

selecting binding handles, 64

server entries, 123-126 named pipe (np transport), 58 nbase.h, 102

ncacn_dnet_nsp protocol, 56 ncacn_ip_tcp protocol, 56 ncacn_nb_nb protocol, 57 ncacn_nb_tcp protocol, 57 ncacn_np protocol, 57 ncacn_spx protocol, 57 ncadg_ip_udp protocol, 56 ncalrpc protocol, 57 ncalrpc transport (local RFC), 58 NetBEUI transport, 57 NetBEUI, NCA connection using, 56 NetBIOS, NCA connection using, 56 network

address

finding, 58-59 host, 104

RFC binding, 14

services protocol (nsp), 57 Network Computing Architecture (NCA),

56-57

Network Data Representation (NDR), 32 nocode attribute, 44, 140 node-by-node allocation, 96-97 np transport (named pipe), 58 NSI (name service independent) routines, 14 nsp (network services protocol), 57 null pointers, 80, 83

object types, managing, 43, 147 opaque structure, 100, 131 open_inventory procedure, 109 out attribute, 38-40, 140 /out option, MIDL compiler, 42 outdated endpoints (see endpoints, manag ing) output parameters, pointers as, 80-82

parameter attributes, 38-40 partially bound binding handle, 59

pass by

reference, 7

value, 38

persistent memory storage, 98 phnbk.txt, 202 phonebook (phnbk) application, 201-221

ACF file, 205

client file, 205

header file, 213

input, 221

Makefile, 202

MIDL file of, 204

remote procedures, 214

resource file, 213

server, 217

window module definitions, 213 pipes, NCA connection using, 56 pointer attributes, 80, 86 pointer_default attribute, 30, 85, 137 pointers, 33

aliasing, 83, 87

as input parameters, 82-84

as output parameters, 80-82

as procedure return values, 86-87

default, 85, 89

definition of, 79

differentiating between, 87-90

full. 33. 80, 86-90. 140

interface handles, 103

managing, 87-90

in remote procedures, 113-115

MIDL attributes, 138

multiple, 89

multiple levels of indirection, 84

null, 80, 83

reference, 80, 114, 138

server context handles, 133

to other pointers, 84-86

to strings, 138

unique, 80, 83, 114-115, 138 privacy, data, 71 procedures

conformant arrays as parameters, 93

context rundown (see context rundown procedures)

declaration, 27, 38-40 contents of, 4

excluding unused, 44

parameter attributes, 139-140

Microsoft RFC Programming Guide

procedures (cont'd)

remote (see remote procedures)

returning pointers, 86-87

with context handles, 134-135 protocol sequences, 56

definition of, 14

finding, 56-58

inventory application, 158

LAN for, 58

RFC routines, 43, 145

selecting at server initialization, 104-107

timeouts for, 58

WAN for, 58 protocol, selecting a, 58 ptr attribute, 140

queue, client request, 100

ref attribute, 33, 138

reference pointers, 33, 80, 84, 87-90, 114 registering server interfaces, 102-104 remote file applications (see rfile applica tions) remote procedures

calls, multi-threaded, 48

handling errors, 72-74

implementing, 11-12

inventory application, 163

managing memory in, 112-115

multiple implementations, 104

of arithmetic application, 153

phnbk application, 214

renaming in server code, 104

returning context handle, 130

rfile applications, 198

testing and debugging, 76

with binding handles, 133

with context handles, 133-135

writing, 112-117 remote_close RFC, 133 remote_open RFC, 132 remote_send RFC, 132 rfile applications, 129, 191-200

client, 195

context rundown procedures, 197

do_string_binding, 196

get_args, 195

how to run, 191

interface, 194

Makefile, 192

MIDL file, 194

remote procedures, 198

server, 199 RFC (remote procedure calls)

client binding information in, 113

finding servers, 55

group entries, naming, 107

handling, 99-101

(see also servers, initializing)

listening for, 110-112

multi-threaded, 48

runtime library

context runtime procedures, 136 handling client request, 100-101 registering server interfaces, 102 role of, 17

runtime routines, 143-147

interpreting binding information, 60 name service database, 61-64 reporting errors, 102 RpcBindingFree, 63, 66, 68-69 RpcBindingFromStringBinding, 56,

59-60, 66

RpcBindinglnqAuthClient, 71 RpcBindinglnqAuthlnfo, 71 RpcBindingReset function, 51 RpcBindingSetAuthlnfo, 71 RpcBindingToStringBinding, 61 RpcMgmtlnqComTimeout, 58 RpcMgmtSetComTimeout, 58 RpcNetworklnqProtseqs, 56, 66 RpcNsBindinglmport, 56, 58 RpcNsBindinglmportBegin, 63 RpcNsBindinglmportDone, 63 RpcNsBindinglmportNext, 63 RpcNsBindingLookup, 56, 58, 64 RpcNsBindingSelect, 64 RpcProtseqVectorFree, 66 RpcStringBindingCompose, 56, 59, 66 RpcStringBindingParse, 61 RpcStringFree, 6l, 66 vector data structure, 102

security, 71

(see also authentication)

selecting array portion, 90-91

service, server's, 106 rpc_binding_handle_t, 31, 53 RpcBindingVectorFree, 19, 110, 112

231

rpc_binding_vector_t, 102 RPC_C_NS_SYNTAX_DEFAULT, 63, 108 RPC_C_PROTSEQ_MAX_CALLS_DEFAULT,

105

rpcdce.h, 102

RpcEndExcept macro, 111-112 RpcEpRegister, 19, 106, 110 RpcEpUnregister, 110, 112 RpcExcept macro, 111-112 rpc.h, 102

RpcMgmtStopServerListening, 110 RpcNsBindingExport, 19, 108, 125 RpcNsBindingUnexport, 126 rpc_protseq_vector_t, 102 RpcServerAllProtseqlf, 110 RpcServerlnqBindings, 105, 112 RpcServerListen, 19, 110-113 RpcServerRegisterlf, 19, 104 RpcServerUseAllProtseqs, 105 RpcServerUseAUProtseqsIf, 106 RpcServerUseProtseq, 105 RpcServerUseProtseqEp, 106, 110 RpcServerUseProtseqlf, 106, 110 RpcTryExcept macro, 111-112 running applications (see applications)

search_spec_bind, 69 search_spec_unbind, 69 security, 71

selecting binding method (see binding meth ods) sequences, protocol (see protocol

sequences)

server entries, 123-126 creating, 125-126 naming, 124

server files, generatiJng, 42 /server none, MIDL compiler, 42 server.c, 150, 159 servers

advertising, 107-109 binding information

automatic, 50

client, 113

creating, 104-107

explicit, 55

implicit, 52

interpreting, 61

with binding handles, 133

building, 149

client communication break, 134, 136 compiling and linking, 21-23, 117-119 context handles, 133-135 contiguous memory, 97 copying text from clients, 129 data structures, 102 developing, 11

errors in, 72-74 endpoint map, 106 finding/locating, 13

from strings, 64-66

host, 58-59

particular, 45-66

with name service, 61-64 handling

client request, 100-101

exceptions, 72 header files, 102 initializing, 15, 18-19, 99-112, 153

data structures, 101-102

header files, 101-102

inventory application, 169

managing endpoints, 109-110, 112

rfile applications, 199

selecting protocol sequences, 104-107 listening for RPCs, 110-112 managing

context in, 133-136

routines for, 147 naming conventions, 107 naming multiple, 122 phnbk application, 217 producing, 117 registering interfaces, 102-104 remote procedure implementations, 99 stub auxiliary file, 117 using discriminated unions, 38 writing, 99-119 (see also clients) size_is attribute, 35, 91-93, 138 spx transport, 58 SPX, NCA connection using, 57 status.h, 74, 150 strbind.c, 192

string attribute, 34, 138, 140 strings, 34-35

pointers to, 138 struct keyword, 35

Microsoft RFC Programming Guide

structure members

attributes, 139

pointers as, 89 structures, 35-36 stubs

code for memory management, 96

data transmission, 32

definition of, 1

generating, 7

with MIDL compiler, 41

support routines, 113 sum_arrays, 11, 149 switch keyword, 37

tcp, 57

TCP/IP, protocols with, 56

testing remote procedures, 76

text variables (see strings)

threads

for processing client requests, 100

for RPCs, 112-113 timeouts, protocol sequences, 58 transmission control protocol, 57 transmit_as attribute, 139 transport protocol, 57

in RPC binding, 14 type definitions, MIDL, 30-38 typedef keyword, 33

unbind procedure, 68-69 union case attributes, 139 unique attribute. 33, 138, 140 unique pointers, 33, 80, 84, 87-90

allocating memory, 114-115 unsigned32 variable

reporting errors, RPC, 102 UUID (universal unique identifier)

definition of, 5

management routines for, 43, 144, 146 uuid attribute, 30, 137 uuidgen, use of, 5

varying arrays, 34, 90-91

declaring, 90

MIDL attributes, 138

selection portion of, 90-91 vectors, 102

version attribute, 30, 103, 137 version number, interface, 30

void data type, 40

WAN, protocol sequences, 58

wchar_t data type, 31

well-known endpoints, 59-60, 110, 137

creating binding information with, 106

exporting, 108

in binding information, 123

server binding information with, 106-107 whatare_subparts, 116, 158 Windows NT, Microsoft, 97

security, 71

Windows phonebook application, 201-221 wphnbk.def, 202 wphnbk.h, 202 wphnbk.rc, 202 writing

clients, 45-77

procedures, 134-135 remote, 112-117

servers, 99-119

About the Author

John Shirley is a consultant in the development of software and documentation, particularly in the field of distributed computing. He earned a B.A. from Alfred University with a dual major in mathematics and geology, an M.S. in geology from Miami University with a specialty in structural geology, and an M.S. in computer science from Pace University. John lives in Newtown, Connecticut.

Prior to consulting, John's career included six years in the oil industry as a geophys-icist and international explorationist. His work included the analysis of seismic data from New Zealand, Australia, Turkey, Norway, the Dominican Republic, Jamaica, and the United States. He also worked as a software engineer developing programs for scientific instrument manufacturers.

Ward Rosenberry is a technical writing consultant and author concentrating on distributed computing and computer networking technologies. Ward has distin guished himself writing about the Open Software Foundation's Distributed Computing Environment since 1989, when he helped write Digital Equipment Corporation's original DCE design documents. He has since co-authored two other O'Reilly books about distributed computing: Understanding DCE and Distributing Applications Across DCE and Windows NT. He continues his close DCE involvement designing and developing DCE information both at Digital and at OSF and now operates a consulting firm, Rosenberry Associates, in Chelmsford, Massachusetts.

Ward graduated from the University of Lowell in 1979 with a B.A. in English. Ward, his wife Patricia Pestana, and their two children, William and John, live in North Chelmsford, Massachusetts.

Colophon

The animal on the cover of Microsoft RFC Programming Guide is a starfish, a marine invertebrate animal of the phylum Echinodermata, class Asteroidea. The approxi mately 1500 known living species of starfish are found throughout the world, at all ocean depths, and range in size from 1 cm to 68 cm wide. Most starfish have five arms, but can have as few as four or as many as 50.

Starfish are equipped with five double rows of outgrowths called tube feet. These tube feet, which are usually tipped with "suction cups," function in the respiratory process, enable the starfish to move, and are used to catch prey. The tube feet are connected via a water-vascular system unique to echinoderms. A ring canal in the disc-shaped body trunk connects to a radial canal in each arm, through which gaseous exchange takes place.

When a starfish needs to move, pressure in the water-vascular system causes the tube feet to become erect, lifting up the body. The tube feet then take small steps, moving the starfish slowly forward. One arm takes the lead in movement; when the direction changes, the lead shifts to another arm. Most of the time, however, starfish are sedentary creatures who prefer to stay anchored in one place. They will move to search for food, or if there is a change in external conditions.

The majority of starfish are predators, feeding on bivalves, crustaceans, and other echinoderms. By anchoring its arms on the sea floor, the starfish is able to use the suction pull of the tube feet to pry open the shells of bivalves. The starfish can then extrude its stomach through its mouth and into the tiny crevice of the bivalve shell, and begin the digestive process outside of its body.

Many species of starfish can reject an arm if it is injured in an attack. The body will generate a new arm, but this is a slow process that can take more than a year to complete. In a few speciess, the arm that has broken off will generate a body trunk and four new arms. At least one species of starfish eschews sexual reproduction in favor of this asexual mode, and has developed the ability to break off an arm at will.

Starfish usually reproduce by releasing eggs and sperm into the waves. The fertilized eggs form free-swimming larvae, although the female adult will provide some form of brood care in colder regions.

Edie Freedman designed the cover of this book, using a 19th-century engraving from the Dover Pictorial Archive. The cover layout was produced with Quark XPress 3.3 using the ITC Garamond font.

The inside layout was designed by Edie Freedman and Jennifer Niederst and imple mented in gtroff by Lenny Muellner. The text and heading fonts are ITC Garamond Light and Garamond Book. The illustrations that appear in the book were created in Aldus Freehand 4.0 by Chris Reilley. This colophon was written by Clairemarie Fisher O'Leary, with assistance from Kiersten Nauman.

picture40

FORM

Books from O'Reilly & Associates, Inc.

Fortran/Scientific Computing

Fall/Winter 1994-95

picture41

Migrating to Fortran 90

By James F. Kerrigan

1st Edition November 1993

389pages, ISBN 1-56592-049-X

Many Fortran programmers do not know where to start with Fortran 90. What is new about the language? How can it help them? How does a programmer with old habits learn new strategies?

This book is a practical guide to Fortran 90 for the current Fortran programmer. It provides a complete overview of the new features that Fortran 90 has brought to the Fortran standard, with examples and suggestions for use. The book discusses older ways of solving problems—both in FORTRAN 77 and in common tricks or extensions—and contrasts them with the new ways provided by Fortran 90.

The book has a practical focus, with the goal of getting the current Fortran programmer up to speed quickly. Two dozen examples of full programs are interspersed within the text, which includes over 4,000 lines of working code.

Topics include array sections, modules, file handling, allocatable arrays and pointers, and numeric precision. Two dozen examples of full programs are interspersed within the text, which includes over 4,000 lines of working code.

"This is a book that all Fortran programmers eager to take advantage of the excellent feature of Fortran 90 will want to have on their desk." — FORTRAN Journal

High Performance Computing

By Ketin Dou'd

1st Edition June 1993

398pages, ISBN 1-56592-032-5

picture42

HigT Performance Computing

High Performance Computing makes sense of the newest generation of work stations for application programmers and purchasing managers. It covers everything, from the basics of modern workstation architecture, to structuring benchmarks, to squeezing more perfor mance out of critical applications. It also explains what a good compiler can do— and what you have to do yourself. The book closes with a look at the high-performance future: parallel computers and the more "garden variety" shared memory processors that are appearing on people's desktops.

UNIX for FORTRAN Programmers

By Mike Loukides

1st Edition August 1990

264 pages, ISBN 0-937175-51-X

This handbook lowers the UNIX entry barrier by providing the serious scientific programmer with an introduction to the UNIX operating system and its tools. It familiarizes readers with the most important tools so they can be productive as quickly as possible. Assumes some knowledge of FORTRAN, none of UNIX or C.

picture43

FOR INFORMATION: 800-998-9938 707-829-0515; NUTS@ORA.COM

C Programming Libraries

POSIX.4

By Bill Gallmeister

1st Edition Winter 1994-95 (est.)

400pages (est.), ISBN 1-56592-074-0

POSIX.4

A general introduction to real-time programming and real-time issues, this book covers the POSIX.4 standard and how to use it to solve "real-world" problems. If you're at all interested in real-time applications—which include just about everything from telemetry to transation processing—this book is for you. An essential reference.

POSIX Programmer's Guide

By Donald Lewine

1st Edition April 1991

640pages, ISBN 0-937175-73-0

POSIX

PROGRAMMER'S GUIDE

Most UNIX systems today are POSIX compliant because the Federal govern ment requires it for its purchases. Given the manufacturer's documenta tion, however, it can be difficult to distinguish system-specific features from those features defined by POSIX. The POSIX Programmer's Guide, intended as an explanation of the POSIX standard and as a reference for

the POSIX. 1 programming library, helps you write more

portable programs.

"If you are an intermediate to advanced C programmer and are interested in having your programs compile first time on anything from a Sun to a VMS system to an MSDOS system, then this book must be thoroughly recommended." — Sun UK User

Understanding and Using COFF

By Gintaros R. Gircys

1st Edition November 1988

196pages, ISBN 0-937175-31-5

COFF—Common Object File Format—is the formal definition for the structure of machine code files in the UNIX System V environment. All machine code files are COFF files. This handbook explains COFF data structure and its manipulation.

picture44

COFF

picture45

Using C on the UNIX System

By Dave Curry

1st Edition January 1989

250pages, ISBN 0-937175-23-4

This is the book for intermediate to experienced C programmers who want to become UNIX system programmers. It explains system calls and special library routines available on the UNIX system. It is impossible to write UNIX utilities of any sophistication without understanding the material in this book.

"A gem of a book.... The author's aim is to provide a guide to system programming, and he succeeds admirably. His balance is steady between System V and BSD-based systems, so readers come away knowing both." — SUN Expert

Practical C Programming

By Steve Oualline

2nd Edition January 1993

396pages, ISBN 1-56592-035-X

C programming is more than just getting the syntax right. Style and debugging also play a tremendous part in creating programs that run well. Practical C Programming teaches you not only the mechanics of programming, but also how to create programs that are easy to read, maintain, and debug. There are lots of introductory C books, but

this is the Nutshell Handbook®! In this edition, programs

conform to ANSI C.

"This book is exactly what it states—a practical book in C programming. It is also an excellent addition to any C programmer's library." —Betty Zinkarun, Books & Bytes

Programming with curses

By John Strung

1st Edition 1986

76pages, ISBN 0-937175-02-1

Curses is a UNIX library of functions for controlling a terminal's display screen from a C program. This handbook helps you make use of the curses library. Describes the original Berkeley version of curses.

picture46

picture47

TO ORDER: 800-889-8969 (CREDIT CARD ORDERS ONLY); ORDER@ORA.COM

C Programming Tools

picture48

Software Portability with imake

By Paul DuBois

1st Edition July 1993

390pages, ISBN 1-56592-055-4

imake is a utility that works with make to enable code to be compiled and installed on different UNIX machines. imake makes possible the wide portability of the X Window System code and is widely considered an X tool, but it's also useful for any software project that needs to be ported to many UNIX systems.

This Nutshell Handbook®—the only book available on imake —is ideal for X and UNIX programmers who want their software to be portable. The book is divided into two sections. The first section is a general explanation of imake, X configuration files, and how to write and debug an Imakefile. The second section describes how to write configuration files and presents a configuration file architecture that allows development of coexisting sets of configuration files. Several sample sets of configuration files are described and are available free over the Net.

Managing Projects with make

By Andrew Oram & Steve Talbott 2nd Edition October 1991 152pages, ISBN 0-937175-90-0

make is one of UNIX's greatest contribu tions to software development, and this book is the clearest description of make ever written. It describes all the basic features of make and provides guidelines on meeting the needs of large, modern projects. Also contains a description of free products, that contain major enhancements to make,

"I use make very frequently in my day to day work and thought I knew everything that I needed to know about it. After reading this book I realized that I was wrong! —Rob Henley, Siemens-Nixdorf

"If you can't pick up your system's yp Makefile, read every line, and make sense of it, you need this book." — Rootjournal

picture49

picture50

Checking C Programs with lint

By Ian F. Darwin

1st Edition October 1988

84pages. ISBN 0-937175-30-7

The lint program checker has proven time and again to be one of the best tools for finding portability problems and certain types of coding errors in C programs, lint verifies a program or program segments against standard libraries, checks the code for common portability errors, and tests the programming against some tried and true guidelines. Linting your code is a necessary (though not sufficient) step in writing clean, portable, effective programs. This book introduces you to lint, guides you through running it on your programs, and helps you interpret lint's output.

"I can say without reservation that this book is a must for the system programmer or anyone else programming in C." — Rootjournal

lex & yacc

By John Letine, Tony Mason & Doug Brown 2nd Edition October 1992 366pages, ISBN 1-56592-000-7

Shows programmers how to use two UNIX utilities, lex and yacc, in program development. The second edition contains completely revised tutorial sections for novice users and reference sections for advanced users. This edition is twice the size of the first, has an expanded index, and now covers Bison and Flex.

Power Programming with RPC

By John Bloomer

1st Edition February 1992

522pages, ISBN 0-937175-77-3

RPC, or remote procedure calling, is the ability to distribute the execution of func tions on remote computers. Written from a programmer's perspective, this book shows what you can do with RPCs, like Sun RPC, the de facto standard on UNIX systems. It covers related programming topics for Sun and other UNIX systems and teaches through examples.

picture51

picture52

FOR INFORMATION: 800-998-9938, 707-829-0515; HUTS@ORA.COM

Multi-Platform Programming

picture53

Guide to Writing DCE Applications

By John Shirley, WeiHu & David Magid

2nd Edition May 1994

462 pages, ISBN 1-56592-045-7

A hands-on programming guide to OSF's Distributed Computing Environment (DCE) for first-time DCE application programmers. This book is designed to help new DCE users make the transition from conventional, nondistributed applications programming to distributed DCE programming. In addi tion to basic RFC (remote procedure calls), this edition covers object UUIDs

and basic security (authentication and authorization).

Also includes practical programming examples.

"This book will be useful as a ready reference by the side of the novice DCE programmer." — ;login

Distributing Applications Across DCE and Windows NT

By Ward Rosenbeny &Jim league 1st Edition November 1993 302 pages. ISBN 1-56592-047-3

This book links together two exciting technologies in distributed computing by showing how to develop an application that simultaneously runs on DCE and Microsoft systems through remote proce dure calls (RFC). Covers the writing of portable applications and the complete differences between RFC support in the two environments.

Understanding DCE

By Ward Rosenbeny, DavidKmney & Gerry Fisher

1st Edition October 1992

266pages, ISBN 1-56592-005-8

A technical and conceptual overview of OSF's Distributed Computing Environment (DCE) for programmers, technical managers, and marketing and sales people. Unlike many O'Reilly & Associates books, Understanding DCE has no hands-on programming elements. Instead, the book focuses on how DCE can be used to accomplish typical programming tasks

and provides explanations to help the reader understand all

the parts of DCE.

picture54

picture55

picture56

Encyclopedia of Graphics File Formats

By James D. Murray & William vanRyper

1st Edition July 1994

928pages (CD-ROM included), ISBN 1-56592-058-9

The computer graphics world is a veri table alphabet soup of acronyms; BMP DXF, EPS, GIF, MPEG, PCX, PIC, RTF, TGA, RIFF, and TIFF are only a few of the many different formats in which graphics images can be stored. The Encyclopedia of Graphics File Formats is the definitive work on file formats— the book that will become a classic for graphics programmers and

everyone else who deals with the low-level technical details of graphics files. It includes technical information on nearly 100 file formats, as well as chapters on graphics and file format basics, bitmap and vector files, metafiles, scene description, animation and multimedia formats, and file compression methods.

Best of all, this book comes with a CD-ROM that collects many hard-to-find resources. We've assembled original vendor file format specification documents, along with test images and code examples, and a variety of software packages for MS-DOS, Windows, OS/2, UND(, and the Macintosh that will let you convert, view, and manipulate graphics files and images.

Multi-Platform Code Management

By Kevin Jameson

1st Edition August 1994

354pages (two diskettes included), ISBN 1-56592-059-7

For any programmer or team struggling with builds and maintenance, this book—and its accompanying software (available for fifteen platforms, including MS-DOS and various UNIX systems)—can save dozens of errors and hours of effort. A "one-stop-shop ping" solution for code management problems, it shows you how to structure a large project and keep your files and builds under control over many releases and platforms. The building blocks are simple: common-sense strategies, public-domain tools that you can obtain on a variety of systems, and special utilities developed by the author. The book also includes two diskettes that provide a complete system for managing source files and builds.

Get Microsoft RPC Programming Guide now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.