Copyright: Wednesday, July 02, 2008 12:55:58, V. 1.1


Introduction
Introduction: RPC Broker V. 1.1

The RPC Broker is a client/server system within VA's Veterans Health Information Systems and Technology Architecture (VistA) environment. It enables client applications to communicate and exchange data with VistA M Servers.

This manual describes the development features of the RPC Broker. The emphasis is on using the RPC Broker in conjunction with Borland's Delphi software. However, the RPC Broker supports other development environments.

This manual provides a complete reference for development with the RPC Broker. For an overview of development with the RPC Broker component, please refer to the RPC Broker Getting Started with the Broker Development Kit manual.

This document is intended for the VistA development community and Information Resource Management (IRM) staff. A wider audience of technical personnel engaged in operating and maintaining the Department of Veterans Affairs (VA) software might also find it useful as a reference.

Contents

Broker Overview

Orientation

About this Version of the RPC Broker

What's New in the BDK

Developer Considerations

Application Issues

Silent Login

Context-sensitive Help for the RPC Broker

For the latest RPC Broker product information, please refer to the RPC Broker Home Page at the following Web address:

http://vista.med.va.gov/broker/index.asp


About this Version of the RPC Broker

Version 1.1 of the RPC Broker (fully patched) provides programmers with the capability to develop new VistA client/server software using the following RPC Broker Delphi components in the 32-bit environment:

•	TCCOWRPCBroker

•	TRPCBroker

•	TSharedBroker

•	TSharedRPCBroker

•	TXWBRichEdit

For a complete list of patches released with Version 1.1 of the RPC Broker, please refer to the Patch Module on FORUM or visit the "ISS Released Patches" Web site at the following Web address:

http://vista.med.va.gov/iss/patches/released.asp#broker

To develop VistA applications in a 32-bit environment you must have Delphi V. 2.0 or greater. This version of the RPC Broker does not allow you to develop new applications in Delphi V. 1.0 (16-bit environment). However, the RPC Broker routines on the VistA M Server will continue to support VistA applications previously developed in the 16-bit environment.

The default installation of the RPC Broker creates a separate Broker Development Kit (BDK) directory (i.e., BDK32) that contains the required RPC Broker files for development.

 The Office of Information & Technology (OI&T) will support the Broker Development Kit running in the currently offered version of Delphi and the immediately previous version of Delphi. This level of support became effective 6/12/2000.

Sites may continue to use outdated versions of the RPC Broker Development Kit but do so with the understanding that support will not be available and that continued use of outdated versions will not afford features that may be essential to effective client/server operations in the VistA environment. An archive of old (no longer supported) Broker Development Kits will be maintained at:

http://vista.med.va.gov/broker/archive.asp


What's New in the BDK

Here is What’s New Through June 2008

This topic highlights some of the major changes made to the RPC Broker V. 1.1 since its original release (patch references are included where applicable):

•	Classes Added

•	Components Added

•	Design-time and Run-time Packages

•	Functionality Added

•	Library Methods

•	Added

•	Modified

•	Properties Added

•	Source Code Availability

•	Types Added/Modified

No new methods, properties, etc. were added with RPC Broker Patch XWB*1.1*47.

Classes Added

•	TVistaLogin

As of Patches XWB*1.1*13, this Class was added to Version 1.1 of the RPC Broker.

•	TVistaUser

As of Patches XWB*1.1*13, this Class was added to Version 1.1 of the RPC Broker.

•	TXWBWinsock

As of Patches XWB*1.1* 40, this Class was added to Version 1.1 of the RPC Broker.

Components Added:

•	TCCOWRPCBroker

As of Patch XWB*1.1*40, the TCCOWRPCBroker component was added to Version 1.1 of the RPC Broker. This component allows applications to be CCOW-enabled and Single Sign-On/User Context (SSO/UC)-aware.

•	TSharedBroker

As of Patch XWB*1.1*26, the TSharedBroker component was added to Version 1.1 of the RPC Broker. This component allows applications to share a single Broker connection.

•	TSharedRPCBroker

As of Patch XWB*1.1*26, the TSharedRPCBroker component was added to Version 1.1 of the RPC Broker. This component allows applications to share a single Broker connection.

•	TXWBRichEdit

As of Patch XWB*1.1*13, the TXWBRichEdit component was added to Version 1.1 of the RPC Broker. This component replaced the Introductory Text Memo component on the Login Form. It permits URLs to be identified and launched.

Design-time and Run-time Packages

As of Patch XWB*1.1*14, the BDK now contains separate run-time and design-time packages.

For details and compiling instructions, please refer to the "Developer Considerations" topic.

Functionality Added

•	Support for Delphi V. 7.0—As of Patch XWB*1.1*40, the BDK supports Delphi V. 7.0.

•	Single Sign-On/User Context (SSO/UC)-aware TCCOWRPCBroker Component—As of Patch XWB*1.1*40, the TCCOWRPCBroker component enabled Single Sign-On/User Context (SSO/UC) in CCOW-enabled applications.

For more information on SSO/UC, please consult the Single Sign-On/User Context (SSO/UC) Installation Guide and Single Sign-On/User Context (SSO/UC) Deployment Guide on the VistA Documentation Library (VDL).

•	Non-Callback Connections—As of Patch XWB*1.1*35, the RPC Broker components are built with a UCX or non-callback Broker connection, so that it can be used from behind firewalls, routers, etc. This functionality is controlled via the new TRPCBroker component IsBackwardCompatibleConnection property.

•	Silent Login— As of Patch XWB*1.1*13, the RPC Broker provides "Silent Login" capability. It provides functionality associated with the ability to make logins to a VistA M Server without the RPC Broker asking for Access and Verify code information.

Two types of Silent Login are provided with Version 1.1 of the BDK:

1.	Access/Verify Code-based—One type of Silent Login uses Access and Verify codes provided by the application. This type of Silent Login may be necessary for an application that runs as a background task and repeatedly signs on for short periods. Another case would be for applications that are interactive with the user, but are running under conditions where they cannot provide a standard dialog window, such as that used by the Broker to request Access and Verify codes. Examples might be applications running on handheld devices or within a browser window.

2.	Token-based—The second type of Silent Login utilizes a token obtained by one application that is passed along with other information as a command line argument to a second application that it is starting. The token is obtained from the VistA server and remains valid for about twenty (20) seconds. When the newly started application sends this token during login the server identifies the same user and completes the login.

Due to the various conditions under which Silent Logins might be used, it was also necessary to provide options to the applications on error handling and processing. Applications that run as system services will crash if they attempt to show a dialog box. Similarly, applications running within Web browsers are not permitted to show a dialog box or to accept windows messages. Properties have been provided to permit the application to handle errors in a number of ways.

As a part of the Silent Login functionality, the TVistaUser class providing basic user information was added. This class is used as a property by the TRPCBroker class and is filled with data following completion of the login process. This property and its associated data is available to all applications, whether they are using a Silent Login or not.

•	Documented Deferred RPCs and Capability to Run RPCs on a Remote Server:

Deferred RPCs

Running RPCs on a Remote Server

•	Multi-instances of the RPC Broker— As of Patch XWB*1.1*13, the RPC Broker code was modified to permit an application to open two separate Broker instances with the same Server/ListenerPort combination, resulting in two separate partitions on the server. Previously, an attempt to open a second Broker instance ended up using the same partition. For this capability to be useful for concurrent processing, an application would have to use threads to handle the separate Broker sessions.

 Although we believe there should be no problems, the RPC Broker is not yet guaranteed to be thread safe.

Library Methods

Added

As of Patch XWB*1.1*13, the following library methods were new in the TVCEdit Unit:

•	ChangeVerify

function ChangeVerify(RPCBroker: TRPCBroker): Boolean;

•	SilentChangeVerify

function SilentChangeVerify(RPCBroker: TRPCBroker; OldVerify, NewVerify1, NewVerify2: String; var Reason: String): Boolean;

•	StartProgSLogin

procedure StartProgSLogin(const ProgLine: String; ConnectedBroker: TRPCBroker);

As of Patch XWB*1.1*40, the following library methods were new with the TCCOWRPCBroker component:

•	GetCCOWtoken

function GetCCOWtoken(Contextor: TContextorControl): string;

•	IsUserCleared

function IsUserCleared: Boolean;

•	IsUserContextPending

function IsUserContextPending(aContextItemCollection: IContextItemCollection):  Boolean;

•	WasUserDefined

function WasUserDefined: Boolean;

Modified

As of Patch XWB*1.1*13, the following library methods were modified:

•	CheckCmdLine

function CheckCmdLine(SLBroker: TRPCBroker): Boolean;

Changed from procedure to function with a Boolean return value.

•	GetServerInfo

The GetServerInfo library function in the RpcConf1 unit, which can be used to select the desired Server name and ListenerPort, was modified to add a "new" button. This button can be used to add a new Server/ListenerPort combination to those available for selection. It will also accept and store a valid IP address, if no name is known for the location. This will permit those who have access to other Server/ListenerPort combinations that may not be available in the list on the current workstation to access them. However, they will still need a valid Access and Verify code to log on to the added location.

•	TParams

procedure Clear was moved from Private to Public.

•	TRPCB Unit

TOnLoginFailure = procedure (VistaLogin: TVistaLogin) of object;

Changed from Object: TObject, since this is what should be expected by the procedure if it is called.

TOnRPCBFailure = procedure (RPCBroker: TRPCBroker) of object;

Changed from Object: TObject, since this is what should be expected by the procedure if it is called.

Properties Added

•	TCCOWRPCBroker Properties:

•	CCOWLogonIDName (Public)

•	CCOWLogonIDValue (Public)

•	CCOWLogonName (Public)

•	CCOWLogonNameValue (Public)

•	CCOWLogonVpid (Public)

•	CCOWLogonVpidValue (Public)

•	Contextor (Public)

As of Patch XWB*1.1*40, these properties were added to Version 1.1 of the RPC Broker.

•	TRPCBroker Properties

•	BrokerVersion (Public)

•	CurrentContext (Public)

•	IsBackwardCompatibleConnection (Published)

•	IsNewStyleConnection (Public)

•	KerneLogIn (Published)

•	LogIn (Public)

•	OldConnectionOnly (Published)

•	OnRPCBFailure (Public)

•	RPCBError (Public)

•	ShowErrorMsgs (Published)

•	User (Public)

As of Patches XWB*1.1*13 and 35, these properties were added to Version 1.1 of the RPC Broker.

•	TSharedBroker and TSharedRPCBroker Properties:

•	AllowShared (Public)

•	OnConnectionDropped  (Public)

•	OnLogout (Published)

As of Patch XWB*1.1*23, these properties were added to Version 1.1 of the RPC Broker.

•	TVistaLogin Properties:

•	DomainName  (Public)

•	IsProductionAccount  (Public)

As of Patch XWB*1.1*40, these properties were added to Version 1.1 of the RPC Broker.

•	TVistaUser Property:

•	Vpid (Public)

As of Patch XWB*1.1*40, these properties were added to Version 1.1 of the RPC Broker.

For properties and methods introduced with the RPC Broker 32-bit BDK, please refer to the "Historical Information Regarding the 16-Bit BDK vs. 32-Bit BDK" topic. This topic also highlights disposition of the Client Manager and those properties and parameters that were obsolete and removed from the 32-bit version of the BDK.

Source Code Availability

As of Patch XWB*1.1*14, the BDK contains the Broker source code. The source code is located in the ..\BDK32\Source directory.

 Modified BDK source code should not be used to create VistA GUI applications. For more details, please refer to the "Developer Considerations" topic.

Not all methods and properties found in the source code are documented at this time. Only those documented methods and properties are guaranteed to be made backwards compatible in future versions of the BDK.

Types Added/Modified

•	TLoginMode

•	TShowErorMsgs

•	TOnLoginFailure

•	TOnRPCBFailure

•	TParamType

As of Patch XWB*1.1*13 and XWB*1.1*40, these Types were added to or modified in Version 1.1 of the RPC Broker.


Connect Disconnect Behavior
Component Connect/Disconnect Behavior

Connect

The first time one of the Broker components in your application connects, it will establish an actual connection with the server. The connection record will be added to the list of all active connections for your application. This list is internal to the application and is completely under the control of the Broker component and is transparent to you. If another Broker component tries to connect to the same server/port, the existing connection record will be found in the list and its socket will be shared. The new connection will also be added to this list. This process is repeated with each connection request.

Disconnect

When a Broker component disconnects, its connection record is removed from the internal list of active connections. If it happens to be the last record for the particular server/port combination, the connection is actually closed. This scheme provides the illusion of multiple connections without "clogging up" the server.


Context-sensitive Help for the RPC Broker Components

The installation of the BDK automatically makes the RPC Broker context-sensitive help available within Delphi for the RPC Broker components.

You can select any property in the object inspector, press F1, and get help for that property. Also, you can select any of the RPC Broker components on a form, press F1, and get help for the component.


Orientation

Classes, Objects, and Components

The BDK includes classes, objects, and components. For each class, object, and component, this Help file lists the unit, declaration, properties, methods, and a description of how to use the class, object, or component.

•	Class—A class is a data type that wraps up code and data all in one bundle.

•	Object—An object is a specific instance of that class with associated values.

•	Component—A component is an object with additional properties, methods, and events that makes it suitable for specialized purposes.

Routines

Routines can either be functions or procedures. A function returns a value, and a procedure does not.

For topics in this Help file describing routines, the unit and declaration for each routine is listed, as well as a description of the routine is provided.

Types

A type defines the possible range of values for a property or a method. A number of types are declared in the BDK, which you may need to make use of yourself in your own code. For topics in this Help file describing types, the unit and declaration for each type, as well as a description of the type is also provided.

Units

A unit is a Pascal source-code file. The BDK includes a number of units. This Help file documents some of the units provided, and details what parts of the BDK are declared in each unit.

Sometimes it is helpful to know in which unit a particular item, such as a type or routine, is declared in the BDK. This is because if you use the item in your own code, you may need to include the corresponding unit in your own Pascal unit's uses clause.


Broker Overview

The RPC Broker is a bridge connecting the application front-end on the client workstation (e.g., Delphi-based GUI applications) to the M-based data and business rules on the VistA M Server.

Client Side of the RPC Broker	Server Side of RPC the Broker
• Manages the connection to the client workstation. For details, please refer to the "RPC Broker Systems Manual." • The RPC Broker components allow Delphi-based applications to make RPCs to the server. • The Broker Dynamic Link Library (DLL) provides support for COTS/HOST client/server software.	• Manages the connection to the client. For details, please refer to the RPC Broker Systems Manual. • Authenticates client workstation. • Authenticates user. • Manages RPCs from the client, executes the M code, and passes back return values.

The RPC Broker frees GUI developers from the details of the client-server connection and allows them to concentrate executing operations on the VistA M Server.

Broker Call Steps

These steps present a basic outline of the events that go into an RPC Broker call, starting with the initial client-server connection. Once the client machine and user are authenticated, any number of calls (Steps #3-5) can occur through the open connection.

GUI developer issues are noted for each step.

1.	Authentication of client machine. When a client machine initiates a session, the Broker Listener on the server spawns a new job. The server then calls the client back to ensure that the client’s address is accurate.

GUI Developer Issues:

•	None. This process is built into the RPC Broker. For more details, please refer to the RPC Broker Systems Manual.

2.	Authentication of user. After the server connects back to the client machine, the user is asked for an Access and Verify code.

GUI Developer Issues:

•	Applications must create a context for the user. This process checks the user’s access to individual RPCs associated with the application.

•	Developers must decide whether to enable Silent Login.

3.	Client makes a Remote Procedure Call.

GUI Developer Issues:

Developers creating Delphi GUI applications can use the TRPCBroker or TSharedRPCBroker components to connect to VistA. For each transaction, the application must set parameters and execute a call. Issues include:

•	Determine data types for input and return.

•	Determine the kind of call to make.

In addition to the RPC Broker components, other components are available. The VA FileMan Delphi components (FMDC) encapsulate the details of retrieving, validating and updating VA FileMan data within a Delphi-based application.

For more information on the VA FileMan Delphi Components (FMDC), please refer to the following Web address:

http://vista.med.va.gov/fmdc/index.asp

In the future, components may become available to encapsulate other VistA functions.

4.	RPC execution on server.

GUI Developer Issues:

A Remote Procedure Call (RPC) is a defined call to M code that runs on a VistA M server. For details, please refer to the "RPCs " topic. Issues include:

•	Determine the best RPC. The BDK provides some RPC BROKER APIs. You may need to create your own RPC from scratch. In many cases, an existing M API can be wrapped into an RPC.

•	RPCs must be registered on the server so users of the GUI VistA application will have access to them.

For more information on registering RPCS, please refer to the "RPC Security: How to Register an RPC" topic.

5.	RPC returns information to the client.

GUI Developer Issues:

•	Handling the return values, including any error messages.


Developer Considerations

Source Code

As of RPC Broker Patch XWB*1.1*14, the RPC Broker source code was released. The release of the source code does not affect how a developer uses the Broker Components or other parts of the BDK.

 Modified BDK source code should not be used to create VistA GUI applications. For details, please refer to the "Developer Considerations" topic.

Suggestions for changes to the BDK should be done via VistA 's REMEDY system (for bugs) or VistA 's Electronic Error and Enhancement Requests (E3R) system (for enhancements) for review and possible inclusion in a future patch.

The source code is located in the ..\BDK32\Source directory.

Design-time and Run-time packages

As of RPC Broker Patch XWB*1.1*14, the BDK now has separate run-time and design-time packages. There is no longer a VistA Broker package. The new packages are XWB_Dxx and XWB_Rxx, where "D" means Design-time and "R" means Run-time and where "xx" is two digits indicating the version of Delphi with which it should be used (e.g., XWB_D50 is the design-time package for Delphi V. 5.0). The run-time package should not be used to create executables that depend on a separate XWB_Rxx.bpl installed on client workstations. There is no procedure in place at this time to reliably install the correct version of the run-time bpl on client workstations.

 Do not compile your project so that it relies on dynamic linking with the BDK's run-time package; that is, do not check the "Build with runtime packages" box on the Packages tab of the Project Options dialog.

Reuse

Developers should be aware of existing resources that may be of use. These resources may be available nationally or through a particular project. Possibilities include:

•	Delphi components such as the VA FileMan Delphi components (FMDC).

For more information on the VA FileMan Delphi components (FMDC), please refer to the following Web address:

http://vista.med.va.gov/fmdc/index.asp

•	RPC BROKER APIs

•	Existing M APIs


Application Issues

Application Version Numbers

There may be a need to set or pass application version numbers. The suggested format is as follows:

VersionNumber_PatchNumber(3 digits)

Thus, Patch 22 of Version 8.2 would be:

8.2022

Deferred RPCs

In order to increase efficiency, applications can run RPCs in the background.

Remote RPCs

In order to work with patient data across sites, applications can run RPCs on a remote server.

Blocking RPCs

Applications can install RPCs that should be used only in certain contexts. It is possible to block access to an RPC.

Silent Login

In special cases, applications can use one of two types of Silent Login to log in users without the RPC Broker prompting for login information.


Historical Information Regarding the 16-Bit BDK vs. 32-Bit BDK

The following items should be noted when transitioning from the original 16-bit Broker Development Kit (BDK) V. 1T11 (i.e., Preview BDK released in October 1995) to the 32-bit BDK V. 1.1 (i.e., first released in September 1997):

Properties

The following properties were introduced with the 32-bit version of the RPC Broker:

Property

RPCTimeLimit

RPCVersion

Obsolete Properties

The following properties were previously included with the Broker component distributed with the BDK preview version. These properties were removed from the 32-bit version of the Broker, because they were obsolete:

Property	Disposition

ConnectMode	Removed from the RPC Broker component (i.e., TRPCBroker)

DisconnectMode	Removed from the RPC Broker component (i.e., TRPCBroker)

Protocol	Removed from the RPC Broker component (i.e., TRPCBroker)

Result	Removed from the RPC Broker component (i.e., TRPCBroker)

ServerJob	Removed from the RPC Broker component (i.e., TRPCBroker)

Method

The following method was introduced with the 32-bit version of the RPC Broker:

CreateContext

Obsolete PType Parameters

The following properties were previously included with the Broker component distributed with the BDK preview version. These properties were removed from the 32-bit version of the Broker because they were obsolete:

PType Parameter	Disposition

wordproc PType	Removed (Not Supported) – The wordproc PType was used in the preview version of the RPC Broker BDK to pass text out of memo boxes, for example. However, the 32-bit version of the Broker uses list instead of wordproc.

null PType	Removed (Not Supported) – The null PType was used in the preview version of the RPC Broker BDK. It has also been removed. If your RPC has no input parameters, you should not use the Param property.

Client Manager (obsolete)

As of Version 1.1 of the RPC Broker, the Client Manager is no longer used. The Client Manager that was originally distributed with version 1.0 of the Broker provided two types of services:

1.	It was used to invoke the RPCBI.DLL.

2.	It was used by developers to set programmer preferences for using the TRPCBroker component.

By replacing the RPCBI.DLL that was distributed with the RPC Broker V. 1.0 with the BAPI32.DLL, the Client Manager is no longer required with the 32-bit version of the Broker. Configuration of programmer preferences is done via the Broker Programmer Preferences Program.

 The RPCBI.DLL and Client Manager (i.e., CLMAN.EXE) installed with Broker V. 1.0 must not be removed from the VistA/Broker directory on the client workstation. They are still required for any 16-bit Broker-based applications created using version 1.0 of the Broker (e.g., PCMM).

VA FileMan Delphi Components (FMDC)

Sample 16-bit VA FileMan Delphi Components (FMDC) were originally distributed with the preview version of the RPC Broker Developer Kit (BDK) released in October of 1995. The 32-bit RPC Broker V. 1.1 is not compatible with the 16-bit FMDC. However, the 32-bit FileMan Delphi V. 1.0 Components (i.e., available on the Intranet in January 1997) are compatible with version 1.1 of the Broker.

Please be advised that the VA FileMan Delphi Components are not distributed with the RPC Broker.

For more information on the VA FileMan Delphi Components (FMDC), please refer to the following Web address:

http://vista.med.va.gov/fmdc/index.asp


ConnectMode Property
ConnectMode Property (obsolete)

Applied to

TRPCBroker component

Declaration

property ConnectMode:  Enumerated;

Description

Enhancements to how the Broker manages multiple connections make the ConnectMode property unnecessary. Consequently, it is being phased out. For now it has been "demoted" from published to public declaration. This means that this property will no longer be visible in the Object Inspector, however, the application will still compile. At run-time it is ignored.

If your application uses more than one Broker component, you should be aware of the component's connect and disconnect behavior.

This property was used to set the mode that determines when your application connected to the server. It could be set to one of the following values:

AsNeeded:	If the Broker component was not already connected to the server, this established a connection with the server when a call was made. This was the recommended setting. You can still manually connect the Broker component using the Connected property.

ManualConnect:	Required the developer to manually connect to the server by setting the Connected property to True.

OnCreate:	Connected to the server when the TRPCBroker component was created. This setting was ignored while in Delphi IDE.

 The ConnectMode property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).


DisconnectMode Property
DisconnectMode Property (obsolete)

Applied to

TRPCBroker component

Declaration

property DisconnectMode:  Enumerated;

Description

Enhancements to how the Broker manages multiple connections make the DisconnectMode property unnecessary. Consequently, it is being phased out. For now it has been "demoted" from published to public declaration. This means that this property will no longer be visible in the Object Inspector, however, the application will still compile. At run-time it is ignored.

If your application uses more than one Broker component, you should be aware of the component's connect and disconnect behavior.

This property was used to set the mode that determines when your application disconnected from the server. It could be set to one of the following values:

ManualDisconnect:	With this setting, the TRPCBroker did not try to disconnect from the server when it was destroyed. This setting was used when there were multiple Broker components in your application and it was not the last Broker component to be disconnected.

OnDestroy:	This setting was used to disconnect your application from the server when the TRPCBroker component was destroyed. This was used if you only had a single Broker component or it would be the last component to be disconnected when you had multiple Broker components.

 The DisconnectMode property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).


Protocol Property
Protocol Property (obsolete)

Applied to

TRPCBroker component

Description

The Protocol property was originally put in the TRPCBroker component as a placeholder for future development, however, it was never used. Thus, it has been removed from this version of the TRPCBroker component.

 The Protocol property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).


Result Property
Result Property (obsolete)

Applied to

TRPCBroker component

Description

The Result property was ambiguous with Delphi's reserved Result variable (i.e., used to return values from functions) and has been removed from this version of the Broker. What previously was returned in the Result property should now be returned in the 0th element of the Results Property referenced as Results[0].

 The Result property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).

Developer's should not just do a search and replace of the word "Result", however. In some cases the word "Result" being referenced can be Delphi's legitimate use of the reserved word.


ServerJob Property
ServerJob Property (obsolete)

Applied to

TRPCBroker component

Declaration

property ServerJob:  String

Description

The original intent of the ServerJob read-only property was to contain the $JOB of the corresponding process on the server. However, the RPC Broker has never populated this property with a value, and it is not supported in the 32-bit version of the Broker. Therefore, this property has been removed from the TRPCBroker component.

 The ServerJob property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).


Contents
RPC Broker V. 1.1 Developer's Guide

Contents

Overview

Components

(listed alphabetically)

•	TCCOWRPCBroker

•	TRPCBroker

•	TSharedBroker

•	TSharedRPCBroker

•	TXWBRichEdit

Classes

(listed alphabetically)

•	TMult

•	TParamRecord

•	TParams

•	TVistaLogin

•	TVistaUser

•	TXWBWinsock

Units

(listed alphabetically)

•	Hash

•	LoginFrm

•	MFunStr

•	RPCConf1

•	RpcSLogin

•	SplVista

•	TRPCB

•	TVCEdit

Remote Procedure Calls (RPCs)

Other RPC Broker APIs

Debugging and Troubleshooting

Developer Utilities

Tutorial

DLL Interface


 TRPCBroker Component

Properties	Methods	Example

Parent Class

TRPCBroker = class(TComponent)

Unit

TRPCB

Description

The TRPCBroker component (Trpcb.pas) provides VistA application developers with all of the client/server-related functionality in one integrated component. Using the TRPCBroker component, an application can connect to the VistA M Server by simply setting the Connected property to True. Remote procedures on the server can be executed by preparing the Param and RemoteProcedure properties and invoking either the Call, strCall or lstCall methods. The TRPCBroker component can be found on the Kernel tab in the component palette.

Properties inherited from the parent component (i.e., TComponent) are not discussed in this Help file (only those properties added to the parent component are described). For help on inherited properties, please refer to Delphi's documentation on the parent component (i.e., TComponent).


TRPCBroker Example

The following example demonstrates how a TRPCBroker component can be used to connect to the VistA M Server, execute various remote procedures, return the results and finally disconnect from the server. This example assumes that a TRPCBroker component already exists on the form as brkrRPCBroker1:

procedure TForm1.Button1Click(Sender: TObject);

begin

  try

    {connect to the server}

    brkrRPCBroker1.Connected := True;

    //assign RPC name

    brkrRPCBroker1.RemoteProcedure := 'SOME APPLICATION RPC';

    {make the call}

    brkrRPCBroker1.Call;

    {display results}

    ListBox1.Items := brkrRPCBroker1.Results;

    {disconnect from the server}

    brkrRPCBroker1.Connected := False;

  except

    //put error handling code here

  end;

end;

For more examples, please refer to the Samples directory on the use of the TRPCBroker component:

..\BDK32\Samples\RPCBroker


TRPCBroker Properties

TRPCBroker	Legend

BrokerVersion

ClearParameters

ClearResults

Connected

CurrentContext

DebugMode

IsBackwardCompatibleConnection

IsNewStyleConnection

KernelLogIn

ListenerPort

LogIn

OldConnectionOnly

OnRPCBFailure

Param

RemoteProcedure

Results

RPCBError

RPCTimeLimit

RPCVersion

Server

ShowErrorMsgs

Socket

User


TRPCBroker Methods

TRPCBroker

Call

CreateContext

lstCall

pchCall

strCall


BrokerVersion Property
BrokerVersion Property (read-only)

Applies to

TRPCBroker component

Declaration

property BrokerVersion:  String;

Description

The BrokerVersion property is available at run-time only. This read-only property indicates the RPC Broker version used in generating the application (currently, it returns the string "XWB*1.1*40").


ClearParameters Property

Example

Applies to

TRPCBroker component

Declaration

property ClearParameters:  Boolean;

Description

The ClearParameters design-time property gives the developer the option to clear the Param property following every invocation of the Call, strCall, or the lstCall methods. Setting ClearParameters to True clears the Param property.

Simple assignment of True to this property clears the Param property after every invocation of the Call, strCall, and lstCall methods. Thus, the parameters need only be prepared for the next call without being concerned about what was remaining from the previous call. By setting ClearParameters to False, the programmer can make multiple calls with the same Param property. It is also appropriate to set this property to False when a majority of the parameters in the Param property should remain the same between calls. However, minor changes to the parameters can still be made.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.


ClearParameters Example

The following program code sets the ClearParameters property to True:

procedure TForm1.Button1Click(Sender: TObject);

begin

  brkrRPCBroker1.ClearParameters := True;

end;


ClearResults Property

Example

Applies to

TRPCBroker component

Declaration

property ClearResults:  Boolean;

Description

The ClearResults design-time property gives the developer the option to clear the Results property prior to every invocation of the Call method. The strCall and lstCall methods are unaffected by this property. Setting ClearResults to True clears the Results property.

If this property is True, then the Results property is cleared before every invocation of the Call method, thus, assuring that only the results of the last call are returned. Conversely, a setting of False accumulates the results of multiple calls in the Results property.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.


ClearResults Example

The following program code sets the ClearResults property to True:

procedure TForm1.Button1Click(Sender: TObject);

begin

  brkrRPCBroker1.ClearResults := True;

end;


Connected Property

Example

Applies to

TRPCBroker component

Declaration

property Connected:  Boolean;

Description

The Connected design-time property connects your application to the VistA M Server:

•	Setting this property to True connects the application to the server.

•	Setting it to False disconnects the application from the server.

It is not necessary for your application to manually establish a connection to the VistA M Server. This version of the Broker automatically connects and disconnects from the server. When you invoke an RPC, if a connection has not already been established, one will be established for you. However, a user will not be able to run your RPC unless a context has been created with the CreateContext method.

There are other advantages to establishing a connection manually. You can check if a connection is established, and branch accordingly depending on whether a connection was established or not. One good place to do this is in your application form's OnCreate event. For that event, you could include code like the following:

try

   brkrRPCBroker1.Connected:= True;

except

   on EBrokerError do

   begin

       ShowMessage('Connection to server could not be established!');

       Application.Terminate;

   end;

end;

