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); } |