ThreadClient.cpp 

All non-multithreading class library programs can run on both 32-bit Windows and UNIX platforms. This sample program is for Microsoft Windows developers. The program shows how the class library can be used with the MFC to provide a user interface. For more information, please see the detailed comments in each program and the documentation for each class library function.

 

/////////////////////////////////////////////////////////

// CrClntTh.cpp : implementation file

/////////////////////////////////////////////////////////

 

#include "CrClntTh.h"

extern CRfcTrace RfcClassTrace; // For debugging trace

int main( int argc, char ** argv)

{

setbuf(stdout, NULL);

strcpy(work_file, std_work_file);

if (argc == 1)

syntax_OK = 1;

else

syntax_OK = 0;

if (syntax_OK == 0)

{

printf("\nSyntax: rfcthcli [options]\n");

printf("\n options: file=<test data file>\n\n");

exit(1);

}

for (;;)

{

printf("\n\n");

printf(" **********************************************\n");

printf(" * *\n");

printf(" * SAP RFC-API TEST *\n");

printf(" * *\n");

printf(" * Single threaded on *\n");

printf(" * all supported platforms *\n");

printf(" * *\n");

printf(" * or *\n");

printf(" * *\n");

printf(" * Multi threaded on *\n");

printf(" * Windows NT/95 *\n");

printf(" * *\n");

printf(" **********************************************\n\n");

Get_Parameters();

printf("\n");

fflush(stdout);

#ifdef RFCwithTHREADS

THREAD_ID_TYPE hThread[1001];

THREAD_ID_TYPE dwThreadId;

int i,

thread_rc,

active = 0,

success = 0,

failure = 0,

delay_time = 0;

unsigned long dwExitCode = 0;

memset(hThread, 0, sizeof(hThread));

for (i=1; i<=thread_no; i++)

{

hThread[i] = THREAD_CREATE(RFC_PerformanceThread, (void *)i, &dwThreadId);

}

for(;;)

{

active = 0;

for (i=1; i<=thread_no; i++)

{

if (hThread[i] != THREAD_INVALID_ID)

{

thread_rc = THREAD_EXIT_CODE(hThread[i], &dwExitCode);

if (thread_rc == EBUSY)

{

active = 1;

}

else

{

if (thread_rc == 0)

{

if (dwExitCode == 0)

success++;

else

{

if (dwExitCode == 99)

printf("\n\n Main Thread: RFC-ERROR OCCURS ==> Thread %d exited\n", i);

else

printf("\n\n Main Thread: Thread %d exited with rc=%d\n", i, dwExitCode);

failure++;

}

}

else

{

printf("\n\n Main Thread: Thread %d returned %d\n", i, thread_rc);

failure++;

}

CloseHandle(hThread[i]);

hThread[i] = THREAD_INVALID_ID;

}

}

}

if (active == 0)

break;

/* Don't use all of the CPU */

#if defined(SAPonNT)

Sleep(1000);

#elif defined(SAPonUNIX)

sleep(1);

#endif

}

if (success)

printf("\n\n Main Thread: %d thread(s) successfully terminated.\n", success);

if (failure)

printf("\n\n Main Thread: %d thread(s) terminated with an error.\n", failure);

#else

RFC_PerformanceThread(0);

#endif /* RFCwithTHREADS */

printf("\n\n");

do

{

printf(" Continue (y/n)..................: ");

fflush(stdout);

gets(wantContinue);

wantContinue[0] = (char) toupper(wantContinue[0]);

} while ((wantContinue[0] != 'Y') && (wantContinue[0] != 'N'));

if (wantContinue[0] == 'N')

break;

}

return 0;

}

/*=================================================================*/

/* */

/* Thread for calling function module RFC_SHOW. The function */

/* module RFC_SHOW can be any function module defined in the R/3 */

/* System. */

/*=================================================================*/

int RFC_PerformanceThread(void *lpParms)

