The QMClient API allows an external application to connect to a QM server. There are API equivalents to the major file handling statements of QMBasic as well as a range of string functions for dynamic array data manipulations, functions to execute commands and call catalogued subroutines on the server, etc. Where both ends of the connection support it, the network traffic is encrypted for security.
QMClient allows multiple simultaneous connections from a single client process. This allows development of applications that draw on data from multiple sources or transfer data between accounts or servers.
QMClient is usable from many languages and environments. The table below shows the library name, function definition record in the SYSCOM file. Except as noted below, the library files appropriate to the version of QM in use are normally automatically installed in the bin subdirectory of the QMSYS account. Because the client software might be for a different system type, these files are also on the Downloads page of the openqm.com web site. Some QMClient variants are separately downloadable items on the Resources and Solutions page of the openqm.com web site as noted below.
The secret of writing efficient client server applications is to perform the bulk data processing on the server and only handle user interface issues on the client. This minimises the data transferred between the systems and hence optimises performance.
QMClient has some security issues that need special consideration.
A QMClient session is an interactive use of the system and hence is counted in determining the licensed user limit on the server.
The QMClient libraries listed above may be freely distributed with application software. The QM licence redistribution clauses apply to the server software, not the QMClient client-side components. Although every attempt is made to ensure compatibility with older versions of the client libraries, there may be times when changes require the distributed client components to be updated.
There are some aspects of the QMClient API that differ between the various client languages. The following descriptions cover the most commonly used languages. For the less widely used languages such as PowerBasic, see the comments at the head of the relevant item in the SYSCOM file.
Using the C API
Use of the C programmers' API is different depending on the compiler in use. On Unix/Linux based systems, programs need to include the libqmclient.a library when linking the application. The Linux version of QM also includes a shared object version of QMClient API named qmclilib.so. On Windows, the qmclilib.dll dynamic link library is used and two import libraries are provided to include when linking the application; qmcllbbl.lib for Borland C users and qmclilib.lib for Microsoft C users. All of these components can be found in the bin subdirectory of the QMSYS account. The function definitions can be found in the qmclilib.h include record in the SYSCOM file.
Functions that return Boolean values, return 0 for False, 1 for True in the C API library.
With the exception of QMError(), all API calls that return strings dynamically allocate memory to hold the returned data. It is the calling program's responsibility to release this memory using the QMFree() function when it is no longer required. On Windows systems, this function must be used in place of the standard free() C runtime library routine to ensure compatibility with the memory allocator used by the QMClient library. On other platforms, use of QMFree() is strongly recommended but this should be compatible with the C run time library free() function.
The QMClient C API has three modes of operation for handling character string data:
1.The functions documented in the following sections use 8-bit characters. Using these functions to return data that is outside the 8-bit character set (e.g. reading a record containing ECS characters) will return only the low order 8 bits of each character. No error status will be reported.
2.The QMConnectionType() function can be used to select a mode in which the functions that pass character strings in 8-bit form do so using UTF-8 encoding. This allows an application using the 8-bit character functions to use characters from the entire Unicode Basic Multilingual Plane. Note that use of this mode requires that characters in the upper half of the 8-bit character set, including the multivalue mark characters, are correctly encoded as their UTF-8 equivalents. The five mark characters encode as
3.All functions in the QMClient C API that return a character string or have at least one character string argument have wide character variants formed by appending a W to the function name. For example, the wide character version of QMDel() is named QMDelW(). In the wide character versions, return values or arguments shown in the function definitions as char * become wchar_t *. Note that, for compatibility with the default behaviour of the C run time library, the definition of this data type is a 16 bit unsigned integer on Windows but a 32 bit unsigned integer on Linux and Unix systems.
The wide character API functions can be used regardless of whether the server to which the connection is open is in ECS mode or not, however, passing characters with values over 255 in API calls in this situation may have unexpected effects. The QMIsECS() function can be used to determine whether the server supports ECS or not.
QMBasic subroutines and functions can update their argument values. For the C API this would require that the memory space allocated to a subroutine argument that may be updated by the server must be large enough to hold the longest updated value that could occur. Failure to observe this rule may result in memory corruption on the client side of the connection. To avoid this issue, the C API supports an alternative mechanism for handling returned argument values where the original argument variable is not updated but instead the new value can be retrieved with the QMGetArg() function. To make use of this system, the client software should use QMCallx() instead of QMCall(). The QMCreateObject(), QMGet() and QMSet() functions also allow updated argument values to be retrieved with QMGetArg().
Using the Visual Basic .Net API
Use of QMClient from Visual Basic .Net requires two dynamic link libraries; qmclivb.dll and qmclilib.dll. Inclusion of the first of these libraries as a reference from the Visual Basic project and adding
to the Visual Basic classes makes the QMClient functions available. The descriptions for each QMClient function in this documentation show the VB.Net data types.
The dynamic link libraries must be installed on the client system. They are automatically placed in the Windows directory (not necessarily c:\windows) when QM is installed. These components may be freely copied and distributed as necessary. They can also be downloaded separately from the openqm.com web site.
All strings in the Visual Basic .Net API are Unicode.
Where a client application calls a QMBasic subroutine or function on the server that updates its argument values, the modified value will be visible in the client process too when using QMCall(). The alternative method of calling subroutines with QMCallx() and handling returned argument values via the QMGetArg() function is also available in the Visual Basic .Net API.
Using the Visual Basic 2005 API
QM currently retains support for Visual Basic 2005 using the qmclient.dll dynamic link library and a Visual Basic module named QMClient 2005.vb in the SYSCOM file that contains the API function definitions. Many of the function argument values passed by the VB.Net API as integers are passed as short integers in the old Visual Basic API and hence differ from the VB.Net definitions shown in the function descriptions in this documentation. See the QMClient2005.vb file for the correct definitions.
The QMClient.dll library must be installed on the client system. This library is placed in the Windows directory (not necessarily c:\windows) when QM is installed. These components may be freely copied and distributed as necessary.
All strings in the Visual Basic 2005 API are 8-bit.
Where a client application uses QMCall() to call a QMBasic subroutine or function on the server that updates its argument values, the modified values will be visible in the client process.
Visual Basic versions 5 and 6 are no longer supported though the function definition items for these in the SYSCOM file will not be deleted by the installer.
Using the QMBasic Class Module API
The QMClient class module is supplied as a globally catalogued item named !QMCLIENT. To create a QMClient session, the object is instantiated with a statement of the form
session = object("!qmclient")
The session is then connected to a server using the CONNECT() method:
ok = session->connect(hostname, port, user, password, account)
There is no equivalent of the QMConnectLocal() function in the QMBasic class module API.
Functions that return Boolean values, return 0 for False, 1 for True in the QMBasic class module API. Status codes referenced with a prefix of SV_ in the function descriptions are defined in the SYSCOM KEYS.H include record with a prefix of SV$. For example, SV_OK becomes SV$OK for the QMBasic variant of the QMClient API.
All examples in the detailed function descriptions assume that the object has been instantiated as a variable named "session".
Using the Java QMClient API
Two distinct versions of the Java API are available. The original implementation is platform specific because it uses the Java Native Interface (JNI). This version can be downloaded from the OpenQM web site Resources and Solutions area. The Java QMClient API installation package includes separate HTML documentation covering its usage.
A pure Java version of the API was introduced at QM release 3.4-7 and can be found on the main downloads page of the web site. This version is portable across all platforms that support Java. Documentation for the functions in this API appears in the sections that follow. To use this API, the client program should use
and then reference the functions in the form qm.Name() such that, for example, the QMExtract() function becomes
var = qm.Extract(dyn_array, field, value, subvalue);
All references to the Java API in the following sections relate to the portable Java API. All examples in the function descriptions assume that the object has been instantiated as a variable named "qm".
Using QMClient from Python
The qmclient.py item in the SYSCOM file has definitions and descriptions for Python versions of the API functions and also has comment text at the top of the module that describes how to use it. Essentially, the Python program should use
import qmclient.py as qm
and then reference the functions in the form qm.Name() such that, for example, the QMExtract() function becomes
var = qm.Extract(dyn_array, field, value, subvalue)
If the qmclient.py file is not in the current directory, the PYTHONPATH environment variable must be set as a list of directories to search for imported modules in the same form as used for the PATH environment variable. Also note that on Windows, which has a case insensitive file system, the casing of Python module filenames must match that used in the import statement.
Because Python does not support passing arguments by reference, QMClient functions that use this capability in other languages are modified to return two items as a list such that, for example, QMRead() becomes
rec, err = qm.Read(fno, id)
or QMLocate() becomes
found, pos = qm.Locate(item, dyn_array, field, value, subvalue, order)
All examples in the function descriptions assume that the object has been instantiated as a variable named "qm".
Error Handling in QMClient Applications
QMClient was originally developed for use in applications that had a directly associated user screen on which error messages could be displayed. It has subsequently found use in applications that do not have a directly associated screen such as the server side of a web application. In such situations when using some languages, it will be necessary to use the QMConnectionType function to disable display of error messages. To ensure that older applications continue to run unchanged, the default behaviour of QMClient is to display errors either using a pop-up message box (Windows) or by sending the message to the stderr error channel (Linux).
From release 2.11-3, nearly all QMClient functions start by setting the QMError() error string to null. Applications can test if QMError() is a null string in order to determine whether an error has occurred. Errors are returned in this way even if the older style displayed messages are still enabled. The functions that do not change the QMError value are QMFree, QMStatus and QMError itself. Alternatively, applications can check the server status code as described later in this section.
The QMClient API supports multi-threading so long as two threads do not attempt an operation on the same session simultaneously. If a session could never be accessed by more than one thread simultaneously, no special coding is needed. In languages such as Java or Python where each QM session is instantiated as a separate object, each function call references the specific object to which it applies. For other languages, sessions are identified by a numeric value and a thread may switch between multiple sessions using QMSetSession() in which case QMClient will correctly track the currently active session in each thread. If a single session could be accessed by multiple threads simultaneously, it will be necessary to use semaphores or similar synchronisation techniques to ensure that actions on a single session do not overlap.
API Function Summary
For the C API, "W" indicates that a wide string version of the function is available.
The Server Status Code
Many functions return a server error status referenced as Err in the detailed function descriptions. In variants of the QMClient API that allow function argument variables to be updated by the function (C, VB.Net, QMBasic class module), this variable is an integer argument, passed by reference. In the Python variant, the error status is returned as a second return value. For the Java variant, applications should test the ServerError property.
In all cases, the value returned will be one of the following that broadly corresponding to the various clauses applicable to the equivalent QMBasic statements.
The tokens shown above are defined in the SYSCOM include record or module relevant to the language in use. For the Java and QMBasic variants of the API, the names are modified to be SV$xxx instead of SV_xxx.
In the function descriptions that follow, the language specific details are presented as an expanding text that can be shown by clicking on the language name in the blue bar for the relevant language.