Application Note

 

 

AltiaTM Design 2.3 for Windows 3.1/95/NT

Human Interface Design Software

Using Microsoft Visual Basic with Altia Design

This Application Note outlines how to use Microsoft Visual Basic to create application programs that interact with Altia Design interfaces.

This document assumes Altia Design is installed relative to the c:\usr\altia directory. Your installation directory may be different. If so, occurrences of c:\usr\altia would be replaced with your installation directory choice.

Visual Basic Overview

Visual Basic is a Basic programming language environment with extensions for developing Windows applications. The Basic code developed in this environment is executed by a Basic language interpreter. This is in contrast to the more complex compile/link/execute cycle required by C/C++ language tools. An interpreter allows developers to make program changes and test those changes immediately. In addition, Visual Basic supplies a program editor that automatically checks the syntax of your code and reports errors during the editing phase. These features, in conjunction with Basic's easy to learn syntax, make Visual Basic an excellent application prototyping environment. The Windows controls available with Visual Basic enhance its appeal even further as a prototyping and development environment for Windows applications. Visual Basic, however, does not support the full GDI (Graphics Device Interface). This makes it less suitable for prototyping or developing applications which require custom graphics. Fortunately, Altia Design can be used to develop custom graphics interfaces and these interfaces can be controlled from Visual Basic code using Altia's Visual Basic Application Programming Interface (API). This is a function library (in the form of a DLL) that allows Visual Basic programs to send or receive events to/from an Altia Design interface.

Using Visual Basic with Altia Design creates a powerful prototyping environment. Altia Design allows you to create dynamic concept displays without writing graphics code and Visual Basic provides an easy to learn environment for controlling the behavior of the displays.

System Configuration Requirements

Before proceeding with the integration of a Visual Basic program and an Altia Design interface, you should verify the following system configuration requirements:

· Your Windows directory or Windows system directory (typically c:\windows or c:\windows\system) must contain a copy of the Altia Design 16-bit DLL altiadde.dll and the 32-bit DLL altdde32.dll. If it does not, simply copy the DLL files from the c:\usr\altia\lib directory to the Windows directory. An alternative approach is to add c:\usr\altia\lib to the PATH environment variable in your AUTOEXEC.BAT file.

· If you chose not to install Altia Design in the c:\usr\altia directory or it is on a drive different from your Visual Basic installation directory, you should set the ALTIAHOME environment variable in your AUTOEXEC.BAT file to reference the actual installation directory. For instance, if Altia Design is installed on the d: drive under \altia, add a line to AUTOEXEC.BAT that looks like:

set ALTIAHOME=d:\altia

Please note that ALTIAHOME must be all upper-case characters - no lower-case characters, underscores, or spaces are accepted. An alternative approach is to add the Altia Design bin directory path to the PATH environment variable also found in AUTOEXEC.BAT (e.g., set PATH=c:\windows;c:\bin;c:\vb;d:\altia\bin).

· If you make changes to AUTOEXEC.BAT, you must exit Windows and restart you computer before the changes will take affect.

Getting Started with Visual Basic 3.0

To create a Visual Basic 3.0 program that interfaces to Altia Design, proceed as follows:

1. Start Visual Basic and create a new project by choosing New Project from the File menu.

2. From the Options menu, select Project.... In the Project Options dialog, select the "Start up Form" option and change its setting to "Sub Main". This will force the main subroutine to be called when the project is started.

3. From the Options menu, select Environment.... In the Environment Options dialog, select the "Require Variable Declaration" option and change its setting to "Yes". Though this step is not required, it is recommended anytime Visual Basic is calling external DLL's. It insures that the parameters passed to external routines are of the correct type.

4. From the File menu, select Load Text.... Using the Load Text dialog, find the file c:\altia\lib\altiaapi.txt and double-click on it. This will create a new code module that contains the declarations for the 16-bit Altia Application Programming Interface (API) routines provided by altiadde.dll - the 16-bit Altia API DLL. These declarations describe the functions supported by the DLL. In general, these functions are used to control dynamic graphics objects in an Altia Design interface or receive events which were triggered by mouse or keyboard activity.