{

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

/* Open RFC connection */

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

RFC_TABLE tables[2];

char dbuf[512];

int nrcount;

char *function = NULL;

RFC_PARAMETER exporting[2],

importing[2];

char *exception = NULL;

RFC_RC rfc_rc;

int nCount;

RFC_HANDLE rfc_handle;

rfc_handle = RFC_connect((int) lpParms);

if(rfc_handle == RFC_HANDLE_NULL)

return 99;

sprintf(dbuf, "Connection, RFC Handle = %4d", rfc_handle);

PRINT_RFC_CALL((int) lpParms, dbuf);

tables[0].name = "CONTENTS";

tables[0].nlen = 8;

tables[0].type = TYPC;

tables[0].leng = TEXT_LEN;

tables[0].itmode = RFC_ITMODE_BYREFERENCE;

tables[0].ithandle = ItCreate("CONTENTS", TEXT_LEN, 0, 0);

// Put some data into the table

if (tables[0].ithandle == NULL)

{

rfc_error("ItCreate CONTENTS", (int) lpParms);

return 99;

}

for (nrcount=0; nrcount < nrcall; nrcount++)

{

/*-----------------------------------------------------*/

/* Call RFC_SHOW */

/*-----------------------------------------------------*/

function = RfcFunctionName;

memset(&importing[0], 0, sizeof(importing));

rfc_param(&importing[0], "COUNT", TYPINT, &nCount, sizeof(RFC_INT));

memset(&exporting[0], 0, sizeof(exporting));

memset(titleName, 0, TEXT_LEN);

strcpy(titleName, "This is a test for multithreading");

rfc_param(&exporting[0], "TITLE", TYPC, titleName, TEXT_LEN);

tables[1].name = NULL;

/* Fill tables as required */

if (fill_table(tables[0].ithandle, nTabLines))

{

sprintf(dbuf, "ERROR: Fill tables[0]");

PRINT_RFC_CALL((int) lpParms, dbuf);

return 99;

}

rfc_rc = RfcCallReceive(rfc_handle,

function,

exporting,

importing,

tables,

&exception);

/* check return code */

if (rfc_rc == RFC_CLOSED) return 0;

switch(rfc_rc)

{

case RFC_OK:

break;

case RFC_EXCEPTION:

case RFC_SYS_EXCEPTION:

{

rfc_error(exception, (int) lpParms);

return 99;

}

default:

{

rfc_error("RfcCallReceive", (int) lpParms);

return 99;

}

}

/* Output the results. */

sprintf(dbuf, "Execution, RFC Handle = %4d Call Number: %3d", rfc_handle, nrcount+1);

PRINT_RFC_CALL((int) lpParms, dbuf);

sprintf(dbuf, "Number of table entries : %6d", nCount);

PRINT_RFC_CALL((int) lpParms, dbuf);

if (nrcount < nrcall-1)

{

/* Free the internal table */

ItFree(tables[0].ithandle);

/* Close and Reopen current RFC connection if required */

/* or RFC server is external */

if (use_close[0] == 'Y')

{

RfcClose(rfc_handle);

rfc_handle = RFC_connect((int) lpParms);

if(rfc_handle == RFC_HANDLE_NULL)

return 99;

sprintf(dbuf, "Connection, Call Number: %3d, RFC Handle = %4d", nrcount+1, rfc_handle);

PRINT_RFC_CALL((int) lpParms, dbuf);

}

}

}

/*----------------------------------------------------------------*/

/* Close RFC connection */

/*----------------------------------------------------------------*/

RfcClose(rfc_handle);

/*----------------------------------------------------------------*/

/* Delete all used internal tables[0] */

/*----------------------------------------------------------------*/

ItDelete(tables[0].ithandle);

return 0;

}

/*-----------------------------------------------------------------*/

/* Prepare and Open an RFC-Connection to an external system */

/*-----------------------------------------------------------------*/

RFC_HANDLE RFC_connect(int thread_id)

