Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Contents
1 About this document....................................................................................................................................................3
2 About SAPx ......................................................................................................................................................................4
3 Architectural overview.................................................................................................................................................5
3.1 RFC function architecture....................................................................................................................................... 6
3.1.1 Data representation........................................................................................................................................... 6
3.1.2 Data mapping.................................................................................................................................................... 7
3.1.3 Early and late function binding......................................................................................................................... 8
3.2 Client applications.................................................................................................................................................... 9
3.2.1 Using connection aliases ...............................................................................................................................10
3.2.2 Features of transactional calls .......................................................................................................................10
3.3 Server applications ................................................................................................................................................10
3.3.1 Using command line.......................................................................................................................................11
4 Installation.......................................................................................................................................................................12
4.1 System requirements ............................................................................................................................................12
4.2 Additional requirements ........................................................................................................................................12
4.3 Building SAPx binaries ..........................................................................................................................................13
4.4 Installing components ...........................................................................................................................................13
5 HowTo call ABAP function with SAPx ...............................................................................................................15
6 HowTo work with SAPx components................................................................................................................17
7 HowTo write a Server function with SAPx.......................................................................................................20
8 HowTo write a Server function with SAPx as NT service..........................................................................21
Appendix A – Data type and mapping............................................................................................................................23
Appendix B – Early and late function binding.............................................................................................................25
Appendix C – Defining server parameters....................................................................................................................26
Appendix D – Transaction management in SAPx server application..............................................................27
Appendix E – SAPx component list.................................................................................................................................30
Appendix F – Listing of SAPx client application........................................................................................................32
Appendix G – Listing of SAPx server as console application .............................................................................34
Appendix H – Listing of SAPx server as NT service ................................................................................................40
This document might be very useful for Borland Delphi developers in:
• Extending functionality of a SAP application server by creating external non-SAP server programs.
In this guide you will find a general overview of the software SAPx and its possible applications. This
document helps to understand the main architectural concepts of SAPx work: information on RFC
function architecture, different types of data mapping and function binding. You will also learn general
concepts of creating client and server applications based on SAPx. This guide provides the developer
necessary installation ins tructions and gives a brief overview of components installed.
Here are some practical suggestions “How to …”. They give process overviews of creating simple both
client and server applications and contains some recommendations how to use SAPx components
during design time as well as at run time.
If you need to get any additional information not mentioned in this guide do not hesitate to contact us:
2 About SAPx
SAPx is an object-oriented software library. It has been specially designed for access to SAP application
servers using Borland® Delphi™ and for building partner server programs run in non-SAP systems.
SAPx is a flexible and versatile tool for:
• Integration of existing Delphi™ applications with SAP systems. This feature allows corporations to
use their own information systems and create superstructures offering new opportunities;
• Development of new systems and applications that have access to SAP application server as
clients;
• Extension of SAP system functionality through SAPx by building external non-SAP servers. This
feature gives the de veloper an opportunity to avoid costs connected with ABAP training as all
functionality extensions are implemented in Delphi™ programs.
SAPx encapsulates Remote Function Call (RFC) interface and offers high -level software components
and classes.
RFC API is a set of C-language routines that perform certain end user’s communication tasks and allow
execution of remote calls between two SAP Systems or between a SAP System and a non-SAP system.
RFC API supports a number of external systems, such as OS/2, Windows, WindowsNT and
Windows95, as well as all of R/3-based UNIX platforms. This feature makes it possible to use RFC
functionality for interaction of a SAP System with a C-program based on the platforms mentioned above
(there exists a RFC SDK that includes RFC library specific for each platform supported).
3 Architectural overview
On Figure 1 you can see the way Delphi applications can interact with SAP system through SAPx. SAPx
can be used both in client and server applications.
In the first case, when the developer wants to call an ABAP function he has to use SAPx object methods
and properties. SAPx packs all the necessary data and transfers the call to the RFC library. In such a
way the client request is sent to the SAP system. On receiving the request the SAP application server
processes it and returns the result. SAPx gets resulting data from the RFC library and the developer can
have access to it.
Application server
Client
SAP gateway
SAPx
Delphi application
If you want to understand the way RFC function can be called and how to work with function parameters
it is necessary to examine RFC function architecture.
SAPx
RFC function
Export Import
Tables
parameters parameters
Output data .
Input data
SAP R/3 servers are able to run on different types of computers. And they may have different than on
WinTel representations of integer and float data. So, data representation should be changed, when data
are received from / transmitted to SAP R/3 server and data representations of server and client are
different. SAPx performs that for you. How SAPx will do that is controlled by alias parameters
RFC data types can be divided into three groups with different mapping methods: simple data type,
structured data type and tables.
Figure 3 shows concepts of simple RFC data type mapping (you can find more details on data mapping
procedure in Appendix A). If a data type has ambiguous mapping, the developer can definitely indicate
the target Delphi data type. Otherwise, SAPx maps this data type to the most appropriate Delphi data
type.
dtCharGS String
dtNumGS Int64
. .
. .
. .
dtTimeGS TDateTime
dtDateGS
Simple Delphi
RFC data types data types
Unlike simple data types structured one, i.e. dtStructureGS, does not have Delphi analogues. Figure 4
illustrates how SAPx to wrap dtStructureGS type by means of TSAPxRFCParameterGS class that
contains field list of TSAPxRFCFieldsListGS class. So the structure corresponds to the field list and
individual field of TSAPxRFCFieldGS describes each structure item. SAPx does not support nested
structured data types. It means that each structure item should be of simple data type (you can find
more details on data mapping procedure in Appendix A).
Item 1 Field 1
Item 2 Field 2
. .
. .
. .
Item N Field N
Field list
Structured
RFC data type Parameter
We should also pay more attention to the way SAPx works with function tables featuring their own
format. SAPx includes TSAPxRFCvTableGS component derived from TDataSet that, on the one hand,
offers clear and easy interface for Delphi developers and, on the other hand, works with RFC library
using RFC data types and formats.
There are two types of binding ABAP RFC functions with SAPx function objects in SAPx, early and late
binding.
Early binding means that an ABAP function name has been known at design time already. So SAPx
function object is statically defined. It is recommended to get a wrapping code for the ABAP functions
with SAPx Explorer tool (see SAPx Explorer User Guide). It will save you a lot of time and will help you
to avoid lots of mistakes.
On the contrary, late binding allows the developer to call an ABAP function at run time dynamically. In
this case SAPx aut omatically gets the necessary metadata.
• Early binding has a higher productivity as it excludes application roundtrip to the SAP system for
metadata retrieval;
The developer can choose one binding mode or another depending on the specific task (you can find
more details on quantitative indicators for early and late binding in Appendix B).
RFC
1
n
TSAPxRFCvClientConnectionGS
1 1
n n
TSAPxRFCvFunctionGS TSAPxRFCvServerTableGS
1 1
Delphi application
n n
TSAPxRFCvParamsGS TSAPxRFCvTableGS SAPx
to communicate with RFC library. The developer can use TSAPxRFCvParamsGS and
TSAPxRFCvTableGS components to operate TSAPxRFCvFunctionGS function parameters and tables.
The components TSAPxRFCvParamsGS, TSAPxRFCvTableGS, and TSAPxRFCvServerTableGS
inherited from TDataSet can be linked with any data aware controls.
To build a client application you can use components as well as objects encapsulated into these
components.
A client application establishes communication with SAP system through RFC library. A connection has
its own set of parameters that are to be specified before connecting. For convenience developers may
apply SAPx aliases to describe connection parameters. The developer can maintained SAPx alias by
SAPx Explorer (see SAPx Explorer User Guide) and then use it in client application.
SAPx supports transactional functions. Transactional function should be called only between starting
and ending points of a transaction. These are distinctive features of transactional calls:
SAPx supports transactional server functions (you can find detailed information on transactional
management in )
RFC library
1
n
TSAPxRFCvServerConnectionGS
1
n
TSAPxRFCvServerFunctionGS
SAPx
Server connection parameters can be specified in the command line when the server application is
starting. In this case command line parameters are automatically assigned to CommandLine property of
TSAPxRFCvServerConnectionGS component. Appendix C shows command line switches and their
meaning. When server starts it becomes possible to specify either PROGRAM_ID, GWHOST,
GWSERV and RFC_TRACE parameters or just a DESTINATION parameter solely.
In the second case you have to define entry named DESTINATION in the saprfc.ini file specifying all
connection parameters (see example in Appendix C). This way to specify server connection parameters
is much more flexible than the first one.
While using command line it is very important to remember that you cannot specify more than one set of
server connection parameters. So, for server applications with multiple connections the developer
should definitely and explicitly specify Com mandLine property of TSAPxRFCvServerConnectionGS
component.
4 Installation
• SAP RFC library version at least 4.6 is installed on your PC. RFC library is specific for different
operational systems. For example, librfc32.dll is used in Windows 95/NT/2000. SAP RFC library
may be installed as part of SAPgui installation.
Notice. SAP RFC library from SAP GUI v 6.x has a bug – each unload of librfc32.dll will result
memory loss around 6 Mb.
• SAP R/3 system you want to work with is at least Release 2.1
SAP user account used by SAPx client application should have all required privileges to execute
following RFC function modules:
SAPx software includes a set of BAT command files. They may be used to build SAPx binary files don’t
running IDE, but from command line:
compileD6.bat Delphi 6
compileD7.bat Delphi 7
All BAT files will automatically detect is the tool installed or not and where it is installed. And if the tool is
not installed you will get an error message about that. The command files has optional parameters:
fullbin Used together with “tolib”. If specified, then set of binary files will include
additional file, required to build package / applications. It is DFM, RES,
DCR, etc files. If not specified, these files will stay in <SAPx>\ directory.
Installation of new components has become very easy due to the Delphi package system. To install
SAPx:
2. Choose File -> Open. Set Files of type to Delphi package (*.dpk) and open appropriate Package
Project file in the SAPx installation directory:
gsSAPxRFCD6.dpk Delphi 6
gsSAPxRFCD7.dpk Delphi 7
3. Click on Com pile button in Package window and then press Install button.
The new components should appear in the Delphi Component Palette (Figure 7).
In order to examine how to call an ABAP function developer can create a simple application that calls
ABAP function RFC_GET_NAMETAB. This function returns as result time stamp of table creation
(CRSTAMP). Input parameter TABNAME specifies the table name.
1. To create a new application form with a set of standard components on it (see Figure 8).
Figure 8 : The main form of the application calling ABAP function module RFC_GET_NAMETAB
Prepared := True;
InParams.ParameterByName('TABNAME').AsString := edtTableName.Text;
ExecFunction;
edtStamp.Text :=
OutParams.ParameterByName('HEADER').SubFields.FieldByName('CRSTAMP').AsString;
end;
end;
{ --------------------------------------------------------------------------- }
procedure TfrmMain.btnConnectClick(Sender: TObject);
begin
ClientConnection.Connected := True;
end;
{ --------------------------------------------------------------------------- }
procedure TfrmMain.btnDisconnectClick(Sender: TObject);
begin
ClientConnection.Connected := False;
end;
5. To run the application.
7. To specify the target table name and press Execute button. The final result is shown on Figure 9
Let us take as an example a simple application that calls ABAP function RFC_GET_FUNC_LOC_DATA.
This function returns information on locked SAP DB table by its name (you can find complete listing of
this application in Appendix F).
To build it using SAPx components the developer has to take the following steps:
Figure 10: The main application form with SAPx client components located on it.
3. Now you have access to function parameters and tables using data aware controls such as
TDBGrid, TDBEdit, TDBLable and others. To make it possible key components properties should be
maintained in accordance with Table 6.
Table 6: Maintaining key SAPx components properties for work using data aware controls.
Component name Class name Property
ClientConnection TSAPxRFCvClientConnectionGS AliasFileName = <Full name of alias file>
AliasName = <Any valid alias>
GetFuncData TSAPxRFCvFunctionGS Connection = ClientConnection
ObjName = ‘RFC_GET_FUNC_LOC_DATA’
PInput TSAPxRFCvParamsGS Func = ‘GetFuncData’
ParamKinds = [ipIn]
POutput TSAPxRFCvParamsGS Func = ‘GetFuncData’
ParamKinds = [ipOut]
Table TSAPxRFCvTableGS Func = ‘GetFuncData’
TableName = ‘SAP_FIELD_DATA’
dsrInput TDataSource DataSet = PInput
dsrOutput TDataSource DataSet = Poutput
dsrTable TDataSource DataSet = Table
edtFuncLoc TDBEdit DataSource = dsrInput
DataField = ‘I_FUNC_LOC’
grdOutput TDBGrid DataSource = dsrOutput
grdTable TDBGrid DataSource = dsrTables
btnConnect TButton OnClick = btnConnectClick
btnDisconnect TButton OnClick = btnDisconnectClick
btnPrepare TButton OnClick = btnPrepareClick
btnExecute TButton OnClick = btnExecuteClick
4. To run the application and connect to the SAP system by clicking on Connect button. When clicking
on Prepare button you prepare the GetFuncData function to access to its parameter list and tables
(Listing 2 shows implementation of btnConnectClick and btnPrepareClick event handlers). When the
function is prepared, its parameters and tables will be displayed in DB grids.
To enhance SAP system functionality by implementing a non-SAP server we are going to build, as an
example, a server console application that supports transactional calls. The application has a single
server function that is very simple as it can only write its input parameters to its table.
To build such server application the developer should take the following steps (you can find complete
listing of this application in Appendix G):
1. To create a new console application TransServer and its main class TxServer
2. To add the following main SAPx server objects to TxServer as class members:
4. To implement server function actions into HandleExecute event handler. HandleError event handler
contains actions that have to be performed when an error occurs. If the server has to support
transactions, then it is necessary to implement transaction events handlers such as
HandleCheckTID, HandleCommit, HandleRollback and HandleConfirm .
5. To write code that will launch and terminate the application server using Start and Shutdown
methods of TSAPxRFCServerApplicationGS object. Use SAPxRFCServerApplication function to
access to TSAPxRFCServerApplicationGS global object.
The majority of server programs in Windows NT are implemented as services. SAPx server can be
implemented as NT service as well. Server of this kind is built on TService standard Borland Delphi
class and uses TService events to control SAPx application server. To design such SAPx server the
developer should take the following steps (you can find complete listing of this application in Appendix
H):
Table 7: Maintaining of key SAPx components work properties using data aware controls.
Component (object) name Class name Property
FSConnection1 TSAPxRFCvServerConnectionGS CommandLine.IniDest = ‘DEST1’
OnCheckTID = ‘HandleCheckTID’
OnCommit = HandleCommit
OnConfirm = HandleConfirm
OnRollback = HandleRollback
FSConnection2 TSAPxRFCvServerCo nnectionGS CommandLine.IniDest = ‘DEST2’
OnCheckTID = ‘HandleCheckTID’
OnCommit = HandleCommit
OnConfirm = HandleConfirm
OnRollback = HandleRollback
FSFunction11 TSAPxRFCvServerFunctionGS Connection = FSConnection1
ObjName = ‘SAPXRFCF11’
OnExecute = FSTxFunctionExecute
FSFunction12 TSAPxRFCvServerFunctionGS Connection = FSConnection1
ObjName = ‘SAPXRFCF12’
OnExecute = FSFunctionExecute
FSFunction21 TSAPxRFCvServerFunctionGS Connection = FSConnection2
ObjName = ‘SAPXRFCF21’
OnExecute = FSTxFunctionExecute
FSFunction22 TSAPxRFCvServerFunctionGS Connection = FSConnection2
ObjName = ‘SAPXRFCF22’
OnExecute = FSFunctionExecute
5. To implement handlers for the following TService’s events: OnStart, OnStop, OnPause and
OnContinue. These handlers are quite simple (see Listing 3).
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
SAPxRFCServerApplication.Shutdown;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServicePause(Sender: TService; var Paused: Boolean);
begin
SAPxRFCServerApplication.Pause;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
SAPxRFCServerApplication.Resume;
end;
6. To include all server function actions into HandleExecute event handler.
7. If the server has to support transactions, it is necessary to implement event handlers such as
HandleCheckTID, HandleCommit, HandleRollback and HandleConfirm .
Mapping of simple RFC data type to Delphi data and field types
RFC data type Delphi data type Delphi field type
(see gsSAPxRFCStdObj) (see gsSAPxRFCvClient)
dtCharGS String • ftString (size <= 8192)
• ftMemo (size > 8192)
Listing 4: Early binding. Wrapping code generated for RFC_READ_TABLE ABAP function by SAPxExplorer.
TSAPxRFCRFC_READ_TABLEFuncGS = class(TSAPxRFCFunctionGS)
private
proc edure SetDELIMITER(const AValue: String);
function GetDELIMITER: String;
function GetDATA: TSAPxRFCTAB512TableGS;
public
constructor Create; override;
property DELIMITER: String read GetDELIMITER write SetDELIMITER;
property DATA: TSAPxRFCTAB512TableGS read GetDATA;
end;
implementation
procedure Execute;
begin
// working with TSAPxRFCRFC_READ_TABLEFuncGS object interface
with FCFunction as TSAPxRFCRFC_READ_TABLEFuncGS do begin
DELIMITER := ‘%’;
ExecFunction;
with DATA do begin
{ do something with table ‘DATA’ }
end;
end;
end;
procedure Execute;
begin
// working with TSAPxRFCFunctionGS object interface
with FCFunction do begin
ObjName := ‘RFC_READ_TABLE’;
Prepared := True;
InParams.ParameterByName('DELIMITER').AsString := ‘%’;
ExecFunction;
with Tables.TableByName('DATA') do begin
{ do something with table ‘DATA’ }
end;
end;
end;
// -----------------------------------------------------------------------
// SAPx server destinations
// ---------- -------------------------------------------------------------
DEST=S1
TYPE=R
PROGID=SAPXRFCTEST_PROGID1
GWHOST=myserver.mydomain.com
GWSERV=sapgw00
SAPx support s transactional server functions. SAP R/3, the RFC library and SAPx server connection
communicate in two phases (see Figure 12: Scheme of calling a transactional function):
Function transfer phase is initiated in ABAP program and is divided into three parts:
• T1 – OnCheckTID event handler has to check TID status, update it and return corresponding
check result
• T2 – OnExecute event handler should contain the required RFC server function implementation
• T3 (T3’) – OnCommit (OnRollback) event handler updates TID status and commits (rolls back)
database (non -SAP database) transaction(s)
Confirmation phase starts as soon as RFC library informs SAP system about successful T3 (not T3’ ).
TSAPxRFCvServerConnectionGS component receives confirmation of the current transaction
immediately. In OnConfirm event handler the developer should update TID status (delete). After this
phase is over current transaction is successfully completed on both sides.
TSAPxRFCvServerConnectionGS
F1 T1
OnCheckTID
// Check and update TID
T2
OnExecute
// Execute some actions
SAP tRFC T3
RFC library OnCommit
component // Update TID and commit DB
if necessary
T3'
OnRollback
// Update TID and rollback DB
if necessary
F2 T4
OnConfirm
// Update (delete) TID
SAPx
{-----------------------------------------------------------------------------}
procedure TxServer.HandleCommit(Sender: TObject; const ATID: String);
begin
UpdateStatus(ATID, tsExecuted);
CommitDB(ATID); // committing non-SAP database transaction
end;
{-----------------------------------------------------------------------------}
procedure TxServer.HandleConfirm(Sender: TObject; const ATID: String);
begin
UpdateStatus(ATID, tsDeleted);
end;
{-----------------------------------------------------------------------------}
procedure TxServer.HandleRollback(Sender: TObject; const ATID: String);
begin
RollbackDB(ATID); // rolling non-SAP database transaction back
end;
SAPx building components are divided into two groups: components for client programs and for non-
SAP server programs. In the following sections you can find description of each of these groups.
Client components
SAPx components used in client programs with access to SAP application server RFC functions are
called client components.
SAPx Explorer is a specially designed tool that offers the developer SAP system dictionary information
on RFC objects. For more detailed information about this tool, please, refer to SAPx Explorer User
Guide.
TSAPxRFCvClientConnectionGS
TSAPxRFCvFunctionGS
TSAPxRFCvTableGS
TSAPxRFCvServerTableGS
TSAPxRFCvParamsGS
Server components
The set of SAPx server components allows implementation of non-SAP server programs that enhance
SAP system functionality.
TSAPxRFCvServerConnectionGS
TSAPxRFCvServerFunctionGS
unit ClientApp;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, gsSAPxRFCvClient, DB, StdCtrls, Grids, DBGrids, Mask, DBCtrls;
type
{ --------------------------------------------------------------------------- }
TfrmMain = class(TForm)
ClientConnection: TSAPxRFCvClientConnectionGS;
GetFuncData: TSAPxRFCvFunctionGS;
btnExecute: TButton;
btnConnect: TButton;
grpInput: TGroupBox;
grpOutput: TGroupBox;
grpTables: TGroupBox;
btnDisconnect: TButton;
Table: TSAPxRFCvTableGS;
dsrInput: TDataSource;
dsrOutput: TDataSource;
dsrTables: TDataSource;
POutput: TSAPxRFCvParamsGS;
edtFuncLoc: TDBEdit;
PInput: TSAPxRFCvParamsGS;
grdOutput: TDBGrid;
GrdTable: TDBGrid;
btnPrepare: TButton;
lblFieldName: TLabel;
procedure btnExecuteClick(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure btnDisconnectClick(Sender: TObject);
procedure btnPrepareClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
{ --------------------------------------------------------------------------- }
procedure TfrmMain.btnExecuteClick(Sender: TObject);
begin
GetFuncData.ExecFunction;
end;
{ --------------------------------------------------------------------------- }
procedure TfrmMain.btnConnectClick(Sender: TObject);
begin
ClientConnection.Connected := True;
end;
{ --------------------------------------------------------------------------- }
procedure TfrmMain.btnDisconnectClick(Sender: TObject);
begin
ClientConnection.Connected := False;
end;
{ --------------------------------------------------------------------------- }
pro cedure TfrmMain.btnPrepareClick(Sender: TObject);
begin
GetFuncData.Prepare;
PInput.Active := True;
POutput.Active := True;
Table.Active := True;
end;
{ --------------------------------------------------------------------------- }
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ClientConnection.Connected := False;
end;
end.
program TransServer;
{$APPTYPE CONSOLE}
uses
Windows, SysUtils, gsSAPxRFCvServer, StdCtrls, gsSAPxRFCServer, gsSAPxRFCBase,
gsSAPxRFCvClient, gsSAPxRFCStdObj, Classes, dbtables, db;
type
TSAPxRFCABAPTEXTTableGS = class;
TSAPxRFCZMY_STRUCTUREStrGS = class;
TSAPxRFCZMY_SERVER_FUNCTIONFuncGS = class;
{-----------------------------------------------------------------------------}
{ TxServer }
{-----------------------------------------------------------------------------}
TxServer = class(TObject)
private
FSConnection1: TSAPxRFCServerConnectionGS;
FSFunction1: TSAPxRFCZMY_SERVER_FUNCTIONFuncGS;
procedure InitConnection;
procedure InitFunction;
procedure HandleExecute(AFunction: TSAPxRFCServerFunctionGS);
procedure HandleError(Sender: TObject; E: Exception;
var AErrAction: TSAPxRFCErrorActionGS);
procedure HandleCheckTID(Sender: TObject; const ATID: String;
var AResult: TSAPxRFCCheckTIDResultGS);
procedure HandleCommit(Sender: TObject; const ATID: String);
procedure HandleConfirm(Sender: TObject; const ATID: String);
procedure HandleRollback(Sender: TObject; const ATID: String);
public
constructor Create;
destructor Destroy; override;
procedure Start;
procedure Shutdown;
end;
{-----------------------------------------------------------------------------}
{ TSAPxRFCABAPTEXTTableGS }
{-----------------------------------------------------------------------------}
TSAPxRFCABAPTEXTTableGS = class(TSAPxRFCTableGS)
private
procedure SetLINE(const AValue: String);
function GetLINE: String;
public
constructor Create; override;
property LINE: String read GetLINE write SetLINE;
end;
{-----------------------------------------------------------------------------}
{ TSAPxRFCZMY_STRUCTUREStrGS }
{-----------------------------------------------------------------------------}
TSAPxRFCZMY_STRUCTUREStrGS = class(TSAPxRFCParameterGS)
private
procedure SetTABNAME(const AValue: String);
{-----------------------------------------------------------------------------}
{ TSAPxRFCZMY_SERVER_FUNCTIONFuncGS }
{-----------------------------------------------------------------------------}
TSAPxRFCZMY_SERVER_FUNCTIONFuncGS = class(TSAPxRFCServerFunctionGS)
private
function GetASTAT: TSAPxRFCZMY_STRUCTUREStrGS;
function GetDATA: TSAPxRFCABAPTEXTTableGS;
function GetFTABNAME: string;
procedure SetFTABNAME(Value: string);
public
constructor Create; override;
property ASTAT: TSAPxRFCZMY_STRUCTUREStrGS read GetASTAT;
property FTABNAME: string read GetFTABNAME write SetFTABNAME;
property DATA: TSAPxRFCABAPTEXTTableGS read GetDATA;
end;
{-----------------------------------------------------------------------------}
{ TxServer }
{-----------------------------------------------------------------------------}
constructor TxServer.Create;
begin
FSConnection1 := TSAPxRFCServerConnectionGS.Create;
FSFunction1 := TSAPxRFCZMY_SERVER_FUNCTIONFuncGS.Create;
InitConnection;
InitFunction;
end;
{-----------------------------------------------------------------------------}
destructor TxServer.Destroy;
begin
FSConnection1.Free;
FSFunction1.Free;
inherited Destroy;
end;
{-----------------------------------------------------------------------------}
procedure TxServer.InitConnection;
begin
with FSConnection1 do begin
OnError := HandleError;
OnCheckTID := HandleCheckTID;
OnCommit := HandleC ommit;
OnConfirm := HandleConfirm;
OnRollback := HandleRollback;
end;
end;
{-----------------------------------------------------------------------------}
procedure TxServer.InitFunction;
begin
// the initialization of server function
with F SFunction1 do begin
Connection := FSConnection1;
OnExecute := HandleExecute;
end;
end;
{-----------------------------------------------------------------------------}
procedure TxServer.Start;
begin
SAPxRFCServerApplication.Start;
end;
{-----------------------------------------------------------------------------}
procedure TxServer.Shutdown;
begin
SAPxRFCServerApplication.Shutdown;
end;
{-----------------------------------------------------------------------------}
procedure TxServer.HandleExecute(AFunction: TSAPxRFCServerFunctionGS);
var
sStructDump, sTabName: String;
begin
if AFunction is TSAPxRFCZMY_SERVER_FUNCTIONFuncGS then
with AFunction as TSAPxRFCZMY_SERVER_FUNCTIONFuncGS do begin
sTabName := FTABNAME;
sStructDump := ASTAT.TABNAME + '; ' + ASTAT.FLAG;
DATA.Append;
DATA.LINE := sTabName + '; ' + sStructDump;
DATA.Post;
end;
end;
{-----------------------------------------------------------------------------}
procedure TxServer.HandleError(Sender: TObject; E: Exception;
var AErrAction: TSAPxRFCErrorActionGS);
begin
{ Error handling }
end;
{-----------------------------------------------------------------------------}
procedure TxServer.HandleCheckTID(Sender: TObject; const ATID: String;
var AResult: TSAPxRFCCheckTIDResultGS);
begin
{ Check status of transaction with ATID }
{ if the transaction has not been started, then }
{ AResult := crOkGS, else AResult := crCancelGS }
end;
{-----------------------------------------------------------------------------}
procedure TxServer.HandleCommit(Sender: TObject; const ATID: String);
begin
{ do DB Commit }
{ Update status of transaction with ATID }
end;
{-----------------------------------------------------------------------------}
{-----------------------------------------------------------------------------}
procedure TxServer.HandleRollback(Sender: TObject; const ATID: String);
begin
{ do DB Rollback }
end;
{-----------------------------------------------------------------------------}
{ TSAPxRFCABAPTEXTTableGS }
{-----------------------------------------------------------------------------}
constructor TSAPxRFCABAPTEXTTableGS.Create;
begin
inherited Create;
TableType := dtCharGS;
with Fields.AddField do begin
Name := 'LINE';
DataType := dtCharGS;
DataSize := 72;
Offset := 0;
end;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCABAPTEXTTableGS.SetLINE(const AValue: String);
begin
Fields[0].AsString := AValue;
end;
{-----------------------------------------------------------------------------}
function TSAPxRFCABAPTEXTTableGS.GetLINE: String;
begin
Result := Fields[0].AsString;
end;
{-----------------------------------------------------------------------------}
{ TSAPxRFCZMY_STRUCTUREStrGS }
{-----------------------------------------------------------------------------}
constructor TSAPxRFCZMY_STRUCTUREStrGS.Create;
begin
inherited Create;
InstallStructure;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCZMY_STRUCTUREStrGS.SetTABNAME(const AValue: String);
begin
SubFields[0].AsString := AValue;
end;
{-----------------------------------------------------------------------------}
function TSAPxRFCZMY_STRUCTUREStrGS.GetTABNAME: String;
begin
Result := SubFields[0].AsString;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCZMY_STRUCTUREStrGS.SetFLAG(const AValue: String);
begin
SubFields[1].AsString := AValue;
end;
{-----------------------------------------------------------------------------}
function TSAPxRFCZMY_STRUCTUREStrGS.GetFLAG: String;
begin
Result := SubFields[1].AsString;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCZMY_STRUCTUREStrGS.InstallStructure;
var
oStr: TSAPxRFCStructureCacheItemGS;
i: Integer;
begin
oStr := FSAPxRFCEnvironment.StructureCache.FindStructure('ZMY_STRUCTURE');
if oStr = nil then begin
oStr := FSAPxRFCEnvironment.StructureCache.Add;
with oStr do begin
StructName := 'ZMY_STRUCTURE';
with Elements.AddElement do begin
Name := 'TABNAME';
DataType := dtCharGS;
DataSize := 30;
Offset := 0;
end;
with Elements.AddElement do begin
Name := 'FLAG';
DataType := dtCharGS;
DataSize := 1;
Offset := 30;
end;
end;
oStr.Install;
end;
DataType := dtStructureGS;
TypeHandle := oStr.TypeHandle;
SubFields.Clear;
for i := 0 to oStr.Elements.Count - 1 do
oStr.Elements[i].CreateField(SubFields);
end;
{-----------------------------------------------------------------------------}
{ TSAPxRFCZMY_SERVER_FUNCTIONFuncGS }
{-----------------------------------------------------------------------------}
constructor TSAPxRFCZMY_SERVER_FUNCTIONFuncGS.Create;
begin
inherited Create;
Name := 'ZMY_SERVER_FUNCTION';
with InParameters.AddParameterEx(TSAPxRFCZMY_STRUCTUREStrGS) do begin
Name := 'FSTAT';
DataSize := 31;
end;
with InParameters.AddParameter do begin
Name := 'FTABNAME';
DataSize := 30;
DataType := dtCharGS;
end;
with Tables.AddTableEx(TSAPxRFCABAPTEXTTableGS) do begin
Name := 'FDATA';
RecordSize := 72;
Open;
end;
end;
{-----------------------------------------------------------------------------}
function TSAPxRFCZMY_SERVER_FUNCTIONFuncGS.GetASTAT: TSAPxRFCZMY_STRUCTUREStrGS;
begin
Result := InParameters[0] as TSAPxRFCZMY_STRUCTUREStrGS;
end;
{-----------------------------------------------------------------------------}
function TSAPxRFCZMY_SERVER_FUNCTIONFuncGS.GetDATA: TSAPxRFCABAPTEXTTableGS;
begin
Result := Tables[0] as TSAPxRFCABAPTEXTTableGS;
end;
{-----------------------------------------------------------------------------}
function TSAPxRFCZMY_SERVER_FUNCTIONFuncGS.GetFTABNAME: string;
begin
Result := InParameters[1].AsString;
end;
{-----------------------------------------------------------------------------}
procedure TSA PxRFCZMY_SERVER_FUNCTIONFuncGS.SetFTABNAME(Value: string);
begin
InParameters[1].AsString := Value;
end;
{-----------------------------------------------------------------------------}
var
Srv: TxServer;
F1: TextFile;
Ch: Char;
begin
Srv := TxSe rver.Create;
try
Srv.Start;
AssignFile(F1, '');
Reset(F1);
try
repeat
Read(F1, Ch);
until UpperCase(Ch) = 'Q';
finally
CloseFile(F1);
end;
finally
Srv.Shutdown;
Srv.Free;
end;
end.
unit fMain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
gsSAPxRFCvServer, gsSAPxRFCServer, gsSAPxRFCBase, gsSAPxRFCStdObj, Db, DBTables;
type
{-----------------------------------------------------------------------------}
{ TSAPxRFCService }
{-----------------------------------------------------------------------------}
TTransStatus = (tsCreated, tsExecuted);
TSAPxRFCServer = class(TService)
FSConnection1: TSAPxRFCvServerConnectionGS;
FSFunction21: TSAPxRFCvServerFunctionGS;
FSFunction11: TSAPxRFCvServerFunctionGS;
FSConnection2: TSAPxRFCvServerConnectionGS;
FSFunction12: TSAPxRFCvServerFunctionGS;
FSFunction22: TSAPxRFCvServerFunctionGS;
procedure ServiceStart(Sender: TService; var Started: Boolean);
procedure ServicePause(Sender: TService; var Paused: Boolean);
procedure ServiceContinue(Sender: TService; var Continued: Boolean);
procedure ServiceCreate(Sender: TObject);
procedure FSFunctionExecute(AFunction: TSAPxRFCServerFunctionGS);
procedure FSTxFunctionExecute(AFunction: TSAPxRFCServerFunctionGS);
procedure ServiceExecute(Sender: TService);
procedure ServiceStop(Sender: TService; var Stopped: Boolean);
procedure HandleCommit(Sender: TObject; const ATID: String);
procedure HandleConfirm(Sender: TObject; const ATID: String);
procedure HandleRollback(Sender: TObject; const ATID: String);
procedure HandleCheckTID(Sender: TObject; const ATID: String;
var AResult: TSAPxRFCCheckTIDResultGS);
procedure ServiceDestroy(Sender: TObject);
private
FTransList: TStringList;
procedure CreatingOnFly;
public
function GetServiceController: TServiceController; override;
end;
var
SAPxRFCServer: TSAPxRFCServer;
implementation
{$R *.DFM}
{-----------------------------------------------------------------------------}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
SAPxRFCServer.Controller(CtrlCode);
end;
{-----------------------------------------------------------------------------}
{ TSAPInfoService }
{-----------------------------------------------------------------------------}
function TSAPxRFCServer.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServiceStart(Sender: TService; var Started: Boolean);
begin
SAPxRFCServerApplication.Start;
Started := not SAPxRFCServerApplication.Terminated;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServicePause(Sender: TService; var Paused: Boolean);
begin
SAPxRFCServerApplication.Pause;
end;
{-------------------------------------------------------------- ---------------}
procedure TSAPxRFCServer.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
SAPxRFCServerApplication.Shutdown;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServiceContinue(Sender: TService; var Continued: Boolean);
begin
SAPxRFCServerApplication.Resume;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServiceCreate(Sender: TObject);
begin
FTransList := TStringList.Create;
CreatingOnFly;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServiceDestroy(Sender: TObject);
begin
FTransList.Free;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.FSFunctionExecute(AFunction: TSAPxRFCServerFunctionGS);
begin
{ non-transactional actions }
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.FSTxFunctionExecute(AFunction: TSAPxRFCServerFunctionGS);
begin
{ transactional actions }
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.ServiceExecute(Sender: TService);
begin
while not Terminated do
ServiceThread.ProcessRequests(True);
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.CreatingOnFly;
var
i: Integer;
oFSFunction: TSAPxRFCvServerFunctionGS;
begin
for i := 0 to ComponentCount - 1 do
if Components[i] is TSAPxRFCvServerFunctionGS then begin
oFSFunction := TSAPxRFCvServerFunctionGS(Components[i]);
oFSFunction.InParameters.Clear;
oFSFunction.OutParameters.Clear;
with oFSFunction.InParameters.AddParameter do begin
{ specifying a set of input parameters }
end;
with oFSFunction.OutParameters.AddParameter do begin
{ specifying a set of output parameters }
end;
end;
end;
{--------------------------- --------------------------------------------------}
procedure TSAPxRFCServer.HandleCheckTID(Sender: TObject; const ATID: String;
var AResult: TSAPxRFCCheckTIDResultGS);
begin
if FTransList.IndexOf(ATID) = -1 then begin
FTransList.AddObject(ATID, TObject(tsCreated));
AResult := crOkGS;
end
else
AResult := crCancelGS;
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.HandleCommit(Sender: TObject; const ATID: String);
var
i: Integer;
begin
i := FTransList.IndexOf(ATID);
if i <> -1 then
FTransList.Objects[i] := TObject(tsExecuted);
{ DB commit }
end;
{-----------------------------------------------------------------------------}
procedure TSAPxRFCServer.HandleConfirm (Sender: TObject; const ATID: String);
var
i: Integer;
begin
i := FTransList.IndexOf(ATID);
if i <> -1 then
FTransList.Delete(i);
end;
{-----------------------------------------------------------------------------}
end.