TOC PREV NEXT INDEX

Using AVS/Express




10 Projects and Processes


This chapter describes AVS/Express projects and processes. It includes the following sections:

10.1 Overview

An AVS/Express project defines your development and execution environment. Whenever you work with AVS/Express, you are working in a project. A project, which serves as the framework for your working environment, includes three major components:

When you first use AVS/Express, you work in the install area's project, with its full complement of AVS/Express template objects (see Install Area Project on page 3-7). The install area project is read only and cannot be modified; you create your own projects as summarized in Creating a Runtime Project on page 10-3.

Creating and Compiling Projects

You create your own projects as children of your current project. You can create a new project from any existing project (install or other), as long as it is your current (parent) project. A new project can be either a distinct project (the default) or a derived project.

Both distance and derived projects are dependant on the original installed version of AVS/Express for V files and other files needed at runtime. If you wish to create a project that is not dependant on the original install of AVS/Express see "See Creating a Runtime Project on page 10-3."

Creating and Compiling Processes

As noted in the previous section, a project comes with the set of predefined processes, some of which are created as needed for objects. You can also create additional processes by inserting them into the root-level ProcTemplates object in which processes are defined.

For details, see Defining Processes for Objects on page 10-12, Creating New Processes on page 10-14, and The proc.v File on page 10-29.

When working with AVS/Express, you will often need to compile processes, for example to include new or revised definitions of objects. You can compile a process either from within AVS/Express or from the command line. When you do the former, AVS/Express uses information that you provide-for example, source filenames, library dependencies, and process name-to construct a makefile and, if possible, use it to build a new executable. During the compile process, AVS/Express can also generate template source files in cases where an object's source file does not exist.

For details, see Compiling Projects and Processes on page 10-14.

Creating a Runtime Project

Only Developer Edition users can create a runtime project. As a Developer Edition user, once you understand project architecture, you can use AVS/Express to create more sophisticated projects. To do this, you will compile and save a selected set of objects into a separate project area. This mechanism allows you to build runtime versions of your AVS/Express applications that are smaller, start up faster, and depend upon fewer files, and are therefore ideal for distribution.

For details, see Saving Compiled Projects (Generating a Runtime Project) on page 10-30.

10.2 Projects and Processes

Processes contain definitions for the objects in an AVS/Express project, enable the objects' interactions, and perform operations required by the project. Any number of processes can attach to a single AVS/Express session. Each AVS/Express object in a project lives in exactly one process, but all processes see the same object hierarchy and any process can operate on any other object regardless of which process contains it. AVS/Express processes can either exist on the local host or run on a remote host.

A project comes with an express process and a base internal bootstrap process, and user processes are created as needed for objects (see Defining Processes for Objects on page 10-12). You can also create additional processes as needed (see Creating New Processes on page 10-14). The processes for a given project are defined in its root-level ProcTemplates object (see The proc.v File on page 10-29).

You must compile an AVS/Express process to use the objects it defines.

For details, see Compiling Projects and Processes on page 10-14.

The Main (express) Process

The main process, named express, synchronizes all other processes. It must, therefore, start up before any other process attaches to AVS/Express and exit after all other processes detach from AVS/Express. The main process serves as a hub for the exchange of addresses among processes: when one process attempts to access an object in another process, it forms a direct socket connection to that process via the main process. If the processes are on different hosts and the hosts have different data formats, AVS/Express performs the required data conversions automatically.

The main process starts some processes automatically when you create objects that live in them. Other processes are started externally and attach to an existing session.

The following figure illustrates the process organization of the AVS/Express object hierarchy:

Figure J-1 .


Any AVS/Express process can initiate an operation, but the main process controls the execution of operations through an AVS/Express object called the Scheduler. The Scheduler synchronizes operations by calling push_ctx and pop_ctx routines to push and pop contexts for them on a stack (see Contexts on page 8-11 for details). Only a single push_ctx call can be active at one time: if the Scheduler has an outstanding push_ctx call and receives another, it queues the additional push_ctx call. The process that initiated the queued push_ctx call waits on the current push_ctx call until it completes with a pop_ctx call.

AVS/Express provides a definition of a default C main in the library -lmnc and a definition of a default C++ main in the library -lmncxx. By default, these libraries are included on the link line of any process that is constructed through an AVS/Express compilation. Whether AVS/Express uses the C or C++ version depends on which compiler it uses to compile a process; this is system dependent. You can also define your own main; for details, see Defining Your Own Main Process on page 10-9.

Setting the Process Type

You use the following three environment variables to specify whether a process is the main process or an external process; that is, a process that attaches to the main process:

Table J-1
environment variable
Description
OM_BOSS
The primary socket address of the main process
OM_BOSS_2
The secondary socket address of the main process
OM_ROOT_OBJ
A text version of the Root object ID

You can define these environment variables in several ways:

process_name -server filename
For a client process, use the following option, which loads the definitions from the specified file:
process_name -client filename
This option loads the definitions.
$server_info > filename
Process Components

Each AVS/Express process has the following components:

Defining the Modules in a Process

When AVS/Express compiles a process, it generates code for two functions, PREinit and BASEinit, that AVS/Express' initialization routine calls (see Initializing AVS/Express on page 10-8 for details). At initialization, PREinit and BASEinit do the following:

The PREinit function is called before object definitions in the Templates hierarchy are defined and the BASEinit function after the Templates objects are defined but before any template objects are instanced.

You can add your own code to the PREinit and BASEinit functions by setting the properties pre_init_code (for PREinit) and init_code (for BASEinit). Each of these properties specifies C code that is added directly to PREinit or BASEinit functions (the string value for each must define a complete C statement). These functions are generated in the order in which objects appear in the Templates library, thus a particular library is defined after all of the libraries upon which it depends are defined.

Although PREinit and BASEinit are defined with C-scoped names, AVS/Express may compile them with a C++ compiler. Therefore, you must be sure that any functions called in the init_code and pre_init_code property values are declared before they are used. You can do this as follows:

For example, using V code, if the library MYLIB is included in the current process, you can call the function MYLIB_init in the BASEinit function as follows:

flibrary MYLIB<hdr_code="void MYLIB_init();",
  init_code="MYLIB_init();">;

Setting the Process Name

Each process has a name, so that AVS/Express can determine which processes are running and create the right objects in the right process. The name should correspond to the name of the object defined in the root-level ProcTemplates object (see The proc.v File on page 10-29). When AVS/Express generates a process, it sets the process name automatically by code inserted into the PREinit function; for example:

OMset_my_proc_name(OMstr_to_name("express"));

You need to set the name of a process explicitly only if you are generating your own PREinit and BASEinit functions for a process that will define local objects. In this case, you must set the name of the process to the process property value set for the objects that you will define locally.

Initializing AVS/Express

You call the OMmain_init routine (or equivalent) to initialize AVS/Express. You must make this call before you attempt to access any AVS/Express objects. Once it returns, you can create and destroy AVS/Express objects.

How OMmain_init is called varies depending on your platform. For UNIX platforms, it is called as follows:

int OMmain_init(int argc, char **argv)

For Windows platforms, it is called as follows:

int OMmain_init(HINSTANCE hInst,
      HINSTANCE hPrevInst,
     LPSTR CmdStr, int CmdShow)

These routines parse the command-line arguments that AVS/Express parses (you can disable them by passing in empty command line strings). If you have command-line arguments that your program recognizes, you should remove them from arguments that you pass to OMmain_init since the routine displays error messages about arguments that it does not recognize.

This routine returns a flag that indicates whether the -vcp or -novcp options were specified in the command-line arguments. The flag should be passed to the OMmain_loop routine to enable the functionality of these command-line arguments.

Handling Events

The following call processes events for AVS/Express processes:

OMmain_loop(int vcp_flag)

The vcp_flag argument can have one of the following three values:

Table J-2
Value
Description
OM_VCP_DEFAULT
Enables the V Command Processor for the main process and disable it for other processes
OM_VCP_SUPPRESS
Always suppresses the V Command Processor for the specified process
OM_VCP_PRESENT
Always enables the V Command Processor for the specified process

Defining Your Own Main Process

As noted previously, AVS/Express provides definitions of default C and C++ main processes in the libraries -lmnc and -lmncxx, respectively, and includes these libraries on the link line of any process that it compiles. If you define your own main for a particular process, you must disable the use of the default main processes as follows:

