57
Johannes Meiners, Wilhelm Nüßer SAP-Schnittstellen- programmierung

SAP-Schnittstellen- programmierung...3.4 Häufige Fehler auf der Client-Seite ..... 91 3.5 Übersicht über die verwendeten Funktionen und Strukturen ..... 93 3.6 Vom Aufruf einer

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Johannes Meiners, Wilhelm Nüßer

SAP-Schnittstellen-programmierung

Inhalt 5

1.1 Der Applikationsserver ......................................................................... 16

1.2 Der Dialogprozess ................................................................................. 18

1.3 Der Verbucher ....................................................................................... 20

1.4 Der Enqueue-Prozess ............................................................................ 21

1.5 Der Gateway-Server .............................................................................. 23

1.6 Lastverteilte Systeme und der Message-Server .................................... 27

1.7 Die RFC-Schnittstelle innerhalb des R/3-Systems ................................ 29

2.1 Die ABAP-Entwicklungsumgebung ....................................................... 32

2.2 Datenbanktabellen anlegen .................................................................. 362.2.1 Das Data Dictionary ................................................................. 362.2.2 Beziehungen zwischen Domäne, Datenelement und Tabelle ..... 372.2.3 Anlegen einer Domäne ............................................................. 382.2.4 Anlegen eines Datenelements .................................................. 402.2.5 Anlegen einer transparenten Tabelle ......................................... 422.2.6 Pflege von Datensätzen durch den Data Browser ...................... 45

2.3 Ein einfaches Programm ........................................................................ 45

2.4 ABAP-Datentypen und Variablendeklaration ........................................ 49

2.5 Elementare Programmanweisungen in ABAP ........................................ 532.5.1 Wertzuweisungen .................................................................... 532.5.2 Verzweigungen ........................................................................ 552.5.3 Schleifen .................................................................................. 562.5.4 Zugriff auf interne Tabellen ...................................................... 572.5.5 Zugriff auf Datenbanktabellen .................................................. 592.5.6 Gestaltung von Selectionscreens .............................................. 62

2.6 Anlegen von Funktionsbausteinen ........................................................ 62

2.7 Coding-Konventionen im Buch ............................................................. 69

Inhalt

Einleitung 11

1 Grundlagen der R/3-Systemarchitektur 15

2 Grundlagen der Programmiersprache ABAP 31

6 Inhalt

3.1 Die Aufgabenstellung für das erste Beispiel ......................................... 72

3.2 Die Programmierung der SAP-Funktionsbausteine ............................... 73

3.3 Die Programmierung des Clients .......................................................... 753.3.1 Der Aufbau der main()-Funktion .............................................. 763.3.2 Verbindung zum R/3-System aufnehmen ................................. 793.3.3 Funktionsbausteine im R/3-System ansteuern .......................... 85

3.4 Häufige Fehler auf der Client-Seite ....................................................... 91

3.5 Übersicht über die verwendeten Funktionen und Strukturen .............. 93

3.6 Vom Aufruf einer RFC-Funktion zum Funktionsbaustein ..................... 93

3.7 Die Programmierung externer Server .................................................... 963.7.1 Der Aufbau der main()-Funktion für einen externen Server ...... 973.7.2 Verbindung mit dem R/3-System aufnehmen ........................... 993.7.3 Die Implementierung der Nachrichtenschleife .......................... 1033.7.4 Die Realisierung der Dienste des Servers .................................. 1043.7.5 Das Einrichten der Verbindung im R/3-System ......................... 1113.7.6 Die Programmierung des ABAP-Clients .................................... 114

3.8 Häufige Fehler auf der Server-Seite ...................................................... 115

3.9 Verwendete Funktionen ....................................................................... 116

4.1 Type-Mapping und Datenaggregate ..................................................... 1174.1.1 Generische Datentypen ........................................................... 1174.1.2 Die Character-Datentypen ....................................................... 1194.1.3 Numerische Strings .................................................................. 1224.1.4 Die Sache mit den gepackten Zahlen ....................................... 1254.1.5 Abschließende Übersicht über das Type-Mapping .................... 129

4.2 Der Umgang mit Strukturen ................................................................. 130

4.3 Der Umgang mit internen Tabellen ...................................................... 1374.3.1 Anlegen einer internen Tabelle in einem externen Programm ... 1394.3.2 Verwaltung von Datensätzen in einer internen Tabelle ............. 1434.3.3 Schreiben und Lesen von Datensätzen in eine interne Tabelle .. 1454.3.4 Übersicht über die Funktionen für interne Tabellen .................. 149

4.4 Die Nachrichtenschleife ........................................................................ 149

4.5 Alternativen für das Anmelden an ein R/3-System ............................... 1524.5.1 Arbeiten mit einer Konfigurationsdatei ..................................... 1534.5.2 Arbeiten mit Load Balancing .................................................... 1544.5.3 Arbeiten mit der Funktion RfcOpen ......................................... 155

3 Einstieg in die Programmierung mit der RFC-API 71

4 Grundlagen der RFC-Programmierung 117

Inhalt 7

5.1 Der ABAP Debugger ............................................................................. 159

5.2 Die BREAK-Anweisung ......................................................................... 162

5.3 Der Gateway Monitor ........................................................................... 163

5.4 Der RFC Trace ....................................................................................... 1655.4.1 Aufbau der Trace-Datei für einen externen Client ..................... 1675.4.2 Aufbau der Trace-Datei für einen externen Server .................... 1695.4.3 Tracen unter Anwendung der Transaktion ST05 ........................ 170

5.5 Der RFC-Generator ............................................................................... 1715.5.1 Aufbau des generierten Clientprogramms ................................. 1745.5.2 Aufbau des generierten Serverprogramms ................................ 1765.5.3 Makros für das Setzen und Lesen von Werten .......................... 177

5.6 Testprogramme von SAP ....................................................................... 178

6.1 Rückrufe aus dem Server ....................................................................... 183

6.2 Automatisches Anlegen einer Strukturbeschreibung ............................ 192

6.3 Transaktionale Remote Function Calls .................................................. 1986.3.1 Das R/3-System als tRFC-Client ................................................ 2006.3.2 Die Programmierung eines transaktionalen RFC-Servers ........... 2036.3.3 Transaktionaler RFC-Client ....................................................... 208

6.4 Queue RFCs .......................................................................................... 2136.4.1 Verwaltung von qRFCs im R/3-System ..................................... 2156.4.2 Entwickeln eines qRFC-Clients im R/3-System .......................... 2206.4.3 Entwickeln eines externen qRFC-Clients ................................... 2246.4.4 Fazit tRFC- und qRFC-Aufrufe .................................................. 229

6.5 Fehlermeldungen eines externen Servers .............................................. 2306.5.1 Fehlermeldungen durch einen synchronen Server ..................... 2306.5.2 Fehlermeldungen durch tRFC- und qRFC-Server ...................... 234

6.6 Parallelverarbeitung .............................................................................. 2376.6.1 Multitasking und Multithreading .............................................. 2376.6.2 Anlegen und Beenden von Threads .......................................... 2396.6.3 Grundlagen der Synchronisation ............................................... 2406.6.4 Synchronisationsobjekte ........................................................... 2456.6.5 Vorteile der Parallelverarbeitung im Bereich

der RFC-Programmierung ......................................................... 2476.6.6 Implementierung der Parallelverarbeitung bei externen Servern 249

5 Troubleshooting 159

6 Fortgeschrittene Techniken 183

8 Inhalt

7.1 Business-Objekt – ganz nah am Objekt ................................................ 258

7.2 Aufbau des Business-Objekts ............................................................... 261

7.3 Der Aufbau des Business Object Builders ............................................ 266

7.4 Anlegen des Objektschlüssels .............................................................. 269

7.5 Methoden des Business-Objekts .......................................................... 2707.5.1 Instanzabhängige Methoden .................................................... 2717.5.2 Realisierung von Methoden durch ABAP-Programmformen ..... 2737.5.3 Anlegen einer Methode ........................................................... 275

7.6 Objektfreigabe und das Business Object Repository ............................ 281

7.7 Richtlinien für die Entwicklung von API-Methoden ............................. 282

7.8 Möglichkeiten für die Ansteuerung ...................................................... 284

8.1 Was ist COM und ActiveX? .................................................................. 287

8.2 »Wie heißt du?« oder der Einstieg in die Benutzung der ActiveX-Controls ............................................................................ 2918.2.1 Das SAP BAPI-Control ............................................................. 2918.2.2 Verbindung mit dem R/3-System aufnehmen ........................... 2938.2.3 Ansteuern der Business-Objekt-Methode ................................. 2968.2.4 Was ist das BAPI-Proxy-Objekt eigentlich? ............................... 299

8.3 Namenskonventionen bei der Programmierung ................................... 302

8.4 Wrappen des BAPI-Proxy-Objekts ....................................................... 302

8.5 Eine bessere Methode für das Aufbauen einer Verbindung zum R/3-System ................................................................................... 3058.5.1 Einbinden des Logon-Controls in den Client ............................ 3088.5.2 Die Ereignisse der Klasse SAPLogonControl .............................. 3108.5.3 Erkennen eines Verbindungsabbruchs ...................................... 312

8.6 Konzepte für das Anlegen von Datenaggregaten .................................. 314

8.7 Das SAP TableFactory-Control im Detail .............................................. 317

8.8 Verwalten von Strukturen mit dem SAP TableFactory-Control ............. 3198.8.1 Der Zugriff auf Daten in Strukturen .......................................... 3198.8.2 Achtung beim Umgang mit Strukturen! .................................... 320

8.9 Der Umgang mit Tabellen ..................................................................... 3238.9.1 Die Klassenhierarchie für das Arbeiten mit Tabellen ................. 3238.9.2 Wichtige Attribute der Klasse Table ......................................... 3248.9.3 Der Aufbau der Beispielprogramme ......................................... 3258.9.4 Das Lesen der Datensätze in einer Tabelle ................................ 3268.9.5 Das Verändern von Datensätzen .............................................. 3308.9.6 Alternativen für das Anlegen der Feldbeschreibung .................. 331

7 Das Business-Objekt 257

8 Ansteuern von BAPIs durch Clients 287

Inhalt 9

8.10 Visualisierung des Tabelleninhalts ........................................................ 3348.10.1 Die Hierarchie der Klassen des SAP TableView-Controls ........... 3358.10.2 Festlegen des Layouts des Data Grids ....................................... 3368.10.3 Zugriff auf die Zellen in einem Data Grid .................................. 3398.10.4 Festlegen der Datenquelle für das Data Grid ............................ 3448.10.5 Konzepte zum Einfügen und Löschen von Zeilen und Spalten .. 3498.10.6 Arbeiten mit der Zwischenablage ............................................. 352

9.1 Der SAP Java Connector ........................................................................ 3559.1.1 Grundlagen des JCo ................................................................. 3569.1.2 Verwendungsformen des JCo ................................................... 3569.1.3 Das JCo-Package ...................................................................... 3579.1.4 JCo-Releases ............................................................................ 358

9.2 Anwendung des JCo ............................................................................. 3589.2.1 Grundstruktur einer JCo-Anwendung ....................................... 3589.2.2 Verbindungsaufbau .................................................................. 3599.2.3 Ausführung der RFC-Module .................................................... 3619.2.4 Zugriff auf Daten und Tabellen ................................................. 3649.2.5 Vollständiges Beispielprogramm ............................................... 3659.2.6 Fehlerbehandlung und Tracing ................................................. 3719.2.7 Abschließende Bemerkungen ................................................... 373

9.3 Die Zukunft der SAP-Java-Schnittstelle ................................................ 373

9 SAP und Java 353

A Literaturhinweise 375

B Die Autoren 377

Index 378

Einleitung 11

Einleitung

Dieses Buch behandelt die wichtigsten Möglichkeiten für die Entwicklung vonSchnittstellen zwischen R/3-Systemen und externer Software. Den Schwerpunktbildet dabei die RFC-Bibliothek. Darüber hinaus werden aber auch neuere tech-nologische Ansätze von SAP behandelt: Hier liegt der Fokus auf der aktuellenBAPI-Technologie und dem Java Connector (JCo).

Ein Buch über SAP-Schnittstellenprogrammierung, mit Schwerpunkt auf der RFC-Bibliothek, gar mit C-Programmen, aber kein Wort zu Webservices, SAP XI und.Net? Sicher, »reden« muss man wohl manchmal mit dem SAP-System, Schnitt-stellen sind also wichtig, aber ist die Technologie der Remote Function Calls (RFC)– entstanden in der alten R/2-Zeit – heute im Zeitalter von J2EE, .Net, Webser-vices und wie die Technologien alle heißen noch interessant und wichtig? SelbstSAP propagiert doch mit erheblichem Marketing-Aufwand diese modernenAnsätze und will damit aus der Ecke eines Anbieters rein proprietärer Lösungenund Protokolle heraus.

Nun, sicher ist diese Frage rhetorischer Natur, denn wenn wir sie mit einem»Nein« beantwortet hätten, wäre dieses Buch nicht entstanden. Unserer Ansichtnach sprechen einige gute Gründe für die Behandlung dieses Themas im Rahmeneines Buches:

1. Die RFC-Schnittstelle ist ein zentraler Bestandteil des SAP-Applikationsservers.Nach wie vor wird sie SAP-intern und von vielen Kunden für die Realisierungvon z.T. sehr komplexen Lösungen verwendet.

2. Ein Großteil der SAP-Kunden setzt immer noch Releases der SAP-Software ein,die nicht oder nur sehr bedingt die oben genannten neuen Technologien unter-stützen. Diese Kunden sind weiterhin ausschließlich auf die RFC-Bibliothekangewiesen.

3. Selbst wenn jedoch neue Technologien eingesetzt werden können, basieren sieentweder auf der RFC-Schnittstelle oder/und bieten nur einen Teil der Funk-tionalität dieser etablierten Schnittstelle. Wir zeigen dies im letzten Kapitelanhand des Java Connector (JCo) auf.

4. Last but not least sind die Programmiermodelle, die bei der RFC-Programmie-rung eine Rolle spielen, in viele Client-Server-Umgebungen übertragbar. Es gibtalso sogar didaktische Aspekte, warum sich ein Entwickler die RFC-Bibliothekeinmal genauer anschauen sollte – auch wenn es einfachere APIs als die RFC-Schnittstelle gibt.

Wir haben – um insbesondere diesem letzten Aspekt Rechnung zu tragen – einenrecht langsamen, vorsichtigen Einstieg in die Thematik gewählt. Erfahrene SAP-

12 Einleitung

Entwickler werden an der einen oder anderen Stelle auf Altbekanntes stoßen undvorblättern, ein Einsteiger in die SAP-Welt benötigt aber Hintergrundinforma-tionen, die es ihm ermöglichen, nach der Lektüre des Buches selbstständig voran-zuschreiten. Das Buch gliedert sich daher in neun Kapitel:

� Das Kapitel 1 ist eine kurze Einführung in die Grundbegriffe des R/3-Systems.Hier stellen wir wesentliche Elemente wie den SAP-Applikationsserver, dieWorkprozesse und das Gateway vor.

� In Kapitel 2 folgt eine Zusammenstellung der wichtigsten Tools der ABAPWorkbench. Diese beiden ersten Kapitel können von erfahrenen SAP-Entwick-lern ohne weiteres übersprungen werden.

� Im Kapitel 3 beginnt dann die eigentliche Programmierung mit den RFCs derSAP. Wir fangen hier mit der Programmiersprache C an, da sie die originäreSprache der RFC-Schnittstelle ist. Sie lernen in diesem Kapitel einfache Client-Server-Anwendungen kennen.