This code sets the TRPCBroker component's Connected property to True to establish a connection. If a Broker exception (i.e., EBrokerError) was raised (in which case the connection wasn't established), it provides a message to the user and calls the Terminate method to exit.

To verify that your application is connected to the VistA M Server, check the value of the Connected property.

If a connected TRPCBroker component is destroyed (when the application is closed, for example), that component will first disconnect from the VistA M Server. However, for programming clarity, it is advisable to disconnect your application from the server manually by setting the Connected property to False.

If your application uses more than one Broker component, you should be aware of the component's connect and disconnect behavior.


Connected Example

The following program code sets the Connected property to True:

procedure TForm1.btnConnectClick(Sender: TObject);

begin

  brkrRPCBroker1.Server := edtServer.Text;

  brkrRPCBroker1.ListenerPort := StrToInt(edtPort.Text);

  brkrRPCBroker1.Connected := True;

end;

The Server and ListenerPort properties must be set at design or run-time before setting the Connected property to True.


CurrentContext Property
CurrentContext Property (read-only)

Example

Applies to

TRPCBroker component

Declaration

property CurrentContext: String;

Description

The CurrentContext property is available at run-time only. This read-only property provides the current context. Developers can save off the current context into a local variable, set a new context, and then restore the original context from the local variable before finishing. This permits the application to use the CreateContext method with an additional context when an initial context has already been established.


DebugMode Property

Applies to

TRPCBroker component

Declaration

property DebugMode:  Boolean;

Description

The DebugMode design-time property controls how the VistA M Server process should be started. The default setting is False.

A setting of False starts the VistA M Server in the usual manner, as a background process.

For debugging purposes, it can be very helpful to set break points, run the server process interactively, and step through the execution. For those situations, set this property to True. When the TRPCBroker component connects with this property set to True, you get a dialog window indicating your workstation Internet Protocol (IP) address and the port number.

At this point you should switch over to the server, enter any break points that you wish, issue the debug command (e.g., ZDEBUG in DSM), and start the following server process:

>D EN^XWBTCP

You will be prompted for the workstation Internet Protocol (IP) address and the port number. After entering the information, switch over to the client application and click on the OK button of the dialog window.

For more information, please refer to the "How to Debug Your Application" topic.


IsBackwardCompatibleConnection Property

Applies to

TRPCBroker component

Declaration

property IsBackwardCompatibleConnection:  Boolean;

Description

The IsBackwardCompatibleConnection property is used to determine whether the connection to be made should be an old-style (i.e., callback) or a new-style (i.e., non-callback) RPC Broker connection. When set to True, the RPC Broker makes a regular callback connection. If this property is set to False, the RPC Broker makes a non-callback connection. The default value is True. The value should be set to False if any of the ParamType values available with RPC Broker Patch XWB*1.1*40 are used in RPCs.

This property was introduced with RPC Broker Patch XWB*1.1*35.


IsNewStyleConnection Property
IsNewStyleConnection Property (read-only)

Applies to

TRPCBroker component

Declaration

property IsNewStyleConnection:  Boolean;

Description

The IsNewStyleConnection property is available at run-time only. This read-only property indicates whetheror not the current connection is a new-style (i.e., non-callback) connection.


KernelLogIn Property

Example

Applies to

TRPCBroker component

Declaration

property KernelLogIn:  Boolean;

Description

The KernelLogin design-time property is a Boolean property, which indicates the manner of sign-in:

•	If True, the regular Kernel login security form will be presented.

•	If False, the Broker will use the TVistaLogin class for signon.

The TVistaLogin class is referenced during Silent Login.


ListenerPort Property

Example

Applies to

TRPCBroker component

Declaration

property ListenerPort:  Integer;

Description

The ListenerPort design-time property gives the developer the ability to select the Listener port on the VistA M Server. It must always be set before connecting to the server.

If one VistA M Server system has two or more environments (UCIs) that support client/server applications (e.g., Test and Production accounts), the Broker Listener processes must be listening on unique ports. Thus, you must specify which Listener port to use when you start the Listener on the VistA M Server. Consequently, if you have more than one Listener running on the same server, the application needs to specify the correct Listener for its connection request. This is accomplished using the ListenerPort property.

After the initial connection, the VistA M Server connection is moved to another port number (i.e., Socket), which is used for the remainder of the session.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.


ListenerPort Example

The following program code demonstrates using the ListenerPort property:

procedure TForm1.btnConnectClick(Sender: TObject);

begin

  brkrRPCBroker1.ListenerPort := 9001;

  brkrRPCBroker1.Connected := True;

end;


LogIn Property

Example

Applies to

TRPCBroker component

Declaration

property LogIn:  TVistaLogin;

Description

The LogIn property is available at run-time only. It holds parameters that the application needs to pass for Silent Login. The instance of the TVistaLogin used for this property is created automatically during the creation of the TRPCBroker object and is therefore available for reference as a TRPCBroker property without any user setup.


OldConnectionOnly Property

Applies to

TRPCBroker component

Declaration

property OldConnectionOnly:  Boolean;

Description

The OldConnectionOnly property can be set to True if only an old-style (i.e., callback) connection is desired. This is primarily for programmers—during debugging, if an initial connection is not a new-style (i.e., non-callback) RPC Broker connection, an error message is displayed. Pressing OK and F9 (run) causes the old-style (or callback) connection to be made. However, setting this property to True does away with the initial attempt to make a new-style connection, and thus, the error message during debugging. The error message is not seen outside of the debugger within Delphi.

 Applications should not be released with this property set to True!


OnRPCBFailure Property

Example

Applies to

TRPCBroker component

Declaration

property OnRPCBFailure:  TOnRPCBFailure;

Description

The OnRPCBFailure property is available at run-time only. It holds a procedure to be invoked when the Broker generates an exception that permits an application to handle errors as desired, where TOnRPCBFailure is defined as:

TOnRPCBFailure = procedure (RPCBroker: TRPCBroker) of object;

The text associated with the error causing the exception will be found in the RPCBError property.

If OnFailedLogin is also set, it will handle any login errors and not pass them up.

Run the "Error Handling Demo" application (i.e., XWBOnFail.EXE, located in the ..\BDK\Samples\SilentSignOn p [13] directory), to illustrate the effects of TRPCBroker properties related to Error Handling.


Param Property

Example

Applies to

TRPCBroker component

Declaration

property Param:  TParams;

Description

The Param property is available at run-time only. It holds all of the parameters that the application needs to pass to the remote procedure using the Call, strCall, or lstCall methods.

Param is a zero-based array of TParamRecord. You don't need to explicitly allocate any memory for the Param property. Simple reference to an element or a value assignment ( := ) dynamically allocates memory as needed. You should start with the 0th element and proceed in sequence. Do not skip elements.

Each element in the Param array has the following properties:

Mult

PType

Value

 Passing multiple parameters of PType list in one remote procedure call (RPC) is not supported at this time. Only one list parameter can be passed to an RPC, and it must be the last parameter in the actual list.

The Param relationship to the TRPCBroker component is as follows:

The TRPCBroker component contains the Param property (i.e., TParams class).

The TParams class contains the ParamArray property (array [I:integer]: TParamRecord class).

The TParamRecord class contains the Mult property (i.e., TMult class).

The TMult class contains the MultArray property (array[S: string]: string).

The MultArray property internally uses a TStringList in which each element’s object is a TString.

If the remote procedure on the VistA M Server does not require any incoming parameters, applications can pass an empty Param property. The client application merely sets the RemoteProcedure property and makes the call. If the Param property retains a value from a previous call, it can be cleared using the ClearParameters property. Thus, it is possible to make a call without passing any parameters.

 The following restrictions apply with the Param property:

1.	You are not allowed to "skip" passing parameters, such as TAG^ROUTINE(1,,3), where you can skip passing the second parameter in DSM code. If you have fewer elements in your Param array than exist as input parameters in your RPC, the subsequent parameters will not be passed to the RPC.

2.	Passing multiple array parameters in one remote procedure call is not supported at this time. Only one array parameter can be passed to an RPC, and it must be the last parameter in the actual list.

For a demonstration using the Param property, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


Param Example

The following program code demonstrates how the Param property of a TRPCBroker component is referenced and filled with two parameters that the remote procedure expects:

procedure TForm1.Button1Click(Sender: TObject);

begin

  {first parameter is a single string}

  brkrRPCBroker1.Param[0].Value := '05/01/97';

  brkrRPCBroker1.Param[0].PType := literal;

  {second parameter is a list}

  brkrRPCBroker1.Param[1].Mult['"NAME"'] := 'SMITH,JOHN';

  brkrRPCBroker1.Param[1].Mult['"SSN"'] := '123-45-6789';

  brkrRPCBroker1.Param[1].PType := list;

end;

For a demonstration using the Param property, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


RemoteProcedure Property

Example

Applies to

TRPCBroker component

Declaration

property RemoteProcedure:  TRemoteProc;

Description

The RemoteProcedure design-time property should be set to the name of the remote procedure call entry in the REMOTE PROCEDURE file (#8994).


RemoteProcedure Example

The following program code demonstrates using the RemoteProcedure property:

procedure TForm1.Button1Click(Sender: TObject);

begin

  brkrRPCBroker1.RemoteProcedure := 'MY APPLICATION REMOTE PROCEDURE';

  brkrRPCBroker1.Call;

end;


Results Property

Example

Applies to

TRPCBroker component

Declaration

property Results:  Tstrings;

Description

The Results design-time property contains the results of a Call method. In the case where the RPC returns a single value, it will be returned in Results[0]. If a call returns a list of values, the Results property will be filled in the order the list collates on the VistA M Server. The Results property can only contain values of array elements – subscripts are not returned.

For example:

On the VistA M Server, the M routine constructs the list in the following sequence:

S LIST("CCC")="First"

S LIST(1)="Second"

S LIST("AAA")="Third"

S LIST(2)="Fourth"

Before Broker returns the list to the client, M will re-sort it in alphabetical order:

LIST(1)="Second"

LIST(2)="Fourth"

LIST("AAA")="Third"

LIST("CCC")="First"

On the client, the Results property will contain the following:

brkrRPCBroker1.Results[0]=Second

brkrRPCBroker1.Results[1]=Fourth

brkrRPCBroker1.Results[2]=Third

brkrRPCBroker1.Results[3]=First


Results Example

The following program code demonstrates using the Results property:

procedure TForm1.btnSendClick(Sender: TObject);

begin

  {clears Results between calls}

  brkrRPCBroker1.ClearResults := True;

  {the following code returns a single value}

  brkrRPCBroker1.RemoteProcedure := 'SEND BACK SOME SINGLE VALUE';

  brkrRPCBroker1.Call;

  Label1.Caption := 'Value returned is: ' + brkrRPCBroker1.Results[0];

  {the following code returns several values}

  brkrRPCBroker1.RemoteProcedure := 'SEND BACK LIST OF VALUES';

  brkrRPCBroker1.Call;

  ListBox1.Items := RPCBroker.Results;

end;


RPCBError Property
RPCBError Property (read-only)

Applies to

TRPCBroker component

Declaration

property RPCBError:  String;

Description

The RPCBError property is available at run-time only. This read-only property contains the Message property associated with the exception or error that was encountered by the instance of the TRPCBroker component.


RPCTimeLimit Property

Example

Applies to

TRPCBroker component

Declaration

property RPCTimeLimit:  Integer;

Description

The RPCTimeLimit property is a public integer property that is available at run-time only. It specifies the length of time a client will wait for a response from an RPC. The default and minimum value of this property is 30 seconds. If an RPC is expected to take more than 30 seconds to complete, adjust the RPCTimeLimit property accordingly. However, it is not advisable to have an RPCTimeLimit that is too long. Otherwise, the client-end of the application will appear to "hang", if the VistA M Server doesn’t respond in a timely fashion.


RPCTimeLimit Example

The following program code demonstrates using the RPCTimeLimit property:

procedure TForm1.Button1Click(Sender: TObject);

var

  intSaveRPCTimeLimit: integer;

begin

  brkrRPCBroker1.RemoteProcedure := 'GET ALL LAB RESULTS';

  brkrRPCBroker1.Param[0].Value := 'DFN';

  brkrRPCBroker1.Param[0].PType := reference;

  {save off current time limit}

  intSaveRPCTimeLimit := brkrRPCBroker1.RPCTimeLimit;

  {can take up to a minute to complete}

  brkrRPCBroker1.RPCTimeLimit := 60;

  brkrRPCBroker1.Call;

  {restore previous time limit}

  brkrRPCBroker1.RPCTimeLimit := intSaveRPCTimeLimit;

end;


RPCVersion Property

Example

Applies to

TRPCBroker component

Declaration

property RPCVersion:  String;

Description

The RPCVersion design-time property is a published string type property used to pass the version of the RPC. This can be useful for backward compatibility.

As you introduce new functionality into an existing RPC, your RPC can branch into different parts of the code based on the value of the RPCVersion property. The Broker sets the XWBAPVER variable on the VistA M Server to the contents of the RPCVersion property. This property cannot be empty and defaults to "0" (zero).

You may wish to use the application version number in the RPCVersion property.

For a suggested method for constructing version numbers, please refer to the Application Issues topic.


RPCVersion Example

In the following example, an RPC is first called with two parameters that will be added together and the sum returned to the client. Again, this same RPC is called with the same parameters, however, this time it uses a different RPC version value. Thus, the two numbers are simply concatenated together and the resulting string is returned:

On the client:

procedure TForm1.Button1Click(Sender: TObject);

begin

  {make sure the results get cleared}

  brkrRPCBroker1.ClearResults := True;

  {just re-use the same parameters}

  brkrRPCBroker1.ClearParameters := False;

  brkrRPCBroker1.RemoteProcedure := 'MY APPLICATION REMOTE PROCEDURE';

  brkrRPCBroker1.Param[0].Value := '333';

  brkrRPCBroker1.Param[0].PType := literal;

  brkrRPCBroker1.Param[1].Value := '444';

  brkrRPCBroker1.Param[1].PType := literal;

  brkrRPCBroker1.Call;

  {the result will be 777}

  Label1.Caption := 'Result of the call: ' + brkrRPCBroker1.Results[0];

  brkrRPCBroker1.RPCVersion := '2';

  brkrRPCBroker1.Call;

  {the result will be 333444}

  Label2.Caption := 'Result of the call: ' + brkrRPCBroker1.Results[0];

end;

On the server:

TAG(RESULT,PARAM1,PARAM2)	;Code for MY APPLICATION REMOTE PROCEDURE

IF XWBAPVER<2 SET RESULT=PARAM1+PARAM2

ELSE  SET RESULT=PARAM1_PARAM2

QUIT RESULT


Server Property

Example

Applies to

TRPCBroker component

Declaration

property Server:  String;

Description

The Server design-time property contains the name or Internet Protocol (IP) address of the VistA M Server system. If the name is used instead of the IP address, Microsoft Windows Winsock should be able to resolve it. Winsock can resolve a name to an IP address either through the Domain Name Service (DNS) or by looking it up in the HOSTS file on the client workstation. In the case where the same name exists in the DNS and in the HOSTS file, the HOSTS file entry takes precedence. Changing the name of the VistA M Server while the TRPCBroker component is connected disconnects the TRPCBroker component from the previous server.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.


Server Example

The following program code demonstrates using the Server property:

procedure TForm1.btnConnectClick(Sender: TObject);

begin

  brkrRPCBroker1.ListenerPort := 9200;

  brkrRPCBroker1.Server := 'DHCPSERVER';

  brkrRPCBroker1.Connected := True;

end;


ShowErrorMsgs Property

Applies to

TRPCBroker component

Declaration

property ShowErrorMsgs:  TShowErrorMsgs;

Description

The ShowErrorMsgs design-time property gives the developer the ability to determine how an exception will be handled, if an error handler has not been provided through the OnRpcbError property (i.e., a procedure property that is set to the name of a procedure that will be called if an error is encountered). If the OnRpcbError property is assigned, then exception processing will be delegated to that procedure. Otherwise, exception handling will be based on the value of ShowErrorMsgs property.

The following table lists the possible values:

Value	Meaning

semRaise (default)	This is the default value. The Broker will not handle the error directly but pass it off to the application in general to process, which may result in a different message box display or some other type of error indication.

semQuiet	The error will not be displayed or raised. This requires the application to check the value of the RpcbError property following calls to the Broker to determine whether an error has occurred, and if so, what the error was. This may be desirable, if the application requires that errors not result in display boxes, etc., as might be the case with an NT service or Web application.

Run the "Error Handling Demo" application (i.e., XWBOnFail.EXE, located in the ..\BDK\Samples\SilentSignOn p [13] directory), to illustrate the effects of TRPCBroker properties related to Error Handling.


Socket Property

Example

Applies to

TRPCBroker component

Declaration

property Socket:  Integer;

Description

The Socket property is available at run-time only. It contains the active port being used for the TCP/IP connection to the VistA M Server. This is the port that is currently in use on the server as opposed to the ListenerPort that was used to make the initial connection. After the initial connection, the server connection is moved to another port number (i.e., Socket), which is used for the remainder of the session.


Socket Example

The following program code populates the Socket property with the active port on the VistA M Server:

function ExistingSocket(Broker: TRPCBroker): integer;

var

  Index: integer;

begin

  Result := 0;

  if Assigned(BrokerConnections) and

     BrokerConnections.Find(Broker.Server + ':' + IntToStr(Broker.ListenerPort), Index) then

    Result := TRPCBroker(BrokerConnections.Objects[Index]).Socket;

end;


User Property

Example

Applies to

TRPCBroker component

Declaration

property User:  TVistaUser;

Description

The User property is available at run-time only. This instance of the TVistaUser object is created during the Create process for the TRPCBroker instance. The object contains data on the current user and is updated as a part of the user authentication process.


EBrokerError

Unit

TRPCB

Description

The EBrokerError is an exception raised by the TRPCBroker component. This exception is raised when an error is encountered when communicating with the VistA M Server. You should use a try…except block around all server calls to handle any EbrokerError exceptions that may occur.

For example:

try

   brkrRPCBroker1.Connected:= True;

except

   on EBrokerError do

   begin

       ShowMessage('Connection to server could not be established!');

       Application.Terminate;

   end;

end;

For descriptions/resolutions to specific error messages that can be displayed by EBrokerError, please refer to the Broker Error Messages topic.


TParamRecord Class

Properties	Example

Unit

TRPCB

Description

The TParamRecord class is used to hold all of the information on a single RPC parameter. Depending on the type of the parameter needed, different properties are used. The PType property is always used to let the Broker on the VistA M Server know how to interpret the parameter. For a single value parameter, the Value property should be used. In the case of a list or a word-processing text, use the Mult property.

The TParamRecord relationship to the TRPCBroker component is as follows:

The TRPCBroker component contains the Param property (i.e., TParams class).

The TParams class contains the ParamArray property (array [I:integer]: TParamRecord class).

The TParamRecord class contains the Mult property (i.e., TMult class).

The TMult class contains the MultArray property (array[S: string]: string).

The MultArray property internally uses a TStringList in which each element’s object is a TString.

 Developers should rarely have a need to use TParamRecord by itself in their code. TParamRecord is the type of the elements in the ParamArray, default array property of the TRPCBroker component Param property. This means that when you are working with a Param[x] element, you are in reality working with an instance of TParamRecord.


TParamRecord Example

The following program code demonstrates how you can use a TParamRecord variable to save a copy of a single parameter of a TRPCBroker component. This example assumes that prior to calling this procedure, a TRPCBroker variable has been created and some parameters have been set up. Pay close attention to how properties are copied one at a time. This is the only way that a separate copy could be created. If you try to simply assign one of the TRPCBroker parameters to the TParamRecord variable, you’ll simply re-point the TParamRecord variable to that parameter:

procedure TForm1.Button1Click(Sender: TObject);

var

  ParamRecord: TParamRecord;

begin

  {Create ParamRecord. Make Form1 its owner}

  ParamRecord := TParamRecord.Create(Form1);

  {Store properties one at a time}

  ParamRecord.Value := RPCBroker.Param[0].Value;

  ParamRecord.PType := RPCBroker.Param[0].PType;

  {This is how to copy a Mult}

  ParamRecord.Mult.Assign(RPCBroker.Param[0].Mult);

end;


TParamRecord Properties

TParamRecord

Mult

PType

Value


Value Property

Example

Applies to

TParamRecord class

Declaration

property Value:  String;

Description

The Value design-time property is used to pass either a single string or a single variable reference to the VistA M Server, depending on the PType.


Value Example

The following program code demonstrates a couple of different uses of the Value property. Remember that each Param[x] element is really a TParamRecord-type class.

procedure TForm1.Button1Click(Sender: TObject);

begin

  with brkrRPCBroker1 do begin

    RemoteProcedure := 'SET NICK NAME';

    {A variable reference}

    Param[0].Value := 'DUZ';

    Param[0].Ptype := reference;

    {A string}

    Param[1].Value := edtNickName.Text;

    Param[1].Ptype := literal;

    Call;

  end;

end;


PType Property

Example

Applies to

TParamRecord class

Declaration

property PType:  TParamType;

Description

(PType is a property of the TParamRecord used in the Param property.)

The PType design-time property determines how the parameter will be interpreted and handled by the Broker.

Value	Definition

literal	The VistA M Server receives the contents of the corresponding Value property as one string or one number.

reference	The VistA M Server receives the contents of the corresponding Value property as a name of a variable defined on the server. Using indirection, the Broker on the server will resolve this parameter before handing it off to the application.

list	This value is used whenever an application wants to send a list of values to the VistA M Server. Data is placed in a local array. In this case, the contents of the corresponding Mult property is sent, while the Value property is ignored.

global	This value is similar to list, but instead of data being placed in a local array, it is placed in a global array. Use of this value removes the potential problem of allocation errors when large quantities of data are transmitted. This value was made available with RPC Broker Patch XU*1.1*40.

empty	This value indicates that no parameter value is to be passed; it simply passes an empty argument.. This value was made available with RPC Broker Patch XU*1.1*40.

stream	This value indicates that the data should be passed as a single stream of data.. This value was made available with RPC Broker Patch XU*1.1*40.

undefined	The Broker uses this value internally. It should not be used by an application.

For instance, if you need to pass an empty string to the remote procedure call (RPC), the Value property should be set to '' (i.e., null) and the PType to literal. Using reference, a programmer can pass an M variable (e.g., DUZ) without even knowing its value. However, If the M variable being referenced is not defined on the VistA M Server, a run-time error will occur. When passing a list to an RPC: set the PType to list, populate the Mult property, and don't put anything into the Value property (in this case, Value is ignored).

For a demonstration using PType, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


PType Example

The following program code demonstrates a couple of different uses of the PType property. Remember that each Param[x] element is really a TParamRecord-type class.

procedure TForm1.Button1Click(Sender: TObject);

begin

  with brkrRPCBroker1 do begin

    RemoteProcedure := 'SET NICK NAME';

    Param[0].Value := 'DUZ';

    Param[0].PType := reference;

    Param[1].Value := edtNickName.Text;

    Param[1].PType := literal;

    Call;

  end;

end;

For a demonstration using PType, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


TParamType

Unit

TRPCB

Declaration

TParamType = (literal, reference, list, global, empty, stream, undefined);

Description

The TParamType type defines the possible values of the RPC parameter type (PType property of TParamRecord class).

RPC Broker Patch XU*1.1*40 added the global, empty, and stream values. These values can only be used if a new-style (i.e., non-callback) connection is present (and if these are to be used, it is recommended that the TRPCBroker IsBackwardCompatibleConnection be set to False to insure that only a new-style connection can be made).

 Use of the undefined TParamType in applications is not supported. It exists for the RPC Broker’s internal use only.


Mult Property

Example

Applies to

TParamRecord class

Declaration

property Mult: TMult;

Description

(Mult is a property of the TParamRecord used in the Param property.)

The Mult design-time property of a TParamRecord class, which is the type of each TRPCBroker component’s Param[x] element, can be used to pass a string-subscripted array of strings to the VistA M Server. For example, if you need to pass a patient's name and SSN to a remote procedure, you could pass them as two separate parameters as PType literals, or you could pass them in one parameter using the Mult property as a PType list. If one is being sent, a Mult must be the last element in the Param array.


Mult Example

The following program code demonstrates how the Mult property can be used to pass several data elements to the VistA M Server in one parameter:

procedure TForm1.Button1Click(Sender: TObject);

begin

  with brkrRPCBroker1 do begin

    Param[0].PType :=list;

    Param[0].Mult['"NAME"'] := 'DOE,JOHN';

    Param[0].Mult['"SSN"'] := '123456789';

    RemoteProcedure := 'SETUP PATIENT INFO';

    Call;

  end;

end;

Assuming variable P1 is used on the VistA M Server to receive this array, it would look like the following:

P1("NAME")=DOE,JOHN

P1("SSN")=123456789


Call Method

Example

procedure Call;

This method executes a remote procedure on the VistA M Server and returns the results in the Results property. Call expects the name of the remote procedure and its parameters to be set up in the RemoteProcedure and Param properties respectively. If ClearResults is True, then the Results property is cleared before the call. If ClearParameters is True, then the Param property is cleared after the call finishes.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the RPC Limits topic.

Whenever the Broker makes a call to the VistA M Server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration using the Call method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


Call Example

The following program code demonstrates the use of the Call method in a hypothetical example of bringing back demographic information for a patient and then displaying the results in a memo box:

procedure TForm1.Button1Click(Sender: TObject);

begin

  brkrRPCBroker1.RemoteProcedure := 'GET PATIENT DEMOGRAPHICS';

  brkrRPCBroker1.Param[0].Value := 'DFN';

  brkrRPCBroker1.Param[0].PType := reference;

  brkrRPCBroker1.Call;

  Memo1.Lines := brkrRPCBroker1.Results;

end;

For a demonstration using the Call method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


CreateContext Method

Example

function CreateContext(strContext: string): boolean;

You can use the CreateContext method of the TRPCBroker component to create a context for your application. To create context, pass an option name in the strContext parameter. If the function returns True, a context was created, and your application can use all RPCs entered in the option's RPC multiple. If the TRPCBroker component is not connected at the time context is created, a connection will be established. If for some reason a context could not be created, the CreateContext method will return False.

Since context is nothing more than a client/server "B"-type option in the OPTION file (#19), standard MenuMan security is applied in establishing a context. Therefore, a context option can be granted to user(s) exactly the same way as regular options are done using MenuMan. Before any RPC can run, it must have a context established for it to on the VistA M Server. Thus, all RPCs must be registered to one or more "B"-type option(s). This plays a major role in Broker security.

A context cannot be established for the following reasons:

•	The user has no access to that option.

•	The option is temporarily out of order.

An application can switch from one context to another as often as it needs to. Each time a context is created the previous context is overwritten.

Please refer to the CurrentContext property for information about saving off the current context in order to temporarily create a different context and then restore the previous context.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the RPC Limits topic.

Whenever the Broker makes a call to the VistA M Server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration that creates an application context, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


CreateContext Example

The following program code demonstrates the use of the CreateContext method:

procedure TForm1.Button1Click(Sender: TObject);

begin

  brkrRPCBroker1.Connected := True;

  if brkrRPCBroker1.CreateContext('MY APPLICATION') then

    Label1.Caption := 'Context MY APPLICATION was successfully created.'

  else

    Label1.Caption := 'Context MY APPLICATION could not be created.';

end;

For a demonstration that creates an application context, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


lstCall Method

Example

procedure lstCall(OutputBuffer: Tstrings);

This method executes a remote procedure on the VistA M Server and returns the results into the passed Tstrings- or TStringList-type variable, which you create outside of the call. It is important to free the memory later. lstCall expects the name of the remote procedure and its parameters to be set up in the RemoteProcedure and Param properties respectively. The Results property is not affected by this call. If ClearParameters is True, then the Param property is cleared after the call finishes.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the RPC Limits topic.

Whenever the Broker makes a call to the VistA M Server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration using the lstCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


lstCall Example

The following program code demonstrates the use of the lstCall method in a hypothetical example of bringing back a list of user's keys and automatically filling a list box with data:

procedure TForm1.Button1Click(Sender: TObject);

begin

  brkrRPCBroker1.RemoteProcedure := 'GET MY KEYS';

  brkrRPCBroker1.lstCall(ListBox1.Items);

end;

For a demonstration using the lstCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


strCall Method

Example

function strCall: string;

This method executes a remote procedure on the VistA M Server and returns the results as a value of a function. The strCall method expects the name of the remote procedure and its parameters to be set up in the RemoteProcedure and Param properties respectively. The Results property is not affected by this call. If ClearParameters is True, then the Param property is cleared after the call finishes.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the RPC Limits topic.

Whenever the Broker makes a call to the VistA M Server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration using the strCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


strCall Example

The following program code demonstrates the use of the strCall method in a hypothetical example of bringing back the name of the user currently logged on and automatically displaying it in a label:

procedure TForm1.Button1Click(Sender: TObject);

begin

  brkrRPCBroker1.RemoteProcedure := 'GET CURRENT USER NAME';

  Label1.Caption := brkrRPCBroker1.strCall;

end;

For a demonstration using the strCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


TMult Class

Properties	Methods	Example

Unit

TRPCB

Description

The TMult class is used whenever a list of multiple values needs to be passed to a remote procedure call (RPC) in a single parameter. The Mult property of a parameter is of TMult type. The information put in the TMult variable is really stored in a TStringList, but the access methods (used to read and write) take strings as subscripts and provide the illusion of a string-subscripted array.

It’s important to note that items in a TMult class may or may not be sorted. If the Sorted property is False (default), then the elements will be stored in the order they are added. If Sorted is True, items will be stored in ascending alphabetical order by subscripts.

If you attempt to reference an element by a nonexistent subscript you will get an error in form of a Delphi exception. Don’t forget that M syntax dictates that all strings must be surrounded by double quotes. So, if your goal is to pass a string subscripted array of strings using TMult as a parameter to an RPC on the VistA M Server, don’t forget to surround each of the subscripts and their associated values with double quotes ("). Otherwise, M will assume that you’re passing a list of variables and will attempt to reference them, which is probably not what you want.


TMult Example

The following program code demonstrates how to store and retrieve elements from a TMult variable:

procedure TForm1.Button1Click(Sender: TObject);

var

  Mult: TMult;

  Subscript: string;

begin

  {Create Mult. Make Form1 its owner}

  Mult := TMult.Create(Form1);

  {Store element pairs one by one}

  Mult['First'] := 'One';

  Mult['Second'] := 'Two';

  {Use double quotes for M strings}

  Mult['"First"'] := '"One"';

  {Label1.Caption will get "One"}

  Label1.Caption := Mult['"First"'];

  {Error! 'Third' subscripted element was never stored}

  Label1.Caption := Mult['Third'];

end;


TMult Properties

TMult

Count

First

Last

Sorted


TMult Methods

TMult

Assign

Order

Position

Subscript


Count Property (TMult Class)

Example

Applies to

TMult class

Declaration

property Count: Word;

Description

The Count design-time property contains the number of items in a TMult class. If TMult class is empty, Count will be zero.


Count Example (TMult Class)

The following program code displays the number of items in a Mult class in the caption of a label when the user clicks the CountItems button:

procedure TForm1.CountItemsClick(Sender: TObject);

begin

  Label1.Caption := 'There are ' + IntToStr(Mult.Count) +

    ' items in the Mult.';

end;


First Property

Example

Applies to

TMult class

Declaration

property First: String;

Description

The First design-time property contains the subscript of the first item in a TMult class. The first item is always in the 0th Position. You can think of the First property as a short cut to executing the TMult.Order(‘’,1) method. If a TMult variable does not contain any items, the First property will be empty.


First Example

The following program code displays the subscript and value of the first item in a Mult variable in the caption of a label when the user clicks the GetFirst button:

procedure TForm1.GetFirstClick(Sender: TObject);

var

  Mult: TMult;

  Subscript: string;

begin

  {Create Mult. Make Form1 its owner}

  Mult := TMult.Create(Form1);

  Mult['Fruit'] := 'Apple';

  {Store element pairs one by one}

  Mult['Vegetable'] := 'Potato';

  Label1.Caption := 'The subscript of the first element: ' + Mult.First + ', and its value: ' + Mult[Mult.First];

end;


Last Property

Example

Applies to

TMult class

Declaration

property Last: String;

Description

The Last design-time property contains the subscript of the last item in a TMult class. The last item is always in count-1 Position. You can think of the Last property as a short cut to executing the TMult.Order(‘’,-1) method. If a TMult variable does not contain any items, the Last property will be empty.


Last Example

The following program code displays the subscript and value of the last item in a Mult variable in the caption of a label when the user clicks the GetLast button:

procedure TForm1.GetLastClick(Sender: TObject);

var

  Mult: TMult;

  Subscript: string;

begin

  {Create Mult. Make Form1 its owner}

  Mult := TMult.Create(Form1);

  Mult['Fruit'] := 'Apple';

  {Store element pairs one by one}

  Mult['Vegetable'] := 'Potato';

  Label1.Caption := 'The subscript of the last element: ' + Mult.Last +

    ', and its value: ' + Mult[Mult.Last];

end;


Sorted Property

Example

Applies to

TMult class

Declaration

property Sorted:  Boolean;

Description

The Sorted design-time property value determines the order of the items in a TMult variable. If Sorted is True, the items are sorted in ascending order of their string subscripts. If Sorted is False (default), the items are unsorted, and will appear in the order they were added. Keep in mind that changing Sorted from False to True will irreversibly sort the list so that changing Sorted back to False will not put the list back in its original order, unless the original order was already sorted of course.


Sorted Example

The following program code demonstrates the effect the Sorted property has on a TMult variable. Notice that by setting the Sorted property back to False, the list does not revert to its unsorted order:

1.	Start a new application.

2.	Drop one memo and one button on the form. Arrange controls as in the figure below.

3.	Copy the following code to the Button1.OnClick event:

procedure TForm1.Button1Click(Sender: TObject);

var

  Mult1: TMult;

  Subscript: string;

begin

  //Create Mult1. Make Form1 its owner

  Mult1 := TMult.Create(Form1);

  //Fill Mult1 with some strings

  Mult1['First'] := 'One';

  Mult1['Second'] := 'Two';

  Mult1['Third'] := 'Three';

  Mult1['Fourth'] := 'Four';

  Mult1['Fifth'] := 'Five';

  //configure memo box for better display

  Memo1.Font.Name := 'Courier';

  Memo1.ScrollBars := ssVertical;

  Memo1.Lines.Clear;

  Memo1.Lines.Add('Natural order:');

  //set a starting point

  Subscript := '';

  repeat

    //get next Mult element

    Subscript := Mult1.Order(Subscript, 1);

    //if not the end of list

    if Subscript <> '' then

      //display subscript – value

      Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])

  //stop when reached the end

  until Subscript = '';

  //list will now be sorted alphabetically

  Mult1.Sorted := True;

  Memo1.Lines.Add('');

  Memo1.Lines.Add('Sorted order:');

  //set a starting point

  Subscript := '';

  repeat

    //get next Mult element

    Subscript := Mult1.Order(Subscript, 1);

    //if not the end of list

    if Subscript <> '' then

      //display subscript – value

      Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])

  //stop when reached the end

  until Subscript = '';

  //existing entries will remain in sorted order

  Mult1.Sorted := False;

  Memo1.Lines.Add('');

  Memo1.Lines.Add('Unsorted order:');

  //set a starting point

  Subscript := '';

  repeat

    //get next Mult element

    Subscript := Mult1.Order(Subscript, 1);

    //if not the end of list

    if Subscript <> '' then

      //display subscript – value

      Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])

      //stop when reached the end

  until Subscript = '';