See Providing Code Management Information on page 8-28.

Be sure to supply your definition in the correct language for your process. On UNIX systems, AVS/Express links your process with the C++ compiler if any objects in the process need C++, otherwise it links with the C compiler. If you are not certain which compiler your system uses, supply your definition of the main process in a C++ source file to force the use of C++ for the link.

The rest of this section discusses topics relevant to defining your own main process.

Using the UNIX XtEvent Dispatch Facilities

On UNIX systems, you can configure your main process to use the standard Xt event dispatch facilities (for example, XtAppMainLoop, XtAppNextEvent, or XtAppProcessEvent) instead of the routine OMmain_loop. Doing this makes it easer to integrate AVS/Express objects into existing Motif/Xt based applications. See your platform documentation for information on the XT event dispatch facilities.

In order to take advantage of this facility, you must do the following:

1. Place a call to the function EVXinit_display_xt() for each Display used in your program. This function is declared as follows:
void EVXinit_display_xt(Display *display)
To include a definition of this function in your main, include the header file avs/event_x.h in your program as follows:
#include <avs/event_x.h>
You must place this call after you open the display but before you enter the event dispatch loop of your program; that is, before you call XtAppMainLoop, XtAppNextEvent or XtAppProcessEvent.
2. Define your own main loop, bypassing the AVS/Express main loop. Doing this prevents you from using the V Command Processor (VCP) from within this process. However, you can start up the VCP in another process that manipulates objects in the current process as follows:
a. Start your main process with the -server /tmp/file option, as follows:
% express -server /tmp/file
b. In another window, enter the following command:
% base -client /tmp/file -vcp
The VCP available in the shell started by the base command can manipulate objects in your express process.

If you intend to use UI Kit objects in your application, you must ensure that your code and the UI Kit code share only a single XtAppContext. Currently, the only way to do this is to obtain the Widget pointer from the handle.widget subobject of a UI object used in your application. From this Widget pointer, you can use the XtWidgetToApplicationContext and XtDisplay functions to access the XtAppContext and the Display:

Example

This example illustrates how to create a dummy shell object outside of the express project mechanism, obtain a Widget pointer from that object, and perform an EVXinit_display_xt call. It uses the example source code that follows the set of instructions.

1. Save the example source code at the end of this section (see Example Source Code) into your project directory in a file called xtmain.cxx.
2. Create a file called dummy.v and enter the following line into it:
module dummy<no_main=1,cxx_src_files="xtmain.cxx">;
3. Select the Workspace_1 object (or any library that defines objects for the express process) for dummy.v.
4. In the Network Editor, select Objects->Load Objects.
5. In the Network Editor, select Project->Compile.

The resulting express process uses the xtmain.cxx file as its main program.

Example Source Code
---- xtmain.cxx:
#include <stdlib.h>
#include <avs/om.h>
#include <avs/event_x.h>
#include <X11/Intrinsic.h>

void
main (int argc, char **argv)
{
   int vcp;
   OMobj_id shell_id, widget_id, macro;
   Widget widget;

   vcp = OMmain_init(argc, argv);

   OMpush_ctx(OMroot_obj,0,0,0);
   macro = OMcreate_obj_from_path("macro", "my_macro", OMinst_obj);
   shell_id = OMcreate_obj_from_path("UIshell", "xt_shell", macro);
   OMset_name_int_val(shell_id, OMstr_to_name("visible"), 0);
   OMpop_ctx(OMroot_obj);

   widget_id= OMfind_str_subobj(shell_id,"handle.widget",OM_OBJ_RD);
   if (OMget_ptr_val(widget_id, (void **)&widget, 0) != 1)
      widget = NULL;
   if (widget == NULL) {
      fprintf(stderr,"can't get widget\n");
      exit(-1);
   }

   EVXinit_display_xt(XtDisplay(widget));

   XtAppMainLoop(XtWidgetToApplicationContext(widget));

   OMexit(0);
}
Adding Your Own Event Handlers

When defining your own main process, you can define functions that AVS/Express will call in response to system events such as a time-out interval, an idle event, or an event on a file descriptor. You do this using the Object Manager API routine EVadd_select.

For details, see the reference description of EVadd_select in the AVS/Express online help.

Exiting Processes

There are two ways to make a process exit.

OMexit(int status)
The process that issues this call exits using the exit system call with the status code provided as the first argument.
OMprocess_exit(OMproc_id proc_id, int status)
The process specified by the proc_id argument exits with the status specified by the status argument. This call is most useful when you want an external process to make the main process exit. Note that the process ID of the main process is always 0.

For details, see C and C++ API Routines on page 9-5 and the reference descriptions of these routines in the AVS/Express online help.

Defining Processes for Objects

Each template object in AVS/Express belongs to exactly one process. The process for an object is set using the process property, which specifies the string name of an object defined in the root-level ProcTemplates object (see The proc.v File on page 10-29). This property is inherited as you move down the object hierarchy: if it is set on a library, each module in the library is placed in the specified process unless you override this value by setting the process property on the module itself to another process). If process property is unset for both an object and its parent, the object is placed in the default process, which is the first process in the ProcTemplates list (by default, the express process).

The following rules specify in more detail how the process for a particular object is set. Note that the order of these rules is significant: the first rule that applies to the object is used to set its process.

1. If the process property is set on the object itself or the template object from which it was created, the object is placed in the specified process.
2. If the process property is set on an ancestor of the object, the object is placed in the specified process.
3. If the process is set on an ancestor of a template object from which the object was created, the object is placed in the specified process.
4. If the process is unset for any of the preceding, the object is placed in the default process.

The following diagrams illustrate these rules. In each figure, the circles represent objects in the Templates hierarchy, belonging to processes as noted in the key.

Figure J-2


If the library that contains C and D is given an explicit process setting, C no longer inherits the process from its superclass B and is instead assigned to the process of its parent.

Figure J-3


Note that when you change the process on an object, you must recompile the affected processes:

See the next section, Compiling Projects and Processes, for details.

Creating New Processes

As noted previously, a project comes with an express process and a base internal bootstrap process, and user processes are created as needed for objects (see Defining Processes for Objects on page 10-12). Using the VCP, you can also create additional processes as needed while running AVS/Express, by inserting them into the root-level ProcTemplates object in which processes are defined (see The proc.v File on page 10-29).

To create a new process, enter the VCP window and navigate to the ProcTemplates object, then define your new process as in the following example:

OM(Root) -> ProcTemplates {
OM(Root) ->    process new_process_name;

When you save the project that contains this new process, your new proc.v file looks like the following:

"$XP_PATH<0>/v/proc.v" ProcTemplates {
process new_process_name;
};

When you compile this process, AVS/Express generates filenames with your process name as the identifier. Advanced Visual Systems recommends that you assign process names that have fewer than seven characters, in order to avoid problems on machines that limit filenames to eight or fewer characters.

Compiling Projects and Processes

You must compile an AVS/Express process to use the objects it defines. The simplest way to compile a single, specific process other than the express process is from within AVS/Express. Using information that you supply-source filenames, library dependencies, process name-AVS/Express compiles the process by constructing a makefile and, if possible, executes it. (If necessary, AVS/Express also generates source files that contain prototype source code for methods.) On most platforms, AVS/Express compiles a process dynamically, to make use of shared AVS/Express libraries. The next subsections describe compiling with shared libraries and compiling a single, nonexpress process.

Note that you cannot compile either of the following from within AVS/Express:

You must perform these compilations from outside AVS/Express, as described later in this section; however, both use AVS/Express-supplied compile functionality to simplify the task.

You can choose to compile a process manually without using AVS/Express compile functionality of any kind; however, this is a complicated task because you must perform independently each of the tasks that an AVS/Express compilation performs for you.

Compiling with Shared Libraries

Shared libraries offers several notable benefits, including smaller executable size and drastically reduced link times when relinking your processes. AVS/Express uses shared libraries on all platforms except AIX, Windows NT, and Windows 95. You use shared libraries by dynamically linking to them (the default) at compile time.

Advanced Visual Systems recommends that if your platform supports shared libraries, you use dynamic linking. However, you can use static linking (as described later in this section), in which case your application is no longer dependent on AVS/Express external libraries.

Dynamic Linking

Dynamic linking is the default behavior. If a dynamically linked application references the libmods.so or libmods.sl shared library, AVS/Express dynamically loads the image file reader and writer libraries, contained in the libmods.a library archive.

Static Linking

Static linking, which you must set explicitly, enables you to avoid using shared libraries at compile and/or link time. To do this, you set the NO_DLLIBS environment variable to a nonzero value for the make process (the recommended values are t or l). When you do this, the AVS/Express shared libraries are neither generated when compiling nor included on the link line when linking, and your process is linked with static libraries instead.

You can set NO_DLLIBS in any of the following ways:

% make -f express.mk NO_DLLIBS=t relink
Compiling a Single External Process

Compiling a single process other than express from within AVS/Express is a straightforward procedure that consists of the following steps:

1. (Optional) Save your project.
2. Select an object in the process that you want to compile.
3. Select the Project->Compile command.

AVS/Express executes the compilation by performing the following tasks:

1. Create a makefile for the process and place it in your project directory.
AVS/Express creates the makefile by navigating all branches of the object hierarchy under Templates, except where it finds the compile_subs=0 property, looking for objects that are part of the process being compiled. The makefile is called process_name.mk. If a file by this name already exists in your project directory, AVS/Express removes it and creates a new one.
While creating the makefile, AVS/Express sends informational and error messages, if any, to the startup window (in which the V Command Processor appears).
2. Generate the files process_name.c, xprocessname.cxx and process_name.h and place them in your project directory.
3. If a method's source file does not exist and the method specifies the src_file property, generate template source files.
See Writing Target Functions on page 8-15 for details.
4. If necessary, generate wrapper code for encapsulating structures and functions.
See Introduction on page 9-2 for details.
5. If the process to be compiled is not running, execute the make program on its makefile.
When AVS/Express runs make on the makefile, it pops up a window in which to display any compile-time messages.
6. If the make is successful, place the resulting executable in a machine-specific subdirectory of your project's bin directory.
7. On Windows platforms, AVS/Express creates .dsp and .dsw files for use by Microsoft Developer Studio. These files can be used to recompile or debug the project.

For a description of error messages that may appear during this procedure, see Common Error Messages on page 10-20.

Compiling the Express Process

Because you cannot compile a process while it is executing, you cannot compile the express process from within AVS/Express. Instead, you compile it as follows:

1. Run Project->Compile. As for a single nonexpress process, AVS/Express prepares a makefile named express.mk for the express process and places it in your project directory. However, because the express process is running, it does not run a make on the makefile. On Windows, AVS/Express also creates Microsoft Developer Studio project files express.dsp and express.dsw.
2. Save your project if you have not already done so.
3. Exit AVS/Express.
4. Change your current directory to your project directory.
5. Run make on the express makefile by entering the following (On Unix):
% make -f express.mk

Run make on the express makefile by entering the following (On Windows):

> nmake -f express.mk
6. On Windows you can also compile (and debug) by using the Microsoft Developer Studio project files.

Note: Once the express process compiles, be sure to run the express process that you just compiled rather than the express process in the AVS/Express install directory.
Compiling All Processes

With one exception, you can compile at one time all processes in your project (as defined in the root-level ProcTemplates object; see The proc.v File on page 10-29). The exception is that you cannot include the base internal bootstrap process, because you use it to perform the multiprocess compilation, as follows:

1. Exit AVS/Express.
2. Enter the following command:
% base -compile -exit

Note that you can also use the base process to build a specific process from outside of AVS/Express as follows:

% base -comp_proc process_name -exit

Your XP_PATH environment variable must be set properly (for example, through the avsenv file) for this to work.

For details see The avsenv File on page 10-26.

You can gain further control over the compilation process by separating the code generation steps and the actual compilation.

% base -gen_proc process_name -exit
% make -f process_name.mk

This can save time when you are working on C/C++/FORTRAN code of a project, but not changing the V code. You can recompile the project without repeating the code generation process.

Debugging with Microsoft Developer Studio.

If you are working on Windows, you will probably use the debugger integrated into Microsoft Developer Studio to debug your project.

You can start Microsoft Developer Studio by clicking on the .dsw file that AVS/Express generates.




You can also start Microsoft Developer Studio from the command line. First change directory so that the the current working directory is the same as the root of the project directory.

> msdev express.dsw

Alternatively you can bypass the autogenerated project files and start up Microsoft Developer Studio directory on the express executable

> msdev bin\pc\express.exe

No matter how you start up Microsoft Developer Studio you will see to set the Working directory. Go to the Debug tab of the

Project->Setting control panel, and set the Working directory to the root of the project directory.



Common Error Messages

This section describes common error messages that AVS/Express may return when you use it to compile a process.

The following error message may appear in the startup window when you compile a process:

This message means that AVS/Express has created the makefile for this process, but cannot run a make on it because the specified process is currently executing. AVS/Express typically returns this message in the following circumstances:
  • When you compile the express process from within AVS/Express
  • When you compile an external process (for example, user) while it is running; that is, you instanced and compiled an object in a running process

The following types of error messages may appear in a popup window while the makefile is being processed. (The actual message text depends on the operating system.)

This message, from the linker, indicates that a required function is missing.
  • If the undefined function belongs to an object that you added, this message may mean that you did not set a c_src_files (or similar) property.
  • If the undefined function belongs to an object in one of AVS/Express' kits, your objects may have a dependency that you did not account for by setting the libdeps property.
See Providing Code Management Information on page 8-28.
You are compiling a function that receives pointers to a C structure that you have defined and to a bitmask structure generated by AVS/Express. The generated file includes the header file where your C structure is defined, so you do not have to include it again in the function's source file.
10.3 AVS/Express Code Generation

This section provides detailed information about certain aspects of AVS/Express process compilation. You do not need this information for relatively straightforward compilations, but it may be helpful when you implement and debug more complex projects.

The AVS/Express compilation process contains two main stages: code generation and process build.

This section provides detailed information about the code generation process. For information about the process build, see the make command documentation available with your system.

Marking Needed Objects

In Pass 1, AVS/Express determines what objects belong in what processes, using the rules discussed in Defining Processes for Objects on page 10-12, and marks the objects needed by the process to be compiled. When AVS/Express marks an object as needed, it also marks the containing library. For example, if the process needs the UIbutton object, AVS/Express marks both this object and the UI library that contains it. Note that other objects in a marked library (for example, UIshell in the UI library) are marked only if the project specifically needs them. To continue the previous example, AVS/Express marks UIshell, another object in the UI library, only if it is needed.

Note that if you compile using Project->Save Compiled Project instead of Project->Compile, this pass is modified so that only the objects that select are marked as needed. As a result, the process contains only a subset of the objects defined for this process in templ.v, and templ.v is not explicitly modified.

Two properties affect the way in which objects are marked as needed:

Library Dependencies

The libdeps property takes a list of names of AVS/Express template objects. In its object-marking pass, AVS/Express marks these objects but not their subobjects as needed by the process. This property is useful for guaranteeing that AVS/Express marks the link files specified by one library whenever another library is needed by a process. This is necessary only when those AVS/Express objects do not express this dependency directly.

For example, if you define a library that calls the FLD library but does not contain any FLD objects, AVS/Express may report that the FLD routines are undefined when you link. To fix this problem, set the libdeps property as follows to indicate this dependency:

library MY_LIB<libdeps="FLD">;
Dynamic Object Dependencies

The need_objs property also takes a list of AVS/Express objects. In its object-marking pass, AVS/Express marks these objects and their subobjects as needed by the process. You set this property on a module that creates objects dynamically to ensure that AVS/Express places them in any compiled project that contains the module.

For example, if you write a module that dynamically creates a UIbutton object and include the module in a compiled project, AVS/Express may report that the UIbutton object was not included in your project. To fix this problem, set the need_objs property as follows to indicate this dependency:

module my_module<need_objs="UIbutton"> { ...
Generating Code

During the code generation stage, AVS/Express generates initialization code, header definitions, source definitions, and the process makefile.

In Pass 2, AVS/Express generates code for objects marked as needed during Pass 1; specifically:

The Build Directory

The build_dir property specifies the build directory for an object and its subobjects. If this property is specified with a relative pathname, it is taken to be relative to the project directory. If the build_dir property is unset for an object or its ancestor, AVS/Express uses the project directory as the build directory.

All build files processed for an object and its subobjects are taken to be relative to the current build directory. T his includes values taken from the c_hdr_files, cxx_hdr_files, c_src_files, cxx_src_files, src_files, and link_files properties.

Source Files

The c_src_files and cxx_src_files properties specify one or more source files required for processes that need this object. AVS/Express addes rules for constructing object files from the source files to the process makefile and adds the resulting object files to the link line for the process. (Recall that these files are specified relative to the current build directory.) If a process needs an object for which the cxx_src_files property is set, AVS/Express uses the C++ linker to link that process.

The src_file property also specifies one or more source files. It implements similar logic on its arguments except that it determines the language of the files from the filename suffixes. The omethod and cxxmethod base types also use current value of the src_file property to determine whether to generate target-function prototypes (see Target Functions on page 8-15 for details). You can turn off prototype generation by setting the use_src_file property to 0 on an object for which the src_file property is set.

Header Files

The c_hdr_files and cxx_hdr_files properties specify one or more header files that contain the definitions needed to compile this object or its subobjects. Setting these properties puts an #include statement in the file that contains generated header definitions for this object, either the file specified by the out_hdr_file property, or the default file process_name.h if out_hdr_file is unset.

If AVS/Express can find an absolute path to each header file (recall that it looks relative to the current build directory), it adds the files to a list used to generate makefile dependencies for object files in this process. If it cannot find the header files, it includes them using a pathname specified specified from the property definition. AVS/Express does not treat this behavior as an error, nonetheless this does not generate proper dependencies.

Microsoft Developer Studio Project Files

On Windows, AVS/Express creates .dsp and .dws files for use by Microsoft Developer Studio. You can use these to recompile or debug the project.

10.4 Projects

AVS/Express project architecture is accessible to all users, and all users will find the discussion of project architecture in this section useful. Only Developer Edition users can generate runtime projects. An AVS/Express user who thoroughly understands project architecture can use AVS/Express to create more sophisticated projects; for example:

This section describes AVS/Express project architecture, then (for Developer Edition users) explains how to use Save Compiled Project to save a runtime project.

Project Architecture

A project is based in a project directory. The project directory hierarchy contains all of the files and directories required by the project. At absolute minimum, it contains a directory called v, which contains the v files needed for the project. However, it typically contains much more than a v directory, including files and directories such as the following:

AVS/Express may generate some of these files and directories as needed, and you may supply others. The following sections do not describe all of a project's possible files and directories, but do discuss typical components.

The avsenv File

The avsenv file contains environment-variable definitions. AVS/Express generates an avsenv file in your project directory whenever you create or save a project; for example:

#   WARNING: this file is program generated.
#   Remove these two lines to protect the file from overwrites.
XP_PATH=/home/users/me/proj1 /home/express

In this example:

You can modify an avsenv file by adding environment variable definitions as required; they take effect for AVS/Express only. If you do modify this file, be sure to remove the first two lines so that AVS/Express does not regenerate the file, thus removing your modifications, the next time you save the project.

Whenever AVS/Express starts up, it looks for an avsenv file in the following places in the order listed, and uses the first file it finds:

The XP_PATH Environment Variable

A particularly important environment variable-one required by AVS/Express whenever it starts up-is XP_PATH. The value of this environment variable is a list of project directories, specified as absolute pathnames; for example (from the previous avsenv file):

XP_PATH=/home/users/me/proj1 /home/express

Your project's directory (if any) should be specified first, followed by the install area project's directory.

Whenever AVS/Express starts up, it looks for an definition of XP_PATH in the following places in the order listed, and uses the first definition it finds:

% express -path "/home/users/me/proj1 /home/express"
% setenv XP_PATH "/home/users/me/proj1 /home/express"

If AVS/Express does not find a definition, it sets XP_PATH to the directory two levels above the executable's directory. For example, if the executable is in the directory /home/express/bin/hp, AVS/Express sets XP_PATH to /home/express.

Note that when you refer to the XP_PATH environment variable in V code, you can supply an index value to indicate a particular project directory in its list. This usage has the following format:

$XP_PATH<n>

Indexes for project directories in the XP_PATH list begin with 0 for the rightmost directory and increase by 1 as you move to the left. Recall the previous example:

XP_PATH=/home/users/me/proj1 /home/express

In this definition, $XP_PATH<0> refers to /home/express and $XP_PATH<1> refers to /home/users/me/proj1.

The templ.v File

The templ.v file, a V file located in the v directory, defines the contents of the Templates library which, in turn, defines all of the templates from which you can create new objects. For example:

"$XP_PATH<0>/v/templ.v" Templates {
flibrary MYLIB {
module my_module {
int p1;
omethod+notify+read update = "my_module_update";
};
};
};

The first line in this file (following) creates your project's Templates library:

"$XP_PATH<0>/v/templ.v" Templates {

Observe that the type of Templates is a filename. The $XP_PATH<0> component of the name refers to the rightmost path in XP_PATH, typically the install directory. Therefore, the entire name, $XP_PATH<0>/v/templ.v, refers to the install area project's templ.v file. As a result, the Templates library for your project begins with all of the objects in the install area project.

The subsequent lines define additions and modifications for your project. In this example, the project contains an additional library named MYLIB and and a simple module named named my_module that is defined in that library.

The proc.v File

The proc.v file, a V file located in the v directory, creates a root-level object called ProcTemplates that defines a project's processes. The relevant (noncomment) portion of the install area project's proc.v file is as follows :

group ProcTemplates {
process express;
process user;
process base;
};

The project consists of three processes named as express, user, and base. The executable is given the same name as the name of the process object.

Here is a version of proc.v as it might appear in your project directory:

"$XP_PATH<0>/v/proc.v" ProcTemplates {
process myproc;
};

Observe that the type of ProcTemplates is a filename. The $XP_PATH<0> component of the name refers to the rightmost path in XP_PATH, typically the install directory. Therefore, the entire name, $XP_PATH<0>/v/proc.v, refers to the install area project's proc.v file. As a result, the ProcTemplates object for your project starts off with all of the processes of the install area project. You can manually insert additional lines to create additional processes; for example:

"$XP_PATH<0>/v/proc.v" ProcTemplates<NEvisible=0> {
process myproc<path_name="myproc";
};
Network Editor Library Files

Two V files in the V directory contain information that defines the Network Editor libraries.

For more information on libraries, see Understanding Libraries on page 5-11

Saving Compiled Projects (Generating a Runtime Project)
Note: The information in this section is relevant only to Developer Edition users. Visualization Edition users cannot use the Save Compiled Project command.

The default AVS/Express environment provides access to a large number of objects in the application development process. The Developer Edition of AVS/Express provides a feature, implemented as the Save Compiled Project command, that you can use to generate a project containing a subset of the objects used in the base project. There are two main advantages to using this feature:

You should consider streamlining a project with Save Compiled Project in the following circumstances:

Whenever you use the compiled project capability of this command, AVS/Express creates a separate project directory that contains local versions of the make files and configuration files that it generates for the project. This project directory also contains a local version of each AVS/Express executable needed by the objects contained in the compiled project.

The Save Compiled Project Command

The Save Compiled Project command is available on the Network Editor's Project menu. Selecting Project->Save Compiled opens the following dialog box:

Figure J-1


As illustrated in this figure, there are three sets of controls in the Save Compiled Project dialog box:

Project Directory Selection Controls

You use the project directory controls to specify the directory for the compiled project. You can specify either a new directory or an existing directory. In the latter case, if the directory already contains a project, the new project replaces the previous project. You specify the directory either by typing its name into the text box or selecting the Browser button and navigating to it in the file-browser dialog box that opens.

There is directory, called runtime, under the "compiled project directory". The dictionary files for different languages are copied into this directory. Any files necessary for executing the runtime will be copied automatically into this sub-directory.

This used to be a manual process in Release 3.0; it is now automated in Release 4.0

Object Selection Controls

You use the object selection controls to specify the core set of objects that the compiled project will contain. You can choose either of two objection-selection modes:

In addition to the core set of objects specified by your choice of mode, AVS/Express automatically includes any objects that the core set of objects need. For example:

Option Controls

The operation selection controls specify a number of operations that the command can perform when it executes. These operations are as follows:

This option controls whether or not AVS/Express automatically instances the objects selected for the compiled project operation when it starts up the main (express) process.
  • Check it if you are using AVS/Express to generate a compiled project from a single object that contains the entire definition of the object.
  • Uncheck it if your program dynamically creates the AVS/Express objects itself, or the objects you selected are libraries (it does not make sense to instance a library of objects).
This option controls whether the Network Editor is a part of the compiled project.
  • Check it to include the Network Editor.
  • Uncheck it to exclude the Network Editor.
If you include the Network Editor, it is instanced when the main (express) process of your project is executed, just as in a normal AVS/Express session. As usual, the default creation of the Network Editor can be disabled with the -none command line option.
Since your project will contain only a compilation of system objects, the organization of the Libraries object in the Network Editor must also display a subset of the objects in the system. The current version of AVS/Express does not perform a subset operation on the existing Libraries organization for you. Instead, it creates a default v/libs.v file that displays the contents of the Templates object only. This display lists all of the libraries that are included in AVS/Express but in a very raw form. In order to get a better libraries organization, you must create your own customized v/libs.v file.
As noted previously, the Save Compiled Project command generates a single binary V file that contains the definitions of all objects needed to implement the selected set of objects. This option controls whether the V definitions are stored in a separate binary V file that is loaded when the main (express) process is started or the binary V file is directly linked into the executable of the main process.
  • Check it to link the binary V file linked into the executable of the main process.
  • Uncheck it to store the V definitions in a separate binary V file that is loaded when the main process is started.
If you select this option (that is, link the binary V file into the executable), you can produce a single standalone executable file with which to deploy the application. Note, however, that any runtime files needed by any objects that the compiled project uses are still required; for example, the runtime files that are required to use the Network Editor in an application.
There are some drawbacks to selecting this option:
  • Linking the binary V file into the executable takes longer than storing it in a separate file.
  • You must always relink the executable if you change the project. With a separate binary V file, you can make changes to the project that require only updating the binary V file rather than relinking and rebuilding the project.
This option controls the building of the project's exexcutable. This is on as a default.
This option automaticaly generates wrapper code for the project. This is on as a default.
"Save Compiled Project" Dialog Error Messages
Compile Diagnostics

Diagnostics are available when you select Project->Compile.

You may see a warning message if you copied methods from the "Standard Objects" page but did not provide a new function value to replace the default method value (OMomethod_unset, OMmethod_unset, OMcmethod_unset).

This warning message can be ignored, but it provides the name of the methods that are not functional in your system.

You can eliminate the extra warning message by setting the method value to a valid function name or deleting the method from your Templates library. If you want to "deactivate" the object that this method belongs to, you can set the "compile_subs" property to 0.

Dependencies on the Original Project

When AVS/Express compiles a project, it chains it off the project directories of the original project; that is, the project that was active at compilation time. You can determine which project directories were used to create the new project by reviewing the avsenv file in the new project directory. The compiled project uses libraries and object files from these other project directories when its executable is being linked; therefore, you must also compile these other projects if they define any new code that the compiled project uses.

Files in a Compiled Project

The following figure illustrates the files generated when you execute Save Compiled Project command with the Generate source option checked.

Figure J-2


These directories and files are as follows:

A machine-specific subdirectory of this directory contains the object files compiled for this project. None of the files in this subdirectory tree are necessary to run an application built with this project. On UNIX machines, you can obtain the value of the $MACHINE variable for a particular platform by running the xp_mach shell script. On Windows machines, this value is always pc.
This file, generated if you compiled the project with the Build V into executable option turned off, contains the V definitions for the compiled project. It is required for running applications built from the project, and must be located in the v subdirectory of XP_PATH when you run the project.
See Build V definition into executable on page 10-33.
This file is generated if you compiled the project with the Include network editor in project option turned on. The file is a simple prototype that you can replace by a custom version.
See Include network editor in project on page 10-32.
A machine-specific subdirectory of this directory contains contains all of the process executables necessary to run this project. On UNIX machines, you can obtain the value of the $MACHINE variable for a particular platform by running the xp_mach shell script. On Windows machines, this value is always pc.
These files are generated for each process used by the compiled project. They are necessary only for compiling the project, not for running applications built with it.
This file stores the value of the XP_PATH variable used to construct the project. It is necessary for compiling the project and is necessary to run the project if any of the components it uses rely on any files stored relative to XP_PATH.
This source file, generated if you compiled the project with the Build V into executable option turned on, contains a hexadecimal description of the binary V description for the objects used by the project. It is necessary for compiling the project but not for running it.

There is a subdirectory of the Compiled Project Directory called runtime. The dictionary files for different languages are copied into this directory , and any files necessary for executing the runtime will be copied automatically into this subdirectory.

Examples of Save Compile Project

The examples in this section illustrate uses of the Save Compiled Project command.

Example 1

In this example, imagine that you have produced an application that is entirely represented using an AVS/Express network, and it is running as the current application. You now want to produce a version of this application that runs more efficiently and is easier to hand over to another user. To do this:

1. Select the Project->Save Compiled Project... command. The Compiled Project Dialog box opens.
2. Enter the name of the directory to create for the compiled project.
3. Select the Save current application option: the current application is the only object you need in the compiled project.
4. Deselect the Include network editor in project option: the user of this application will not be editing it.
5. Select or deselect Build V into executable (either is appropriate for this project).
6. Select Compile Project.
7. Select Generate Source.
8. Click on OK.
Example 2

In this example, imagine that you have constructed an application that dynamically creates and modifies AVS/Express networks: specifically, it dynamically creates objects from the Data Visualization and the Graphics Display kits. You now want to deploy a more efficient version of this application to a set of users. To do this:

1. Select the Templates library from the Libraries combo box in the Network Editor.
2. Scroll to and select the DV icon.
3. Scroll to and shift-select the GD icon. Both DV and GD should now be selected.
4. Select the Project->Save Compiled Project... command. The Compiled Project Dialog box opens.
5. Enter the name of the directory to create for the compiled project.
6. Select the Save selected objects option: you want to save the objects you have selected in the compiled project.
7. Deselect the Include network editor in project option: the user of this application will not be editing it.
8. Select or deselect Build V into executable (either is appropriate for this project).
9. Select Compile Project.
10. Select Generate Source.
11. Click on OK.
10.5 Integrating with a Microsoft Foundation Class (MFC) Application

The following procedure explains how use AVS/Express and Microsoft Visual C++ to create a simple multiple-document interface (MDI) application that allows you to read AVS/Express geometry files and display them. The application that you will be creating is called Geomview. The file that you will access while creating this application is:

<install_dir>\tutor\mfc\geomview.v

where <install_dir> is the directory in which AVS/Express is installed.

All of the steps that you perform in this procedure are specific to building the Geomview application, however, the steps can be adjusted and the concepts can be applied to developing similar types of applications.

The application is created as follows:

1. Start AVS/Express.
n Choose "None" when asked for the initial application type.
2. Select Templates from the Libraries combo box.


3. Make the Templates library the selected object by clicking on its border.


Notice that the border around the various sublibraries is highlighted.
4. Select Object->Load Objects and load the following V code:
<install_dir>\tutor\mfc\geomview.v
5. Select Project->Configure.
a. When the dialog box is displayed, disable the Annotation and Graphing Kit, the Print Renderer, the VRML Renderer, and the VPS Renderer.
6. Drag the scrollbar at the bottom of the Libraries.Templates object all the way to the right, so the GEOMVIEW object becomes visible.
7. Highlight the Libraries.Templates.GEOMVIEW object by clicking on it.


8. Select Project->Save Compiled Project.
a. Specify a new project directory.
b. Turn off the following toggles:
Instance objects automatically on restore
Build project's executable
c. Press OK.
9. After the compiled project has been generated, exit from AVS/Express and start Microsoft Developer Studio.
Creating a Project with Microsoft Developer Studio

The following steps are performed using Microsoft Developer Studio.

1. Select File->New
2. The New Project Workspace dialog box appears. Select the Projects tab if it is not already selected.
3. Select MFC AppWizard (.exe) from the list of project workspace types.
4. Enter a name for your project.
Note: This tutorial assumes that the project is called "geomview". If you choose a different name, you will need to make the necessary adjustments as you complete the steps.
5. Press OK.
The MFC AppWizard appears.
6. Click Next on pages 1, 2, and 3 of the MFC AppWizard, since you will be using the default settings for these steps.
7. On page 4 of the MFC AppWizard,
a. Turn off the Printing and print preview option.
b. Select the Advanced... button.
c. Set the File extension to geo.
8. Click Close on the Advanced dialog box.
9. Click Next to step through pages 5 and 6 of the MFC AppWizard.
10. Click Finish to finish up with the MFC AppWizard.
After you are done with the MFC AppWizard, the project directory will be created.
11. Copy the following files to the MFC AppWizard-created geomview project directory from the compiled project directory that you generated using AVS/Express:
geomviewOMX.cxx
geomviewOMX.h
express.c
express.h
v\appl.vo
xexpress.cxx
Note that the appl.vo file should be placed directly into your geomview project directory; there is no need to create a v subdirectory.
12. Optionally, use a text editor to examine the file express.dsp from the compiled project directory.
Examine the file looking for lines that start with:
#ADD LINK32_OBJS
The libraries and files listed on these lines should match the list of files you will be specifying later when you change your project settings.

13. In your geomview project directory, create a file called avsenv, and enter the information for setting the XP_PATH variable so that it indicates the name of your project directory.
For example, if your project directory is c:\projects\geomview, your avsenv file should contain the following line:
XP_PATH=c:\projects\geomview
14. Using Project->Add to Project->Files, insert the following files into your project:
geomviewOMX.cxx
express.c
xexpress.cxx
Changing the Project Settings
Note: The instructions below assume that AVS/Express is installed in C:\express. Be sure to substitute the appropriate installation directory when assigning your project settings.
1. Select Project->Settings to display the Project Settings dialog box. In the "Settings for:" list box on the left side of the dialog, make sure "All Configurations" is selected.
2. Go to the C/C++ tab.
a. In the "General" category, add the preprocessor definition MSDOS to the end of the list of existing definitions.
b. In the "Precompiled Headers" category, select the "Not using precompiled headers" toggle.
c. In the "Preprocessor" category, add the following entries to the "Additional include directories:" text field:
C:\express\include,C:\express
d. Go to the Link tab, and specify the following files as Object/library modules:
/libpath:C:\Express\lib\pc
/libpath:C:\Express\lib\pc\om
/libpath:C:\Express\lib\pc\pal
/libpath:C:\Express\lib\pc\fld
/libpath:C:\Express\lib\pc\nt_ui
lib_vers.obj xp_init.obj uci_pal.obj Xfld.obj UIcursor.obj UIcursoP.obj ui_gen.obj
libacvt.a libgeom.a libutil.a libgdogl.a libgdsw.a libgd.a libmutil.a libvxbx.a libui.a libcxxut.a libpal.a libdmap.a libdbxx.a libgmod.a libwtobj.a express.lib wsock32.lib
Note: This needs to be entered as one long line in the typein window.
3. Go back to the C/C++ tab and the General category.
a. In the "Settings for:" list box on the left side of the dialog box, change the selection so that only the Debug version of the project is selected.
b. Remove the _DEBUG preprocessor directive.
c. Change the /MDd flag in the Project Options area to /MD.

You are now finished with the Project Settings dialog box.

Adding Required Code and Methods
1. Add the following line to geomview.h:
#include "express.h"
2. Add the following line immediately before the final return statement in the code for CGeomviewApp::InitInstance in geomview.cpp:
OMmain_init(m_hInstance, m_hPrevInstance,
"Debug\\geomview -novcp", SW_SHOWNORMAL);
3. Add the following protected class member to CGeomviewDoc in geomviewDoc.h:
CGeomFileReader *m_reader;
4. Add the following public class method to CGeomviewDoc:
CGeomFileReader *GetReader() { return(m_reader); }
5. Using the ClassWizard (View->ClassWizard), add the OnOpenDocument and OnCloseDocument messages to the CGeomviewDoc class.
6. Add the following code to CGeomviewDoc's constructor:
m_reader = NULL;
7. Add the following code to CGeomviewDoc::OnOpenDocument in geomviewdoc.cpp:
m_reader = new CGeomFileReader;
m_reader->push_ctx();
m_reader->filename = lpszPathName;
m_reader->pop_ctx();
8. Add the following code to CGeomviewDoc::OnCloseDocument:
delete m_reader;
9. Add the following protected class member to CGeomviewView in geomviewView.h:
C3DViewer *m_viewer;
10. Using ClassWizard, add the OnInitialUpdate, PostNcDestroy, WM_LBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP, and WM_SIZE messages to the CGeomviewView class.
11. Add the following code to CGeomviewView's constructor in geomviewView.cpp:
m_viewer = NULL;
12. Add the following code to CGeomviewView::OnDraw:
if (m_viewer) {
m_viewer->push_ctx();
m_viewer->event = 3;
m_viewer->pop_ctx();
}
13. Add the following code to CGeomviewView::OnInitialUpdate:
CGeomviewDoc *pDoc = GetDocument();
CGeomFileReader *reader = pDoc->GetReader();
if (!reader) return;
m_viewer = new C3DViewer;
if (OMadd_obj_ref((OMobj_id) m_viewer->objs,
(OMobj_id) reader->obj, 0) != OM_STAT_SUCCESS) {
MessageBox("Can't connect document and view geometry objects");
return;
}
m_viewer->push_ctx();
m_viewer->window = (int) GetSafeHwnd();
m_viewer->widget = (int) GetSafeHwnd();
m_viewer->hdc = 0;
m_viewer->event = 1;
m_viewer->pop_ctx();
14. Add the following code to CGeomviewView::PostNcDestroy:
delete m_viewer;
15. Add the following code to CGeomviewView::OnLButtonDown:
if (m_viewer && GetCapture() != this) {

m_viewer->push_ctx();

if (nFlags & MK_CONTROL)
m_viewer->mode = 2;
else if (nFlags & MK_SHIFT)
m_viewer->mode = 1;
else
m_viewer->mode = 0;

m_viewer->x = (int) point.x;
m_viewer->y = (int) point.y;
m_viewer->state = 1;
m_viewer->time = (int) GetCurrentTime();
m_viewer->pop_ctx();

SetCapture();
}
16. Add the following code to CGeomviewView::OnLButtonUp:
if (GetCapture() == this) {
ReleaseCapture();
m_viewer->push_ctx();
m_viewer->x = (int) point.x;
m_viewer->y = (int) point.y;
m_viewer->state = 3;
m_viewer->time = (int) GetCurrentTime();
m_viewer->pop_ctx();
}
17. Add the following code to CGeomviewView::OnMouseMove:
if (GetCapture() == this) {
m_viewer->push_ctx();
m_viewer->x = (int) point.x;
m_viewer->y = (int) point.y;
m_viewer->state = 2;
m_viewer->time = (int) GetCurrentTime();
m_viewer->pop_ctx();
}
18. Add the following code to CGeomviewView::OnSize:
if (m_viewer) {
m_viewer->push_ctx();
m_viewer->event = 2;
m_viewer->pop_ctx();
}
19. Add the following code to CChildFrame::PreCreateWindow:
cs.cx = cs.cy = 400;
Running the Project and Displaying Data
1. Build and execute the project.
The program starts up with an initial empty view window.
2. To display some data, select File->Open and input an AVS geometry file (e.g. c:\express\data\geom\teapot.geo).
n The geometry is displayed in a new view window.

You can rotate, scale, or XY-translate the geometry using the left mouse button. To scale, hold the Shift key down while dragging. To translate, press the Control key while dragging.

If you select Window->New Window, a new view window appears, and it displays the currently selected geometry using the default transform.

If you select File->Close, the geometry for the currently selected view is deleted, and all of the geometry's view windows are closed.

10.6 Creating ActiveX Controls using AVS/Express C++ Classes using VC ++

Example : Geomview

The following procedure explains how to use AVS/Express 6.0 and Microsoft Visual C++ 6.0 to create an ActiveX Control (the technology formally known as OCX's). This is as an alternative to using AVS/Express to generate the OCX directly using the Save_Compiled_Project options. The advantages of this methodology are that you have none of the limitations regarding control naming or number of properties. It is also more robust, works in a wider variety of MS applications and is transportable.

The application that you will be creating is called Geomview. It is a simple OCX that allows you to display AVS/Express geometry files. This is the same Express application that the MFC example uses with the exception of shortcuts made in regard to access of the readers. The separate class for the reader is kept for future expansion purposes.

Part 1. AVS/Express 6.0

1. Start AVS/Express 6.0. Choose "None" when asked for the initial application type.

2. The v code we have supplied is a library. Use the following procedure to load the library. Select the "Templates" library from the Libraries combo box near the top of the Network Editor. Then, highlight the Templates library by clicking on its border.

3. Select the Object_Load_Objects... pulldown menu entry, and load the following V code: (note hard coded path name for teapot.geo. As this example develops, we will add additional controls to read other filenames) If you load the geomview.v that comes with express then you must modify it to contain the file name if you are not going to add code to choose the file to be loaded because it is not coded in the .v file as shown below.

flibrary+global GEOMVIEW
<out_hdr_file = "geomviewOMX.h", out_src_file = "geomviewOMX.cxx">
{

macro CGeomFileReader <export_cxx=3> {
ACread_geom ACread_geom {
array_flag = 0;
filename => "C:\\express\\data\\geom\\teapot.geo";
};
GDM.DataObject DataObject {
in => <-.ACread_geom.out_field;
};
olink obj <export=2> => .DataObject.obj;
};

macro C3DViewer <export_cxx=3> {
UIwinHandle handle {
window <export=3>;
widget <export=3>;
event <export=3>;
hdc <export=3>;
};
imlink objs <export=2>;
GDM.Mscene3D scene {
Top.child_objs => <-.<-.objs;
View.View.renderer = 0;
View.View.handle => <-.<-.<-.handle;
};
GDtrack_edit track {
camera => <-.scene.View.View.picked_camera;
obj => <-.scene.View.View.picked_obj;
view => <-.scene.View.View;
mode <export=3>;
x <export=3>;
y <export=3>;
time <export=3>;
int state <export=3> => .event;
};
};
};

4. Now we want to do a "Save_Compiled_Project". We don't need to create a project for this library. We do want to strip off any unnecessary kits. To do that, select the Project-Configure... pulldown menu entry, and use the dialog box to disable the Annotation and Graphing Kit, the Print Renderer, the VPS Renderer, and the VRML Renderer.

5. The highlight the Libraries.Templates.GEOMVIEW object by clicking on it. This is what we will save.

6. Select the Project-Save_Compiled_Project... pulldown menu entry. Specify a new project directory, and turn off the toggles labeled "Instance objects automatically on restore" and "Build project's executable". Then select the dialog's OK button. We only want to create the source code files (.cxx, .c and .h) and the binary v file (.vo).

7. After the compiled project has been generated, exit from AVS/Express and start Microsoft Developer Studio.

Part 2. MS Visual C++ 6.0

1. Select File-New-Project. The New Project Workspace dialog box appears. Select MFC ActiveXControlWizard, and enter a name for your project, e.g. geomview. Select the Create_new_workspace button. Click OK. The AppWizard now appears. Click Next on pages 1. On page 2 (step 2) of AppWizard, also check "Available in 'Insert Object' dialog" in addition to the defaults. Click Finish at the bottom. After you are done with the AppWizard, the project directory will be created.

The discussion below assumes that the project is called "geomview".

2. Copy the following files to your MSVC++ project directory from the compiled project directory that you generated using AVS/Express:

geomviewOMX.cxx
geomviewOMX.h
express.c
express.h
v/appl.vo
xexpress.cxx

Note that the appl.vo file should be placed directly into your MSVC++ project directory; there is no need to create a "v" subdirectory.

3. In your MSVC++ project directory, create a file called avsenv, that sets the XP_PATH variable to the name of your project directory. For example, if your project directory is c:\projects\geomview, your avsenv file should contain the following line:

XP_PATH=c:\projects\geomview

4. Using Project-Add_to_Project-Files, insert the following files into your project:

geomviewOMX.cxx
geomviewOMX.h
express.c
xexpress.cxx

5. Select Project-Settings... to display the Project Settings dialog box.

Go to the C/C++ tab.

1. In the "General" category, add the preprocessor definition MSDOS to the end of the list of existing definitions.
2. In the "Precompiled Headers" category, select the "Not using precompiled headers" toggle.
3. In the "Preprocessor" category, add the following entries to the "Additional include directories:" text field:
$(XP_ROOT)\include,$(XP_ROOT)
(This, of course, assumes that you have the environment variable XP_ROOT set. Be sure to set this.)

Go to the Link tab, and specify the following files as Object/library modules: (note inclusion of mfc libraries to force link before the other run-time libraries). Cut and paste these - it's a lot to type. This is a rather long line which will be cut off from the view in most browsers.

For Express 5.1 use the following libraries

lib_vers.obj uci_pal.obj Xfld.obj xp_init.obj UIcursor.obj UIcursoP.obj ui_gen.obj libacvt.a libgeom.a libutil.a libgdogl.a libgdsw.a libgd.a libmutil.a libvxbx.a libui.a libcxxut.a libpal.a libdmap.a libdbxx.a libgmod.a libwtobj.a libwtool.a express.lib wsock32.lib mfc42.lib mfcs42.lib

For Express 6.0 use the following libraries

express.lib Xfld.obj lib_vers.obj UIcursor.obj UIcursoP.obj ui_gen.obj libgdogl.a libgdsw.a libgd.a libvxbx.a libusers.a libacmod.a libac.a libacvt.a libgeom.a libutil.a librf.a libui.a libcxxut.a libmods.a libavsx.a libbmp.a libgif.a libjpeg.a libpbm.a libsunrs.a libsgiim.a libtif.a libip.a libpal.a libdmap.a libdbxx.a libgmod.a libmutil.a libwtobj.a libwtool.a liblic.lib wsock32.lib xp_init.obj libagx.lib libag.a ag_omx.obj mfc42.lib mfcs42.lib

In the "Settings for:" list box on the left side of the dialog box, change the selection so that only the Win32 Debug version of the project is selected.

Go back to the C/C++ tab. In the "Preprocessor" category, remove the _DEBUG preprocessor directive and add MSDOS to the list. Go to Project_Options, change the /MDd flag in the Project Options area to /MD.

Go to the link tab.

1. If you choose to use the debug version, you will need to make the changes to the link line. Go to Link->General, change mfc42.lib and mfcs42.lib to mfc42d.lib and mfcs42d.lib and add mfco42d.lib.You may have to specifically exclude mfc42.lib and mfc42s.lib in the Setting/Link/Input dialog.

Add the following in the ignore libraries typein in the Link->Input panel:

libc.lib,mfc42.lib,mfcs42.lib

OR

2. If you are using non debug then you will need to add the following in the ignore libraries typein in the Link->Input panel:

libc.lib,libcmt.lib,msvcrd.lib

Go to the Link->Input->Additional Library Path and typin:

..,.,$(XP_ROOT)\lib\pc,$(XP_ROOT)\lib\pc\pal,$(XP_ROOT)\lib\pc\fld,$(XP_ROOT)\lib\pc\nt_ui,$(XP_ROOT)\lib\pc\gmod,$(XP_ROOT)\lib\pc\ip_lib\inter,$(XP_ROOT)\lib\pc\ne,$(XP_ROOT)\lib\pc\om,$(XP_ROOT)\lib\pc\ag,$(XP_ROOT)\lib\pc\animator

You are now finished with the Project Settings dialog box.

1. Add the following line to geomview.h:

#include "express.h"

2. In the code for CGeomviewApp::InitInstance, add the following line, just before the final return statement. Note full path name. Change this path if you use the Release build in VC++.

OMmain_init(m_hInstance, m_hPrevInstance, "c:\\geomview\\Debug\\geomview -novcp",SW_SHOWNORMAL);

3. In the code for CGeomviewApp::ExitInstance, add the following line.

OMmain_uninit(1);

4. Add the following public class method to CGeomviewCtrl:

CGeomFileReader *GetReader() {return(m_reader);}

5. Add the following protected class members to CGeomviewCtrl:

C3DViewer *m_viewer;
CGeomFileReader *m_reader;

6. Using ClassWizard, add functions for the following messages

1. WM_DESTROY,
2. WM_CREATE,
3. WM_LBUTTONDOWN,
4. WM_MOUSEMOVE,
5. WM_LBUTTONUP, and
6. WM_SIZE.

7. Add the following code to CGeomviewCtrl's constructor:

m_viewer = NULL;
m_reader = NULL;

8. Add the following code to CGeomviewCtrl::OnDraw:

if (m_viewer) {
m_viewer->push_ctx();
m_viewer->event = 3;
m_viewer->pop_ctx();
}

9. Add the following code to CGeomviewCtrl::OnCreate:

m_reader = new CGeomFileReader;

CGeomFileReader *reader = GetReader();
if (!reader) return -1;

m_viewer = new C3DViewer;

if (OMadd_obj_ref((OMobj_id) m_viewer->objs,
(OMobj_id) reader->obj, 0) != OM_STAT_SUCCESS) {
MessageBox("Can't connect document and view geometry objects");
return -1;
}

m_viewer->push_ctx();
m_viewer->window = (int) GetSafeHwnd();
m_viewer->widget = (int) GetSafeHwnd();
m_viewer->hdc = 0;
m_viewer->event = 1;
m_viewer->pop_ctx();

10. Add the following code to CGeomviewCtrl::OnDestroy:

delete m_viewer;
delete m_reader;

11. Add the following code to CGeomviewCtrl::OnLButtonDown:

if (m_viewer && GetCapture() != this) {

m_viewer->push_ctx();

if (nFlags & MK_CONTROL)
m_viewer->mode = 2;
else if (nFlags & MK_SHIFT)
m_viewer->mode = 1;
else
m_viewer->mode = 0;

m_viewer->x = (int) point.x;
m_viewer->y = (int) point.y;
m_viewer->state = 1;
m_viewer->time = (int) GetCurrentTime();
m_viewer->pop_ctx();

SetCapture();
}

12. Add the following code to CGeomviewCtrl::OnLButtonUp:

if (GetCapture() == this) {
ReleaseCapture();
m_viewer->push_ctx();
m_viewer->x = (int) point.x;
m_viewer->y = (int) point.y;
m_viewer->state = 3;
m_viewer->time = (int) GetCurrentTime();
m_viewer->pop_ctx();
}

13. Add the following code to CGeomviewCtrl::OnMouseMove:

if (GetCapture() == this) {
m_viewer->push_ctx();
m_viewer->x = (int) point.x;
m_viewer->y = (int) point.y;
m_viewer->state = 2;
m_viewer->time = (int) GetCurrentTime();
m_viewer->pop_ctx();
}

* Add the following code to CGeomviewCtrl::OnSize:

if (m_viewer) {
m_viewer->push_ctx();
m_viewer->event = 2;
m_viewer->pop_ctx();
}

14. Build and execute the project.

The ActiveX Control (OCX) is registered as part of the build process.

You can test the OCX in the MSDEV ActiveX test container located in the Tools menu. The most likely place of error is at CGeomviewApp::InitInstance where OMmainInit is called. If the test container seems to hang, comment out the call to OMmainInit and rebuild and reregister. You should then get an empty control with the appropriate error messages. Make sure the avsenv file has correct pathways and the OMmainInit function has a valid path.

You are now finished with VC++ and MSDEV.

To use it in Visual Basic, startup Visual Basic, select the OLE icon from the toolbar and use the mouse to create the container framework in the default "Form1" and then choose Geomview Control from the list box of available controls.

To use it in MS Internet Explorer, download the MS ActiveX Control Pad from Microsoft (if you don't already have it) and follow directions for inserting an ActiveX control into an html document.

You can rotate, scale, or XY-translate the geometry using the left mouse button. To scale, hold the Shift key down while dragging. To translate, hold the Ctrl key down while dragging.

Additions to your control - Adding properties

The following section will describe how you can go about adding properties to your control. These will be visible when you use the control in VC++ or VB (or any other programming environment that will accept ActiveX controls.

Example : Color of DataObject (Scalar property)

Properties are added to controls using ClassWizard. Start it up from View->ClassWizard and then click on the Automation tab, making sure that CGeomviewCtrl is showing in the Class name box. Press the Add Property .. button to bring up the property dialog, and fill it in as described.

The External name of the property will be RedLight, and containers such as Visual Basic and Internet Explorer will use this when they want to manipulate it. The property will be of type BOOL, which we have chosen from the Type drop-down list that contains all the permissible types. A protected member variable called m_redLight will represent the property in the CGeomViewCtrl class. Choose the property implemented in your C++ code as a Member variable of the class.

Press OK to dismiss the ClassWizard, and go to the control class to look at the code. If you look in the header file, CGeomviewCtl.h, you'll find that Class Wizard has added declarations for the property variable and notification function.

// Dispatch maps
//{{AFX_DISPATCH(CGeomviewCtrl)
BOOL m_redLight;
afx_msg void OnRedLightChanged();
//}}AFX_DISPATCH

To ensure that the property is initialized correctly (redLight will be FALSE by default). So add line m_redLight = FALSE to the constructor :

CGeomviewCtrl::CGeomviewCtrl()
{
InitializeIIDs(&IID_DGeomview, &IID_DGeomviewEvents);

// TODO: Initialize your control's instance data here.
m_viewer = NULL;
m_reader = NULL;

m_redLight = FALSE;
}

Using the Property Page

We can now use the property page object that we were given by the ClassWizard to allow users to modify the values of the properties at design time. The property page is already associated with the control, but at present it does nothing. You can see the property page by placing the Geomview Control in the Test Container, and then selecting the Edit | Properties... menu.

At the moment, the property page only contains the test string "TODO: Place controls to manipulate properties of Geomview control on this dialog". To fix this, open up the project's resources and find the property page dialog resource, which will be called IDD_PROPPAGE_GEOMVIEW. When you open it, you'll see that it is blank apart from the test string, which you can delete.

Add the checkbox to represent the property, as follows:

Drag and drop a check box. Go to checkbox properties and specify the id as IDC_RED_LIGHT

Give the checkbox suitable labels, and place it on the dialog.

Use ClassWizard to associate variables with the controls on the page. Select the CgeomviewPropPage class, and click on the Member Variables tab. Highlight the IDC_RED_LIGHT ID, and press Add Variable ... to open the following dialog. Type in the values as below.

The member variable in the property page class will be called m_bRedLight, of type Bool.

If you go and look at the code in the property page class, you'll see that the DoDataExchange () function now contains code to transfer data.

void CGeomviewPropPage::DoDataExchange(CDataExchange* pDX)
{
//{{AFX_DATA_MAP(CGeomviewPropPage)
DDP_Check(pDX, IDC_RED_LIGHT, m_bRedLight, _T("RedLight") );
DDX_Check(pDX, IDC_RED_LIGHT, m_bRedLight);
//}}AFX_DATA_MAP
DDP_PostProcessing(pDX);
}

Add the below handler code to OnRedLightChanged method.

void CGeomviewCtrl::OnRedLightChanged()
{
// TODO: Add notification handler code

int status;
OMobj_id grp_id,col_id;

/* Get object id of the viewer */
grp_id = m_viewer->obj_id();

/* Get the object id of the scene subobject of the viewer */
grp_id = OMfind_subobj(grp_id,OMstr_to_name("scene"),OM_OBJ_RW);

/* Get the object id of Lights */
grp_id = OMfind_subobj(grp_id,OMstr_to_name("Lights"),OM_OBJ_RW);

/*Get tht subobject id of Lights within Lights */
grp_id = OMfind_subobj(grp_id,OMstr_to_name("Lights"),OM_OBJ_RW);

/* Get the first object in the Lights list */
OMget_array_val(grp_id, 0, &grp_id, OM_OBJ_RW);

/* Get the col subobject id */
col_id = OMfind_subobj(grp_id,OMstr_to_name("col"),OM_OBJ_RW);

/* Constrain the data type. */
int array_type = OM_TYPE_FLOAT;

// force type to float array
float *col = NULL;
/* Don't constrain dims */
int ndims = 0;
int dimension_size[OM_ARRAY_MAXDIM];

/* Get color array in write mode */
status = OMget_array(col_id, &array_type,(char **)&col,&ndims, dimension_size, OM_GET_ARRAY_RW);

if (status != 1) {
fprintf(stderr,"error occurred\n");
}

/* Assign the lighting to red light RGB = {1,0,0}*/
col[0]=1;col[1]=0;col[2]=0;

SetModifiedFlag();
ARRfree(col);


}

The above code adds red light to the teapot. Build the control and test it in the Test Container. If you select the red light check box , the Apply button will become enabled. Pressing this will add the red light property to the control.


TOC PREV NEXT INDEX