� Das Kapitel 4 vertieft die eher didaktisch motivierten Ansätze des Kapitels 3.Datentypen in der RFC-Bibliothek und im R/3-System sind hier ein wichtigesThema. Dieses und das vorige Kapitel sind das Kernstück des Buches.

� Da Sie nach der Lektüre der ersten Kapitel in der Lage sind, auch durchauskomplexe Programme zu entwerfen und zu realisieren, liegt es nahe, im Kapi-tel 5 Werkzeuge zur Fehlerdiagnose und zum Troubleshooting vorzustellen.Auch dieses Kapitel kann ein SAP-Kundiger überschlagen, da die meistenWerkzeuge bekannt sein dürften.

� Das Kapitel 6 greift dann einige weniger bekannte und durchaus als »fort-geschrittene Programmierung« zu bezeichnende Aspekte der RFC-Schnittstelleauf. Hier behandeln wir z.B. Themen wie tRFCs, qRFCs und Parallelverarbei-tung.

� Eine konzeptionell sehr wichtige Form der Schnittstellen des SAP-Systems, dieBAPIs (Business Application Programming Interfaces), diskutiert das Kapitel 7.BAPIs stellen einen von SAP definierten objektorientierten Weg zu stabilenSchnittstellen dar – und werden letztlich über die RFC-Schnittstelle angespro-chen.

� Eine der wichtigsten Anwendungen finden die BAPIs im Zusammenhang mitden ActiveX-Controls. Dieses Zusammenspiel ist Inhalt des Kapitels 8. Hierverlassen wir den bis dahin weitgehend plattformunabhängigen Rahmen undkonzentrieren uns auf die Microsoft-Welt.

� Das Kapitel 9 geht in dieser Hinsicht den umgekehrten Weg: Der Java Connec-tor (JCo) benötigt als Laufzeitumgebung nur die übliche Java Virtual Machineund ist dann auf allen Plattformen lauffähig. Er stellt für uns auch den Über-

Einleitung 13

gang in die oben angesprochenen modernen Technologien dar. Er ist z.B. Teilder Java Connector Architecture und damit der Anbindung von SAP an J2EE-Server.

Dabei sind die C/C++-Programmbeispiele in den Kapiteln 3 bis 6 auf Windows-2000-Betriebssystemen entwickelt worden, so dass bei Entwicklungen für anderePlattformen entsprechende Anpassungen vorgenommen werden müssen.

Wir hätten uns im Rahmen dieses Buches noch viele weitere Themen vorstellenkönnen. Gerade die aktuell viel zitierten Webservices liefern technologischgesehen eine echte Alternative zum RFC. Uns war jedoch an einer Fokussierungauf Themen gelegen, die man als »klassisch« in dem Sinn bezeichnen kann, dasssie für eine große Zahl an laufenden Systemen relevant sind. Webservices sindeine Option für die Zukunft; die zum jetzigen Zeitpunkt noch nicht abgeschlos-sene Konsolidierung der Standards und der Software ließen das Thema für diesesBuch – noch – nicht passend erscheinen.

Das Buch wendet sich primär an Entwickler, also an die Personen, die versuchenmüssen, aus den Ideen des Beraters ein »sauberes« Programm zu gestalten. Wirzeigen ihnen, welche Möglichkeiten zur Gestaltung von Schnittstellen zwischenR/3-System und externen Systemen bestehen. Wir wenden uns aber auch anBerater; sie müssen zwar nicht selbst ihr Konzept für eine Schnittstelle umsetzen,dennoch ist es in der Planungsphase häufig hilfreich, wenn man ein Gefühl dafürhat, welche Alternativen für die Realisierung von Schnittstellen bestehen.

Um Ihnen das leidige Abtippen der zahlreichen langen Beispiele zu ersparen, fin-den Sie den Quellcode der vollständigen Programme auf der Katalogseite zumBuch unter www.sap-press.de. Auf dieser Website finden Sie außerdem ein Forumzum Buch, in dem Sie sich mit anderen Lesern austauschen und mit den Autorenin einen fachlichen Kontakt treten können.

An der Entstehung eines Buches wie dem vorliegenden sind immer viele Men-schen direkt und indirekt beteiligt. Johannes Meiners dankt besonders Herrn Prof.Dr. Nowack von der Fachhochschule Münster, University of Applied Sciences, derihm den Zugang zu den dortigen SAP-Labors ermöglichte. Weiterhin geht seinDank an die Abteilungen Entwicklung und Technical Consulting der itelligenceAG, Bielefeld, für ihre hilfreiche Unterstützung bei der Beantwortung fachlicherFragen. Wilhelm Nüßer dankt im Besonderen der Heinz Nixdorf Stiftung, ohnederen großzügige Unterstützung ihm die Beteiligung an diesem Buch nicht mög-lich gewesen wäre, und der Fachhochschule der Wirtschaft (FHDW), Paderborn.Gemeinsam danken wir auch den Mitarbeitern von SAP – allen voran Herrn Tho-mas Becker –, die uns mit Rat und Tat zur Seite gestanden haben und derenUnterstützung wesentlich zur Fertigstellung des Buches beigetragen hat. Fernermöchten wir uns bei Florian Zimniak vom Verlag Galileo Press für die freundlicheBetreuung bedanken.

Grundlagen der RFC-Programmierung 117

4 Grundlagen der RFC-Programmierung

Im vorangegangenen Kapitel haben wir einfache externe Clients und Server ent-wickelt, die mit dem R/3-System Daten austauschen. In diesem Kapitel werdennun folgende Aspekte der RFC-API vertieft:

� Type-Mapping

� Umgang mit Datenaggregaten

� Nachrichtenschleife

4.1 Type-Mapping und Datenaggregate

Eines der gemeinsten Computergesetze von Murphy lautet:

»Programmieren ist wie Romanschreiben. Erst denkt man sich ein paarTypen aus, und dann muss man sehen, wie man mit ihnen zurechtkommt.«1

Damit Sie beim Umgang mit Datentypen in Zukunft weniger Probleme haben,sollen Ihnen die folgenden Abschnitte zeigen, welche Aspekte bei der Übertra-gung von Datentypen beachtet werden sollten. Behandelt werden dabei u.a.:

� Probleme bei der Übertragung von Strings

� Umgang mit gepackten Zahlen

4.1.1 Generische Datentypen

Dieser Abschnitt zeigt, was ein generischer Datentyp überhaupt ist und warum ernicht in einem RFC-fähigen Funktionsbaustein verwendet werden darf. Der Aus-gangspunkt für unsere Überlegungen ist die Anforderung, den Namen eines Kun-den von einem R/3-System an ein externes Programm zu senden.

Der gestandene ABAP-Entwickler könnte der Versuchung erliegen, in der Schnitt-stelle des Funktionsbausteins einfach einen zusätzlichen Exporting-Parameter mitdem Datentyp c zu deklarieren. Aber Halt! Versuchen Sie im Anschluss an dieDefinition des Parameters den Funktionsbaustein zu übersetzen, erscheint fol-gende seltsame Fehlermeldung: Beim RFC sind keine generischen Typen zugelassen.

Was wurde falsch gemacht? Schließlich ist es in einem normalen Funktionsbau-stein zulässig, eine Variable mit dem Datentyp c zu deklarieren. Die Antwort aufdieses Phänomen soll die Betrachtung eines in ABAP geschriebenen Unterpro-gramms geben.

1 Dieses und die in späteren Kapiteln zitierten Computergesetze sind entnommen aus: Graf,Joachim: Murphy’s gemeinste Computergesetze. Markt+Technik 1998.

118 Grundlagen der RFC-Programmierung

Wenn an einen ABAP-Entwickler die Anforderung gestellt wird, ein Unterpro-gramm zu entwickeln, das die Länge eines Strings ausgibt, würde er in etwa fol-gendes Unterprogramm entwerfen:

FORM write_string_length USING VALUE(ip_string) TYPE c.DATA: lp_size TYPE i.lp_size = strlen( ip_string ).WRITE: / 'Die Länge des Strings ist: ', lp_size.

ENDFORM.

Werden in einem ABAP-Report zwei Variablen des Typs c deklariert, kann dasobige Unterprogramm ohne weiteres die Länge der Strings ermitteln.

REPORT zprintstrlen.DATA: Vorname(20) TYPE c VALUE 'Luke'

, Nachname(40) TYPE c VALUE 'Skywalker'.START-OF-SELECTION.PERFORM write_string_length USING Vorname.PERFORM write_string_length USING Nachname.

Es ist erstaunlich, dass das Programm einwandfrei funktioniert. Für den Typ c, derin der Schnittstelle des Unterprogramms definiert wurde, ist die Standardgrößeein Byte. Er kann somit nur ein Zeichen aufnehmen. Die Variablen Vorname undNachname sind aber 20 bzw. 40 Zeichen groß. Dennoch wird die korrekte Längedes Vor- und Nachnamens ausgegeben.

Dies liegt daran, dass die Variable des Typs c tatsächlich in der Schnittstelle desUnterprogramms nicht vollständig definiert wurde. Die Größe der Variablenwurde nicht festgelegt. Diese Art von Schnittstellenparametern bezeichnet manauch als generische Parameter. Bei einem generischen Schnittstellenparameterergänzt das SAP-System die fehlenden Eigenschaften zur Laufzeit selber, indemdie Eigenschaften vom Datentyp derjenigen Variable übernommen werden, diean das Unterprogramm zur Laufzeit übergeben wird. Der SchnittstellenparameterIP_STRING ist somit einmal 20 und einmal 40 Byte groß. Neben dem Typ c gehörenzu den generischen Schnittstellenparametern auch noch die numerischen Strings,die gepackten Zahlen sowie der Typ x.

Genau dasselbe Prinzip zur Ergänzung fehlender Typinformationen findet auchbei den Schnittstellenparametern in Funktionsbausteinen Anwendung. Hierergibt sich jedoch ein Problem, falls der Funktionsbaustein RFC-fähig ist. Beieinem RFC-Aufruf werden nur Bytes zwischen Sender und Empfänger übertragen,aber keine Informationen über Datentypen. Der Sender oder Empfänger einerBytefolge muss daher selbst wissen, wie er die Bytefolge zu interpretieren hat.Dies kann er aber nur, wenn er die Anzahl der übertragenen Variablen und ihreGröße kennt. Kann der Empfänger diese Informationen nicht selbst bereitstellen,

Type-Mapping und Datenaggregate 119

besteht die Gefahr, dass die Bytefolge falsch interpretiert wird und Daten falschverarbeitet werden. Deshalb müssen alle Schnittstellenparameter eines RFC-fähi-gen Funktionsbausteins voll qualifiziert sein. Voll qualifiziert bedeutet, dassDatentyp und Größe des Schnittstellenparameters eindeutig festgelegt sind.

Bei einem Integer-Parameter gibt es keine Probleme. Der Datentyp i besitzt inABAP die festgelegte Größe von vier Byte. Bei einem echten generischen Daten-typ gibt es dagegen folgende Möglichkeiten, ihn vollständig zu qualifizieren:

� Bezugnahme auf ein entsprechendes Tabellen- oder Strukturfeld, das diegewünschten Eigenschaften besitzt. Der Schnittstellenparameter referenziertmit LIKE auf das Feld der Tabelle oder Struktur.

� Bezugnahme auf ein Datenelement oder eine Domäne des Data Dictionary.Hier referenziert der Schnittstellenparameter mit dem Schlüsselwort TYPE aufdas Datenelement oder die Domäne.

4.1.2 Die Character-Datentypen

Der vorangegangene Abschnitt zeigte, was bei der Deklaration von Strings in derSchnittstelle eines Funktionsbausteins zu beachten ist. Wir betrachten nun, wel-che Probleme es bei der Übertragung von Zeichenketten geben kann.

Zu den Character-Datentypen gehören RFC_CHAR, RFC_NUM, RFC_DATE undRFC_TIME. Die drei letztgenannten Datentypen unterscheiden sich vom TypRFC_CHAR dahin gehend, dass die Strings nur numerisch sein sollten.

Das Übertragen eines einzelnen Zeichens ist unproblematisch. Client und Serversenden bzw. empfangen immer dasselbe Zeichen. Anders verhält es sich bei Zei-chenketten. Bei ihnen besteht das Problem primär darin, dass C/C++ und ABAPunterschiedliche Methoden zur Erkennung des Stringendes besitzen.

In C/C++ ist ein String eine Null-terminierte Zeichenkette. Eine Zeichenkette siehtsomit in C/C++ intern so aus:

Die Bedeutung der Null (\0) besteht darin, dass sie das Ende der Zeichenkettesignalisiert. Fehlt sie, erkennt C/C++ das Ende nicht.

In C/C++ gelten für die Arbeit mit Strings folgende Regeln:

� Strings sind mit einer Null zu terminieren.

� Die Größe des Character-Felds ist die Summe aus der Anzahl der Zeichen pluseins für die abschließende Null. Soll der Vorname 30 Zeichen umfassen, ist dasentsprechende Character-Feld 31 Zeichen groß.

S t r i n g \0

120 Grundlagen der RFC-Programmierung

� Character-Felder müssen immer typengerecht mit NULL initialisiert werden, daim Allgemeinen in C/C++ keine automatische typengerechte Initialisierungstattfindet.

Dies gilt für ABAP jedoch nicht. Dort gelten folgende Regeln:

� Die Größe des Strings wird allein durch die Länge des Wertes determiniert, derin ihm gespeichert werden soll. Eine Variable Vorname, die zehn Zeichenumfassen soll, wird in ABAP deklariert als:

data: Vorname(10) type c.

� Eine Zeichenkette besitzt als Initialwert immer den Wert ' ' – sprich Space.Dieses Zeichen entspricht dem Wert 20hex in der ASCII-Tabelle.

Diese Regeln lassen folgende Schlüsse zu:

� In ABAP und C/C++ werden Strings, die Werte gleicher Größe speichern sollen,eine unterschiedliche Größe aufweisen, weil in C/C++ noch ein extra Byte fürdie abschließende Null benötigt wird.

� ABAP interpretiert das Stringende-Kennzeichen Null als #. C/C++ hingegensieht das Zeichen ' ' nicht als Stringende-Kennung an.

Dies hat gravierende Folgen, wenn Strings zwischen einem SAP-System undexternen C/C++-Programmen zu übertragen sind:

� Wenn ein mit einer Null initialisierter String von einem C/C++-Client an einSAP-System gesendet wird, werden die Nullen als # interpretiert, falsch in denABAP-String übernommen und später falsch in die Datenbanktabelle geschrie-ben.

� Wird umgekehrt ein String von einem SAP-System an einen externen C/C++-Server gesendet, erkennt dieser das Ende der Zeichenfolge nicht, weil dasASCII-Zeichen ' ' (Space) nicht der Stringende-Kennung in C/C++ entspricht.

� Das gravierendste Problem ist jedoch die Byteverschiebung nach rechts (Stringwird von einem C/C++-Programm zum SAP-System gesendet) bzw. links(String wird vom SAP-System an ein externes C/C++-Programm gesendet), dieeine falsche Zuordnung der Daten bewirkt.

Um den letzten Punkt zu verdeutlichen, nehmen wir an, dass von einem externenC/C++-Client der Vor- und Nachname einer Person an ein R/3-System gesendetwerden soll. Der Vor- und Nachname soll jeweils fünf Zeichen umfassen. DerC/C++-Entwickler wird in seinem Programm eine Struktur anlegen, die wie folgtdefiniert ist:

Type-Mapping und Datenaggregate 121

struct _PERSONENDATEN{char Vorname[6],

Nachname[6];}

Die Größe der Struktur ist zwölf Byte. Die entsprechende ABAP-Definition siehtjedoch so aus:

TYPES: BEGIN OF st_Personendaten, Vorname(5) TYPE c, Nachname(5) TYPE c

, END OF st_Personendaten.

Die ABAP-Struktur ist somit nur zehn Byte groß. Sendet ein externer Client Datenvom Typ Personendaten an das SAP-System, geschieht das, was in Abbildung 4.1dargestellt ist.

Abbildung 4.1 Byteverschiebung nach rechts

Die Rechtsverschiebung ist deutlich zu erkennen. Das sechste Byte des Vor-namens mit der Stringende-Kennung \0 im C/C++-Client wird auf das erste Bytedes Nachnamens im ABAP-Server verschoben und dort als # interpretiert, wäh-rend das fünfte Byte des Nachnamens mit dem Wert r gar nicht mehr im ABAP-Server auftaucht. Es wird einfach abgeschnitten.

0

D

0

D a r t h V a d e r \0\0

1 2 3 4 5 0 1 2 3 4 5

1 2 3 4 5 0 1 2 3 4 5

a r t h # V a d e

1 2 3 4 0 1 2 3 4

122 Grundlagen der RFC-Programmierung

Das Problem der Byteverschiebung ist nicht nur auf Strukturen mit Zeichenkettenbeschränkt, sondern tritt immer dann auf, wenn in Client und Server die Datenunterschiedliche Größen besitzen.

Wie können nun die Probleme bei der Übertragung von Strings und Strukturen,die Strings enthalten, gelöst werden? Am sinnvollsten ist es, wenn Sie im C/C++-Programm mit zwei Stringvariablen oder Strukturen arbeiten. Die erste String-variable genügt den Anforderungen an einen String in einem C/C++-Programm,während die zweite Stringvariable den Anforderungen an einen String in einemABAP-Programm entspricht. Dies bedeutet:

� Die Stringvariable im C/C++-Format besitzt immer eine Feldgröße, die dieSumme aus der maximalen Länge der aufzunehmenden Zeichenkette plus einsfür die Stringende-Kennung ist.

� Die Stringvariable im C/C++-Format wird immer mit einer Null initialisiert.

� Die Stringvariable im ABAP-Format besitzt immer eine Feldgröße, die gleichder maximalen Länge der aufzunehmenden Zeichenkette ist.

� Die Stringvariable im ABAP-Format wird immer mit ' ' (Space) initialisiert.

In einem externen Client nimmt die Stringvariable im C/C++-Format alle zu über-tragenden Werte vom Anwender entgegen. Vor der Übertragung der Daten wer-den die Werte auf den String im ABAP-Format kopiert. Umgekehrt gilt für einenC/C++-Server, dass die Stringvariable, die den Anforderungen an das ABAP-For-mat genügt, die Zeichenkette als Erstes empfängt und im zweiten Schritt dieDaten auf den String im C/C++-Format überträgt.

Durch dieses Vorgehen wird Folgendes sichergestellt:

� Es kommt zu keiner Byteverschiebung, weil der an das SAP-System zu sen-dende String im C/C++-Programm die gleiche Größe besitzt wie im SAP-Funk-tionsbaustein.

� Es werden keine fehlerhaften Werte für die Stringende-Kennung Null über-tragen. Der String, der an das SAP-System gesendet wird, ist ja mit Space initia-lisiert.

� Der externe Client oder Server erkennt das Ende einer Zeichenkette immer.

4.1.3 Numerische Strings

Numerische Strings sind Zeichenketten, die nur aus Ziffern bestehen dürfen. InABAP gibt es dafür den Datentyp n. In einem ABAP-Programm wird überprüft, obeiner Variable vom Typ n ein numerischer Wert zugewiesen wurde. Ist dies nichtder Fall, entfernt das Programm den nicht numerischen Wert und füllt die Varia-ble mit führenden Nullen auf. Das nachfolgende Beispiel verdeutlicht dies:

Type-Mapping und Datenaggregate 123

REPORT ztestnumerisch.DATA: numerisch(5) TYPE n.START-OF-SELECTION.numerisch = '012A4'.WRITE: / numerisch.

Das Programm erzeugt die Ausgabe 00124. Das A wurde entfernt und der Stringmit führenden Nullen aufgefüllt, bis die definierte Länge des numerischen Stringserreicht wurde.

Leider existiert in C/C++ kein numerischer Datentyp. Selbst der Datentyp RFC_NUMder RFC-API ist nichts anderes als ein unsigned char, wie aus dem folgenden Aus-zug der Header-Datei deutlich wird:

typedef unsigned char RFC_CHAR.typedef RFC_CHAR RFC_NUM

Daher können einer Variable des Typs RFC_NUM alle ASCII-Zeichen zugewiesenwerden. Dies umfasst auch die nicht numerischen Zeichen. Damit ergeben sichfür die Übertragung von numerischen Strings zwei Fragen:

� Was geschieht, wenn einer Variablen mit Datentyp n in einem Funktionsbau-stein ein Wert zugewiesen wird, der nicht numerisch ist?

� Wie kann sichergestellt werden, dass ein externer Client in einem numerischenFeld auch nur numerische Werte speichert?

Zur Beantwortung der ersten Frage ergänzen wir die Schnittstelle unseres Funk-tionsbausteins Z_RFC_ADD um den Importing-Parameter IP_NUMC, der eine Längevon fünf Zeichen besitzt. In unserem externen Client fügen wir der Schnittstellen-beschreibung ebenfalls den Parameter hinzu. Zusätzlich weisen wir im Clientpro-gramm dem Parameter IP_NUMC den Wert 012A4 zu. Abschließend aktivieren wirden ABAP Debugger, indem im Feld TRACE der Wert D eingegeben wird.

Starten wir jetzt unser C-Programm, können wir im ABAP Debugger beobachten,dass der Variablen IP_NUMC im Funktionsbaustein der Wert 012A4 zugewiesenwird. Das A wird nicht gelöscht. Statt dessen wird im SAP-Funktionsbaustein dernicht numerische Wert in einer Variablen des Datentyps n akzeptiert. Dieser Wertwürde auch in einer Datenbanktabelle gespeichert werden.

Dieses Ergebnis ist nicht befriedigend. Die Problematik wird durch folgendeÜberlegung noch deutlicher. SAP pflegt in seinen Datenbanktabellen sehr häufigeinen Zeitstempel, d.h., das SAP-System speichert Datum und Uhrzeit der letztenDatensatzänderung. Das Datumsfeld ist vom Typ DATS. Beim Datentyp DATS han-delt es sich um ein acht Byte großes numerisches Feld. Ähnlich ist es mit der Zeit.

124 Grundlagen der RFC-Programmierung

Hierbei handelt es sich um eine Variable des Typs TIME. Der Typ TIME ist vom Typn mit der Größe sechs Byte.

In der RFC-API existieren für das Übertragen von Datums- und Zeitwerten dieTypen RFC_DATE und RFC_TIME. Ihre Definition lautet:

typedef RFC_CHAR RFC_DATE[8]typedef RFC_CHAR RFC_TIME[6].

Der Type RFC_CHAR ist, wie oben bereits erwähnt, definiert als:

typedef unsigned char RFC_CHAR .

Damit können auch in Variablen der Typen RFC_DATE und RFC_TIME alle ASCII-Zei-chen gespeichert werden. Somit ist es möglich, Zeit- und Datumsvariablen in derSchnittstelle eines Funktionsbausteins nicht numerische Werte über einenexternen Client zuzuweisen. Diese Werte würden auch falsch in einer Datenbank-tabelle gespeichert. Dies hat weit reichende Konsequenzen. Es kann zum Beispielnicht mehr festgestellt werden, wann welcher Datensatz geändert wurde. Dahermuss in einem externen Client sichergestellt werden, dass in einer Variablenumerischen Typs auch nur Ziffern gespeichert werden.

Leider verfügt die RFC-API über keine entsprechende Prüffunktion. Sie sindgezwungen, hier selbst eine zu entwickeln. Dies ist aber sehr schnell getan, wiedas nachfolgende Beispiel zeigt.

int IsStringNumeric(char *Numc, char **pos){

if(!Numc || !pos)return 1;

*pos = Numc;while(*pos && **pos != '\0'){

if(!isdigit(**pos))return 1;

(*pos)++;}return 0;

}

Listing 4.1 Beispiel für die Prüfung auf nicht-numerische Zeichen

Die Funktion IsStringNumeric erhält als Übergabewerte die Referenz auf den zuüberprüfenden String und eine Referenz auf eine Zeigervariable vom Typ Char. Inder letztgenannten Variable wird die Adresse des nicht numerischen Zeichenszurückgegeben, falls der String ein solches Zeichen enthält, ansonsten ist derWert null. Die Startadresse des zu überprüfenden Strings wird der Variablen pos

Type-Mapping und Datenaggregate 125

zugewiesen. Im Anschluss wird innerhalb einer Schleife für jedes Zeichen desStrings geprüft, ob es sich um ein numerisches Zeichen handelt. Für diese Prüfungwird die Bibliotheksfunktion isdigit verwendet.

4.1.4 Die Sache mit den gepackten Zahlen

Jeder ABAP-Programmierer hat schon einmal mit gepackten Zahlen in Form vonVariablen des Datentyps Quantity, Currency oder selbst definierten Variablen desDatentyps p zu tun gehabt. Dies sind in ABAP sehr beliebte Datentypen. Der Werteiner Variablen vom packed-Datentyp kann aufbereitet dargestellt werden, d.h.,es werden Trennzeichen für Dezimalstellen eingefügt. Dies ist bei Variablen mitdem Datentyp float nicht ohne weiteres möglich.

So wird der Wert 1000,25 von einer Variablen des Typs float ausgegeben als1,0002500000000000E+03, und von einer Variablen des Typs p decimals 2 als1.000,25.

Wenn aber eine Variable des Typs p decimals übertragen werden soll, tritt einProblem auf: Wie lautet das entsprechende Pendant zum packed-Typ auf der Seitedes externen Programms? Sehen Sie sich die Typen von C/C++ an, finden Sie dortkeinen entsprechenden Datentyp. Daher wollen wir jetzt klären, was gepackteZahlen sind und wie diese zwischen dem SAP-System und einem externen Pro-gramm ausgetauscht werden.

Gepackte Zahlen sind zunächst nicht anderes als Binary Coded Decimals (BCD).Eine gepackte Zahl wird somit in einem Feld des Datentyps unsigned byte darge-stellt, wobei jedes Byte genau zwei Dezimalziffern aufnimmt. Diese Besonderheitwird dadurch ermöglicht, dass bei gepackten Zahlen jede Dezimalziffer für sichbetrachtet und in eine binäre Darstellung übertragen wird.

Abbildung 4.2 Umwandlung von Dezimal- in BCD-Darstellung

Die Vierergruppe von Binärzahlen bezeichnet man auch als Tetrade. Da jedeTetrade vier Bit und der Datentyp Byte acht Bit umfasst, ist es möglich, in einemByte zwei Tetraden (2 * 4 Bits) und somit zwei Dezimalziffern zu verwalten. DieUmwandlung einer binär kodierten Zahl in eine Dezimalziffer ist dann ganz ein-fach (siehe Abbildung 4.3).

Der Dezimalwert 56

wird in gepackter Form dargestellt als 0101 0110

126 Grundlagen der RFC-Programmierung

Abbildung 4.3 Umwandlung von BCD- in Dezimaldarstellung

Welche umgewandelte Tetrade mit welcher Zehnerpotenz zu multiplizieren ist,hängt offensichtlich von der Position der Tetrade in dem Byte-Array ab.

Bleibt noch ein kleines Problem. Der Datentyp unsigned byte ist in der Dateisaprfc.h der RFC-API definiert als:

typedef unsigned char rfc_byte_t.

Daher verwaltet er leider keine binären Zahlen, sondern nur Dezimalzahlen imBereich von 0 bis 255 oder Character-Zeichen gemäß dem ASCII-Zeichensatz.Daher muss die binäre Darstellung der gepackten Zahl noch – als Ganzes – in eineDezimalzahl umgewandelt werden. Der Vorgang ist in Abbildung 4.4 dargestellt.

Abbildung 4.4 Umwandlung von Dezimalwert in eine BCD-Zahl

Es sei nochmals betont, dass der Wert 86 zwei binär kodierte Ziffern, nämlich 5und 6 repräsentiert.

Natürlich muss man als Entwickler nicht mehr selbst Routinen für die Konvertie-rung von gepackten Zahlen entwickeln, sondern kann hier auf folgende Funk-tionen der RFC-API zurückgreifen:

� RfcConvertCharToBcd

� RfcConvertBcdToChar

Die Funktion RfcConvertCharToBcd wandelt eine Zahl, die ihr in Form einesStrings übergeben wird, in ein entsprechendes Bytefeld um. Die Schnittstelle derFunktion ist:

0101 0110

5 x 101 + 6 x 100=56

01010110binär

wird zu 86

Type-Mapping und Datenaggregate 127

Die Funktion gibt eine Variable des Datentyps int zurück. Über den Wert derVariablen teilt die Funktion dem rufenden Programm den Status der Ausführungmit. Es werden folgende Werte zurückgegeben:

Der Aufruf der Funktion könnte so aussehen:

int main(int argc, char** argv){

RFC_RC rc = RFC_OK;rfc_byte_t Zahl[10];int iRC = 0,

iDecimals = 2;iRC = RfcConvertCharToBcd(

"1000.25", strlen("1000.25"),&iDecimals, Zahl, sizeof(Zahl));

return (int)rc;}

Listing 4.2 Aufruf der Funktion RfcConvertCharToBcd

Variable Bedeutung

*in Zeiger auf einen String, der die umzuwandelnde Zahl enthält. Eine Dezimal-zahl sollte der internen Darstellung einer Dezimalzahl entsprechen: Vorzei-chen an erster Stelle, Dezimalstellen durch einen Punkt getrennt.

in_len Länge des Strings

*pdecs Referenz auf die Variable, in der die Anzahl der Dezimalstellen hinterlegt ist

*out Referenz auf ein Feld, in dem die BCD-Darstellung der Zahl gespeichert wird

out_len Bytegröße des Felds

int Rückgabewert der Funktion

Tabelle 4.1 Schnittstelle der Funktion RfcConvertCharToBcd

Rückgabewert Bedeutung

0 Funktion wurde erfolgreich ausgeführt.

2 Die Größe des Felds zur Speicherung der BCD Darstellung der Zahl ist zu klein.

3 Der umzuwandelnde String enthält keine gültige Zahl.

4 Die Länge des Strings ist falsch.

Tabelle 4.2 Rückgabewerte der Funktion RfcConvertCharToBcd

128 Grundlagen der RFC-Programmierung

Das Gegenstück zur Funktion RfcConvertCharToBcd ist RfcConvertBcdToChar. DieFunktion RfcConvertBcdToChar wandelt ein Bytefeld in die entsprechende Dezi-maldarstellung der Zahl um, wobei die Dezimaldarstellung in einem Stringzurückgeben wird. Der Wert in dem String kann im Anschluss unter Anwendungder Funktion atof einer Variablen des Typs float zugewiesen werden. Die Funk-tion RfcConvertBcdToChar besitzt die folgende Schnittstelle:

Auch bei der Funktion RfcConvertBcdToChar enthält der Rückgabewert Informa-tionen über den Status der Ausführung der Funktion. Die Funktion kann folgendeWerte zurückgeben:

Die Funktionen RfcConvertCharToBcd und RfcConvertBcdToChar basieren auf denFunktionen str2nbcd und nbcd2str, die vom RFC-Code angelegt werden.