{

char connect_param[512];

RFC_HANDLE rfc_handle;

RFC_ERROR_INFO_EX error_info;

memset(connect_param, 0, sizeof(connect_param));

sprintf(connect_param, "TYPE=E");

if (rfc_trace[0] == 'Y')

strcpy(connect_param+strlen(connect_param), " TRACE=1");

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

/* Working with 'saprfc.ini' */

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

sprintf(connect_param+strlen(connect_param)," DEST=%s", rfc_dest);

rfc_handle = RfcOpenEx(connect_param, &error_info);

if (rfc_handle == RFC_HANDLE_NULL)

{

char ebuf[1024];

sprintf(ebuf+strlen(ebuf), "\nGroup Error group %d\n", error_info.group);

sprintf(ebuf+strlen(ebuf), "Key %s\n", error_info.key);

sprintf(ebuf+strlen(ebuf), "Message %s\n\n", error_info.message);

PRINT_RFC_CALL(thread_id, ebuf);

}

return rfc_handle;

}

/*-----------------------------------------------------------------*/

/* set up RFC parameters */

/*-----------------------------------------------------------------*/

void rfc_param(RFC_PARAMETER *rfc_param,

char *abap_field_name,

unsigned data_type,

void *data_addr,

unsigned data_len)

{

RFC_PARAMETER *p = rfc_param;

p->name = (void *)abap_field_name;

p->nlen = abap_field_name == NULL ? 0 : strlen(abap_field_name);

p->type = data_type;

p->addr = data_addr;

p->leng = data_len;

/* init next parameter for no more parameter */

p++;

p->name = NULL;

p->nlen = 0;

p->type = 0;

p->addr = NULL;

p->leng = 0;

return;

}

/*-----------------------------------------------------------------*/

/* Fill internal table as required */

/*-----------------------------------------------------------------*/

int fill_table(ITAB_H itab_h,

long leng)

{

unsigned ulen;

long position,

lineleng,

linenr;

char *ptr,

etext[1001];

if (leng == 0)

return 0;

lineleng = ulen = ItLeng(itab_h);

memset(etext, BLANK, 1000);

for (position=40; position<lineleng; position++)

sprintf(etext+position, "%01d", position % 10);

sprintf(etext, "Line Length: %04d Line No.: ", lineleng);

for (linenr=1; linenr<=leng; linenr++)

{

sprintf(etext+30, "%05d", linenr);

etext[35] = ' ';

ptr = (char *) ItAppLine(itab_h);

if (ptr == NULL) break;

memcpy(ptr, etext, ulen);

}

if (linenr <= leng)

return 1;

else

return 0;

}

/*-----------------------------------------------------------------*/

/* Error Cleanup because of an RFC-Error */

/*-----------------------------------------------------------------*/

void rfc_error(char *operation, int thread_id)

{

char ebuf[1024];

RFC_ERROR_INFO_EX error_info;

memset(ebuf, 0, sizeof(ebuf));

RfcLastErrorEx(&error_info);

sprintf(ebuf, "\nRFC Call/Exception: %s\n", operation);

sprintf(ebuf+strlen(ebuf), "Group Error group %d\n", error_info.group);

sprintf(ebuf+strlen(ebuf), "Key %s\n", error_info.key);

sprintf(ebuf+strlen(ebuf), "Message %s\n", error_info.message);

PRINT_RFC_CALL(thread_id, ebuf);

return;

}

/*-----------------------------------------------------------------*/

/* Output itab on screen */

/*-----------------------------------------------------------------*/

int output_table(ITAB_H itab_h,

char *itabname)

{

unsigned ulen;

long lineleng;

char tbuff[1001];

lineleng = ulen = ItLeng(itab_h);

printf("\n%s:\n", itabname);

for (j = 1; ; j++)

{

char *ptr = (char *) ItGetLine(itab_h, j);

if (ptr == NULL) break;

memcpy(tbuff, ptr, ulen);

tbuff[lineleng] = 0;

printf("'%s'\n", tbuff);

}

return 0;

}

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

This function retrieves user parameters from the screen or gets

them from a file. After the users enter the parameter values,

the values are saved in a file for the future use.

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

void Get_Parameters(void)