5. Create a new code module for Sub Main by choosing New Module from the File menu. In the new code module window, erase the existing line containing "Option Explicit" and simply type:

Sub Main<Enter>

where <Enter> is the Enter key from the keyboard. Visual Basic will insert an "End Sub" statement automatically. You are now ready to type statements into the body of the Main Subroutine as described under Creating the Visual Basic Main Subroutine.

Getting Started with Visual Basic 4.0

To create a Visual Basic 4.0 program that interfaces to Altia Design, proceed as follows:

1. Start Visual Basic and create a new project by choosing New Project from the File menu.

2. Select Options... from the Tools menu. In the Options dialog, press the Project tab, click to open the Startup Form list, and select "Sub Main". This will force the main subroutine to be called when the project is started.

3. While still in the Options dialog from step 3, choose the Environment tab and enable the "Require Variable Declaration" option (i.e., it should have a check mark next to it). Though this step is not required, it is recommended anytime Visual Basic is calling external DLL's. It insures that the parameters passed to external routines are of the correct type.

4. From the File menu, select Add File..., choose to list files of type "All Files (*.*), find the file c:\altia\lib\altia32.txt, and double-click on it. This will create a new code module that contains the declarations for the 32-bit Altia Application Programming Interface (API) routines provided by altdde32.dll - the 32-bit Altia API DLL. These declarations describe the functions supported by the DLL. In general, these functions are used to control dynamic graphics objects in an Altia Design interface or receive events which were triggered by mouse or keyboard activity. If you are using the 16-bit version of Visual Basic 4.0, load the file c:\altia\lib\altiaapi.txt instead of altia32.txt.

5. Create a new code module for Sub Main by choosing Module from the Insert menu. In the new code module window, erase the existing line containing "Option Explicit" and simply type:

Sub Main<Enter>

where <Enter> is the Enter key from the keyboard. Visual Basic will insert an "End Sub" statement automatically. You are now ready to type statements into the body of the Main Subroutine as described under Creating the Visual Basic Main Subroutine.

Creating the Visual Basic Main Subroutine

To successfully use Altia Design, your Visual Basic program will need to make Altia API DLL calls inside of an "idle loop". An idle loop is a program loop designed to wait for events to occur. The standard Visual Basic idle loop is typically placed within the Main subroutine in the following manner:

Sub Main ()

' This is a comment. Your code to show or load any VB forms would go in

' in this area if applicable.

Do While DoEvents()

' Idle loop code goes here between Do and Loop. It is executed

' when time is available.

Loop

End Sub

The best way to incorporate Altia Design into the "idle loop" is by using the altiaPending() Altia API function. This function checks to see if any events sent by the Altia interface are waiting to be processed. If there are events available, it returns a value representing the number of available events. If no events are available, it returns 0. It will also return -1 if the Altia interface connection is no longer working (which implies that the Altia interface has been closed by the user). The following is an example of a complete Main subroutine with an idle loop that includes a call to altiaPending():

Sub Main ()

' Variables used by this subroutine:

Dim res As Integer

Dim eventName As String * 128

Dim event As String

Dim value As Integer

Dim quit As Integer

' Select to receive "button" and "knob" events from altia. The first call to any

' Altia API function forces a connect with the Altia interface process if one exists.

res = altiaSelectEvent("button")

res = altiaSelectEvent("knob")

quit = 0

Do Until quit = 1

res = altiaPending()

if res = -1 Then

quit = 1

ElseIf res > 0 Then

' Get the next event that is waiting for us from Altia.

res = altiaNextEvent(eventName,Len(eventName), value)

event = Left$(eventName, InStr(eventName, Chr$(0)) - 1)

