TUXEDO System/WS For WINDOWS

What this Chapter is About

This chapter describes the use of the TUXEDO System/T /Workstation for Microsoft Windows, Version 3.0 and later.

This instantiation offers significant benefits to the application developers:

The major sections in this chapter cover:

Definitions of Terms, Acronyms and Abbreviations

System/T terms are defined in the BEA TUXEDO Glossary but we have extracted terms specific to this feature:

Dynamic Link Libraries (DLL)
A DLL is a collection of functions grouped into a load module that is dynamically linked with an executable program at run time. It is similar to a shared object under the UNIX operating system. The Microsoft Windows operating environment makes extensive use of this feature. Most software products for Windows provide a DLL interface.
Ordinal Export Numbers
An ordinal export number is a number assigned in a module definition file, by which a function in a DLL may be referenced. Some software packages reference DLL functions by name, while others (for example, SQLWindows) reference DLL function entry points by numbers only.
Import libraries
An import library is a collection of stub function names associated with a DLL. To link edit an application object calling a DLL routine, the linker needs a stub that defines where the subroutine exists.
Module Definition File
This file defines the characteristics of an executable and is used at link time. For a DLL this file details the exported functions along with their import numbers that can be called from the DLL and other imported functions which the DLL will call.

Prerequisites

Hardware

The TUXEDO System/Workstation for Windows runs on Intel 80286 processors and above.

The machine on which the /Workstation is installed runs as a remote machine to a UNIX server.

Software

Workstation for Windows runs under the Windows Version 3.0 or later operating system.

In Windows while using TCP/IP any Windows Sockets Compliant TCP/IP stack can be used. The Windows DLL has been tested with the NOVELL LAN WorkPlace for MS-DOS using the Windows Sockets interface.

In Windows 95 the native TCP/IP stack is used.

The UNIX server machine must have the TUXEDO System/T and the native-side /Workstation installed.

Programming Considerations with the Windows DLL

This section covers items specific to writing and building TUXEDO System/T client programs to run under Microsoft Windows. They are intended to supplement the material presented in the BEA TUXEDO Programmer's Guide.

For information on defining application-specific buffers types for the Windows environment, please see the chapter "Buffers" in the BEA TUXEDO Administrator's Guide and the tuxtypes(5) manual page.

Our assumption is that readers of this section either have experience in writing Windows programs or have access to tutorial material on that subject. Our discussion is limited to a description of how you go about putting System/T functions into Windows modules.

Writing Client Programs

The ATMI and FML calls used in Windows client programs are much the same as described in the BEA TUXEDO Programmer's Guide. They must, however, be incorporated into Windows modules. The following things work slightly differently than they do in the UNIX environment:

Global Variables
The error global variables are not available in the way they normally are; they are defined as macros in the .h files. To make them available in client programs:

for tperrno or tpurcode -- #include "atmi.h"
for Ferror -- #include "fml.h"
for Uunixerr -- #include "Uunix.h"
for proc_name -- #include "userlog.h"

See Figure 2 for an example.

tpsetunsol
Use MakeProcInstance() to create a "thunk" pointer. Both the .DEF file and the .C file must include the definition. This step is required under Windows 3.x. See Figure 4 for an example.
Buffer Size
On DOS and WINDOWS workstations, message buffer sizes are limited to 64K less the size of the message header (currently under 400 bytes).
Environment
Once set, the environment in MS Windows cannot be changed. Because of this the environment will be handled locally within the DLL. The functions tuxgetenv(3c) and tuxputenv(3c) have been created for this purpose. An example is given in Figure 1 and the reference manual pages are in the BEA TUXEDO Reference Manual: Section 3c

Fig. 1: Handling the environment

	LPSTR szRplyMax;
	long wCurrRplyMax = 0;	/* Current value of TUXEDO Reply buffer in
				 * memory
				 */
	....
	if(szRplyMax = tuxgetenv((LPSTR)"WSRPLYMAX") == NULL)
		wCurrRplyMax = 0L;
	else
		wCurrRplyMax = atol(szRplyMax);
	if(wCurrRplyMax < 10240L) {
		if(tuxputenv("WSRPLYMAX=16384") == 0)
			wCurrRplyMax = 16384L;
	}
	....

Using bankapp as an Example

Among the files in the directory $TUXDIR/apps/ws you will find the following:


BALANCE.DLG  - dialog resource for BANKAPPW BALANCE window
BANKAPPW.C   - Windows application
BANKAPPW.DEF - Windows definition file for BANKAPPW
BANKAPPW.RC  - Windows resource file for BANKAPPW
BANKAPP.H    - BANKAPPW window field identifiers
BANKFLDS     - FML buffer field identifiers
MSC.MAK      - Microsoft C makefile

These are the files needed to produce a bankapp client for Windows. Notice there are two make files, MSC.MAK, if you use the Microsoft C compiler and

Take a look through the application file, BANKAPPW.C; we want to call your attention to a few items. Figure 2 shows the #include files you should include.