{

work_fp = fopen(work_file, "r");

if (work_fp == NULL)

{

Get_Parameters_From_Screen();

Save_Parameters_To_File();

}

else

{

Get_Parameters_From_File();

if (work_fp != NULL)

{

fclose(work_fp);

work_fp = NULL;

}

}

}

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

This function gets user parameters from the screen

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

void Get_Parameters_From_Screen(void)

{

memset(wbuf, 0, 512);

memset(ips, 0, 257);

printf(" The server program is an external program for this client.\n\n");

/* Destination in saprfc.ini, user enter it */

if (strlen(rfc_dest) == 0)

strcpy(rfc_dest, std_rfc_dest_r3);

printf(" Destination in 'saprfc.ini'......(%s): ", rfc_dest);

fflush(stdout);

gets(ips);

if (strlen(ips) == 0)

strcpy(ips, rfc_dest);

ips[32] = 0;

strcpy(rfc_dest, ips);

for (i = 0; i < (int) strlen(rfc_dest); i++)

rfc_dest[i] = (char) toupper(rfc_dest[i]);

sprintf(wbuf+strlen(wbuf), "DEST=%s ", rfc_dest);

/* RFC Remote Function Name on the multithreading server */

if (strlen(RfcFunctionName) == 0)

strcpy(RfcFunctionName, std_functionName);

printf(" Remote Function Name on the server......(%s): ", RfcFunctionName);

fflush(stdout);

memset(ips, 0, 257);

gets(ips);

if (strlen(ips) == 0)

strcpy(ips, RfcFunctionName);

ips[55] = 0;

strcpy(RfcFunctionName, ips);

for (i = 0; i < (int) strlen(rfc_dest); i++)

RfcFunctionName[i] = (char) toupper(RfcFunctionName[i]);

sprintf(wbuf+strlen(wbuf), "REMOTE=%s ", RfcFunctionName);

/* Thread number on this client */

if (thread_no < 0) thread_no = 0;

printf(" Number of threads on the client(Maximum: 999)....(%d): ", thread_no);

fflush(stdout);

memset(ips, 0, 257);

gets(ips);

if (strlen(ips) == 0)

{

if (thread_no < 0)

thread_no = 0;

itoa(thread_no, ips, 10);

}

else

{

thread_no = atoi(ips);

if (thread_no > 999)

{

thread_no = 999;

itoa(thread_no, ips, 10);

}

}

sprintf(wbuf+strlen(wbuf), "THREADNO=%s ", ips);

/* Number of the RFC function calls in one thread */

if (nrcall < 1) nrcall = 1;

printf(" Number of the RFC function calls in one thread......(%d): ", nrcall);

fflush(stdout);

memset(ips, 0, 257);

gets(ips);

if (strlen(ips) == 0)

{

if (nrcall < 1)

nrcall = 1;

itoa(nrcall, ips, 10);

}

else

{

nrcall = atoi(ips);

}

sprintf(wbuf+strlen(wbuf), "NRCALL=%s ", ips);

/* Number of table entries */

if (nTabLines < 0) nTabLines = 0;

printf(" Number of lines in a table......(%d): ", nTabLines);

fflush(stdout);

memset(ips, 0, 257);

gets(ips);

if (strlen(ips) == 0)

{

if (nTabLines < 0)

nTabLines = 0;

itoa(nTabLines, ips, 10);

}

else

{

nTabLines = atoi(ips);

}

sprintf(wbuf+strlen(wbuf), "NTABLINES=%s ", ips);

/* If RFC debug trace is needed */

if (strlen(rfc_trace) == 0)

rfc_trace[0] = 'N';

do

{

printf(" RFC trace (Y/N) (%c): ", rfc_trace[0]);

fflush(stdout);

memset(ips, 0, 257);

gets(ips);

if (strlen(ips) == 0)

ips[0] = rfc_trace[0];

ips[0] = (char) toupper(ips[0]);

} while ((ips[0] != 'Y') && (ips[0] != 'N'));

rfc_trace[0] = ips[0];

sprintf(wbuf+strlen(wbuf), "RFCTRACE=%s ", rfc_trace);

/* If the table data should be output to the screen */

if (strlen(output_table_to_screen) == 0)

output_table_to_screen[0] = 'Y';

do

{

printf(" Output table data to the screen (Y/N) (%c): ", output_table_to_screen[0]);

fflush(stdout);

memset(ips, 0, 257);

gets(ips);

if (strlen(ips) == 0)

ips[0] = output_table_to_screen[0];

ips[0] = (char) toupper(ips[0]);

} while ((ips[0] != 'Y') && (ips[0] != 'N'));

output_table_to_screen[0] = ips[0];

sprintf(wbuf+strlen(wbuf), "OUTABLE=%s ", output_table_to_screen);

/* Determines whether to close a connection after each call */

if (strlen(use_close) == 0)

use_close[0] = 'N';

do

{

printf(" Close connection after each call (Y/N) (%c): ", use_close[0]);

fflush(stdout);

memset(ips, 0, 257);

gets(ips);

if (strlen(ips) == 0)

ips[0] = use_close[0];

ips[0] = (char) toupper(ips[0]);

} while ((ips[0] != 'Y') && (ips[0] != 'N'));

use_close[0] = ips[0];

sprintf(wbuf+strlen(wbuf), "USECLOSE=%s ", use_close);

/* Last confirm for test */

printf("\n");

do

{

printf(" Do You Want To Test With These Parameters (Y/N)..: ");

fflush(stdout);

gets(ips);

ips[0] = (char) toupper(ips[0]);

} while ((ips[0] != 'Y') && (ips[0] != 'N'));

if (ips[0] == 'N')

{

if (work_fp != NULL)

{

fclose(work_fp);

work_fp = NULL;

}

Get_Parameters_From_Screen();

Save_Parameters_To_File();

}

return;

}