' Do Altia event processing in an If...ElseIf...End If block.

If event = "button" And value = 1 Then

res = altiaSendEvent("led", 1)

ElseIf event = "button" And value = 0 Then

res = altiaSendEvent("led", 0)

ElseIf event = "knob" Then

res = altiaSendEvent("knob_integer", value)

End If

End If

DoEvents ' This will do the Visual Basic event processing

Loop

' Officially disconnect from the Altia interface - especially important with 32-bit VB

altiaDisconnect

End Sub

The first Altia specific action for this Main subroutine is to select to receive events from the Altia interface. This is accomplished with one or more calls to altiaSelectEvent(). In this example, the events selected are named "button" and "knob". As the program comments point out, the first Altia API function call automatically attempts to open a connection to the Altia interface process. This can only work if an Altia interface process is already running. The process can be an editor or runtime session. The connection is made using a DDE named "altDDE", but details such as this are taken care of automatically by the Altia API DLL.

The altiaPending() function call checks to see if any events are available. If so, a call is made to altiaNextEvent() to get the next available event. If more than one event is available, the oldest event is returned. In the above example, eventName must be a fixed length string. Since it is easier to deal with variable length strings, the line following the call to altiaNextEvent() copies just the string portion of eventName to event. Because altiaNextEvent() always terminates strings with the NULL (0) character, this is easily accomplished.

After getting a new Altia event, this example compares the event string to the strings "button" and "knob". If event matches "button", the value of the event is also tested. If value is 1, altiaSendEvent() is called to send an event back to the Altia interface. In this case, it is a request to set the state of an animation named "led" to 1. If the value for the "button" event is 0, the "led" animation is set to 0. If the incoming event is named "knob", the value for the "knob" event is used to set the state for an animation named "knob_integer". Presumably, "knob_integer" is an integer animation associated with a text i/o object (i.e., a dynamic text input/output object originating from the Altia textio.dsn models library).

A call to DoEvents completes the idle loop. The DoEvents call checks for inputs from the Visual Basic product interface.

Before a program ends, it should always call the altiaDisconnect() function. This insures the proper termination of the Altia DLL.

Prior to the idle loop, you may want to include custom initialization code. For example, you may want to start the runtime version of Altia Design and have it automatically load your specific interface. This can be done with a call to altiaStartInterface(). This function searches for the Altia Runtime executable, altiart.exe, in %ALTIAHOME%\bin if the ALTIAHOME environment variable is set. Otherwise, it searches for altiart.exe in the directories specified in the PATH environment variable, then it searches in the current working directory, and finally it looks in \usr\altia\bin if all previous searches failed. In the above example, it would be placed before the altiaSelectEvent() calls and immediately after the Dim quit As Integer statement. For example:

Dim id

id = altiaStartInterface("c:\altiavb\my.dsn", 0, "")

If id = -1 Then

End

End if

If the function call returns -1, then the Altia interface startup failed. In this particular example, a return of -1 will force the program to end. For much more detail on altiaStartInterface() and all of the other functions supported by the Altia API DLL, refer to the comments found in the declarations portion of the code module created from the c:\usr\altia\lib\altiaapi.txt or altia32.txt file.

As your program grows, you can partition it into additional subroutines and call these subroutines from the Main subroutine or each other. New subroutines are created in the same manner as the Main subroutine (i.e., type: Sub New_Sub_Name<Enter> in the code module window).

Available Demonstration Designs

Several examples are supplied with Altia Design that demonstrate integration with Visual Basic programs. The first is a version of the standard Stress Monitor demo. To load the project for this demo into Visual Basic, select Open Project... from the File menu, change directory to c:\usr\altia\demos\stress\vbasic[16] in the Open Project dialog, and double-click on stress.mak. Or, an even easier method is to simply double-click on stress.mak from a file browser window (e.g., File Manager in Windows 3.1 or Windows Explorer in Windows 95). The easier method assumes that the Windows file type registry is mapping .mak files to the Visual Basic project file type. Under c:\usr\altia\demos\vbasic[16] is a second demonstration - a simple blood meter prototype. This demo shows how a state machine can be built and how timer events are used. To load this project, open c:\usr\altia\demos\vbasic[16]\meter.mak. If you are using a 16-bit Visual Basic development environment, then open the project files in the vbasic16 directories while 32-bit Visual Basic users should open the project files in the vbasic directories.