Schaut man sich die Funktionen RfcConvertCharToBcd und RfcConvertBcdToCharan, ist festzustellen, dass sie einen String in eine gepackte Zahl umwandeln bzw.die Dezimalform einer gepackten Zahl in einen String zurückgeben. Daher stelltsich bei Eigenentwicklungen die Frage, ob es nicht sinnvoller ist, dass die betei-ligte ABAP-Softwarekomponente die Konvertierung einer gepackten Zahl in einenString vornimmt und der externen Softwarekomponente den String übergibt.

Variable Bedeutung

*in Feld des Typs RFC_BCD mit der BCD-Darstellung der gepackten Zahl

in_len Bytegröße des Felds

decs Anzahl der Dezimalstellen der gepackten Zahl

*out Referenz auf einen String, in dem die Dezimaldarstellung der gepackten Zahl zurückgegeben wird

out_len Bytegröße des Strings

int Rückgabewert der Funktion

Tabelle 4.3 Schnittstelle der Funktion RfcConvertBcdToChar

Rückgabewert Bedeutung

0 Funktion wurde erfolgreich ausgeführt.

2 Die Länge des Strings reicht nicht aus, um in ihm die Dezimaldarstellung der gepackten Zahl zu speichern.

3 Der Wert im BCD-Feld stellt keine Zahl dar.

4 Die Größe des Bytefelds ist falsch.

Tabelle 4.4 Rückgabewerte der Funktion RfcConvertBcdToChar

Type-Mapping und Datenaggregate 129

Dies würde aber dem Gedanken, dass die an einer Client-Server-Beziehung betei-ligten Softwarekomponenten weitgehend autonom sein sollen, widersprechen. InSinne der Autonomie ist es besser, wenn die Softwarekomponenten die Datenmit ihrem originären Datentyp – sprich dem Datenbankdatentyp – austauschen.Sollte eine der beteiligten Softwarekomponenten den Datentyp nicht verarbeitenkönnen, muss sie selbst für die Konvertierung in einen Datentyp sorgen, den sieverarbeiten kann. Sie sollte sich nicht darauf verlassen, dass ihr die Aufgabe durchdie Drittsoftwarekomponente abgenommen wird.

4.1.5 Abschließende Übersicht über das Type-Mapping

Mit einer Übersicht über das Mapping von RFC-Datentypen auf ABAP-Datentypenund über dasjenige von RFC-Datentypen auf häufig verwendete Datenbankdaten-typen werden die Betrachtungen über das Type-Mapping abgeschlossen.

ABAP-Datentyp

Bedeutung RFC-Datentyp

c Zeichen (Character) RFC_CHAR

d Datum (Date, Darstellung im Format YYYYMMDD)

RFC_DATE

f Gleitpunktzahl (Float) RFC_FLOAT

i ganze Zahl (Integer) RFC_INT

n numerischer String RFC_NUM

p BCD-Zahl RFC_BCD

string Zeichenfolge (String) in Schnittstellen von Funktions-bausteinen nicht zulässig

t Zeitpunkt (Time, Darstellung im Format HHMMSS)

RFC_TIME

x Byte (Hexadecimal) RFC_BYTE

xstring Bytefolge (X-String) in Schnittstellen von Funktions-bausteinen nicht zulässig

Tabelle 4.5 Mapping zwischen ABAP- und RFC-Datentypen

Datenbank-datentyp

Bedeutung RFC-Datentyp

ACCP Buchungsperiode JJJJMM RFC_CHAR

CHAR Zeichenfolge RFC_CHAR

Tabelle 4.6 Mapping zwischen Datenbank- und RFC-Datentypen

130 Grundlagen der RFC-Programmierung

4.2 Der Umgang mit Strukturen

Unsere bisherigen externen Client- und Serverprogramme waren recht einfachgestrickt, da sie auch nur einfache Datentypen mit dem R/3-System austauschen.Leider werden in der Realität nur sehr selten einzelne Variablen ausgetauscht.Statt dessen werden meistens ein oder mehrere Datensätze (Strukturen) ge-sendet. Wie Sie Datensätze austauschen können, wird im Folgenden dargelegt.

Das Übertragen einer Struktur wird anhand eines Beispielprogramms vorgestellt.Das Ziel ist die Übertragung eines Kundenstammdatensatzes von einem R/3-Sys-tem zu einem externen Programm. Im Clientprogramm wird die Kundennummerdes Kunden erfasst, für den die Stammdaten aus dem R/3-System zu lesen und anden Client zu übertragen sind.

Für den SAP-Teil des Beispiels verwenden wir den FunktionsbausteinZ_RFC_GET_SINGLE_CUSTOMER, der bereits vorgestellt wurde. Wir müssen somit nur

CLNT Mandant RFC_CHAR

CUKY Währungsschlüssel, wird von CURR-Feldern referiert

RFC_CHAR

CURR Währungsfeld, abgelegt als DEC RFC_BCD

DATS Datumsfeld (JJJJMMDD), abgelegt als CHAR(8)

RFC_DATE

DEC Rechen- oder Betragsfeld mit Komma und Vorzeichen

RFC_BCD

FLTP Gleitpunktzahl mit acht Byte Genauigkeit RFC_FLOAT

INT1 1-Byte-Integer RFC_INT1

INT2 2-Byte-Integer, nur für Längenfeld vor LCHR oder LRAW

RFC_INT2

INT4 4-Byte-Integer RFC_INT

LANG Sprachkennzeichen RFC_CHAR

NUMC numerische Zeichenfolge RFC_NUM

QUAN Mengenfeld, abgelegt als DEC RFC_BCD

RAW uninterpretierte Folge von Bytes RFC_BYTE

TIMS Zeitfeld (HHMMSS), abgelegt als CHAR(6) RFC_TIME

UNIT Einheitenschlüssel für QUAN-Felder RFC_CHAR

Datenbank-datentyp

Bedeutung RFC-Datentyp

Tabelle 4.6 Mapping zwischen Datenbank- und RFC-Datentypen (Forts.)

Der Umgang mit Strukturen 131

noch das externe Programm entwickeln. Damit ein externes Programm mit einemFunktionsbaustein eine Strukturvariable austauschen kann, müssen in diesemProgramm folgende zusätzliche Schritte ausgeführt werden:

� Im Programm muss eine Strukturdefinition angelegt werden. Die Definitionder Struktur muss mit der Strukturdefinition im R/3-System übereinstimmen.

� Die Beschreibung des Strukturaufbaus muss bei der RFC-API registriert wer-den.

� Die Strukturvariable muss als Parameter in der Beschreibung der Schnittstellefür den Datenaustausch bekannt gegeben werden.

Auf unser Beispiel bezogen bedeutet dies, dass wir die Struktur _RSCUSTOMERSAPanlegen. Sie besitzt den gleichen Aufbau wie die Datenbanktabelle ZKNA1JMS imData Dictionary. Die Struktur wird benutzt, um die Kundenstammdaten mit demR/3-System auszutauschen. Aufgrund der geschilderten Probleme mit Strings ver-wenden wir aber noch eine zweite Strukturdefinition. Die Struktur_RSCUSTOMEREXT besitzt die gleichen Felder wie die Struktur _RSCUSTOMERSAP,jedoch sind die CHAR-Felder alle um ein Byte größer, sodass auch das Stringende-Kennzeichen \0 gespeichert werden kann. Die Struktur _RSCUSTOMEREXT wird ver-wendet, um die empfangenen Daten weiterzuverarbeiten. Die Struktur_RSCUSTOMERSAP ist definiert als:

typedef struct _RSCUSTOMERSAP{ RRC_CHAR MANDT[3]; RFC_CHAR KUNNR[10]; RFC_CHAR NAME1[35]; RFC_CHAR LAND1[3]; RFC_CHAR ORT01[35]; RFC_CHAR PSTLZ[10]; RFC_CHAR STRAS[35]; RFC_INT UMSEXP; RFC_CHAR WAERS[5]; RFC_CHAR TELF1[16]; RFC_CHAR TELFX[31];} RSCUSTOMERSAP;

Listing 4.3 Definition der Struktur _RSCUSTOMERSAP

Als Nächstes müssen wir eine Beschreibung des Strukturaufbaus anlegen und beider RFC-API registrieren. Das Anlegen einer Strukturbeschreibung beinhaltet,dass für jedes Feld der Struktur eine Beschreibung der technischen Eigenschaftenerfasst wird. Die technischen Eigenschaften werden dabei der Struktur im Data

132 Grundlagen der RFC-Programmierung

Dictionary entnommen. Die Beschreibung wird in einem Array des TypsRFC_TYPE_ELEMENT2 hinterlegt. Dieser Typ ist in der RFC-API definiert als:

Der Offset für ein Feld kann so berechnet werden:

Offset akt Feld = Offset Vorgänger

+ Bytegröße des Datentyps vom Vorgängerfeld

Sofern sich die Struktur in dem externen Programm auf eine Struktur im Data Dic-tionary bezieht, existieren folgende Optionen für die Ermittlung der Bytegrößedes Datentyps:

� In der Datenbanktabelle DD03L steht in dem Feld INTLEN für jedes Feld einerStruktur oder Tabelle die Bytegröße des zugrunde liegenden Datentyps.

� Im Data Dictionary können Sie sich über das Menü Hilfsmittel • Laufzeitobjektanzeigen u.a. eine Übersicht über die Eigenschaften der Felder einer Strukturoder Tabelle ansehen. In der Spalte DDLn ist die Bytegröße des Datentyps zusehen (siehe Abbildung 4.5).

Ferner kann dem Laufzeitobjekt für ein Data-Dictionary-Element auch direkt derOffset für ein Feld entnommen werden. Er steht in der Spalte Offs.

Für das Feld NAME1 der Struktur _RSCUSTOMERSAP sieht der Eintrag so aus:

RFC_TYPE_ELEMENT2 DESC_RS_CUSTOMER_SAP[11]DESC_RS_CUSTOMER_SAP[2].name = "NAME1"DESC_RS_CUSTOMER_SAP[2].type = TYPCDESC_RS_CUSTOMER_SAP[2].length = 35;DESC_RS_CUSTOMER_SAP[2].decimals = 0;DESC_RS_CUSTOMER_SAP[2].offset =

DESC_RS_CUSTOMER_SAP[1].offset+ DESC_RS_CUSTOMER_SAP[1].length;

Feld Bedeutung

name Name des Felds in der Data-Dictionary-Struktur des R/3-Systems

type Typ des Felds. Hier ist ein Wert des Aufzähltyps RFC_TYPE zu hinterlegen.

length Bytegröße des Felds

decimals Anzahl der Dezimalstellen

offset Distanz des Felds vom Beginn der Struktur in Byte

Tabelle 4.7 Aufbau der Struktur RFC_TYPE_ELEMENT2

Der Umgang mit Strukturen 133

Abbildung 4.5 Laufzeitobjekt der Tabelle ZKNA1JMS

Die Größe des Arrays entspricht der Anzahl der Felder in der Struktur. Unser Arraymuss elf Beschreibungen speichern, da die Tabelle ZKNA1JMS elf Felder umfasst.Das Anlegen der Strukturbeschreibung kann durch folgende Hilfsfunktion verein-facht werden:

RFC_TYPE_ELEMENT2 BuildTableElement(char* pName,int iType,int iLength,int iDecimalsint iOffset)

{RFC_TYPE_ELEMENT2 Element;Element.name = pName;Element.type = iType;Element.length = iLength;Element.decimals = iDecimals;Element.offset = iOffset;return Element;

};

Listing 4.4 Hilfsfunktion, um die Struktur RFC_TYPE_ELEMENT2 zu füllen

134 Grundlagen der RFC-Programmierung

Der Aufruf der Funktion sieht für das Feld NAME1 der Tabelle ZKNA1JMS so aus:

DESC_RS_CUSTOMER_SAP[2] = BuildTableElement("NAME1",TYPC, 35, 0,

( DESC_RS_CUSTOMER_SAP[1].offset+ DESC_RS_CUSTOMER_SAP[1].length) );

Im Anschluss an den Aufbau der Feldbeschreibung muss dieser gegenüber derRFC-API registriert werden. Dies geschieht durch die FunktionRfcInstallStructure2. Der Funktion müssen Werte für nachfolgende Variablenübergeben werden:

Wenn die Funktion RfcInstallStructure2 erfolgreich ausgeführt wurde, steht inder Variablen pTypeHandle dasjenige Handle, mit dem die RFC-API die Struktur-beschreibung verknüpft hat.

Zum Schluss muss die Strukturvariable RSCustomerSAP vom Typ RSCUSTOMERSAP inder Schnittstellenbeschreibung bekannt gegeben werden. Dies geschieht durchdas Eintragen der Strukturvariable in das Array ExpParam. Das Array nimmt alleVariablen auf, für die unser Programm Daten vom R/3-System empfangen kann.Wichtig ist, dass wir jetzt das durch die Funktion RfcInstallStructure2 ermit-telte Type-Handle im Feld type der Struktur RFC_PARAMETER übergeben.

Ruft das Clientprogramm jetzt den Funktionsbaustein Z_RFC_GET_SINGLE_CUSTOMER im R/3-System auf, steht in der Strukturvariable RSCustomerSAP derKundenstammdatensatz.

Das unten stehende Programmfragment ist ein Ausschnitt aus dem ProgrammGetCustomerSAP. Es zeigt nochmals die genannten Schritte, um eine Strukturvaria-ble als Austauschparameter anzulegen.

Variable Bedeutung

name Name der Struktur, mit der die Beschreibung verknüpft wird

elements Adresse des Arrays mit der Beschreibung des Feldaufbaus

entries Anzahl der Elemente in dem Feld

pTypeHandle Referenz auf eine Variable des Typs RFC_TYPEHANDLE. Die Variable nimmt das Type-Handle auf, mit dem die RFC-API die Feldbeschreibung ver-knüpft hat.

RFC_RC Rückgabewert der Funkion, der den Status der Ausführung signalisiert

Tabelle 4.8 Schnittstelle der Funktion RfcInstallStructure2

Der Umgang mit Strukturen 135

RFC_RC GET_CUSTOMER_FROM_SAP(RFC_HANDLE hConnection,RFC_ERROR_INFO_EX *pErrorInfo)