/* This function is for saving parameters to a file for future use. */

void Save_Parameters_To_File(void)

{

/* Open the work file */

work_fp = fopen(work_file, "w");

if (work_fp == NULL)

{

printf("\n\nCan not save RFC-parameters for next tests");

printf("\n\nHit return key to continue\n");

fflush(stdout);

getchar();

}

else

{

fputs(wbuf, work_fp);

fclose(work_fp);

work_fp = NULL;

}

}

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

This function reads parameters from a file.

First, it reads the data into a buffer, then it searches the

buffer to find the appropriate parameters.

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

void Get_Parameters_From_File(void)

{

if (read_record(work_fp, sbuf1) == NULL)

{

printf("\nCannot read data file\n");

exit(1);

}

strcpy(sbuf, sbuf1);

int rc;

printf(" The server program is an external program for this client.\n\n");

/* Destination in saprfc.ini, user enter it */

memset(rfc_dest, 0, 32);

rc = PM_search(rfc_dest, "DEST=", 32);

if (rc)

{

printf("\n\nInfo about destination (DEST=) not found or not correct");

exit(1);

}

printf(" Destination in 'saprfc.ini'......(%s): ", rfc_dest);

/* RFC Remote Function Name on the multithreading server */

memset(RfcFunctionName, 0, 55);

rc = PM_search(RfcFunctionName, "REMOTE=", 55);

if (rc)

{

printf("\n\nInfo about Remote Function Name on the server (REMOTE=) not found or not correct");

exit(1);

}

printf(" Remote Function Name on the server......(%s): ", RfcFunctionName);

/* Thread number on this client */

memset(ips, 0, 257);

rc = PM_search(ips, "THREADNO=", 257);

if (rc)

{

printf("\n\nInfo about Number of threads on the client(THREADNO=) not found or not correct");

exit(1);

}

if (strlen(ips) == 0)

thread_no = 0;

else

thread_no = atoi(ips);

printf(" Number of threads on the client....(%d): ", thread_no);

/* Number of the RFC function calls in one thread */

memset(ips, 0, 257);

rc = PM_search(ips, "NRCALL=", 257);

if (rc)

{

printf("\n\nInfo about Number of the RFC function calls in one thread(NRCALL=) not found or not correct");

exit(1);

}

if (strlen(ips) == 0)

nrcall = 0;

else

nrcall = atoi(ips);

printf(" Number of the RFC function calls in one thread......(%d): ", nrcall);

/* Number of table entries */

memset(ips, 0, 257);

rc = PM_search(ips, "NTABLINES=", 257);

if (rc)

{

printf("\n\nInfo about number of lines in the table(NTABLINES=) not found or not correct");

exit(1);

}

if (strlen(ips) == 0)

nTabLines = 0;

else

nTabLines = atoi(ips);

printf(" Number of lines in a table......(%d): ", nTabLines);

/* If RFC debug trace is needed */

memset(rfc_trace, 0, 1);

rc = PM_search(rfc_trace, "RFCTRACE=", 1);

if (rc)

{

printf("\n\n(RFCTRACEM=) Entry not found or not correct");

exit(1);

}

printf(" RFC trace (Y/N) (%c): ", rfc_trace[0]);

/* Determines if the table data should be output to the screen */

memset(output_table_to_screen, 0, 1);

rc = PM_search(output_table_to_screen, "OUTABLE=", 1);

if (rc)

{

printf("\n\n(OUTABLE=) Entry not found or not correct");

exit(1);

}

printf(" Output table data to the screen (Y/N) (%c): ", output_table_to_screen[0]);

/* Determines whether to close connection after each call */

memset(use_close, 0, 1);

rc = PM_search(use_close, "USECLOSE=", 1);

if (rc)

{

printf("\n\n(USECLOSE=) Entry not found or not correct");

exit(1);

}

printf(" Close connection after each call (Y/N) (%c): ", use_close[0]);

/* Last confirm for test */

printf("\n");

do

{

printf(" Do You Want To Test With These Parameters (Y/N)..: ");

fflush(stdout);

gets(ips);

ips[0] = (char) toupper(ips[0]);

} while ((ips[0] != 'Y') && (ips[0] != 'N'));

if (ips[0] == 'N')

{

if (work_fp != NULL)

{

fclose(work_fp);

work_fp = NULL;

}

Get_Parameters_From_Screen();

Save_Parameters_To_File();

}

return;

}