Fig. 2: bankapp for Windows: #include files

    15	#include <stdio.h>
    16	#undef NULL
    17	#include <windows.h>
    18	#include <stdlib.h>
    19	#include <string.h>
    20	#include <ctype.h>
    21	#include <atmi.h>
    22	#include <Usysflds.h>
    23	#include <fml.h>
    24	#include <userlog.h>
    25	#include "bankapp.h"
    26	#include "bankflds.h"

The #undef NULL at line 16 is there to prevent a compiler warning caused by NULL being defined in both stdio.h and windows.h.

At line 45, as Figure 3 shows, you declare your FBFR as a FAR pointer. In Windows NT FAR and PASCAL are defined to be nothing. Figure 3 also shows that you write your client program as a WinMain() module.

Fig. 3: bankapp for Windows: WinMain declaration

    44	static HANDLE	hInst;
    45	static FBFR FAR *fbfr;
    46
    47	int PASCAL
    48	WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
    49	HANDLE hInstance;
    50	HANDLE hPrevInstance;
    51	LPSTR lpCmdLine;
    52	int nCmdShow;

In Figure 4 there are examples of the statements needed to declare a routine to pick up unsolicited messages. The statement must be in both the .C file and the .DEF file. The figure also shows a call to tpsetunsol.

Fig. 4: bankapp for Windows: declaring unsolicited message routine

In BANKAPPW.C
    40	BOOL FAR PASCAL CloseDlg(HWND, WORD, WORD, LONG);
    41	BOOL FAR PASCAL OpenDlg(HWND, WORD, WORD, LONG);
    42	void FAR PASCAL UnsolProc(char FAR *, long, long);
        .
        .
        .
   167			lpfnCloseDlg = MakeProcInstance(CloseDlg,hInst);
   168			lpfnOpenDlg = MakeProcInstance(OpenDlg,hInst);
   169			lpfnUnsolptr=MakeProcInstance((FARPROC)UnsolProc,hInst);
   170
   171			if(tpsetunsol((void FAR*)lpfnUnsolptr) == TPUNSOLERR)
   172				userlog("tpsetunsol failed");
In BANKAPPW.DEF
    16	EXPORTS		WndProc
    17			TransferDlg
    18			BalanceDlg
    19			DepositDlg
    20			WithdrawDlg
    21			CloseDlg
    22			OpenDlg
    23			UnsolProc

Lines 183 to 325 are Field Validation Routines: five routines that check the validity of the input typed in by the user. We will not show this code except for an example (in Figure 5) of how syntax errors cause a message to be displayed on the user's screen by means of a call to MessageBox.