As discussed earlier, the file c:\usr\altia\lib\altiaapi.txt contains declarations for all of the functions supported by the 16-bit Altia API DLL. It also includes documentation for each function. A copy of altiaapi.txt is actually included in the declarations portion of the ALTIAAPI.BAS code module for each 16-bit Visual Basic demonstration project.

The c:\usr\altia\lib\altia32.txt file contains the 32-bit DLL function declarations. A copy of altia32.txt is actually included in the declarations portion of the ALTIA32.TXT code module in each 32-bit Visual Basic demonstration project.

Guidelines for Mixing VB Form and Control Event Procedures with Altia API DLL Function Calls

A Visual Basic program using the Altia API functions can also contain Visual Basic form and control event procedures for controlling a Visual Basic interface. The Visual Basic interface will appear in a window (or windows) independent of the Altia interface window. Input from objects in the VB interface can control objects in the Altia interface and vice-a-versa using the Altia API functions; however, some guidelines must be followed to insure proper program execution:

· A Visual Basic event procedure should not directly call an Altia API DLL function. When using the idle loop approach described earlier, VB interface events are processed by the altiaPending() function and appropriate VB event procedures are called as a result. If an event procedure makes a call to an Altia API DLL function, problems can occur because two functions in the same DLL are trying to execute at the same time. This phenomenon is referred to as reentrancy. The Altia API DLL does not support reentrancy. Instead, a VB event procedure should set a global variable (e.g., assign it a value of 1). Statements in the idle loop can test the variable after altiaPending() returns, take appropriate action if the variable is set, and then reset the variable (e.g., assign it a value of 0). If an event procedure must make Altia API calls, it can first call the function altiaBusy() to check the status of the Altia API DLL. The altiaBusy() function returns 0 if the DLL is not busy (i.e., it is safe to make Altia API calls from the event procedure) and non-zero if it is busy.

A symptom of reentrancy is the sudden failure of communications between the Altia interface and the program. The Altia interface seems to no longer listen to events from the program and it stops sending events to the program.

· A Visual Basic timer event procedure should not directly call an Altia API DLL function for the same reason described above. Setting a global variable in the event procedure and testing it in the idle loop is one method for avoiding problems. Statements in the idle loop can test the variable after altiaPending() returns, take appropriate action if the variable is set, and then reset the variable. Or, as an alternative to using Visual Basic timers, you may wish to consider using Altia timer stimulus instead. It is a standard feature on Altia Design 1.40 or newer versions. Please refer to the Timers option in the Stimulus Editor's Help menu for more details.

Advanced Tips

Here are issues to keep in mind while writing and debugging your Visual Basic programs:

· The Altia API DLL uses buffered output when communicating with an Altia interface. This means that events sent to the interface using altiaSendEvent() are not immediately passed on to the interface. As a result, a program may execute one or more altiaSendEvent() calls without causing any immediate visual change to the Altia interface. This behavior is an attempt by the DLL to optimize performance by saving (i.e., buffering) events until it can send several to the interface all at once. The events are sent when the DLL's buffer is filled or the Basic program calls the altiaPending() function. This guarantees that events will be flushed each time through the program's idle loop assuming that an altiaPending() call is part of the loop. Buffered events can also be flushed immediately with a call to altiaFlushOutput().

During program debug, it may be useful to permanently disable event buffering. This is done with a call to altiaCacheOutput() that looks like:

res = altiaCacheOutput(0)