end;

4.	Run project and click on the button.

Expected output:

You may have to scroll up and down to see all of the output.


Order Method

Example

Applies to

TMult class

Declaration

function Order(const StartSubscript: string; Direction: integer): string;

Description

The Order method works very similar to the $ORDER function in M. Using the Order method you can traverse through the list of elements in the Mult property of an RPC parameter.

The StartSubscript parameter is the subscript of the element whose next or previous sibling will be returned. If the Direction parameter is a positive number, then the subscript of the following element will be returned, while if it’s 0 or negative, then the predecessor’s subscript will be returned. If the list is empty or there are no more elements beyond the StartSubscript parameter, then empty string will be returned. You can use the empty string as a StartSubscript parameter, then, depending on the Direction parameter, you will get the subscript of the first or the last element in the list.

There are some important differences between this method and the $ORDER function in M. Unlike the $ORDER function, the Order method requires both parameters to be passed in. If the StartSubscript parameter is not an empty string, it must be equal to one of the subscripts in the list, otherwise an empty string will be returned. It is case-sensitive. Unlike arrays in M, elements in TMult may or may not be in alphabetical order, depending on the Sorted property, so Order may not return the next or previous subscript in collating sequence.

For information about the size of parameters and results that can be passed to and returned from the  TMult class, please refer to the RPC Limits topic.


Order Example

The following program code demonstrates how to get the next and previous elements in a TMult list:

procedure TForm1.Button1Click(Sender: TObject);

var

  Mult: TMult;

  Subscript: string;

begin

  {Create Mult. Make Form1 its owner}

  Mult := TMult.Create(Form1);

  Mult['First'] := 'One';

  {Store element pairs one by one}

  Mult['Second'] := 'Two';

  Mult['Third'] := 'Three';

  Mult['Fourth'] := 'Four';

  {Subscript will be Fourth}

  Subscript := Mult.Order('Third',1);

  {Subscript will be Second}

  Subscript := Mult.Order('Third',-1);

  {Subscript will be ''. THIRD subscript does not exist}

  Subscript := Mult.Order('THIRD',1);

  {Subscript will be First}

  Subscript := Mult.Order('',1);

  {Subscript will be Fourth}

  Subscript := Mult.Order('',-1);

end;


Position Method

Example

Applies to

TMult class

Declaration

function Position(const Subscript: string): longint;

Description

The Position method takes the string subscript of an item in a TMult variable and returns its numeric index position much like a TStringList’s IndexOf method. Because TMult uses a TStringList internally, the IndexOf method is used to implement the Position method. The first position in the TMult is 0. If TMult is empty, or the Subscript does not identify an existing item, Position returns -1.

The Position and Subscript methods are the reciprocals of each other.

For information about the size of parameters and results that can be passed to and returned from the  TMult class, please refer to the RPC Limits topic.


Position Example

The following program code demonstrates how to get the position of an item in a TMult variable:

procedure TForm1.Button1Click(Sender: TObject);

var

  Mult: TMult;

begin

  {Create Mult. Make Form1 its owner}

  Mult := TMult.Create(Form1);

  Label1.Caption := 'The position of the ''Third'' element is ' +

     {will be -1 since the list is empty}

     IntToStr(Mult.Postion('Third'));

  Mult['Second'] := 'Two';

  Label1.Caption := 'The position of the ''Third'' element is ' +

     {will be -1 since 'Third' item does not exit}

     IntToStr(Mult.Postion('Third'));

  Label1.Caption := 'The position of the ''Second'' element is ' +

     {will be 0, TMult positions start with 0}

     IntToStr(Mult.Postion('Second'));

end;


Subscript Method

Example

Applies to

TMult class

Declaration

function Subscript(const Position: longint): string;

Description

The Subscript method takes the numeric position of an item in a TMult variable and returns its string subscript. If TMult is empty, or the Position is greater than the number of items in the list, an empty string will be returned.

The Subscript and Position methods are the reciprocals of each other.

For information about the size of parameters and results that can be passed to and returned from the  TMult class, please refer to the RPC Limits topic.


Subscript Example

The following program code demonstrates how to get the subscript of an item in a TMult variable:

procedure TForm1.Button1Click(Sender: TObject);

var

  Mult: TMult;

begin

  {Create Mult. Make Form1 its owner}

  Mult := TMult.Create(Form1);

  Label1.Caption := 'The subscript of the item at position 1 is ' +

     {will be empty since the list is empty}

     Mult.Subscript(1);

  Mult['Second'] := 'Two';

  Label1.Caption := 'The subscript of the item at position 1 is ' +

     {will be empty. Only one item in list so far at 0th position}

     Mult.Subscript(1);

  Mult['Third'] := 'Three';

  Label1.Caption := 'The subscript of the item at position 1 is ' +

     {will be Third}

     Mult.Subscript(1);

end;


Assign Method (TMult Class)

Example

Applies to

TMult class

Declaration

procedure Assign(Source: TPersistent);

Description

The Assign method for a TMult class takes either a Tstrings, a TStringList, or another TMult. In the case where the source is a TMult, the owner of the Assign method gets the exact copy of the source with all string subscripts and values. In the case where the source is a Tstrings or a TStringList, the items are copied such that the strings property of each item becomes the Value, while the index becomes the subscript in the string form.

For information about the size of parameters and results that can be passed to and returned from the  TMult class, please refer to the RPC Limits topic.


Assign Example (TMult Class)

The following program code demonstrates the use of the TMult assign method to assign listbox items (Tstrings) to a TMult:

1.	Start a new application.

2.	Drop one listbox, one memo and one button on the form. Arrange controls as in the figure below.

3.	Copy the following code to the Button1.OnClick event:

procedure TForm1.Button1Click(Sender: TObject);

var

  Mult1: TMult;

  Subscript: string;

begin

  //Create Mult1. Make Form1 its owner

  Mult1 := TMult.Create(Form1);

  //Fill listbox with some strings

  ListBox1.Items.Add('One');

  ListBox1.Items.Add('Two');

  ListBox1.Items.Add('Three');

  ListBox1.Items.Add('Four');

  ListBox1.Items.Add('Five');

  //assign (copy) listbox strings to Mult

  Mult1.Assign(ListBox1.Items);

  //configure memo box for better display

  Memo1.Font.Name := 'Courier';

  Memo1.Lines.Clear;

  Memo1.Lines.Add('Tstrings assigned:');

  //set a starting point

  Subscript := '';

  repeat

    //get next Mult element

    Subscript := Mult1.Order(Subscript, 1);

    //if not the end of list

    if Subscript <> '' then

      //display subscript – value

      Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])

  //stop when reached the end

  until Subscript = '';

end;

4.	Run the project and click on the button.

Expected output:

The following program code demonstrates the use of the TMult assign method to assign one TMult to another:

1.	Start a new application.

2.	Drop one memo and one button on the form. Arrange controls as in the figure below.

3.	Copy the following code to the Button1.OnClick event:

procedure TForm1.Button1Click(Sender: TObject);

var

  Mult1, Mult2: TMult;

  Subscript: string;

begin

  //Create Mult1. Make Form1 its owner

  Mult1 := TMult.Create(Form1);

  //Create Mult2. Make Form1 its owner

  Mult2 := TMult.Create(Form1);

  //Fill Mult1 with some strings

  Mult1['First'] := 'One';

  Mult1['Second'] := 'Two';

  Mult1['Third'] := 'Three';

  Mult1['Fourth'] := 'Four';

  Mult1['Fifth'] := 'Five';

  //assign (copy) Mult1 strings to Mult2

  Mult2.Assign(Mult1);

  //configure memo box for better display

  Memo1.Font.Name := 'Courier';

  Memo1.Lines.Clear;

  Memo1.Lines.Add('TMult assigned:');

  //set a starting point

  Subscript := '';

  repeat

    //get next Mult element

    Subscript := Mult2.Order(Subscript, 1);

    //if not the end of list

    if Subscript <> '' then

      //display subscript – value

      Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult2[Subscript])

  //stop when reached the end

  until Subscript = '';

end;

4.	Run the project and click on the button.

Expected output:


TParams Class

Property	Method	Example

Unit

TRPCB

Description

The TParams class is used to hold parameters (i.e., array of TParamRecord) used in a remote procedure call (RPC). You don’t need to know in advance how many parameters you’ll need or allocate memory for them; a simple reference or an assignment to a parameter creates it.

The Clear procedure can be used to remove/clear data from TParams. Previously, this procedure was Private, but as of Patch XWB*1.1*13, it was made Public.


TParams Example

The following program code demonstrates how a TParams class can be used to save off the TRPCBroker component parameters and restore them later:

procedure TForm1.Button1Click(Sender: TObject);

var

  SaveParams: TParams;

  SaveRemoteProcedure: string;

begin

  {create holding variable with Form1 as owner}

  SaveParams := TParams.Create(self);

  {save parameters}

  SaveParams.Assign(brkrRPCBroker1.Param);

  SaveRemoteProcedure := brkrRPCBroker1.RemoteProcedure;

  brkrRPCBroker1.RemoteProcedure := 'SOME OTHER PROCEDURE';

  brkrRPCBroker1.ClearParameters := True;

  brkrRPCBroker1.Call;

  {restore parameters}

  brkrRPCBroker1.Param.Assign(SaveParams);

  brkrRPCBroker1.RemoteProcedure := SaveRemoteProcedure;

  {release memory}

  SaveParams.Free;

end;


TParams Property

TParams

Count


TParams Method

TParams

Assign


Count Property (TParams Class)

Example

Applies to

TParams class

Declaration

property Count: Word;

Description

The Count property contains the number of parameters in a TParams class. If the TParams class is empty, Count will be zero.


Count Example (TParams Class)

The following program code displays the number of parameters in a TParams variable within the caption of a label when the user clicks the CountParameters button:

procedure TForm1.CountParametersClick(Sender: TObject);

begin

  Label1.Caption := 'There are ' + IntToStr(brkrRPCBroker1.Param.Count) +

    ' parameters.';

end;


Assign Method (TParams Class)

Example

Applies to

TParams class

Declaration

procedure Assign(Source: TParams);

Description

The Assign method for a TParams class takes another TParams class parameter. The Assign method is useful for copying one TParams class to another. The entire contents of the passed in TParams class are copied into the owner of the assign method. The Assign method first deletes all of the parameters in the receiving class and then copies the parameters from the passed in class, creating a whole duplicate copy.

For information about the size of parameters and results that can be passed to and returned from the  TParams class, please refer to the RPC Limits topic.


Assign Example (TParams Class)

The following program code demonstrates how a TParams assign method can be used to save off the TRPCBroker component parameters and restore them later:

procedure TForm1.Button1Click(Sender: TObject);

var

  SaveParams: TParams;

  SaveRemoteProcedure: string;

begin

  {create holding variable with Form1 as owner}

  SaveParams := TParams.Create(self);

  {save parameters}

  SaveParams.Assign(brkrRPCBroker1.Param);

  SaveRemoteProcedure := brkrRPCBroker1.RemoteProcedure;

  brkrRPCBroker1.RemoteProcedure := 'SOME OTHER PROCEDURE';

  brkrRPCBroker1.ClearParameters := True;

  brkrRPCBroker1.Call;

  {restore parameters}

  brkrRPCBroker1.Param.Assign(SaveParams);

  brkrRPCBroker1.RemoteProcedure := SaveRemoteProcedure;

  {release memory}

  SaveParams.Free;

end;


RPCConf1 Unit

Library Methods

GetServerInfo

GetServerIP

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


SplVista Unit

Library Methods

SplashOpen

SplashClose

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


MFunStr Unit

Library Methods

piece

translate

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


Hash Unit

Library Methods

Encrypt

Decrypt

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


TRPCB Unit

The TRPCB unit contains the declarations for the various RPC Broker components.

When you add a component declared in this unit to a form, the unit is automatically added to the uses clause of that form's unit.

The following items are automatically declared in the uses clause:

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs

Classes

TMult

TParamRecord

TParams

TVistaLogin

TVistaUser

Component

TRPCBroker

Library Methods

GetAppHandle

TMult Class Methods

TParams Class Method

TRPCBroker Component Methods

Types

EBrokerError

TloginMode

TParamType

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


IP Address

The Internet Protocol (IP) address is the network interface address for a client workstation, server, or device.


DNS

The Domain Name Service (DNS) is a distributed database that maps names to their Internet Protocol (IP) addresses or IP addresses to their names. A query to this database is used to resolve names and IP addresses.


HOSTS File

The HOSTS file is an ASCII text file that contains a list of the servers and their Internet Protocol (IP) addresses. We recommend you put in an entry (i.e., "DHCPSERVER") that points to the main server you intend using with the Broker the majority of the time. In your applications you will be able to specify any server you wish, however, if the Server property = " (i.e., null), you will get an error.


JOB
$JOB

Contains your operating system job number on the VistA M Server.

On DSM for OpenVMS systems, this is the process identification (PID) number of your process.

On DSM for DEC OSF/1 systems, the job number is the PID of the child process created when you enter the DSM command.


ORDER
$ORDER

$ORDER(variable name{,integer code})

Returns the subscript of the previous or next sibling in collating sequence of a specified array node.

To obtain the first subscript of a level, specify a null subscript in the argument.


REMOTE PROCEDURE File

The RPC Broker consists of a single global that stores the REMOTE PROCEDURE file:

File #	File Name	Global Location