Fig. 5: bankapp for Windows: displaying a syntax error

   203		if (i < 5 || i > 6 || account[i] != '\0') {
   204			/* SetDlgItemText (hDlg, item, ""); */
   205			MessageBox (hDlg,
   206				"Account number must be 5 or 6 digits",
   207				"BANKAPP", MB_OK);
   208			SetFocus(GetDlgItem(hDlg, item));
   209			return(-1);

The actual work of the application begins at with the comments at line 354 describing six dialog boxes. Figure 6 shows the beginning of this section of the code.

Fig. 6: bankapp for Windows: dialog boxes

   354	/*
   355	 * Routines to handle Dialog Boxes for Services
   356	 *	BalanceDlg(hDlg, message, wParam, lParam)
   357	 *	CloseDlg(hDlg, message, wParam, lParam)
   358	 *	DepositDlg(hDlg, message, wParam, lParam)
   359	 *	OpenDlg(hDlg, message, wParam, lParam)
   360	 *	TransferDlg(hDlg, message, wParam, lParam)
   361	 *	WithdrawDlg(hDlg, message, wParam, lParam)
   362	 */
   363	BOOL FAR PASCAL
   364	BalanceDlg(hDlg, message, wParam, lParam)
   365	HWND hDlg;
   366	WORD message;
   367	WORD wParam;
   368	LONG lParam;

The dialog boxes, which take up the rest of the code, accept input from the user, start a transaction (assuming -Dtran is specified when the client is built), make a call to the requested service and return information to the user. The code in Figure 7 shows how errors might be handled. In lines 391-392, for example, the the call to tpbegin fails, a message is sent to userlog(3c) and also to the user's screen via the string account1. In lines 397-403, if the service call fails and the buffer is not NULL, the status line is picked up and returned to the user. If the failure is due to another reason or if the buffer is NULL, a hard-coded error message is returned.

Lines 416-417 show the service request being successfully performed and the requested balance being displayed on the user's screen.

Fig. 7: bankapp for Windows: error handling

   390	#ifdef tran
   391			if (tpbegin(30, 0) == -1) {
   392				(void) userlog("failed to begin transaction\n");
   393 				lstrcpy(account1, "Transaction failed");
   394			}
   395			else
   396	#endif
   397			if (tpcall("INQUIRY", (char FAR *)fbfr, 0,
				(char FAR *FAR *)&fbfr, &len, 0) == -1) {
   398				if(tperrno== TPESVCFAIL && fbfr != NULL &&
   399 				(s=Ffind(fbfr,STATLIN,0,0)) != 0) {
   400				 lstrcpy(account1, s);
   401				}
   402				else
   403				 lstrcpy(account1,"Inquiry failed");
   404	#ifdef tran
   405				(void) tpabort(0);
   406	#endif
   407			}
   408			else {
   409	#ifdef tran
   410				if(tpcommit(0) < 0) {
   411					lstrcpy(account1, "Inquiry failed");
   412				}
   413				else
   414	#endif
   415
   416				wsprintf(account1, "Account Balance:  %s",
   417					(LPSTR) Ffind(fbfr, SBALANCE, 0, 0));
   418			}

Blocking Network Behavior

When an ATMI function is called the Windows DLL could block on the network waiting for a reply from the server on the UNIX machine. This can happen on any call that initiates a network message to the UNIX machine, for example, tpcall(), tpinit(), tpgetrply() and so on. These functions may take an arbitrary long time to complete; a good example is tpcall(), which may block until the server has completed the processing required.

Windows 3.x is not a preemptive multitasking operating system and there is only one system wide Windows input queue. Because of this if a client program blocks on the network; the entire Windows interface "freezes" until the network call returns.

With the TUXEDO System Workstation for Windows a blocking operation that cannot be completed immediately is handled as follows. The DLL initiates the operation and enters a loop in which it dispatches any windows messages (yielding the processor to another thread if necessary) and then checks for the completion of the ATMI function. If the ATMI call is complete the blocking call is completed and the appropriate result is returned to the caller. If not complete the DLL continues to dispatch Windows messages. For a complete description of this behavior see AEWsetblockinghook(3) AEWsetblockinghook(3) in the BEA TUXEDO Reference Manual: Section 3c.

If a Windows message is received for a process for which a blocking operation is in progress, there is a risk that the application will attempt to issue another ATMI call. Such application behavior is not supported by ATMI calls. AEWisblocked(3c) can be called at any time to detect if there is a blocking ATMI call outstanding. Any other ATMI call made while this condition exists will fail and set tperrno to TPEPROTO.

Although this mechanism is sufficient for simple applications, it cannot support the complex message dispatch requirements of more advanced applications (for example, those using the MDI (Multiple Document Interface) model). For such applications, ATMI includes AEWsetblockinghook(3) AEWsetblockinghook(3), which allows the programmer to define a special routine which will be called instead of the default routine.

If an application invokes a blocking operation like tpcall() and provides a typed buffer to it as an argument, it is the responsibility of the application to ensure that the buffer is available to ATMI until the operation is completed.

FML functions will continue to work even if there is a blocking call in progress, therefore it is the responsibility of the application to not use FML buffers that are passed in as an argument to an ATMI call that is currently in progress until the ATMI call completes.

Restoring the Environment

As Workstation for Windows 3.x starts up it copies the environment from the Windows area to a local buffer and maintains a distinct environment space for each client. The local space is destroyed when tpterm() is called. It is the responsibility of the application to reinstate the environment and other information installed using tpsetunsol() and AEWsetblockinghook() after tpterm() is called.

Building Client Programs

For Windows any compiler that can read Microsoft C import libraries can be used.

When compiling System/T client programs for Windows 3.x, use the C preprocessor flag


-D_TM_WIN

When link editing your client programs, use buildclt(1) with the -W flag.

TUXEDO System/T clients can be build without using the buildclt(1) utility. If the Microsoft Visual C++ projects are used then set the Preprocessor options to


-D_TM_WIN

for Windows 3.x


-DWIN32

for Windows 95. In the linker options add


WTUXWS.LIB

to the input libraries for Windows 3.x and


WTUXWS32.LIB MSVCRT.LIB

for Windows 95. In addition to this set the INCLUDE, LIB and PATH search directories appropriately.

Using views in 16 bit windows

Windows Version 3.x (16 bit) recommends that C programs use "structure packing" on a one byte boundary. With the Microsoft C compiler this is enabled using the /Zp option. The view compiler viewc uses the Microsoft C compiler to calculate the offsets of the C structures. In order for viewc to use the structure packing and get the correct offsets set the CFLAGS variable to /Zp before running viewc. As an example if the client C program uses structure packing on a one byte boundary then compile the C code as follows


CL /Zp -D_TM_WIN CLIENT.C

and before compiling the views


set CFLAGS=/Zp
VIEWC.EXE CLVIEW.V

Runtime

When you run client programs, your PATH must include %TUXDIR%/bin.

Limitations

The following is a list of limitations that apply to Release 5.0 (and higher) of the System/T Windows DLL.

  • Microsoft Windows ``real'' mode is not supported under Windows 3.X.
  • Multiplexed network connections are not available; each client process requires a separate network connection.
  • The TUXEDO libraries (DLLs) are not thread-safe. This means that either applications should not use threads, or threaded access is serialized through all TUXEDO calls (such as ATMI, FML, userlog( ), and so on).