/*-----------------------------------------------------------------*/

/* Search for a specific parameter */

/*-----------------------------------------------------------------*/

int PM_search(char *param,

char *text,

int leng)

{

char *pa,

*pe;

int znr;

memset(param, 0, leng);

pa = strstr(sbuf, text);

if (pa == NULL)

return 99;

pa = pa + strlen(text);

if (*pa == '"')

{

pe = (char *) memchr(pa+1, '"', leng);

if (pe == NULL)

znr = &sbuf[strlen(sbuf)] - pa;

else

znr = pe - pa + 1;

}

else

{

pe = (char *) memchr(pa, ' ', leng);

if (pe == NULL)

znr = &sbuf[strlen(sbuf)] - pa;

else

znr = pe - pa;

}

if (znr == 0)

return 99;

if (znr > leng)

znr = leng;

memcpy(param, pa, znr);

return 0;

}

/*-----------------------------------------------------------------*/

/* Read record from file with single or multiple lines */

/*-----------------------------------------------------------------*/

char *read_record(FILE *fp,

char *ibuf)

{

int offset = 0;

char *ptr,

line[LINE_SIZE+1];

ibuf[0] = 0;

for (;;)

{

if ((ptr = fgets(line, LINE_SIZE, fp)) == NULL)

return (NULL);

if (line[strlen(line)-1] == '\n')

line[strlen(line)-1] = 0;

ptr = line;

switch (*ptr)

{

case '\0': continue;

case '*' : continue;

case ' ' : continue;

default : ;

}

strcpy(ibuf+offset, ptr);

if (ibuf[strlen(ibuf)-1] == '&')

{

ibuf[strlen(ibuf)-1] = 0;

offset = strlen(ibuf);

continue;

}

break;

}

return (ibuf);

}