8994	REMOTE PROCEDURE	^XWB(8994,

This is the common file used by all applications to store all remote procedure calls accessed via the Broker. All RPCs used by any site-specific client/server application software using the RPC Broker interface must be registered and stored in this file.

This file is used as a repository of server-based procedures in the context of the Client/Server architecture. By using the Remote Procedure Call (RPC) Broker, applications running on client workstations can invoke (call) the procedures in this file to be executed by the server and the results are returned to the client application.

The RPC subfield (#19.05) of the OPTION File (#19) points to RPC field (#.01) of the REMOTE PROCEDURE file (#8994).


Windows Registry
Microsoft Windows Registry

Applications built with Version 1.1 of the Broker use the Microsoft Windows Registry to store the available servers and ports accessed via the Broker.

The Windows Registry replaces the [RPCBroker_Servers] section of the VISTA.INI file. The VISTA.INI file is no longer used by applications built with Version 1.1 of the Broker. However, this file continues to be used by applications built using version 1.0 of the Broker (e.g., PCMM). During the installation of the Broker relevant data from the VISTA.INI file is moved to the Windows Registry. Subsequent reads and writes are done via the Registry.

 The VISTA.INI file created with Broker V. 1.0 must not be removed from the Windows directory on the client workstation. It is still required for 16-bit Broker-based applications created using version 1.0 of the Broker (e.g., PCMM).


ZDEBUG

A command used to enable or disable debug mode in Digital Standard M (DSM):

>ZDEBUG ON	(turns on debugging)

>ZDEBUG OFF	(turns off debugging)


XUPROGMODE

A security key distributed by Kernel as part of its Menu Manager. This security key enables access to a number of programmer-oriented options in Kernel.


legend
Accessibility (Image Legend)

 Run-time only

 Read-only


TVistaLogin Class

Properties	Example

Unit

TRPCB

Description

The TVistaLogin class is used to hold login parameters for Silent Login.


TVistaLogin Properties

TVistaLogin Class	Legend

AccessCode

Division

DivList

DomainName

DUZ

ErrorText

IsProductionAccount

LoginHandle

Mode

MultiDivision

OnFailedLogin

PromptDivision

VerifyCode


AccessCode Property

Example

Applies to

TVistaLogin class

Declaration

property AccessCode: String;

Description

The AccessCode property is available at run-time only. It holds the Access code for the lmAVCodes mode of Silent Login. The user's Access code value should be set in as clear text. It is encrypted before it is transmitted to the VistA M Server.

For more information on Access codes, please refer to the "Part 1: Sign-On/Security" section in the "Kernel Systems Manual."

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.


Division Property (TVistaLogin Class)
Division Property

Applies to

TVistaLogin class

Declaration

property Division: String;

Description

The Division property is available at run-time only. It can be set to the desired Division for a user for Silent Login.

For information about handling multi-divisions during the Silent Login process, please refer to the "Handling Divisions During Silent Login" topic.


DivList Property
DivList Property (read-only)

Applies to

TVistaLogin class

Declaration

property DivList:  Tstrings;

Description

The DivList property is available at run-time only. This read-only property is a list of divisions that are available for selection by the user for the signon division. This list is filled in, if appropriate, during the Silent Login at the same time that the user is determined to have multiple divisions from which to select. The first entry in the list is the number of divisions present, followed by the names of the divisions that are available to the user.

For information about handling multi-divisions during the Silent Login process, please refer to the "Handling Divisions During Silent Login" topic.


DomainName Property

Applies to

TVistaLogin class

Declaration

property DomainName: String;

Description

The DomainName property is available at run-time only. It can be used to obtain the domain name of the server to which the RPC Broker is currently connected.


DUZ Property (TVistaLogin Class)
DUZ Property

Applies to

TVistaLogin class

Declaration

property DUZ: String;

Description

The DUZ property is available at run-time only. It holds the user’s Internal Entry Number (IEN) from the NEW PERSON file (#200) for TVistaLogin.


ErrorText Property

Applies to

TVistaLogin class

Declaration

property ErrorText: String;

Description

The ErrorText property is available at run-time only. It holds text of any error message returned by the VistA M Server during the attempted Silent Login. It should be checked if the login fails. For example, it could indicate the following:

•	The Verify code needs to be changed.

•	An invalid Access/Verify code pair.

•	An invalid Division.


IsProductionAccount Property

Applies to

TVistaLogin class

Declaration

property IsProductionAccount:  Boolean;

Description

The IsProductionAccount property is available at run-time only. It can be checked to determine if the current connection is to a Production account. The property value will be True if the account is a Production account, otherwise it will be False. While it is declared as a read-write property, it should be considered to be read-only, since changing its value will not change the nature of the serverto which the RPC Broker is connected.


LoginHandle Property

Applies to

TVistaLogin class

Declaration

property LoginHandle: String;

Description

The LoginHandle property is available at run-time only. It holds the Application Handle for the lmAppHandle mode of Silent Login. The Application Handle is obtained from the VistA M Server by a currently running application using the GetAppHandle function in the TRPCB unit. The function returns a String value, which is then passed as a command line argument with an application that is being started. The new application must know to look for the handle, and if present, set up the Silent Login. The StartProgSLogin procedure in the RpcSLogin unit can be used directly or as an example of how the application would be started with a valid AppHandle as a command line argument. The CheckCmdLine procedure in the RpcSLogin unit can be used in an application to determine whether an AppHandle has been passed and to initiate the Broker connection or used as an example of how this could be done.

The two procedures referenced here also pass the current Server, ListenerPort, and Division for the user so that the connection would be made to the same VistA M Server as the original application.

The AppHandle that is obtained via the GetAppHandle function is only valid for approximately 20 seconds, after which the Silent Login would fail.

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.


Mode Property

Example

Applies to

TVistaLogin class

Declaration

property Mode:  TloginMode;

Description

The Mode property is available at run-time only. It indicates the mode of Silent Login. The possible values include: lmAVCodes and lmAppHandle.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.


MultiDivision Property

Applies to

TVistaLogin class

Declaration

property MultiDivision:  Boolean;

Description

The MultiDivision property is available at run-time only. It indicates whether the user has multi-divisional access. It is set during the Silent Login process, if the user has more than one division that can be selected.

For information about handling multi-divisions during the Silent Login process, please refer to the "Handling Divisions During Silent Login" topic.


OnFailedLogin Property

Example

Applies to

TVistaLogin class

Declaration

property OnFailedLogin: TOnLoginFailure;

Description

The OnFailedLogin property is available at run-time only. It holds a procedure to be invoked on a failed Silent Login that permits an application to handle errors as desired, where TOnLoginFailure is defined as:

TOnLoginFailure = procedure (VistaLogin: TVistaLogin) of object;

For example, an application could define:

Procedure HandleLoginError(Sender: TObject);

and then set:

OnFailedLogin := HandleLoginError;


PromptDivision Property

Example

Applies to

TVistaLogin class

Declaration

property PromptDivison:  Boolean;

Description

The PromptDivision property is available at run-time only. It should be set to True, if the user should be prompted for Division during Silent Login. The prompt will only occur if the user has multi-division access. This property should be set to False, if the prompt should not be displayed due to the manner in which the application is running. However, if set to False and multi-division access is a possibility, then the application must handle it in another way. For example, the application developer would do the following:

1.	Set Login.PromptDivision to False.

2.	Set the Connected property to True to signon.

3.	On return, check whether the Connected property was set to True or check whether the Login.ErrorText property was non-null (and especially "No Division Selected").

4.	If the connection was successful, there is no problem. Otherwise, proceed to Steps 5 - 8.

5.	Check the Login.MultiDivision property and see if it was set to True (which is what would be expected).

6.	If the Login.MultiDivision property is set to True, then check the Login.DivList property for a list of the available divisions (remember the first entry is the number of entries that follow) and, in whatever method was available to the application, have the user select the correct division.

7.	Set the Login.Division property to the selected Division.

8.	Set theConnected property to True, so the connection would be attempted to be established again.


VerifyCode Property

Example

Applies to

TVistaLogin class

Declaration

property VerifyCode: String;

Description

The VerifyCode property is available at run-time only. It holds the Verify code for lmAVCodes mode of Silent Login. Like the AccessCode property, the user's Verify code is also encrypted before it is transmitted to the VistA M Server.

For more information on Verify codes, please refer to the "Part 1: Sign-On/Security" section in the "Kernel Systems Manual."

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.


TVistaUser Class

Properties

Unit

TRPCB

Description

The TVistaUser class is used to hold parameters related to the current user. These parameters are filled in as part of the login procedure.

This class is used as a property by the TRPCBroker class. This property with its associated data is available to all applications, whether or not they are using a Silent Login.


TVistaUser Properties

TVistaUser Class	legend

Division

DTime

DUZ

Language

Name

ServiceSection

StandardName

Title

VerifyCodeChngd

Vpid


Division Property (TVistaUser Class)
Division Property

Applies to

TVistaUser class

Declaration

property Division: String;

Description

The Division property is available at run-time only. It is set to the division for a user when they are logged on.


DTime Property

Applies to

TVistaUser class

Declaration

property DTime: String;

Description

The DTime property is available at run-time only. It holds the user’s DTime. DTime sets the time a user has to respond to timed read. It can be set from 1 to 99999 seconds.


DUZ Property (TVistaUser Class)
DUZ Property

Applies to

TVistaUser class

Declaration

property DUZ: String;

Description

The DUZ property is available at run-time only. It holds the user's Internal Entry Number (IEN) from the NEW PERSON file (#200) for TVistaUser.


Language Property

Applies to

TVistaUser class

Declaration

property Language: String;

Description

The Language property is available at run-time only. It holds the user’s language from the NEW PERSON file (#200).


Name Property

Applies to

TVistaUser class

Declaration

property Name: String;

Description

The Name property is available at run-time only. It holds the user's name from the NEW PERSON file (#200).


ServiceSection Property

Applies to

TVistaUser class

Declaration

property ServiceSection: String;

Description

The ServiceSection property is available at run-time only. It holds the user’s service section from the NEW PERSON file (#200).


StandardName Property

Applies to

TVistaUser class

Declaration

property StandardName: String;

Description

The StandardName property is available at run-time only. It holds the user's standard name from the NEW PERSON file (#200).


Title Property

Applies to

TVistaUser class

Declaration

property Title: String;

Description

The Title property is available at run-time only. It holds the user’s title from the NEW PERSON file (#200).


VerifyCodeChngd Property

Applies to

TVistaUser class

Declaration

property VerifyCodeChngd:  Boolean;

Description

The VerifyCodeChngd property is available at run-time only. It indicates whether or not the user's Verify code has changed.


Vpid Property

Applies to

TVistaUser class

Declaration

property Vpid:  String;

Description

The Vpid property is available at run-time only. It returns the Department of Veterans Affairs Personal Identification (VPID) value for the current user from the NEW PERSON file (#200), if the facility has already been enumerated. If the facility has not been enumerated, the value returned is a null string.


Silent Login

Example

Silent Login is a way to log in a user with known login information. Silent Login skips the step of asking the user for login information. It is similar to Auto Signon in some ways, but there are important differences.

Silent Login Compared to Auto Signon

In Auto Signon, the Client Agent manages the login process on the client. On a primary login (i.e., no existing connections), the user is prompted for Access and Verify codes. On secondary logins, the Client Agent handles the login with the information from the primary login. Developers do not have access to the Auto Signon process.

For more information on Auto Signon, please refer to the RPC Broker Systems Manual.

Silent Login offers developers an opportunity to skip the login process for the user if they have access to login information from some other source. It is up to the developer to deliver the appropriate login information to the application and enable the Silent Login process.

Interaction Between Silent Login and Auto Signon

On primary login, Silent Login happens if it is enabled (the KernelLogIn property is set to False and the AccessCode, VerifyCode and Mode properties of the LogIn property are set or the AppHandle and Mode properties are set). On secondary logins, the Client Agent, if enabled, handles the login and the Silent Login is bypassed. In other words, if there already is a connection and the Client Agent is enabled, the Silent Login information is not used.

The "XUS SIGNON SETUP" RPC is called before a normal login or a Silent Login and if it identifies the user via Client Agent at the IP address, that identification is used to log the user in.


Silent Login Examples

Silent Login

Example 1: lmAVCodes

Here is an example of how to use Silent Login by passing the Access and Verify codes to the TVistaLogin class.

brkrRPCBroker1.KernelLogIn := False;

brkrRPCBroker1.LogIn.Mode := lmAVCodes;

brkrRPCBroker1.LogIn.AccessCode := ********;

brkrRPCBroker1.LogIn.VerifyCodeCode := ********;

brkrRPCBroker1.LogIn.PromptDivison := True;

brkrRPCBroker1.LogIn.OnFailedLogin := myevent;

try

    brkrRPCBroker1.Connected := True;

except

  exit

end;

If brkrRPCBroker1.Connected is True, then Silent Login has worked.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

Example 2: lmAppHandle

Here is an example of how to use Silent Login by passing an Application Handle to the TVistaLogin class.

The lmAppHandle mode of the Silent Login is used when an application starts up a second application. If the second application tests for arguments on the command line, it is possible for this application to be started and make a connection to the VistA M Server without user interaction.

An example of a procedure for starting a second application with data on the command line to permit a Silent Login using the LoginHandle provided by the first application is shown below. This is followed by a procedure that can be called in the processing related to FormCreate to use this command line data to initialize the TRPCBroker component for Silent Login.

 It should be noted that the procedures shown here are included within the RpcSLogin unit, and can be used directly from there.

If the value for ConnectedBroker is nil, the application specified in ProgLine will be started and any command line included in ProgLine will be passed to the application.

In the second application, a call to the Broker should be made shortly after starting, since the LoginHandle passed in has a finite lifetime (approximately 20 seconds) during which it is valid for the Silent Login.

procedure StartProgSLogin(const ProgLine: String; ConnectedBroker: TRPCBroker);

var

  StartupInfo: TStartupInfo;

  ProcessInfo: TProcessInformation;

  AppHandle: String;

  CmndLine: String;

begin

  FillChar(StartupInfo, SizeOf(TStartupInfo), 0);

  with StartupInfo do

  begin

    cb := SizeOf(TStartupInfo);

    dwFlags := STARTF_USESHOWWINDOW;

    wShowWindow := SW_SHOWNORMAL;

  end;

  CmndLine := ProgLine;

  if ConnectedBroker <> nil then

  begin

    AppHandle := GetAppHandle(ConnectedBroker);

    CmndLine := CmndLine + ' s='+ConnectedBroker.Server + ' p='

                         + IntToStr(ConnectedBroker.ListenerPort) + ' h='

                         + AppHandle + ' d=' + ConnectedBroker.User.Division;

  end;

  CreateProcess(nil, Pchar(CmndLine), nil, nil, False,

      NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);

end;

{btnStart is clicked to start the second application Test2.exe}

procedure TForm1.btnStartClick(Sender: TObject);

var

  CurDir: string;

begin

  {Use Test2.exe and expecting it to be in the startup directory for the current application}

  CurDir := ExtractFilePath(ParamStr(0)) + 'Test2.exe';

  {Now start application with Silent Login}

  StartProgSLogin(CurDir, brkrRPCB1);

end;

The following procedure (CheckCmdLine) would be called in the FormCreate code of the application being started to check for command line input, and if relevant to the Broker connection, to set it up.

This code assumes that s=, p=, d=, and h= are used in conjunction with the values for Server, ListenerPort, User.Division, and LoginHandle, respectively.

The command line might look like:

ProgramName.exe s=DHCPSERVER p=9200 d=692 h=~1XM34XYYZZQQ_X

The TRPCB and RpcSLogin units would need to be included in the USES clause.

procedure CheckCmdLine(brkrRPCB: TRPCBroker);

var

 j: integer;

begin

  // Iterate through possible command line arguments

  for j := 0 to 15 do

  begin

    if ParamStr(j) <> '' then

      Form1.Memo1.Lines.Add(IntToStr(j) + '  ' + ParamStr(j));

    if Pos('p=',ParamStr(j)) > 0 then

      brkrRPCB.ListenerPort := StrToInt(Copy(ParamStr(j),

                       (Pos('=',ParamStr(j))+1),length(ParamStr(j))));

    if Pos('s=',ParamStr(j)) > 0 then

      brkrRPCB.Server := Copy(ParamStr(j),

                       (Pos('=',ParamStr(j))+1),length(ParamStr(j)));

    if Pos('h=',ParamStr(j)) > 0 then

    begin

      brkrRPCB.Login.LoginHandle := Copy(ParamStr(j),

                       (Pos('=',ParamStr(j))+1),length(ParamStr(j)));

      if brkrRPCB.Login.LoginHandle <> '' then

      begin

        brkrRPCB.KernelLogIn := False;

        brkrRPCB.Login.Mode := lmAppHandle;

      end;

    end;

    if Pos('d=',ParamStr(j)) > 0 then

      brkrRPCB.Login.Division := Copy(ParamStr(j),

                       (Pos('=',ParamStr(j))+1),length(ParamStr(j)));

  // for end

  end;

end;

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.


TLoginMode Type

The TLoginMode type is used with the Mode property as part of the TVistaLogin class.

Unit

TRPCB

type TLoginMode = (lmAVCodes, lmAppHandle);

Description

The TLoginMode type includes the acceptable values that can be used during Silent Login. If the KernelLogIn property is set to False, then it will be a Silent Login. Thus, one of these mode types has to be set in the TVistaLogin class Mode property. The Broker will use the information to perform a Silent Login.

The following table lists the possible values:

Value	Meaning

lmAVCodes	Used if the application is passing in the user's Access and Verify codes during Silent Login.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

lmAppHandle	Used to pass in an application handle rather than a user's Access and Verify codes during Silent Login. It sets the mode to lmAppHandle and the KernelLogIn property to false. Indicates that an application handle is being passed to the application when it was being started as opposed to Access and Verify codes.

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.


Handling Divisions During Silent Login

A login may be successful, but if the user has multiple divisions from which to choose and fails to select one, the connection is terminated and a failed login message is generated. This becomes a potential problem in that a Silent Login may have problems, if the user has multiple divisions from which to choose and the PromptDivision property is not set to True.

If the application wishes to handle the user specification of the division, it may attempt to set the TRPCBroker component Connected property to True. If upon return, the Connected property is still False, it can check the Login.MultiDivision property. If the MultiDivision property is True, the user has multiple divisions from which to choose. The application will find the possible values for selection in the Login.DivList property (i.e., Tstrings). The values that are present in the DivList property will be similar to the following example:

3

1^SAN FRANCISCO^66235

2^NEW YORK^630

3^SAN DIEGO^664^1

The first (index = 0) entry is the total number of divisions that can be selected (e.g., 3 in this example). This is followed by the different divisions comprised of the following pieces:

•	The second ^-piece of each entry is the name.

•	The third ^-piece of each entry is the number associated with the division.

•	The fourth ^-piece with the value of 1, if present in one of the entries, is the default division for the user.

The safest value to set as the Login.Division property might be the third ^-piece of the selected division.

If the desired division is known ahead of time, it can be set into the Login.Division property for the TRPCBroker component prior to attempting the connection.


pchCall Method

function pchCall: Pchar;

The pchCall function is the lowest level call used by the TRPCBroker component and each of the other Call methods (i.e., Call, strCall, and lstCall), which are implemented via pchCall. The return value is a Pchar, which can contain anything from a null string, a single text string, or many strings each separated by Return and/or LineFeed characters. For converting multiple lines within the return value into a Tstrings, use the SetText method of the Tstrings.


CurrentContext Example

The following program code demonstrates the use of the CurrentContext property in a hypothetical example of saving and restoring the current context of an application:

procedure TForm1.MyFantasticModule;

var

  OldContext: String;

begin

  OldContext := RPCB.CurrentContext;  // save off old context

  try

    RPCB.SetContext('MyContext');

    .

    .

    .

  finally

    RPCB.SetContext(OldContext);  // restore context before leaving

  end;

end;


OnRPCBFailure Example

For example, an application could define:

Procedure HandleBrokerError(Sender: TObject);

and then set:

OnRPCBFailure := HandleBrokerError;

The initialization of the OnRPCBFailure property should be before the first call to the TRPCBroker component.

The following instance of an error handler will take the Message property of the exception and store it with a time date stamp into a file named Error.Log in the same directory with the application exe:

procedure TForm1.HandleBrokerError(Sender: TObject);

var

  ErrorText: String;

  Path: String;

  StrLoc: TStringList;

  NowVal: TDateTime;

begin

  NowVal := Now;

  ErrorText := TRPCBroker(Sender).RPCBError;

  StrLoc := TStringList.Create;

  try

    Path := ExtractFilePath(Application.ExeName);

    Path := Path + 'Error.Log';

    if FileExists(Path) then

      StrLoc.LoadFromFile(Path);

    StrLoc.Add(FormatDateTime('mm/dd/yyyy hh:mm:ss  ',NowVal) + ErrorText);

    StrLoc.SaveToFile(Path);

  finally

    StrLoc.Free;

  end;

end;


 TXWBRichEdit Component

Property

Parent Class

TXWBRichEdit = class(TComponent)

Unit

XwbRich20

Description

The TXWBRichEdit component replaces the Introductory Text Memo component on the Login Form. TXWBRichEdit (XwbRich20.pas) is a version of the TRichEdit component that uses Version 2 of Microsoft's RichEdit Control and adds the ability to detect and respond to a Uniform Resource Locator (URL) in the text. This component permits us to provide some requested functionality on the login form. As an XWB namespaced component we are required to put it on the Kernel tab of the component palette, however, it rightly belongs on the Win32 tab.

Properties inherited from the parent component (i.e., TComponent) are not discussed in this Help file (only those properties added to the parent component are described). For help on inherited properties, please refer to Delphi's documentation on the parent component (i.e., TComponent).


TXWBRichEdit Property

TXWBRichEdit

URLDetect


URLDetect Property

Applies to

TXWBRichEdit component

Declaration

property URLDetect:  Boolean;

Description

The URLDetect design-time property is used to create active ("live") links in an application. If this property is set to True, URLs (http:, mailto:, file:, etc.) are shown in blue and underlined. If the user clicks on the URL, it will open the URL in the appropriate application. If the property is False (the default), URLs appear as normal text and are not active.


TVCEdit Unit

The RPC Broker calls the TVCEdit unit at logon when users must change their Verify code (i.e., Verify code has expired). There is also a checkbox on the Signon form that allows uses to change their Verify code at any time.

Library Methods

ChangeVerify

SilentChangeVerify

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


RpcSLogin Unit

Library Methods

CheckCmdLine

StartProgSLogin

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


LoginFrm Unit

With Patch XWB*1.1*13, a "Change VC" checkbox was added to the to the login form. The user can use this checkbox to indicate that she/he wants to change their Verify code. If this box has been checked, after the user has completed logging in to the system, the Change Verify code dialog will be displayed.

To see a listing of items declared in this unit including their declarations, please use the ObjectBrowser.


 TSharedBroker Component

Properties	Example

Parent Class

TSharedBroker = class(TComponent)

Unit

TRPCB

Description

The TSharedBroker component is derived from the existing TRPCBroker component. The TSharedBroker component provides applications or plug-ins to applications easy access to an RPCBroker without the need for a separate M partition. Each component has its own security (i.e., option) as well. The default value of the AllowShared is True. If an application will have RPCs that require extensive time, it would be best to NOT share a Broker instance and the AllowShared should then be set to False.

For its functionality, the TSharedBroker component uses the RPCSharedBrokerSessionMgr.EXE, which is an out of process Common Object Module (COM) component. This executable handles the actual Broker connections and communication, permitting multiple applications to use a single connection and partition to the VistA M Server. However, it also handles connections of different applications to different Server/Port combinations and can handle multiple connections to a specific Server/Port combination, if an application sets AllowShared to False.

Like the TRPCBroker, the TSharedBroker component and RPCSharedBrokerSessionMgr executable provide VistA application developers with all of the client/server-related functionality in one integrated component. Using the TSharedBroker component, an application can connect to the VistA M Server by simply setting the Connected property to True. Remote procedures on the server can be executed by preparing the Param and RemoteProcedure properties and invoking either the Call, strCall or lstCall methods.

Using the TSharedBroker Component

To use the TSharedBroker component in place of the TRPCBroker component with an existing application, do the following:

1.	Open the application.

2.	Notate the current name assigned to the TRPCBroker component.

3.	Remove the TRPCBroker component.

4.	Add the TSharedBroker component and give it the same name that was used for the TRPCBroker component (see Step #2).

5.	If you do not have any other components (e.g., FileMan Delphi Components) that reference the original TRPCBroker component (see Step #2), simply recompile and run the application. Otherwise, proceed to Step #6.

6.	If you have components (e.g., FMLister, FMGets, etc.) that reference the original TRPCBroker component, do the following:

a.	Click on the component(s).

b.	Select the new TSharedBroker component at the TRPCBroker reference for this component in the object inspector. The assignment isn't by name but to the actual component instance or location in memory at the time, and this has to be reset.

c.	Repeat Steps #6a-6b for each additional component

d.	Recompile and run the application.

Application developers must remember to include the RPCSharedBrokerSessionMGR.EXE when building their applications.

When the first application connects, you will see an instance of the RPCSharedBrokerSessionMgr appear in the taskbar. All Broker connections via the TSharedBroker component are routed through this executable.

For help on inherited properties, please refer to the parent component (i.e., TRPCBroker).


TSharedBroker Example

The following example demonstrates how a TSharedBroker component can be used to connect to the VistA M Server, execute various remote procedures, return the results and finally disconnect from the server. This example assumes that a TSharedBroker component already exists on the form:

procedure TForm1.Button1Click(Sender: TObject);

var

  i: Integer;

begin

  try

    if not SharedBroker1.Connected then

      SharedBRoker1.Connected := True;          {connect to the server}

    //assign RPC name

    SharedBroker1.RemoteProcedure := 'SOME APPLICATION RPC';

    SharedBroker1.Call;                               {make the call}

    for i=0 to Pred(SharedBroker1.Results.Count) do

      ListBox1.Items.Add(SharedBroker1.Results[i]);   {display results}

  except

    //put error handling code here

  end;

end;

For more examples, please refer to the Samples directory on the use of the TSharedRPCBroker component:

..\BDK32\Samples\SharedRPCBroker


TSharedBroker Properties

TSharedBroker	Alphabetically 	Legend

In TSharedBroker

AllowShared

OnConnectionDropped

OnLogout

Since the TSharedBroker component is a class derived from the TRPCBroker component,  it contains all of the properties, methods, etc., of its parent.


TSharedBroker Properties (Alpha)

TSharedBroker	By Object 	Legend

The following is a list of the properties that are available with the TSharedBroker component (includes those properties inherited from the TRPCBroker parent component):

AllowShared

BrokerVersion

ClearParameters

ClearResults

Connected

CurrentContext

DebugMode

IsBackwardCompatibleConnection

IsNewStyleConnection

KernelLogIn

ListenerPort

LogIn

OldConnectionOnly

OnConnectionDropped

OnLogout

OnRPCBFailure

Param

RemoteProcedure

Results

RPCBError

RPCTimeLimit

RPCVersion

Server

ShowErrorMsgs

Socket

User


 TSharedRPCBroker Component

Properties	Example

Parent Class

TSharedRPCBroker = class(TComponent)

Unit

TRPCB

Description

The TSharedRPCBroker component is derived from the existing TRPCBroker component. The TSharedRPCBroker component provides applications or plug-ins to applications easy access to an RPCBroker without the need for a separate M partition. Each component has its own security (i.e., option) as well. The default value of the AllowShared is True. If an application will have RPCs that require extensive time, it would be best to NOT share a Broker instance and the AllowShared should then be set to False.

For its functionality, the TSharedRPCBroker component uses the RPCSharedBrokerSessionMgr.EXE, which is an out of process Common Object Module (COM) component. This executable handles the actual Broker connections and communication, permitting multiple applications to use a single connection and partition to the VistA M Server. However, it also handles connections of different applications to different Server/Port combinations and can handle multiple connections to a specific Server/Port combination, if an application sets AllowShared to False.

Like the TRPCBroker, the TSharedRPCBroker component and RPCSharedBrokerSessionMgr executable provide VistA application developers with all of the client/server-related functionality in one integrated component. Using the TSharedRPCBroker component, an application can connect to the VistA M Server by simply setting the Connected property to True. Remote procedures on the server can be executed by preparing the Param and RemoteProcedure properties and invoking either the Call, strCall or lstCall methods.

Using the TSharedRPCBroker Component

To use the TSharedRPCBroker component in place of the TRPCBroker component with an existing application, do the following:

1.	Open the application.

2.	Notate the current name assigned to the TRPCBroker component.

3.	Remove the TRPCBroker component.

4.	Add the TSharedRPCBroker component and give it the same name that was used for the TRPCBroker component (see Step #2).

5.	If you do not have any other components (e.g., FileMan Delphi Components) that reference the original TRPCBroker component (see Step #2), simply recompile and run the application. Otherwise, proceed to Step #6.

6.	If you have components (e.g., FMLister, FMGets, etc.) that reference the original TRPCBroker component, do the following:

a.	Click on the component(s).

b.	Select the new TSharedRPCBroker component at the TRPCBroker reference for this component in the object inspector. The assignment isn't by name but to the actual component instance or location in memory at the time, and this has to be reset.

c.	Repeat Steps #6a-6b for each additional component

d.	Recompile and run the application.

Application developers must remember to include the RPCSharedBrokerSessionMGR.EXE when building their applications.

When the first application connects, you will see an instance of the RPCSharedBrokerSessionMgr appear in the taskbar. All Broker connections via the TSharedRPCBroker component are routed through this executable.

For help on inherited properties, please refer to the parent component (i.e., TRPCBroker).


TSharedRPCBroker Example

The following example demonstrates how a TSharedRPCBroker component can be used to connect to the VistA M Server, execute various remote procedures, return the results and finally disconnect from the server. This example assumes that a TSharedRPCBroker component already exists on the form:

procedure TForm1.Button1Click(Sender: TObject);

var

  i: Integer;

begin

  try

    if not SharedRPCBroker1.Connected then

      SharedRPCBRoker1.Connected := True;          {connect to the server}

    //assign RPC name

    SharedRPCBroker1.RemoteProcedure := 'SOME APPLICATION RPC';

    SharedRPCBroker1.Call;                               {make the call}

    for i=0 to Pred(SharedRPCBroker1.Results.Count) do

      ListBox1.Items.Add(SharedRPCBroker1.Results[i]);   {display results}

  except

    //put error handling code here

  end;

end;


TSharedRPCBroker Properties

TSharedRPCBroker	Alphabetically	Legend

In TSharedRPCBroker

AllowShared

OnConnectionDropped

OnLogout

Since the TSharedRPCBroker component is a class derived from the TRPCBroker component,  it contains all of the properties, methods, etc., of its parent.


TSharedRPCBroker Properties (Alpha)

TSharedRPCBroker	By Object 	Legend

The following is a list of the properties that are available with the TSharedRPCBroker component (includes those properties inherited from the TRPCBroker parent component):

AllowShared

BrokerVersion

ClearParameters

ClearResults

Connected

CurrentContext

DebugMode

IsBackwardCompatibleConnection

IsNewStyleConnection

KernelLogIn

ListenerPort

LogIn

OldConnectionOnly

OnConnectionDropped

OnLogout

OnRPCBFailure

Param

RemoteProcedure

Results

RPCBError

RPCTimeLimit

RPCVersion

Server

ShowErrorMsgs

Socket

User


AllowShared Property

Applies to

TSharedRPCBroker component

Declaration

property AllowShared:  Boolean;

Description

The AllowShared property determines whether or not the connection through the RPCBroker to the VistA M Server can be shared with other applications. If it is not set, the value will be False and the application will have its own dedicated partition on the server. If it is set to True, the partition may be shared with other applications.

 If an application depends on whether local variables from previous calls are present in the partition **DO NOT** permit the partition to be Shared. If the partition is shared, local variables will be cleared out between RPC calls.


OnLogout Property

Applies to

TSharedRPCBroker component

Declaration

property OnLogout:  TNotifyEvent;

Description

The OnLogout property is used to provide a capability in the future for the RPCSharedBrokerSessionMgr to receive a message requesting all applications to log out. This message would then be propagated to all applications that are connected with the RPCSharedBrokerSessionMgr. If a procedure is specified as a value for the OnLogout property, it will be called when this message is received. It can do any processing necessary prior to logging out of the system. There is a default method that will pass the message along to the main window for the application, requesting it to close.

TLogout = procedure () of object;

This class defines the structure of the procedure necessary to be used as an OnLogout value. It would simply be a procedure with no arguments.


OnConnectionDropped Property

Applies to

TSharedRPCBroker component

Declaration

property OnConnectionDropped:  TOnConnectionDropped;

Description

The OnConnectionDropped property is used to provide a capability for handling a connection loss. Loss of a connection to the VistA M Server may be recognized when an RPC call is made, or it may be recognized when the RPCBroker sends its background messages to the VistA M Server at intervals of 45 to 60 seconds to let the server know that the application is still connected. Since, with the SharedRPCBroker, this loss would be recognized in the RPCSharedBrokerSessionMgr and not in the individual applications, they would not normally be aware of this problem until another RPC call is made. To promptly notify the application, the RPCSharedBrokerSessionMgr will send a message back to the applications that have implemented a procedure for the OnConnectionDropped property. This procedure would accept as arguments an integer (the connection index) and a WideString containing any error text for the disconnection. As indicated by the TOnConnectionDropped declaration.

A default procedure is supplied that will display a dialog box indicating the loss of connection and any error text supplied. If further processing is desired, a custom procedure should be created and the OnConnectionDropped property set to it.

TOnConnectionDropped = procedure (ConnectionIndex: Integer; ErrorText: WideString) of object;

This indicates the format of the procedure and arguments required for a method to be used as the OnConnectionDropped property.


 TCCOWRPCBroker Component

Properties	Methods	Example

Parent Class

TRPCBroker = class(TComponent)

Unit

CCOWRPCBroker.pas

Description

The TCCOWRPCBroker component (CCOWRPCBroker.pas) is derived from the existing TRPCBroker component. The TCCOWRPCBroker component (Trpcb.pas) allows VistA application developers to make their applications CCOW-enabled and Single Sign-On/User Context (SSO/UC)-aware with all of the client/server-related functionality in one integrated component. Using the TCCOWRPCBroker component, an application can share User Context stored in the CCOW Context Vault.

Thus, when a VistA CCOW-enabled application is recompiled with the TCCOWRPCBroker component and other required code modifications are made, that application would then become SSO/UC-aware and capable of single sign-on (SSO).

For more detailed information on the application developer procedures and code modifications needed to make CCOW-enabled RPC Broker-based applications SSO/UC aware, please refer to the "RPC Broker-based Client/Server Applications" topic in the "Making VistA Applications SSO/UC-aware" chapter in the Single Sign-On User Context (SSO/UC) Deployment Guide.

Properties inherited from the parent component (i.e., TComponent) are not discussed in this Help file (only those properties added to the parent component are described). For help on inherited properties, please refer to Delphi's documentation on the parent component (i.e., TComponent).

For help on inherited properties, please refer to the parent component (i.e., TRPCBroker).


TCCOWRPCBroker Example

For more examples, please refer to the Samples directory on the use of the TCCOWRPCBroker component:

..\BDK32\Samples\CCOWRPCBroker


TCCOWRPCBroker Properties

TCCOWRPCBroker	Alphabetically	Legend

TCCOWRPCBroker

The following is a list of the properties that are unique to the TCCOWRPCBroker component:

CCOWLogonIDName

CCOWLogonIDValue

CCOWLogonName

CCOWLogonNameValue

CCOWLogonVpid

CCOWLogonVpidValue

Contextor

Since the TCCOWRPCBroker component is a class derived from the TRPCBroker component,  it contains all of the properties, methods, etc., of its parent.


TCCOWRPCBroker Properties (Alpha)

TCCOWRPCBroker	By Object 	Legend

The following is a list of the properties that are available with the TCCOWRPCBroker component (includes those properties inherited from the TRPCBroker parent component):

BrokerVersion

CCOWLogonIDName

CCOWLogonIDValue

CCOWLogonName

CCOWLogonNameValue

CCOWLogonVpid

CCOWLogonVpidValue

ClearParameters

ClearResults

Connected

Contextor

CurrentContext

DebugMode

IsBackwardCompatibleConnection

IsNewStyleConnection

KernelLogIn

ListenerPort

LogIn

OldConnectionOnly

OnRPCBFailure

Param

RemoteProcedure

Results

RPCBError

RPCTimeLimit

RPCVersion

Server

ShowErrorMsgs

Socket

User


CCOWLogonIDName Property
CCOWLogonIDName Property (read-only)

Applies to

TCCOWRPCBroker component

Declaration

property CCOWLogonIDName:  String;

Description

The CCOWLogonIDName property is available at run-time only. This read-only property is the name used within the CCOW Context Vault to store the LogonId.

It permits the user to identify the logon ID name associated with the CCOWLogonIDValue property logon ID name value used within the Context Vault related to User Context.


CCOWLogonIDValue Property
CCOWLogonIDValue Property (read-only)

Applies to

TCCOWRPCBroker component

Declaration

property CCOWLogonIDValue:  String;

Description

The CCOWLogonIDValue property is available at run-time only. This read-only property gives the value currently associated with the LogonId in the CCOW Context Vault.

It permits the user to identify the logon ID value associated with the CCOWLogonIDName property logon ID name used within the Context Vault related to User Context.


CCOWLogonName Property
CCOWLogonName Property (read-only)

Applies to

TCCOWRPCBroker component

Declaration

property CCOWLogonName:  String;

Description

The CCOWLogonName property is available at run-time only. This read-only property gives the name used to store the LogonName of the currently active user.

It permits the user to identify the logon name associated with the CCOWLogonNameValue property logon name value used within the Context Vault related to User Context.


CCOWLogonNameValue Property
CCOWLogonNameValue Property (read-only)

Applies to

TCCOWRPCBroker component

Declaration

property CCOWLogonNameValue:  String;

Description

The CCOWLogonNameValue property is available at run-time only. This read-only property gives the value of the LogonName of the currently active user.

It permits the user to identify the logon name value associated with the CCOWLogonName property logon name used within the Context Vault related to User Context.


CCOWLogonVpid Property
CCOWLogonVpid Property (read-only)

Applies to

TCCOWRPCBroker component

Declaration

property CCOWLogonVpid:  String;

Description

The CCOWLogonVpid property is available at run-time only. This read-only property gives the name used to store the LogonVpid value in the CCOW Context Vault.

It permits the user to identify the logon VPID name associated with the CCOWLogonVpidValue property logon VPID value used within the Context Vault related to User Context.


CCOWLogonVpidValue Property
CCOWLogonVpidValue Property (read-only)

Applies to

TCCOWRPCBroker component

Declaration

property CCOWLogonVpidValue:  String;

Description

The CCOWLogonVpidValue property is available at run-time only. This read-only property gives the value of the VA Person Identification (VPID) value for the currently logged on user, if the facility has been enumerated; otherwise, the value returned will be a null string.

It permits the user to identify the logon VPID value associated with the CCOWLogonVpid property logon VPID name used within the Context Vault related to User Context.


Contextor Property

Applies to

TCCOWRPCBroker component

Declaration

property Contextor:  TContextorControl;

read Fcontextor write FContextor;  //CCOW

Description

The Contextor property is available at run-time only. It must be set to an active instance of the TContextorControl component in order to initiate a login with CCOW User Context. If it is not set to an active instance, then the component basically reverts to an instance of TRPCBroker, since none of the features of CCOW User Context will be used.

The TContextorControl component is the interface for the Sentillion Vergence ContextorControl that communicates with the Context Vault. The component is created based on the type library for the DLL.

Since developers may want to use the TcontextorControl component to initialize their own instances, the TContextor Control component is placed on the Kernel palette in Delphi; however, it is almost as easy to simply create it at runtime without using a component.


TCCOWRPCBroker Methods

TCCOWRPCBroker

GetCCOWtoken

IsUserCleared

IsUserContextPending

WasUserDefined


GetCCOWtoken Method

function GetCCOWtoken(Contextor: TContextorControl): string;

This method returns the CCOW token as a string value. This value is passed in as authentication for the current user. The developer should not need access to this, since it is handled directly within the code for making the connection.

The TContextorControl component is the interface for the Sentillion Vergence ContextorControl that communicates with the Context Vault. The component is created based on the type library for the DLL.

Since developers may want to use the TcontextorControl component to initialize their own instances, the TContextor Control component is placed on the Kernel palette in Delphi; however, it is almost as easy to simply create it at runtime without using a component.

For an example of the GetCCOWtoken method, please refer to the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


IsUserCleared Method

Example

function IsUserCleared: Boolean;

This method returns a value of True if the user value in the Context Vault has been cleared. The value is only of interest if WasUserDefined has a True value (since unless the user has been defined previously, it wouldn't have a value). This method returns:

•	True—CCOW User Context is currently cleared.

•	False—CCOW User Context is currently not cleared.

This method is used in response to an OnPending event to determine if the pending change is User Context related, and if so, whether the User value in the Context Vault has been cleared. If the value has been cleared, then the application should shut down. Switching User Context is not supported, since OCIS policy indicates that the current user must sign off the client workstation and the new user must sign on the client workstation.


IsUserCleared Example

In the event handler for the Commit event of the TContextorControl, developers can check whether or not the user was previously defined, and is now undefined or null. In this case, developers would want to do any necessary processing, then halt.

Procedure TForm1.CommitHandler(Sender: TObject)

begin

    with CCOWRPCBroker1 do

        if WasUserDefined and IsUserCleared then

        begin

            //   do any necessary processing before halting

            halt;

        end;

end;


IsUserContextPending Method

function IsUserContextPending(aContextItemCollection: IContextItemCollection):  Boolean;

This method returns a value of True if the pending context change is related to User Context; if not, then it may be related to the Patient Context, etc. This method returns:

•	True—CCOW pending context change is related to User Context.

•	False—CCOW pending context change is not related to User Context (e.g., Patient Context change).

This method is used in response to an OnPending event to determine if the pending change is User Context related, and if so, whether the User value in the Context Vault has been cleared. If the value has been cleared, then the application should shut down. Switching User Context is not supported, since OCIS policy indicates that the current user must sign off the client workstation and the new user must sign on the client workstation.

For an example of the IsUserContextPending method, please refer to the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


WasUserDefined Method

Example

function WasUserDefined: Boolean;

This method is used to determine whether or not a User Context is currently or was previously defined in the Context Vault. It returns True any time after the initial establishment of User Context. This method returns:

•	True—CCOW User Context established.

•	False—CCOW User Context not established.

This method is used in response to an OnPending event to determine if the pending change is User Context related, and if so, whether the User value in the Context Vault has been cleared. If the value has been cleared, then the application should shut down. Switching User Context is not supported, since OCIS policy indicates that the current user must sign off the client workstation and the new user must sign on the client workstation.


WasUserDefined Example

In the event handler for the Commit event of the TContextorControl, developers can check whether or not the user was previously defined, and is now undefined or null. In this case, developers would want to do any necessary processing, then halt.

Procedure TForm1.CommitHandler(Sender: TObject)

begin

    with CCOWRPCBroker1 do

        if WasUserDefined and IsUserCleared then

        begin

            //   do any necessary processing before halting

            halt;

        end;

end;


TXWBWinsock Class

Unit

TRPCB

Description

The code handling connections and transmission was moved into the TXWBWinsock class, which is defined in wsockc.pas. It facilitates the ability for making and maintaining multiple independent RPC Broker connections. To get around cyclic issues with the Using clause, XWBWinsock within Trpcb.pas is defined as TObject and must be cast to TXWBWinsock when it is used.

The methods in the wsockc.pas unit were originally library methods or methods not associated with a class. To ensure that the TCCOWRPCBroker component is thread-safe (i.e., thread safe operation of RPC Broker instances created in different threads), it became necessary for each instance of the TRPCBroker to have its own instance of these methods, values, etc. Thus, the TXWBWinsock class was created to encapsulate the Public members.


RPC Overview

A Remote Procedure Call (RPC) is a defined call to M code that runs on a VistA M Server. A client application, through the RPC Broker, can make a call to the VistA M Server and execute an RPC on the server. This is the mechanism through which a client application can:

•	Send data to a VistA M Server.

•	Execute code on a VistA M Server.

•	Retrieve data from a VistA M Server.

An RPC can take optional parameters to do some task and then return either a single value or an array to the client application. RPCs are stored in the REMOTE PROCEDURE file (#8994).

The following topics are covered:

What makes a good RPC?

Creating RPCs

Using an Existing M API

•	M Entry Point for an RPC

Relationship Between an M Entry Point and an RPC

M Entry Point First Input Parameter

M Entry Point Return Value Types

M Entry Point Input Parameters

M Entry Point Examples

•	RPC Entry in Remote Procedure File

RPC Entry in Remote Procedure File

RPC Version in Remote Procedure File

Blocking an RPC in Remote Procedure File

Cleanup after RPC Execution

Documenting RPCs

•	Executing RPCs from Clients

How to Execute an RPC from a Client

RPC Security: How to Register an RPC

RPC Limits

Online Code Samples for RPCs


What Makes a Good RPC?

The following characteristics help to make a good remote procedure call (RPC):

•	Silent calls (no I/O to terminal or screen, no user intervention required).

•	Minimal resources required (passes data in brief, controlled increments).

•	Discrete calls (requiring as little information as possible from the process environment).

•	Generic as possible (different parts of the same package as well as other packages could use the same RPC).


Create Your Own RPCs
Creating RPCs

You can create your own custom RPCs to perform actions on the VistA M Server and to retrieve data from the VistA M Server. Then you can call these RPCs from your client application. Creating an RPC requires you to perform the following two steps:

•	Write and test the M entry point that will be called by the RPC.

•	Add the RPC entry that invokes the M entry point, in the REMOTE PROCEDURE file (#8994).


Relationship Between M Entry Point and RPC
Relationship Between an M Entry Point and an RPC

An RPC can be thought of as a wrapper placed around an M entry point for use with client applications. Each RPC invokes a single M entry point.

An M entry point has defined input and output values/parameters that are passed via the standard M invoking methods. An RPC, however, needs to do the following:

•	Accept input from the Broker (i.e., passing data/parameters from the client application).

•	Pass data to the M entry point in a specified manner.

•	Receive values back from the M code in a pre-determined format.

•	Pass M code output back through the Broker to the client application.

You can use the $$BROKER^XWBLIB function in M code to determine whether the code is being run in an environment where it was invoked by the Broker. This can help you use M code simultaneously for Broker and non-Broker applications.

You can use the RPCVersion property to support multiple versions of an RPC. The RPCVersion Example shows you how to do this on the client and server sides.


RPC First Input Parameter
First Input Parameter (Required)

The RPC Broker always passes a variable by reference in the first input parameter to your M routine. It expects results (one of five RETURN VALUE TYPEs) to be returned in this parameter. You must always set some return value into that first parameter before your routine returns.


RPC Return Value Types
Return Value Types

There are five RETURN VALUE TYPEs for RPCs as shown in the table below. You should choose a return value type that is appropriate to the type of data your RPC needs to return. For example, to return the DUZ, a return value type of SINGLE VALUE would be appropriate.

The RETURN VALUE TYPE you choose then determines what value(s) you should set into the return value parameter of your M entry point.

You should always set some value into the Return Value parameter of the M entry point, even if your RPC encounters an error condition.

The following RPC settings, combined with your M entry point, determine how data is returned to your client application:

RPC Return Value Type	How M Entry Point Should Set the Return Parameter	RPC Word Wrap On Setting	Value(s) returned in Client Results
Single Value	Set the return parameter to a single value. For example: TAG(RESULT) ;  S RESULT="DOE, JOHN"  Q	No effect	Value of parameter, in Results[0].
Array	Set an array of strings into the return parameter, each subscripted one level descendant. For example: TAG(RESULT) ;  S RESULT(1)="ONE"  S RESULT(2)="TWO"  Q  If your array is large, consider using the GLOBAL ARRAY return value type, to avoid memory allocation errors.	No effect	Array values, each in a Results item.
Word Processing	Set the return parameter the same as you set it for the ARRAY type. The only difference is that the WORD WRAP ON setting affects the WORD PROCESSING return value type.	True False	Array values, each in a Results item. Array values, all concatenated into Results[0].
Global Array	Set the return parameter to a closed global reference in ^TMP. The global's data nodes will be traversed using $QUERY, and all data values on global nodes descendant from the global reference are returned. This type is especially useful for returning data from VA FileMan WORD PROCESSING type fields, where each line is on a 0-subscripted node.  The global reference you pass is killed by the Broker at the end of RPC Execution as part of RPC cleanup. Do not pass a global reference that is not in ^TMP or that should not be killed. This type is useful for returning large amounts of data to the client, where using the ARRAY type can exceed the symbol table limit and crash your RPC. For example, to return signon introductory text you could do: TAG(RESULT);  M ^TMP("A6A",$J)= ^XTV(8989.3,1,"INTRO")  ;this node not needed  K ^TMP("A6A",$J,0)  S RESULT=$NA(^TMP("A6A",$J))  Q	True False	Array values, each in a Results item. Array values, all concatenated into Results[0].
Global Instance	Set the return parameter to a closed global reference. For example the following code returns the whole 0th node from the NEW PERSON file (#200) for the current user: TAG(RESULT) ;  S RESULT=$NA(^VA(200,DUZ,0))  Q	No effect	Value of global node, in Results[0].
In the M code called by an RPC, you can use the $$RTRNFMT^XWBLIB function to change the RETURN VALUE TYPE of an RPC on-the-fly.


RPC Input Parameter Types
Input Parameters (Optional)

The M entry point for an RPC can optionally have input parameters (i.e., beyond the first parameter, which is always used to return an output value). The client passes data to your M entry point through these parameters.

The client can send data to an RPC (and therefore your entry point) in one of the following three Param types:

Param PType	Param Value

literal	Delphi string value, passed as a string literal to the VistA M Server.

reference	Delphi string value, treated on the VistA M Server as an M variable name and resolved from the symbol table at the time the RPC executes.

list	A single-dimensional array of strings in the Mult property of the Param property, passed to the VistA M Server where it is placed in an array. String subscripting can be used.

The type of the input parameters passed in the Param property of the TRPCBroker component determines the format of the data you must be prepared to receive in your M entry point.


RPC M Entry Point Examples
Examples

The following two examples illustrate sample M code that could be used in simple RPCs.

1.	This example takes two numbers and returns their sum:

SUM(RESULT,A,B)	;add two numbers

 S RESULT=A+B

 Q

2.	This example receives an array of numbers and returns them as a sorted array to the client:

SORT(RESULT,UNSORTED)	;sort numbers

 N I

 S I=""

 F  S I=$O(UNSORTED(I)) Q:I=""  S RESULT(UNSORTED(I))=UNSORTED(I)

 Q


RPC Entry in the Remote Procedure File

After the M code is complete, you need to add the RPC to the REMOTE PROCEDURE file (#8994). The following fields in the REMOTE PROCEDURE file (#8994) are key to the correct operation of an RPC:

Field Name	Required?	Description
NAME (#.01)	Yes	The name that identifies the RPC (this entry should be namespaced in the package namespace).
TAG (#.02)	Yes	The tag at which the remote procedure call begins.
ROUTINE (#.03)	Yes	The name of the routine that should be invoked to start the RPC.
WORD WRAP ON (#.08)	No	Affects GLOBAL ARRAY and WORD PROCESSING return value types only. If set to False, all data values are returned in a single concatenated string in Results[0]. If set to True, each array node on the M side is returned as a distinct array item in Results.
RETURN VALUE TYPE (#.04)	Yes	This can be one of five types: SINGLE VALUE, ARRAY, WORD PROCESSING, GLOBAL ARRAY, GLOBAL INSTANCE. This setting controls how the Broker processes an RPC's return parameter.


Cleanup after RPC Execution?

The Broker uses XUTL^XUSCLEAN to clean up globals upon application termination.

In addition, there is an RPC RETURN VALUE TYPE, GLOBAL ARRAY, where the application RPC returns a closed form global reference, for example:

^TMP("EKG",220333551)

The Broker kills the data for the global reference for this type of RPC at the end of RPC execution.


Documenting RPCs

Each individual application development team is responsible for identifying and providing documentation for all object components, classes, and remote procedure calls they create. Other developers using these components will need to know what RPCs are called because they will need to register them with their applications.

RPCs should be documented in the DESCRIPTION field (#1) in the REMOTE PROCEDURE file (#8994) for those RPCs installed on your system. This gives you the capability of generating a catalog of RPCs from File #8994.

Delphi Component Library and Sample RPCs

In the future, an Enterprise library of object components, classes, and remote procedure calls that are in use and available to the development community at large may be available. The essential benefit of this type of library is the promotion of object re-use, thereby enhancing development productivity, application consistency, and quality assurance. Therefore, it could contain a wide variety of components, classes, and RPCs from many VistA software applications.

The immediate intent is to classify and catalogue all of the object classes in use (including the standard Delphi classes), and to make the catalogue available to all interested parties


How to Execute an RPC from a Client Application
How to Execute an RPC from a Client

1.	If your RPC has any input parameters beyond the mandatory first parameter, set a Param node in the TRPCBroker's Param property for each. For each input parameter, set the following subproperties:

•	Value

•	PType (literal, list, or reference).

If the parameter's PType is list, however, instead of specifying a value, instead set a list of values in the Mult property.

Here is an example of some settings of the Param property:

brkrRPCBroker1.Param[0].Value := '10/31/97';

brkrRPCBroker1.Param[0].PType := literal;

brkrRPCBroker1.Param[1].Mult['"NAME"'] := 'SMITH, JOHN';

brkrRPCBroker1.Param[1].Mult['"SSN"'] := '123-45-6789';

brkrRPCBroker1.Param[1].PType := list;

2.	Set the TRPCBroker's RemoteProcedure property to the name of the RPC to execute.

brkrRPCBroker1.RemoteProcedure:='A6A LIST';

3.	Invoke the Call method of the TRPCBroker component to execute the RPC. All calls to the Call method should be done within an exception handler try...except statement, so that all communication errors (which trigger the EBrokerError exception) can be trapped and handled. For example:

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('A problem was encountered communicating with the server.');

end;

4.	Any results returned by your RPC are returned in the TRPCBroker component's Results property. Depending on how you set up your RPC, results are returned either in a single node of the Results property (Results[0]), or in multiple nodes of the Results property.

You can also use the lstCall and strCall methods to execute an RPC. The main difference between these methods and the Call method is that lstCall and strCall do not use the Results property, instead returning results into a location you specify.


RPC Security: How to Register an RPC

Security for RPCs is handled through the RPC registration process. Each client application must create a context for itself, which checks if the application user has access to a "B"-type option in the Kernel menu system. Only RPCs assigned to that option can be run by the client application.

To enable your application to create a context for itself:

1.	Create a "B"-type option in the OPTION file (#19) for your application.

The OPTION TYPE "B" represents a Broker client/server type option.

2.	In the RPC multiple for this option type, add an entry for each RPC that your application calls. The following fields can be set up for each RPC in your option:

Field Name	Entry	Description
RPC (#.01)	Required	This field is used to enter a pointer to the REMOTE PROCEDURE file (#8994). This field links the remote procedure call in the REMOTE PROCEDURE file (#8994) to the package option.
RPCKEY (#1)	Optional	This field is used to restrict the use of a remote procedure call to a particular package option. The RPCKEY field is a free-text pointer to the SECURITY KEY file (#19.1).
RULES (#2)	Optional	This field is used to enter M code that is executed when an RPC request is made to verify whether the request should be honored.
3.	When you export your package using Kernel Installation and Distribution System (KIDS), export both your RPCs and your package option. KIDS will automatically associate the RPCs with the package option.

4.	Your application must create a context for itself on the VistA M Server, which checks access to RPCs. In the initial code of your client application, make a call to the CreateContext method of your TRPCBroker component. Pass your application's "B"-type option's name as a parameter. For example:

if not brkrRPCBroker1.CreateContext(option_name) then

  Application.Terminate;

If the CreateContext method returns True, only those RPCs designated in the RPC multiple of your application option will be permitted to run.

If the CreateContext method returns False, you should terminate your application (if you don't, your application will run but you will get errors every time you try to access an RPC).

5.	End-users of your application must have the "B"-type option assigned to them on one of their menus, in order for CreateContext to return True. This allows system managers to control access to client applications.


Bypassing RPC Security for Development

Having the XUPROGMODE security key allows you to bypass the Broker security checks. You can run any RPC without regard to application context (without having to use the CreateContext method). This is a convenience for when you are developing an application. When you complete development, make sure you test your application from an account without the XUPROGMODE security key, to ensure that all RPCs needed are properly registered.


RPC Limits

The following is a list of various constants, maximum, and minimum parameters associated with the use of the RPC Broker:

•	Maximum number of parameters that can be passed to the VistA M Server.

•	Maximum size of array that can be passed to the VistA M Server.

•	Maximum size of data that can be received in the VistA Graphical User Interface (GUI) application from the VistA M Server.

•	RPC Time limit.


Maximum Number of Parameters

The remote procedure calls (RPCs) become M DO procedures on the VistA M Server. Since RPCs are communicated to the VistA M Server through a message mechanism, additional information is included with the message.

Parameters are processed as PASCAL short strings with a maximum of 255 characters. Each parameter is encoded with a three-character length plus a type character. Therefore, every parameter occupies length (parameter) + four. The maximum transmission at this time is 240 characters, since additional header information is present with every RPC.

A theoretical maximum, where every parameter was length 1 would give number of parameters = 240/5 or 48 parameters. A single parameter (e.g., a long string) could not exceed 240 - 4, or 236 characters. Future support will be based on the PASCAL 32-bit string, which can, theoretically, reach 2 GB. Limitations on the VistA M Server will still limit this to far less, however.


Maximum Size of Array

Although approximately only 240 characters can be sent to the VistA M Server as call parameters, a single array parameter can be passed in with greater capacity. The RPC can carry both literal and array parameters except that literal parameters are placed first and the single array last in order. Arrays are instantiated at the VistA M Server and are stored in a local array format. The maximum size will be dependent on the symbol space available to the VistA M Server process. The index size and the value size are subject to limitations as follows: Index and value each cannot exceed 255 - 3, or 252 characters approximately for each individual array elements.

At the time of this writing, 30 to 40 K arrays have easily been passed to the VistA M Server in a single RPC call.


Maximum Size of Data

The M server can transmit very large buffers of data back to the Microsoft Windows client. The Windows client receives the returned data from an RPC into a 32-bit PASCAL string. RPCs can be written on the VistA M Server so that they store their results in an M GLOBAL structure, which can span RAM and disk storage media. This GLOBAL storage could be quite large depending on the assigned system quotas to the VistA M Server process. The return of the RPC can deliver this quantity to the Windows client. The actual limit will depend on the capacity that the Microsoft Windows operating system will allow the client to process. Tests on a 32-megabyte RAM system have allowed buffers of several megabytes of data to be transmitted from the VistA M Server to the Microsoft Windows client.


Time Limits
RPC Time Limits

A public READ/WRITE property (i.e., RPCTimeLimit) allows the application to change the network operation timeout prior to a call. This can be useful during times when it is known that a certain RPC, by its nature, can take a significant amount of time to execute. The value of this property is an integer that cannot be less than 30 seconds nor greater that 32767 seconds. Care should be taken when altering this value, since the network operation will block the application until the operation finishes or the timeout is triggered.

There is also a Server time limit for how long to stay connected when the client doesn't respond.


RPC Broker Example (32-Bit)

The RPC Broker Example sample application provided with the BDK (i.e., BrokerExample.EXE, located in the ..\BDK32\Samples\BrokerEx directory) demonstrates the basic features of developing RPCBroker applications, including:

•	Connecting to an M server

•	Creating an application context

•	Using the GetServerInfo function

•	Displaying the VistA splash screen

•	Setting the TRPCBroker.Param property for each Param PType (literal, reference, list)

•	Calling RPCs with the Call method

•	Calling RPCs with the lstCall and strCall methods

The client source code files for the BrokerExample application are located in the ..\BDK32\Samples\BrokerEx directory.

Initially, use Delphi to compile the BrokerExample.DPR into an executable.


Using an Existing M API

In some cases an existing M API will provide a useful M entry point for an RPC. As with any M entry point, you will need to add the RPC entry that invokes the M entry point, in the REMOTE PROCEDURE file (#8994).

See also: Relationship Between an M Entry Point and an RPC


Blocking an RPC in the Remote Procedure File

The INACTIVE field of the REMOTE PROCEDURE file (#8994) allows blocking of RPCs. The blocking can apply to local access (users directly logged into the site) or remote access (users logged on to a different site) or both. The field can be set either by a package developer and exported by KIDS or by a site manager using VA FileMan.

Value in INACTIVE field

1 = Completely unusable

2 = Unusable locally

3 = Unusable remotely


RPC Version in the Remote Procedure File

The VERSION field of the REMOTE PROCEDURE file (#8994) indicates the version number of an RPC installed at a site. The field can be set either by an application developer and exported by KIDS or by a site manager using VA FileMan.

Applications can use XWB IS RPC AVAILABLE or XWB ARE RPCS AVAILABLE to check the availability of a version of an RPC on a server. This is especially useful for RPCs run remotely, as the remote server may not have the latest RPC installed.


Other APIs Overview
Other RPC Broker APIs

The Broker Development Kit (BDK) provides the following development APIs in addition to the RPC Broker components:

GetServerInfo Function

VistA Splash Screen Procedures

XWB GET VARIABLE VALUE RPC

M Emulation Functions

Encryption Functions

XWB IS RPC AVAILABLE

XWB ARE RPCS AVAILABLE

Running RPCs on a Remote Server

Deferred RPCs

The RPC Broker software provides the following application program interfaces (APIs) on the VistA M Server for use in RPC code:

$$BROKER^XWBLIB (Determine if running from a Broker call)

$$RTRNFMT^XWBLIB (Change return format of RPC)


GetServerInfo Function

Example

The GetServerInfo function retrieves the end-user's selection of server and port to which to connect. Use this function to set a TRPCBroker component's Server and ListenerPort properties to reflect the end-user's choice before connecting to the VistA M Server.

If there is more than one server/port from which to choose, GetServerInfo displays an application window that allows users to select a service to connect to:

Syntax:

function GetServerInfo(var Server, Port: string): integer;

The unit is RpcConf1.

The GetServerInfo function handles the following scenarios:

•	If there are no values for server and port in the Windows Registry, GetServerInfo does not display its dialog window, and the automatic default values returned are BROKERSERVER/9200. GetServerInfo returns mrOK.

•	If exactly one server and port entry is defined in the Windows Registry, GetServerInfo does not display its dialog window. The values in the single Windows Registry entry are returned to the calling application, with no user interaction. GetServerInfo returns mrOK.

•	If more than one server and port entry exists in the Windows Registry, the dialog window is displayed. The only time that passed in server and port values will be returned to the calling application is if the user presses Cancel. However, if a user selects an entry and clicks on the OK button, the server and port parameters will be changed and returned to the calling application. GetServerInfo returns mrOK if the user pressed the OK button, or mrCancel if the user pressed the Cancel button.

For a demonstration using the Broker and GetServerInfo function, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


GetServerInfo Example

The following is example of the GetServerInfo function:

procedure TForm1.btnConnectClick(Sender: TObject);

var

  strServer, strPort: string;

begin

  if GetServerInfo(strServer, strPort)<> mrCancel then begin {getsvrinfo begin}

    brkrRPCBroker1.Server := strServer;

    brkrRPCBroker1.ListenerPort := StrToInt(strPort);

    brkrRPCBroker1.Connected := True;

  {getsvrinfo end}

  end;

end;

For a demonstration using the Broker and GetServerInfo function, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


VistA Splash Screen Procedures

Example

Two procedures in SplVista.PAS unit are provided to display a VistA Splash Screen when an application loads:

procedure SplashOpen;

procedure SplashClose(TimeOut: longint);

It is recommended that the VistA Splash Screen be opened and closed in the section of Pascal code in an application's project file (i.e., .DPR).

To use the VistA Splash Screen in an application:

1.	Open your application's project (.DPR) file (in Delphi, choose View | Project Source).

2.	Include the SplVista in the uses clause of the project source.

3.	Call SplashOpen immediately after the first form of your application is created and call SplashClose just prior to invoking the Application.Run method.

4.	Use the TimeOut parameter to ensure a minimum display time. The TimeOut parameter is the minimum number of milliseconds the screen will be shown.

The VistA Splash Screen is illustrated below:

For a demonstration using the VistA Splash Screen, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


VistA Splash Screen Example

The following is example of displaying the VistA Splash Screen in an application:

uses

  Forms, Unit1 in 'Unit1.pas', SplVista;

{$R *.RES}

begin

  Application.Initialize;

  Application.CreateForm(TForm1, Form1);

  SplashOpen;

  SplashClose(2000);

  Application.Run;

end.

For a demonstration using the VistA Splash Screen, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


XWB GET VARIABLE VALUE RPC

Example

You can call the XWB GET VARIABLE VALUE RPC (distributed with the RPC Broker) to retrieve the value of any M variable in the VistA M Server environment. Pass the variable name in Param[0].Value, and the type (reference) in Param[0].PType. Also, the current context of your user must give them permission to execute the XWB GET VARIABLE VALUE RPC (it must be included in the RPC multiple of the "B"-type option registered with the CreateContext function).


XWB GET VARIABLE VALUE Example

The following is example of the XWB GET VARIABLE VALUE RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB GET VARIABLE VALUE';

brkrRPCBroker1.Param[0].Value :='DUZ';

brkrRPCBroker1.Param[0].PType := reference;

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

ShowMessage('DUZ is '+brkrRPCBroker1.Results[0]);


M Emulation Functions

Examples

Piece Function

The Piece function is a scaled down Pascal version of M's $PIECE function. It is declared in MFUNSTR.PAS.

function Piece(x: string; del: string; piece: integer) : string;

Translate Function

The Translate function is a scaled down Pascal version of M's $TRANSLATE function. It is declared in MFUNSTR.PAS.

function Translate(passedString, identifier, associator: string): string;


M Emulation Examples

Piece Function

Piece3Str:=piece('123^456^789','^',3);

Translate Function

hiStr:=translate('HI','ABCDEFGHI','abcdefghi');


Encryption Functions

Kernel and the RPC Broker provide encryption functions that can be used to encrypt messages sent between the client and the server.

In Delphi

Include HASH in the "uses" clause of the unit in which you'll be encrypting or decrypting.

Function prototypes are as follows:

function Decrypt(EncryptedText: string): string;

function Encrypt(NormalText: string): string;

On the VistA M Server

To encrypt:

KRN,KDE>S CIPHER=$$ENCRYP^XUSRB1("Hello world!") W CIPHER

/U'llTG~TVl&f-

To decrypt:

KRN,KDE>S PLAIN=$$DECRYP^XUSRB1(CIPHER) W PLAIN

Hello world!

These encryption functions can be used for any communication between the client and the server where encryption is desired.


$$BROKER^XWBLIB

Use this function in the M code called by an RPC to determine if the current process is being executed by the RPC Broker.

Format

$$BROKER^XWBLIB

Input

(none)

Output

Return Value	1 if the current process is being executed by the Broker; 0 if not.

Example

I $$BROKER^XWBLIB D

.; broker-specific code


$$RTRNFMT^XWBLIB

Use this function in the M code called by an RPC to change the return value type that the RPC will return on the fly.

Format

$$RTRNFMT^XWBLIB(type, wrap)

Input

type	Set this to the RETURN VALUE TYPE to change the RPC's setting to. You can set it to one of the following numeric or free text values:

numeric	free text

1	SINGLE VALUE

2	ARRAY

3	WORD PROCESSING

4	GLOBAL ARRAY

5	FOR GLOBAL INSTANCE

wrap	Set to 1 to set the RPC's WORD WRAP ON setting to True; set to 0 to set the RPC's WORD WRAP ON setting to False.

Output

Return Value	0 if the return value type could not be changed; otherwise, the numeric code representing the return value type that the RPC is changed to.

Example

I '$$RTRNFMT^XWBLIB("ARRAY",1) D

.; branch to code if can't change RPC type


XWB IS RPC AVAILABLE

Example

Checking RPC Availability on a Remote Server

Use this RPC to determine if a particular RPC is available on a VistA M Server. The RPC PARAMETER passes the name of the RPC to be checked. The RUN CONTEXT PARAMETER allows you to test availability to a local or a remote user. The VERSION NUMBER PARAMETER allows you to check for a minimum version of an RPC on a remote VistA M Server.

RETURN VALUE:	Boolean

1 = RPC Available

0 = RPC Not Available

RPC PARAMETER:	Pass the name of the RPC to be tested in Param[0].Value, and the type (literal) in Param[0].PType.

RUN CONTEXT PARAMETER (Optional):	Pass the run context (local or remote) of the RPC in Param[1].Value, and the type (literal) in Param[1].PType. Possible values are:

•	L = Check if available to be run locally (by a user logged into the VistA M Server)

•	R = Check if available to be run remotely (by a user logged in a different VistA M Server)

If this parameter is not sent, the RPC is checked for both local and remote and both run contexts must be available for the return to be ‘1’ (RPC Available). The check is done against the INACTIVE field in the REMOTE PROCEDURE file .

VERSION NUMBER PARAMETER (Optional):	Pass the minimum acceptable version number of the RPC in Param[2].Value, and the type (literal) in Param[2].PType. This parameter is only used if the RUN CONTEXT parameter = "R". If a numeric value is in this parameter, it will be checked against the value in the VERSION field of the REMOTE PROCEDURE file. If the version number passed is less than or equal to the number in the VERSION field, the RPC will be marked available.

If the VERSION field is null, the check will fail for a numeric value in this parameter.

Also, the current context of your user must give them permission to execute the XWB IS RPC AVAILABLE (it must be included in the RPC multiple of the "B"-type option registered with the CreateContext function).


XWB IS RPC AVAILABLE Example

The following is example of the XWB IS RPC AVAILABLE RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB IS RPC AVAILABLE';

brkrRPCBroker1.Param[0].Value :='XWB GET VARIABLE VALUE';

brkrRPCBroker1.Param[0].PType := literal;

brkrRPCBroker1.Param[1].Value := 'R';

brkrRPCBroker1.Param[1].PType := literal;

  {no version number passed in this example as XWB GET VARIABLE VALUE has only one version}

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; branch code to handle RPC availability


XWB ARE RPCS AVAILABLE

Example

Checking RPC Availability on a Remote Server

Use this RPC to determine if a set of RPCs is available on a VistA M Server. The RUN CONTEXT PARAMETER allows you to test availability on a local or remote VistA M Server. The RPC INPUT PARAMETER passes the names and (optionally) minimum version number of the RPCs to be checked.

RETURN VALUE:	A 0-based array. The index corresponds to the index of the RPC in the RPC Input Parameter.

1 = RPC Available

0 = RPC Not Available

RUN CONTEXT PARAMETER (Optional):	Pass the run context (local or remote) of the RPC in Param[0].Value, and the type (literal) in Param[0].PType. Possible values are:

•	L = Check if available to be run locally (by a user logged into the VistA M Server).

•	R = Check if available to be run remotely (by a user logged in a different VistA M Server).

If this parameter is not sent, the RPC is checked for both local and remote, and both run contexts must be available for the return to be "1" (RPC Available). The check is done against the INACTIVE field in the REMOTE PROCEDURE file.

RPC INPUT PARAMETER:	Pass a 0-based array of the names and (optionally) version numbers of RPCs to be tested in Param[1].Mult[], and the type (List) in Param[1].PType. The format is:

RPCName^RPCVersionNumber

The RPCVersionNumber is used only if the Run Context parameter = "R". If a numeric value is in the second ^-piece and Run Context = "R", it will be checked against the value in the VERSION field of the REMOTE PROCEDURE file If the version number passed is less than or equal to the number in the VERSION field, the RPC will be marked available.

If the VERSION field is null, the check will fail for a numeric value in this parameter.

Also, the current context of your user must give them permission to execute the XWB ARE RPCS AVAILABLE (it must be included in the RPC multiple of the "B"-type option registered with the CreateContext function).


XWB ARE RPCS AVAILABLE Example

The following is example of the XWB ARE RPCS AVAILABLE RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB ARE RPCS AVAILABLE';

brkrRPCBroker1.Param[0].Ptype:= Literal;

brkrRPCBroker1.Param[0].Value := 'L';

brkrRPCBroker1.Param[1].Ptype := List;

brkrRPCBroker1.Param[1].Mult['0'] = 'MY FIRST RPC';

brkrRPCBroker1.Param[1].Mult['1'] = 'MY OTHER RPC^2';

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; branch code to handle availability of RPCs


Options For Running RPCs on a Remote Server

The RPC Broker can be used to facilitate invocation of Remote Procedure Calls on a remote VistA M Server. Applications can use either XWB DIRECT RPC or XWB REMOTE RPC to pass:

•	The desired remote VistA M Server.

•	The desired remote RPC.

•	Any parameters for the remote RPC.

The RPC Broker on the local VistA M Server uses VistA HL7 as a vehicle to pass the remote RPC name and parameters to the remote VistA M Server. VistA HL7 is used to send any results from the remote server back to the local server. The RPC Broker on the local VistA M Server then passes the results back to the client application.

The local VistA M Server is the server the user is logged into. The remote VistA M Server is any server the user is not logged into.

USING XWB DIRECT RPC

XWB DIRECT RPC blocks all other Broker calls until the results of the remote RPC are returned. The data is passed and the user waits for the results to return from the remote system.

USING XWB REMOTE RPC

XWB REMOTE RPC is set up to allow other activity while the remote RPC is in process. In response to XWB REMOTE RPC the local VistA M Server returns a HANDLE to the user application. At this point other Broker calls may commence while the server-to-server communication continues in the background.

XWB REMOTE STATUS CHECK allows the application to check the local VistA M Server for the presence of results from the remote RPC. This RPC passes the HANDLE to the local server and receives back the status of the remote RPC.

XWB REMOTE GETDATA is the vehicle for retrieving the results from the remote RPC after the status check indicates that the data has returned to the local VistA M Server. The RPC passes the HANDLE and receives back an array with whatever data has been sent back from the remote site.

XWB REMOTE CLEAR must be used to clear the data under the HANDLE in the ^XTMP Global.

Applications using XWB REMOTE XWB should use XWB DEFERRED CLEARALL on application close to clear all known data associated with the job on the VistA M Server.

XWB DIRECT RPC and XWB REMOTE RPC are available only on a controlled subscription basis.


Checking RPC Availability on a Remote Server

Applications can check the availability of RPCs on a remote VistA M Server. Use:

XWB DIRECT RPC or XWB REMOTE RPC

to pass:

XWB IS RPC AVAILABLE or XWB ARE RPCS AVAILABLE

to the remote server.

The Run Context Parameter in XWB IS RPC AVAILABLE or XWB ARE RPCS AVAILABLE should be set to ‘R’ or null to check that the remote VistA M Server will allow RPCs to be run by users not logged into that remote server.


XWB DIRECT RPC

Example

Use this RPC to request that an RPC be run on a remote system. This RPC blocks all other Broker calls until the results of the remote RPC are returned. Use XWB REMOTE RPC to allow other Broker activity while the remote RPC runs.

For a comparison of the two methods, please refer to the "Options For Running RPCs on a Remote Server" topic.

LOCATION PARAMETER:	Pass the station number of the remote VistA M Server in Param[0].Value, and the type (literal) in Param[0].PType.

RPC PARAMETER:	Pass the name of the RPC to be run in Param[1].Value, and the type (literal) in Param[1].PType.

RPC VERSION PARAMETER (Optional):	Pass minimum version of RPC to be run in Param[2].Value, and the type (literal) in Param[2].PType. It will be checked against the value in the VERSION field of the REMOTE PROCEDURE file on the remote VistA M Server.

PARAMETERS TO THE REMOTE RPC:	Pass up to seven parameters for the remote RPC in Param[3] through Param[9].

RETURN VALUE:	An array with whatever data has been sent back from the remote site. In the case of an error condition the first node of the array is equal to a string with the syntax "-1^error text".

XWB DIRECT RPC is available only on a controlled subscription basis.


XWB DIRECT RPC Example

The following is example of the XWB DIRECT RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB DIRECT RPC';

brkrRPCBroker1.Param[0].Ptype:= Literal;

brkrRPCBroker1.Param[0].Value := 'Station Number';

brkrRPCBroker1.Param[1].Ptype:= Literal;

brkrRPCBroker1.Param[1].Value := 'XWB GET VARIABLE VALUE';

{no version numbers for remote RPC so null value in Param[2]}

brkrRPCBroker1.Param[2].Ptype:= Literal;

brkrRPCBroker1.Param[2].Value := '';

brkrRPCBroker1.Param[3].Ptype:= Reference;

brkrRPCBroker1.Param[3].Value := 'DUZ';

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; code to handle brkrRPCBroker1.Results[]


XWB REMOTE RPC

Example

Use this RPC to request that an RPC be run on a remote system. This RPC allows other Broker activity while the remote RPC runs. Use XWB DIRECT RPC to block all other Broker activity while the remote RPC runs.

For a comparison of the two methods, please refer to the "Options For Running RPCs on a Remote Server" topic.

XWB REMOTE RPC requests the remote RPC. The return value is a HANDLE that is used to check status and retrieve data. The following RPCs must be used to complete the transaction

•	XWB REMOTE STATUS CHECK

•	XWB REMOTE GETDATA

•	XWB REMOTE CLEAR

LOCATION PARAMETER:	Pass the station number of the remote VistA M Server in Param[0].Value, and the type (literal) in Param[0].PType.

RPC PARAMETER:	Pass the name of the RPC to be run in Param[1].Value, and the type (literal) in Param[1].PType.

RPC VERSION PARAMETER (Optional):	Pass minimum version of RPC to be run in Param[2].Value, and the type (literal) in Param[2].PType. It will be checked against the value in the VERSION field of the REMOTE PROCEDURE file on the remote VistA M Server.

PARAMETERS TO THE REMOTE RPC:	Pass up to seven parameters for the remote RPC in Param[3] through Param[9].

RETURN VALUE:	An array. The first node is equal to a string that serves as a HANDLE. This HANDLE should be stored by the application and used to check the status and retrieve the data. In the case of an error condition the first node of the array is equal to a string with the syntax "-1^error text".

XWB REMOTE RPC is available only on a controlled subscription basis.


XWB REMOTE RPC Example

The following is example of the XWB REMOTE RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE RPC';

brkrRPCBroker1.Param[0].Ptype:= Literal;

brkrRPCBroker1.Param[0].Value := 'Station Number';

brkrRPCBroker1.Param[1].Ptype:= Literal;

brkrRPCBroker1.Param[1].Value := 'MY RPC’;

brkrRPCBroker1.Param[2].Ptype:= Literal;

brkrRPCBroker1.Param[2].Value := '1';

brkrRPCBroker1.Param[3].Ptype:= Reference;

brkrRPCBroker1.Param[3].Value := 'MY RPC PARAMETER';

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; code to store HANDLE returned in brkrRPCBroker1.Results[]

The application will need to use XWB REMOTE STATUS CHECK, XWB REMOTE GETDATA, and XWB REMOTE CLEAR to complete the transaction.


XWB REMOTE STATUS CHECK

Example

Use this RPC to check for results of XWB REMOTE RPC. Periodically call this RPC and pass the HANDLE returned by XWB REMOTE RPC.

RETURN VALUE:	The return value is always an array. The first node of the array is equal to one of the following values:

•	"-1^Bad Handle -- An invalid handle has been passed.

•	"0^New" -- The request has been sent via VistA HL7.

•	"0^Running" -- VistA HL7 indicates that the message is being processed.

•	"1^Done" -- RPC has completed and the data has been returned to the local VistA M Server. The data is not returned by this RPC. Use XWB REMOTE GETDATA to retrieve the data.

The second node of the array is the status from the VistA HL7 package.


XWB REMOTE STATUS CHECK Example

The following is example of the XWB REMOTE STATUS CHECK RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE STATUS CHECK';

brkrRPCBroker1.Param[0].Value :='MYHANDLE';

brkrRPCBroker1.Param[0].PType := literal;

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; code to handle results of check


XWB REMOTE GETDATA

Example

Use this RPC to retrieve the results of XWB REMOTE RPC. Before calling this RPC, use XWB REMOTE STATUS CHECK to ensure that the results have been returned to the local VistA M Server. When the results have arrived, call this RPC and pass the HANDLE returned by XWB REMOTE RPC.

After the application is finished with the data on the VistA M Server, it should use XWB REMOTE CLEAR to clear the ^XTMP global.

RETURN VALUE:	An array containing the data. In the case of an error condition the first node of the array is equal to a string with the syntax "-1^error text".


XWB REMOTE GETDATA Example

The following is example of the XWB REMOTE GETDATA RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE GETDATA';

brkrRPCBroker1.Param[0].Value :='MYHANDLE';

brkrRPCBroker1.Param[0].PType := literal;

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; code to handle data


XWB REMOTE CLEAR

Example

This RPC is used to clear the data created by a remote RPC under the HANDLE in the ^XTMP. Pass the HANDLE returned by XWB REMOTE RPC.

RETURN VALUE:	An array. The first node in the array is equal to 1.


XWB REMOTE CLEAR Example

The following is example of the XWB REMOTE CLEAR RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE CLEAR';

brkrRPCBroker1.Param[0].Value :='MYHANDLE';

brkrRPCBroker1.Param[0].PType := literal;

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;


HANDLE

A HANDLE is a string returned by XWB REMOTE RPC or XWB DEFERRED RPC. The application should store the HANDLE and use it to check for the return of the data, retrieve the data, and clear the data from the VistA M Server.


Overview of Deferred RPCs

Remote Procedure Calls can now be run in the background with XWB DEFERRED RPC.

USING XWB DEFERRED RPC

XWB DEFERRED RPC is used to pass the name of the RPC to be run in deferred mode and any parameters associated with the deferred RPC. In response to this RPC the VistA M Server returns a HANDLE to the user application. At this point other Broker calls can commence while the job runs in the background.

XWB DEFERRED STATUS allows the application to check the local VistA M Server for the presence of results from the deferred RPC. This RPC passes the HANDLE to the local server and receives back the status of the remote RPC.

XWB DEFERRED GETDATA is the vehicle for retrieving the results from the remote RPC after the status check indicates that the data has returned to the local VistA M Server. The RPC passes the HANDLE and receives back an array with whatever data has been returned by the deferred RPC.

XWB DEFERRED CLEAR must be used to clear the data under the HANDLE in the ^XTMP Global.

Applications using XWB DEFERRED RPC should use XWB DEFERRED CLEARALL on application close to clear all known data associated with the job on the VistA M Server.


XWB DEFERRED RPC

Example

Use this RPC to request that an RPC be run in deferred mode. The return value is a HANDLE that is used to check status and retrieve data. The following RPCs must be used to complete the transaction:

•	XWB DEFERRED STATUS

•	XWB DEFERRED GETDATA

•	XWB DEFERRED CLEAR

RPC PARAMETER:	Pass the name of the RPC to be run in Param[0].Value, and the type (literal) in Param[0].PType.

RPC VERSION PARAMETER (Optional):	Pass minimum version of RPC to be run in Param[1].Value, and the type (literal) in Param[1].PType. It will be checked against the value in the VERSION field of the REMOTE PROCEDURE file on the remote VistA M Server.

PARAMETERS TO THE REMOTE RPC:	Pass up to eight parameters for the remote RPC in Param[2] through Param[9].

RETURN VALUE:	An array. The first node is equal to a string that serves as a HANDLE. This HANDLE should be stored by the application and used to check the status and retrieve the data. In the case of an error condition the first node of the array is equal to a string with the syntax "-1^error text".


XWB DEFERRED RPC Example

The following is example of the XWB DEFERRED RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED RPC';

brkrRPCBroker1.Param[0].Ptype:= Literal;

brkrRPCBroker1.Param[0].Value := 'MY RPC’;

brkrRPCBroker1.Param[1].Ptype:= Literal;

brkrRPCBroker1.Param[1].Value := '1';

brkrRPCBroker1.Param[2].Ptype:= Reference;

brkrRPCBroker1.Param[2].Value := 'MY RPC PARAMETER';

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; code to store HANDLE returned in brkrRPCBroker1.Results[0]

The application will need to use XWB DEFERRED STATUS, XWB DEFERRED GETDATA, and XWB DEFERRED CLEAR to complete the transaction.


XWB DEFERRED STATUS

Example

Use this RPC to check for results of XWB DEFERRED RPC. Periodically, call this RPC and pass the HANDLE returned by XWB REMOTE RPC.

RETURN VALUE:	The return value is always an array. The first node of the array is equal to one of the following values:

•	"-1^Bad Handle" -- An invalid handle has been passed.

•	"0^New" -- The request has been sent via VistA HL7.

•	"0^Running" -- VistA HL7 indicates that the message is being processed.

•	"1^Done" -- RPC has completed and the data has been returned to the local VistA M Server. The data s not returned by this RPC. Use XWB REMOTE GETDATA to retrieve the data.


XWB DEFERRED STATUS Example

The following is example of the XWB DEFERRED STATUS RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED STATUS';

brkrRPCBroker1.Param[0].Value :='MYHANDLE';

brkrRPCBroker1.Param[0].PType := literal;

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; code to handle results of check


XWB DEFERRED GETDATA

Example

Use this RPC to retrieve the results of XWB DEFERRED RPC. Before calling this RPC, use XWB DEFERRED STATUS to ensure that the job has finished. When the results are available, call this RPC and pass the HANDLE returned by XWB DEFERRED RPC.

After the application is finished with the data on the VistA M Server, it should use XWB DEFERRED CLEAR to clear the ^XTMP global.

RETURN VALUE:	An array containing the data. In the case of an error condition the first node of the array is equal to a string with the syntax "-1^error text".


XWB DEFERRED GETDATA Example

The following is example of the XWB DEFERRED GETDATA RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED GETDATA';

brkrRPCBroker1.Param[0].Value :='MYHANDLE';

brkrRPCBroker1.Param[0].PType := literal;

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;

.; code to handle data


XWB DEFERRED CLEAR

Example

This RPC is used to clear the data created by a deferred RPC under the HANDLE in the ^XTMP global. Pass the HANDLE returned by XWB DEFERRED RPC.

RETURN VALUE:	An array. The first node in the array is equal to 1.


XWB DEFERRED CLEAR Example

The following is example of the XWB DEFERRED CLEAR RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED CLEAR';

brkrRPCBroker1.Param[0].Value :='MYHANDLE';

brkrRPCBroker1.Param[0].PType := literal;

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;


XWB DEFERRED CLEARALL

Example

This RPC is used to CLEAR ALL the data known to a remote RPC or deferred RPC job in the ^XTMP global. It makes use of the list in ^TMP("XWBHDL",$J,handle). Applications using XWB REMOTE RPC or the XWB DEFERRED RPC should use this RPC on application close to clear all known data associated with the job on the VistA M Server.

RETURN VALUE:	An array. The first node in the array is equal to 1.


XWB DEFERRED CLEARALL Example

The following is example of the XWB DEFERRED CLEARALL RPC:

brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED CLEAR';

try

    brkrRPCBroker1.Call;

except

  On EBrokerError do

    ShowMessage('Connection to server could not be established!');

end;


GetServerIP Function

Example

The GetServerIP function provides a means for determining the Internet Protocol (IP) address for a specified VistA M Server address. The value returned is a string containing the IP address, or if it could not be resolved, the string "Unknown!"

function GetServerIP(ServerName: string): string;


GetServerIP Example

The following is example of the GetServerIP function:

  //  include the unit RpcConf1 in the Uses clause

  //  An edit box on the form is assumed to be named edtIPAddress

  //  Another edit box (edtInput) is used to input a desired server name

uses RpcConf1;

procedure Tform1.Button1Click(Sender: TObject);

var

  ServerName: string;

begin

  ServerName := 'forum.med.va.gov';

  edtIPAddress.Text := GetServerIP(edtInput.Text);

    // For Forum.va.gov returns '152.128.1.25'

    // For garbage returns 'Unknown!'

end;


ChangeVerify Function

The ChangeVerify function can be used to provide the user with the ability to change his/her Verify code.

function ChangeVerify(RPCBroker: TRPCBroker): Boolean;

Argument:

RPCBroker -- The Broker instance for the account on which the Verify code is to be changed.

Result:

The return value indicates whether the user changed their Verify code (True) or not (False).


SilentChangeVerify Function

The SilentChangeVerify function can be used to change the Verify code for a user without any windows being displayed.

function SilentChangeVerify(RPCBroker: TRPCBroker; OldVerify, NewVerify1, NewVerify2: String; var Reason: String): Boolean;

Arguments:

RPCBroker -- The current instance of the Broker for the account for which the Verify code is to be changed.

OldVerify -- The string representing the current Verify code for the user.

NewVerify1 -- A string representing the new Verify code for the user.

NewVerify2 -- A second independent entry for the string representing the new Verify code for the user.

Reason -- A string that on return will contain the reason why the Verify code was not changed (if the result value is False).

Result:

The return value indicates whether the Verify code was successfully changed (True) or not (False). If the result is False, the reason for the failure will be in the Reason argument.


CheckCmdLine Function

With Patch XWB*1.1*13, the CheckCmdLine method was changed from a procedure to a function with a Boolean return value.

function CheckCmdLine(SLBroker: TRPCBroker): Boolean;

Argument:

SLBroker -- The instance of the Broker with which information on the command line should be used, and to be used for the connection, if a Silent Login is possible.

Result:

The return value indicates whether the information on the command line was sufficient to connect the RPCBroker instance to the specified Server/ListenerPort. If the value is True the connection has already been made. Otherwise, the Broker is not connected to the VistA M Server.


StartProgSLogin Method

The StartProgSLogin method can be used to initiate another program with information sufficient for a Silent Login, or it can be used to launch a standalone program that does not use a TRPCBroker connection. If the program is being used to launch another executable with information for a Silent Login, it is recommended that the CheckCmdLine function be used in the program being launched (since this function does use the command line information to make a Silent Login if possible).

procedure StartProgSLogin(const ProgLine: String; ConnectedBroker: TRPCBroker);

Argument:

ProgLine -- This is the command line that should be used as the basis for launching the executable. It would contain the executable (and path, if not in the working directory or in the system path) and any command line arguments desired. If the ConnectedBroker argument is not nil, then the VistA M Server address, ListenerPort, Division, and ApplicationToken will be added to the command line and the application launched.

ConnectedBroker -- This is the instance of the TRPCBroker that should be used to obtain an ApplicationToken for a Silent Login. The VistA M Server address and ListenerPort for this instance will be used as command line arguments for launching the application, so that it will make a connection to the same Server/ListenerPort combination. If the application to be launched is not related to the TRPCBroker, then this argument should be set to nil.

Example 1:

To launch a program, Sample1, with command line arguments xval=’MyData’ and yval=’YourData’, and connect with a Silent Login (which would be handled in Sample1.exe via the CheckCmdLine method):

MyCommand := ‘C:\Program Files\VISTA\Test1\Sample1.exe xval=MyData yval=YourData’;

StartProgSLogin(MyCommand, RPCBroker1);

This would result in the following command line being used to launch the application:

C:\Program Files\VISTA\Test1\Sample1.exe xval=MyData yval=YourData s=ServerName p=9200 d=Division h=AppHandleValue

Example 2:

To launch a program unrelated to TRPCBroker and VistA M Server connections (e.g., Microsoft Notepad), the command line as desired is used as the first argument, and the value nil is used as the second argument:

MyCommand := ‘Notepad logtable.txt’;

StartProgSLogin(MyCommand, nil);


Introduction to the RPC Broker DLL Interface
RPC Broker 32-bit DLL Interface Introduction

The functionality of the TRPCBroker component for Delphi is provided in a 32-bit Dynamic Link Library (DLL) interface, in BAPI32.DLL. This enables the use of any development product that can access Windows 32-bit DLLs to create applications that communicate with VistA M Servers through the RPC Broker.

In Delphi, you have direct access to the TRPCBroker component itself, and its properties and methods. In other development environments, you can only access the properties and methods of the TRPCBroker component through DLL functions. So to understand the DLL interface, you should understand how the TRPCBroker component is used in its native environment (Delphi).

DLL Exported Functions

The following special issues should be considered when accessing RPC Broker functionality through its DLL:

RPC Results from DLL Calls

GetServerInfo Function and the DLL

Header Files

Header files for using the DLL are provided for C (BAPI32.H), C++ (BAPI32.HPP), and Visual Basic (BAPI32.BAS).

Guidelines for Calling DLL from C++

Guidelines for Calling DLL from C

Guidelines for Calling DLL from Visual Basic

Sample DLL Application

The VB5EGCHO sample application, distributed with the Broker Development Kit (BDK), demonstrates use of the RPC Broker 32-bit DLL from Microsoft Visual Basic. The source code is located in the ..\BDK32\Samples\Vb5Egcho directory.


RPC Results through the DLL
RPC Results from DLL Calls

When executing an RPC on a VistA M Server, results from the RPC are returned as a text stream. This text stream may or may not have embedded <CR><LF> character combinations.

In Delphi, when you call an RPC using the TRPCBroker component directly, the text stream returned from an RPC is automatically parsed and returned in the TRPCBroker component's Results property, either in Results[0] or in multiple Results nodes. If there are no embedded <CR><LF> character combinations in the text stream, only Results[0] is used. If there are embedded <CR><LF> character combinations, results are placed into separate Results nodes based on the <CR><LF> delimiters.

When using the DLL interface, the return value is a text stream, but no processing of the text stream is performed for you. It is up to you to parse out what would have been individual Results nodes in Delphi, based on the presence of any <CR><LF> character combinations in the text stream.

You must create a character buffer large enough to receive the entire return value of an RPC.


GetServerInfo Function and the DLL

When you use the TRPCBroker component for Delphi, you are able to call the GetServerInfo function to retrieve the end-user workstation's server and port settings.

The functionality provided by GetServerInfo is not currently available through the RPC Broker 32-bit DLL interface. A future version of the RPC Broker will provide access to the GetServerInfo functionality for DLL users.

To work around this for now, when using the RPC Broker 32-bit DLL, you should prompt the user directly for the server and port to connect to.


DLL Function Reference
DLL Exported Functions

The following functions for TRPCBroker components are exported in BAPI32.DLL:

RPCBCall	Execute an RPC.

RPCBCreate	Create a TRPCBroker component.

RPCBCreateContext	Create context.

RPCBFree	Destroy a TRPCBroker component.

RPCBMultItemGet	Get value of a Mult item in a Param.

RPCBMultPropGet	Get value of a Mult property in a Param.

RPCBMultSet	Set a Mult item in a Param to a value.

RPCBMultSortedSet	Sorts a Mult Param property.

RPCBParamGet	Get the value of a Param.

RPCBParamSet	Set the value of a Param.

RPCBPropGet	Get the value of a TRPCBroker component property.

RPCBPropSet	Set the value of a TRPCBroker component property.


RPCBCall Function

Examples

Executes a remote procedure call, and fills the passed buffer with the data resulting from the call. This is equivalent to the TRPCBroker component's Call method.

Declarations

Delphi	procedure RPCBCall(const RPCBroker: TRPCBroker; CallResult: PChar);

C	char *(__stdcall *RPCBCall) (void *, char *);

C++	char * RPCBCall( char * s);

VB	Sub RPCBCall (ByVal intRPCBHandle As Long, ByVal strCallResult As String)

Parameter	Description

RPCBroker	Handle of the Broker component that contains the name of the remote procedure and all of the required parameters.

CallResult	An empty character buffer that the calling application must create (allocate memory for) before making this call. This buffer is filled with the result of the call.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the "RPC Limits" topic.


RPCBCall Examples

C

RPCBCall(RPCBroker, Value);

C++

// MyInstance is defined as an instance of the TRPCBroker.

MyInstance.RPCBCall( strbuffer);

Visual Basic

Call RPCBCall(intRPCBHandle, strBuffer)


RPCBCreate Function

Examples

Creates a new RPC Broker component for the application, which can then be used to connect to the VistA M Server and call remote procedures.

Declarations

Delphi	function  RPCBCreate: TRPCBroker;

C	void * (__stdcall *RPCBCreate)(void);

C++	N/A (encapsulated in TRPCBroker class definition)

VB	Function RPCBCreate () As Long

Return Value

A handle for the TRPCBroker component created.


RPCBCreate Examples

C

// Create the TRPCBroker component instance.

RPCBroker = RPCBCreate();

Visual Basic

intRPCBHandle = RPCBCreate()


RPCBCreateContext Function

Examples

This procedure calls the TRPCBroker component's CreateContext method to set up the environment on the VistA M Server for subsequent RPCs.

Declarations

Delphi	function  RPCBCreateContext(const RPCBroker: TRPCBroker; const Context: PChar): boolean;

C	bool (__stdcall *RPCBCreateContext) (void *, char *);

C++	bool RPCBCreateContext ( char * s);

VB	Function RPCBCreateContext (ByVal intRPCBHandle As Long, ByVal strContext As String) As Integer

Return Value

True/1 if context could be created; false/0 if context could not be created.

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

Context	Null-terminated string identifying the option on the VistA M Server for which subsequent RPCs are registered.


RPCBCreateContext Examples

C

// XWB EGCHO is a "B" (Broker) type option in the OPTION file.

result = RPCBCreateContext(RPCBroker, "XWB EGCHO");

C++

// XWB EGCHO is a "B" (Broker) type option in the OPTION file.

MyInstance.RPCBCreateContext("XWB EGCHO");

Visual Basic

intResult = RPCBCreateContext(intRPCBHandle, "MY APPLICATION")

'where MY APPLICATION is a "B" (Broker) type option in the Option file.


RPCBFree Function

Examples

Destroys the RPC Broker component and releases associated memory.

Declarations

Delphi	procedure RPCBFree(RPCBroker: TRPCBroker);

C	void (__stdcall *RPCBFree)(void *);

C++	N/A (encapsulated in TRPCBroker class definition)

VB	Sub RPCBFree (ByVal intRPCBHandle As Long)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component to destroy.


RPCBFree Examples

C

// Destroy the TRPCBroker component instance.

RPCBFree(RPCBroker);

Visual Basic

RPCBFree (intRPCBHandle)


RPCBMultItemGet Function

Examples

Returns a requested item in a TRPCBroker Param property's Mult property.

Declarations

Delphi	procedure RPCBMultItemGet (const RPCBroker: TRPCBroker; ParamIndex: integer; Subscript, Value: PChar);

C	void (__stdcall *RPCBMultItemGet) (void *, int, char *, char *);

C++	void RPCBMultItemGet ( int i, char * s, char * t);

VB	Sub RPCBMultItemGet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal strSubscript As String, ByVal strValue As String)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

ParamIndex	Integer index of the parameter that contains the Mult property.

Subscript	Null-terminated string identifying the Mult element to get.

Value	An empty buffer that the calling application must create (allocate memory for) before making this call. This buffer will be filled with value of the Mult property item.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the "RPC Limits" topic.


RPCBMultItemGet Examples

C

// The following corresponds to getting the value of PARAM[0].Mult["0"]

RPCBMultItemGet(RPCBroker, 0 , "0", Value);

C++

MyInstance.RPCBMultItemGet(0 , "0", Value);

Visual Basic

Call RPCBMultItemGet(intRPCBHandle, 0,  "0", strResult)


RPCBMultPropGet Function

Examples

Returns a selected property value of a TRPCBroker Param property's Mult property.

Declarations

Delphi	procedure RPCBMultPropGet(const RPCBroker: TRPCBroker; ParamIndex: integer; Prop,Value: PChar);

C	void (__stdcall *RPCBMultPropGet) (void *, int, char *, char *);

C++	void RPCBMultPropGet (int i , char * s, char * t);

VB	Sub RPCBMultPropGet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal strProp As String, ByRef strValue As String)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

ParamIndex	Integer index of the parameter that contains the Mult property.

Prop	Null-terminated string identifying the name of the TMult property to get.

Value	An empty buffer that the calling application must create (allocate memory for) before making this call. This buffer will be filled with value of the Mult property that is in the Prop.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the "RPC Limits" topic.


RPCBMultPropGet Examples

C

RPCBMultPropGet(RPCBroker, 0, "Count", Value);

C++

MyInstance.RPCBMultPropGet(0, "Count", Value);

Visual Basic

Call RPCBMultPropGet(intRPCBHandle, 0, "Count", strResult)


RPCBMultSet Function

Examples

Sets an item in a TRPCBroker Param property's Mult property to a value.

Declarations

Delphi	procedure RPCBMultSet(const RPCBroker: TRPCBroker; ParamIndex: integer; Subscript, Value: PChar);

C	void (__stdcall *RPCBMultSet) (void *, int, char *, char *);

C++	void RPCBMultSet ( int i, char * s, char * t);

VB	Sub RPCBMultSet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal strSubscript As String, ByVal strValue As String)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

ParamIndex	Integer index of the parameter that contains the Mult property.

Subscript	Null-terminated string of the Mult item to set.

Value	Null-terminated string containing the value that the Mult item should be set to.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the "RPC Limits" topic.


RPCBMultSet Examples

C

RPCBMultSet(RPCBroker, 0, "1", "12/19/97");

C++

MyInstance.RPCBMultSet(0, "1", "12/19/97");

Visual Basic

Call RPCBMultSet(intRPCBHandle, 0, "1", "12/19/97")


RPCBMultSortedSet Function

Examples

Sets the Sorted property of a Mult property. In essence, sorts and keeps the Mult property sorted or just leaves it in the order it is populated.

Declarations

Delphi	procedure RPCBMultSortedSet(const RPCBroker: TRPCBroker; ParamIndex: integer; Value: boolean);

C	void (__stdcall *RPCBMultSortedSet) (void *, int, bool);

C++	void RPCBMultSortedSet (int i, bool v);

VB	Sub RPCBMultSortedSet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal intValue As Integer)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

ParamIndex	Integer index of the parameter that contains the Mult property.

Value	Can be either a Boolean or, if the calling application language does not support Boolean type, can be an integer. True or 1 will sort the Mult and keep it sorted thereafter when other elements are added. False or 0 will not sort the Mult and the elements will be stored in the order they are added.


RPCBMultSortedSet Examples
RPCBMultSortedSet

C

RPCBMultSortedSet(RPCBroker, 0, 1);

C++

MyInstance.RPCBMultSortedSet(0, 1);

Visual Basic

Call RPCBMultPropGet(intRPCBHandle, 0, 1)


RPCBParamGet Function

Examples

Returns two values in two parameters: the value and the parameter type of a Param item.

You can compare the returned parameter type to the following enumerated values: literal, reference and list.

Declarations

Delphi	procedure RPCBParamGet(const RPCBroker: TRPCBroker; ParamIndex: integer; var ParamType: TParamType; var ParamValue: PChar);

C	void (__stdcall *RPCBParamGet) (void *, int, int, char *);

C++	void RPCBParamGet ( int i, int j, char * s);

VB	Sub RPCBParamGet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal intParTyp As Integer, ByVal intParVal As String)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

ParamIndex	Integer index of the parameter to get value of.

ParamType	This variable, after making the RPCBParamGet call, is filled with PType property of a Param[ParamIndex].

ParamValue	An empty buffer that you must create (allocate memory for) before making this call. This buffer, after making the RPCBParamGet call, is filled with Value of a Param[ParamIndex].

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the "RPC Limits" topic.


RPCBParamGet Examples

C

// PType and Value are variables to retrieve values into.

RPCBParamGet(RPCBroker, 0, PType, Value);

C++

// PType and Value are variables to retrieve values into.

MyInstance.RPCBParamGet(0, PType, Value);

Visual Basic

Call RPCBParamGet(intRPCBHandle, 0, PType, strResult)

' where PType and strResult are variables to retrieve values into


RPCBParamSet Function

Examples

Sets one Param item's Value and PType properties, in a single call.

Declarations

Delphi	procedure RPCBParamSet(const RPCBroker: TRPCBroker; const ParamIndex: integer; const ParamType: TParamType; const ParamValue: PChar);

C	void (__stdcall *RPCBParamSet) (void *, int, int, char *);

C++	void RPCBParamSet ( int i, int j, char * s);

VB	Sub RPCBParamSet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal intParTyp As Integer, ByVal intParVal As String)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

ParamIndex	Integer index of the parameter .

ParamType	Set to the parameter type for the parameter you are setting. The value should be one of the integer values that are valid as a PType: 0 (literal), 1 (reference) and 2 (list). You can use the enumerated values literal, reference and list, as declared in the C, C++ , or Visual Basic header file.

ParamValue	Null-terminated string containing the Value to set.

For information about the size of parameters and results that can be passed to and returned from the TRPCBroker component, please refer to the "RPC Limits" topic.


RPCBParamSet Examples

C

RPCBParamSet(RPCBroker, 0, reference, "DUZ");

C++

MyInstance.RPCBParamSet(0, reference, "DUZ");

Visual Basic

Call RPCBParamSet(intRPCBHandle, 0, literal, Text3.Text)


RPCBPropGet Function

Examples

Returns a requested property of a TRPCBroker component.

Declarations

Delphi	procedure RPCBPropGet(const RPCBroker: TRPCBroker; const Prop: PChar; {var} Value: PChar);

C	void (__stdcall *RPCBPropGet) (void *, char *, char *);

C++	void RPCBPropGet ( char * s, char * t);

VB	Sub RPCBPropGet (ByVal intRPCBHandle As Long, ByVal strProp As String, ByVal strValue As String)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

Prop	Null-terminated string of the property to get. Not case-sensitive. Valid properties to get are: ClearParameters, ClearResults, Connected, DebugMode, ListenerPort, RemoteProcedure, RPCTimeLimit, RPCVersion, and Server.

Value	An empty buffer that you must create (allocate memory for) before making this call. After this call, the buffer is filled with value of the property that is in the Prop. This procedure takes care of all the necessary type conversions. Boolean property values are returned as 1 (True) or 0 (False).


RPCBPropGet Examples

C

RPCBPropGet(RPCBroker, "Connected", Value);

C++

MyInstance.RPCBPropGet("Connected", Value);

Visual Basic

Call RPCBPropGet(intRPCBHandle, "Server", strResult)


RPCBPropSet Function

Examples

Sets a TRPCBroker property to some value.

Declarations

Delphi	procedure RPCBPropSet(const RPCBroker: TRPCBroker; Prop,Value: PChar);

C	void (__stdcall *RPCBPropSet) (void *, char *, char *);

C++	void RPCBPropSet ( char * s, char * t);

VB	Sub RPCBPropSet (ByVal intRPCBHandle As Long, ByVal strProp As String, ByVal strValue As String)

Parameter	Description

RPCBroker	Handle of the TRPCBroker component.

Prop	Null-terminated string of the property to set. Not case-sensitive. Valid properties to set are: ClearParameters, ClearResults, Connected, DebugMode, ListenerPort, RemoteProcedure, RPCTimeLimit, RPCVersion, and Server.

Value	Null-terminated string of the value to which the Prop property should be set. This procedure takes care of converting the passed in value to whatever type the property expects. For Boolean properties, pass in 1 (True) or 0 (False).


RPCBPropSet Examples

C

RPCBPropSet(RPCBroker, "ListenerPort", "9200");

C++

MyInstance.RPCBPropSet("ListenerPort", "9200");

Visual Basic

Call RPCBPropSet(intRPCBHandle, "Server", cboServer.Text)


C++ Guidelines
Guidelines for C++ Overview

The BAPI32.HPP header file defines a class "wrapper" around the RPC Broker 32-bit DLL, defining a TRPCBroker C++ class. Objects of this class include all functions exported in the DLL, as methods of the TRPCBroker C++ class.

TRPCBroker C++ class methods.

One feature of wrapping a class around the RPC Broker 32-bit DLL is that all the ordinary details of working with a DLL (loading the DLL, getting the addresses of the functions in the DLL, and freeing the DLL) are done within the class definition. When you initialize the class, all of the details of loading and unloading the detail (LoadLibrary, GetProcAddress, and FreeLibrary) are done for you.

To use objects of the class, simply initialize the class, and then create and destroy objects of the class.

To use the TRPCBroker C++ class that encapsulates BAPI32.DLL:

1.	Initialize the Class

2.	Create Broker Instances

3.	Connect to the Server

4.	Execute RPCs

5.	Destroy Broker Instances


C++ View: Methods
C++: TRPCBroker C++ Class Methods

The functions in the RPC Broker 32-bit DLL are encapsulated in the following TRPCBroker C++ class methods:

DLL Function	TRPCBroker C++ class method

RPCBCall	char * RPCBCall( char * s);

RPCBCreateContext	bool RPCBCreateContext ( char * s);

RPCBMultItemGet	void RPCBMultItemGet ( int i, char * s, char * t);

RPCBMultPropGet	void RPCBMultPropGet (void * ptr, int i , char * s, char * t);

RPCBMultSet	void RPCBMultSet ( int i, char * s, char * t);

RPCBMultSortedSet	void RPCBMultSortedSet (void * ptr, int i, bool v);

RPCBParamGet	void RPCBParamGet ( int i, int j, char * s);

RPCBParamSet	void RPCBParamSet ( int i, int j, char * s);

RPCBPropGet	void RPCBPropGet ( char * s, char * t);

RPCBPropSet	void RPCBPropSet ( char * s, char * t);


C++ View: Initializing RPCBroker Class
C++: Initialize the Class

The first step to using the RPC Broker 32-bit DLL in a C++ program is to load the DLL and get the process addresses for the exported functions.

To initialize access to the Broker DLL functions:

1.	Include bapi32.hpp in your program:

#include bapi32.hpp

This includes the TRPCBroker C++ class definition in your program. When you (later) create a TRPCBroker C++ class object in your program, the class definition takes care of loading the DLL if not already loaded, mapping the DLL functions if not already mapped, and creating the instance of the TRPCBroker component.


C++ View: Creating Broker Instances
C++: Create Broker Instances

To create instances of TRPCBroker C++ class objects in your C++ program:

1.	Create a variable of type TRPCBroker. This initializes the TRPCBroker class, creates a TRPCBroker C++ class object instance, and creates a TRPCBroker component:

// Initialize the TRPCBroker class.

TRPCBroker RPCInst;

The properties and methods of the created TRPCBroker component can be accessed through the TRPCBroker C++ class object.


C++ View: Connecting to the Server
C++: Connect to the Server

To connect to the VistA M Server from your C++ program:

1.	Set the server and port to connect to:

// Set the Server and Port properties to determine where to connect.

RPCInst.RPCBPropSet("Server", server);

RPCInst.RPCBPropSet("ListenerPort", "9200");

2.	Set the Connected property to true; this attempts a connection to the VistA M Server:

// Set the Connected property to True, to connect.

RPCInst.RPCBPropSet("Connected", "1");

3.	Check if you are still connected. If so, you can continue (your connection was made). If not, you should quit or branch accordingly:

// If still connected, can continue.

RPCInst.RPCBPropGet("Connected", Value);

if (atoi(Value) != 1) return false;

4.	Attempt to create context for your application's "B"-type option. If you can't create context, you should quit or branch accordingly. If RPCBCreateContext returns True, then you are ready to call all RPCs registered to your application's "B"-type option:

// Create Context for your application's option (in this case, XWB EGCHO).

result = RPCInst.RPCBCreateContext("XWB EGCHO");

return result;


C++ View: Executing RPCs
C++: Execute RPCs

If you can make a successful connection to the RPC Broker VistA M Server, and create an application context, you can execute any RPCs registered to your context.

To execute RPCs from your C++ program:

1.	Create a character buffer large enough to hold your RPC's return value:

char Value [1024];

2.	Set the RemoteProcedure property of the TRPCBroker component to the RPC to execute:

RPCInst.RPCBPropSet("RemoteProcedure","XWB GET VARIABLE VALUE");

3.	Set the Param values for any parameters needed by the RPC. In the following example, one TRPCBroker Param node is set (the equivalent of Param[0]):

a.	A value of 0 for parameter 1 denotes the integer index of the Param node being set (Param[0]).

b.	A value of reference for parameter 2 denotes the setting for the equivalent of Param[0].PType. This uses the enumerated values for PType declared in the header file.

c.	A value of "DUZ" for parameter 3 denotes that the equivalent of Param[0].Value is "DUZ":

RPCInst.RPCBParamSet(0, reference, "DUZ");

4.	Use the RPCBCall method to execute the RPC:

RPCInst.RPCBCall(Value);

The return value from the RPC is returned in the first parameter (in this case, the Value character buffer).


C++ View: Destroying Broker Instances
C++: Destroy Broker Instances

You do not need to do anything special to free up memory used by the TRPCBroker component instances and their companion TRPCBroker C++ class objects. They are automatically destroyed when your program terminates, just as normal variables are automatically destroyed.

Also, when your program terminates, the FreeLibrary Windows API call is automatically executed to unload the RPC Broker 32-bit DLL, so there is no need to do this manually.


C Guidelines
Guidelines for C Overview

The BAPI32.H header file defines the function prototypes for all functions exported in the RPC Broker 32-bit DLL.

DLL Exported Functions

To use the DLL Broker functions, using C, exported in BAPI32.DLL:

1.	Initialize -- LoadLibrary and GetProcAddress

2.	Create Broker Components

3.	Connect to the Server

4.	Execute RPCs

5.	Destroy Broker Components


C: Initialization - LoadLibrary and GetProcAddress
C: Initialize -- LoadLibrary and GetProcAddress

The first step to using the RPC Broker 32-bit DLL in a C program is to load the DLL and get the process addresses for the exported functions.

To initialize access to the Broker DLL functions:

1.	Use the Windows API LoadLibrary function to load the DLL.

HINSTANCE hLib = LoadLibrary("bapi32.dll");

if((unsigned)hLib<=HINSTANCE_ERROR)

{

   /* Add your error handler for case where library fails to load. */

   return 1;

}

2.	If you successfully load the DLL, map function pointers to the addresses of the functions in the DLL that you need for your application:

RPCBCreate = (void *(__stdcall*)()) GetProcAddress(hLib, "RPCBCreate");

RPCBFree = (void (__stdcall*)(void *)) GetProcAddress(hLib, "RPCBFree");

RPCBCall = (char *(__stdcall*)(void *, char *)) GetProcAddress(hLib, "RPCBCall");

RPCBCreateContext = (bool (__stdcall*)(void *, char *)) GetProcAddress(hLib, "RPCBCreateContext");

RPCBMultSet = (void (__stdcall*)(void *, int, char *, char *)) GetProcAddress(hLib, "RPCBMultSet");

RPCBParamGet = (void (__stdcall*)(void *, int, int, char *)) GetProcAddress(hLib, "RPCBParamGet");

RPCBParamSet = (void (__stdcall*)(void *, int, int, char *)) GetProcAddress(hLib, "RPCBParamSet");

RPCBPropGet = (void (__stdcall*)(void *, char *, char *)) GetProcAddress(hLib, "RPCBPropGet");

RPCBPropSet =(void (__stdcall*)(void *, char *, char *)) GetProcAddress(hLib, "RPCBPropSet");

//

// GetProcAddress, returns null on failure.

//

if( RPCBCreate == NULL || RPCBFree == NULL || RPCBCall == NULL || RPCBCreateContext == NULL

   || RPCBMultSet == NULL || RPCBParamGet == NULL || RPCBParamSet == NULL || RPCBPropGet == NULL

   || RPCBPropSet == NULL)

{

/* Add your error handler for cases where functions are not found. */

   return 1;

}

Now you can use functions exported in the DLL.


C: Creating Broker Components
C: Create Broker Components

To create TRPCBroker components in your C program:

1.	Create a pointer for the TRPCBroker component:

// Generic pointer for the TRPCBroker component instance.

void * RPCBroker;

2.	Call the RPCBCreate method to create a TRPCBroker component and return its address into the pointer you created:

// Create the TRPCBroker component instance.

RPCBroker = RPCBCreate();

Now you can use the pointer to the created Broker component to call its methods.


C: Connecting to the Server
C: Connect to the Server

To connect to the VistA M Server from your C program:

1.	Set the server and port to connect to:

// Set the Server and Port properties to determine where to connect.

RPCBPropSet(RPCBroker,"Server", "BROKERSERVER");

RPCBPropSet(RPCBroker, "ListenerPort", "9200");

2.	Set the Connected property to true; this attempts a connection to the VistA M Server:

// Set the Connected property to True, to connect.

RPCBPropSet(RPCBroker, "Connected", "1");

3.	Check if you are still connected. If so, you can continue (your connection was made). If not, you should quit or branch accordingly:

// If still connected, can continue.

RPCBPropGet(RPCBroker, "Connected", Value);

if (atoi(Value) != 1) return false;

4.	Attempt to create context for your application's "B"-type option. If you can't create context, you should quit or branch accordingly. If RPCBCreateContext returns True, then you are ready to call all RPCs registered to your application's "B"-type option:

// Create Context for your application's option (in this case, XWB EGCHO).

result = RPCBCreateContext(RPCBroker, "XWB EGCHO");

return result;


C: Executing RPCs
C: Execute RPCs

If you can make a successful connection to the RPC Broker VistA M Server, and create an application context, you can execute any RPCs registered to your context.

To execute RPCs from your C program:

1.	Create a character buffer large enough to hold your RPC's return value:

static char Value [1024];

2.	Set the RemoteProcedure property of the TRPCBroker component to the RPC to execute:

RPCBPropSet(RPCBroker, "RemoteProcedure","XWB GET VARIABLE VALUE");

3.	Set the Param values for any parameters needed by the RPC. In the following example, one TRPCBroker Param node is set (the equivalent of Param[0]):

a.	A value of 0 for parameter 2 denotes the integer index of the Param node being set (Param[0]).

b.	A value of reference for parameter 3 denotes the setting for the equivalent of Param[0].PType. This uses the enumerated values for PType declared in the header file.

c.	A value of "DUZ" for parameter 4 denotes that the equivalent of Param[0].Value is "DUZ":

RPCBParamSet(RPCBroker, 0, reference, "DUZ");

4.	Use the RPCBCall method to execute the RPC:

RPCBCall(RPCBroker, Value);

The return value from the RPC is returned in the second parameter (in this case, the Value character buffer).


C: Destroying Broker Components
C: Destroy Broker Components

When you are done using any TRPCBroker component, you should call its destroy method to free it from memory.

To destroy TRPCBroker components from your C program:

1.	Make sure the TRPCBroker component is not connected:

RPCBPropSet(RPCBroker, "Connected", "0");

2.	Call the RPCBFree method to destroy the object:

// Destroy the RPCBroker component instance.

RPCBFree(RPCBroker);

3.	When you have destroyed all TRPCBroker components, but before your application terminates, you should call the Windows API FreeLibrary function to unload the DLL:

FreeLibrary(hLib);


Visual Basic Guidelines
Guidelines for Visual Basic Overview

The BAPI32.BAS header file defines the function prototypes for all functions exported in the RPC Broker 32-bit DLL.

DLL Exported Functions

To use the DLL Broker functions, using Visual Basic, exported in BAPI32.DLL:

1.	Initialize

2.	Create Broker Components

3.	Connect to the Server

4.	Execute RPCs

5.	Destroy Broker Components

Sample DLL Application

The VB5EGCHO sample application, distributed with the Broker Development Kit, demonstrates use of the RPC Broker 32-bit DLL from Microsoft Visual Basic. The source code is located in the ..\BDK32\Samples\Vb5Egcho directory.


Visual Basic: Initialization
Visual Basic: Initialize

The first step to using the RPC Broker 32-bit DLL in a Visual Basic program is to load the DLL and get the process addresses for the exported functions.

To initialize access to the Broker DLL functions:

1.	Include BAPI32.BAS as a module in your Visual Basic program.

Visual Basic takes care of loading the DLL and mapping its functions.


Visual Basic: Creating Broker Components
Visual Basic: Create Broker Components

To create TRPCBroker components in your Visual Basic program:

1.	Create a variable to be a handle for the TRPCBroker component:

Public intRPCBHandle As Long

2.	Call the RPCBCreate method to create a TRPCBroker component and return its address into the variable you created:

intRPCBHandle = RPCBCreate()

Now you can use the handle to the created Broker component to call its methods.


Visual Basic: Connecting to the Server
Visual Basic: Connect to the Server

To connect to the VistA M Server from your Visual Basic program:

1.	Set the server and port to connect to:

Call RPCBPropSet(intRPCBHandle, "Server", "BROKERSERVER")

Call RPCBPropSet(intRPCBHandle, "ListenerPort", "9200")

2.	Set the Connected property to true; this attempts a connection to the VistA M Server:

Call RPCBPropSet(intRPCBHandle, "Connected", "1")

3.	Check if you are still connected. If so, you can continue (your connection was made). If not, you should quit or branch accordingly:

RPCBPropGet(intRPCBHandle, "Connected", strResult)

4.	Attempt to create context for your application's "B"-type option. If you can't create context, you should quit or branch accordingly. If RPCBCreateContext returns True, then you are ready to call all RPCs registered to your application's "B"-type option:

intResult = RPCBCreateContext(intRPCBHandle, "MY APPLICATION")


Visual Basic: Executing RPCs
Visual Basic: Execute RPCs

If you can make a successful connection to the RPC Broker VistA M Server, and create an application context, you can execute any RPCs registered to your context.

To execute RPCs from your Visual Basic program:

1.	Create a character buffer large enough to hold your RPC's return value:

Public strBuffer As String * 40000

2.	Set the RemoteProcedure property of the TRPCBroker component to the RPC to execute:

Call RPCBPropSet(intRPCBHandle, "RemoteProcedure", "XWB GET VARIABLE VALUE")

3.	Set the Param values for any parameters needed by the RPC. In the following example, one TRPCBroker Param node is set (the equivalent of Param[0]):

a.	A value of 0 for parameter 2 denotes the integer index of the Param node being set (Param[0]).

b.	A value of reference for parameter 3 denotes the setting for the equivalent of Param[0].PType. This uses the enumerated values for PType declared in the header file.

c.	A value of "DUZ" for parameter 4 denotes that the equivalent of Param[0].Value is "DUZ":

Call RPCBParamSet(intRPCBHandle, 0, reference, "DUZ");

4.	Use the RPCBCall method to execute the RPC:

Call RPCBCall(intRPCBHandle, strBuffer)

The return value from the RPC is returned in the second parameter (in this case, the Value character buffer).


Visual Basic: Destroying Broker Components
Visual Basic: Destroy Broker Components

When you are done using any TRPCBroker component, you should call its destroy method to free it from memory.

To destroy TRPCBroker components from your Visual Basic program:

1.	Make sure the TRPCBroker component is not connected:

Call RPCBPropSet(intRPCBHandle, "Connected", "0")

2.	Call the RPCBFree method to destroy the object:

RPCBFree(intRPCBHandle)

Visual Basic takes care of the details of unloading the DLL.


Debugging and Troubleshooting Overview

The Broker Development Kit (BDK) provides facilities for debugging and troubleshooting your VistA Graphical User Interface (GUI) applications.

How to Debug Your Application

Identifying the Listener Process

Identifying the Handler Process

RPC Error Trapping

Testing Your RPCBroker Connection

Memory Leaks

Client Timeout and Buffer Clearing

Broker Errors

For commonly asked questions, please refer to the RPC Broker FAQs at the following Web address:

http://vista.med.va.gov/broker/faqs.asp.


Debug
How to Debug Your Application

Beside the normal debugging facilities provided by Delphi, you can also invoke a debug mode so that you can step through your code on the client side and your RPC code on the VistA M Server side simultaneously.

To do this:

1.	On the client side, set the DebugMode property on the TRPCBroker component to True. When the TRPCBroker component connects with this property set to True, you will get a dialog window indicating your workstation IP address and the port number.

2.	At this point, switch over to the VistA M Server, and set any break points in the routines being called in order to help isolate the problem. Then issue the M debug command (e.g., ZDEBUG in DSM).

3.	Start the following VistA M Server process:

>D EN^XWBTCP

You will be prompted for the workstation IP address and the port number. After entering the information, switch over to the client application and click on the OK button of the dialog window.

4.	You can now step through the code on your client, and simultaneously step through the code on the VistA M Server side for any RPCs that your client calls.


ID Listener
Identifying the Listener Process on the Server

On DSM systems, where the Broker Listener is running, the Listener process name is RPCB_Port:NNNN, where NNNN is the port number being listened to. This should help quickly locate Listener processes when troubleshooting any connection problems.

Example

RPCB_Port:9200


ID Handler
Identifying the Handler Process on the Server

On DSM systems the name of a Handler process is ipXXX.XXX:NNNN, where XXX.XXX are the last two octets of the client IP address and NNNN is the port number.

Example:

ip1.205:3504


Error Handling
RPC Error Trapping

M errors on the VistA M Server that occur during RPC execution are trapped by the use of M and Kernel error handling. In addition, the M error message is sent back to the Delphi client. Delphi will raise an exception EBrokerError and a popup box displaying the error. At this point RPC execution terminates and the channel is closed.

In some instances, an application's RPC could get a memory allocation error on the VistA M Server (in DSM an "allocation failure"). Kernel does not trap these errors. However, these errors are trapped in the operating system's error trap. For example, if an RPC receives or generates an abundance of data in local memory, the symbol table could be depleted resulting in a memory allocation error. To diagnose this problem, users should check the operating system's error trap.


Testing Connection
Testing Your RPC Broker Connection

To test the RPC Broker connection from your workstation to the VistA M Server, use the RPC Broker Diagnostic Program (i.e., RPCTEST.EXE, located in the ..\Broker directory that was installed with the client workstation software).

For a complete description of the RPC Broker Diagnostic program, please refer to Chapter 4, "Troubleshooting," in the "RPC Broker Systems Manual."

For a demonstration/test using the Broker to connect to a VistA M Server, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.


Memory Leaks

A good indication of a memory leak is when a running program is steadily decreasing the free pool of memory. As it runs or every time the program is started and stopped, free memory is steadily decreased.

Specifically, a program requests some bytes of memory from the Microsoft Windows operating system (OS). When the OS provides it, it marks those bytes as taken. The free pool of memory (i.e., unmarked bytes) is decreased. When the program is finished with the memory, it should return the memory back to the OS by calling the FREE or DISPOSE functions. This allows the OS to clear the "taken" status of that memory, thereby replenishing its free pool. When a programmer forgets to free the memory after use or the program fails before it has a chance to execute the code that frees the memory, the memory is not reclaimed.

At all times, the program should keep track of which memory it's using. It does this by storing "Handles" (i.e., memory addresses of the beginning byte of each memory block). Later, when freeing memory, the Handle is used to indicate which memory address to free. If the variable that holds such a Handle is overwritten, there is no way to determine the Handle.

Nine out of ten times, memory leakage can be traced back to the application code that requests memory and then forgets to return it or cannot clean up after a crash.

As common with other professional-level languages (e.g., C/C++), Delphi has constructs that applications can use to: request memory, type cast it, and return it. This requires developers to use their best judgement on how to best work with the system memory.

Avoiding memory leaks (and the often-subtle coding errors that lead to them) is a challenge for Delphi programmers, especially for those whose main experience is working with M.

The insidious effect of these leaks (e.g., gobbling up 1K of memory each time that a certain event occurs) makes them difficult to detect with normal program testing. By "normal testing" we mean exercising all the possible paths through the code once, a difficult enough process in a Microsoft Windows environment. Often, these leaks will result in a symptom only under peculiar conditions (e.g., several other applications are running, reducing system resources) or only after extended use of the application (e.g., Do you notice that Microsoft Windows problems crop up in the afternoon, even though you were doing the same thing that morning?).

The symptom that we are most likely to hear about from users is the following:

"My computer was working fine until I installed the XYZ VistA software application on my PC. Now, it freezes up (gives me error message, says it's out of memory, etc.) all the time, even when I am not using the XYZ package. No, I can't duplicate it, it just happens!"

One of the reasons that there is an extensive market for automated testing tools for Microsoft Windows and client/server applications is that thorough testing is very difficult to do manually.

Fortunately, there are diagnostic products available for detecting code that will cause memory leaks. It will help programmers and code reviewers to find these leaks. Its use by people just starting out in Delphi programming will help them identify the situations that cause memory leaks. This can serve as a good learning experience for the new Delphi developer.

No application is immune from memory leaks, careful analysis of previous Broker code revealed some places where, under certain conditions, memory was not being released after it was used (i.e., memory leaks). These areas have been identified and corrected with this version of the Broker.


Buffer Clearing
Client Timeout and Buffer Clearing

If a remote procedure call (RPC) fails to successfully complete due to a timeout on the client, the buffer on the VistA M Server would contain data from the uncompleted call. Without special handling, this buffer on the server would be returned whenever the next RPC was executed.

The solution to this problem is:

1.	The RPCTimeLimit property on the TRPCBroker component on the client helps avoid the problem in the first place.

2.	In the event of a cancellation of a Network I/O operation, the Broker state on the client changes from NO FLUSH to FLUSH. When this state change occurs, the next RPC executed undergoes a READ operation prior to execution where any leftover incoming buffer is discarded. At the end of this operation, the Broker state on the client will return to NO FLUSH and the RPC will execute normally. While the FLUSH state exists, users may experience a delay while the corrupted RPC data is discarded. The delay will be proportional to the amount of data in the buffer.


Broker Errors
Broker Error Messages

The following list of errors/messages are Broker-specific and are not Winsock related:

Error/Message	Name	Number	Description
Insufficient Heap	XWB_NO_HEAP	20001	This is a general error condition indicating insufficient memory. It can occur when an application allocates memory for a variable. This error can occur for some of the following reasons: • Too many open applications. • Low physical memory. • Small virtual memory swap file (if dynamic, maybe low disk space). • User selecting too many records. Resolution: Common solutions to this error include the following: • Close some or all other applications. • Install more memory. • Increase the swap file size or, if dynamic, leave more free space on disk. • Try working with smaller data sets. • Reboot the workstation.
M Error - Use ^XTER	XWB_M_REJECT	20002	The VistA M Server side of the application errored out. The Kernel error trap has recorded the error. Resolution: Examine the Kernel error trap for more information and specific corrective actions.
Signon was not completed	XWB_BadSignOn	20004	This error indicates the user did not successfully signon. Resolution: Either the Access and Verify codes were incorrect or the user pressed the Cancel button on the VistA Sign-on window.
BrokerConnections list could not be created	XWB_BldConnectList	20005	This error is a specific symptom of a low memory condition. Resolution: Please refer to the "Insufficient Heap" error message for a more detailed explanation and corrective measures.
RpcVersion cannot be empty	XWB_NullRpcVer	20006	This error occurs when an RPC does not have an associated version number. Each RPC must have a version number. Resolution: Contact the developers responsible for the application software to take corrective action.
Remote procedure not registered to application	XWB_RpcNotReg	20201	This error indicates the application attempted to execute an RPC that was not, entered into the RPC multiple field in the REMOTE PROCEDURE file (#8994) for this application. Resolution: The developers responsible for the application should be contacted. As a "last resort" corrective measure, you may try to re-index the cross-reference on the RPC field (#.01) in the REMOTE PROCEDURE file (#8994) with the RPC field (#320) of the OPTION file (#19). Ideally, this should only be attempted during off or low system usage.
For common Winsock error messages, please refer to the RPC Broker "FAQ: Common Winsock API Error/Status Messages" at the following Web address:

http://vista.med.va.gov/broker/archive/docs/winsock.asp.


Tutorial: Introduction

The major functions of a TRPCBroker component in a Delphi-based application are to:

•	Connect to an RPC Broker VistA M Server system from a client.

•	Execute remote procedure calls (RPCs) on that system.

•	Return data results from RPC to the client.

This tutorial guides you through using a TRPCBroker component to perform each of these tasks, by having you create a Delphi-based application, step-by-step. This application will retrieve a list of terminal types from the VistA M Server, and display information about each terminal type.

After you have completed this tutorial, you should be able to:

•	Include a TRPCBroker component in a Delphi-based application.

•	Retrieve the end-user client workstation's designated VistA M Server and port to connect to.

•	Establish a connection through the RPC Broker component to an RPC Broker VistA M Server.

•	Create M routines that return data in the formats necessary to be called from RPCs.

•	Create RPCs.

•	Call RPCs from a Delphi-based application to retrieve data from a VistA M database.

•	Pass parameters from your Delphi-based application to RPCs.


Tutorial: Advanced Preparation

Namespacing of Routines and RPCs

Each tutorial user should choose a unique namespace beginning with Z, concatenated with two or three other letters, for example ZYXU. Use this namespace as the beginning of the names for all routines and RPCs that you create during this tutorial. Using your namespace protects the system you are using from having existing routines and RPCs overwritten. This namespace is referred to as Zxxx during the tutorial.

Tutorial Prerequisites

To use this tutorial:

•	You should already have M programming skills, and some familiarity with Delphi and Object Pascal.

•	You must have Delphi and the Broker Development Kit (BDK) installed on your client workstation.

•	Your client workstation must have network access to an M account that is running a RPC Broker server process.

•	You must have programmer access in this M account, and it should be a test account (not production). Also, you need the XUPROGMODE security key assigned to your user account.


Tutorial: Step 1—RPC Broker Component
Tutorial: Step 1 -- RPC Broker Component

The first step of this tutorial is to create a Delphi-based application that includes a TRPCBroker component.

To do this:

1.	In Delphi, create a new application. Delphi will create a blank form, named Form1.

2.	Set Form1's Caption property to Terminal Type Display.

3.	From the Kernel component palette tab, add a TRPCBroker component to your form. The instance of the component will automatically be named RPCBroker1. It should be renamed to brkrRPCBroker1.

In general the name of the component can be any meaningful name that begins with "brkr" to indicate a TRPCBroker component.

4.	Leave the default values for Server and ListenerPort as is (they are retrieved from your workstation's Registry). In the next section of the tutorial, you will add code to retrieve these values at run-time from the workstation's Registry.

5.	Set the ClearParameters and ClearResults properties to True if they are not set to True already. This ensures that each time a call to an RPC is made, the Results property is cleared beforehand, and the Param property is cleared afterwards.

Your form should look like:

The next tasks are to use the TRPCBroker component to retrieve the client workstation's RPC Broker server and port information (Step 2), and then to establish a connection through the TRPCBroker component to the VistA M Server (Step 3).


Tutorial: Step 2—Get Server/Port
Tutorial: Step 2 -- Get Server/Port

The TRPCBroker component you've added to your form is hard coded to access the Broker server and listener port that it picks up from your own (developer) workstation (by default, BROKERSERVER and 9200). Naturally you don't want this to be the only server and port that your application can connect to. To retrieve the end-user workstation's designated Broker server and port to connect to, as stored in their Registry, you can use the GetServerInfo function.

To retrieve the end-user workstation's designated server and port:

1.	Include the RPCConf1 unit in your Pascal file's uses clause. This is the unit that GetServerInfo is a part of.

2.	Double-click on a blank region of the form. This creates an event handler procedure, TForm1.FormCreate, in your Pascal source code.

3.	Add code to the FormCreate event handler that retrieves the correct server and port to connect to, using the GetServerInfo function. If mrCancel is returned, your code should quit. Otherwise, your code should then set brkrRPCBroker1's Server and ListenerPort properties to the returned values.

The code should look like the following:

procedure TForm1.FormCreate(Sender: TObject);

var   ServerStr: String;

        PortStr: String;

begin

  // Get the correct port and server from the Registry.

  if GetServerInfo(ServerStr,PortStr)<> mrCancel then

  begin

    brkrRPCBroker1.Server:=ServerStr;

    brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);

  {connectOK}

  end

  else

    Application.Terminate;

end;

Now that you have code to retrieve the appropriate RPC Broker server and listener port, in the next section of the tutorial (Step 3) your application will use the TRPCBroker component to establish a connection to the VistA M Server.


Tutorial: Step 3—Establish Broker Connection
Tutorial: Step 3 -- Establish Broker Connection

Now that your application can determine the appropriate RPC Broker server and port to connect to (Step 2), you can add code to establish a connection to the designated RPC Broker server from your application. The act of establishing a connection leads the user through signon. If signon succeeds, a connection is established.

To establish a connection from your application to a RPC Broker server:

1.	Add code to Form1's OnCreate event handler. The code should:

a.	Set brkrRPCBroker1's Connected property to True (inside of an exception handler try...except block). This will cause an attempt to connect to the RPC Broker server.

b.	Check if an EBrokerError exception is raised. If this happens, connection failed, and your code should inform the user of this and terminate the application.

The OnCreate event handler should now look like:

procedure TForm1.FormCreate(Sender: TObject);

var   ServerStr: String;

        PortStr: String;

begin

  // Get the correct port and server from the Registry.

  if GetServerInfo(ServerStr,PortStr)<> mrCancel then

  {connectOK begin}

  begin

    brkrRPCBroker1.Server:=ServerStr;

    brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);

    // Establish a connection to the RPC Broker server.

    try

      brkrRPCBroker1.Connected:=True;

    except

      On EBrokerError do

      {error begin}

      begin

        ShowMessage('Connection to server could not be established!');

        Application.Terminate;

      {error end}

      end;

    {try end}

    end;

  {connectOK end}

  end

  else

    Application.Terminate;

end;

Every call that invokes an RPC Broker server connection should be done in an "exception handler" try...except block, so that EBrokerError exceptions can be trapped.

2.	Save, compile and run your application. It should connect to the VistA M Server returned by the GetServerInfo function. You may be prompted to sign on with Access and Verify codes (unless Auto Signon is enabled, and you are already signed on). If you can connect successfully, your application will run (at this point, it is just a blank form). Otherwise, troubleshoot your RPC Broker connection until you can get your application to connect.

3.	If the server system defined in your Registry is not your development system (the one on which you will create RPCs for this application), update your Registry using the ServerList.EXE program so that your application will connect to the proper VistA M Server.

Now that your application can establish a connection to the end-user's server system, you can go about retrieving data from the VistA M Server.

In the next steps of the tutorial, you will create a custom RPC that retrieves a list of all of the terminal types on the VistA M Server and call that RPC from your application.


Tutorial: Step 4—Routine to List Terminal Types
Tutorial: Step 4 -- Routine to List Terminal Types

Now that your application uses an RPC Broker component to connect correctly to an RPC Broker server (Step 3), you are ready to create custom RPCs that your application can call. For the tutorial, you will create an RPC that retrieves the list of all terminal types from the RPC Broker server.

The first step in creating an RPC is to create the routine that the RPC will execute. You must create its input and output in a defined format that will be compatible with being executed as an RPC.

To do this:

1.	Choose the data format that your RPC should return. The type of data that you need to return to your client application determines the format of the routine that your RPC will call. There are five return value types for RPCs:

•	SINGLE VALUE

•	ARRAY

•	WORD PROCESSING

•	GLOBAL ARRAY

•	GLOBAL INSTANCE

Since the type of data the tutorial application would like returned is a list of terminal types, and that list could be quite long, use a return value type GLOBAL ARRAY for your RPC. For the routine called by your RPC, this means that:

•	Your routine should return a list of terminal types in a global. Each terminal type should be on an individual data node, subscripted numerically.

•	The return value of your routine (always returned in the routine's first parameter) should be the global reference of the data global, in closed root form. The data nodes should be one level descendant from the global reference.

2.	Create a routine, in the M account that your TRPCBroker component connects to, that outputs a list of terminal types in the format determined above. The format for each data node that is returned for a terminal type could be anything; for the sake of this application, set each data node to "ien^.01 field" for the terminal type in question. Store each node in ^TMP($J,"ZxxxTT",#).

ZxxxTT   ;ISC-SF/KC TUTORIAL RTN, BRK 1.1; 7/22/97

 ;;1.0;;

TERMLIST(GLOBREF) ; retrieve list of term types

 ; return list in ^TMP($J,"ZxxxTT")

 ; format of returned results: ien^.01 field

 N %                             ; scratch variable

 K ^TMP($J,"ZxxxTT")             ; clear data return area

 D LIST^DIC(3.2)                 ; retrieve list of termtype entries

 ; now set termtype entries into data global

 I '$D(DIERR) D

 .S %=0 F  S %=$O(^TMP("DILIST",$J,2,%)) Q:%=""  D

 ..S ^TMP($J,"ZxxxTT",%)=$G(^TMP("DILIST",$J,2,%))_"^"_$G(^TMP("DILIST",$J,1,%))

 K ^TMP("DILIST",$J)               ; clean up

 S GLOBREF=$NA(^TMP($J,"ZxxxTT"))   ; set return value

 Q

3.	Test the routine. Call it like the Broker would:

> D TERMLIST^ZxxxTT(.RESULT)

a.	Confirm that the return value is the correct global reference:

> W RESULT

  ^TMP(566363396,"ZxxxTT")

b.	Confirm that the data set into the global is in the following format:

^TMP(566347920,"ZxxxTT",1) = 1^C-3101

^TMP(566347920,"ZxxxTT",2) = 2^C-ADDS

^TMP(566347920,"ZxxxTT",3) = 3^C-ADM3

^TMP(566347920,"ZxxxTT",4) = 38^C-DATAMEDIA

^TMP(566347920,"ZxxxTT",5) = 106^C-DATATREE

^TMP(566347920,"ZxxxTT",6) = 4^C-DEC

^TMP(566347920,"ZxxxTT",7) = 5^C-DEC132

^TMP(566347920,"ZxxxTT",8) = 93^C-FALCO

^TMP(566347920,"ZxxxTT",9) = 6^C-H1500

^TMP(566347920,"ZxxxTT",10) = 103^C-HINQLINK

^TMP(566347920,"ZxxxTT",11) = 132^C-HINQLINK

^TMP(566347920,"ZxxxTT",12) = 63^C-HP110

^TMP(566347920,"ZxxxTT",13) = 34^C-HP2621

Once you've tested your routine, and confirmed that it returns data correctly, the next step (Step 5) is to create the RPC that will call this routine.


Tutorial: Step 5—RPC to List Terminal Types
Tutorial: Step 5 -- RPC to List Terminal Types

Now that you've created an RPC-compatible routine to list terminal types (Step 4), you can go ahead and create the RPC itself (the entry in the REMOTE PROCEDURE file) that will call the routine.

To create an RPC that uses the TERMLIST^ZxxxTT routine:

1.	Using VA FileMan, create a new RPC entry in the REMOTE PROCEDURE file. Set up the RPC as follows:

             NAME: ZxxxTT LIST

              TAG: TERMLIST

          ROUTINE: ZxxxTT

RETURN VALUE TYPE: GLOBAL ARRAY

     WORD WRAP ON: TRUE

      DESCRIPTION: Used in RPC Broker developer tutorial.

The RPC's RETURN VALUE TYPE is set to GLOBAL ARRAY. This means that the RPC expects a return value that is a global reference (with data stored at that global reference).

Also, the RPC's WORD WRAP ON is set to TRUE. This means each data node from the VistA M Server is returned as a single node in the Results property of your TRPCBroker component in Delphi. Otherwise, the data would be returned concatenated into a single node in the Results property.

In the next step of the tutorial (Step 6) you will call this RPC from the tutorial application, through its TRPCBroker component.


Tutorial: Step 6—Call ZxxxTT LIST RPC
Tutorial: Step 6 -- Call ZxxxTT LIST RPC

Now that you have created and tested the ZxxxTT LIST RPC on the VistA M Server, you can use your Delphi-based application's TRPCBroker component to call that RPC.

To call the ZxxxTT LIST RPC from your Delphi-based application to populate a list box:

1.	Place a TListBox component on your form. It should be automatically named ListBox1.

•	Size it so that it uses the full width of the form, and half of the form's height.

2.	Place a button beneath ListBox1.

•	Set its caption to 'Retrieve Terminal Types'.

•	Size the button so that it is larger than its caption.

3.	Double-click on the button. This creates an event handler procedure, TForm1.Button1Click, in your Pascal source code.

4.	In the TForm1.Button1Click event handler, add code to call the ZxxxTT LIST RPC and populate the list box with the retrieved list of terminal type entries. This code should:

a.	Set RCPBroker1's RemoteProcedure property to ZxxxTT LIST.

b.	Call brkrRPCBroker1's Call method (in a try...except exception handler block) to invoke that RPC.

c.	Retrieve results from brkrRPCBroker1's Results property, setting them one-by-one into the list box's Items property.

This code should look as follows:

Procedure TForm1.Button1Click(Sender: TObject);

var

   i: integer;

begin

  brkrRPCBroker1.RemoteProcedure:='ZxxxTT LIST';

  try

    {call begin}

    begin

      brkrRPCBroker1.Call;

      ListBox1.Clear;

      for i:=0 to (brkrRPCBroker1.Results.Count-1) do

        ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));

    {call end}

    end;

  except

    On EBrokerError do

      ShowMessage('A problem was encountered communicating with the server.');

  {try end}

  end;

end;

5.	Include the mfunstr unit in the Uses clause of your project's Pascal source file. This enables your application to use the piece function included in mfunstr.

6.	Your user account must have XUPROGMODE key assigned. This allows your application to execute any RPC, without the RPC being registered. Later in the tutorial you will register your RPCs.

7.	Now run your application, and press the Retrieve Terminal Types button. It should retrieve and display terminal type entries, and appear as follows:

Now that you can retrieve a list of terminal type entries, the next logical task is to retrieve a particular entry when a user selects that entry in the list box.


Tutorial: Step 7—Associating IENs
Tutorial: Step 7 -- Associating IENs

When a user selects a terminal type entry in the list box, a typical action would be to retrieve the corresponding record and display its fields. The key to retrieving any VA FileMan record is knowing the IEN of the record. Thus, when a user selects an entry in the list box, you need to know the IEN of the corresponding VA FileMan entry. However, the list box items themselves only contain the name of each entry, not the IEN.

The subscripting of items in the list box still matches the original subscripting of items returned in brkrRPCBroker1's Results property, as performed by the following code in Button1Click event handler:

for i:=0 to (brkrRPCBroker1.Results.Count-1) do

  ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));

If no further calls to brkrRPCBroker1 were made, you could simply refer back to brkrRPCBroker1's Results[x] item to obtain the matching IEN of a list boxes' Items[x] item. But, since brkrRPCBroker1 will be used again, the Results property will be cleared. So the results must be saved off in another location, if you want to be able to refer to them after other Broker calls are made.

To save off the Results to another location:

1.	Create a variable named TermTypeList, of type TStrings. This is where brkrRPCBroker1.Results will be saved. Create the variable in the section of code where TForm1 is defined as a class:

type

  TForm1 = class(TForm)

    brkrRPCBroker1: TRPCBroker;

    ListBox1: TListBox;

    Button1: TButton;

    procedure FormCreate(Sender: TObject);

    procedure Button1Click(Sender: TObject);

  private

    {Private declarations}

  public

    {Public declarations}

// Added declaration of TermTypeList.

    TermTypeList: TStringList;

  end;

2.	In Form1's OnCreate event handler, call the Create method to initialize the TermTypeList. Do this in the first line of code of the event handler:

TermTypeList:=TStringList.Create;

3.	Create an event handler for Form1's OnDestroy event (select Form1, go to the Events tab of the Object Inspector, and double-click on the right-hand column for the OnDestroy event). In that event handler, add one line of code to call the Free method for TermTypeList. This frees the memory used by the list:

procedure TForm1.FormDestroy(Sender: TObject);

begin

  TermTypeList.Free;

end;

4.	In Button1's OnClick event handler, add a line of code to populate TermTypeList with the list of terminal types returned in brkrRPCBroker1's Results property. This code will use the Add method of TStrings sequentially so that the subscripting of TermTypeList will match the subscripting of Results. The code for that event handler should then look like:

procedure TForm1.Button1Click(Sender: TObject);

var

  i: integer;

begin

  brkrRPCBroker1.RemoteProcedure:='Zxxx LIST';

  try

   {call begin}

    begin

      brkrRPCBroker1.Call;

      for i:=0 to (brkrRPCBroker1.Results.Count-1) do begin {copy begin}

        ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));

        // Added line.

        TermTypeList.Add(brkrRPCBroker1.Results[i]);

      {copy end}

      end;

    {call end}

    end;

  except

    On EBrokerError do

      ShowMessage('A problem was encountered communicating with the server.');

  {try end}

  end;

end;

5.	Then, to determine (and display) the IEN of the corresponding terminal type when a user selects an item in the list box:

a.	Create an OnClick event handler for ListBox1 by double-clicking on the list box.

b.	Add code to the new event handler that checks if an item is selected. If an item is selected in the list box, display the first piece of the corresponding item saved off in the TermTypeList array (the index subscripts of TermTypeList and of the list box match each other). This is the IEN of the corresponding VA FileMan entry.

procedure TForm1.ListBox1Click(Sender: TObject);

var

  ien: String;

begin

  if (ListBox1.ItemIndex <> -1) then

  {displayitem begin}

  begin

    ien:=piece(TermTypeList[ListBox1.ItemIndex],'^',1);

    ShowMessage(ien);

  {displayitem end}

  end;

end;

6.	Compile and run your application. When you click on an item in the list box, the IEN corresponding to that item should be displayed in a pop-up message window.

Now that you can determine the IEN of any entry the user selects in the list box, you can retrieve and display the corresponding VA FileMan record for any selected list box entry.


Tutorial: Step 8—Routine to Retrieve Terminal Types
Tutorial: Step 8 -- Routine to Retrieve Terminal Types

Now that you have associated an IEN for each record displayed in the list box (Step 7), you can use that IEN to display fields from any terminal type entry in the list box that a user selects. To retrieve the fields for any selected terminal type entry, you should create a second custom RPC. This RPC will need to take an input parameter, the record IEN, to know which record to retrieve.

To create an RPC routine to retrieve individual terminal type records:

1.	Choose the data format that your RPC should return. The type of data that you need to return to your client application determines the format of the routine that your RPC will call. In this case, the RPC should, given an IEN, return fields .01, 1, 2, 3, 4, 6, and 7 (Name, Right Margin, Form Feed, Page Length, Back Space, Open Execute, and Close Execute).

Since this information is constrained and small, a return type of ARRAY would be suitable for this RPC. The return format of the array is arbitrary; for the sake of this application, the routine should return fields .01, 1, 2, 3, and 4 in node 0; field 6 (a 245-character field) in node 1; and field 7 (also a 245-character field) in node 2. This array must be returned in the first parameter to the routine.

2.	The routine for this RPC also needs to be able to take an IEN as an input parameter. Any additional input parameters such as one for the IEN must follow the required input parameter in which results are returned.

3.	Add a second subroutine to the ZxxxTT routine for the second RPC, similar to the following. This subroutine uses an IEN to retrieve fields for a particular terminal type. It then sets three result nodes, each containing a specified set of fields for the record corresponding to the IEN parameter.

TERMENT(RESULT,IEN) ; retrieve a string of fields for a termtype

 ; format of results (by field number):

 ; RESULT(0)=.01^1^2^3^4

 ; RESULT(1)=6

 ; RESULT(2)=7

 ;

 N I,ARRAY S IEN=IEN_",",RESULT(1)=""

 D GETS^DIQ(3.2,IEN,".01;1;2;3;4;6;7","","ARRAY")

 S RESULT(0)="" I '$D(DIERR) D

 .F I=.01,1,2,3,4 D

 ..S RESULT(0)=RESULT(0)_ARRAY(3.2,IEN,I)_"^"

 .S RESULT(1)=ARRAY(3.2,IEN,6)

 .S RESULT(2)=ARRAY(3.2,IEN,7)

 Q

4.	Test the routine. Call it like the Broker would:

>D TERMENT^ZxxxTT(.ARRAY,103)

Confirm that the return array contains the specified fields in the following nodes:

ARRAY(0)=C-HINQLINK^80^#,$C(27,91,50,74,27,91,72)^24^$C(8)^

ARRAY(1)=U $I:(0:255::255:512)

ARRAY(2)=U $I:(:::::512) C $I

Once you've tested your routine, and confirmed that it returns data correctly, the next step (Step 9) is to create the RPC that will call this routine.


Tutorial: Step 9—RPC to Retrieve Terminal Types
Tutorial: Step 9 -- RPC to Retrieve Terminal Types

Now that you've created an RPC-compatible routine to retrieve fields from a terminal type record (Step 8), you can go ahead and create the RPC itself.

To create an RPC that uses the TERMENT^ZxxxTT routine:

1.	Using VA FileMan, create a new RPC entry in the REMOTE PROCEDURE file. Set up the RPC as follows:

             NAME: ZxxxTT RETRIEVE

              TAG: TERMENT

          ROUTINE: ZxxxTT

RETURN VALUE TYPE: ARRAY

      DESCRIPTION: Used in RPC Broker tutorial.

  INPUT PARAMETER: IEN    PARAMETER TYPE: LITERAL

The RPC's RETURN VALUE TYPE is set to ARRAY. This means that the RPC expects a return value that contains results nodes, each subscripted only at the first subscript level.

The WORD WRAP ON setting does not affect RPCs whose RETURN VALUE TYPE is ARRAY.

The additional input parameter needed to pass in a record IEN is documented in the INPUT PARAMETER multiple. Its parameter type is LITERAL, which is appropriate when being passed the numeric value of an IEN.

This RPC can now be called from a Delphi-based application, through the TRPCBroker component.


Tutorial: Step 10—Call Zxxx RETRIEVE RPC
Tutorial: Step 10 -- Call Zxxx RETRIEVE RPC

When a user selects a terminal type entry in the list box, the OnClick event is triggered. The new ZxxxTT RETRIEVE RPC can be called from that OnClick event, as a replacement for the code there that simply displays the IEN of any selected record.

To use the ZxxxTT RETRIEVE RPC to display fields from a selected terminal type:

1.	Create labels and edit boxes for each of the fields the RPC returns from the Terminal type file:

Terminal Type Field:	Add a TEdit component named:	Add a Label with the Caption:

.01	Name	Name

1	RightMargin	Right Margin:

2	FormFeed	Form Feed:

3	PageLength	Page Length:

4	BackSpace	Back Space:

6	OpenExecute	Open Execute:

7	CloseExecute	Close Execute:

2.	Update ListBox1's OnClick event handler. Add code so that when the user clicks on an entry in the list box, your application will call the ZxxxTT RETRIEVE RPC to retrieve fields for the corresponding terminal type, and display those fields in the set of TEdit controls on your form. This code should:

a.	Set RCPBroker1's RemoteProcedure property to ZxxxTT RETRIEVE.

b.	Pass the IEN of the selected terminal type to the RPC, using the TRPCBroker's runtime Param property. Pass the IEN in the Value property (i.e., brkrRPCBroker1.Param[0].Value).

c.	The PType for the IEN parameter should be passed in brkrRPCBroker1.Param[0].PType. Possible types are literal, reference and list. In this case, to pass in an IEN, the appropriate PType is literal.

d.	Call brkrRPCBroker1's Call method (in a try...except exception handler block) to invoke the ZxxxTT RETRIEVE RPC.

e.	Set the appropriate pieces from each of the three Results nodes into each of the TEdit boxes corresponding to each returned field.

The code for the OnClick event handler should look like the following:

procedure TForm1.ListBox1Click(Sender: TObject);

var

  ien: String;

begin

  if (ListBox1.ItemIndex <> -1) then

  {displayitem begin}

  begin

    ien:=piece(TermTypeList[ListBox1.ItemIndex],'^',1);

    brkrRPCBroker1.RemoteProcedure:='ZxxxTT RETRIEVE';

    brkrRPCBroker1.Param[0].Value := ien;

    brkrRPCBroker1.Param[0].PType := literal;

    try

      {call code begin}

      begin

        brkrRPCBroker1.Call;

        Name.Text:=piece(brkrRPCBroker1.Results[0],'^',1);

        RightMargin.Text:=piece(brkrRPCBroker1.Results[0],'^',2);

        FormFeed.Text:=piece(brkrRPCBroker1.Results[0],'^',3);

        PageLength.Text:=piece(brkrRPCBroker1.Results[0],'^',4);

        BackSpace.Text:=piece(brkrRPCBroker1.Results[0],'^',5);

        OpenExecute.Text:=brkrRPCBroker1.Results[1];

        CloseExecute.Text:=brkrRPCBroker1.Results[2];

      {call code end}

      end;

    except

    On EBrokerError do

      ShowMessage('A problem was encountered communicating with the server.');

    {try end}

    end;

  {displayitem end}

  end;

end;

3.	Compile and run your application. When you click on an entry in the list box now, the corresponding fields should be retrieved and displayed in the set of edit boxes on your form.


Tutorial: Register RPCs

Up until now, it has been assumed that the only user of your application is you, and that you have programmer access and the XUPROGMODE key in the account where your RPCs are accessed.

Under any other circumstance, any RPCs that your application uses must be registered for use by your application on the host system. Registration authorizes the RPC(s) for use by your client based on user privileges.

To register the RPCs used by the tutorial application:

1.	Create an option of type "B" (Broker). For example, create an option called ZxxxTT TERMTYPE for the tutorial application.

2.	In the "B"-type option's RPC multiple, make one entry for each RPC your application calls. In the case of this tutorial, there should be two entries: one for ZxxxTT LIST and one for ZxxxTT RETRIEVE.

3.	Follow the steps in How to Register an RPC to create an application context, using the ZxxxTT TERMTYPE option. Essentially, add a line of code that calls the CreateContext function, and terminates the application if False is returned. The code for Form1's OnCreate event should now look like:

procedure TForm1.FormCreate(Sender: TObject);

var   ServerStr: String;

        PortStr: String;

begin

  TermTypeList:=TStringList.Create;

  // Get the correct port and server from Registry.

  if GetServerInfo(ServerStr,PortStr)<> mrCancel then

  {connectOK begin}

  begin

    brkrRPCBroker1.Server:=ServerStr;

    brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);

    // Establish a connection to the RPC Broker server.

    try

      brkrRPCBroker1.Connected:=True;

      // Check security.

      if not brkrRPCBroker1.CreateContext('ZxxxTT TERMTYPE') then

        Application.Terminate;

    except

      On EBrokerError do

     {error begin}

      begin

        ShowMessage('Connection to server could not be established!');

        Application.Terminate;

      {error end}

      end;

    {try end}

    end;

  {connectOK end}

  end

  else

    Application.Terminate;

end;

4.	Compile and run your application. Try running it both with and without the XUPROGMODE security key assigned to you. Without XUPROGMODE, you won't be able to run your application unless the ZxxxTT TERMTYPE option is assigned to your menu tree.


Tutorial: FileMan Delphi Components (FMDC)

Congratulations! You have now created a sample application that performs entry lookup, and retrieves fields from any record selected by the end-user. You are now ready to create your own Delphi-based applications using the RPC Broker.

If your application needs to perform database tasks with VA FileMan on a VistA M Server, you should consider using the FileMan Delphi Components (FMDC). These components automate the major tasks of working with database records through Delphi. Among the functions they provide are:

•	Automated entry retrieval into a set of controls

•	Automated online help for database fields

•	Automated validation of user data entry

•	Automated filing of changed data

•	IEN tracking in all controls

•	Automated DBS error tracking on the Delphi client

•	Generic lookup dialog

•	Record locking

•	Record deletion

If you need to do more than the most simple database tasks in your Delphi-based applications, the FileMan Delphi Components (FMDC) encapsulate most of the coding needed to retrieve, validate, and file VA FileMan data.

For more information on the VA FileMan Delphi Components (FMDC), please refer to the following Web address:

http://vista.med.va.gov/fmdc/index.asp


Tutorial: Source Code
Tutorial Source Code

unit tut1;

interface

uses

  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Trpcb, RPCConf1, StdCtrls, MFunStr;

type

  TForm1 = class(TForm)

    brkrRPCBroker1: TRPCBroker;

    ListBox1: TListBox;

    Button1: TButton;

    Name: TEdit;

    RightMargin: TEdit;

    FormFeed: TEdit;

    OpenExecute: TEdit;

    CloseExecute: TEdit;

    PageLength: TEdit;

    BackSpace: TEdit;

    Label1: TLabel;

    Label2: TLabel;

    Label3: TLabel;

    Label4: TLabel;

    Label5: TLabel;

    Label6: TLabel;

    Label7: TLabel;

    procedure FormCreate(Sender: TObject);

    procedure Button1Click(Sender: TObject);

    procedure ListBox1Click(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

  private

    {Private declarations}

  public

    {Public declarations}

     // Added declaration of TermTypeList.

     TermTypeList: TStrings;

  end;

var

  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);

var   ServerStr: String;

        PortStr: String;

begin

  TermTypeList:=TStringList.Create;

  // Get the correct port and server from the Registry.

  if GetServerInfo(ServerStr,PortStr)<> mrCancel then

  {connectOK begin}

  begin

    brkrRPCBroker1.Server:=ServerStr;

    brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);

    // Establish a connection to the RPC Broker server.

    try

      brkrRPCBroker1.Connected:=True;

      if not brkrRPCBroker1.CreateContext('ZxxxTT TERMTYPE') then

        Application.Terminate;

    except

      On EBrokerError do

      {error begin}

      begin

        ShowMessage('Connection to server could not be established!');

        Application.Terminate;

      {error end}

      end;

    {try end}

    end;

  {connectOK end}

  end

  else

    Application.Terminate;

end;

procedure TForm1.Button1Click(Sender: TObject);

var

  i: integer;

  brkrRPCBroker1.RemoteProcedure:='ZxxxTT LIST';

  try

    {call begin}

    begin

      brkrRPCBroker1.Call;

   for i:=0 to (brkrRPCBroker1.Results.Count-1) do begin {copy begin}

     ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));

     // Added line.

     TermTypeList.Add(brkrRPCBroker1.Results[i]);

   {copy end}

   end;

    {call end}

    end;

  except

    On EBrokerError do

      ShowMessage('A problem was encountered communicating with the server.');

  {try end}

begin

  end;

end;

procedure TForm1.ListBox1Click(Sender: TObject);

var

  ien: String;

begin

  if (ListBox1.ItemIndex <> -1) then

  {displayitem begin}

  begin

    ien:=piece(TermTypeList[ListBox1.ItemIndex],'^',1);

    brkrRPCBroker1.RemoteProcedure:='ZxxxTT RETRIEVE';

    brkrRPCBroker1.Param[0].Value := ien;

    brkrRPCBroker1.Param[0].PType := literal;

    try

      {call code begin}

      begin

        brkrRPCBroker1.Call;

        Name.Text:=piece(brkrRPCBroker1.Results[0],'^',1);

        RightMargin.Text:=piece(brkrRPCBroker1.Results[0],'^',2);

        FormFeed.Text:=piece(brkrRPCBroker1.Results[0],'^',3);

        PageLength.Text:=piece(brkrRPCBroker1.Results[0],'^',4);

        BackSpace.Text:=piece(brkrRPCBroker1.Results[0],'^',5);

        OpenExecute.Text:=brkrRPCBroker1.Results[1];

        CloseExecute.Text:=brkrRPCBroker1.Results[2];

      {call code end}

      end;

    except

    On EBrokerError do

      ShowMessage('A problem was encountered communicating with the server.');

    {try end}

    end;

  {displayitem end}

  end;

end;

procedure TForm1.FormDestroy(Sender: TObject);

begin

 TermTypeList.Free;

end;

end.


RPC Broker Programmer Preferences

You can use the RPC Broker Programmer Preferences application (i.e., BrokerProgPref.EXE) to define certain default property values for the TRPCBroker component. When you add a TRPCBroker component to a Delphi-based application, the settings you define in the Programmer Preferences Editor are used as the default property values.

Click on various parts of the RPC Broker Programmer Preferences screen below for information on that setting.

(If you are visually challenged or unable to access the information available on this client-side image map, please refer to the "Programmer Preferences Dialogue Box Description" topic.)

You may want to make an entry for BrokerProgPref.EXE in Delphi's Tools Menu, to make it easily accessible from within Delphi.

The BrokerProgPref.EXE is located in the ..\BDK32 directory.


ClearParameters  (Programmer Preferences)
ClearParameters

If checked, automatically sets the ClearParameters design-time property of a TRPCBroker component to True when you add one to a form.


ClearResults  (Programmer Preferences)
ClearResults

If checked, automatically sets the ClearResults design-time property of a TRPCBroker component to True when you add one to a form.


ListenerPort  (Programmer Preferences)
ListenerPort

Sets the ListenerPort design-time property of a TRPCBroker component to the specified value when you add one to a form.


Server  (Programmer Preferences)
Server

Sets the Server design-time property of a TRPCBroker component to the specified value when you add one to a form.


Connect in Delphi IDE (Programmer Preferences)
Connect in Delphi IDE

Enables or disables the connection to the VistA M Server from within the Borland Integrated Development Environment (IDE). Disabling this is useful when you are developing in an environment without a connection to an VistA M Server, because an attempt is made to connect to the server (if enabled) when certain TRPCBroker component properties are edited.


Defaults  (Programmer Preferences)
Defaults

Pressing Defaults returns the programmer settings to their default values.


Programmer Preferences Dialogue Box Description

The RPC Broker Programmer Preferences application presents a GUI dialogue box that allows developers to set default values for certain RPC Broker component properties and default settings for RPC Broker development. You can set any of the following:

•	ClearParameters (check box) -- If checked, automatically sets the ClearParameters design-time property of a TRPCBroker component to True when you add one to a form.

•	ClearResults (check box) -- If checked, automatically sets the ClearResults design-time property to of a TRPCBroker component to True when you add one to a form.

•	ListenerPort (text box) -- Sets the ListenerPort design-time property of a TRPCBroker component to the specified value when you add one to a form.

•	Server (text box) -- Sets the Server design-time property of a TRPCBroker component to the specified value when you add one to a form.

•	Connect in Delphi IDE (check box) -- Enables or disables the connection to the VistA M Server from within the Borland Integrated Development Environment (IDE). Disabling this is useful when you are developing in an environment without a connection to a VistA M Server, because an attempt is made to connect to the server (if enabled) when certain TRPCBroker component properties are edited.

•	Defaults (button) -- Pressing Defaults returns the programmer settings to their default values.