{ / *Deklaration der Variablen zum Aufnehmen der Daten von bzw. zum Senden an SAP */ : RSCUSTOMERSAP RSCustomerSAP; /* Deklaration der Arrays für die Importing- und Exporting-Parameter */ RFC_PARAMETER ImpParam[2] , ExpParam[2] ; /* zusaetzliche Deklarationen fuer Struktur */ RFC_TYPEHANDLE Tabletype; RFC_TYPE_ELEMENT2 DESC_RS_CUSTOMER_SAP[11]; : /* Aufbau der Feldbeschreibung für die Struktur _RSCUSTOMERSAP */ DESC_RS_CUSTOMER_SAP[0] = BuildTableElement ("MANDT", TYPC, 3, 0, 0); : /* Struktur bei der RFC-API registrieren */ if(( rc = RfcInstallStructure2 ("IS_CUSTOMER_DATA", DESC_RS_CUSTOMER_SAP, 11, &Tabletype)) != RFC_OK){

RfcLastErrorEx(pErrorInfo);return RFC_FAILURE;

}; /* Strukturvariable als Exporting-Parameter bekannt- geben */ ImpParam[0] = BuildSimpleParam("IS_CUSTOMER_DATA", /* Tabletype der Funktion RfcInstallStructure2 ueber- geben */ Tabletype, sizeof(RSCUSTOMERSAP), &RSCustomerSAP);

Listing 4.5 Anlegen einer Struktur als Importing-Parameter

Sie werden zurecht kritisch anmerken, dass das manuelle Anlegen der Beschrei-bung des Feldaufbaus für umfangreiche Tabellen und Strukturen sehr zeitintensivist. Daher wird in Kapitel 6 eine Lösung zur Automatisierung vorgestellt. An dieser

136 Grundlagen der RFC-Programmierung

Stelle wollen wir jedoch noch veranschaulichen, wieso diese Arbeit vor allem inkomplexeren Systemumgebungen unumgänglich ist. Dazu müssen wir noch ein-mal auf die oben beschriebenen Abbildungen des ABAP-Typsystems auf das RFC-System eingehen:

� Das ABAP-Typsystem wird vom SAP-Applikationsserver bereitgestellt und istdamit auf einer abstrakten Ebene plattformunabhängig.

� Die Plattformen, auf denen z.B. die Clients ausgeführt werden, haben jedochz.T. unterschiedliche Formen in der internen Darstellung von Daten. Hierzugehören natürlich die Größe der einzelnen Datentypen (z.B. haben 32-Bit-Platt-formen einen vier Byte großen Long-Typ) und die Anforderungen an die Aus-richtung (Alignment) von Daten. Es kann z.B. sein, dass eine Plattform fordert,dass Integer-Werte immer auf 4- oder gar auf 8-Byte-Grenzen ausgerichtet sind.

Für den Bereich der Netzwerk-Programmierung, die die RFC-Entwicklung ja letzt-lich ist, kommt zudem noch die so genannte Endian-Problematik hinzu. DieGrundentscheidung, die hier eine Rolle spielt und auf der Hardware-Ebene einerPlattform getroffen wird, betrifft die Anordnung der einzelnen Bytes innerhalbeiner Mehr-Byte-Variablen, z.B. einer 4-Byte-Integer. Auf vielen Plattformen wirddie auf den ersten Blick seltsam anmutende Form gewählt, dass das »unwich-tigste« Byte an vorderer Stelle im Speicher auftaucht (»Little Endian«). Dies istz.B. bei den Intel-Prozessoren der x86-Reihe so. Andere CPUs hingegen, wie z.B.die SUN-Sparc-Serie, speichern das wichtigste, d.h. höchstwertige Byte auch anvorderer Stelle im Speicher ab. Diese zunächst unscheinbare Tatsache kann aller-dings z.B. bei der Übertragung gemischter Datentypen – wie eben Strukturen –erhebliche Konsequenzen haben. Das folgende Beispiel zeigt zunächst die Big-Endian-Darstellung einer Struktur aus einer Integer-Variablen (hier mit Wert 4)und einer Zeichenvariablen (Wert 'a'):

Jedes Feld entspricht dabei einem Byte. In einer Little-Endian-Umgebung wäredas entsprechende Layout im Speicher:

Die Konvertierung einer solchen einfachen Struktur von einem Little-Endian-Sys-tem zu einem Big-Endian-System gelingt damit offensichtlich nur noch, wennInformationen über das Speicher-Layout mitgeliefert werden. Gerade dieseInformationen sind es, die bei der Anmeldung einer Struktur bei der RFC-API mit-gegeben werden.

0 0 0 4 'a'

4 0 0 0 'a'

Der Umgang mit internen Tabellen 137

4.3 Der Umgang mit internen Tabellen

Interne Tabellen werden eingesetzt, wenn zwischen einem externen Programmund einem SAP-Funktionsbaustein mehrere Datensätze auszutauschen sind. Diesist sehr häufig der Fall. Somit sind Kenntnisse im Umgang mit internen Tabellenauch für die RFC-Programmierung wichtig.

Um Ihnen den Umgang mit internen Tabellen zu demonstrieren, wird ein Modulentwickelt, das in der Lage ist, neue Kundenstammdaten an den Funktionsbau-stein Z_RFC_CREATE_NEW_CUSTOMER zu schicken. Der Funktionsbaustein schreibtdie Datensätze auf der Datenbanktabelle ZKNA1JMS fort.

Überlegen wir uns zunächst das Design des Moduls. Das Modul soll die Kunden-stammdatensätze inklusive ihrer Übertragung an das R/3-System verwalten. Esmuss daher intern den Aufbau der Schnittstelle für den Austausch der Daten mitdem SAP-Funktionsbaustein kapseln. Ferner muss das Modul Operationen zurManipulation der Datensätze von außen bereitstellen. Diese Funktionen für dieManipulation der Datensätze sind die eigentlichen Schnittstellen dieses Moduls.Zusätzlich muss das Modul die Definition der Struktur der Datensätze verfügbarmachen. Durch die Definition wissen Programmteile, die die Operationen desModuls aufrufen, wie die zu übergebenden Datensätze aussehen müssen. ZumAbschluss wird eine Operation benötigt, die die Daten an das SAP-System über-trägt.

An dieser Stelle beschränken wir uns auf die Realisierung der Funktionalität in C,um die Konsistenz zur bisherigen Darstellung zu wahren. Sicher liegt hier die Ver-wendung von C++ nahe. Eine entsprechende Implementierung in C++ finden Sieauf der zum Buch gehörenden Webseite auf www.sap-press.de.

Ein Designentwurf könnte wie folgt aussehen:

/* öffentliche Funktionen */RFC_RC Initialisation(void);RFC_RC AppendCustomer(RSCUSTOMEREXT *pCustomerExt,

RFC_ERROR_INFO_EX *pErrorInfo);RFC_RC InsertCustomer(char *KUNNR,

RSCUSTOMEREXT *pCustomerExt,RFC_ERROR_INFO_EX *pErrorInfo);

RFC_RC UpdateCustomer(char *KUNNR,RSCUSTOMEREXT *pCustomerExt,RFC_ERROR_INFO_EX *pErrorInfo);

RFC_RC DeleteCustomer(char *KUNNR,RFC_ERROR_INFO_EX *pErrorInfo);

138 Grundlagen der RFC-Programmierung

RFC_RC GetCustomer(char *KUNNR,RSCUSTOMEREXT* pCustomerExt,RFC_ERROR_INFO_EX *pErrorInfo);

RFC_RC SendDataToSAP(RFC_HANDLE *phConnection,RFC_ERROR_INFO_EX *pErrorInfo);

int GetIndexOfKunnr(char *KUNNR);int GetAnzRS(void)

{return ItFill(m_TableParam[0].ithandle);};

/* modul-interne Funktionen */void InitialMembers(void);void CreateInterface(void);RSCUSTOMERSAP ConvertDataFromExtToSAPFormat(

RSCUSTOMEREXT *pCustomerExt);RSCUSTOMEREXT ConvertDataFromSAPToExtFormat(

RSCUSTOMERSAP *pCustomerSAP);/* modul-interne Members *//* für die Tabellen-Parameter */static RFC_TABLE m_TableParam[2];

/* Verwalten von Kundennummer u. Tabellenindex */typedef struct{

char Kunnr[11];int iTableIndex;

}RSINDEXKUNNR;/* Array zur Verwaltung der Kundennummer und ihres

Index in der internen Tabelle */RSINDEXKUNNR RSIndexKunnr[600];

Listing 4.6 Definitionen der Komponenten des Moduls CreateCustomerSAP zum Austausch von Kundenstammdaten

Der oben vorgestellte Ansatz unterscheidet zwischen öffentlichen und modul-internen Funktionen und Variablen. Durch die Bezeichnung »modul-intern« wirdzum Ausdruck gebracht, dass die Funktionen nicht durch einen Client, der dasModul verwendet, benutzt werden können. Würde der oben vorgestellte Ansatzunter Windows als DLL umgesetzt, wären modul-interne Funktionen nicht in derDefinitionsdatei enthalten. Die Definitionsdatei sähe demnach folgendermaßenaus:

; RfcCreateCustomer.def Definitionsdatei für; exportierte FunktionenLIBRARY "RfcCreateCustomer"

Der Umgang mit internen Tabellen 139

DESCRIPTION "Bibliothek-Funktionen zur Kundenanlage"

EXPORTSInitialisationAppendCustomerInsertCustomerUpdateCustomerDeleteCustomerGetCustomerSendDataToSAPGetIndexOfKunnrGetAnzRS

Listing 4.7 Definitionsdatei unter Windows für das Modul CreateCustomerSAP

Im obigen Entwurf werden die auszutauschenden Tabellen im Array m_TableParamgekapselt. Die Funktion Initialisation dient zur Initialisierung des Moduls. Sieruft intern die Funktionen InitialMembers und CreateInterface für die Initiali-sierung des Moduls auf. Die Funktion CreateInterface baut die Beschreibung derSchnittstelle zum SAP-Funktionsbaustein auf. Für den Client ist es bequemer,über die Kundennummer auf den Kundenstammdatensatz zuzugreifen. Deshalbwurde die modul-interne Variable RSIndexKunnr eingeführt. Die Variable referiertauf die Struktur RSINDEXKUNNR. In der Struktur wird die Zuordnung von Kunden-nummer zum entsprechenden Tabellenindex verwaltet. Somit ist es möglich, dassden Funktionen AppendCustomer, InsertCustomer, UpdateCustomer, Delete-Customer und GetCustomer, die den Zugriff auf die Datensätze realisieren, an ihrerSchnittstelle die Kundennummer übergeben wird. Die Funktion SendDataToSAPbietet die Möglichkeit, die Daten an das SAP-System zu senden. Zum Schlusskann durch die Funktion GetIndexOfKunnr der Tabellenindex zu einer Kunden-nummer ermittelt werden.

4.3.1 Anlegen einer internen Tabelle in einem externen Programm

Alle Funktionen der RFC-API für die Arbeit mit internen Tabellen sind in der Dateisapitab.h definiert. Daher ist diese Datei zusätzlich in ein externes Programm ein-zubinden, das mit internen Tabellen arbeitet.

Um eine interne Tabelle in einem externen Programm anzulegen, sind folgendeSchritte erforderlich:

� Reservieren von Speicher für die interne Tabelle. In dem angeforderten Spei-cherbereich werden die Datensätze gespeichert.

140 Grundlagen der RFC-Programmierung

� Anlegen und Registrieren des Strukturaufbaus der Tabelle gegenüber der RFC-API

� Einfügen des Tabellenparameters in die Schnittstellenbeschreibung für denDatenaustausch

Die Allokation des Speichers erfolgt durch die Funktion ItCreate. Der Funktionmüssen Werte für die folgenden Variablen übergeben werden:

Wurde die Funktion ItCreate erfolgreich ausgeführt, gibt sie das Handle auf dieinterne Tabelle zurück. Das Handle bildet eine symbolische Verknüpfung zu demSpeicher, der für die Datensätze reserviert wurde. Seine Bedeutung veranschau-licht Abbildung 4.6.

Es wird deutlich, dass das externe Programm den Speicherbereich mit den Daten-sätzen der internen Tabelle nicht direkt verwaltet. Nur die RFC-API hat diesenZugriff auf den Speicherbereich. Möchte das externe Programm auf Datensätze indiesem Speicherbereich zugreifen, geht das nur über die Funktionen der RFC-API.Dazu muss das externe Programm das Tabellenhandle übergeben, durch das dieRFC-API den Speicherbereich identifiziert.

Das Pendant zur Funktion ItCreate ist die Funktion

int SAP_API ItDelete (ITAB_H itab)

Die Funktion ItDelete löscht alle Informationen bezüglich der durch das Tabel-lenhandle identifizierten internen Tabelle. Die Funktion gibt den Speicherplatz,den die Datensätze belegen, wieder frei. Danach wird der Eintrag für die Verwal-tungsinformationen der internen Tabelle gelöscht. Das Tabellenhandle ist nachder Ausführung der Funktion nicht mehr zu benutzen.

Variable Bedeutung

name Name, um die interne Tabelle in Trace-Dateien zu identifizieren

leng Bytegröße der Struktur. Sie wird mit dem sizeof-Operator ermittelt.

occu Anzahl der Datensätze, für die Speicher angefordert werden soll, wenn erst-malig ein Datensatz in die interne Tabelle eingefügt wird

Speichergröße = Anzahl der Datensätze * Bytegröße der Struktur

memo nur intern von SAP genutzt, muss mit 0 besetzt werden

ITAB_H Das Handle der Tabelle ist der Rückgabewert der Funktion.

Tabelle 4.9 Schnittstelle der Funktion ItCreate

Der Umgang mit internen Tabellen 141

Abbildung 4.6 Bedeutung des Tabellenhandles

Soll nur der Speicherplatz freigegeben werden, den die Datensätze in der inter-nen Tabelle belegen, ist folgende Funktion der RFC-API anzuwenden:

int SAP_API ItFree (ITAB_H itab)

Sie gibt nur den Speicherbereich frei, den die Datensätze belegen. Aber die Ver-waltungsinformationen der internen Tabelle werden nicht gelöscht. Die interneTabelle kann somit weiter genutzt werden, um zum Beispiel neue Zeilen anzu-hängen.

Nachdem die interne Tabelle angelegt wurde, müssen wir als Nächstes dieBeschreibung des Strukturaufbaus bei der RFC-API registrieren. Das Anlegen derBeschreibung des Feldaufbaus für Tabellen und seine Registrierung ist identischmit dem im vorigen Abschnitt geschilderten Verfahren für Strukturen. Es wirddaher hier nicht wiederholt.

Abschließend müssen wir noch die Schnittstellenbeschreibung für den Datenaus-tausch um die interne Tabelle ergänzen. Alle mit dem SAP-System auszutau-schenden Tabellen werden in einem Array des Typs RFC_TABLE verwaltet. Bei die-sem Typ handelt es sich um eine Struktur der RFC-API. Sie verfügt über denfolgenden Aufbau:

ExternesProgramm

BesitztHandle

RFC-API

Tabelle

Handle-Speicher

Adress-bereich

Speicher-bereich mit den Datensätzen

übergibt

greift auf den Speicherbereichzu

142 Grundlagen der RFC-Programmierung

Die Struktur RFC_TABLE wird für unser Beispiel in der Funktion CreateInterfacemit folgenden Werten belegt:

m_TableParam[0].name = "IT_CUSTOMER_DATA";m_TableParam[0].nlen = strlen("IT_CUSTOMER_DATA");m_TableParam[0].type = Tabletype;m_TableParam[0].leng = sizeof(_RSCUSTOMERSAP);m_TableParam[0].itmode = RFC_ITMODE_BYREFERENCE;m_TableParam[0].ithandle =

ItCreate("IT_CUSTOMER_DATA", sizeof(_RSCUSTOMERSAP),100, 0);

Listing 4.8 Aufbau der Schnittstellenbeschreibung für die Tabelle IT_CUSTOMER_DATA

Die Art der Übergabe der internen Tabelle wird durch den Wert im Feld itmodespezifiziert. Hier können folgende Werte angegeben werden:

Feld Bedeutung

name Name der Tabelle in der Schnittstelle des Funktionsbausteins

nlen Länge des Namens der Tabelle

type Handle auf die Beschreibung des Strukturaufbaus, mit dem die Tabelle verknüpft ist. Das Handle wird durch die Funktion RfcInstallStructure2 ermittelt.

leng Bytegröße der Struktur

ithandle Tabellenhandle – Rückgabewert der Funktion ItCreate

itmode Art der Datenübergabe zwischen SAP-System und externem Pro-gramm

newitab Flag zur Kennzeichnung, dass die Tabelle durch die RFC-API angelegt wurde

Tabelle 4.10 Aufbau der Struktur RFC_TABLE

Wert Bedeutung

RFC_ITMODE_BYREFERENCE Die Übergabe erfolgt als Referenzübergabe. Änderungen am Tabelleninhalt werden dem Client übermittelt.

RFC_ITMODE_BYVALUE Die Übergabe erfolgt als Wertübergabe. Änderungen am Tabel-leninhalt werden dem Client nicht übermittelt. Diese Art der Übergabe wird nur SAP-intern verwendet.

RFC_ITMODE_

KEEPALIVE

Diese Art der Übergabe wird nur SAP-intern verwendet.

Tabelle 4.11 Mögliche Werte des Felds itmode

Der Umgang mit internen Tabellen 143

4.3.2 Verwaltung von Datensätzen in einer internen Tabelle

Dieser Abschnitt beschreibt, wie die RFC-API die Datensätze in einer internenTabelle verwalten könnte. Zwar muss sich der Entwickler nicht mehr um dieProgrammierung der Verwaltung kümmern, dennoch sind Kenntnisse über dieInterna einer internen Tabelle wichtig für den richtigen Umgang mit ihr.

Eine interne Tabelle muss in der Lage sein, Datensätze mit unterschiedlichem Auf-bau und unterschiedlicher Größe zu verwalten. Schließlich können nicht nurKundenstammdaten an das SAP-System gesandt werden, sondern auch Auftrags-daten, die sicher einen anderen Aufbau als Kundenstammdaten besitzen. Die Ver-waltung von Daten mit unterschiedlichem Aufbau über eine gemeinsameProgrammierschnittstelle erfolgt am effektivsten in einem Feld des Datentypsvoid* – sprich: Zeiger des Typs void. Er besitzt die Eigenschaft, dass er die Adresseeiner Variablen mit einem beliebigen Datentyp speichern kann. Er erfüllt somitgenau die Bedingungen des von uns gesuchten Datentyps.

Eine Funktion zur Initialisierung eines Arrays vom Typ void* könnte wie untendargestellt programmiert sein.

typedef void* PVOID;PVOID *ArrayAnyType;int iRSSize = 0;void CreateArrayAnyType(int iAnzArgu, int iSizeOfRS){

ArrayAnyType = (void**)malloc(iAnzArgu);iRSSize = iSizeOfRS;for(int iArgC = 0; iArgC < iAnzArgu; iArgC++){

ArrayAnyType[iArgC] = NULL;}

}

Listing 4.9 Funktion zur Initialisierung eines Arrays des Typs void*

Die Funktion CreateArrayAnyType erhält als Übergabevariable die Anzahl deranzulegenden Datensätze sowie die Bytegröße des Datensatzes, der in ihr gespei-chert werden soll. Sie legt ein Feld von Zeigern des Typs void* an. Die Zeiger desTyps void nehmen später die Adresse des neu reservierten Speichers für dieeinzelnen Datensätze auf. Ferner wird die Bytegröße des Datensatzes in derglobalen Variable iRSSize gespeichert. Zum Schluss wird in einer Schleife derInhalt des Felds mit NULL initialisiert.

Wird die Variable iAnzArgu durch die Variable occu und die Variable iSizeOfRSdurch die Variable leng der Funktion ItCreate ersetzt, wird deutlich, dass die

144 Grundlagen der RFC-Programmierung

Funktion CreateArrayAnyType die Funktion ItCreate der RFC-API simuliert. Esfehlt lediglich die Variable name, da keine Einträge in eine Trace-Datei geschriebenwerden. Der Aufruf der Funktion CreateArrayAnyType sieht unter der Annahme,dass Datensätze des Typs RSCUSTOMERSAP gespeichert werden sollen, wie folgt aus:

CreateArrayAnyType(10, sizeof(RSCUSTOMERSAP));

Das Speichern und Auslesen von Datensätzen in dem Array zeigen die FunktionenInsertRS und GetRS.

void* InsertRS(int iIndex){

return ArrayAnyType[iIndex] = calloc(1, iRSSize);};void* GetRS(int iIndex){

return ArrayAnyType[iIndex];};

Die Funktion InsertRS erhält den Index zur Identifikation des Felds, in dem dieAdresse des neu angeforderten Speichers verwaltet werden soll. Sie reserviertSpeicher für den neu anzulegenden Datensatz über die Funktion calloc. DieAdresse der Speicherstelle wird zurückgegeben, sodass der Aufrufer der FunktionInsertRS den Inhalt der Speicherstelle manipulieren kann. Der Aufruf der Funk-tion sieht wie folgt aus:

RSCUSTOMERSAP *pCustomer = NULL; pCustomer = (RSCUSTOMER*)InsertRS(2);

Die Funktion InsertRS zeigt auch Ähnlichkeit mit der Funktion ItInsLine derRFC-API, die weiter unten noch besprochen wird.

Die Funktion GetRS zeigt zum Abschluss den Zugriff auf einen Datensatz. DerZugriff erfolgt über den Index zur Identifizierung des Felds, in dem die Adressedes Datensatzes gespeichert ist. Die Funktion GetRS gibt die Adresse der Spei-cherstelle zurück. Auch diese Funktion weist Ähnlichkeit mit der FunktionItGupLine der RFC-API auf.

Fassen wir die Erkenntnisse nochmals kurz zusammen:

� Eine interne Tabelle kann mit einem Array vom Typ void* verglichen werden.

� Das Anlegen einer internen Tabelle kann mit dem Anfordern von Speicher fürdas Array des Typs void* verglichen werden.

Der Umgang mit internen Tabellen 145

� Im Array werden die Adressen der Speicherstellen verwaltet, an denen sich dieDatensätze befinden.

� Den Zugriff auf die Adresse eines Datensatzes erhalten Sie über den Index.

� Ein neuer Datensatz wird in das Feld in der Art eingefügt, dass zur LaufzeitSpeicher für den Datensatz reserviert wird. Die Adresse der Speicherstelle wirdin der Variablen des Typs void* gespeichert. Diese ist ein Element des Arraysvom Typ void* und kann über ihren Index angesprochen werden.

4.3.3 Schreiben und Lesen von Datensätzen in eine interne Tabelle

Im vorangegangenen Abschnitt wurde die Verwaltung einer internen Tabellesimuliert, um ein besseres Verständnis des Begriffs »interne Tabelle« zu erlangen.Jetzt wollen wir die Funktionen der RFC-API für die Verwaltung von Datensätzenin internen Tabellen näher betrachten. Damit kehren wir wieder zu unseremModul CreateCustomerSAP zurück, dessen Aufgabe die Verwaltung von Kunden-stammdaten ist.

Das Modul sieht Operationen für den Zugriff auf die Kundenstammdaten vor.Dies sind die Funktionen AppendCustomer, InsertCustomer, UpdateCustomer,DeleteCustomer und GetCustomer. Die Funktionen AppendCustomer und Insert-Customer fügen neue Kundenstammdaten in die interne Tabelle ein. Der Unter-schied zwischen den beiden Funktionen besteht darin, dass AppendCustomer denneuen Datensatz an das Ende der internen Tabelle anhängt, während Insert-Customer den Datensatz an einer bestimmten Position einfügt. Die FunktionUpdateCustomer aktualisiert einen existierenden Datensatz und DeleteCustomerlöscht einen Datensatz. GetCustomer gibt einfach die Kundenstammdaten zurück.Diese Funktionen werden mit denen der RFC-API für das Verwalten von Daten-sätzen in internen Tabellen realisiert.

Um die Methoden AppendCustomer und InsertCustomer zu realisieren, werdendie Funktionen ItAppLine und ItInsLine der RFC-API benötigt. Die Definitionder Funktion ItAppLine lautet

void* SAP_API ItAppLine(ITAB_H itab);

Die Funktion ItAppLine hängt einen Datensatz an das Ende einer internen Tabellean. Sie benötigt als Übergabeparameter lediglich das Tabellenhandle, um dieinterne Tabelle zu identifizieren, an die der Datensatz angehängt werden soll.Konnte Speicherplatz für den Datensatz reserviert werden, gibt die Funktion dieAdresse der Speicherstelle zurück. Schlägt die Allokation des Speicherplatzes fehl,ist der Rückgabewert NULL.

146 Grundlagen der RFC-Programmierung

Die Funktion ItInsLine fügt einen Datensatz an einer bestimmten Stelle ein. DieSchnittstelle der Funktion ist der nachfolgenden Tabelle zu entnehmen:

Unter Anwendung der Funktion ItAppLine wird die Funktion AppendCustomer desModuls CreateCustomerSAP wie folgt realisiert:

RFC_RC AppendCustomer(RSCUSTOMEREXT *pCustomerExt,RFC_ERROR_INFO_EX *pErrorInfo)

{/* Prüfen, ob die Zeiger gültig sind */

if(!pCustomerExt || !pErrorInfo)return RFC_FAILURE;

void *pRow = NULL;/* neue leere Zeile an die interne Tabelle anhängen */

if(!(pRow = ItAppLine(m_TableParam[0].ithandle))){RfcLastErrorEx(pErrorInfo);return RFC_FAILURE;

}/* Daten in das SAP-Format übertragen

und Daten an die durch pRow bezeichneteSpeicherstelle kopieren */memcpy(pRow,

&(ConvertDataFromExtToSAPFormat(pCustomerExt)),sizeof(_RSCUSTOMERSAP));

return RFC_OK;}

Die Realisierung der übrigen Funktionen wird nicht mehr explizit dargestellt. Sieerfolgt analog und kann dem Programm CreateCustomerRFC auf der Webseitezum Buch entnommen werden.

Das Ändern und Löschen von Datensätzen erfolgt durch die FunktionenItGupLine und ItDelLine der RFC-API. Die Schnittstelle der Funktion ItGupLinelautet:

Variable Bedeutung

itab Tabellenhandle zur Identifikation der Tabelle, in die der Datensatz einzu-fügen ist

line Position, an der der Datensatz einzufügen ist

void* Rückgabetyp der Funktion – Adresse des reservierten Speicherbereichs

Tabelle 4.12 Schnittstelle der Funktion ItInsLine

Der Umgang mit internen Tabellen 147

Die Funktion ItGupLine gibt die Adresse der Speicherstelle des Datensatzeszurück. Der Inhalt der Speicherstelle kann somit durch das rufende Programmverändert werden.

Die Funktion zum Löschen von Datensätzen in einer internen Tabelle istItDelLine. Ihre Schnittstelle lautet:

Beim Löschen eines Datensatzes rücken alle nachfolgenden Datensätze um einePosition nach vorn. Besteht eine interne Tabelle aus drei Datensätzen und wirdder zweite gelöscht, wird aus dem dritten Datensatz der neue zweite.

Der lesende Zugriff auf einen Datensatz erfolgt durch die Funktion ItGetLine.Der Aufbau ihrer Schnittstelle lautet:

Variable Bedeutung

itab Tabellenhandle zur Identifikation der Tabelle, in der der Datensatz steht

line Index der Position, an der der Datensatz steht

void* Rückgabetyp der Funktion; Adresse der Speicherstelle, an der der Daten-satz steht

Tabelle 4.13 Schnittstelle der Funktion ItGupLine

Variable Bedeutung

itab Tabellenhandle zur Identifikation der Tabelle, in der der zu löschende Datensatz steht

line Index der Position, an der der Datensatz steht

int Rückgabetyp der Funktion, durch dessen Wert signalisiert wird, ob die Operation erfolgreich ausgeführt wurde. Es gilt:

Rückgabewert = 0: erfolgreiche Ausführung

Rückgabewert > 0: Datensatz existiert nicht

Rückgabewert < 0: unbekannter Fehler

Tabelle 4.14 Schnittstelle der Funktion ItDelLine

Variable Bedeutung

itab Tabellenhandle zur Identifikation der Tabelle, in der der zu lesende Datensatz steht

line Index der Position, an der der Datensatz steht

void* Rückgabetyp der Funktion – in ihm steht die Speicheradresse des Daten-satzes

Tabelle 4.15 Schnittstelle der Funktion ItGetLine

148 Grundlagen der RFC-Programmierung

Die Funktion ItGetLine soll gemäß der Dokumentation von SAP nur einen lesen-den Zugriff auf den Datensatz der internen Tabelle ermöglichen. Eine Modifika-tion des Speicherinhalts der zurückgegebenen Speicherstelle soll nicht auf dieinterne Tabelle zurückwirken. Dies ist jedoch nicht der Fall. Die FunktionItGetLine gibt ebenso wie die Funktion ItGupLine die Speicheradresse zurück, ander sich der Originaldatensatz in der internen Tabelle befindet. Damit wirkt eineVeränderung des Inhalts der Speicherstelle auch auf den Inhalt der internenTabelle zurück. Um richtig zu arbeiten, müsste die Funktion ItGetLine den Inhaltder Speicherstelle in einen neu angeforderten Speicherbereich kopieren und dieAdresse des neuen Speicherbereichs zurückgeben.

Folgende Funktion wird benutzt, um den Datensatz in einer internen Tabelle ineinen anderen Speicherbereich zu kopieren:

int SAP_API ItCpyLine (ITAB_H itab, unsigned line, void *dest)

Dabei wird der zu kopierende Datensatz über das Feld line identifiziert. Das Zieldes Kopiervorgangs wird im Feld dest angegeben. Das Tabellenhandle itab legtdie anzusprechende interne Tabelle fest.

Das Gegenstück zur Funktion ItCpyLine ist folgende der RFC-API:

int SAP_API ItPutLine (ITAB_H itab, unsigned line, void* src)

Die Funktion kopiert den Inhalt des durch src identifizierten Speicherbereichs aufden durch line angesprochenen Datensatz. Die Tabelle wird wieder durch dasTabellenhandle identifiziert.

Die Anzahl der Datensätze in einer internen Tabelle wird mit dieser Funktionermittelt:

unsigned SAP_API ItFill (ITAB_H itab)

Sie erhält als Argument das Handle der Tabelle. Die Funktion gibt die Anzahl derDatensätze in der durch das Handle identifizierten Tabelle zurück.

Mit folgender Funktion lässt sich ermitteln, wie viel Speicher für jeden Datensatzin der internen Tabelle angefordert wird:

unsigned SAP_API ItLeng (ITAB_H itab)

Ihr wird das Tabellenhandle zur Identifikation der internen Tabelle übergeben,und die Funktion gibt den Speicherbedarf zurück.

Die Nachrichtenschleife 149

4.3.4 Übersicht über die Funktionen für interne Tabellen

Die nachfolgende Tabelle zeigt nochmals die Funktionen zum Umgang mit inter-nen Tabellen in alphabetischer Übersicht.

4.4 Die Nachrichtenschleife

Die Nachrichtenschleife ist ein elementarer Bestandteil jedes externen Servers. Indiesem Abschnitt werden wir uns noch einmal mit den Möglichkeiten ihrerProgrammierung beschäftigen.

Bei unserem ersten Server in Kapitel 3 wurde schon darauf hingewiesen, dass zweiArten der Programmierung einer Nachrichtenschleife möglich sind:

1. Blocking-Modus

2. Polling-Modus

Der Blocking-Modus wurde im vorherigen Kapitel erläutert. Hier wird dieProgrammierung einer Nachrichtenschleife im Polling-Modus vorgestellt. Für dieProgrammierung einer Nachrichtenschleife in diesem Modus bietet die RFC-APIzwei Funktionen an:

Funktion Bedeutung

ItAppLine Anhängen einer Zeile an eine interne Tabelle

ItCpyLine Kopieren des Inhalts eines Datensatzes von einer internen Tabellen an einen durch dest angegebenen Speicherbereich

ItCreate Anlegen einer internen Tabelle

ItDelete Löschen einer internen Tabelle inklusive der Verwaltungsinformationen

ItDelLine Löschen eines Datensatzes aus der internen Tabelle

ItFill Anzahl der Datensätze in der internen Tabelle

ItFree Löschen aller Datensätze aus der internen Tabelle. Die Verwaltungs-informationen bleiben erhalten.

ItGetLine Rückgabe der Speicheradresse eines Datensatzes in der internen Tabelle

ItGupLine Rückgabe der Speicheradresse eines Datensatzes in der internen Tabelle

ItInsLine Einfügen eines Datensatzes in die interne Tabelle an der durch den Index angegebenen Position

ItLeng Bytegröße eines zu speichernden Datensatzes

ItPutLine kopiert den Inhalt der Speicherstelle src auf den durch Index identifizier-ten Datensatz

Tabelle 4.16 Funktionen zum Umgang mit internen Tabellen

150 Grundlagen der RFC-Programmierung

� RfcListen

� RfcWaitForRequest

Der Unterschied zwischen beiden Funktionen besteht darin, dass die FunktionRfcListen nur prüft, ob eine Nachricht vom SAP-System vorliegt, und mit demErgebnis der Überprüfung sofort zurückkehrt. Dabei sind drei Rückgabewertemöglich, die die folgende Bedeutung haben:

Der Nachteil der Funktion RfcListen besteht darin, dass sie – aufgrund der sofor-tigen Rückkehr – permanent überprüfen muss, ob eine Nachricht vom SAP-Sys-tem vorliegt. Der ausführende Prozess muss also ständig lauschen und wird nichtsuspendiert, wodurch die Systembelastung ansteigt. Wenn Sie sich hiervon über-zeugen möchten, sehen Sie sich beispielsweise unter Windows im Taskmanagerdie CPU-Nutzung eines Programms an, das eine Nachrichtenschleife mit derFunktion RfcListen realisiert.

Besser ist die Verwendung der Funktion RfcWaitForRequest. Die Schnittstelle derFunktion RfcWaitForRequest lautet:

Der Funktion wird somit zusätzlich das Zeitintervall übergeben, in dem sie aufNachrichten vom R/3-System wartet. Der Thread wird für die Dauer des Zeitinter-valls suspendiert. Er erhält somit keine CPU-Zeit zugeteilt, wodurch die Belastungdes Systems enorm zurückgeht. Das Zeitintervall wird dabei in Sekunden ange-geben. Die Rückgabewerte der Funktion RfcWaitForRequest sind identisch mitdenen der Funktion RfcListen.

Sehen wir uns an, wie die Programmierung einer Nachrichtenschleife im Polling-Modus aussieht:

Rückgabewerte Bedeutung

RFC_OK Eine Nachricht von einem SAP-System liegt vor.

RFC_RETRY Es liegt keine Nachricht vor.

RFC_FAILURE Fehler in der Kommunikation SAP-System/RFC-Server.

Tabelle 4.17 Mögliche Rückgabewerte der Funktion RfcListen

Variable Bedeutung

handle Verbindungshandle

wtime Zeitintervall, in dem auf eingehende Nachrichten vom SAP-Sys-tem gewartet werden soll

Tabelle 4.18 Schnittstelle der Funktion RfcWaitForRequest

Die Nachrichtenschleife 151

do{rc = RfcWaitForRequest(hConnection, 1);switch(rc){

case RFC_RETRY:{rc = RFC_OK;break;}

case RFC_OK:{if((rc = RfcDispatch(hConnection)) != RFC_OK){

RfcLastErrorEx(&ErrorInfo);printf("%s\n", ErrorInfo.message);

}break;

}case RFC_FAILURE:{

RfcLastErrorEx(&ErrorInfo);printf("%s\n", ErrorInfo.message);break;

}}while(rc == RFC_OK);

Listing 4.10 Nachrichtenschleife im Polling-Modus

Eine Nachrichtenschleife im Polling-Modus besteht im Wesentlichen aus einerDO-WHILE-Schleife Die DO-WHILE-Schleife wird durchlaufen, solange die Schleifen-kontrollvariable rc den Wert RFC_OK besitzt. Innerhalb der Schleife wird die Funk-tion RfcWaitForRequest aufgerufen. Die Funktion RfcWaitForRequest prüft, obeine Nachricht vom SAP-System vorliegt, und kehrt mit dem Ergebnis der Über-prüfung zurück.

Das Ergebnis der Abfrage wird in einer case-Anweisung ausgewertet. Liegt eineNachricht vor, wird die Funktion RfcDispatch aufgerufen, die ihrerseits die Call-back-Funktion ansteuert. Es sei explizit betont, dass die Funktion RfcWait-ForRequest nur überprüft, ob eine Nachricht vorliegt. Sie veranlasst nicht, dassdie Callback-Funktion angesteuert wird. Dasselbe gilt auch für die FunktionRfcListen.

Ein häufig geäußertes Argument gegen das Suspendieren eines Prozesses kriti-siert, dass Anfragen von SAP-Systemen nun nicht mehr sofort ausgeführt werden.Aber dieses Argument ist wenig stichhaltig, wenn Sie sich ansehen, wie gering diemaximale Verzögerung der Ausführung einer Anfrage von einem SAP-System ist.In unserem Beispiel würde die Verzögerung nur eine Sekunde betragen. Dies ist

152 Grundlagen der RFC-Programmierung

eine Zeitspanne, die in der Praxis für die meisten Einsatzzwecke vollkommenbelanglos sein dürfte.

Sollte die Zeitspanne für die Suspendierung des Prozesses von einer Sekundedennoch nicht akzeptabel sein, kann sie verringert werden, indem Sie die Funk-tion RfcListen in Kombination mit einer Betriebssystemfunktion für die Suspen-dierung des Prozesses verwenden. Unter Linux beispielsweise stehen die Funk-tionen sleep für die Suspendierung im Sekundenbereich und nanosleep für dieSuspendierung auf Nanosekunden-Ebene zur Verfügung. Im Bereich der Win-dows-Programmierung wird hierfür sehr häufig die Funktion SLEEP verwendet.Der SLEEP-Funktion suspendiert einen Thread für n Millisekunden. Die Modifizie-rung der Nachrichtenschleife sieht so aus:

do{rc = RfcListen(hConnection);switch(rc){

case RFC_RETRY:{/* Prozess fuer 300 Millisekunden suspendieren */

Sleep(300);rc = RFC_OK;break;

}:}

Listing 4.11 Suspendieren des Prozesses in einer Nachrichtenschleife, wenn keine Nachrichten des SAP-Systems vorliegen

Betrachtet man abschließend den Programmieraufwand, den eine Nachrichten-schleife im Polling-Modus verursacht, wird klar, dass er auch nicht wesentlichhöher als bei einer Nachrichtenschleife im Blocking-Modus ist. Somit ist deutlichgeworden, dass Nachrichtenschleifen im Polling- und Blocking-Modus gleich-wertig sind.

4.5 Alternativen für das Anmelden an ein R/3-System

Nun sollen noch einmal verschiedene Möglichkeiten für die Anmeldung an das R/3-System gezeigt werden. Vorgestellt werden:

� Arbeiten mit einer Konfigurationsdatei

� Load Balancing

� Funktion RfcOpen

Alternativen für das Anmelden an ein R/3-System 153

4.5.1 Arbeiten mit einer Konfigurationsdatei

Auch bei einem externen Client besteht die Option, mit der Konfigurationsdateisaprfc.ini zu arbeiten. Möchten Sie eine Konfigurationsdatei verwenden, ist indem String mit den Verbindungsargumenten für die Funktion RfcOpenEx das fol-gende Argument aufzunehmen:

dest=<Verweis auf Eintrag in der Datei saprfc.ini>

Mit diesem Wert liest die Funktion RfcOpenEx die Daten für die Verbindung ausder Datei, dabei werden alle anderen systemspezifischen Logon-Daten im Stringmit den Verbindungsdaten ignoriert. Das nachfolgende Beispiel zeigt, wie dieDatei saprfc.ini für die Anmeldung an einen bestimmten Applikationsserver auf-gebaut sein muss. Anstelle der IP-Adresse eines Applikationsservers kann übrigensauch ein vollständiger SAP Router-String verwendet werden.

DEST=RFCRECHNERTYPE=AASHOST=10.10.34.131SYSNR=01RFC_TRACE=0ABAP_DEBUG=0USE_SAPGUI=0

Für den Aufbau der Datei saprfc.ini existieren mehrere Optionen. Um sich überalle Optionen zu informieren, wird von SAP eine Musterdatei mit dem RFC-SDKausgeliefert. Unter Windows befindet sich die Datei im Verzeichnis \SAP\Front-End\SAPgui\rfcsdk\text.

Die Verbindungsargumente für die Verwendung der Datei saprfc.ini werden derFunktion RfcOpenEx wie folgt übergeben:

char ConParam[] = "DEST=RFCRECHNER CLIENT=099 "\"USER=<User> PASSWD=<Password> "\"LANG=DE ABAP_DEBUG=0

memset(&ErrorInfoEx, NULL,sizeof(RFC_ERROR_INFO_EX_EX));

if((hConnection = RfcOpenEx(ConParam, &ErrorInfoEx))== RFC_HANDLE_NULL){

printf("%s\n", ErrorInfo.message);rc = RFC_FAILURE;

}return rc;

154 Grundlagen der RFC-Programmierung

4.5.2 Arbeiten mit Load Balancing

Für die Nutzung des Load Balancings gibt es zwei Alternativen:

� Verwendung einer Konfigurationsdatei

� direkte Angabe der IP-Adresse des Rechners, auf dem sich der Message-Serverbefindet

Die Konfigurationsdatei heißt SAPMSG.INI. In der Datei ist der Name des Rech-ners hinterlegt, auf dem sich der Message-Server des SAP-Systems befindet.Unter Windows befindet sich die Datei im Verzeichnis C:\WINNT. Die folgendeTabelle zeigt, wie die Verbindungsargumente bei der Nutzung von Load Balancingzu spezifizieren sind, wenn mit der Datei SAPMSG.INI gearbeitet wird:

Wird die Verbindung über einen SAP Router hergestellt, ist der Wert für das Argu-ment r3name wie unten dargestellt aufzubauen:

r3name=<Name des SAP Routers><R/3-Systemname = Verweis auf einen Eintrag in der Datei SAPMSG.INI>

Dabei verweist die Angabe für den R/3-Namen auf einen Eintrag in der DateiSAPMSG.INI, die sich auf dem SAP Router befindet.

Auch für die Angabe des SAP Routers bietet SAP die Option, mit einer Konfigu-rationsdatei zu arbeiten. Der Name der Datei lautet SAPROUTE.INI. Unter Win-dows befindet sich die Datei ebenfalls im Verzeichnis C:\WINNT. Wird mit zweiKonfigurationsdateien gearbeitet, ist der Wert für das Argument r3name fol-gendermaßen aufzubauen:

r3name=<Verweis auf SAP Router in der Datei SAPROUTE.INI><R/3-Systemname = Verweis auf Eintrag in der Datei SAPMSG.INI>

Wird ohne eine Konfigurationsdatei gearbeitet, müssen folgende Verbindungs-argumente angegeben werden:

Argument Bedeutung

r3name Name des R/3-Systems. Zu dem Namen muss in der Datei SAPMSG.INI die Adresse des Rechners angegeben sein, auf dem sich der Message-Server befindet.

group optionale Angabe der Logon-Gruppe

Tabelle 4.19 Aufbau der Verbindungsargumente für das Load Balancing unter Anwendung von SAPMSG.INI

Alternativen für das Anmelden an ein R/3-System 155

Erfolgt die Herstellung der Verbindung über einen SAP Router, muss in dem Argu-ment mshost zusätzlich der Name des SAP Routers vorangestellt werden.

4.5.3 Arbeiten mit der Funktion RfcOpen

In Kapitel 3 wurde die Funktion RfcOpenEx für die Anmeldung an das R/3-Systemverwendet. An dieser Stelle soll ihr Vorgänger RfcOpen vorgestellt werden. DieFunktion soll zwar in neuen Projekten nicht mehr genutzt werden, dennoch wirdsie noch von SAP ausgeliefert.

Der Vorteil der Funktion RfcOpen liegt darin, dass die Verbindungsdaten in Struk-turen hinterlegt werden, sodass anhand der Namen der Strukturfelder sofortersichtlich ist, um was für eine Art von Information es sich handelt. Zudem wird inDialogfenstern mit Eingabefeldern gearbeitet. Eine Struktur bietet hier den Vor-teil, das Eingabefeld direkt mit dem Strukturfeld zu verknüpfen, was bei einemString nicht so ohne weiteres möglich ist.

Die Funktion RfcOpen verwendet für die Spezifizierung der Verbindungsdatenzwei Strukturen. In der ersten Struktur werden die benutzerabhängigen Verbin-dungsdaten gespeichert und in der zweiten die systemabhängigen.

Die Struktur für die benutzerabhängigen Verbindungsdaten ist RFC_OPTIONS. Sieverfügt über folgende Felder:

Argument Bedeutung

r3name Name des R/3-Systems

mshost Adresse des Rechners, auf dem sich der Message-Server befindet

group optionale Angabe der Logon-Gruppe

Tabelle 4.20 Aufbau der Verbindungsargumente für das Load Balancing ohne Anwendung von SAPMSG.INI

Felder Bedeutung

destination Verweis auf Eintrag in der Datei saprfc.ini

mode Art der Verbindung

connopt Verweis auf Struktur mit den Systemdaten für die Verbindung

client Client

user Anwender

password Passwort des Anwenders

Tabelle 4.21 Aufbau der Struktur RFC_OPTIONS

156 Grundlagen der RFC-Programmierung

In den Feldern client, user, password und language werden die anwenderspezi-fischen Logon-Daten hinterlegt. Durch das Feld trace wird die Protokollierungder aufgerufenen Funktionen und gesendeten Daten in einer Trace-Datei akti-viert.

Über das Feld mode wird gesteuert, auf welche Strukturvariable im Feld connopt zuverweisen ist. Die Strukturvariable enthält die Systemdaten. In der Praxis werdenzwei Modi häufig verwendet:

In diesem Abschnitt wird nur auf die Option RFC_MODE_VERSION_3 eingegangen,da sie das Load Balancing unterstützt. Bei der Option RFC_MODE_VERSION_3 wer-den die Systemdaten in einer Strukturvariable des Typs RFC_CONNOPT_VERSION_3übergeben. Der Aufbau der Struktur RFC_CONNOPT_VERSION_3 ist folgender:

language Anmeldesprache

trace Trace aktivieren

Modus Zusätzliche Struktur

RFC_MODE_R3ONLY RFC_CONNOPT_R3ONLY

RFC_MODE_VERSION_3 RFC_CONNOPT_VERSION_3

Tabelle 4.22 Häufig verwendete Modi für die Struktur RFC_OPTIONS

Feld Bedeutung

hostname IP-Adresse des Applikationsservers, falls die Anmeldung an einem bestimmten Applikationsserver erfolgen soll

sysnr Systemnummer

use_load_balancing Kennzeichen zur Festlegung, ob für die Anmeldung das Load Balancing verwendet werden soll. Ist der Wert ungleich null, wird das Load Balancing verwendet.

lb_host IP-Adresse des Applikationsservers, auf dem der Message-Server läuft

lb_system_name Systemnummer

lb_group Logon-Gruppe, an die man sich anmelden möchte

use_sapgui Kennzeichen, ob das SAP GUI aktiv sein soll

Tabelle 4.23 Felder der Struktur RFC_CONNOPT_VERSION_3

Felder Bedeutung

Tabelle 4.21 Aufbau der Struktur RFC_OPTIONS (Forts.)

Alternativen für das Anmelden an ein R/3-System 157

Das Feld use_load_balancing der Struktur RFC_CONNOPT_VERSION_3 entscheidetdarüber, ob die Load-Balancing-Option genutzt wird oder nicht. Wird LoadBalancing eingesetzt, ist im Feld lb_host die IP-Adresse des Applikationsserversanzugeben, auf dem der Message-Server läuft. Sollte das verteilte R/3-Systemzwar aus mehreren Applikationsservern bestehen, diese aber nicht zu Logon-Gruppen zusammengefasst sein, ist die Default-Logon-Gruppe NULL im Feldlb_group anzugeben. Ferner werden Angaben in den Feldern hostname und sysnrnicht berücksichtigt, sobald die Option use_load_balancing gesetzt wurde.

378 Index

Index

AABAP

= Operator 53CASE 56COMMIT WORK 61, 200DATA 50Datentypen 49DO 56Dump-Analyse 233ereignisgesteuert 48EXIT 57IF 55INSERT 60interne Tabelle 52, 57LOOP 57MESSAGE 186MODIFY 58MOVE-CORRESPONDING 54Namenskonventionen 69PARAMETERS 62READ 58ROLLBACK WORK 61SELECT 59START-OF-SELECTION 48Strukturen 51, 54Tabellentyp 52TYPES 51Typkonvertierung 53Variable 49vordefinierten Datentypen 50WHILE 57WRITE 48Zeitpunktanweisungen 48

ABAP Debugger 159Einzelschrittausführung 160interne Tabelle 161RETURN 160Step-Over-Ausführung 160Weiter 160

ABAP Dictionary 34ABAP Editor 33ABAP-Prozessor 18ActiveX-Controls 285, 354angestartete Server 99, 113API-Methoden

ActiveX-Controls 285

funktionsorientierter Zugriff 284Java Connector 286objektorientierter Zugriff 285

Applikationsserver 16, 17

BBAPI 274Binary Coded Decimals 125Blocking-Modus 103, 149Breakpoint 162

Break 162dynamischer 163

Business Application Programming Interface -> s. BAPI

Business Object Builder 266Business Object Builder, Funktionen

Fehlerliste 268Freigabestatus 268Parameter 268Programm 268

Business Object Repository 281Business-Objekt 257

Attribute 262BAPI 274BEGIN OF KEY 263BEGIN_DATA 263BEGIN_DATA_CLASS 263BEGIN_METHOD 270Element anlegen 269END OF KEY 263END_DATA 263END_DATA_CLASS 263END_METHOD 270END_PROPERTY 264Ereignisse 262Freigabezustände 281GET_PROPERTY 264instanzabhängige Methoden 270Interface 262Methoden 262Methoden-Aufbau 271Methoden-Implementierung 270Namenskonventionen 266Objektschlüssel 269Report zur Realisierung 262SAP Service Marketplace 286

Index 379

Schlüsselfelder 261, 269Schüsselfeld-Implementierung 270Sichtbarkeitsbereiche 260SWC_CREATE_OBJECT 271SWC_GET_ELEMENT 264, 265SWC_GET_TABLE 265SWC_SET_ELEMENT 264, 265SWC_SET_TABLE 265SWO_CREATE 271SWOCONT 264synchrone Methoden 270

Business-Objekt-MethodeAttribute einer Methode 275Funktionsbaustein 274halbautomatisches Anlegen 275Schnittstellenparameter 277vollautomatisches Anlegen 278

CCCell, Attribute 339Class Builder 35Column

Attribute 332Value 329

ColumnsAdd 331Insert 331Item 329Remove 331

COM 287ActiveX 289CDispImpl 301CoClass 288EnableAutomation 290GetCoClass 289IDispatch 300Invoke 300Schnittstelle 287Simulation 287, 288

com.sap.mw.jco 356Connection

Anwenderdaten 307Applikationsserver 307Ereignisse 310IsConnected 308, 312Load Balancing 307Logoff 294, 295, 312Logon 294, 312

Methoden 306sonstige Eigenschaften 308

Connection-String 79CORBA 24CPI-C 24, 25, 29CreateCustomer 325CreateThread 239CViewColumn

Attribute 338Methoden 349

CViewColumnsCell 341Item 341Value 341

CViewRowAttribute 337Cell 340Item 340Methoden 349Value 340

DData Browser 43, 45Data Dictionary 34Datenbankservice 16Datenelement 37Datentypen der RFC-API

RFC_OPTIONS 166, 167Dialoganwendungen 31Dialogprozess 18

ABAP-Prozessor 18Dynpro-Prozessor 19Taskhandler 19

Dispatcher 17Domäne 37

anlegen 38Dynpro 31Dynpro-Prozessor 19

EEarly Binding 341ECA-Prinzip 262Enqueue Prozess 21

Kommunikationswege 22Entwicklungsklasse 35Entwicklungsumgebung 32

ABAP Editor 33Class Builder 35

380 Index

Data Dictionary 34, 36Menu Painter 35Namenskonvention 35Object Navigator 33Screen Painter 35

EreignisseAuto-Reset-Ereignisse 245CloseHandle 246CreateEvent 245Manual-Reset-Ereignisse 245ResetEvent 246SetEvent 246

Exchange Infrastructure 374ExistenceCheck 313externer Client

Aufgaben 72Leistungsumfang 75Main-Funktion 76, 77Programmablaufplan 75

externer ServerAufbau der Callback-Funktion 104Aufgaben 97logischer Fehler 230, 231Main-Funktion 97Softwarekomponenten 96Systemfehler 230, 234

FFunktionen der RFC-API

RfcOpen 166RfcOpenEx 166

Funktionsbaustein 32Ablaufart 67Anlegen 62Schnittstelle 32, 65voll qualifizierte Schnittstellenparameter 119

FunktionsbausteineDESTINATION 201IN BACKGROUND TASK 200SO_DOCUMENT_SEND_API1 236TRFC_SET_QUEUE_NAME 220

Funktionsgruppe 32

GGateway Monitor 163

Liste der externen Clients 163registrierten Server 164

Gateway-Server 23, 25Gateway-Leser 25Gateway-Monitor 25Gateway-Workprozess 25

generischerDatentyp 117Parameter 118

gepackte Zahlen 125Binary Coded Decimals 125Currency 125Quantity 125

gepoolte Verbindungen 359

IImplementierung der Schnittstelle 85Instanz 258interne Tabellen 52, 57, 137, 149

Art der Übergabe 142CCreateCustomerSAP 145Datentyp void* 143Handle 140RFC_TABLE 141sapitab.h 139

JJ2EE 354Java 353

Eigenschaften 353Java 2 Enterprise Edition 354Java Connector 286, 353, 355

Anwendung 358Releases 358

Java Connector Architecture 354Java Native Interface 356Java Virtual Machine 354JavaBeans 354Java-Exceptions 371JCo -> s. Java ConnectorJCo-Anwendung 358

Ausführung der RFC-Module 361Fehlerbehandlung 371Verbindungsaufbau 359Zugriff auf Daten und Tabellen 364

JCo-Package 357Hilfsklassen 358Klassen 357

JNI 356JRFC 373

Index 381

KKlasse 258kooperative Betriebssysteme 238Kopplungstabelle 262kritischer Bereich

DeleteCriticalSection 247EnterCriticalSection 247InitializeCriticalSection 247LeaveCriticalSection 247TryEnterCriticalSection 247

LLate Binding 297, 315, 322, 341Load Balancing 27, 154, 156, 157Logical Unit of Work -> s. LUWLogon-Gruppe 27LUW 198, 200, 282

MMarshalling 373Menu Painter 35Message Server 17Message Service 27Microsoft .NET 353Microsoft Foundation Class 290Multithreading 238

NNachrichtenschleife 149

Blocking-Modus 103, 149Polling-Modus 103, 149, 151

Namenskonventionen 302Native SQL-Standard 16

OObject Navigator 33

Navigationsbereich 34Objektliste 34

objektorientierte Programmierung 257Open SQL-Standard 16

PParallelverarbeitung

Betriebssysteme 237echte 237externer Server 249kooperative Betriebssysteme 238Multithreading 238

nebenläufige 237präemptive Betriebssysteme 238Prozess 237

Polling-Modus 103, 149Polymorphismus 259, 260Pool-Manager 360präemptive Betriebssysteme 238Präsentationsebene 15Präsentationsserver 16

SAP GUI 16Process After Input 19Process Before Output 19Programmierschnittstelle 24Protokoll 23Proxy Objekt 297

Wrapper-Klasse 303, 305Prozess 237

suspendieren 238Prüffunktion 124

QQOUT Scheduler 216qRFC 213

Eingangsmonitor 219interne TID 226, 227, 228QOUT Scheduler 216Registrierung von Destinationen 217TRFC_GET_QIN_INFO_DETAILS 227TRFC_SET_QUEUE_NAME 220TRFCQSTATE 227Übersicht der Ausgangsqueues 218

Rregistrierte Server 113

Anmeldung an das SAP Gateway 99Remote Function Call -> s. RFCReport 31

anlegen 45Anweisung 47

Repository-Objekt 358RFC 19, 24, 29, 30

RFC-Bibliothek 29RFC Trace

Aktivierung 165externer Client 167Gateway Monitor 166Informationen 165Level 166

382 Index

Transaktion ST05 167, 170RFC/Verbuchungsinclude 94RFC_ONCALL 104RFC-API, Datentypen

Liste 87RFC_CHAR 119RFC_CONNOPT_VERSION_3 156RFC_DATE 119, 124RFC_ERROR_INFO 78RFC_HANDLE 79RFC_NUM 119, 123RFC_OPTIONS 155RFC_PARAMETER 85RFC_RC 78RFC_TABLE 86RFC_TID 205RFC_TIME 119, 124RFC_TYPE_ELEMENT2 132

RFC-API, FunktionenItAppLine 145ItCpyLine 148ItCreate 140ItCreate, Simulation 143ItDelete 140ItFill 148ItFree 141ItGupLine 144, 146ItInsLine 144, 146ItLeng 148ItPutLine 148RfcAccept 102RfcCall 89, 167RfcCallEx 183RfcCallReceive 88, 90, 167RfcCallReceiveEx 183RfcClose 84RfcConfirmTransID 210RfcConvertBcdToChar 128RfcConvertCharToBcd 126RfcCreateTransID 209RfcDispatch 103, 151, 169, 248, 256RfcExidToRfcType 192, 194RfcGetData 105, 169RfcGetStructureInfoAsTable 192RfcIndirectCallEx 209, 213RfcInstallFunction 108, 111RfcInstallStructure2 134RfcInstallTransactionControl2 206

RfcLastError 78RfcListen 150RfcOpen 155, 167RfcOpenEx 79, 81, 153RfcQueueInsert 224RfcRaiseErrorMessage 232RfcRaiseTable 232RfcReceive 90, 167RfcReceiveEx 183RfcSendData 106, 169RfcWaitForRequest 150

RFC-Clients 19RFC-Generator 171

Client-Testprogramm 174INS-Funktion 175LOG-Funktion 176OUT-Makro 175OUTS-Funktion 175Server-Testprogramm 176

RMI 24Row, Value 328Rows

Add 330Insert 330Item 328RemoveAll 331RemoveRow 331

RPC 24, 29Rückruf

an externen Client 189aus externem Server 183Destination BACK 190

SSAP BAPI-Control

Connection 292Datenaggregate 315Methoden 292Proxy-Objekt 292SAPBAPIControl 292SAPBusinessObject 293

SAP Connector 355SAP Gateway 99SAP GUI 16SAP J2EE-Engine 355SAP Logon-Control 305

Connection 306CRfcConnectionStatus 308, 313

Index 383

CSAPLogonControl 311Eventhandler 310Konfigurationsdatei 310SAPLogonControl 306

SAP Router 154SAP Service Marketplace 286SAP TableFactory-Control 317

Column 324, 328Columns 324, 328Datenaggregate 315Klassenhierarchie 317Row 324, 327Rows 324, 327Structure 317Table 317, 323, 344Tables 317View 324Views 324, 344

SAP TableView-ControlAnzahl Zeilen und Spalten 349beliebige Datenquelle 347CCell 336Cell 339, 340CopyToClipboard 352CViewColumn 335CViewColumns 335CViewRow 335, 340CViewRows 335, 340Datenquelle 344direkter Zugriff 340Ereignisse 350Eventhandler 342Klassenhierarchie 335PasteFromClipboard 352SAPTableView 324, 335Schreibschutz 338spaltenorientierter Zugriff 341Value 339, 340zeilenorientierter Zugriff 340Zugriff auf Zelle 339Zwischenablage 352

SAPBAPIControl 317Attribute 292Connection 293DimAs 315, 317, 321, 322GetSAPObject 298, 299, 301

sapjcorfc 356

SAPLogonControlEvents 311NewConnection 306

SAPMSG.INI 154SAPMSSY1 94

REMOTE_FUNCTION_CALL 94saprfc.h 76SAPRFC.INI 100, 101, 153, 155SAPROUTE.INI 154SAPTableFactory

Attribute 319CreateFromR3Repository 316, 321Methoden 318NewStructure 316, 321NewTable 316

SAPTableViewAttribute 337Events 343

SAP-TestprogrammeBatch-Datei 179Quelltexte 178rfcping.exe 91startrfc.exe 179Verzeichnis 178

SCODE 346Early Binding 346Visual Basic 346

Screen Painter 35Server 15ShowMultiCustomer 325Strings 119

numerische 122Structure

Attribute 320Value 319

Strukturbeschreibung 131Hilfsfunktion 133

Strukturen, ABAP 54SWO_TYPE_INFO_GET 301Synchronisation

Ereignisse 245, 252, 253kritischer Bereich 246, 252Nachrichtenschleife 252Synchronisationsarten 242Synchronisationsobjekt 242WaitForMultipleObjects 244WaitForSingleObject 244

384 Index

TTabelle 37

Eigenschaften pflegen 42Felder pflegen 43Tabellenpflege 43technischen Eigenschaften pflegen 44transparente 37

TableAppendRow 330Arten des Datenzugriffs 326Attribute 324Cell 326Columns 329Create 332CreateFromTable 331DeleteRow 331direkter Datenzugriff 326InsertRow 330Klassenhierarchie 324Refresh 345, 346, 347spaltenorientierter Datenzugriff 328Value 326zeilenorientierter Datenzugriff 327

Taschenrechnerfalsche Ergebnisse 92Funktionsbausteine 73remote Debuggen 92Softwarekomponenten 73Z_RFC_ADD 73

Taskhandler 19TCP-Sockets 29Thread

ExitThread 240Nachrichtenschleife 249, 251ResumeThread 239Suspend Count 239SuspendThread 239Synchronisation 242TerminateThread 240ThreadProc 239

Transaktion 282transaktionaler RFC 198

ARFCSDATA 201ARFCSSTATE 201LUW 198, 200Programmkontext 208SM58 202

TID 201tRFC-Server 203Verwaltung im SAP-System 201

Transaktionen 32Transportauftrag 35tRFC-Client 208

ARFC_DEST_SHIP 210tRFC-Server

logischer Fehler 234onCheckTIDEx 204onCommitEx 204, 205onConfimTIDEx 204onConfirmTIDEx 206onRollbackEx 204, 205Systemfehler 234

Typehandle 134Typkonvertierung, ABAP 53

UUnicode 30Unterprogramm, Schnittstelle 118User Memory 19

VVerbindungsargumente 79

benutzerspezifische Daten 80extra Attribute 81systemspezifische Daten 80

Verbindungsdaten pflegen 111Verbucher 20

asynchrone Verbuchung 21synchrone Verbuchung 21

Vererbung 258Views

Methoden 345Remove 347

WWebservices 30, 374Wertübergabe 74

ZZeichenketten

ABAP 120Byteverschiebung 120in C / C++ 119Übertragung 119, 120