Download as pdf or txt
Download as pdf or txt
You are on page 1of 504

Microsoft® Dexterity

Programmer’s Guide Volume 2


Release 12
Copyright Copyright © 2012 Microsoft Corporation. All rights reserved.

Limitation of liability This document is provided “as-is”. Information and views expressed in this document, including
URL and other Internet Web site references, may change without notice. You bear the risk of using
it.

Some examples depicted herein are provided for illustration only and are fictitious. No real
association or connection is intended or should be inferred.

Intellectual property This document does not provide you with any legal rights to any intellectual property in any
Microsoft product.

You may copy and use this document for your internal, reference purposes.

Trademarks Microsoft, ActiveX, Dexterity, Excel, Microsoft Dynamics, Outlook, Visual Basic, Visual SourceSafe,
and Windows are trademarks of the Microsoft group of companies. FairCom and c-tree Plus are
trademarks of FairCom Corporation and are registered in the United States and other countries.

All other trademarks are property of their respective owners.

Warranty disclaimer Microsoft Corporation disclaims any warranty regarding the sample code contained in this
documentation, including the warranties of merchantability and fitness for a particular purpose.

License agreement Use of this product is covered by a license agreement provided with the software product. If you
have any questions, please call the Microsoft Dynamics GP Customer Assistance Department at
800-456-0025 (in the U.S. or Canada) or +1-701-281-6500.

Publication date December 2012


Contents
Introduction ................................................................................................................................. 2
What’s in this manual .................................................................................................................. 2
Symbols and conventions............................................................................................................ 3

Part 1: sanScript .................................................................................................................... 6


Chapter 1: Syntax................................................................................................................. 7
General syntax............................................................................................................................... 8
Names............................................................................................................................................. 8
Statements.................................................................................................................................... 11
Functions...................................................................................................................................... 11
Data types in sanScript .............................................................................................................. 12
Variables ....................................................................................................................................... 14
Constants...................................................................................................................................... 15
Expressions .................................................................................................................................. 16
Operators ..................................................................................................................................... 19
Order of precedence ................................................................................................................... 22
Casting.......................................................................................................................................... 23
Arrays ........................................................................................................................................... 24

Chapter 2: The Script Editor ................................................................................... 25


Using the Script Editor............................................................................................................... 25
Script Editor controls.................................................................................................................. 26
Syntax coloring............................................................................................................................ 27
The Names window ................................................................................................................... 27
Script menu.................................................................................................................................. 30
Script drill-down......................................................................................................................... 31
Compiling scripts........................................................................................................................ 32
Online help support ................................................................................................................... 34
Naming scripts ............................................................................................................................ 35

Chapter 3: Attaching Scripts .................................................................................. 39


Field scripts.................................................................................................................................. 39
Window scripts ........................................................................................................................... 41

PROGRAMMER’S GUIDE VOLUME 2 i


C O N T E N T S

Form scripts ................................................................................................................................ 43


Other scripts................................................................................................................................ 43

Part 2: Basic Scripting ............................................................................................... 46


Chapter 4: Writing scripts.......................................................................................... 47
Scripting overview..................................................................................................................... 47
Interaction-based programming .............................................................................................. 48
Procedure: Creating scripts....................................................................................................... 49

Chapter 5: Communicating With the User ................................................. 51


Dialogs ......................................................................................................................................... 51
Controlling forms and windows.............................................................................................. 53
Controlling fields ....................................................................................................................... 53
Controlling the focus ................................................................................................................. 54

Chapter 6: Performing Calculations ................................................................. 55


Basic calculations........................................................................................................................ 55
Overflow in numeric expressions............................................................................................ 55
Calculations with variable currency values ........................................................................... 56
Bit operations .............................................................................................................................. 57
Hexadecimal values................................................................................................................... 57
String calculations...................................................................................................................... 58

Chapter 7: Program Structures ............................................................................. 61


Decision structures..................................................................................................................... 61
Loop structures........................................................................................................................... 62

Part 3: Working with Controls ........................................................................ 66


Chapter 8: Standard Controls ................................................................................ 67
Button drop lists ......................................................................................................................... 67
Check boxes ................................................................................................................................ 69
Drop-down lists and combo boxes .......................................................................................... 70
Push buttons ............................................................................................................................... 70
Radio buttons.............................................................................................................................. 73
String fields ................................................................................................................................. 74
Text fields .................................................................................................................................... 77

ii P R O G R A M M E R ’ S G U I D E V O L U M E 2
C O N T E N T S

Controls on toolbars ................................................................................................................... 77


Tooltips ......................................................................................................................................... 77

Chapter 9: Composites ................................................................................................. 79


Procedure: Creating standard composites .............................................................................. 80
Procedure: Creating extended composites.............................................................................. 82
Accessing composites from within scripts.............................................................................. 85
Component-based scripts .......................................................................................................... 86
Comparing composites .............................................................................................................. 88

Chapter 10: Scrolling Windows ............................................................................ 89


Scrolling window types ............................................................................................................. 90
Scrolling window elements ....................................................................................................... 91
Scrolling window properties..................................................................................................... 94
Designing scrolling windows ................................................................................................... 96
Adding scripts to a scrolling window ..................................................................................... 97
Controlling the focus................................................................................................................ 105
Using lookups ........................................................................................................................... 106
Single-line scrolling windows................................................................................................. 106
Procedure: Creating a scrolling window............................................................................... 108

Chapter 11: Lookups ..................................................................................................... 111


How lookups work................................................................................................................... 112
Implementing lookups............................................................................................................. 113

Chapter 12: Tree View ................................................................................................. 117


Terminology............................................................................................................................... 118
Tree view nodes......................................................................................................................... 119
Tree view properties ................................................................................................................. 120
Tree view scripts ....................................................................................................................... 120
Adding nodes to tree view fields ........................................................................................... 123
Image types for tree view nodes............................................................................................. 124
Adding images to a tree view field ........................................................................................ 125
Image sizes................................................................................................................................. 126
Specifying the images to use ................................................................................................... 126
Background colors .................................................................................................................... 126
Searching tree view fields........................................................................................................ 127

PROGRAMMER’S GUIDE VOLUME 2 iii


C O N T E N T S

Chapter 13: List View .................................................................................................. 129


Terminology .............................................................................................................................. 130
List view items.......................................................................................................................... 132
List view properties ................................................................................................................. 133
List view scripts........................................................................................................................ 134
Image types for list views ....................................................................................................... 136
Adding images to a list view field......................................................................................... 137
Image sizes ................................................................................................................................ 138
Specifying the images to use .................................................................................................. 138
Background colors ................................................................................................................... 138
Working with list views .......................................................................................................... 139
Working with the selection ..................................................................................................... 141
Searching a list view ................................................................................................................ 142

Part 4: Working with Tables ........................................................................... 146


Chapter 14: Table Overview .................................................................................. 147
Common table operations....................................................................................................... 147
Data in windows ...................................................................................................................... 147
Table buffers.............................................................................................................................. 148

Chapter 15: Working with Records ................................................................ 151


Example 1 - One window and one table............................................................................... 152
Example 2 - Two windows and two tables........................................................................... 156
Multiple records with the same key value ........................................................................... 163
Modifying the values of key fields ........................................................................................ 165

Chapter 16: Ranges ....................................................................................................... 167


Range overview........................................................................................................................ 167
Ranges for multisegment keys ............................................................................................... 168
Range types............................................................................................................................... 169
Well-behaved ranges................................................................................................................ 171

Chapter 17: Memory-based tables................................................................... 173


Creating memory-based tables .............................................................................................. 173
Pathnames for memory-based tables .................................................................................... 174
Using memory-based tables ................................................................................................... 174

iv P R O G R A M M E R ’ S G U I D E V O L U M E 2
C O N T E N T S

Chapter 18: Multiuser processing ................................................................... 175


Record locking........................................................................................................................... 175
Releasing locks .......................................................................................................................... 176
Coding a multiuser application .............................................................................................. 176
Multiuser examples .................................................................................................................. 178

Chapter 19: Transactions......................................................................................... 181


Transaction overview ............................................................................................................... 181
Error handling for transactions .............................................................................................. 182
Transaction template ................................................................................................................ 182
Guidelines for transactions ..................................................................................................... 185
Integrating applications........................................................................................................... 186

Part 5: Advanced Scripting............................................................................. 188


Chapter 20: Procedures ............................................................................................ 189
Terminology............................................................................................................................... 189
Creating and calling procedures............................................................................................. 190
Parameters ................................................................................................................................. 190
Using parameters...................................................................................................................... 191
Optional parameters................................................................................................................. 194
Passing parameters to other procedures ............................................................................... 195
Using global fields as parameter types.................................................................................. 196
Table buffers .............................................................................................................................. 198
Form procedures ....................................................................................................................... 200
Anonymous tables and fields ................................................................................................. 200
Background and remote processing....................................................................................... 204
Process groups........................................................................................................................... 205

Chapter 21: User-defined Functions ............................................................. 209


Creating user-defined functions ............................................................................................. 209
Using user-defined functions.................................................................................................. 210
Form functions .......................................................................................................................... 213
Naming functions ..................................................................................................................... 213

Chapter 22: Dynamic Link Libraries ............................................................. 215


Dexterity and DLLs .................................................................................................................. 215
Using a DLL with Dexterity .................................................................................................... 215

PROGRAMMER’S GUIDE VOLUME 2 v


C O N T E N T S

Setting up the procedure for the DLL ................................................................................... 216


Calling the DLL ........................................................................................................................ 217
Paths for accessing DLLs ........................................................................................................ 218

Chapter 23: Controlling the Compiler ......................................................... 219


Script preprocessor .................................................................................................................. 219
Script preprocessor examples................................................................................................. 220
Pragmas ..................................................................................................................................... 222
Pragma reference...................................................................................................................... 222

Chapter 24: Call Stacks ............................................................................................ 225


Call stack usage ........................................................................................................................ 225
Managing call stacks................................................................................................................ 227

Chapter 25: References ............................................................................................. 231


Creating references .................................................................................................................. 232
Assigning references................................................................................................................ 232
Using references ....................................................................................................................... 233
Guidelines ................................................................................................................................. 233
Reference examples.................................................................................................................. 234

Chapter 26: Structured Exception Handler............................................. 237


Overview ................................................................................................................................... 237
User exceptions......................................................................................................................... 238
System exceptions .................................................................................................................... 239
Implementing an exception handler ..................................................................................... 244
Exception handler examples................................................................................................... 246

Part 6: Analysis Tools ............................................................................................. 252


Chapter 27: Script Debugger ............................................................................... 253
The Debug menu...................................................................................................................... 253
The Script Debugger window ................................................................................................ 254
Breakpoints ............................................................................................................................... 257
Using the debugger.................................................................................................................. 260
Examining the state of the application.................................................................................. 263
Editing scripts........................................................................................................................... 270
Debugging runtime errors ...................................................................................................... 271

vi P R O G R A M M E R ’ S G U I D E V O L U M E 2
C O N T E N T S

Chapter 28: Script Profiler .................................................................................... 273


Using the Script Profiler........................................................................................................... 273
Understanding the script profile ............................................................................................ 275

Chapter 29: Script Logger ...................................................................................... 279


Logging scripts.......................................................................................................................... 279
Understanding the script log .................................................................................................. 279
Using the Script Logger ........................................................................................................... 280

Chapter 30: Resource Usage................................................................................ 281


Building the reference information table .............................................................................. 281
Viewing reference information ............................................................................................... 282
Updating the reference information table............................................................................. 284

Part 7: Software Engineering....................................................................... 286


Chapter 31: The Development Process ...................................................... 287
Application development........................................................................................................ 287
Dexterity application development ....................................................................................... 288
Managing development........................................................................................................... 289

Chapter 32: Design Guidelines .......................................................................... 291


Resources ................................................................................................................................... 291
Scripting ..................................................................................................................................... 293
Features ...................................................................................................................................... 294

Chapter 33: Optimizing Your Application ............................................... 295


Procedures and functions ........................................................................................................ 295
Forms and windows................................................................................................................. 296
Tables .......................................................................................................................................... 297
Reports ....................................................................................................................................... 298
Scrolling windows .................................................................................................................... 298
Scripts ......................................................................................................................................... 298

Chapter 34: Testing Your Application ......................................................... 299


Characteristics of a good application..................................................................................... 299
The SQA process ....................................................................................................................... 300
Testing Dexterity applications ................................................................................................ 301
Phases of testing........................................................................................................................ 302

PROGRAMMER’S GUIDE VOLUME 2 vii


C O N T E N T S

The macro system..................................................................................................................... 303


The Macro menu ...................................................................................................................... 303
Additional macro menu items ............................................................................................... 304
Using macros for testing ......................................................................................................... 309
Structure and syntax of a macro .............................................................................................311
The macro language................................................................................................................. 312

Chapter 35: Creating an International Product .................................. 315


Locales ....................................................................................................................................... 316
Designing for eventual translation ........................................................................................ 317
Window design......................................................................................................................... 318
Report design............................................................................................................................ 320
Coding issues............................................................................................................................ 321
International defaults file settings ......................................................................................... 325

Part 8: COM .......................................................................................................................... 328


Chapter 36: Introduction to COM .................................................................... 329
Automation ............................................................................................................................... 329
Classes and objects................................................................................................................... 330
Events......................................................................................................................................... 331

Chapter 37: COM Libraries ..................................................................................... 333


Type libraries ............................................................................................................................ 333
Referencing type libraries ....................................................................................................... 333

Chapter 38: Referencing COM Objects....................................................... 337


COM references ........................................................................................................................ 337
Generic references .................................................................................................................... 338
Creating COM references........................................................................................................ 338

Chapter 39: COM in sanScript ............................................................................ 341


Objects........................................................................................................................................ 341
Properties and methods .......................................................................................................... 343
Constants................................................................................................................................... 344
Data type conversion............................................................................................................... 344
Class Browser............................................................................................................................ 345
Collections................................................................................................................................. 346

viii P R O G R A M M E R ’ S G U I D E V O L U M E 2
C O N T E N T S

COM exceptions........................................................................................................................ 346


Debugging COM integrations ................................................................................................ 348
Assemblies created with the .NET Framework.................................................................... 348

Chapter 40: Callbacks and Events .................................................................. 351


Callback objects......................................................................................................................... 351
Accessing callback objects ....................................................................................................... 354
Events ......................................................................................................................................... 354
Creating an event handler ....................................................................................................... 355

Part 9: Using COM ...................................................................................................... 360


Chapter 41: Microsoft Word ................................................................................. 361
Microsoft Word Object Library overview ............................................................................. 361
Declared variables .................................................................................................................... 362
Application object..................................................................................................................... 362
Document object ....................................................................................................................... 364
Range object............................................................................................................................... 366
Paragraph object ....................................................................................................................... 367
Table object ................................................................................................................................ 369
Cell object................................................................................................................................... 370
Script example........................................................................................................................... 371

Chapter 42: Microsoft Excel ................................................................................. 375


Microsoft Excel Object Library overview.............................................................................. 375
Declared variables .................................................................................................................... 376
Application object..................................................................................................................... 376
Workbook object ....................................................................................................................... 378
Worksheet object ....................................................................................................................... 380
Range object............................................................................................................................... 381
WorksheetFunction object ....................................................................................................... 384
Chart object................................................................................................................................ 385
Script example........................................................................................................................... 387

Chapter 43: Microsoft ADOX............................................................................... 389


Microsoft ADOX Object Library overview ........................................................................... 389
Declared variables .................................................................................................................... 390
Catalog object ............................................................................................................................ 390

PROGRAMMER’S GUIDE VOLUME 2 ix


C O N T E N T S

Table object................................................................................................................................ 392


Key object .................................................................................................................................. 393
Column object........................................................................................................................... 394
Script example .......................................................................................................................... 396

Chapter 44: Microsoft ADO ................................................................................... 399


Microsoft ADO Object Library overview ............................................................................. 399
Declared variables.................................................................................................................... 400
Connection object ..................................................................................................................... 400
Recordset object........................................................................................................................ 401
Field object ................................................................................................................................ 404
Script example .......................................................................................................................... 405

Chapter 45: Microsoft Internet Explorer ................................................... 407


Microsoft Internet Controls Object Library overview ........................................................ 407
Declared variables.................................................................................................................... 407
InternetExplorer object ............................................................................................................ 408
Script example .......................................................................................................................... 410

Chapter 46: Microsoft Outlook .......................................................................... 411


Microsoft Outlook Object Library overview.........................................................................411
Declared variables.................................................................................................................... 412
Outlook security....................................................................................................................... 413
Application object .................................................................................................................... 413
NameSpace object .................................................................................................................... 414
MAPIFolder object ................................................................................................................... 415
MailItem object ......................................................................................................................... 417
Attachment object .................................................................................................................... 420
Recipient object......................................................................................................................... 421
ContactItem object ................................................................................................................... 424
Script example .......................................................................................................................... 427

Chapter 47: Microsoft XML ................................................................................... 429


Microsoft XML Object Library overview.............................................................................. 429
Declared variables.................................................................................................................... 430
DOMDocument object............................................................................................................. 431
IXMLDOMNode object ........................................................................................................... 433
IXMLDOMNodeList object .................................................................................................... 435

x P R O G R A M M E R ’ S G U I D E V O L U M E 2
C O N T E N T S

IXMLDOMProcessingInstruction object ............................................................................... 436


IXMLDOMElement object ....................................................................................................... 437
IXMLDOMText object .............................................................................................................. 440
Script example........................................................................................................................... 443

Appendix .................................................................................................................................. 448


Appendix A: Dexterity Limits .............................................................................. 449
Appendix B: Reserved Words............................................................................... 453
Appendix C: ASCII Character Codes ............................................................ 455

Glossary ..................................................................................................................................... 457

Index............................................................................................................................................... 473

PROGRAMMER’S GUIDE VOLUME 2 xi


xii P R O G R A M M E R ’ S G U I D E V O L U M E 2
INTRODUCTION
Introduction
The Microsoft® Dexterity Programmer’s Guide is designed to give you an
in-depth understanding of how to use the Dexterity system. It is divided
into two volumes. Volume 1 contains information about creating resources
and working with dictionaries. Volume 2 contains information about
adding scripts to an application.

What’s in this manual


Volume 2 of the Programmer’s Guide contains the following parts:

• Part 1, sanScript, introduces you to sanScript, the scripting language


used in Dexterity. You will learn how to write scripts for your applica-
tion.

• Part 2, Basic Scripting, describes how to begin writing scripts for your
Dexterity application.

• Part 3, Working with Controls, explains how to work with the various
user interface controls available in Dexterity.

• Part 4, Working with Tables, describes how to use scripts to interact


with tables.

• Part 5, Advanced Scripting, describes advanced features of the


scripting language.

• Part 6, Analysis Tools, introduces Dexterity’s integrated source code


debugger. It also describes other tools like the Script Profiler and Script
Logger, that allow you to analyze the performance of your application.

• Part 7, Software Engineering, describes the development process for


Dexterity-based applications, provides design guidelines for applica-
tions, and describes how to optimize and test your application.

• Part 8, COM, describes how to use COM, the Component Object


Model, in your Dexterity-based applications.

• Part 9, Using COM, explains how to use Dexterity’s COM functionality


to integrate with other Microsoft applications.

2 P R O G R A M M E R ’ S G U I D E V O L U M E 2
IN TRO DUCT IO N

Symbols and conventions


To help you use the Dexterity documentation more effectively, we’ve used
the following symbols and conventions within the text to make specific
types of information stand out.

Symbol Description
➥ of table Items; A continuation character indicates that a script
continued from one line to the next should be
typed as a single line in the Script Editor.
The light bulb symbol indicates helpful tips,
shortcuts and suggestions.

Warnings indicate situations you should be aware


of when completing tasks with Dexterity.

Margin notes summa- Margin notes call attention to critical information,


rize important informa- and direct you to other areas of the
tion. documentation where a topic is explained.

New The new symbol indicates additions and changes


available with this release of Dexterity.
The SQL symbol indicates information that
SQL
applies only when a SQL database type is used.

Convention Description

Part 2, Basics Bold type indicates a part name.

Chapter 10, “Forms” Quotation marks indicate a chapter name.

Applying formats Italicized type indicate a section name.


'l_Item' = 1; This font is used to indicate script examples.
RUNTIME.EXE Words in uppercase indicate a file name.
Software Development Acronyms are spelled out the first time they’re
Kit (SDK) used.
TAB or ALT+M Small capital letters indicate a key or a key
sequence.

PROGRAMMER’S GUIDE VOLUME 2 3


4 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 1: SANSCRIPT
Part 1: sanScript
This part of the documentation introduces sanScript, the Dexterity scripting
language. It describes the syntax, how to use the Script Editor, and how to
attach scripts. The following items are discussed:

• Chapter 1, “Syntax,” introduces the Dexterity scripting language.

• Chapter 2, “The Script Editor,” describes Dexterity’s built-in script


editor that you can use to write scripts.

• Chapter 3, “Attaching Scripts,” describes how to attach scripts to


various objects in a Dexterity application.

6 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 1: Syntax
To make your application work properly, you need to apply logic and rules
that determine how the application will function. The Dexterity
development system has its own programming language, sanScript, that
you’ll use to control how your application operates.

Unlike many traditional languages that require you to write long pieces of
program code, sanScript is written in small segments, or scripts, that are
attached to objects in an application dictionary, such as fields, menus,
windows and forms. Scripts are run as the user interacts with that
particular object in the application. For example, a script applied to a push
button will run when the user clicks the button.

This script-based approach and sanScript’s English-like instructions are


designed to make Dexterity applications easier to write than applications
written with other languages. If you’ve had experience writing programs in
other languages such as Pascal or BASIC, you’ll find many concepts are
similar in sanScript.

Information is divided into the following sections:

• General syntax
• Names
• Statements
• Functions
• Data types in sanScript
• Variables
• Constants
• Expressions
• Operators
• Order of precedence
• Casting
• Arrays

PROGRAMMER’S GUIDE VOLUME 2 7


PA RT 1 SA N SCRI P T

General syntax
SanScript is a relatively easy language to learn, but you must follow some
basic rules when you write scripts.

• SanScript is case-sensitive, as are names of fields, windows, forms,


menus and other resources. All keywords in sanScript must be lower-
case.

• Each statement in a script must end with a semi-colon. Statements can


span multiple lines.

• Comments can appear anywhere in a script. They must be bounded by


braces – { } – and can span multiple lines.

• If a script has parameters or local variables, these must be declared at


the beginning of the script before any other lines in the script.

• Each script must be less than 24,000 characters in length, including


spaces and comments.

Names
In a script, you’ll refer to the names of objects such as fields, windows or
forms in an application dictionary. Depending on the object referenced in
the script, you must indicate either the object’s simple name or qualified name.

Simple names
A simple name is the name you give an object when you create it. When
you use a simple name, sanScript assumes that the object is part of the
current window where you’re attaching the script. This allows the same
object to be used in multiple places.

For instance, in an application that stores customer records, the Customer


Number field is used in several places. If a simple name is used to refer to
the Customer Number field, Dexterity assumes you’re referring to the
Customer Number field in the window where you’re attaching the script.
The following script will disable the Customer Number field of the current
window.

disable field 'Customer Number';

8 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

A simple name must start with a letter, and can contain up to 78 additional
letters, digits, underscores or spaces for a total size of 79 characters. A
simple name that has spaces in it must be surrounded by single quotation
marks when referenced in a script.

Because names must be surrounded with single quotation marks if they contain
spaces, we recommend that you substitute underscores for spaces in names when
you name objects in your application. This makes them easier to use in scripts.

Examples of valid simple names are shown in the following table:

This name Is valid because


CustomerMaster There are no spaces in the name so no single
quotation marks are needed.
Customer_Master This name has an underscore instead of a
space between the first and second words.
'Customer Master' The name is enclosed in single quotation
marks, so it may contain spaces.

The following names aren’t valid simple names:

This name Isn’t valid because


Customer Master It contains a space, but isn’t surrounded by
single quotation marks.
1CustomerMaster The name starts with a digit.

Single and double quotation marks are used differently in scripts. Single quotation
marks indicate the names of objects, while double quotation marks indicate the item
between the quotation marks is a string value.

Qualified names
A qualified name explicitly specifies the location of the object being
referenced. Qualified names consist of a qualifier, which specifies the
location of the object, and a simple name. Qualified names are used to
reference objects that aren’t part of the current window or to resolve name
conflicts. For example, to refer to the Customer Name field in the
Customer_Master table instead of the Customer Name field in the current
window, you would qualify the field with the of table qualifier as shown in
the following script.

'Customer Name' of table Customer_Master = "Bob Smith";

PROGRAMMER’S GUIDE VOLUME 2 9


PA RT 1 SA N SCRI P T

A qualified name can have one of three syntaxes:

• When the script refers to a field in another window of the current form,
use the following syntax:

field name of window window name

• When the script refers to a field in a window that is not part of the cur-
rent form, use this syntax:

field name of window window name of form form name

• When the script refers to a field in a table:

field name of table table name

When you use qualified names containing spaces in the name, the “of”
portion of the name shouldn’t be inside the single quotation marks. The
following name is valid:

This name Is valid because


'Customer Name' of table The “of” portion of the name is not within the
Customer_Master single quotation marks.

The following name isn’t a valid qualified name:

This name Isn’t valid because


'Customer Name of table The “of” portion of the name is within the
Customer_Master' single quotation marks.

Local fields have a special qualifier that indicates the field is a local
field. When you reference a local field in a script, the letter L in
parentheses – (L) – must be included before the name of the field, with the
entire name enclosed in single quotes. For example, the following name for
the Customer Type local field is valid:

This name Is valid because


'(L) Customer Type' The (L) portion of the name is enclosed within
the single quotation marks.

However, the following name isn’t valid:

This name Isn’t valid because


(L) 'Customer Type' The (L) portion of the name is not within the
single quotation marks.

10 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

Statements
Statements are a type of command used in sanScript to complete a specific
action in your application, such as opening a window, saving an item in a
table or displaying a message for the user. For instance, to display a
message in your application you can use the error statement:

error "Please enter your password.";

Functions
Functions are commands similar to statements, but unlike statements, they
return a value that is then used by another portion of the script. For
example, the countitems() function is used to count the number of entries
in a list box field displayed in a window. The name of the list box field is the
function’s parameter while the number of items displayed in the list box is
the value returned. The following example sets the variable “number” to
the number of items in the list box named Shipping Methods.

number = countitems('Shipping Methods');

Refer to the Function Functions such as countitems() are built into sanScript. The sanScript
Library Reference language also has dozens of functions that are contained in the function
manual for more libraries. The function libraries are groups of special-purpose functions that
information about extend the capability of Dexterity. For instance, the WinHelp function
function libraries. library contains functions used to implement an online help system for a
Dexterity application.

You can also create your own functions for use in scripts. Refer to Chapter
21, “User-defined Functions,” for more information.

PROGRAMMER’S GUIDE VOLUME 2 11


PA RT 1 SA N SCRI P T

Data types in sanScript


For a complete list of Dexterity uses several different data types to specify how information is
Dexterity data types stored and displayed in fields. When writing scripts, it’s important to know
and their how information in a field using a particular data type is stored, so you’ll
characteristics, refer to know how script commands will control the information.
Chapter 6, “Data
Types,” in Volume 1 of Storing data types
the Dexterity Fields can store data in the following standard forms: boolean, currency,
Programmer’s Guide. integer, long, string, text, date, time, and variable currency. The control type
used for the data type determines how a particular field stores information.
The following table lists each storage type, its description, and the control
types that use that storage type.

Storage Description Control types


type
Boolean A value of either true or false. Boolean
Check box
Currency A currency value in the range Currency
[-99,999,999,999,999.99999 to
99,999,999,999,999.99999]. The decimal point is
implied in the number, but not stored. For display
purposes, currency values are limited to 14 digits to
the left of the decimal and 5 digits to the right.
Integer An integral number in the range Button drop list
[-32768 to 32767]. Drop-down list
Group box
Integer
List box
Non-native list box
Progress indicator
Visual switch
Long An integral number in the range [-2,147,483,648 to Long integer
2,147,483,647].
String A sequence of up to 255 characters. Combo box
String
Text A sequence of up to 32,000 characters. Text
Date Date based upon the Julian calendar. Date
Time Time based on the 24-hour standard. Time
DateTime A combined date and time value used for COM None
integrations.
Variable A currency value with up to 23 digits. Up to 15 digits Currency (variable)
Currency of the number can be used for the decimal portion.

12 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

String and text data types are stored as Pascal strings in a data file. Pascal
strings use a length byte (1 byte for strings, 2 bytes for text) to store the
length of the field. Typically, these data types must also have an even
storage size. If the sum of the storage size and length byte is an odd
number, a pad will be used when you set the storage size for the data type.
Even storage sizes are required for microprocessor compatibility.

The other control types not mentioned in the previous table either don’t
store information or store information in a format unique to the control
type. Push button, radio button, reference, tree view and list view control
types don’t store information. Composite, multi-select list box and picture
control types each store data in their own unique format.

Converting data
When working with fields in scripts, it may be necessary to convert how the
data is stored to a different storage method. This conversion can happen
implicitly or explicitly.

Type conversion happens implicitly in many situations. For instance, if an


integer value and a currency value are added together in an expression and
the result is stored in a currency field, the result would be a currency. If the
result of the same expression was stored in an integer field, the result would
be an integer. The conversions that occur depend on where the result is
stored.

To explicitly convert a string to a numeric value, use the value() function. To


explicitly convert a numeric value to a string use the str() function. For
more information about each of these functions, refer to the SanScript
Reference manual.

You can also use casting to convert values from one type to another. Refer to
Casting on page 23 for more information.

PROGRAMMER’S GUIDE VOLUME 2 13


PA RT 1 SA N SCRI P T

Variables
Variables allow an application to temporarily store values used by the
application. Dexterity has two types of variables: local variables and global
variables.

Local variables
Local variables are specific to a single script and are active only while the
script is running. They’re used to store intermediate values, such as the
resulting value of an expression, while a script is running. To create local
variables, define them at the beginning of the script they’ll be used in. The
word local, followed by the type of variable (integer, long, currency,
vcurrency, string, time, boolean) and the variable name are required for
each local variable.

Note that you use the word long to indicate a long integer type in scripts. Use the
word vcurrency to indicate a variable currency type in scripts.

In the following example, a local integer variable named


“number_of_dozen” is used to store a temporary integer value for the
script. The variable is set to the value of the Quantity field divided by 12 to
give the amount in dozen.

local integer number_of_dozen;

number_of_dozen = 'Quantity' / 12;

When you declare a local variable, you can specify its initial value. This is
shown in the following example.

local string first_name = "Steve";

Global variables
For more information Global variables are active the entire time a Dexterity application is open, so
about creating global they’re available to any script in the application dictionary, at any time.
variables, refer to Global variables are used to store information that affects the entire
Chapter 22, “Global application, such as whether printing is currently allowed. Global variables
Variables,” in Volume 1 are created in the Resource Explorer. To reference global variables in a
of the Dexterity script, the qualifier of globals must appear after the name of the global
Programmer’s Guide. variable.

14 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

In the following example, the global variable Printing_Status is checked to


determine whether items may be printed.

if Printing_Status of globals = "Yes" then


run report Customer_List;
else
warning "Printing is currently disabled. Try again later.";
end if;

Constants
Constants are fixed numeric or string values that are used in scripts, where
the constant name is used in place of the value associated with it. Two types
of constants are available in Dexterity: Dexterity constants and user-defined
constants.

Dexterity constants
Refer to Chapter 21, Dexterity has a number of predefined constants that can be used in scripts.
“Constants,” in Volume For example, the three constants listed in the following table are used with
1 of the Dexterity the ask() function.
Programmer’s Guide
for a list of special Constant name Description
predefined constants ASKBUTTON1 The value returned from the ask() function when the first button
in Dexterity. is clicked in the ask dialog box.
ASKBUTTON2 The value returned from the ask() function when the second
button is clicked in the ask dialog box.
ASKBUTTON3 The value returned from the ask() function when the third
button is clicked in the ask dialog box.

In the following example, the ask() function uses predefined constants to


determine which button the user clicked.

if ask("Include sales tax?","Yes","No") = ASKBUTTON1 then


Total = Total + Tax;
end if;

PROGRAMMER’S GUIDE VOLUME 2 15


PA RT 1 SA N SCRI P T

User-defined constants
Refer to Chapter 21, You can also create your own constants using the Constant Definition
“Constants,” in Volume window. For example, you could define a constant named “PAY_PERIODS”
1 of the Dexterity to have the value 24, representing the number of pay periods in a year. To
Programmer’s Guide calculate an employee’s salary in a script, you can use the constant in place
for information about of the number.
how to create
user-defined constants. 'Check Amount' = Salary / PAY_PERIODS;

You can define global constants or form-level constants. Global constants can
be accessed by any script in your application. You should use them when
you anticipate a constant will be used by scripts throughout the application.

Form-level constants are designed to be used by a specific form in the


application. You should use them when several scripts on a form use a
constant, but there is little need to use the constant elsewhere in the
application.

Within the scope of a form, you can reference a form-level constant directly.
To reference a form-level constant from outside the scope of a form, use the
qualifier of form form_name. If a form-level constant and a global constant
have the same name, by default, scripts attached to the form will use the
form-level constant. To refer to the global constant instead, use the qualifier
of globals following the name of the constant. For example, the following
statement refers to the BUNGALOW constant defined on the Houses form.

'Type' of window Buyers = BUNGALOW of form Houses;

Expressions
An expression is a sequence of operands and operators that are evaluated to
return a value. Operators indicate the type of procedure to perform on the
operands. The operands are usually items in the application dictionary,
such as the content of fields or the values returned from functions or other
expressions. In sanScript, there are four kinds of expressions: numeric, date
and time, string, and boolean.

Numeric expressions
Evaluating a numeric expression results in numeric value. For instance, the
following sanScript statement uses a numeric expression that returns the
total price of a sale by adding the subtotal and sales tax fields.

'Total' = 'Subtotal' + 'Tax';

16 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

The following table lists the numeric operators in the order they’re
evaluated.

Operator Use Example


unary minus (-) negation -15
^ power 10^3
*, /,% multiplication, division 15/3
and modulus
+,- addition and subtraction 5+10
<<, >>, shiftl, shiftr shift operations 4>>2
=,<>,<,>,<=,>= comparison 4 >= 2

Date and time expressions


Evaluating a date and time expression results in a date, time or a numeric
value. For instance, the following sanScript statement adds 30 days to the
value of the Todays Date field to set the Due Date for a payment.

'Due Date' = 'Todays Date' + 30;

The following table lists the date and time operators in the order they’re
evaluated.

Operator Use Example


+,- addition and subtraction sysdate() + 30
=,<>,<,>,<=,>= comparison sysdate() <= 'Due Date'

When comparing time values, be aware that the seconds portion of the time value is
ignored.

String expressions
Evaluating a string expression results in a string value. For instance, the
following sanScript statement joins two string values and stores the result
in the Name field.

Name = "Cindy " + "Johnson";

The following table lists the string operators in the order they’re evaluated.

Operator Use Example


+ concatenation "Sara " + "Johnson"
=,<>,<,>,<=,>= comparison 'Name' <> "Smith"

PROGRAMMER’S GUIDE VOLUME 2 17


PA RT 1 SA N SCRI P T

Boolean expressions
Evaluating a boolean expression results in boolean value of true or false.
Boolean expressions are used in decision-making statements such as the if
then...end if statement. For instance, the following sanScript statement
evaluates the boolean expression in the if then...end if statement to
determine whether the value of the Number of Users field is greater than 5.

if 'Number of Users' > 5 then


warning "There are too many users in the system.";
end if;

The following table lists the boolean operators in the order they’re
evaluated.

Operator Use Example


not logical not not (err() = 0)
=,<> equal, not equal (6 + 4) = (5 + 5)
and logical and (Amount > 10) and
(Amount < 20)
or logical or (Password = "Smith" ) or
(Password = "smith")

18 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

Operators
This section lists the operators supported in sanScript. Examples show how
each operator is used in the different types of expressions.

Operator Description Example


unary minus (-) In numeric expressions, the unary minus neg_val = –10;
operator (-) indicates a negative value.
addition (+) In numeric expressions, the result is the total = subtotal + 5;
sum of the two values.
In string expressions, the result is the name = "Steve " + "Jones";
concatenation of the first and second
strings.
In date expressions, a numeric quantity due_date = sysdate() + 30;
may be added to a date to form a new
date. The numeric value is treated as a
number of days.
In time expression, a numeric quantity next_hour = systime() + 60;
may be added to a time value to form a
new time value. The numeric value is
treated as a number of minutes.
subtraction (-) In numeric expressions, the result is the total = price - discount;
difference of the two values.
In date expressions, a numeric quantity yesterday = sysdate() – 1;
may be subtracted from a date value to
form a new date value. The numeric
value is treated as a number of days.;
Two date values can be subtracted to days_to_pay = due_date - sysdate();
find the difference between them in
days.
In time expressions, a numeric quantity start_time = systime() – 30;
may be subtracted from a time value.
The numeric value is treated as a
number of minutes.
Two time values can be subtracted to elapsed_time = start_time –
find the difference between them in end_time;
minutes.
multiplication (*) The multiplication operator (*) is used in total = number_of_periods *
numeric expressions. The result is the contribution;
product of the two numbers.
division (/) The division operator (/) is used in check_total = salary /
numeric expressions. The result is the number_of_pay_periods;
quotient of the two numbers.
modulus (%) The modulus operator (%) is used in single_items = items_ordered %
numeric expressions. The result is the items_per_box;
remainder of the division of the first
number by the second number (for
example, 71 % 10 = 1).

PROGRAMMER’S GUIDE VOLUME 2 19


PA RT 1 SA N SCRI P T

Operator Description Example


power (^) The power operator is used in numeric number = 10 ^ 5;
expressions. The result is the first
operand raised to the power of the
second operand. Only powers of 10 may
be calculated.
<< or shiftl The shift left operator is used with result = 16 << 2;
numeric expressions. The result is the result = 8 shiftl 3;
supplied integral value with its bits
shifted to the left a specified number of
positions. Zeros are shifted into the
value.
>> or shiftr The shift right operator is used with result = 16 >> 2;
numeric expressions. The result is the result = 256 shiftr 3;
supplied integral value with its bits
shifted to the right a specified number of
positions. Zeros are shifted into the
value.
equality (=) The equality operator is supported in if total = 100 then
numeric, boolean, string, date and time result = true;
expressions. In all expressions the result end if;
is true if the two operands are equal, and
false if they are not equal.
inequality (<>) The inequality operator is supported in if password <> "access" then
numeric, boolean, string, date and time abort script;
expressions. In all expressions the result end if;
is false if the two operands are equal,
and true if they are not equal.
less than (<) The less than operator is supported in if total < 100 then
numeric, string, date and time warning "Total is not 100%";
expressions. In all expressions the result end if;
is true if the first operand is less than the
second operand, and false if it is not.
greater than (>) The greater than operator is supported if current_date > sysdate() then
in numeric, string, date and time warning "Date is not valid.";
expressions. In all expressions the result end if;
is true if the first operand is greater than
the second operand, and false if it is not.
less than or equal The less than or equal to operator is if systime() <= posting_time then
to (<=) supported in numeric, string, date and warning "Posting can't begin.";
time expressions. In all expressions the end if;
result is true if the first operand is less
than or equal to the second operand, and
false if it is not.
greater than or The greater than or equal operator is if total >= 100 then
equal to (>=) supported in numeric, string, date and discount = 10;
time expressions. In all expressions the else
result is true if the first operand is discount = 0;
greater than or equal to the second end if;
operand, and false if it is not.

20 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

Operator Description Example


and In boolean expressions, the result is true if (count > 100) and (total > 0) then
if both of the operands are true, and set discount to 15;
false if either of the operands is false. end if;
In numeric expressions, the and operator result = status and 16;
performs a logical and operation of the
corresponding bits of two integral values
and returns the result.
or In boolean expressions, the result is true if (count > 100) or (total > 100) then
if either of the operands is true, and false discount = 20;
if both of the operands are false. end if;
In numeric expressions, the or operator result = status or 255;
performs a logical or operation of the
corresponding bits of two integral values
and returns the result.
xor In boolean expressions, the result is true if printer xor screen then
if either of the operands is true, and false run report 'Customer List';
if both of the operands are true or both end if;
operands are false.
In numeric expressions, the xor operator result = status xor 255;
performs an exclusive or operation of
the corresponding bits of two integral
values and returns the result.
not In boolean expressions the not operator if not enabled, then
is used to complement (reverse) the warning "Printing not enabled.";
value of a boolean expression. end if;
In numeric expressions, it performs a result = not status;
logical not operation on each bit of an
integral value and returns the result.
implication or In boolean expressions, the implication result = a imp b;
conditional (imp) operator examines the first operand. If it
is true, the value of the second operand
is returned; otherwise, the value true is
returned.

PROGRAMMER’S GUIDE VOLUME 2 21


PA RT 1 SA N SCRI P T

Order of precedence
The order of precedence is the order in which the operations are carried out
for an expression. The order of precedence for sanScript is:

• Unary minus and not (-, not)


• Exponentiation (^)
• Multiplication, division and modulus (*, /, %)
• Addition and subtraction (+, -)
• Shift operations (shiftl, shiftr, <<, >>)
• Equality operators (=, <>, <, >, <=, >=)
• Logical and
• Logical or, xor
• Implication

Exercise caution when you use bit-wise operators in expressions. Based on


the order of precedence, you may not get the result you expect. For
example, the following two expressions look similar, but are evaluated very
differently:

if ((int_val1 and int_val2) > 0)

if (int_val1 and int_val2 > 0)

The first expression performs a bit-wise and operation on the two integer
values and then compares the result to 0. The second expression compares
the second integer value to 0 and then performs a bitwise and operation on
that boolean result and int_val1. The second expression can’t be compiled
because sanScript can’t perform a logical and operation on a boolean and an
integer.

22 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 S Y N T A X

Casting
A cast allows you to explicitly change the type of an expression. Casts are
used when you know the type of expression you need, and want the
compiler to carry out the conversion. Use the following syntax to perform a
cast:

type(expression)

type – Specifies the resulting type of the expression. This can be integer,
long, currency, vcurrency, string or boolean.

expression – The expression whose type is being converted.

Some casts are not permitted. For example, you can’t use a cast to convert a
currency expression into a date expression. Invalid casts will compile, but
will generate errors at runtime.

The following example converts the value 15 to a long integer.

local long long_int_val;

long_int_val = long(15);

The following example converts the string “45.12” to a currency value.


Because the value() function returns a variable currency value, a cast is
used to convert the result to a currency.

local currency cur_val;

cur_val = currency(value("45.12"));

PROGRAMMER’S GUIDE VOLUME 2 23


PA RT 1 SA N SCRI P T

Arrays
Refer to Chapter 8, The individual pieces that make up an array are called elements. The
“Global Fields,” in elements are numbered from 1 to the size of the array. Arrays can have up
Volume 1 of the to 32,767 elements. The number used to indicate a specific element of the
Dexterity array is called the array index. A specific element of the array is referenced in
Programmer’s Guide sanScript using its corresponding array index.
for more information
about creating array An array can be used in place of several fields that have the same data type
fields. and will be storing similar information. For example, if an application
keeps track of monthly sales for a year, one monthly sales array field with
an array size of 12 could be used to store this information instead of 12
separate fields.

Arrays in Dexterity
Dexterity applications can use array fields and array local variables. Array
fields are created in the Field Definition window by setting the Array Size
field to the size of the array. Array local variables are created by including
the size of the array in brackets – [ ] – following the local variable name.
When creating local arrays, the array size must be a constant expression.
Array sizes can’t be set at runtime.

Using arrays
To access the elements of an array from within a script, simply use the name
of the array and add the index number of the element you want to
reference. Be sure the index number is included in square brackets after the
name of the array and before the qualifier. The following example sets the
third element of the Quarterly Sales array field (corresponding to the third
quarter) to the sum of the monthly sales for July, August and September.

'Quarterly Sales'[3] = 'Jul Sales' + 'Aug Sales' + 'Sep Sales';

The following example uses a local array field with five elements to act as
status flags for the script. The for loop initializes the flags to false.

local boolean status[5];


local integer i;

for i = 1 to 5 do
status[i] = false;
end for;

24 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 2: The Script Editor
Dexterity has a built-in script editor you can use to write scripts for your
application. The Script Editor operates like an ordinary text editor, allowing
you to enter a script. You can also use the Script Editor to save and compile
scripts. Information is divided into the following sections:

• Using the Script Editor


• Script Editor controls
• Syntax coloring
• The Names window
• Script menu
• Script drill-down
• Compiling scripts
• Online help support
• Naming scripts

Using the Script Editor


The Script Editor operates like any basic text editor, allowing you to enter
and edit scripts up to 24,000 characters long, including spaces and
comments. It opens automatically when you attach a script.

Click Compile to Click Name to view the


compile the names of resources in
current script. the current dictionary.

The script name is


created automatically
when the Script Editor
window is opened.

Script statements and


Script statements and
code comments can be
code comments can be
entered in the text entry
entered in the text entry
area. All comments are
area. All comments are
enclosed in braces.

Compiling errors and


warnings are listed here.

PROGRAMMER’S GUIDE VOLUME 2 25


PA RT 1 SA N SCRI P T

Edit text in the Script Editor the same way you would with any other editor.
You can cut, copy and paste text by choosing the corresponding commands
from the Edit menu. You can also indent a block of text by selecting the text
and pressing the TAB key. To remove an indent from a block of text, select
the text and press SHIFT-TAB.

Script Editor controls


The buttons at the top of the Script Editor window allow you to compile a
script, print a script, look up resource names, debug a script and delete a
script. Each button is described in the following table.

Button Description
Saves the script source to the application dictionary and attempts
to compile the script.

Closes the current script. If only one script is open, the Script
Editor window will be closed. If the script has changed, you will be
asked whether to compile and save changes.
Prints the current script.

Opens the Names window, allowing you to look up the names of


resources in the dictionary.

Opens the Script Debugger window and displays the current


script.

Deletes the current script from the dictionary.

The Compile Messages button. Displays the Compile Messages


window, which lists any compiler errors or warnings for the
current script.
Displays the previous compiler message.

Displays the next compiler message.

26 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 T HE S C R I PT E D IT O R

Syntax coloring
To make scripts easier to read, color coding is applied to the various
elements of the syntax. For example, keywords are shown in one color,
while comments are shown in another. Use the Options window to specify
the colors used for the various syntax elements.

Syntax coloring can be used


in both the Script Editor and
the Script Debugger.
The various syntax elements
will be displayed in these
colors.

You can also specify the font


and size used for scripts.

Syntax coloring can be used in both the Script Editor and the Script
Debugger. You can also specify the font and size of the text used for scripts.

The Names window


Clicking the Names button in the Script Editor displays a list of resources in
the current dictionary, allowing you to retrieve the name of a specific
resource and paste it into a script. The resources in a dictionary are
arranged in a hierarchy that is shown in the following illustration.

Forms Windows Fields Components


Procedures
Functions
Commands
Constants
Tables Fields Components
Keys Fields Components
Global Fields Components
Procedures
Functions
Variables
Constants
Reports

PROGRAMMER’S GUIDE VOLUME 2 27


PA RT 1 SA N SCRI P T

At the top of the hierarchy are the forms, tables, and global resources in the
dictionary. Below that are the resources that are found within the context of
the top-level resource. For example, within the context of a specific form
there is a list of the windows, procedures, functions, commands, and
constants for that form. The Names window follows this hierarchy when it
displays the names of resources in the dictionary. The Names window is
shown in the following illustration.

These fields indicate the


context of the items in the
resource list.

This field indicates the


type of resource displayed
in the resource list.
Use the tabs to select a top-
level resource. Use the
buttons to select resources
lower in the hierarchy.

The resource list displays


the names of resources of
the selected type in the
selected location.

Click OK to copy the


selected name to the
clipboard.

Forms and form-related resources


To use the Names window to access the names of forms and form-related
resources, complete the following procedure:

1. Click the Forms tab.


In the Names window, click the Forms tab. The list of forms for the
dictionary will be displayed.

2. Select a form in the list.


Select the form for which you want to retrieve resource names. If you
need only the form name, click OK to copy the name.

28 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 T HE S C R I PT E D IT O R

3. Choose a sub-resource for the form.


Click Windows, Procedures, Functions, Commands, or Constants to
display the names of a specific resource type for the form. Select a
resource in the list. If this is the resource name you need, click OK.
Otherwise, continue working down the hierarchy.

Tables and table-related resources


To use the Names window to access the names of tables and table-related
resources, complete the following procedure:

1. Click the Tables tab.


In the Names window, click the Tables tab. The list of tables for the
dictionary will be displayed.

2. Select a table in the list.


Select the table for which you want to retrieve resource names. If you
need only the table name, click OK to copy the name.

3. Choose a sub-resource for the table.


Click Fields or Keys to display the names of a specific resource type for
the table. Select a resource in the list. If this is the resource name you
need, click OK. Otherwise, continue working down the hierarchy.

Global resources
To use the Names window to access the names of global resources,
complete the following procedure:

1. Click the Global tab.


In the Names window, click the Global tab. By default, the list of global
procedures for the dictionary will be displayed.

2. Choose the global resource type.


Click Fields, Procedures, Functions, Variables, Constants, or Reports to
display the names of the specific resource type. Select a resource in the
list. If this is the resource name you need, click OK. Otherwise, continue
working down the hierarchy

After you click OK, the Names window will close and the Script Editor
window will be displayed. Place the insertion point where you want the
name to appear in the script and choose Paste from the Edit menu. The
name will be added to your script with its simple name or, if necessary, its
qualified name.

PROGRAMMER’S GUIDE VOLUME 2 29


PA RT 1 SA N SCRI P T

The first time you open the Names window, it will attempt to set the context
based on the resource you’re attaching the script to. For example, if you’re
attaching a script to a window field, the Names window will use the
context of the current form and window. From that point, the Names
window remembers the settings from the last time it was accessed.

Script menu
The Script menu is available only when the Script Editor window is open.
The items in this menu allow you to search and replace text in the script.
You can also check the syntax of the script, save the script source, and drill
down to function and procedure scripts. The following table lists the items
in the Scripts menu.

Menu item Description


Find Opens the Find window, allowing you to search for a specific text
string. The search is case sensitive. If text is selected in the Script
Editor, this text will be used as the search string.
Find Next Finds the next occurrence of the specified text string.
Replace Allows you to search for a specific text string and replace it with
another text string.
Replace and Find Replaces the currently highlighted text with the specified
Next replacement text, then attempts to find the next occurrence of the
specified search string.
Find Matching When the insertion point is between a set of matching brackets,
Bracket selecting this item causes the text between parentheses (), square
brackets [], or braces {} to be selected. If no matching brackets are
found, the Script Editor will beep and no text will be selected.
Open Script Opens the highlighted procedure or function script. Refer to Script
drill-down on page 31 for more information.
Save Source Saves the script source to the dictionary without compiling it.
Check Syntax Checks the syntax of the current script. The script isn’t compiled or
saved.
Convert Script Converts the statement terminator from a period to a semi-colon.
Periods
Class Browser Opens the Class Browser window to look up information about
COM objects.

The Find and Replace menu options search only from the current insertion point
position to the end of the script. To ensure the entire script is searched, move the
insertion point to the beginning of the script before choosing Find or Replace.

30 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 T HE S C R I PT E D IT O R

Script drill-down
For information about Script drill-down allows you to view and switch between multiple
procedures, refer to procedures, user-defined functions, form-level procedures and form-level
Chapter 20, user-defined functions, without having to leave the Script Editor. This is
“Procedures.” For useful when you want to examine a progression of procedures or functions
information about called from a script.
user-defined functions,
refer to Chapter 21, Opening a script
“User-defined To use the script drill-down feature, highlight the name of a procedure,
Functions.” user-defined function, form-level procedure or form-level user-defined
function in a script, and choose Open Script from the Script menu. The
procedure or user-defined function will be displayed in the Script Editor
window.

To open a procedure or
user-defined function,
highlight its name and
choose Open Script from
the Script menu.

The script name will also be added to the Scripts List. (The Scripts List can
be displayed by pressing the button labeled with the small script icon
located on the right side of the Script Editor window.)

The script will appear in


the Scripts List.

PROGRAMMER’S GUIDE VOLUME 2 31


PA RT 1 SA N SCRI P T

When highlighting the names of procedures and user-defined functions,


keep in mind the following:

• For form-level procedures and form-level user-defined functions, be


sure to include the of form formname clause. This in necessary for the
Script Editor to be able to locate the procedure or user-defined function.

• For user-defined functions, be sure to include the first parenthesis for


the function.

Switching between scripts


To switch between scripts, simply use the Scripts List to choose the script
you want to view.

Closing a script
To close a script, choose it from the Scripts List so it appears in the Script
Editor window, then click Close. If the script has changed, you will be asked
whether you want to save the changes and compile the script.

Closing the Script Editor


When you close the Script Editor with several scripts open, the scripts will
be examined for any unsaved changes. If any scripts have been changed,
you will be asked whether you want to save the changes for all scripts. You
can save all changes, discard all changes, or cancel closing the Script Editor.
If you choose to save all changes, any changed scripts will be compiled and
saved. If a compiler error is encountered, the script that contains the error
will be displayed in the Script Editor and the closing process will stop.

Compiling scripts
A complete list of After you write a script, the script must be compiled into a form that can be
compiler messages used at runtime. Dexterity has a built-in compiler that will compile a script
can be found in the when you click Compile. If you want to save the script without compiling
online help. it, choose Save Source from the Script menu.

Compiler messages
The compiler in Dexterity returns two types of messages. Compiler errors
are problems in a script that prevent it from being compiled, such as syntax
errors. Compiler warnings are less serious problems that won’t prevent a
script from being compiled, but should be resolved. An example of a
compiler warning is a local variable that is declared, but not used.

32 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 T HE S C R I PT E D IT O R

If any errors or warnings are encountered during compiling, they will be


listed at the bottom of the Script Editor window. Use the Previous and Next
buttons at the bottom of the Script Editor to move from one message to the
next. As you move from message to message, the appropriate line in the
Script Editor will be selected.

A compiler error is shown in the following illustration.

When you select a


message, the appropriate
line is selected in the
Script Editor.

Use these buttons to


move between messages.

You can also display compiler messages in the Compile Messages window,
shown in the following illustration.

PROGRAMMER’S GUIDE VOLUME 2 33


PA RT 1 SA N SCRI P T

Open the Compile Messages window by clicking the Compile Message


button in the Script Editor. To have the window open automatically when
any compiler errors occur, mark the Open Compiler Messages On Errors
item in the Options window in Dexterity. You can also choose whether the
Compile Messages window will display compiler errors, compiler
warnings, or both types of messages.

These options specify when the


Compile Messages windiw is
opened, and what it displays.

When the Script Editor window is open, The Compile Messages window
shows the errors and warnings for the current script. If the Script Editor is
not open, the Compile Messages window lists all of the compiler messages
from the last scripts that were compiled.

Compiling multiple scripts


To compile all scripts for a form or group of forms, select the form or forms
in the Resource Explorer, and then click the Compile button. All of the
scripts for the form, including window and field scripts, will be compiled.

If you would like to compile all scripts in your dictionary, click the Compile
Dictionary button in the Resource Explorer toolbar. A progress indicator
will be displayed, showing the progress of the compile operation.

Online help support


Help support for the sanScript language is built into the Script Editor. This
feature allows you to look up the syntax of a sanScript statement or
function directly from the Script Editor. To use this feature, simply highlight
the keyword or keywords of the command for which you want help, and
then press F1 in. The Dexterity help system will open and display the help
entry for the selected command.

34 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 T HE S C R I PT E D IT O R

The following illustrations indicate how to make selections in the Script


Editor to request help for the various types of sanScript commands.

For a statement, highlight


the first keyword for the
statement.

For a program structure,


highlight the first keyword
of the program structure.
For a function, highlight
the function keyword, but
not the parentheses for
the function.
For a function from a
function library, highlight
the entire function name,
but not the parentheses
for the function.

If a help entry can’t be found for the text you have selected, the help system
will attempt to find help for an item in the current line of the script. If no
help can be found, the Script Editor will beep.

Naming scripts
Dexterity automatically enters script names for scripts when the Script
Editor opens. These names closely follow the naming conventions used for
products like Microsoft Dynamics™ GP, and are based upon the type of
script and where it’s attached. You can use the automatically-generated
names or your own script names.

The following table describes the conventions used for the automatically-
generated script names. The descriptions use the following standards:

• Bold text in the name indicates text that’s included as shown.

• Italicized text indicates items that are replaced by other names or values.

PROGRAMMER’S GUIDE VOLUME 2 35


PA RT 1 SA N SCRI P T

Script type Name and components Example


Form scripts FormName_FORM_Type This is the name of the form post script for the
- FormName – The name of the form. Sellers form.
- Type – The type of form script. The type can be Sellers_FORM_POST
one of the following:
PRE Form pre script
POST Form post script
Window WindowName_WIN_Type This is the name of window pre script for the
scripts - WindowName – The name of the window. Sellers window.
- Type – The type of window script. The type can be Sellers_WIN_PRE
one of the following:
ACT Window activation script
PRE Window pre script
POST Window post script
PRINT Window print script
Field scripts WindowName FieldName_Type This is the name of the field post script for the
- WindowName – The name of the window the field Seller ID field in the Sellers window.
is in. Sellers Seller ID_POST
- FieldName – The name of the field.
- Type – The type of field script. The type can be
one of the following:
PRE Field pre script
CHG Field change script
POST Field post script
CONTEXTMENU Field context menu script
MOUSE_ENTER Field mouse enter script
MOUSE_EXIT Field mouse exit script
DBLCLICK Tree view or list view double-click script
STATECLICK Tree view or list view state click
script
ITEMCHANGED List view item changed script
COLLAPSE Tree view collapse script
EXPAND Tree view expand script
Procedures PROCEDURE_Number This is the name of the third procedure script
- Number – The number of the procedure in the in the application dictionary.
application dictionary, incremented sequentially. PROCEDURE_3
Functions FUNCTION_Number This is the name of the third function script in
- Number – The number of the function in the the application dictionary.
application dictionary, incremented sequentially. FUNCTION_3
Form-level FormName_FORM_PROCEDURE_Number This is the name of the first form-level
procedures - FormName – The name of the form. procedure for the Sellers form.
- Number – The number of the procedure in the Sellers FORM_PROCEDURE_1
form, incremented sequentially.

36 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 T HE S C R I PT E D IT O R

Script type Name and components Example


Form-level FormName_FORM_FUNCTION_Number This is the name of the first form-level
functions - FormName – The name of the form. function for the Sellers form.
- Number – The number of the function in the form, Sellers FORM_FUNCTION_1
incremented sequentially.
Command FormName_COMMAND_CommandName This is the name of the script for the
scripts - FormName – The name of the form the command CMD_BuyersReport command defined for the
is associated with. Main Menu form.
- CommandName – The name of the command. Main Menu_COMMAND_CMD_BuyersReport
Menu scripts FormName_MENU_MenuName_ITEM_ItemName This is the name of the script for the Activate
- FormName – The name of the form the menu is item in the Actions menu of the Sellers form.
associated with. Sellers_MENU_Actions_ITEM_Activate
- MenuName – The name of the menu.
- ItemName – The name of the item in the menu.
Scrolling ScrollingWindowName SCROLL_Type This is the name of the line pre script for the
window line - ScrollingWindowName – The name of the Seller_Lookup scrolling window.
scripts scrolling window. Seller_Lookup SCROLL_PRE
- Type – The type of scrolling window script. The
type can be one of the following:
PRE Scrolling window line pre script
CHG Scrolling window line change script
POST Scrolling window line post script
FILL Scrolling window line fill script
INS Scrolling window line insert script
DEL Scrolling window line delete script

PROGRAMMER’S GUIDE VOLUME 2 37


38 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 3: Attaching Scripts
You can attach scripts to fields, windows, forms and menus. The following
sections describe how to attach scripts:

• Field scripts
• Window scripts
• Form scripts
• Other scripts

Field scripts
To apply a script to a field, such as a push button or a string field, display
the layout window for the window containing the field. Use the arrow tool
to select the field. Display the Properties window and click the Script tab;
the script types for the field will be displayed.

To apply a script, select a


type from the list and click
the lookup button.

These are the script


types for the field.

In the properties list, select the type of script to apply and click the lookup
button. The Script Editor window will open. After you’ve saved the script,
its name will appear next to the type in the properties list.

PROGRAMMER’S GUIDE VOLUME 2 39


PA RT 1 SA N SCRI P T

Double-clicking the script type in the properties list will also open the Script Editor
window.

The script type you choose depends on the field you’re attaching a script to
and when you want the script to run.

Field pre script This script runs when the focus (the location where the
user currently can enter information) moves to the field from another
location in the window.

Field change script This script runs if the value of the field has
changed and the focus moves out of the field. Typically, most of an
application’s scripts are change scripts.

In fields that toggle, such as push buttons or visual switches, the change
script runs as soon as you click the field. For instance, a push button may
use the following change script to open a window:

open window Customer_Note;

In editable fields, such as string or integer fields, the change script runs
when the focus moves from the field and a change is detected. (Dexterity
makes a comparison to the original value of the field to determine whether
the contents of the field changed.)

For tree view fields, this is called the select script. List view fields have the
selection changed and the item changed scripts that run when the selection
of the list field has changed.

Field post script This script runs when the focus leaves the current
field, regardless of whether the value of the field has changed.

ContextMenu script This script runs when the user right-clicks on the
current field. It is used for context menus.

MouseEnter script This script runs when the mouse pointer moves
over the current field.

Avoid using MouseEnter scripts on combo boxes, composites, drop-down lists, and
radio buttons.

MouseExit script This script runs when the mouse pointer moves off of
the current field.

Avoid using MouseExit scripts on combo boxes, composites, drop-down lists, and
radio buttons.

40 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 A TT A C H I N G S C R I P T S

Collapse script This script is available only for tree view fields. It runs
when a node of the tree is collapsed.

Expand script This script is available only for tree view fields. It runs
when a node of the tree is expanded.

Double click script This script is available only for tree view and list
view fields. It runs when the user double-clicks a node of the tree or double-
clicks an item in the list.

State click script This script is available only for tree view and list
view fields. It runs when the user clicks the state image for a node of the
tree or an item in the list.

Window scripts
To apply scripts to a window, open the layout for the window. Select the
window by clicking somewhere outside of the window area. The window is
selected when resize handles appear on the window’s perimeter. Display
the Properties window and click the Script tab; the script types for the
window will be displayed.

To apply a script, select a


type from the list and click
the lookup button.

These are the script


types for the window.

In the properties list, select the type of script to apply and click the lookup
button. The Script Editor window will open. After you’ve saved the script,
its name will appear next to the type in the properties list.

PROGRAMMER’S GUIDE VOLUME 2 41


PA RT 1 SA N SCRI P T

Window pre script This script runs just as the window is opened.
Typically, window pre scripts can be used to set default values in the
window, or to disable buttons or specific fields before the window is
displayed. Window pre scripts also run when the restart form or restart
window statements are used.

For example, in windows that contain a Delete button, you may want to
disable the button in the window pre script because the window contains
nothing to delete when it opens.

disable field 'Delete Button';

When a record has been retrieved that the user can delete, the Delete button
can be enabled by another script.

Window post script This script runs just as the window is closed. For
example, a window post script can be used to ascertain whether the entries
in the window have been saved to a file when the user closes the window. If
the information hasn’t been saved, the script could display a message
asking the user whether he or she wants to save changes.

Window print script This script runs when the window is active and
the user chooses the Print menu item. Typically, the window print script
uses the run report statement to run a report already created using the
Report Writer.

For example, the following print script prints an invoice when the Invoice
Entry window is active.

run report Invoice with restriction 'Invoice Number' of


➥ table Invoice_Master = 'Invoice Number';

Window activate script This script runs each time the window
becomes active, such as when it’s opened or brought to the front after the
user has stopped working with another window. The window activate
script runs after the window pre script.

The window activate script must be used cautiously. It should not contain any
commands that create dialog windows (such as messages with the error or
warning statements) because the application will become suspended in an endless
loop.

ContextMenu script This script runs when the user right-clicks on the
window. It is used for context menus.

42 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 A TT A C H I N G S C R I P T S

Form scripts
To apply scripts to a form, open the form by clicking the Forms button on
the toolbar and opening the Form Definition window for the form you want
to attach scripts to. In the Form Definition window, click the Scripts tab. Use
the Pre Script and Post Script buttons to attach scripts to the form.

The script icon indicates a


script has been attached.

Form pre script This script runs just as the form is opened. A form is
opened when a window in the form is opened or when the open form
statement is executed. Typically, form pre scripts are used to set initial
characteristics of windows in the form. The form pre script doesn’t run
when a form is restarted.

Form post script This script runs just as the form is closed. A form is
closed when the main window for the form is closed, or when the close
form statement is executed. Typically, form post scripts are used to set
values in other areas of your application based on values entered in the
windows of the form.

Other scripts
You can use other types of scripts in your application that are described in
other locations:

• Chapter 15, “Commands,” in Volume 1 of the Dexterity Programmer’s


Guide describes using scripts for commands.

• Chapter 10, “Scrolling Windows,” describes scripts used for scrolling


windows.

• Chapter 14, “Form-based Menus,” describes attaching scripts to form-


based menu items.

• Chapter 12, “Tree View,” describes attaching scripts to tree view fields.

• Chapter 13, “List View,” describes attaching scripts to list view fields.

• Chapter 20, “Procedures,” describes using procedure scripts.

• Chapter 21, “User-defined Functions,” describes using function scripts.

PROGRAMMER’S GUIDE VOLUME 2 43


44 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 2: BASIC SCRIPTING
Part 2: Basic Scripting
• Chapter 4, “Writing scripts,” provides an overview of scripting, and
contains a procedure for writing scripts.

• Chapter 5, “Communicating With the User,” describes scripting


techniques that allow your application to interact with the user.

• Chapter 6, “Performing Calculations,” explains how to perform various


types of calculations with scripts.

• Chapter 7, “Program Structures,” describes the various program struc-


tures available in sanScript to control the execution of your application.

46 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 4: Writing scripts
To make your application perform useful work, you need to add scripts.
You should create most of the forms, fields, tables and windows in your
application before writing and attaching scripts, because you’ll be
referencing these items from within scripts. Information about creating
scripts is divided into the following sections:

• Scripting overview
• Interaction-based programming
• Procedure: Creating scripts

Scripting overview
Scripts are the essential element that allow an application to perform useful
work. In Dexterity-based applications, scripts perform three basic
functions:

• Performing calculations
• Controlling the user interface
• Working with data in tables

While these are the basic functions a script can have, any particular script
may perform one or more of them.

Performing calculations
In almost all cases, applications written with Dexterity perform some type
of calculations based on data supplied by the user or previously stored in
tables. Chapter 6, “Performing Calculations,” describes special situations
you should be aware of when performing calculations in your application.

Controlling the user interface


Another common task for scripts is controlling the user interface. Some
scripts may perform actions as simple as opening or closing windows.
Many scripts are required if your application uses powerful user interface
elements, such as a tree view or list view. Part 3, Working with Controls,
provided detailed information about how to use scripts with these types of
controls.

PROGRAMMER’S GUIDE VOLUME 2 47


PA RT 2 B A S I C S C R I P T I N G

Working with data in tables


The majority of the code in most Dexterity-based applications is needed to
work with tables. The ability to successfully work with data in tables is the
single most important skill you need to create good applications with
Dexterity. Part 4, Working with Tables, provided detailed information
about how to work with tables in Dexterity-based applications.

Interaction-based programming
In traditional procedural languages, like Pascal or BASIC, programs
typically consist of a main routine that runs when the program starts. This
routine may issue program calls to other routines. When the main routine
has finished, so has the program. Any interaction between the program and
the user is restricted. The user can interact with the program only when the
program allows it.

Graphical applications like those written in Dexterity operate differently.


Rather than having one main routine that runs when the program starts,
code is spread out through the interface. The individual pieces of code run
when the user interacts with the form, window or control where the code is
located. The interaction between the program and the user is not restricted
in any way. The user can interact with any element in the interface at any
time.

This “interaction-based” approach to designing programs is new to many


people learning to create applications with Dexterity. As the programmer,
you need to ensure the program performs the desired tasks, and you also
need to manage all of the possible interactions between the program and
the user.

The next section contains a general procedure you can use when creating
scripts for Dexterity-based applications. This procedure attempts to handle
the “interaction” aspects of scripting, as well as the “functional” aspects.

48 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 WR I T IN G S C R IP T S

Procedure: Creating scripts


To create and attach scripts, open the dictionary the scripts will be part of,
and follow these steps.

1. Decide the function of the script.


Scripts perform tasks such as storing information in and retrieving
information from tables, displaying and modifying data, and
performing numeric calculations. With this in mind, determine the task
your script will perform.

2. Outline the steps the script must perform.


• List the resources the script needs in order to function.

• List any assumptions you make about the script operation.

• Decide what the output or results of the script will be.

• Look for problems the script might encounter, such as having incor-
rect data, or not finding data at all. Think of navigational problems
as well; for instance, the user might close the window before enter-
ing all the necessary data. Think of actions the user could take to
“upset” the script.

3. Decide where the script should be attached and when it


should be run.
Determine when you want your script to run and decide what part of
the application the user will be using when the script is run. Does some
specific action such as clicking a button, closing a window, or moving
the focus out of a field cause the script to run? These answers will tell
you whether you should attach your script to a form, window or field,
and whether the script should be a pre, change or post script.

4. Convert the outline to sanScript.


Convert each step you outlined for the task to sanScript. Refer to the
SanScript Reference and the Function Library Reference manuals for
information about specific script commands.

5. Attach the script.


Use the information in Attaching Scripts on page 39 to attach the script
to the appropriate location.

PROGRAMMER’S GUIDE VOLUME 2 49


PA RT 2 B A S I C S C R I P T I N G

6. Test the script.


Once you’ve written and compiled the script without errors, choose
Test Mode from the Debug menu. Test the application where the script
will run to see the results.

50 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 5: Communicating With the User
The interface you provide for your application is the primary method the
user will have to interact with it. Various sanScript commands are available
to help your application interact with the user. Information about them is
divided into the following sections:

• Dialogs
• Controlling forms and windows
• Controlling fields
• Controlling the focus

Dialogs
Several statements and functions allow you to communicate with the user.
The following are some of the methods you can use.

The warning and error statements


For more information The warning and error statements produce a dialog box that displays a
about the ask() message for the user. This script produces the error dialog shown in the
function, the error following illustration.
statement and the
warning statement, error "This customer number is invalid.";
refer to the SanScript
Reference manual.

You may want to display multiple lines within a dialog box. To have a
multi-line message where you control the line breaks, you need to use a
local text field as the source of the message text. When a text value is
displayed in a dialog box, Dexterity will automatically add a scroll bar and
allow multiple lines to be displayed. You can use the char() statement to
indicate a new line.

PROGRAMMER’S GUIDE VOLUME 2 51


PA RT 2 B A S I C S C R I P T I N G

The following example shows how to create a multi-line message. It


produces the dialog shown in the following illustration.

local text message;

message = "First line" + char(13) + "Second line";


warning message;

The ask() function


The ask() function creates a dialog box that contains a message and up to
three buttons. (It can have a fourth button labeled Help, if you implement
online help for your application). The ask() function returns an integer
value that indicates which button was clicked by the user. This script
produces the ask dialog shown in the following illustration.
local integer answer;

answer = ask("Delete this item?","Yes","No","Cancel");

If the value of the local variable answer is 1, then the user clicked Yes. If the
value is 2, the user clicked No, and if it’s 3, the user clicked Cancel. You can
use the ASKBUTTON constants when examining the return value.

52 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 5 C O M M U N IC AT IN G WI T H T H E U S E R

Controlling forms and windows


You will use scripts to control forms and windows in your application. The
following commands show some of the actions scripts can perform.

Opening or closing forms


The open form statement opens forms. The following script opens the
Houses form.

open form Houses;

You need to open the form before you can open any of the windows that are part of
the form.

The close form statement closes a form. The following script closes the
House_Lookup form.

close form House_Lookup;

Opening or closing windows


The open window statement opens windows. The following script opens
the Customer_History window.

open window Customer_History;

The close window statement closes windows. The following script closes
the Customer_History window.

close window Customer_History;

Controlling fields
Once a window is open and visible to the user, you can use scripts to
control how the fields appear in the window. The following commands
show some of the actions scripts can perform for fields.

Hiding or showing fields in a window


The hide field statement makes a field in the window invisible and
inaccessible to the user. The following script hides the Sales Tax field of the
current window.

hide field 'Sales Tax';

PROGRAMMER’S GUIDE VOLUME 2 53


PA RT 2 B A S I C S C R I P T I N G

The show field statement makes a previously invisible field visible and
accessible to the user. The following script makes the Sales Tax field of the
current window visible.

show field 'Sales Tax';

Disabling or enabling fields in a window


The disable field statement makes a field appear in gray and makes it
inaccessible to the user. The following script disables the Sales Tax field of
the current window.

disable field 'Sales Tax';

The enable field statement makes a previously disabled field accessible to


the user. The following script enables the Sales Tax field.

enable field 'Sales Tax';

Locking or unlocking fields in a window


The lock statement makes a field inaccessible to the user. The following
script locks the Sales Tax field of the current window.

lock field 'Sales Tax';

The unlock statement makes a previously locked field accessible to the user.
The following script unlocks the Sales Tax field.

unlock field 'Sales Tax';

Controlling the focus


The focus statement moves the focus (the location where the user currently
can enter information) to the specified field. The following script moves to
the focus to the Account Number field.

focus field 'Account Number';

54 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 6: Performing Calculations
Scripts are used to perform all of the calculations in your application.
Information about performing calculations is divided into the following
sections:

• Basic calculations
• Overflow in numeric expressions
• Calculations with variable currency values
• Bit operations
• Hexadecimal values
• String calculations

Basic calculations
To perform basic numeric calculations in a script, simply use a numeric
expression. For example, the following script computes the average utility
bill for a three-month period.

local currency average_cost;

average_cost = ('January Cost' + 'February Cost' + 'March Cost') / 3;

For more information about the types of expressions available in sanScript,


refer to Expressions on page 16.

Overflow in numeric expressions


Overflow in a numeric expression occurs when an intermediate or final
result of the expression it too large to be stored by the type of data used in
the expression. This is especially common with integer values.

For example, multiplying the integers 450 and 75 should result in the value
33,750, but instead results in -31,786. Because the actual result is larger than
32,767, the maximum amount that can be represented by an integer in
Dexterity, overflow occurs.

PROGRAMMER’S GUIDE VOLUME 2 55


PA RT 2 B A S I C S C R I P T I N G

One method of preventing overflow is to convert all integer values in the


expression to long integers and then evaluate the expression. All integers in
the expression, not just the final result, must be converted to long integers
to avoid overflow. This is because the overflow can occur in intermediate
steps while evaluating the expression, not only the final step. For example,
the expression in the following script would still overflow:
local long product;

product = 450 * 75;

To avoid the overflow, the two integer values must also be converted to
long integers as shown in the following script:

local long product, operand1, operand2;

operand1 = 450;
operand2 = 75;
product = operand1 * operand2;

Calculations with variable currency values


Variable currency values are especially useful when you need to perform
calculations that require several digits of precision. This section provides
information about using variable currency values in scripts.

To use a variable currency value as a local variable, use the keyword


vcurrency. For example, the following statement declares a local variable
currency value.

local vcurrency interest_rate;

You can perform calculations with variable currency values much like you
perform calculations with standard currency values. All currency functions
such as round() and truncate() work properly with variable currency
values.

To ensure no precision is lost when performing calculations, intermediate


variable currency results can have up to 39 digits with up to 15 decimal
places. The number of digits and decimal places is determined by the value
being calculated.

56 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 6 P ER FO R M I N G C AL C U L A TI O N S

Rounding
When performing calculations with currency or variable currency values,
the final results often must be rounded. You can use the round() function to
round individual values. You can also use the default roundmode to
statement to specify the default rounding characteristics for all calculations
in a specific script.

Retrieving variable currency characteristics


If precision is important in a calculation, you may want to retrieve the
characteristics of a specific variable currency field or value. Use the
precision() function to retrieve the number of digits a variable currency
field or variable can store. Use the scale() function to retrieve how many
decimal places a variable currency field or variable has.

Bit operations
Dexterity includes several functions that allow you to perform bit-wise
operations on integral values. An integral value is one that doesn’t have a
fractional portion, such as an integer. Use the following functions to clear,
set and test the status of a bit:

• bitclear()
• bitset()
• bittest()

Refer to the SanScript Reference manual for more information about using
these functions.

Hexadecimal values
Refer to the SanScript In sanScript, tiny integer, integer and long integer values can be represented
Reference manual for in hexadecimal form. To indicate a hexadecimal value, use one of the
more information following forms:
about the hex() and
value() functions. &hnnnnnnnnn

0xnnnnnnnnn

In these representations, n is a hexadecimal digit (0 to 9, A to F). The first


form is used by Visual Basic®. The second form is standard in C. The
following example shows how to use the hexadecimal representation.

int_value = &hFF;

PROGRAMMER’S GUIDE VOLUME 2 57


PA RT 2 B A S I C S C R I P T I N G

You can convert values between the hexadecimal representation and the
decimal equivalent. The hex() function returns a string containing the
hexadecimal equivalent of an integral value. The value() function can be
used to return the integral equivalent of a string containing a hexadecimal
value.

String calculations
Calculations involving strings and string values are also common in
Dexterity-based applications.

Appending strings
Appending strings together is a common sanScript operation. For example,
the following code appends the Company Name variable into a string.

local string result;

result = "Company " + 'Company Name' + " is eligible for a discount.";

String commands
Several sanScript commands are available to work with strings. Some
commands retrieve information about a string. Other commands
manipulate the string and return the results. For example, the length()
function returns the number of characters in a string. The substring()
function returns the specified portion of a string. Refer to the sanScript
Reference for a complete list of commands that work with strings.

Comparing strings
When strings are compared in boolean expressions, the ASCII values of the
characters in the strings are compared, one character at a time from left to
right, until a character doesn’t match or one of the strings has no more
characters.

If two corresponding characters don’t match, the result of their comparison


is returned as the result of the string comparison. If all of the characters in
the two strings match up to the point where one of the strings runs out of
characters, the shorter string is considered less than the longer string.

ASCII values for lowercase characters are larger than ASCII values for uppercase
characters.

58 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 6 P ER FO R M I N G C AL C U L A TI O N S

The following table lists sample string comparisons.

String1 < <= = <> >= > String2


"A" F T T F T F "A"
"A" T T F T F F "AB"
"B" F F F T T T "AB"
"A " F F F T T T "A"
"ABC" T T F T F F "ABCD"
"ABC" T T F T F F "Z"

PROGRAMMER’S GUIDE VOLUME 2 59


60 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 7: Program Structures
There are several program structure available in sanScript that you will use
to control the flow of your code. Information about program structures is
divided into the following sections:

• Decision structures
• Loop structures

Decision structures
Two decision structures are available for use in scripts.

If then...end if
The if then...end if statement is one of the structures you can use to make
decisions. The if then...end if statement evaluates boolean expressions and,
based on the results, executes a set of sanScript statements.

The following script uses an if then...end if statement to execute a set of


statements based upon the value of the Purchase Amount field.

if 'Purchase Amount' > 'Credit Limit' then


error "Credit limit exceeded. Can't process the transaction";
'Transaction Complete' = false;
else
'Transaction Complete' = true;
end if;

If the purchase amount is greater than the credit limit, an error message is
displayed and the Transaction Complete field is set to false. Otherwise, the
Transaction Complete field is set to true.

PROGRAMMER’S GUIDE VOLUME 2 61


PA RT 2 B A S I C S C R I P T I N G

Case...end case
The other decision structure you can use in scripts is the case...end case
statement. Like the if then...end if statement, this statement allows a series
of statements to run on a conditional basis.

The following script uses the case...end case statement to o set the rebate
amount to be paid to customers based upon their total purchases for the
fiscal year.

case 'FY Total Purchases'


in [-99999 to 999]
'Rebate Award Amount' = 0;
in [1000 to 2999]
'Rebate Award Amount' = 15;
in [3000 to 4999]
'Rebate Award Amount' = 25;
else
'Rebate Award Amount' = 50;
end case;

The case...end case statement makes it easy to run sanScript statements


based on ranges of values.

Loop structures
In cases where you want a set of sanScript statements to be executed
repeatedly, you will use a loop structure. Several loop structures are
available in sanScript.

For loop
The for loop iterates a variable through a specified range of variables. They
are useful when you need to use the value of the variable being iterated,
such as for an array index.

The following script uses a for do...end for statement to set the fields of the
Monthly Total array to 0.

local integer i;

for i = 1 to 12 do
'Monthly Total'[i] = 0;
end for;

62 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 7 P R O G R AM S T R U C T U R E S

Repeat loop
The repeat loop runs a set of sanScript statements, then tests a boolean
condition to determine whether the loop should be repeated. Using a
repeat...until statement ensures that the statements within the loop will be
run at least once.

The following script uses a repeat loop to read through all of the records in
a temporary table.

get first table Temptable;


repeat
get next table Temptable;
until err() = EOF;

While loop
The while loop tests a boolean expression. If the expression is true, the set
of sanScript statements in the loop is run. Using a while do...end while
statement ensures that the condition of the loop is tested before any of the
statements within the loop are ever executed.

The following example uses a while loop to read through all of the records
in a table.

get first table Customer_Master;


while err() = OKAY do
{Not at the end of the table, so read the next item.}
get next table Customer_Master;
end while;

PROGRAMMER’S GUIDE VOLUME 2 63


64 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 3: WORKING WITH CONTROLS
Part 3: Working with Controls
This portion of the documentation describes how to use various user
interface controls available in Dexterity. The following topics are discussed:

• Chapter 8, “Standard Controls,” provides information about control


found in most applications, such as push buttons and check boxes.

• Chapter 9, “Composites,” describes how to use composite fields in an


application.

• Chapter 10, “Scrolling Windows,” explains how to use scrolling win-


dows in an application.

• Chapter 11, “Lookups,” describes how to implement lookup windows


in your application.

• Chapter 12, “Tree View,” explains how to use the tree view control.

• Chapter 13, “List View,” explains how to use the list view control.

66 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 8: Standard Controls
Dexterity provides several standard controls, such as push buttons, check
boxes, and radio buttons. This portion of the documentation provides
detailed information about how to use these controls in your application.
Information about the standard controls is divided into the following
sections:

• Button drop lists


• Check boxes
• Drop-down lists and combo boxes
• Push buttons
• Radio buttons
• String fields
• Text fields
• Controls on toolbars
• Tooltips

Button drop lists


Button drop lists are typically used to provide a method of navigation in an
application. When you define a button drop list data type, you can specify
what will appear on the button and the static text items that will appear in
the list.

Caption and image


The button portion of a button drop list can display a text item, a graphic
item, or both text and graphics. You can use pictures or native pictures for
graphics that appear on the button drop list.

A button drop list can have up to three images: an Up image, a Down image
and an Over image. The Up image is displayed when the button isn’t being
clicked. The Down image is displayed when the button is being clicked. The
Over image is displayed when the pointer is positioned over the button
drop list.

You can use the Field_SetImage() function to specify the images to use for a
button drop list from within scripts.

Use the Style property for the button drop list field to specify which types
of items are displayed on the button. The Style property also controls the
arrangement of the items.

PROGRAMMER’S GUIDE VOLUME 2 67


PA RT 3 WO RKING WI TH C ONTR O LS

If you select 3D Highlight for the Appearance property, the text caption in the
button portion of the button drop list will become bold when the field has the focus.
Be sure to provide extra space for the caption to accommodate the bold text.

Drop indicator
Typically, button drop lists have a drop indicator (a small triangle) in the
lower-right corner of the field. It’s not necessary to include the drop
indicator in the image for the button drop list. Instead, set the
DropIndicator property to True. Use the DropPosX and DropPosY
properties to specify the distance the drop indicator will appear from the
lower-right corner of the button drop list.

This is the drop indicator.

From sanScript, you can use the Field_SetBooleanProperty() and


Field_SetIntegerProperty() functions to specify the characteristics of the
drop indicator.

Cascading items
In some cases, you may want to have a hierarchy in the items appearing in
the list. To do this, you must build the contents of the button drop list with
sanScript code. The Field_BDLCreateSubmenu() and
Field_BDLAddToSubmenu() functions can be used to create cascading or
“pull-right” items in button drop lists. The following illustration shows a
button drop list with cascading items.

68 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 8 S TA N D A R D C O N T R O L S

Check boxes
You can use picture static values with check boxes. In addition, you can use
the Style property to specify whether the check box will appear as a
standard check box or as a push button. The following illustrations show
how check boxes look with the various styles.

Normal style Push button style


Marked

Not marked

If you change the Style property for a check box that uses static picture values, use
the Size to Default tool in the toolbox to resize the check box field to the appropriate
size.

If you use pictures (picture resources) as the static values for a push button-
style check box, you can specify two, four or six images. These images are
used for the various check box states.

• If you specify two images, these images will be used for the up and
down states, respectively.

• If you specify four images, these will be used for the up, up clicked,
down, and down clicked states, respectively.

• If you specify six images, the Appearance property for the check box
must be set to 3D Highlight. The images will be used for the up, up
clicked, down, down clicked, up highlight and down highlight states,
respectively.

PROGRAMMER’S GUIDE VOLUME 2 69


PA RT 3 WO RKING WI TH C ONTR O LS

The following illustration shows the six picture static values defined for the
Note check box field.

The pictures used for


the check box must be
in this order.

Drop-down lists and combo boxes


Use the VisibleItems property to specify the maximum number of items
that will be displayed by a drop-down list or combo box in the dropped
state. If the drop-down list or combo box has more items to display than can
fit in the list, a scroll bar is drawn automatically.

Push buttons
Push buttons provide a method of starting processing in an application.

Caption and image


A push button can display a text item, a graphic item, or both text and
graphics. In versions of Dexterity prior to 6.0, only native pictures could be
used. Now, pictures or native pictures can be used.

Use the Style property for the push button field to specify which types of
items are displayed on the button. The Style property also controls the
arrangement of the items.

70 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 8 S TA N D A R D C O N T R O L S

The following table shows the arrangements possible for text and graphics
on a push button.

Style Example
Text Only

Graphic Only

Text on Top

Text on Bottom

Text on Right

Text on Left

A push button can have up to three images: an Up image, a Down image


and an Over image. The Up image is displayed when the button isn’t being
clicked. The Down image is displayed when the button is being clicked. The
Over image is displayed when the pointer is positioned over the push
button.

If you supply only the Up image for a push button, the Down image will be
drawn automatically when the push button is clicked.

You can use the Field_SetImage() function to specify the images to use for a push
button from within scripts.

PROGRAMMER’S GUIDE VOLUME 2 71


PA RT 3 WO RKING WI TH C ONTR O LS

Appearance
The Appearance property specifies what type of border appears for a push
button. A push button can have a 2-D border or 3-D border.

This is the 3D This is the 3D


border drawn border drawn
on the button on the button
up picture. down picture.

When designing the button graphics, keep in mind that the 3D border will
be drawn on top of the outer two rows of pixels on the button up and
button down images.

You can also use the Appearance property to have push button display with
a 3-D highlight. With this setting, the push button has a flat appearance
until the mouse pointer is moved over the button. Then the button displays
a 3-D appearance. An example is shown in the following illustration.

Normally, the When the mouse pointer


button has a flat moves over the button, the
appearance. 3-D highlight is displayed.

If you select 3D Highlight for the Appearance property, the text caption in the push
button will become bold when the field has the focus. Be sure to provide extra space
for the caption to accommodate the bold text.

Behavior
Several properties for push buttons control their behavior.

Default
Use this property to specify which push button field change script will run
when the user presses ENTER when the window is active. Only one push
button in a window should have this property set to true. Typically, this
property is set to true for an OK button that appears in the window.

Use the Field_SetBooleanProperty() and Field_GetBooleanProperty()


functions to change the Default property from within scripts.

72 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 8 S TA N D A R D C O N T R O L S

Cancel
Use this property to specify which push button field change script will run
when the user presses ESC when the window is active. Only one push
button in a window should have this property set to true. Typically, this
property is set to true for a Cancel button that appears in the window.

Use the Field_SetBooleanProperty() and Field_GetBooleanProperty()


functions to change the Cancel property from within scripts.

Hyperspace
This property should be set to true for Close or Cancel buttons appearing in
the window. When Hyperspace is set to true, the Close or Cancel button can
be clicked without running the change script or post script for the currently-
focused field. Only the change script for the Close or Cancel button will
run. This allows the user to close the window, even though the change or
post script for the current field may have prevented it.

Radio buttons
To make radio buttons work properly in your application, the radio group
and radio button fields must be arranged properly in the window. In the tab
sequence, the radio group must come immediately before the radio buttons.
For example, in the Payment Method radio group shown in the following
illustration, the Payment Method radio group field comes immediately
before the Cash, Check and Charge radio button fields in the tab sequence.

In the tab sequence, the


radio group field comes
immediately before the
radio button fields.

PROGRAMMER’S GUIDE VOLUME 2 73


PA RT 3 WO RKING WI TH C ONTR O LS

String fields
You can use the AutoComplete property for string fields to automatically
fill the contents of the field as the user types, based on the values previously
entered for the field.

Using auto-complete
To use the auto-complete capability for a string field, you must set the
AutoComplete property to true for every occurrence of the field for which
you want the functionality. When a user adds a value to the field and moves
the focus, the value is added to the auto-complete list for the field.

When the user begins to type characters into a field with the AutoComplete
property set to true, the auto-complete list for the field will be examined to
find any matches. The matching items will be displayed in a drop-down
list. The user can continue typing a value to refine the items listed, or use
the arrow keys or mouse to select one of the items in the list. If drop-down
list isn’t large enough to fully display the auto-complete items, use the
resize area in the corner of the list to expand the list.

If any matches are found in the


auto-complete list, the
matching items will be
displayed in a drop-down list.

To remove an item from the auto-complete list, right-click the item and
choose Remove From List in the menu that appears.

If the same global field appears in multiple windows, and the


AutoComplete property is set to true for each instance, the fields will share
the auto-complete data. Auto-complete values entered in one field will also
be available in the other field instances. The behavior is the same for a local
field that appears in multiple windows within a form. If each instance of the
local field has the AutoComplete property set to true, the local field will
share the auto-complete data.

74 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 8 S TA N D A R D C O N T R O L S

If the auto-complete field has a linked-lookup button, an additional item


will appear at the bottom of the auto-complete list. Choosing this item will
open the lookup window, just as if the lookup button had been clicked. You
can use the Field_SetStringProperty() function to specify the text used for
this item.

Choosing this item


performs the same action
as clicking the lookup
button for the field.

Enabling and disabling auto-complete


You can enable or disable auto-complete for the entire application or for
individual fields. Use the AutoComplete_SetMode() function to enable or
disable auto-complete for the entire application.

To enable or disable auto-complete for individual fields, use the


Field_SetBooleanProperty() function with the appropriate constant. To
find out whether auto-complete is enabled for a field, use the
Field_GetBooleanProperty() function.

Adding auto-complete items


Values are added to the auto-complete list for a field any time the focus
moves to the field, the content of the field changes, and the focus leaves the
field. A user changing a field’s value, or a lookup window returning a value
are common ways that values are added to the auto-complete list.

From sanScript, you can use the AutoComplete_AddStringValue()


function to add values to the auto-complete list. This can be useful if you
want to pre-load a set of auto-complete values for a specific field.

PROGRAMMER’S GUIDE VOLUME 2 75


PA RT 3 WO RKING WI TH C ONTR O LS

Saving auto-complete items


When you run your application with the Runtime engine, the auto-
complete items are written to files that are stored in the “Application Data”
folder for the user currently logged into the workstation. The auto-complete
values stored in this table will be used the next time the application is run.

Inside the “Application Data” folder is the “Microsoft Business Solutions”


folder, which contains another folder that is based on your application’s
name. By default, auto-complete files will be stored here. If you want your
application to have multiple sets of auto-complete items, such as one set for
each different company, you can use the AutoComplete_SetOptions()
function to specify the name an additional folder that will be created to
store the auto-complete files.

If you’re running your application in test mode, auto-complete items will work for
the current session, but are not stored in this file.

Removing auto-complete items


You can use the AutoComplete_RemoveFieldData() function to remove all
the auto-complete items for a specific field. To remove only specific auto-
complete items for a field, use the AutoComplete_RemoveStringValue()
function. Users can remove a specific auto-complete item by right-clicking
it and choosing to remove it. You can remove all auto-complete items by
calling the AutoComplete_RemoveAllData() function.

Auto-complete items can also be removed automatically. The


AutoComplete_SetOptions() function allows you to specify the maximum
number of auto-complete items a field can have. If this limit is exceeded, the
oldest auto-complete items are deleted. You can also specify how long
unused auto-complete items remain in the auto-complete data. Each time
an auto-complete item is selected, it is updated with the workstation’s
current system date. If the age of an auto-complete item exceeds the
specified limit, the item will be removed.

76 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 8 S TA N D A R D C O N T R O L S

Text fields
Use the EditMode, ScrollBars and WordWrap properties to specify the
characteristics of text fields on the window:

• By default, the EditMode property is set to Editable. Set the EditMode


property to DisplayOnly to prevent the user from editing text in the
field. Set the EditMode property to SelectOnly to allow the user to
select and copy text, but not edit it.

• By default, text fields display scroll bars. To hide the scroll bars, set the
ScrollBars property to false.

• The WordWrap property controls whether text wraps in the text field.
By default, text does not wrap in a text field. Set the WordWrap prop-
erty to true to make text wrap.

Controls on toolbars
Toolbars typically contain a row of push buttons or button drop lists that
allow the user to navigate to other windows in the application. Toolbars
should contain only fields that don’t need to keep the focus to operate: push
buttons, drop-down lists, button drop list or visual switches. Toolbars can
also contain fields for which the Editable property is set to false.

Tooltips
Most controls allow you to specify a tooltip, which is a small piece of text
that describes the control. The tooltip is displayed when the user moves the
pointer over the top of a control, as shown in the following illustration.

The tooltip appears


when the pointer
moves over a field.

Often, tooltips are used for fields that require additional explanation, such
as buttons on a toolbar. To add a tooltip, select the control in the layout
window and enter a value for the Tooltip property. You can also use
the Field_SetToolTip() function to set a tooltip from a script. Use the
Field_GetToolTip() function to retrieve a tooltip.

PROGRAMMER’S GUIDE VOLUME 2 77


78 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 9: Composites
A composite is a group of fields and their associated data types which form
a single data type. Each part of the composite is called a component. Once
defined, a composite data type can be used like any ordinary data type.

Composites can be used to store information such as account or item


numbers, which are composed of several parts. Each component of the
composite can have different formatting characteristics, allowing you to
display information in a variety of ways.

Composites should be composed of only string and numeric fields, and the
total length of the composite must not exceed 128 characters. While it is
possible to include some other control types in composites, we don’t
recommend it. Text and picture control types should never be included as
composite components.

Dexterity supports two types of composites: standard composites, which


can have up to 9 components, and extended composites, which can have up
to 128 components. Standard composites have a fixed length and flexible
formatting while the length of extended composites is determined at
runtime, but the formatting is slightly less flexible. Extended composites
are used for special purposes such as the account numbers in Microsoft
Dynamics GP.

Information about composites is divided into the following sections:

• Procedure: Creating standard composites


• Procedure: Creating extended composites
• Accessing composites from within scripts
• Component-based scripts
• Comparing composites

PROGRAMMER’S GUIDE VOLUME 2 79


PA RT 3 WO RKING WI TH C ONTR O LS

Procedure: Creating standard composites


Follow this checklist to create a standard composite data type and field.
Refer to the related items listed at the end of this chapter for more
information about creating the fields, data types and formats referred to in
the checklist.

1. Create the data types for the components.


Determine the components of the composite and create data types for
each different component. Data types used for components of a
composite shouldn’t be used for other fields.

2. Apply formats to the components (if necessary).


Create and apply a format to each component that requires special
formatting.

3. Create a field for each component of the composite.

4. Create the composite’s data type.


Open the Data Type Definition window. Enter the name for the data
type, select Composite from the Control Type list, then click the
Composite lookup button; the Composite Lookup window will open.
Click New to open the Composite Definition window, shown in the
following illustration.

Enter the composite


name here.

These are the global


fields that make up the
composite.

80 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 9 C O M P O S IT E S

5. Create the new composite.


Refer to Chapter 7, To create a new composite, name the composite, then highlight each
“Formats,” in Volume 1 component in the Fields list and click Insert to add it to the composite
of the Dexterity definition. The order of the components is significant; the first field in
Programmer’s Guide the Components list is the first component of the composite, the second
for information about field is the second component, and so on. No component can be used in
applying a format to a more than one composite. When you are finished adding components,
composite. click OK.

6. Apply a format to the composite.


Create and apply a format to the composite. A composite must have a
format with a format string.

7. Create the composite field.


Create a field using the composite data type.

Example 1
This example shows a composite item number with two components.

GPS-1151

Vendor Code Part Number

The first part is a vendor code, which is alphabetic, while the second part is
the actual part number, which is numeric, so a composite consisting of a
string component and an integer component was used for this field. The
string component was formatted as alphanumeric, while the integer
component allows only numbers to be entered. The format string 1111-2222
was applied to the composite to add the dash between the two components.

PROGRAMMER’S GUIDE VOLUME 2 81


PA RT 3 WO RKING WI TH C ONTR O LS

Procedure: Creating extended composites


Follow this checklist to create an extended composite data type and field.
Refer to the related items listed at the end of this chapter for more
information about creating the fields, data types and formats referred to in
the checklist.

1. Create the data types for the components.


Determine the maximum number of components that will be in the
composite and create an individual data type for each component. Data
types used for components of a composite shouldn’t be used for other
fields.

2. Create a field for each component of the composite.

3. Create the composite’s data type.


Open the Data Type Definition window. Enter the name for the data
type, select Composite from the Control Type list, then click the
Composite lookup button; the Composite Lookup window will open.

Click New to open the Composite Definition window. Name the


composite, then highlight each component in the Fields list and click
Insert to add it to the composite definition. The order of the
components is significant; the first field in the Components list is the
first component of the composite, the second field is the second
component, and so on. Be sure that all fields that will be components of
the composite have been inserted into the composite. Also, no
component can be used in more than one composite. When you are
finished adding components, click OK to save the composite.

4. Apply a format to the composite.


Create and apply a basic format with a format string to the first few
components of the composite, just as you would for a standard
composite. The number of components in the format string isn’t critical;
the format string just has to exist. This “starting” format will be
overridden at runtime.

5. Create a field that uses the composite data type.

6. Add the composite field to the main window of the Main


Menu form for your application.
The field should be made invisible and display only by setting the
Visible and Editable properties for the field to False.

82 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 9 C O M P O S IT E S

7. Override the composite format.


In the Main Menu form pre script, use the override field statement to
specify the separator character for the composite and whether scroll
arrows will be displayed. Use the override component statement to
indicate how many components of the composite will be displayed, the
size of the individual components and the character that will be used as
the width base for each component.

An extended composite can have only one type of separator character.


This character can be the “empty” character (""). When using the
override component statement to set the number of components to
display and the component length, remember that the total length of
the composite must not exceed 128 characters, including separators.
Components at the end of the composite are the only ones that can have
their length set to 0, indicating they won’t be displayed by the
composite.

8. Use the extended composite field.


The extended composite field can be used in any windows except
windows associated with the Main Menu form, because it won’t have
the proper format in those windows.

When you add the extended composite field to a window, you must set the size of
the field in the window manually, since Dexterity has no way of knowing how large
to make the field.

Example 2
This example describes how to create and use an extended composite for a
customer number with up to 12 components. Twelve string data types and
fields were created for the extended composite, one for each component.
The following “starting” format string was used when the format for the
composite was created:
11111-22222-33333

The starting format string serves only as a placeholder. The structure and
number of components aren’t critical because the format will be overridden
at runtime.
A field was created using the composite data type, placed on the main
window of the Main Menu form and made invisible and display only by
setting the Visible and Editable properties for the field to false.

PROGRAMMER’S GUIDE VOLUME 2 83


PA RT 3 WO RKING WI TH C ONTR O LS

The customer number composite will have the following characteristics:

Number of components to display 6


Separator character :
Length of the components
Component 1 5
Component 2 4
Component 3 4
Components 4 to 12 2
Display scroll arrows Yes

The following is the Main Menu form pre script used to specify the
characteristics of the customer number composite:
local integer segment;
local string separator, width_char;
local integer maximum_num_segments, num_segments;
local integer seg_length[12];
local boolean scroll_arrows;
maximum_num_segments = 12;
{Specify how long each segment will be when it's stored and displayed.
In an actual application, this information would be stored in a
table.}
seg_length[1] = 5;
seg_length[2] = 4;
seg_length[3] = 4;
seg_length[4] = 2;
seg_length[5] = 2;
seg_length[6] = 2;
seg_length[7] = 2;
seg_length[8] = 2;
seg_length[9] = 2;
seg_length[10] = 2;
seg_length[11] = 2;
seg_length[12] = 2;

{A colon will be used as the separator character.}


separator = ":";

{Turn the scroll arrows on for the composite.}


scroll_arrows = true;

{Six segments will be displayed.}


num_segments = 6;

84 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 9 C O M P O S IT E S

{W will be used as the base width character.}


width_char = "W";
{Use the override field statement to set the separator and turn
on scroll arrows for the composite.}
override field 'Customer Number' of window 'Main Window', separator,
➥ scroll_arrows;

{Use the override component statement to set the storage and display
length of each component of the composite. If a segment at the end of
the composite won't be used, set its length to 0.}

for segment equals 1 to maximum_num_segments do


if segment <= num_segments then
override component segment of field 'Customer Number'
➥ of window 'Main Window', seg_length[segment], width_char;
else
override component segment of field 'Customer Number'
➥ of window 'Main Window, 0, width_char;
end if;
end for;

When used and displayed in another window, the formatted customer


number looks like the following illustration.

Accessing composites from within scripts


The value of a component of a composite field can be specified or
referenced from within a script. SanScript has two methods of referencing
components.

Component addressing using a colon


A colon (:) is the common way to reference components of standard
composites. It can also be used to address components of extended
composites. The syntax for this type of referencing is composite field
name:component field name. The colon separates the composite field name
and the component field name.

Example 3
The following script assigns the values shown in Example 1 to the Item
Number composite field.

'Item Number:Vendor Code' = "GPS";


'Item Number:Part Number' = 1151;

PROGRAMMER’S GUIDE VOLUME 2 85


PA RT 3 WO RKING WI TH C ONTR O LS

Component addressing by offset


Component addressing by offset can be used for both standard and
extended composites. This type of addressing is similar to referencing the
elements of an array. The components of a composite are numbered from 1
to n, with n being the total number of components in the composite. A
specific component is addressed by its location in the composite, as shown
in the following examples.

Example 4
The following example sets the local variable l_company to the value of the
second component of the Part Number composite field.

local string l_company;

l_company = component(2) of field 'Part Number';

Example 5
The following example clears all 12 components of the Account Number
field.
local integer index;

for index equals 1 to 12 do


component(index) of field 'Account Number' = "";
end for;

Component-based scripts
Like other fields, composites can have pre, change and post scripts for the
entire field. In addition, the pre, change and post field scripts will be run for
each component if the Call Component Scripts option is marked in the Data
Type Definition window for the composite.

Note there is only one pre, change and post script for the composite field,
not a pre, change and post script for each component of the field. If
component scripts are enabled, the pre, change and post scripts for the
composite field will be run once for each component of the composite and
once for the composite as whole. The currentcomponent() function is used
to determine which component the focus is in when the pre, change or post
script is run.

86 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 9 C O M P O S IT E S

The following table shows which scripts run and the value returned by the
currentcomponent() function when a user moves into, through, and out of
a three-component composite field.

User action Scripts run Value


returned
Move into the first Pre script (for the entire field) 0
component. Pre script (for the first component) 1
Change the first Change script (for the first component) 1
component and tab Post script (for the first component) 1
into the second. Pre script (for the second component) 2
Change the second Change script (for the second component) 2
component and tab Post script (for the second component) 2
into the third. Pre script (for the third component) 3
Change the third Change script (for the third component) 3
component and Post script (for the third component) 3
move out of the Change script (for the entire field) 0
composite. Post script (for the entire field) 0

Example 7
Component scripts for composites are often used to validate components of
the composite as they are entered by the user. The following example is a
change script for the Part Number composite field for which component
scripts are called.

The first component of the Part Number field is the Vendor Number. The
change script validates the Vendor Number component by verifying that
the vendor exists in the Vendors table. If the vendor doesn’t exist, a warning
will be displayed and the field will be restarted. If the vendor does exist, the
remainder of the part number will be entered and the change script will
attempt to retrieve the entry.

if (currentcomponent() = 0) then
{Change script is run for the entire Part Number field.}
{Retrieve the information about the part.}
'Part Number' of table Current_Inventory = 'Part Number' of
➥ window Inventory_Maintenance;
change table Current_Inventory;
if err() = OKAY then
copy from table Current_Inventory;
end if.

PROGRAMMER’S GUIDE VOLUME 2 87


PA RT 3 WO RKING WI TH C ONTR O LS

else
if (currentcomponent() = 1) then
{Validate the Vendor component.}
'Vendor Number' of table Vendors = 'Part Number:Vendor Number';
get table Vendors;
if err() <> OKAY then
warning "This vendor hasn't been entered. Please select
➥ another.";
restart field;
end if;
end if;
end if;

Comparing composites
When composites are compared in boolean expressions, the corresponding
components of the composite are compared. For the composite comparison
to be true, the comparison between the corresponding components must be
true for all components of the composites. Otherwise, the comparison will
return a value of false.

For example, these two composites shown in the following illustration are
compared to determine whether they are equal.

The composites contain two components, so two comparisons are made:


AB = AB and 349 = 375. The first comparison is true, but the second is not,
so false is returned for the entire comparison.

Related items
Use the information listed to learn more about creating and using
composites.

Commands
currentcomponent(), override component, override field

Additional information
Chapter 6, “Data Types,” Chapter 7, “Formats,” and Chapter 8, “Global Fields” in Volume
1 of the Dexterity Programmer’s Guide

88 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 10: Scrolling Windows
Scrolling windows display records from a table, allowing a user to scroll
through records at runtime. Scrolling windows are useful when the number
of items to display is unknown, such as items in an inventory list. Scrolling
windows are also used for data entry, such as transactions made up of
multiple entries.

Scrolling windows are unlike standard windows in that they never appear
by themselves in a Dexterity application. Like fields, they must be added to
the layout area of an existing window. A scrolling window is linked to a
table and operates by displaying one line of information in the scrolling
window for each record in the table. You can display any field from a record
in the table, but usually only the most important fields from each record are
displayed in the scrolling window.

Information about scrolling windows is divided into the following sections:

• Scrolling window types


• Scrolling window elements
• Scrolling window properties
• Designing scrolling windows
• Adding scripts to a scrolling window
• Controlling the focus
• Using lookups
• Single-line scrolling windows
• Procedure: Creating a scrolling window

PROGRAMMER’S GUIDE VOLUME 2 89


PA RT 3 WO RKING WI TH C ONTR O LS

Scrolling window types


Three types of scrolling windows are available in Dexterity: browse-only,
editable, and adds-allowed.

Browse-only scrolling windows


A browse-only scrolling window only displays records from the linked
table. The user can “browse” through the contents of the linked table, but
can’t make changes or add items to the scrolling window. Browse-only
scrolling windows are typically used for lookup windows. You can make
a scrolling window browse-only by setting the WindowType property for
the scrolling window to Browse Only.

A browse-only scrolling
window allow you to
select only one item in the
scrolling window.

Editable scrolling windows


An editable scrolling window allows the user to change the contents
of lines in the scrolling window. These changes can be saved to the table
linked to the scrolling window. You can make a scrolling window editable
by setting the WindowType property for the scrolling window to Editable.

You can edit the items


in an editable scrolling
window.

90 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

Adds-allowed scrolling windows


An adds-allowed scrolling window has a blank line at the bottom of the
window where the user can add new information to the window and save it
in the table linked to the window. You can create an adds-allowed scrolling
window by setting the WindowType property for the scrolling window to
Adds Allowed.

An adds-allowed scrolling
window has a blank line that
allows you to add items to
the scrolling window.

Scrolling window elements


Each scrolling window has a name, a linked table, a layout, attached scripts
and properties for the scrolling window. To add a scrolling window to a
window layout, open the window layout of the window where you want to
place the scrolling window. Select the scrolling window tool from the
Toolbox and draw the scrolling window on the window layout.

Select the scrolling


window tool from the
Toolbox to add a new
scrolling window.

Use the scrolling


window tool to draw the
scrolling window.

PROGRAMMER’S GUIDE VOLUME 2 91


PA RT 3 WO RKING WI TH C ONTR O LS

After you’ve drawn the scrolling window on the layout window, the
Scrolling Window Options window will appear, as shown in the following
illustration. You will use this window to begin specifying characteristics of
the scrolling window.

Name the scrolling


window here.

A scrolling window must


have a linked table.

Name
Only one name is required for the scrolling window, the name used in
scripts to refer to the window. To make the name easier to use in scripts,
you can use underscores (_) between parts of the name instead of spaces.

Linked table
Every scrolling window must be linked to the table that contains the fields
you will add to the scrolling window. The Link Table list in the Scrolling
Window Options window allows you to select one of the tables you created
for your application. This table also must be attached to the form where the
scrolling window is located. Unless specified otherwise in a script, sorting
for the items in the scrolling window will be determined by the key you
select in the Link Key list.

Scrolling window layout


After you’ve named the scrolling window and selected the link table, the
scrolling window will appear in the layout area of the window you placed
it in.

The scrolling window


appears with its name in
the window where it was
drawn.

92 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

You can resize the scrolling window by selecting it and dragging one of its
resize handles. You can select the scrolling window and then use the
Properties window to change the visual characteristics of the scrolling
window.

Once the scrolling window is drawn, you can begin the process of creating
the scrolling window layout. Like all Dexterity windows, scrolling
windows use a layout area so you can add fields and other objects to the
window. To display the layout area for a scrolling window, double-click the
scrolling window in the window layout.

Using the scrolling


window layout area, you
can add fields from the
linked table.

The line below the fields in the layout


marks the boundary of the small line
item. Any objects between this line and
the top of the layout window will appear
in each line of the scrolling window.

When you create the layout for a scrolling window, you are creating the
layout for only one line of the scrolling window. This line is drawn in
the scrolling window once for each record in the linked table, until the
scrolling window is full. The fields you add to the scrolling window
determine what each line in the scrolling window will display at runtime.

The area in the scrolling window layout that corresponds to one line in the
scrolling window is the area between the dashed line and the top of the
layout area. This is known as the small line item. To mark the small line item,
choose Mark Small Line Item from the Tools menu and click in the window
where you want the dashed line to appear. Fields you drag into the
scrolling window layout should be placed between the top of the layout
window and the dashed line. In most cases it’s easier to drag the fields to
the window first, then mark the small line item.

PROGRAMMER’S GUIDE VOLUME 2 93


PA RT 3 WO RKING WI TH C ONTR O LS

As you add fields, you can use the same visual and object properties used
when you design other windows. When you’ve finished designing the
scrolling window layout, close the layout window to redisplay the layout
for the window containing the scrolling window.

Scrolling window properties


Several characteristics of the scrolling window are controlled by the
scrolling window properties. To access the scrolling window visual
properties, simply select the scrolling window in the layout area. The
following visual property is unique to scrolling windows.

Property Description
AltLineColor If this property is set to true, alternate lines of the scrolling
window will appear with a different color. Use the
Field_SetAltLineColor() function to specify the alternate line
color.
Resize-Horizontal Specifies the horizontal resize behavior for the scrolling window
when per field resizing is used. For more information, refer to
Resizing windows on page 146 of Volume 1 of the Dexterity
Programmer’s Guide.
Resize-Vertical Specifies the vertical resize behavior for the scrolling window
when per field resizing is used. For more information, refer to
Resizing windows on page 146 of Volume 1 of the Dexterity
Programmer’s Guide.

To access the scrolling window object properties, open the scrolling


window layout and select the window. You can set the following properties
for the scrolling window.

Property Description
DefaultDblClick In a browse-only scrolling window, setting the DefaultDblClick
property to true provides a short cut, allowing the user to double-
click a line in the scrolling window to accomplish the action of
selecting a line and clicking the push button whose Default
property set to true.
HelpContextID This is the help context ID for the scrolling window.

94 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

Property Description
IgnoreActiveLine This property controls focus and fill behavior of the scrolling
window.

When this property is set to false (the default), Dexterity will


consider which line is active in the scrolling window. When the
focus moves to the scrolling window, either through the tab
sequence or the focus statement, the focus will move to the active
line if the line is visible. If the line is not visible, the focus will move
to the first visible line.
When the scrolling window is filled from the current record,
Dexterity will position the active line to ensure that a maximum
number of rows are displayed.

When this property is set to true, Dexterity will use the traditional
behavior for scrolling windows. When focus moves to the
scrolling window through the tab sequence, the focus will move to
the first line. When the focus statement is used, the focus will
move to the active line if visible, or the first line if it is not.
When the scrolling window is filled from the current record,
Dexterity will position the active line as the first line in the
scrolling window.
LinkTable This is the table linked to the scrolling window. Records displayed
in the scrolling window come from this table. This is originally set
in the Scrolling Window Options window.
LinkTableKey This is the key for the linked table that specifies the default sorting
order for the records in the scrolling window. This is originally set
in the Scrolling Window Options window.
Name This is the name of the scrolling window. This is originally set in
the Scrolling Window Options window.
ScrollToBottom Setting this option to true causes the scrolling window to display
records at the end of the linked table, rather than at the beginning.
In effect, the scrolling window has been scrolled to the bottom of
the table. This is useful for adds-allowed scrolling windows
because the user doesn’t have to scroll to the end of the window
to add a new item.
WindowID This is the resource ID of the scrolling window.
WindowType This property specifies whether you want a browse-only,
editable or adds-allowed scrolling window.
An adds-allowed scrolling window has a blank line at the bottom
of the window where the user can add new lines to the window
and save them in the linked table.
A browse-only scrolling window allows the user to select only one
line in the scrolling window and make no changes.
An editable scrolling window allows the user to edit and change
the contents of lines in the scrolling window. These changes can
be saved in the linked table.

PROGRAMMER’S GUIDE VOLUME 2 95


PA RT 3 WO RKING WI TH C ONTR O LS

Designing scrolling windows


The big line item must Scrolling windows can display information in two modes: normal and
be marked in multiples expanded. The items displayed in each mode depend upon how the scrolling
of the height of the window is designed in the scrolling window layout. The area in the
small line item. scrolling window layout that corresponds to one line in normal mode is the
area between the top of the window and the first dashed line. This area is
called the small line item. The area in the scrolling window layout that
corresponds to the extra items displayed in expanded mode is the area
between the second dashed line and the small line item. This area is called
the big line item.

The following illustrations show the layout for the Customer_List scrolling
window. In normal mode, the window will display the Customer Number
and Customer Name. In expanded mode, it will display the Customer
Number and Name, as well as the Address, City, State, and ZIP Code fields.
The expand window statement is used to switch between normal mode
and expanded mode.

The small line item is marked


here. In normal mode, items in
the small line item are displayed
in the scrolling window.
The big line item is marked here.
In expanded mode, items in
both the big line item and the
small line item are displayed.

This is how the scrolling


window displays
information in normal mode.
The horizontal and vertical
light gray lines were drawn
in the scrolling window
layout using the line tool.

This is how the


scrolling window
displays information in
expanded mode.

96 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

Adding scripts to a scrolling window


Several different scripts can be used to control how a scrolling window
displays and accesses information. These include window scripts, scrolling
window scripts, and field scripts for fields in the scrolling window.

Table buffers for scrolling windows


When writing scripts for scrolling windows, keep in mind that for display
purposes, the scrolling window uses a separate table buffer, instead of the
table buffers for the form where the scrolling window is located. This
means that actions such as scrolling through items in the scrolling window
won’t affect the table buffers for the form where the scrolling window is
located. For other types of table access, such as saving an item in the
scrolling window to a table, the scrolling window uses the form’s table
buffer. If you don’t want the scrolling window to use the form’s table buffer,
consider using form procedures that have their own table buffers for all
tables in the application.

Window scripts
Scripts attached to the window containing the scrolling window and scripts
for fields in the same window are used to fill the scrolling window and
control how it displays information.

For more information Typically, the window pre script for the window containing the scrolling
about the fill window window contains the fill window statement that fills the scrolling window
statement, refer to the from the linked table using the table key specified. If no table key is
SanScript Reference specified, the key selected in the Scrolling Window Options window is
manual. used. The fill window statement can also fill a scrolling window from a
different table.

PROGRAMMER’S GUIDE VOLUME 2 97


PA RT 3 WO RKING WI TH C ONTR O LS

This drop-down list


controls how the scrolling
window is sorted.
These prompts are added
to indicate the items that
appear when the scrolling
window displays in normal
or expanded mode.

You can create these buttons to


control whether the scrolling
window displays in normal
mode or expanded mode.

The table keys for the table linked to the scrolling window control how the
items in the scrolling window are sorted. A drop-down list or other list field
can be used to specify which table key will be used to sort the records when
displaying information.

Scrolling windows can also display information in normal or expanded


mode by using the expand window statement. Typically, push buttons or
visual switches on the window control whether the scrolling window
displays in normal or expanded mode.

Example 1
The following example shows the window pre script for the window
containing the Customer_List_Scroll scrolling window. The pre script sets
the Sort By drop-down list to 1, indicating the first key will be used to sort
the items in the scrolling window. The fill window statement fills the
scrolling window from the linked table using the first key for the table.

'(L) Sort By' = 1;


fill window Customer_List_Scroll by number 1;

98 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

Example 2
The following example is the change script for the Sort By drop-down list,
which controls how the records in the scrolling window are sorted. It uses
the fill window statement to fill the scrolling window using the
appropriate table key to sort the records.

if '(L) Sort By' = 1 then


{Records will be sorted by Customer Number}
fill window Customer_List_Scroll by number 1;
else
{Records will be sorted by Name}
fill window Customer_List_Scroll by number 2;
end if;

Example 3
The following window pre script and change scripts for the normal and
expand buttons control whether the scrolling window displays information
in normal mode or expanded mode. The normal and expand buttons are
visual switches, each with two states indicating the two different modes.

Window pre script:

'Expand Button' = 2; {The expand button is up.}


'Normal Button' = 1; {The normal button is down.}
lock 'Normal Button';{Prevent it from being clicked again.}

Button to display normal mode:

expand window Customer_List_Scroll, false;


lock 'Normal Button'; {Prevent it from being clicked again.}
unlock 'Expand Button'; {Unlock expand so it can be clicked.}
'Expand Button' = 2; {The expand button is up.}

Button to display expanded mode:

expand window Customer_List_Scroll, true;


lock 'Expand Button'; {Prevent it from being clicked again.}
unlock 'Normal Button'; {Unlock normal so it can be clicked.}
'Normal Button' = 2; {The normal button is up.}

PROGRAMMER’S GUIDE VOLUME 2 99


PA RT 3 WO RKING WI TH C ONTR O LS

Scrolling window scripts


The Properties window for the scrolling window allows you to attach
several scripts to the scrolling window: a line pre script, line change script,
line post script, line fill script, line insert script, and line delete script.

To access the scripts for the scrolling window, open the window containing
the scrolling window. Double-click the scrolling window to open the
scrolling window’s layout. Select the scrolling window, and then click the
Script tab in the Properties window. Select the type of script you want to
add or edit, and click the lookup button.

Line pre script


The line pre script runs each time the focus moves to a different line in the
scrolling window. The pre script is useful for updating other fields in the
window based upon the position of the focus in the scrolling window. The
following is the line pre script for the Customer_List_Scroll scrolling
window. It uses the Customer Number of the current line in the scrolling
window to read from the Customer_Comments table and display the
appropriate comments.

'Customer Number' of table Customer_Comments = 'Customer Number' of


➥ window Customer_List_Scroll;
get table Customer_Comments;
if err() = OKAY then
copy from table Customer_Comments;
else
clear Comments of window Customer_List of form Customer_List;
end if;

100 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

The comment displayed is


based on the item
selected in the scrolling
window.

The line pre script should not be used to selectively show/hide, lock/unlock or
enable/disable fields for individual lines in the scrolling window. If you do so, the
scrolling window will not redraw properly.

Line change script


The line change script runs each time any fields in the current line have
changed and the focus leaves the line. The line change script is useful for
editable scrolling windows, saving any changes to the line when the focus
leaves the line. The following script is the line change script for the
Customer_List_Scroll scrolling window. It saves any changes made to fields
in the current line to the Customer_List table.
if empty('Customer Number' of window Customer_List_Scroll) then
{Customer doesn't have a number.}
warning "A customer must have a customer number.";
focus 'Customer Number' of window Customer_List_Scroll;
else
{Save the current line to the table.}
copy to table Customer_List;
save table Customer_List;
end if;

PROGRAMMER’S GUIDE VOLUME 2 101


PA RT 3 WO RKING WI TH C ONTR O LS

Line post script


The line post script runs each time the focus leaves a line in the scrolling
window. The line post script is useful for preparing fields to be updated
when the focus moves to a new line. The following script is the line post
script for the Customer_List_Scroll scrolling window. It clears the
Comments field that was filled by the line pre script, preparing it to display
another comment.
clear field Comments of window Customer_List;

Line fill script


The line fill script runs each time a new line is displayed in the scrolling
window. When the scrolling window first fills, the fill script runs repeatedly
until the scrolling window is full. The fill script also runs when a new line is
added to the scrolling window from the link file, such as by scrolling, or
when the user clicks an existing line in the scrolling window. The fill script
runs before the line pre script.

The reject record statement can be used in the line fill script to keep
specified records from being displayed in the scrolling window. You should
avoid rejecting a large number of records using the line fill script because
this can reduce application performance considerably.

Fill scripts are also useful for reading information from tables other than the
scrolling window’s link table. The following script uses the Part Number
field from the Inventory_Data file to read a description from the Item_List
file.
'Part Number' of table Item_List = 'Part Number' of table
➥ Inventory_Data;
{Read from the additional table.}
get table Item_List;
if err() = OKAY then
{Copy the information to the scrolling window.}
Description of window Inventory_Scroll = Description of table
➥ Item_List;
end if;

102 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

Line insert script


The line insert script runs when the Insert Row menu item is chosen or
when the insert line statement is run. Insert Row is a menu item that can be
inherited by application-level menus. Refer to Chapter 14, “Form-based
Menus,” in Volume 1 of the Dexterity Programmer’s Guide for more
information. The insert line script is used to insert a line into the scrolling
window, just above the currently-selected record.

The line insert script should be used only for scrolling windows that have
the order of the items controlled by sequence numbers. For example, the line
items for an invoice entry window typically use sequence numbers.
Sequence numbers are currency values that are stored as part of the table
and are also part of the table key. They act as reference values when the
scrolling window displays information, ensuring that the records are
displayed in the proper order.

The following example shows the line items for an invoice.

Invoice Sequence Part Description Price


Number Number Number
4510 0 01-100 16 oz. Hammer 7.80
4510 512 02-102 Torx Screwdriver 5.70
4510 1024 03-200 Steel Wool 7.15

The line items are stored in a table that has the Invoice Number and
Sequence Number as keys. Note that the sequence number for each line
item increased by 512. This was done by the line change script in the
scrolling window when the line items were saved. Having the sequence
numbers in the table key ensures that the invoice items will always be
displayed in the order they were entered.

The following script is the line insert script for the scrolling window
displaying the invoice line items. It calculates a new sequence number
based upon where the focus is currently located in the scrolling window
and saves a new record in the table, allowing the user to add a line item.
The scrolling window will be redrawn automatically.

PROGRAMMER’S GUIDE VOLUME 2 103


PA RT 3 WO RKING WI TH C ONTR O LS

local currency temp;

if not empty('Sequence Number' of table Invoice_Data) then


{Store the sequence number of the current record.}
temp = 'Sequence Number' of table Invoice_Data;
{Read the sequence number of the previous record.}
get prev table Invoice_Data;
if err() <> EOF then
temp = temp + 'Sequence Number' of table Invoice_Data;
end if;
temp = temp / 2;
clear table Invoice_Data;
{Save the new record in the table.}
'Invoice Number' of table Invoice_Data = 'Invoice Number';
'Sequence Number' of table Invoice_Data = temp;
save table Invoice_Data;
end if;

If this focus were on the last item in the scrolling window, Steel Wool, and
the user chose to insert a row, a new record would be created in the
Invoice_Data table with the Invoice Number 4510 and the Sequence
Number 768. This ensures that the new item will appear in the scrolling
window before Steel Wool and after the Torx Screwdriver.

Invoice Sequence Part Description Price


Number Number Number
4510 0 01-100 16 oz. Hammer 7.80
4510 512 02-102 Torx Screwdriver 5.70
4510 768
4510 1024 03-200 Steel Wool 7.15

104 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

Line delete script


The line delete script runs when the Delete Row menu item is chosen or
when the delete line statement is run. Delete Row is a menu item that can
be inherited by application-level menus. Refer to Chapter 14, “Form-based
Menus,” in Volume 1 of the Dexterity Programmer’s Guide for more
information. The line delete script is used to delete the current record from
the linked table. It automatically removes the line from the scrolling
window. The following script is the line delete script for the
Customer_List_Scroll scrolling window. It deletes the currently-selected
customer from the Customer_List table.
if ask("Are you sure you want to delete this item?", "Delete",
➥ "Cancel","") = ASKBUTTON1 then
remove table Customer_List.
end if.

Context menu script


The context menu script runs when the user right-clicks on the active line in
the scrolling window. It is used for context menus. For browse-only
scrolling windows, the context menu applies to the entire active line. For
editable and adds-allowed scrolling windows, the line-level context menu
items are added after any items for the field-level context menus. Refer to
Chapter 17, “Context Menus,” in Volume 1 of the Dexterity Programmer’s
Guide for details about using context menus.

Scrolling window field scripts


Pre, change and post scripts can be applied directly to fields in the scrolling
window when the layout window for the scrolling window is open. Field
scripts for scrolling windows are typically used in the same manner as field
scripts for standard windows. For example, a field change script could be
used to verify that the contents of the field are valid.

Controlling the focus


Refer to Chapter 11, Controlling the focus in a scrolling window requires care. When the user
“Windows,” in Volume clicks outside the scrolling window, the focus will leave the scrolling
1 of the Dexterity window. When the focus returns to the scrolling window, there is no way to
Programmer’s Guide determine to which line of the scrolling window the focus will return.
for information about
the Hyperspace To solve this problem, avoid creating situations where the user must click
property for push outside the scrolling window. If the user must click push buttons outside
buttons. the scrolling window, be sure set the Hyperspace property for the push
button to true. This will ensure that the focus never actually leaves the
scrolling window when the push button is clicked.

PROGRAMMER’S GUIDE VOLUME 2 105


PA RT 3 WO RKING WI TH C ONTR O LS

Using lookups
Lookups can be used for fields in the scrolling window. One method of
implementing a lookup is to specify a lookup form for a global field that is
used in the scrolling window. Use the Field Definition window to specify a
lookup form for the global field. When the focus is in that field in the
scrolling window and the user chooses Lookup, the designated lookup
form will be opened and a value returned to the scrolling window field.

You can also use directed hyperspace mode and link a scrolling window
field to a push button in the window where the scrolling window is located.
To do this, you must instead link the scrolling window field to another
push button you’ve added to the scrolling window layout. This additional
push button should be made invisible and non-editable and should be
located below the big line item so it isn’t displayed in the scrolling window.
This “intermediate” push button runs the script for the lookup button
located in the window. This is shown in the following illustration.

Run script

Scrolling Hidden push button in This button opens the


window field scrolling window lookup form and sets
layout. This button up the return path
has the Hyperspace back to the scrolling
property set to true. window field.

Single-line scrolling windows


A single-line scrolling window is created when the small line item or the
big line item is set to use the entire scrolling window area. When used in
this way, a scrolling window displays only one record of information at a
time.

Single-line scrolling windows are used for data entry when many fields are
required for each record. The single-line layout allows a logical
organization of fields and provides more area for prompts.

The Payroll Transaction Entry window in Microsoft Dynamics GP uses a single-


line scrolling window.

106 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

When a scrolling window displays only a single line, the scroll bar is
automatically hidden. Push buttons in the scrolling window are typically
used to move to the next or previous records. The change scripts attached to
these push buttons use the Window_ScrollScrollingWindow() function to
perform the scrolling.

PROGRAMMER’S GUIDE VOLUME 2 107


PA RT 3 WO RKING WI TH C ONTR O LS

Procedure: Creating a scrolling window


To create a scrolling window, open the layout window for the window
where the scrolling window will be placed.

1. Draw the scrolling window.


Select the scrolling window tool and draw the scrolling window on the
window layout. The Scrolling Window Options window will appear.

2. Name the scrolling window.


Enter the name of the scrolling window in the Scrolling Window Name
field.

3. Select the link table and link key.


Select the link table from the Link Table list. This table will be linked to
the scrolling window; data displayed in the window will come from
this table.

Select a table key in the Link Key list. This key determines the order in
which records will be sorted if another key isn’t specified when the
scrolling window is filled. Click OK to close the Scrolling Window
Options window.

4. Specify the scrolling window characteristics.


To specify the visual properties of the scrolling window, select it in the
layout and display the Properties window. The following visual
property is specific to scrolling windows:

Property Description
AltLineColor If this property is set to true, alternating lines of the scrolling
window will appear with a different color. Use the
Field_SetAltLineColor() function to specify the alternate line
color.

To specify the object properties, double-click the scrolling window to


open the scrolling window layout. Display the Properties window
to set the object properties for the scrolling window. Set the following
properties:

Property Description
DefaultDblClick In a browse-only scrolling window, setting the
DefaultDblClick property to true provides a short cut, allowing
the user to double-click a line in the scrolling window to
accomplish the action of selecting a line and clicking the push
button that has the Default property set to true.

108 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 0 S C R O L L I N G W I N D O W S

Property Description
HelpContextID This is the help context ID for the scrolling window.
LinkTable This is the table linked to the scrolling window. Records
displayed in the scrolling window come from this table.
LinkTableKey This is the key for the linked table that specifies the default
sorting order for the records in the scrolling window.
Name This is the name of the scrolling window.
ScrollToBottom Setting this option to true causes the scrolling window to
display records at the end of the linked table, rather than at
the beginning. In effect, the scrolling window has been
scrolled to the bottom of the table. This is useful for adds-
allowed scrolling windows because the user doesn’t have to
scroll to the end of the window to add a new item.
WindowID This is the resource ID of the scrolling window.
WindowType Specify whether you want a browse-only, editable or adds-
allowed scrolling window.

5. Design the scrolling window.


Design how the scrolling window will appear in normal mode by
placing the necessary fields at the top of the window.

6. Mark the small line item.


Choose Mark Small Line Item from the Tools menu and mark the
position of the line, using the crosshairs pointer. The boundary of
the small line item is indicated by a dashed line. The items between the
dashed line and the top of the layout area will be displayed when
the scrolling window is in normal mode.

7. Mark the big line item (if necessary).


If the scrolling window will display information in expanded mode,
add the appropriate additional fields to the window, then choose Mark
Big Line Item from the Tools menu and mark its position. The big line
item must be marked in multiples of the height of the small line item.
For example, if the small line item was 18 pixels high, the big line item
must be marked in multiples of 18 pixels. The items between the
dashed line indicating the big line item and the top of the layout area
will display in expanded mode. If the scrolling window will display
information only in normal mode, you don’t need to mark the big line
item.

If you need to resize the small line item or big line item, just choose Mark
Small Line Item or Mark Big Line Item from the Tools menu and mark the line
again.

PROGRAMMER’S GUIDE VOLUME 2 109


PA RT 3 WO RKING WI TH C ONTR O LS

8. Add scripts to the scrolling window.


With the scrolling window layout still open, select the Script tab in the
Properties window. This lists the scripts that can be applied to the
scrolling window. Refer to Adding scripts to a scrolling window on
page 97 for more detailed information.

A window pre script for the window containing the scrolling window
usually includes the fill window statement, used to fill the scrolling
window with data from the scrolling window’s linked table. The
following table shows the other scripts that can be attached to the
scrolling window.

Script name When the script is run


Line pre script When the focus moves to a different line in the scrolling
window.
Line change script When the focus leaves a line in the scrolling window where
some of the information in that line has changed.
Line post script When the focus leaves a line in the scrolling window.
Line fill script When the scrolling window first fills, the fill script runs until
the window is full. It also runs when a new line is added to
the scrolling window from the linked file or when the focus
moves to an existing line in the scrolling window. The fill
script runs before the line pre script.
Line insert script When the user chooses the Insert Row menu item or when
the insert line statement is run.
Line delete script When the user chooses the Delete Row menu item or when
the delete line statement is run.

Related items
Use the information listed to learn more about creating scrolling windows.

Commands
delete line, expand window, fill window, insert line

Additional information
Chapter 11, “Lookups.” in Volume 2 of the Dexterity Programmer’s Guide

110 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 11: Lookups
Lookup windows allow a user to easily enter key information in an editable
field. One method of opening a lookup window is to use the Lookup menu
item, typically added to the Help menu. Another method is to use a push
button in the window with a script attached to open the lookup window.

The Lookup item, typically


added to the Help menu, can
be used to open lookup
windows in your application.

Information about lookups is divided into the following sections:


• How lookups work
• Implementing lookups

PROGRAMMER’S GUIDE VOLUME 2 111


PA RT 3 WO RKING WI TH C ONTR O LS

How lookups work


Lookups operate by opening a window that displays a list of entries
relevant to the current field. This window is called a lookup window. When
the lookup window opened, a return path is set up back to the current field.
When the user selects an item from the lookup window, its value is
returned to the current field.

For example, the following illustration shows the Sellers window for the
Real Estate Sales Manager application. Values for the Seller ID field can be
returned by the lookup window for that field.

The item selected in the


lookup window is returned
to the Seller ID field. The lookup window is opened
from the Seller ID field.

112 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 1 L O O K U P S

Implementing lookups
Two methods are used to implement lookups. The first method involves
specifying the lookup form for a global or local field definition. The second
method involves creating a lookup push button and setting up a lookup
link in the layout window.

Specifying a lookup form


The Field Definition window and the Local Field Definition window each
have a Lookup Form field. This field specifies the lookup form to open
when the focus is on that field and the Lookup menu item is chosen. A
return path for the lookup is automatically set up when the Lookup menu
item is chosen. The return statement returns a value from the lookup
window to the field. For example, the Customer ID global field has the
Customer_Lookup form designated as the lookup form.

The Customer ID field has


the Customer_Lookup form
designated as the lookup.

When the focus is in the Customer ID field and the Lookup menu item is
chosen, the Customer_Lookup form will open. A return path will be set up
back to the Customer ID field. The Customer_Lookup form will return the
selected value to the Customer ID field.

return 'Customer ID' of window


➥ Customer_Lookup_Scroll;
close form Customer_Lookup;

The select button returns


the value from the lookup.

PROGRAMMER’S GUIDE VOLUME 2 113


PA RT 3 WO RKING WI TH C ONTR O LS

If a lookup form has been designated for a field, the lookup window will
work for any occurrence of the field in the application. For instance, in the
previous example, the lookup would work anywhere you used the
Customer ID field in the application. If you don’t want a specific instance of
the field to access the lookup form, set the DisableLookup property for that
instance of the field to true.

Using a lookup button


The second and more common method of implementing a lookup is to add
a push button to the window. This push button opens the lookup form and
sets up the return path from the lookup window. The Buyer ID field and its
lookup button are shown in the following illustration.

The script on the lookup


button opens the lookup form
and sets up the return path.

The lookup button for the Buyer ID field opens the Buyer_Lookup form
and sets up the return path back to the Buyer ID field. The lookup form uses
the return statement to return a value to the lookup field. The following
script is attached to the lookup button.

open form Buyer_Lookup return to 'Buyer ID';

One way to open the lookup is to click the lookup button. Dexterity also has
the capability to make the Lookup menu item open the lookup form by
effectively “clicking” the lookup button. To do this, open the layout
window containing the field and lookup button. Choose Link Lookup from
the Tools menu; Dexterity will enter lookup linking mode. Simply click
on the field and drag to the lookup button. A flashing black line indicates
the link was made.

This is the lookup linking


pointer. The solid black line
indicates the link was made.

Choose Link Lookup from the Tools menu to exit lookup linking mode.

114 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 1 L O O K U P S

In the preceding example, whenever the focus is in the Buyer ID field, the
Lookup menu item will be enabled. Choosing the Lookup menu item will
run the change script for the lookup button, which in turn opens the lookup
form and sets up the return path.

You should also set the Hyperspace property for the lookup button to True.
This will prevent the change script or post script for the editable field from
running. The change script or post script could potentially keep the lookup
button script from running.

A field linked to a lookup button is the most common implementation of a lookup.


This is because additional processing can be done by the lookup button script, in
addition to opening the lookup form and setting up the return path.

PROGRAMMER’S GUIDE VOLUME 2 115


116 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 12: Tree View
A tree view field displays data as an expandable outline, making it useful
for displaying hierarchical information. A typical tree view field is shown
in the following illustration.

Information about tree view fields is divided into the following sections:

• Terminology
• Tree view nodes
• Tree view properties
• Tree view scripts
• Adding nodes to tree view fields
• Image types for tree view nodes
• Adding images to a tree view field
• Image sizes
• Specifying the images to use
• Background colors
• Searching tree view fields

PROGRAMMER’S GUIDE VOLUME 2 117


PA RT 3 WO RKING WI TH C ONTR O LS

Terminology
When implementing tree view fields, it is helpful to understand the
terminology used to describe them. A tree is composed of nodes. A node
represents one piece of information in the tree.

A tree view field is


composed of nodes.

Nodes are often classified based on their relationship to other nodes. The
following illustration shows a parent node and child nodes.

This is a parent node.

These are child nodes.

A group of child nodes that have the same parent are referred to as siblings.

These nodes are siblings.

118 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 2 T R E E V I E W

Root-level nodes are those that appear in the first level of the tree view.

These are root-level


nodes.

All root-level nodes are children of a hidden node that is identified in


Dexterity by the constant TV_ROOT. In sanScript, whenever you refer to
the parent of a root-level node, you will use this constant.

All root-level nodes are


children of a hidden node
identified by the constant
TV_ROOT.

Tree view nodes


Each node in a tree view has the following attributes:

Node ID The node ID is a long integer that uniquely identifies each node.
You will use the node ID whenever you reference a node from within
sanScript.

Label The label is the text that appears for the node.

Data item Each node has a long integer value associated with it that you
can use to store data specific to a node.

Images Each node can have several images associated with it. One image
is displayed when the node is selected. Another is displayed when the node
is not selected. Additional images can be used to “overlay” the node image.
Still other images can be used to show the state of a node. Use of images is
discussed in the section titled Image types for tree view nodes on page 124.

PROGRAMMER’S GUIDE VOLUME 2 119


PA RT 3 WO RKING WI TH C ONTR O LS

Tree view properties


Property settings control several characteristics of tree view fields. The
following table lists the tree view properties.

Type Property Description


Object SortMethod Specifies whether child nodes in the tree view
field will be sorted by label in ascending or
descending order. If set to None, the child nodes
appear in the order they were added.
Visual ExpandButtons If set to true, expansion buttons are shown for
nodes that have children.
Indent Specifies how many pixels child nodes are
indented from the parent. The value 0 allows the
control to automatically specify the amount.
Lines Specifies how lines are drawn in the tree view
field. If set to None, no lines are drawn. If set to
TreeLines, lines are drawn for nodes below the
root level. If set to RootLines, lines are drawn
for all nodes.
ShowSelection Indicates whether the selected node is indicated
when the tree view field does not have focus.

Tree view scripts


Refer to the Tree view The Properties window allows you to attach the following scripts to a tree
function library in the view field: pre script, select script, post script, collapse script, expand script
Function Library and double-click script.
Reference for
information about Pre script
functions used for tree The pre script runs when the focus moves to the tree view field from
view fields. another location.

Select script
The select script runs each time a different node is selected in the tree view
field.

Post script
The post script runs when the focus leaves the tree view field.

120 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 2 T R E E V I E W

Expand script
Refer to Adding nodes The expand script runs each time a parent node is expanded in the tree
to tree view fields on view field. Use this script to add child nodes when a parent node is
page 123 for more expanded. Use the TreeView_GetExpandingNode() function to retrieve
information about how the ID of the node being expanded.
to add nodes to tree
view fields. The following example is the expand script for the Address List tree view
field. It adds child nodes containing customer information to the node
being expanded.

local long node_ID;


local long new_node;
local string node_label;

{Get the ID of the expanding node.}


node_ID = TreeView_GetExpandingNode('Address List');
{Get the label for the node.}
node_label = TreeView_GetNodeLabel('Address List', node_ID);

{Set the appropriate range for the Customer_Data table.}


range clear table Customer_Data;
set 'Region' of table Customer_Data to node_label;
range start table Customer_Data by key 3;
range end table Customer_Data by key 3;

{Read the customer records for the region.}


get first table Customer_Data;
while err() <> EOF do
{Add the new node with customer information. Use the index card
image (image 3).}
new_node = TreeView_AddNode('Address List', 'Customer Name' of
➥ table Customer_Data, 0, node_ID, false, 3, 3);
get next table Customer_Data;
end while;

PROGRAMMER’S GUIDE VOLUME 2 121


PA RT 3 WO RKING WI TH C ONTR O LS

Collapse script
The collapse script runs each time a parent node is collapsed in the tree
view field. Use this script to remove child nodes from the node being
collapsed. Removing the non-visible nodes allows the tree view field to
operate more efficiently and be more responsive. Use the
TreeView_GetCollapsingNode() function to retrieve the ID of the node
being collapsed.

The following example is the collapse script for the Address List tree view
field. It removes the child nodes from the node being collapsed.

local long node_ID;


local long number_removed;

{Get the ID of the collapsing node.}


node_ID = TreeView_GetCollapsingNode('Address List');
{Remove the children from the node.}
number_removed = TreeView_RemoveChildren('Address List', node_ID);

State click script


The state click script runs each time the user clicks the state image for a
node. Clicking the state image for an item does not change the selection.
Use the TreeView_GetClickNode() function to retrieve the node ID of the
node whose state image was clicked.

The following example is the state click script for the Address List tree view
field. It toggles the state image displayed when the state image is clicked.
local long click_node;
local integer previous_image;

{Find which node's state image was clicked.}


click_node = TreeView_GetClickNode('Address List');

if TreeView_GetNodeStateImage('Address List', click_node) = 1 then


{The clicked item is shown. Show the unclicked item.}
previous_image = TreeView_SetNodeStateImage('Address List',
➥ click_node, 2);
else
{The unclicked item is shown. Show the clicked item.}
previous_image = TreeView_SetNodeStateImage('Address List',
➥ click_node, 1);
end if;

122 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 2 T R E E V I E W

Double-click script
The double-click script runs each time a node is double-clicked. If a node
contains children, the node will be expanded or collapsed and the expand
or collapse script will run. Then the double-click script will run. Use the
TreeView_GetSelectedNode() function to retrieve the node ID of the node
that was double-clicked.

Context menu script


The context menu script runs when the tree view control is right-clicked. It
is used for context menus. Refer to Chapter 17, “Context Menus,” in
Volume 1 of the Dexterity Programmer’s Guide for more information.

Adding nodes to tree view fields


Tree view fields can be used only in windows. They can’t be stored in
tables, so you must add nodes to the tree view each time it is displayed.
Two common methods are used to add nodes to a tree view field:
preloading all nodes or preloading the root-level nodes and then
dynamically adding child nodes as needed.

Preloading all nodes


For tree view fields that contain fewer than 100 nodes, using the window
pre script to add all of the nodes provides acceptable performance. If the
tree will contain more than 100 nodes, the window loading time could
become unacceptably long. If this is the case, you should consider
preloading only root-level nodes, described in the following paragraph.

Preloading only root-level nodes


Refer to Tree view If a tree view field will contain more than 100 nodes, we recommend that
scripts on page 120 for you preload only the root-level nodes using the window pre script. Then
information about the use the expand and collapse scripts for the tree view field to dynamically
expand and collapse add and remove child nodes from the tree. We recommend removing nodes
scripts. with the collapse script because even though the collapsed nodes aren’t
being displayed, they degrade performance of the tree.

Dynamically adding and removing nodes has some additional benefits:

• If the data used for the tree view field changes often, only the most
recent data is used when new nodes are added and displayed.

• The performance of the tree view field will scale as more nodes are
added. This means that performance will be optimal, even as more
nodes are added to the tree view field.

PROGRAMMER’S GUIDE VOLUME 2 123


PA RT 3 WO RKING WI TH C ONTR O LS

Image types for tree view nodes


To display images for nodes, you must first make the images available to
the tree view field. Then you specify the images to use for each node. A tree
view node can have several images associated with it.

Item images
The item image is displayed with the node.

This is the item


image for a node.

State images
The state image is displayed next to the node image. In the following
illustration, the check box next to each node is a state image.

The X is a state
image.

Overlay images
Overlay images allow you to add to the node image without requiring
several versions of the icon. For example, an overlay image containing a
slash could be placed on top of a folder icon, indicating the item can’t be
accessed.

The
The overlay
overlay image
image isis
placed
placed on
on top
top of
of the
the
item image.

124 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 2 T R E E V I E W

Adding images to a tree view field


To make images available to a tree view field, you specify them in the field’s
data type definition. Use the Static Values field in the Data Type Definition
window or the Local Field Definition window to specify the pictures that
will be used. Click the Static Values lookup button to open the Tree View
Images window, shown in the following illustration.

You will use this value to


refer to a specific image.

Use these buttons to add


and remove images.

Item images
Click the Item Images tab to specify item and overlay images that will be
used for nodes in the tree view field. To add a new image, click New.

Only four different images can be used as overlay images at one time.

State images
Click the State Images tab to specify the state images that will be used for
the tree view field. To add a new image, click New.

A tree view can have up to 15 state images defined for it.

PROGRAMMER’S GUIDE VOLUME 2 125


PA RT 3 WO RKING WI TH C ONTR O LS

Image sizes
When a tree view is drawn, it must provide enough room for any images
associated for each node. The size of the first item image added to the tree
view data type is used when drawing the tree. For example, if the first item
image for the tree field is 20 by 20 pixels, an area that size will be used for
every node. Images of other sizes are scaled to fit in the area provided. For
the best appearance, we recommend that all images in the tree view be the
same size.

Images used for nodes are typically 16 by 16 pixels.

State images are always 16 by 16 pixels. If you will be using state images in
your tree view field, we recommend that all of your images be 16 by 16
pixels.

Specifying the images to use


When you add a node to a tree view, you can supply integer values
indicating the images to use for the new node. The values you supply
correspond to the item numbers of the images in the Tree View Images
window. For example, the value 2 indicates that the second image listed
will be used. Use the TV_NOIMAGE constant to specify that no image will
be used.

One image is displayed when


the node is selected. Another
is displayed when it is not.

Background colors
Typically, you will want the images used in a tree view field to blend with
the background color of the field. The color of the image’s first pixel (upper
left corner) specifies which color will be considered transparent, allowing
the field’s background color to show through any pixel of that color.

This pixel specifies the


color that will be
considered transparent.

126 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 2 T R E E V I E W

When you create the images for the list view, you may want to use a unique color
for the image background. That way, the list view background color will not
interfere with the other colors in the image.

Searching tree view fields


At some point, you may want to search a tree view field to find out whether
it contains a specific node. There are numerous ways to search tree view
fields, and a complete discussion of them is beyond the scope of this
manual. The following is the code for the TreeView_Search() function. You
can use this code as a starting point for searching tree view fields.

function returns long node_found;

inout anonymous field tree_field.{The tree field to search.}


in long search_node;{The ID of the node to search from.}
in string search_item;{The item to search for.}

if search_node = TV_NODEINVALID then


{The search node is not valid.}
node_found = TV_NODEINVALID;
else
if TreeView_GetNodeLabel(tree_field, search_node) =
➥ search_item then
{The search item was found.}
node_found = search_node;
else
{If the search node has children, search them.}
node_found = TreeView_Search(tree_field,
➥ TreeView_GetFirstChild (tree_field, search_node),
➥ search_item);
if node_found = TV_NODEINVALID then
{There are no children, so search the next sibling.}
node_found = TreeView_Search(tree_field,
➥ TreeView_GetNextNode(tree_field, search_node),
➥ search_item);
end if;
end if;
end if;

PROGRAMMER’S GUIDE VOLUME 2 127


PA RT 3 WO RKING WI TH C ONTR O LS

The TreeView_Search() function begins searching the tree at the node


specified. If a node having the specific label is found, that node’s ID is
returned. Otherwise, a value corresponding to the TV_NODEINVALID
constant is returned.

This is a depth-first search, meaning that child nodes are searched before
sibling nodes. To make this a breadth-first search, in which sibling nodes
are searched before child nodes, simply swap the two shaded sanScript
statements in the script above.

This is a depth-first search, meaning that child nodes are searched before
sibling nodes. To make this a breadth-first search, in which sibling nodes
are searched before child nodes, simply swap the two sanScript statements
indicated in the above illustration.

The TreeView_Search() function is recursive, meaning the function makes calls to


itself. Many searching algorithms can be coded more efficiently if recursion is used.

The following example uses the TreeView_Search() function to search the


Houses Tree field for the first node whose label is “Fargo”, beginning with
the first root-level node.

local long node_ID;


local boolean result;

node_ID = TreeView_Search('Houses Tree', TreeView_GetRootNode


➥ ('Houses Tree'), "Fargo");

{If a node was found, select it.}


if node_ID <> TV_NODEINVALID then
result = TreeView_SetSelectedNode('Houses Tree', node_ID);
end if;

128 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 13: List View
A list view displays data in icon form or as a multicolumn list. A typical list
view field is shown in the following illustration.

Information about the list view is divided into the following sections:

• Terminology
• List view items
• List view properties
• List view scripts
• Image types for list views
• Adding images to a list view field
• Image sizes
• Specifying the images to use
• Background colors
• Working with list views
• Working with the selection
• Searching a list view

PROGRAMMER’S GUIDE VOLUME 2 129


PA RT 3 WO RKING WI TH C ONTR O LS

Terminology
When implementing list view fields, it is helpful to understand the
terminology used to describe them. A list is composed of items. An item
represents one piece of information in a list.

A list view contains


items.

List view fields can display items in four ways. In large icon view each item is
displayed with the large version of its associated icon.

This list is in large


icon view mode.

In small icon view, each item is displayed with the small version of its
associated icon.

This list is in small


icon view mode.

130 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 3 L I S T V I E W

In list view, items are displayed as a list, along with the small version of their
icons.

This list is in list view


mode.

In report view, items are displayed as a multicolumn list. Subitems are


displayed in the additional columns of the list. Report view is the only
mode that displays subitems.

This list is in report


view mode.

Subitems are displayed


in the additional
columns of the list.

If properties for the list view field are set appropriately, users can sort
columns by clicking the column headings and rearrange columns by
dragging them. They can also resize columns.

PROGRAMMER’S GUIDE VOLUME 2 131


PA RT 3 WO RKING WI TH C ONTR O LS

List view items


Each item in the list view has the following attributes:

Index The index is a long integer that specifies the position of the item in
the list. You will use the index whenever you reference a list item from
sanScript.

Be aware that the index value of a list item may change. For example, when the list
is re-sorted, an item may appear in a different location in the list. Thus, its index
value will have changed.

Label The label is the text that appears with the item.

Data item Each item has a long integer value associated with it that you
can use to store data specific to the item.

Images Each item can have several images associated with it. One image
is used as the icon displayed with the item. Additional images can be used
to “overlay” the icon image. Still other images can be used to show the state
of an item. Use of images in list views is discussed in detail in Image types for
list views on page 136.

Subitems Each list view item can have several subitems associated with
it. A subitem typically consists of a single string value. Subitems can be
displayed when the list view is shown in report view mode. They are not
shown in the other view modes. Each subitem can also have an additional
currency, date, time or integer component that stores a value to be used for
sorting the contents of the list.

By default, a list view will use the string component of a subitem when
sorting a column in the list view. The list view items will be sorted in ASCII
order, which may not be appropriate if the column contains currency,
integer, date or time values. If the subitems in the column have an
additional currency, integer, date or time component, these additional
components will be used to sort the list.

If a subitem has an additional currency, integer, date or time component,


but no string component, the additional component will be displayed in
report view mode.

132 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 3 L I S T V I E W

List view properties


Property settings control several characteristics of list view fields. The
following table describes the list view properties.

Type Property Description


Object DraggableCols Applies only when the list view is displayed in report
view mode. True indicates the user can reorder
columns by dragging them. False indicates columns
can’t be reordered by the user.
MultiSel True indicates multiple items can be selected in the
list view. False indicates only one item can be
selected.
SortMethod Specifies how items in the list view are sorted. If set
to None, items are not sorted and are displayed in
the order they were added. Ascending indicates
items will be sorted in ascending order based on the
item label. Descending indicates items will be sorted
in descending order based on the item label. Column
indicates items will be sorted based on a specific
column in the list view. The user or the
ListView_SetSortColumn() function can specify
the sort column.
Visual AltLineColor If set to true, alternate lines of the list view will
appear with a different color. Set the BackColor,
Pattern and PatternColor properties to Custom, then
use the Field_SetAltLineColor() function to specify
the alternate line color.
FullRowSelect When set to true, the entire row in the list view field
is selected. When set to false, individual row items
can be selected. Applies only when the list view is
displayed in report view mode.
GridLines When set to true, grid lines are drawn between items
in the list view. Applies only when the list view is
displayed in report view mode.
ShowHeadings When set to true, column headings are shown in the
list view. Applies only when the list view is displayed
in report view mode.
ShowSelection Indicates whether the selected items are indicated
when the list view field does not have focus.
ImageSize Specifies how list view images are sized. System
indicates the images will be scaled to standard
system sizes (16 by 16 or 32 by 32 pixels). First Image
indicates images will be scaled to the size of the first
image defined for the list view field.

PROGRAMMER’S GUIDE VOLUME 2 133


PA RT 3 WO RKING WI TH C ONTR O LS

List view scripts


Refer to the List view The Properties window allows you to attach the following scripts to a list
function library in the view field: pre script, post script, selection changed script, double-click
Function Library script and state click script.
Reference for
information about the Pre script
functions used for list The pre script runs when the focus moves to the list view field from another
view fields. location.

Post script
The post script runs when the focus leaves the list view field.

Item changed script


The item changed script runs any time an item is added to or removed from
the selection. Be aware that when the mouse is used to select several items,
this script runs as items are included or excluded from the selection
rectangle.

The item changed script


runs as items are included
or excluded from the
selection rectangle.

The following example is the item changed script for the Explorer List list
view field. It updates the Object Count field with the number of items
selected in the list view.
local long selection_count;

{The selection changed. Update the count of the objects selected.}


selection_count = ListView_SelectionCount('Explorer List');

if selection_count > 0 then


{Indicate how many objects are selected.}
'(L) Object Count' = str(selection_count) + " object(s) selected";
else
{Display the total number of objects in the list.}
'(L) Object Count' = str(ListView_ItemCount('Explorer List'))
➥ + " object(s)";
end if;

134 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 3 L I S T V I E W

Selection changed script


The selection changed script runs one time after the selection in the list
view has changed. The script runs once, regardless of the number of items
that were added to or removed from the selection.

Double-click script
The double-click script runs each time an item is double-clicked. Double-
clicking an item will change the selection, so the selection changed script
will run prior to the double-click script. Use the ListView_GetClickItem()
function to retrieve the index of the item that was double-clicked.

State click script


The state click script runs each time the user clicks the state image for an
item. Clicking the state image for an item does not change the selection. Use
the ListView_GetClickItem() function to retrieve the index of the item
whose state image was clicked.

The following example is the state click script for the Explorer List list view
field. It toggles the state image displayed when the state image is clicked.
local long click_item;
local integer previous_image;

{Find which item's state image was clicked.}


click_item = ListView_GetClickItem('Explorer List');

if ListView_ItemGetStateImage('Explorer List', click_item) = 1 then


{The clicked item is shown. Show the unclicked item.}
previous_image = ListView_ItemSetStateImage('Explorer List',
➥ click_item, 2);
else
{The unclicked item is shown. Show the clicked item.}
previous_image = ListView_ItemSetStateImage('Explorer List',
➥ click_item, 1);
end if;

Context menu script


The context menu script runs when the list view control is right-clicked. It is
used for context menus. Refer to Chapter 17, “Context Menus,” in Volume 1
of the Dexterity Programmer’s Guide for more information.

PROGRAMMER’S GUIDE VOLUME 2 135


PA RT 3 WO RKING WI TH C ONTR O LS

Image types for list views


Images can be used in several places in list view fields. You must first make
the images available to the list view field, then you can specify how you
will use images for each list view item. A list view item can have several
images associated with it.

Icon images
The icon image is displayed with the item.

This is an icon image.

State images
In report view mode, the state image is displayed next to the icon image. In
the following illustration, the check box next to each item is a state image.

The check box is a


state image.

Overlay images
Overlay images allow you to add to the icon image without requiring
several versions of the icon. For example, an overlay image containing the
word “SOLD” could be placed on top of the house icon, indicating the
house has been sold.

The overlay image is placed


on top of the icon image.

136 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 3 L I S T V I E W

Adding images to a list view field


To make images available to a list view field, you specify them in the field’s
data type definition. Use the Static Values field in the Data Type Definition
window or the Local Field Definition window to specify the pictures to use
for the list view field. Click the Static Values lookup button to open the
ListView Images window, shown in the following illustration.

Each icon image or


overlay image has a
small version and a
large version.

You will use this value to Use these buttons to set


refer to a specific image. and clear the images.

Item images
Click the Item Images tab to specify icon images and overlay images that
will be used for the list view field. To add a new image, click New. Each
image can have a large version and a small version. The large image is used
for the large icon view mode. The small image is used for all other view
modes.

Only 4 different images can be used as overlay images at one time.

State images
Click the State Images tab to specify the state images that will be used for
the list view field. To add a new image, click New. Because state images are
shown only in report view mode, there is only a small version of the image.

A list view can have up to 15 state images defined for it.

PROGRAMMER’S GUIDE VOLUME 2 137


PA RT 3 WO RKING WI TH C ONTR O LS

Image sizes
When the list view is drawn, it must provide enough room for the images
associated with each item. The size of the images used is specified by the
ImageSize property of the list view field. If this property is set to System,
large images are scaled to 32 by 32 pixels. Small images are scaled to 16 by
16 pixels. If the ImageSize property is set to First Image, all large images are
scaled to the size of the first large image you define for the list view field.
Likewise, all small images are scaled to the size of the first small image.

If you use the System setting for the ImageSize property, we recommend
that your large images be 32 by 32 pixels. The small images should 16 by 16
pixels. Your images will then have the best appearance because they won’t
have to be scaled. If you allow the image sizes to be based on the first
image, we recommend that all the large images be a uniform size. All small
images should also be a uniform size.

If you don’t supply both the small and large images, the image supplied will scaled
to the proper size and used in place of the missing image.

Specifying the images to use


When you add an item to a list view, you can supply integer values
indicating the icon and state images to use for the new item. The values you
supply correspond to the item numbers of the images in the ListView
Images window. For example, the value 2 indicates the second image listed
will be used. Use the LV_NOIMAGE constant to specify that no image will
be used.

Background colors
Typically, you will want the images used in a list view field to blend with
the background color of the field. The color of the image’s first pixel (upper
left corner) specifies which color that will be considered transparent,
allowing the field’s background color to show through any pixel of that
color.

This pixel specifies the


color that will be
considered transparent.

138 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 3 L I S T V I E W

When you create the images for the list view, you may want to use a unique color
for the image background. That way, the list view background color will not
interfere with the other colors in the image.

Working with list views


When using list view fields in your application, there are several common
tasks you will perform, such as adding items and resizing columns. This
section describes how to perform common list view operations.

Adding items to a list view


Several steps are required to add items to a list view field.

• First, use the ListView_ItemAdd() function to add a new item.

• If additional information will be included with the item, use the


ListView_ItemSetSubitem() function to specify any string subitems.

• If some of the subitems contain currency, integer, date or time values,


you can use functions such as ListView_ItemSetIntSubitem() or
ListView_ItemSetCurrencySubitem() to add an additional integer,
currency, date or time component to each subitem. The additional com-
ponents will be used when items in the list view are sorted.

• Finally, if the list view can be displayed in report view mode, use the
ListView_ColumnAdd() function to add columns to the list. If you
don’t add columns, no items will be shown in report view mode.

If the list view field is shown in report view mode, add all of the items and subitems
before adding columns the list. This prevents the list view field from flashing as
items are added, because the items are shown only after columns are added.

Clearing a list view


To remove a single item from a list view field, use the
ListView_ItemRemove() function, specifying the index of the item to
remove. To remove all items from the list, use the constant LV_ALL to
indicate that all items should be removed.

Removing all items from a list view field does not affect the columns
t h a t h a v e b e e n a d d e d . To r e m o v e a l l c o l u m n s , u s e t h e
ListView_ColumnRemove() function, and use the constant LV_ALL to
indicate all columns should be removed.

PROGRAMMER’S GUIDE VOLUME 2 139


PA RT 3 WO RKING WI TH C ONTR O LS

If your application will displaying an empty list view field, consider using the
ListView_SetEmptyMessage() function to specify a message to be displayed in
the empty list view field.

Sorting
The SortMethod property specifies the default sorting order for items in the
list view field. You can use the ListView_Sort() function to re-sort the items
in the list using another sorting method. When you add items to the list
view field, they will always be added to the end of the list, regardless of the
current sorting order. Use the ListView_Sort() function to re-sort the list
after adding items.

By default, the list view will use the string component of a subitem when
sorting a column in the list view. The list view items will be sorted in ASCII
order, which may not be appropriate if the list view field contains non-
string values, such as currency, integer, date or time values. If this is the
case, you can use functions such as ListView_ItemSetIntSubitem() and
ListView_ItemSetCurrencySubitem() and to add an additional integer,
currency, date or time component to each subitem. If the subitems for a
column contain an additional component, its value will be used as the basis
for sorting the column.

If all the subitems for a column don’t contain the same type of additional
component, the items in that column may not sort consistently. To ensure
consistent sorting, be sure all subitems in a column have the same type of
additional component.

Sizing columns
When you add a column to a list, it will be wide enough to fully display the
column heading. If items in the column are wider than the heading, they
will be truncated. You can use the optional width parameter to specify the
width of the column when you add it. The ListView_GetStringWidth()
function is useful when specifying the width of a column. You pass a string
to this function to find out how wide the column must be to contain the
string without truncating.

If the column has already been added to the list, you can use the
ListView_ColumnSetWidth() function to specify the width of the column.
Specifying the LV_AUTO_SIZE as the column width will size the column so
the widest column item will be displayed without truncating. If you are
setting the width of the last column in the list view, use the LV_AUTO_FIT
constant to resize the column to fill the remaining space in the list view.

140 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 3 L I S T V I E W

Use the LV_AUTO_FIT constant


to resize the last column to fill
the remaining space.

Working with the selection


Once items have been added to a list view, it is often necessary to change
the selection or find out which items are selected.

Changing the selection


The user can select items in the list view. You can also use the
ListView_SelectionSet() function to change the selection. If the list view
field allows multiple items to be selected, use the mode parameter of this
function to specify whether an item is being added to or removed from the
current selection.

Retrieving the selection


If the list view field allows only one item to be selected, simply use the
ListView_SelectionGet() function to return the index of the selected item.
If the list view field allows multiple items to be selected, use the
ListView_SelectionCount() function to retrieve the number of items
selected. Then, using the offset parameter of the ListView_SelectionGet()
function, indicate which of the selected items you want to retrieve.

For example, the following illustration shows a list view field that allows
multiple selections. The ListView_SelectionCount() function indicates that
three items are selected. To retrieve the index for the item “4750 9th Avenue
South”, pass the offset value 2 to the ListView_SelectionGet() function to
retrieve the second selected item.

To retrieve this
item, use 2 as the
offset value.

PROGRAMMER’S GUIDE VOLUME 2 141


PA RT 3 WO RKING WI TH C ONTR O LS

Searching a list view


At some point, you may want to search a list view field to find out whether
it contains a specific item. There are numerous ways to search a list view
field, and a complete discussion of them is beyond the scope of this manual.
The following code is for the ListView_Search() function. You can use this
code as a starting point for searching list view fields.

function returns long item_index;

inout anonymous field listview_field; {The list to search.}


in string search_string; {The string to search for.}
in long start_item; {Where to begin searching.}

local long current_item, item_count, i;


local boolean found;
local integer view_mode, column_count, subitem, j;

{Count the number of items to search.}


item_count = ListView_ItemCount(listview_field);

{Find out the view mode.}


view_mode = ListView_GetView(listview_field);

{Count the number of columns defined.}


column_count = ListView_ColumnCount(listview_field);

{Look through each item.}


found = false;
current_item = start_item;
while (current_item <= item_count) and (found = false) do
{Look at the current item.}
if view_mode = LV_REPORT_VIEW then
{Have to look through the column items as well.}
for j = 1 to column_count do
subitem = ListView_ColumnGetSubitem(listview_field, j);
if pos(ListView_ItemGetSubitem(listview_field,
➥ current_item, subitem), search_string, 1) <> 0 then
{The item was found.}
found = true;
item_index = current_item;
exit for;
end if;
end for;

142 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 3 L I S T V I E W

else
{Only have to look at the item.}
if pos(ListView_ItemGetLabel(listview_field, current_item),
➥ search_string, 1) <> 0 then
{The item was found.}
found = true;
item_index = current_item;
end if;
end if;
current_item = current_item + 1;
end while;

if found = false then


{The item was not found.}
item_index = LV_INVALID;
end if;

The ListView_Search() function begins searching the list at the item


specified. If an item containing the specified text is found, that item’s index
is returned. Otherwise, the constant LV_INVALID is returned.

The following example uses the ListView_Search() function to search the


Explorer List list view field for the item containing the text “Bancroft”,
beginning with the first item.
local long item_index;
local boolean result;

item_index = ListView_Search('Explorer List', "Bancroft", 1);

{If an item was found, select it and make it visible.}


if item_index <> LV_INVALID then
result = ListView_SelectionSet('Explorer List', item_index);
result = ListView_ItemMakeVisible('Explorer List', item_index);
end if;

PROGRAMMER’S GUIDE VOLUME 2 143


144 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 4: WORKING WITH TABLES
Part 4: Working with Tables
This portion of the documentation describes how to work with tables in
your application. The following topics are discussed:

• Chapter 14, “Table Overview,” provides basic information about work-


ing with tables using scripts.

• Chapter 15, “Working with Records,” describes how to save and


retrieve records in tables.

• Chapter 16, “Ranges,” explains how to work with ranges of records in


tables.

• Chapter 17, “Memory-based tables,” describes how to work with tables


that are stored in memory.

• Chapter 18, “Multiuser processing,” explains scripting issues involved


with multiuser applications.

• Chapter 19, “Transactions,” describes how to implement transaction


support available for the SQL database manager.

146 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 14: Table Overview
Dexterity is a database development tool, so the most common use of
scripts is to work with data in tables. The following topics are discussed:

• Common table operations


• Data in windows
• Table buffers

Common table operations


The following is a list of the most common operations that are performed
with tables. They include:

• Saving information displayed in a window to a table (saving a record)

• Retrieving information from a table and displaying it in a window


(retrieving a record)

• Deleting information from a table (removing a record)

Working with tables is one of the most difficult concepts to grasp while learning
Dexterity; you may not understand everything your first time through. The best
approach is to carefully work through the examples provided and then try the
concepts in your own application.

Before these procedures are described, you should have some


understanding of how Dexterity works with windows and tables.

Data in windows
The data you see displayed in windows comes from entries users make in
windows or from tables that are part of the application. Users can change
information in a window without affecting data in tables. Information in a
window is maintained until the form containing the window is closed;
opening or closing a particular window doesn’t change information
displayed in a window.

Scripts are used to move information from the fields in windows to the
fields stored in tables. Dexterity provides special sanScript commands that
make moving data between windows and tables much easier.

PROGRAMMER’S GUIDE VOLUME 2 147


PA RT 4 W O R K I N G W I T H T A B L E S

Table buffers
A buffer is a temporary storage area in memory. Each time you attach a
table to a form, a table buffer is created for the table. If you attach a table to
more than one form, each form will have its own table buffer for that table.

A table buffer can hold one record of information. The information in the
table buffer comes from either windows that are part of the form or from
the table, depending on whether you’re reading a record from the table or
storing the information entered in a window.

The relationship among forms, windows, table buffers and tables is shown
in the following illustration.

Form A Form B

Windows

Table buffers

Table 1 Table 2

Note that there is a table buffer for each table attached to a form, and that
Table 2 is attached to both Form A and Form B, so each form has a table
buffer for Table 2.

148 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 4 T AB L E O V E R V I E W

Now that you have an understanding of the relationships among forms,


windows, table buffers and tables, you’ll see how they work together to
save, retrieve and delete records from tables. The next chapter contains two
examples that show scripts that perform basic operations with tables.

Additional chapters in this part describe more advanced topics, such as


working with ranges of records and handling records in multiuser
environments.

PROGRAMMER’S GUIDE VOLUME 2 149


150 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 15: Working with Records
This portion of the documentation describes basic operations you will
perform when working with records in tables. Two extensive examples are
provided that show basic operations in detail. Information is divided into
the following sections:

• Example 1 - One window and one table


• Example 2 - Two windows and two tables
• Multiple records with the same key value
• Modifying the values of key fields

PROGRAMMER’S GUIDE VOLUME 2 151


PA RT 4 W O R K I N G W I T H T A B L E S

Example 1 - One window and one table


The application shown in the following illustration manages addresses
using one window, Address_Maintenance, and one table, Address_Data.
The key for the table is the Name field. (Remember that a table key is the
field or group of fields used to sort and retrieve the record.) The illustration
shows the form (represented by the black border), window, table and table
buffer for the application.

Form: Address_Maintenance

Window

Name:
Address:
Table buffer City:
State:
ZIP Code:

Table

Address_Data

152 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 5 W O R K I N G W IT H R E C O R D S

Saving a record
When saving information from a window in a table, the user must first
enter the information in the window, in this case, the address information
for A-1 Construction. When all the information is entered, the user can click
the Save button in the window to save the information in the table. The
following script, attached to the Save button, performs two basic steps to
save the information.

{Step 1: Copy the information from the window to the table buffer.}
copy to table Address_Data;
{Step 2: Save the information in the table buffer to the table.}
save table Address_Data;
{Clear the window to accept another record.}
restart form;

The procedure is shown in the following illustration.

Window

copy to
table 1

Name: A-1 Construction


Address: 1234 Main Street
Table buffer City: Springfield
State: NE
save ZIP Code: 55555-0321
table 2

Table

Address_Data

PROGRAMMER’S GUIDE VOLUME 2 153


PA RT 4 W O R K I N G W I T H T A B L E S

Retrieving a record
Retrieving a record is a multi-step process. The user must enter the key
values for the record; in this case, the name A-1 Construction. Then the
following script, a change script for the Name field, retrieves the record and
copies the information to the window.

More information {Release the lock on any record currently in the table buffer.}
about record locking release table Address_Data;
can be found in {Step 1: Copy the key field from the window to the table buffer.}
Chapter 18, “Multiuser 'Name' of table Address_Data = 'Name' of window Address_Maintenance;
processing.”. {Step 2: Retrieve the record from the table, allowing the data to be
changed.}
change table Address_Data;
{Step 3: Copy the information to the window.}
copy from table Address_Data;

Window

set 1

Name: A-1 Construction


Address:
Table buffer City:
State:
ZIP Code:

Table

Address_Data

154 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 5 W O R K I N G W IT H R E C O R D S

Window

copy
from 3
table
Name: A-1 Construction
Address: 1234 Main Street
Table buffer City: Springfield
State: NE
ZIP Code: 55555-0321
change
2

Table

Address_Data

The change statement retrieves the record from the file, based upon the key
value set in the table buffer. In this example, the record for A-1 Construction
was retrieved because the key value was set to A-1 Construction. The copy
from table statement copies the record from the table buffer to the window
so the information is displayed.

Deleting a record
To delete a record, the record must exist in the table and be retrieved using
the “Retrieving a record procedure” just described. Then the record can be
removed from the table. The following script, attached to the Delete button,
will remove the record currently in the table buffer from the table.

{Remove the record currently in the table buffer from the table.}
remove table Address_Data;
{Clear the window to accept another record.}
restart form;

PROGRAMMER’S GUIDE VOLUME 2 155


PA RT 4 W O R K I N G W I T H T A B L E S

Example 2 - Two windows and two tables


The application shown in the following illustration manages a list of
customers using two windows, Customer_Maintenance and Comments.
The Customer_Maintenance window is the main window for the form.

Customer_Maintenance form

Windows

Table buffers

Tables

Customer_List Customer_Comments

The application uses two tables, each with the following fields:

Customer_List Customer ID
Name
Address
City
State
ZIP
Phone Number
Customer_Comments Customer ID
Comments

The Customer ID field is the key for both tables.

156 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 5 W O R K I N G W IT H R E C O R D S

Saving a record
When saving information from a window to a table, the user must first
enter the information in the form’s windows. When all the information is
entered, the user can click the Save button in the window to save the
information to the tables.

Refer to the SanScript To save information entered in windows into tables, the information must
Reference manual for be copied from the windows to the appropriate table buffers. To simplify
more information this process, Dexterity uses multiple table auto-copy. Multiple table auto-copy
about the copy from allows you to transfer all of the information from a table buffer to all the
table and copy to windows in the form using the copy from table statement, or from all
table statements. windows in the form to the table buffer using the copy to table statement.
Data will be copied between the corresponding window and table fields
(those having the same resource ID).

The AutoCopy property for each window field controls whether the field
will be updated by the copy from table and copy to table statements. By
default, the AutoCopy property is set to true.

The copy to table statement must be used carefully when more than one
window in the form contains the same table field. (In this example, the
Name field from the Customer_List table is used for both the
Customer_Maintenance and Comments windows.) The copy to table
statement will copy the fields from the main window to the table buffer,
then copy fields from any child windows (windows in the form other than
the main window) to the table buffer. This means the contents of the
common field in the child window will be copied to the table buffer,
replacing any values copied from the field on the main window. This will
occur even if the child window isn’t open.

To prevent storing fields with empty or incorrect information in a table, be


sure that all common window fields have the same value before using the
copy to table statement. Another solution is to use the copy from window
to table statement, which copies information from only the specified
window to the specified table buffer.

PROGRAMMER’S GUIDE VOLUME 2 157


PA RT 4 W O R K I N G W I T H T A B L E S

The following script, attached to the Save button, performs the steps
necessary to save the information. The illustration on the following page
shows each step.

{Step 1: Because the Name field appears on both the


Customer_Maintenance and Comments windows, the Name field in the
Comments window is set to the value of the Name field in the
Customer_Maintenance window. This will ensure that the correct value
will be saved to the Customer_List table.}
'Name' of window Comments = 'Name' of window Customer_Maintenance;

{Step 2: Copy the information from the windows to the Customer_List


table buffer.}
copy to table Customer_List;

{Step 3: Save the information in the Customer_List table.}


save table Customer_List;

{Step 4: Copy the information from the windows to the


Customer_Comments table buffer.}
copy to table Customer_Comments;

{Step 5: Save the information in the Customer_Comments table.}


save table Customer_Comments;
restart form;

The procedure is shown in the following illustrations. The customer record


for April Berger is entered, then saved.

158 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 5 W O R K I N G W IT H R E C O R D S

1
set

2 copy to
table

save
3 table

Customer_List Customer_Comments

4 copy to
table

save
5 table

Customer_List Customer_Comments

PROGRAMMER’S GUIDE VOLUME 2 159


PA RT 4 W O R K I N G W I T H T A B L E S

Retrieving a record
Retrieving a record is a multi-step process. The user must enter the key
values for the record; in this case, the Customer Number 104 for April
Berger. Then the following script, a change script for the Customer ID field,
retrieves the correct records from the Customer_List table and the
Customer_Comments Table and copies the information to the
Customer_Maintenance and Comments windows.

{Release the lock on any record currently in the Customer_List table


buffer.}
release table Customer_List;

{Step 1: Copy the key field from the window to the Customer_List table
buffer.}
'Customer ID' of table Customer_List = 'Customer ID' of window
➥ Customer_Maintenance;

{Step 2: Retrieve the record from the Customer_List table, allowing


the data to be changed.}
change table Customer_List;

{Step 3: Copy the information from the Customer_List table buffer to


the windows so it is displayed.}
copy from table Customer_List;

{Release the lock on any record currently in the Customer_Comments


table buffer.}
release table Customer_Comments;

{Step 4: Copy the key field from the window to the Customer_Comments
table buffer.}
'Customer ID' of table Customer_Comments = 'Customer ID' of window
➥ Customer_Maintenance;

{Step 5: Retrieve the record from the Customer_Comments table,


allowing the data to be changed.}
change table Customer_Comments;

{Step 6: Copy the information from the Customer_Comments table buffer


to the window so it is displayed.}
copy from table Customer_Comments;

160 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 5 W O R K I N G W IT H R E C O R D S

The procedure is shown in the following illustrations.

1 set

2 change

Customer_List Customer_Comments

copy from
3 table

Customer_List Customer_Comments

PROGRAMMER’S GUIDE VOLUME 2 161


PA RT 4 W O R K I N G W I T H T A B L E S

4 set

5 change

Customer_List Customer_Comments

copy from
6 table

Customer_List Customer_Comments

162 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 5 W O R K I N G W IT H R E C O R D S

Deleting a record
To delete a record, the record must exist in the table and be retrieved as
described in the previous section. Then the record can be removed from the
table. The following script, attached to the Delete button, will remove the
records for the current customer from the Customer_List and
Customer_Comments tables.

{Remove the record currently in the Customer_List table buffer.}


remove table Customer_List;
{Remove the record currently in the Customer_Comments table buffer.}
remove table Customer_Comments;
{Clear the windows to accept another record.}
restart form;

Multiple records with the same key value


Tables that contain records with the same key value must be handled
cautiously. For example, in the table containing customer names, shown in
the following illustration, the key is the customer’s last name. Several
customers have the last name “Smith”. Thus, several records have the same
key value.

Last Name is the key


for the table. Last Name First Name
Schulz Dan
Smith Alan
Four records have
Smith Maria
“Smith” as the key
value. Smith Bob
Smith Sharon
Thompson Jean
Wallace Phil

PROGRAMMER’S GUIDE VOLUME 2 163


PA RT 4 W O R K I N G W I T H T A B L E S

Adding records
To allow multiple records to have the same key value, you must choose the
appropriate options in the Key Definition window when you create keys for
the table. For Pervasive.SQL and c-tree tables, mark the Duplicates option.
For SQL tables, be sure the Unique option is not marked. If you haven’t
chosen the appropriate options, an error indicating a duplicate record will
occur when you add records with the same key value to a table.

Retrieving records
It’s more difficult to retrieve records that have the same key value from a
table. The standard practice of setting the table buffer to the key value and
then using a get or change statement won’t work because the database
manager can’t guarantee which record will be retrieved. For example, if the
table buffer for the table shown in the previous illustration was set to
“Smith” and a get or change statement was used to retrieve a record, the
table buffer could contain the record for Alan, Maria, Bob or Sharon Smith.
There is no way of knowing which record will be read.

Two methods can be used to reliably retrieve records that have the same
key value.

• Start at the beginning of the table using the get first or change first
statement. Then use get next or change next statements to read all of
the records in the table. Be sure you’re using the same key for the get
first or change first and get next or change next statements.

This method will read all of the records in the table, including those
that have the same key value. However, there is no way of determining
the order in which the records having the same key value will be read.

• Use the range start statement to set the beginning of the range to the
duplicate key value, and use the range end statement to set the end of
the range to the duplicate key value. Use the get first or change first
statement to retrieve the first record in the range. Then use the get next
or change next statement to retrieve successive records from the range.
Be sure you’re using the same key for the range and get or change
statements.

This method will read all of the records that have the same key value
specified using the range statements. However, there is still no way of
determining the order in which the records having the same key value
will be read.

164 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 5 W O R K I N G W IT H R E C O R D S

The following script reads all of the “Smiths” from the example table. The
range statements allow the table to access only records with the key value
“Smith.” The get first and get next statements read all of records from the
range in the table. Note that the same key is used for all of the range and get
statements.

{Clear any existing ranges and set up the new range.}


range clear table Customers;
'Last Name' of table Customers = "Smith";
range start table Customers by number 1;
range end table Customers by number 1;
{Read the records.}
get first table Customers by number 1;
while err() <> EOF do
get next table Customers by number 1;
end while;

Modifying the values of key fields


The ability to modify key fields of a record in a table differs, based upon the
database manager used for the table. If you’re using the c-tree or SQL
database managers, you can always modify the contents of key fields of a
record in a table. If you use the Pervasive.SQL database manager, the
contents of key fields can be changed only when the Modifiable key option
is marked. If you try to change the contents of key fields of a Pervasive.SQL
table that doesn’t have the Modifiable key option marked, an alert message
will appear explaining that you attempted to change a non-modifiable key.

The following example illustrates modifying a key field. The change


statement was used to read the record shown in the following illustration.

Last Name is the key


for the table. Last Name First Name
Schulz Dan

PROGRAMMER’S GUIDE VOLUME 2 165


PA RT 4 W O R K I N G W I T H T A B L E S

The value of the key field Last Name was changed from Schulz to Smith
and the record was saved using the save table statement. If the database
manager being used allows modifying key values, the record would be
saved. The record would then contain the new last name as shown in the
following illustration.

Last Name First Name


The value of the key
field was changed. Smith Dan

If the database manager doesn’t allow key values to be modified, an alert


message would be displayed indicating you had attempted to change a
non-modifiable key.

166 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 16: Ranges
When working with tables, it is often efficient to limit the amount of
information being accessed. You can do this by setting up a range for the
table. Information about ranges is divided into the following sections:

• Range overview
• Ranges for multisegment keys
• Range types
• Well-behaved ranges

Range overview
A range is based upon a key for the table, and allows you to access a
specified portion of the table. The selected range will be treated as an entire
table. For instance, a get first statement returns the first record in the range,
a get last statement returns the last record in the range, and so on.

The range statement is used to create a range for a table. You can specify
one range per table, and the range is associated with a specific key. The
range will be used only when the table is accessed by the key the range is
associated with.

In the following example, the range statement is used to limit the records
accessed to only those for which the Selling Price is between 500 and 1000
dollars. Notice that the same key, composed of the Selling Price field, is
used for each of the range statements as well as the get first statement.

{Clear any existing range for the table.}


range clear table Inventory_Data;
{Set the start of the range.}
'Selling Price' of table Inventory_Data = 500;
range start table Inventory_Data by Selling_Price;
{Set the end of the range.}
'Selling Price' of table Inventory_Data = 1000;
range end table Inventory_Data by Selling_Price;
{Read the first record in the range.}
get first table Inventory_Data by Selling_Price;

You can use the Table_IsRangeSet() function to find out whether a range is set for
a table.

PROGRAMMER’S GUIDE VOLUME 2 167


PA RT 4 W O R K I N G W I T H T A B L E S

Ranges for multisegment keys


If a key is composed of several segments, you can create ranges based upon
several key segments. The clear field and fill statements are often used
when setting ranges for multisegment keys. For example, the
Purchase_Data table is shown in the following illustration. It has a key
composed of the Purchase Date and the Store ID.

Purchase Date Store ID Amount


11/16/98 C 100.00
11/17/98 A 50.00
11/17/98 B 75.00
11/17/98 C 22.00
11/18/98 A 175.00
11/18/98 C 60.00
11/19/98 A 45.00
11/19/98 C 16.00
11/20/98 B 100.00

The following script sets a range to include all purchases made on 11/17/98
for all stores. The first segment of the key is set to the date 11/17/98. The
second segment is set to its minimum value using the clear field statement,
then the start of the range is set. The first segment remains 11/17/98. The
second segment is set to its maximum value using the fill statement. Then
the end of the range is set. Using the clear field and fill statements on the
Store ID fields allows all stores to be selected.

{Clear any previous range for the table.}


range clear table Purchase_Data;
{Set the start of the range.}
'Purchase Date' of table Purchase_Data = setdate('Purchase
➥ Date' of table Purchase_Data, 11, 17, 1998);
clear field 'Store ID' of table Purchase_Data;
range start table Purchase_Data by number 1;
{Set the end of the range.}
'Purchase Date' of table Purchase_Data = setdate('Purchase
➥ Date' of table Purchase_Data, 11, 17, 1998);
fill 'Store ID' of table Purchase_Data;
range end table Purchase_Data by number 1;

168 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 6 R AN G E S

Range types
Refer to the range How a range is evaluated depends upon the database manager used for the
statement in the table. For the Btrieve and c-tree database managers, ranges are evaluated
SanScript Reference inclusively. For the SQL database manager, ranges are evaluated either
manual for a complete inclusively or exclusively.
description of how
Dexterity evaluates The following example illustrates the difference between these two
ranges for the methods of evaluating a range. The sample table shown in the following
Pervasive.SQL, c-tree illustration has a key composed of the three segments shown.
and SQL database
managers. Segment 1 Segment 2 Segment 3
A A A
A A B
A A C
A B A
A B B
A B C
A C A
A C B
A C C
B A A
B A B
B A C
B B A
B B B
B B C
B C A
B C B
B C C
C A A
C A B
C A C
C B A
C B B
C B C
C C A
C C B
C C C

PROGRAMMER’S GUIDE VOLUME 2 169


PA RT 4 W O R K I N G W I T H T A B L E S

The following range is set for the table:

Range start: A A A
Range end: A C B

Refer to the range The following records are included in the inclusive range.
statement in the
SanScript Reference Segment 1 Segment 2 Segment 3
manual for a complete A A A
description of how
A A B
inclusive and exclusive
A A C
ranges are evaluated.
A B A
A B B
A B C
A C A
A C B

The following records are included in the exclusive range.

Segment 1 Segment 2 Segment 3


A A A
A A B
A B A
A B B
A C A
A C B

Notice that inclusive and exclusive ranges don’t contain the same records.
This is an issue when developing an application, because the Btrieve and c-
tree database managers always produce inclusive ranges, but the SQL
database manager has optimal performance when it produces exclusive
ranges. The SQL database manager can be forced to produce inclusive
ranges, but the application’s performance may be seriously degraded. To
eliminate the discrepancies that result from the two types of ranges, we
recommend that you implement “well-behaved” ranges in your
application.

170 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 6 R AN G E S

Well-behaved ranges
A “well-behaved” range has the following characteristics:

• Beginning with the leftmost key segment and working to the right, the
first 0 to n segments are set to equal values for both the range start and
the range end.

• The next 0 or 1 segments are set to non-equal values for the range start
and range end.

• The remaining segments (if any) are cleared for the range start and
filled for the range end.

It is desirable for a range to be “well-behaved” because “well-behaved” ranges


produce the same results for all database managers.

The scripts in the first and second examples of this section both create
“well-behaved” ranges. The ranges produced will be the same, regardless
of the database manager being used.

PROGRAMMER’S GUIDE VOLUME 2 171


172 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 17: Memory-based tables
Memory-based tables are just like standard c-tree tables. In Dexterity
release 8 and earlier, these tables were stored in memory, rather than
written to a physical disk. Beginning with Dexterity release 9, memory-
based tables are no longer stored in memory. Instead, they’re written to the
following location in the Documents and Settings folder for the current
user:

User_Name\Local Settings\Temp\TNTxx

While memory-based tables were slightly faster than disk-based tables, you
won’t see a significant change in performance with this change. The change
was necessary due to the number of large memory-based tables that were
being used at one time. As memory became fragmented, no contiguous
blocks large enough could be allocated to complete table operations. In
some cases, this problem caused application errors that affected end-users.
The change to disk-based tables eliminates this issue.

Information about memory-based tables is divided into the following


sections:

• Creating memory-based tables


• Pathnames for memory-based tables
• Using memory-based tables

Creating memory-based tables


To create a memory-based table, select Memory as the Database Type in the
Table Definition window.

Choose Memory as the


database type to create a
memory-based table.

You can also use the open table statement to open an existing table as a
memory-based table.

PROGRAMMER’S GUIDE VOLUME 2 173


PA RT 4 W O R K I N G W I T H T A B L E S

Pathnames for memory-based tables


The Pathname script runs for memory-based tables, just as it does for other
tables. This means that memory-based tables have path information, even
though they are stored in memory.

If you don’t want a memory-based table to have path information, make the
table part of the Pathname series. The Pathname script doesn’t run when
tables in the Pathname series are accessed.

Using memory-based tables


From sanScript, you use memory-based tables just as you would any other
tables. Keep in mind the following guidelines when using memory-based
tables:

• Memory-based tables remain in the current user’s Temp folder until the
application is shut down or the table is removed using the delete table
statement. If the application shuts down unexpectedly, the .DAT and
.IDX files for the table will remain on the user’s disk until manually
removed.

• Memory-based tables have shared access. This means that the table can
be accessed from multiple locations in the application simultaneously.
For example, three separate forms and a procedure could all access a
single memory-based table. Remember that the path information must
be the consistent to access the same memory-based table.

This is the most common use of a memory-based tables–as shared access


temporary tables.

• Memory-based tables can be temporary tables. If you specify temp as


the physical name of a memory-based table, it will act like other tempo-
rary tables. The table won’t have shared access, and its physical name
will be assigned by the operating system.

174 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 18: Multiuser processing
Dexterity supports multiple users accessing the same table at the same
time. To accommodate this, Dexterity applications apply Optimistic
Concurrency Control (OCC), a form of record locking that allows multiple
users to work in the same tables and access the same records with minimal
restrictions, while helping to ensure data integrity.

Information about multiuser processing is divided into the following


sections:

• Record locking
• Releasing locks
• Coding a multiuser application
• Multiuser examples

Record locking
A record must be locked to delete it or save any changes made to it. A lock
is applied when a record is read from a table. Two types of locks can be
used: passive and active.

Passive locking
A passive lock allows other users to access the record. Other users can delete
the record or make changes to it. Passive locking ensures that other users
accessing the record can be made aware that the record has been deleted or
that the contents of the record have changed. A passive lock is applied each
time a record is read using the change or edit table statement.

Active locking
An active lock allows other users to read the record, but not make any
changes or delete the record. Active locking ensures that the user who has
the active lock is the only user who can make changes or delete the record.
If other users try to delete or change the record, a table-sharing error will
occur. An active lock is applied each time a record is read using the change
or edit table statements with the lock keyword included.

The get statement is used only to read a record. It never locks a record.

PROGRAMMER’S GUIDE VOLUME 2 175


PA RT 4 W O R K I N G W I T H T A B L E S

You must mark the Allow Active Locking option in the table definition for
each table on which active locking will be allowed. If you don’t mark this
option, any change or edit table statements that reference that table and
include the lock keyword will produce errors when you attempt to compile
them.

We strongly recommend that you avoid using active locking in your application.
Application performance can degrade when active locking is used, especially when
your application uses a SQL database.

Releasing locks
Any of the following actions releases a record lock:

• Using the release table statement.

• Running the save table or remove statements, regardless of whether


the statement is successful.

If a record is currently locked in a table buffer, and you attempt to lock


another record, you will receive an error message indicating that a record
was already locked.

Coding a multiuser application


To allow multiple users to successfully use your application, you must
choose the type of locking used as well as handle any error conditions that
occur as a result of multiple users working with the same record.

The following table lists the scenarios that can occur. The events listed
happen in order from left to right. For example, in the first row User A
passively locks a record, then User B passively locks the same record. User
A deletes the record, then User B changes the contents of the record and
saves the record. The changes User B made will be saved.

176 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 8 M U L TI U S E R P R O C E S S IN G

Case User A User B User A User B Result


1 Passively locks a Passively locks Deletes the record. Changes the The changes User B made will be
record. the same record. contents of the saved.
record and saves
the changes.
2 Passively locks a Passively locks Changes the Deletes the record. The record will be deleted.
record. the same record. contents of the
record and saves
the record.
3 Passively locks a Passively locks Changes a field Changes a Both changes will be saved.
record. the same record. and saves the different field and
record. saves the record.
4 Passively locks a Passively locks Changes a field Changes the same User B will get an error
record. the same record. and saves the field and attempts indicating the record changed.
record. to save the record. User B’s changes won’t be saved.
5 Passively locks a Passively locks Deletes the record. Attempts to delete User B will get an error
record. the same record. the record. indicating the record is missing.
6 Actively locks a Passively locks Keeps the active Attempts to delete User B will get a record locked
record. the same record. lock. the record or error. The record won’t be
change a field and deleted or the changes won’t be
save the record. saved.
7 Actively locks a Passively locks Deletes the record. Changes the If user B changed the record and
record. the same record. The active lock is record and saves it saved, the changes will be saved.
released. or deletes the If User B attempts to delete the
record. record, User B will get an error
indicating the record is missing.
8 Actively locks a Passively locks Makes changes Changes the If User B changed the same field
record. the same record. and saves the record and saves it as User A, User B will get an
record. The active or deletes the error indicating the record
lock is released. record. changed. User B’s changes won’t
be saved.
If user B changed different fields,
the changes will be saved.
If User B deleted the record, the
record will be deleted.
9 Passively locks a Actively locks the Attempts to delete Keeps the active User A will get a record locked
record. same record. the record or lock. error, even though User B’s
change a field and active lock came later than User
save the record. A’s lock.
10 Actively locks a Attempts to User B will get a record locked
record. actively lock the error.
same record.

PROGRAMMER’S GUIDE VOLUME 2 177


PA RT 4 W O R K I N G W I T H T A B L E S

Scenarios 1 through 3 don’t produce any errors. A multiuser application


should be able to handle scenarios 4 to 10, alerting users that an error
occurred, and allow them to respond appropriately.

In the current version of Dexterity, fields with the text control types should not be
used in tables that are checked for multiuser error conditions. Records can’t be
locked properly if text fields are included in the table. If your application uses text
fields, store them in a separate table that won’t be checked for multiuser error
conditions.

The err() function is used to trap errors so the script can deal with the errors
that occur. The following examples are the Part Number, Save Button and
Delete button scripts for the sample inventory application. They use the
err() function to trap and handle errors.

Multiuser examples
The following examples show how to write the scripts to handle basic
multiuser scenarios. The first example shows how to read a record, the
second shows how to save a record, and the third shows how to delete a
record.

Example 1
Refer to the SanScript The following is the Part Number change script that retrieves and actively
Reference manual for locks a record. It uses the err() function to handle an error resulting from the
more information record being actively locked by another user.
about the err()
function. {Release the lock on any record currently in the table buffer.}
release table 'Inventory_Data';
{Set the value of the key field in the table buffer.}
'Part Number' of table Inventory_Data = 'Part Number' of window
➥ 'Inventory_Maintenance';
{Attempt to retrieve the record from the table and lock it.}
change table 'Inventory_Data' by Inventory_Data_Key1, lock;
if err() = OKAY then
{If there was no error, the record was successfully read.}
copy from table 'Inventory_Data';
clear changes form 'Inventory_Maintenance';
{Enable the Delete button and lock the Part Number field.}
enable 'Delete Button';
lock 'Part Number';

178 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 1 8 M U L TI U S E R P R O C E S S IN G

elseif err() = LOCKED then


{The record is actively locked by another user.}
error "This record is currently locked by another user.";
restart form;
else
{The record is missing. The user must be entering a new
record. Prevent the Part Number field from being modified.}
lock 'Part Number';
end if;

Example 2
The following is the Save button change script. It uses the err() function to
handle an error resulting from the record being changed or being actively
locked by another user.
if required(form Inventory_Maintenance) then
copy to table Inventory_Data;
save table Inventory_Data;
if err() = RECORDCHANGED then
{The record was changed by another user.}
warning "This record has been changed by another user.
➥ The record will be read again.";
change table Inventory_Data;
copy from table Inventory_Data;
elseif err() = LOCKED then
{The record is actively locked by another user.}
warning "This record is currently locked by another
➥ user. Changes will not be saved";
else
{Save was successful.}
restart form;
end if;
else
warning "Please enter all required fields.";
end if;

After the successful save operation, the save table statement automatically
updates the fields in the table buffer that were changed by other users. This
means that the values in the table buffer after the save operation may differ
from the values in the table buffer before the save operation. After a
successful save operation, you may want to update the data displayed in
your application to reflect these changes.

PROGRAMMER’S GUIDE VOLUME 2 179


PA RT 4 W O R K I N G W I T H T A B L E S

Example 3
The following is the Delete button change script. It uses the err() function to
trap and handle an error resulting from the record being actively locked by
another user.
if ask("Delete this item?","Cancel","Delete","") = ASKBUTTON2 then
remove table Inventory_Data;
if err() = LOCKED then
{The record is actively locked by another user.}
warning "This record is currently locked by another user.
➥ It can't be deleted.";
elseif err() = MISSING then
{The record has been deleted by another user. No need to
delete record.}
restart form;
else
restart form;
end if;
end if;

When you’re writing scripts that handle errors using the err() function, you may
want to use the check error statement as a debugging tool while you’re working.
The check error statement will display a message indicating the type of table error
that occurred.

180 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 19: Transactions
Transactions are a database feature that allow you to perform a set of table
operations as a single unit. Transactions are useful when you have sets of
table operations that must all be completed for the integrity of the data to be
maintained. Partial completion of the operations would leave the database
in an inconsistent state.

For example, a transaction would be useful when transferring a balance


from one account to another. This operation requires two actions:
decreasing the balance of one account and increasing the balance of the
other. Both operations must be completed to maintain the integrity of the
data. If either operation can’t be completed, the desired behavior is to “roll
back” the transaction, as if it had never been attempted.

Information about transactions is divided into the following sections:

• Transaction overview
• Error handling for transactions
• Transaction template
• Guidelines for transactions
• Integrating applications

Transaction overview
In Dexterity, transactions are supported only for the Microsoft SQL
Server™ database. You can’t use transactions with any of the other
supported database managers. Use the havetransactions() function to find
out whether the default database type supports transactions.

To start a transaction, use the transaction begin statement. Perform the


table operations that perform the work of the transaction. If all of the table
operations are successful, you can “commit” them using the transaction
commit statement. If any table operations fail and can’t be completed, the
transaction can be “rolled back” using the transaction rollback statement.
The table operations performed in the transaction will be undone, returning
the data to the state it was in before the transaction began.

Once a transaction is started, any scripts that are called are also part of the
transaction. For instance, any database operations performed by
procedures called from within a transaction are part of the transaction.

PROGRAMMER’S GUIDE VOLUME 2 181


PA RT 4 W O R K I N G W I T H T A B L E S

Error handling for transactions


When Dexterity performs ordinary table operations for Microsoft SQL
Server, it automatically uses transactions for each operation. It also handles
any errors that occur during the table operations, such as deadlocks. If you
use transactions in your application, you are responsible for handling any
errors that occur. To make handling errors easier, use the exception
handling capability available in Dexterity. Exception handling is described
in detail in Chapter 26, “Structured Exception Handler.”

The most common recoverable error that occurs when using a transaction is
a deadlock. A deadlock occurs when two users, each having locked a
record, attempt to lock the other user’s record. Each user waits for the other
to release the lock. If a deadlock occurs, an exception will be thrown that
your application will need to handle.

To deal with exceptions, transactions are executed within a try...end try


block. If a deadlock occurs, the pending transaction will automatically be
rolled back. An exception will be thrown and caught by the exception
handler, which will typically contain code to wait for a specified amount of
time, then try the transaction again. The template code provided in the next
section shows how a typical transaction is structured.

Transaction template
This section contains sample sanScript code that you can use as a template
when adding transaction support to your application.

Operation
This sample code is designed to execute a set of sanScript statements within
a transaction. If transaction processing isn’t available for the current
database type, or if a transaction is already in progress, the sanScript
statements will still be executed, just not within a transaction.

This sample code implements exception handling to deal with any


deadlock exceptions that occur. If any table operations performed within
the transaction result in a deadlock condition, the exception handler code
will wait for at least 10 milliseconds, then retry the transaction. If the
transaction isn’t successful after ten attempts, a deadlock exception is
thrown to alert the user to the deadlock condition.

182 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 9 T R A N S AC TI O N S

Using the sample code


To use this sample code, copy and paste it into your application where you
want to perform the transaction. A comment near the beginning of the code
indicates where to add the sanScript statements that will be performed
within the transaction.

Structuring code in a transaction


The code that is executed within a transaction must have certain
characteristics to operate properly. These include the following:

• The code executed should be a restartable process. This means that if


processing was stopped on any line, the code would function properly
when started again from the beginning.

• To ensure the code executed is a restartable process, all record locking


should be managed within the try...end try block. Don’t obtain passive
or active locks prior to starting the transaction.

• If you can’t be certain of the state of a table buffer before you lock a
record, it’s a good idea to use the release table statement to ensure a
record isn’t already locked.

• If you use any c-tree temporary tables within the transaction, you will
need to perform any clean-up operations for them when the transaction
has finished. You will also need to do this if the transaction is rolled
back, restarted or terminated abnormally.

Refer to Guidelines for transactions on page 185 for more information about
designing the code to be executed within the transaction.

PROGRAMMER’S GUIDE VOLUME 2 183


PA RT 4 W O R K I N G W I T H T A B L E S

The following is the transaction template:

local boolean transaction_started;


local integer retry_count;
local integer MAXRETRIES = 10;
local long sleeptime;

retry_count = 0;
try
{If a transaction can be used, start one.}
if (Tools_GetTranLevel() = 0) and (havetransactions()) then
transaction begin;
transaction_started = true;
else
transaction_started = false;
end if;

{*** Statements to execute within the transaction go here ***}

{If a transaction has been started by this code, end it.}


if transaction_started = true then
transaction commit;
end if;

catch [EXCEPTION_CLASS_DB_DEADLOCK]
{If a transaction was started, it was automatically rolled back.}

if transaction_started = true then


{If this code started the transaction, retry it until the
retry limit is exceeded.}
if retry_count < MAXRETRIES then
sleeptime = Timer_Sleep(10);
increment retry_count;
restart try;
else
{The retry count was exceeded. Rethrow the exception.}
throw;
end if;
else
{A deadlock exception occurred, but it wasn’t for the
transaction that this code started. Rethrow the exception.}
throw;
end if;

184 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 1 9 T R A N S AC TI O N S

else
{Some other unexpected exception occurred. If the transaction
this code started is still pending, roll it back.}
if transaction_started = true then
transaction rollback;
end if;

{Some appropriate error-handling code should be placed here to


handle the exception that occurred. This code simply displays
the exception.}
error "An unknown exception occurred. Class: " +
➥ str(Exception_Class()) + " Subclass: " +
➥ str(Exception_SubClass());
end try;

Guidelines for transactions


The following guidelines apply when using transactions in an application.
Be sure to follow them to have optimal performance for your scripts that
use transactions.

• Transactions can’t be nested. Once a transaction is started, you can’t


start another until the current transaction has been committed or rolled
back. Use the Tools_GetTranLevel() function to find out whether a
transaction is currently active.

• Keep transactions as short as possible. Don’t include operations that


aren’t an essential part of the transaction. For example, don’t update
user-interface elements within a transaction. This isn’t essential to the
transaction and should be done after the transaction is complete.

If a transaction contains many table operations, try to restructure the


transaction into several smaller transactions.

• Don’t allow user interaction while a transaction is in progress. For


example, a user may allow a dialog to remain open for an extended
period of time, effectively blocking other users from accessing the
records being accessed by the transaction.

PROGRAMMER’S GUIDE VOLUME 2 185


PA RT 4 W O R K I N G W I T H T A B L E S

• To minimize the possibility of deadlocks, access the tables in each of


your transactions in a consistent order. For example, assume a transac-
tion accesses a record in table A and then a record in table B. The other
transactions in your application should that access these tables should
use the same order. A transaction that didn’t follow this guideline and
accesses a record in table B and then one in table A will increase the
chance of a deadlock occurring.

• If you use the call sproc statement within a transaction, the operations
performed by the stored procedure are considered part of the transac-
tion. If a transaction is active, and the stored procedure called attempts
to start another transaction, an exception will be thrown indicating the
transaction level changed.

• Tables created or dropped during the transaction won’t be considered


part of the transaction.

• Temporary tables accessed during the transaction won’t be considered


part of the transaction.

• Table operations performed in scripts that aren’t run immediately, such


as those started by call background and run script delayed, won’t be
included in the transaction.

• Any pass-through sanScript executed during the transaction won’t be


considered part of the transaction.

Integrating applications
Transactions are implemented throughout Microsoft Dynamics GP. In most
cases, integrating products won’t need to deal with transaction issues. If
your integrating application registers a trigger that is activated within a
Microsoft Dynamics GP transaction, any table operations your script
performs will become part of the transaction. If the transaction is
committed, your database operations will be committed. If the transaction
is rolled back, your database operations will be rolled back.

If you use transactions in your trigger processing procedures, be sure to


verify that no transaction is in progress before starting a transaction.
Otherwise, an exception will be thrown indicating that the transaction level
has changed, since a transaction was already in progress.

186 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 5: ADVANCED SCRIPTING
Part 5: Advanced Scripting
This part describes advanced scripting topics and features available in
Dexterity. Following is a list of the topics that will be discussed, with a brief
explanation of each:

• Chapter 20, “Procedures,” describes procedures in Dexterity and how


they’re used.

• Chapter 21, “User-defined Functions,” describes how to create and use


user-defined functions.

• Chapter 22, “Dynamic Link Libraries,” explains how to use Dynamic


Link Libraries (DLLs) with the Windows version of Dexterity applica-
tions.

• Chapter 23, “Controlling the Compiler,” describes how to use the script
preprocessor in Dexterity.

• Chapter 24, “Call Stacks,” explains what call stacks are and what a pro-
grammer must know to manage them properly.

• Chapter 25, “References,” explains how to create and use references to


resources in your application.

• Chapter 26, “Structured Exception Handler,” describes how to add


exception handling to your application.

188 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 20: Procedures
A procedure is a script that provides functionality common to several parts
of an application. Use of procedures can eliminate duplication of
programming efforts and reduce application maintenance. Information
about procedures is divided into the following sections:

• Terminology
• Creating and calling procedures
• Parameters
• Using parameters
• Optional parameters
• Passing parameters to other procedures
• Using global fields as parameter types
• Table buffers
• Form procedures
• Anonymous tables and fields
• Background and remote processing
• Process groups

Terminology
Unlike other scripts, procedures aren’t attached to fields, windows or
forms; instead, procedures are called from other scripts in an application.
When a procedure is called from another script, the two scripts involved
have specific roles:

• The calling script is the script that accesses, or calls, the procedure. The
calling script can be any other script in the application.

• The called script is the procedure that is invoked by the calling script.

A set of parameters can be used to pass data to the called script or return
data to the calling script.

PROGRAMMER’S GUIDE VOLUME 2 189


PA RT 5 A D V A N C E D S C R I P T I N G

Creating and calling procedures


To create a procedure, point to New in the Explorer menu and choose
Procedure. The Script Editor window will appear. Select the appropriate
core for the procedure. You can begin writing the script for the procedure.

The call and call with name statements temporarily transfer control to a
procedure, passing an optional set of parameters. Refer to the SanScript
Reference manual for complete documentation for the call and call with
name statements.

Parameters
Procedures operate by passing parameters between the calling script and
the procedure. The procedure uses the information in these parameters to
work with variables, fields and tables, and to return values to the calling
script. Three types of parameters can be used, as shown in the following
illustration.

in

out

inout

Parameters are classified based upon how they are used when the calling
script communicates with the called script. The following table describes
the different types.

Type Characteristics
in The value is passed from the calling script to the called script. The
called script can’t change the value of an in parameter.
out The value is passed from the called script back to the calling script.
The called script sets the value of the out parameter.
inout The value is passed from the calling script to the called script and
then back to the calling script. The value can be used and changed
by the called script, which then passes it back to the calling script.

190 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

Procedures allow up to 255 parameters to be passed between the calling


script and the procedure. All parameter declarations in the procedure must
be placed prior to any local variable declarations in the script. The types of
the parameters for the procedure must match the types of the parameters
passed from the calling script. For example, if the calling script passes an
integer parameter to the procedure, the procedure must be set up to receive
an integer as a parameter.

Typically, the parameters passed to and from a procedure have one of the
standard storage types: boolean, currency, variable currency, date, integer,
long, string and time. You can also use existing global field definitions in a
dictionary when declaring parameter types. This method is used when
passing items such as composites to a procedure.

Using parameters
To effectively use procedures, you must develop an understanding of how
in, out and inout parameters are used.

In parameters
In parameters are used to pass values from the calling script to the called
script. In the called script, the value of the in parameter can only be
referenced. You can’t alter the value of an in parameter. The following
example shows how to use an in parameter in a procedure.

Example 1
This procedure warns when a customer is over his or her credit limit:

Procedure Name Credit_Limit_Warning

in currency limit;
in string name;

warning name + " is over the limit " + string(limit);

The following script calls the Credit_Limit_Warning procedure. The


parameters 10000 and Jane Smith are passed to the procedure. A warning
dialog box will display that Jane Smith is over her credit limit.

Script Name Credit_Limit_Test

call Credit_Limit_Warning, 10000, "Jane Smith";

PROGRAMMER’S GUIDE VOLUME 2 191


PA RT 5 A D V A N C E D S C R I P T I N G

Out parameters
Out parameters are used to pass values back to the calling script from
the called script. The called script sets the value of the out parameter. The
calling script can only reference the out parameter; it can’t change
the parameter’s value. The following example shows how to use an out
parameter in a procedure.

Example 2
The following is a procedure that returns a string indicating the discount
percentage to apply, based upon the purchase amount:

Procedure Name Discount_Percent

in currency purchase_amount;
out string discount_percent;

if purchase_amount >= 5000 then


discount_percent = "30%";
elseif purchase_amount >= 2500 then
discount_percent = "20%";
elseif purchase_amount >= 1000 then
discount_percent = "10%";
else
discount_percent = "0%";
end if;

The following script uses the Discount_Percent procedure. The Purchase


Amount field (with the value $4725) and the local string variable l_discount
are passed to the procedure. The value returned to l_discount is 20%.

Script Name Calculate_Purchase

local string l_discount;

call Discount_Percent, 'Purchase Amount', l_discount;

192 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

Inout parameters
Inout parameters allow values to be passed from the calling script to the
called script, and then passed back to the calling script. Both the calling and
the called script can reference and alter the value of an inout parameter. The
following examples shows how to use an inout parameter in a procedure.

Example 3
The following procedure receives a purchase amount through an inout
parameter, modifies the value based upon the amount of the purchase, and
returns the value to the calling script.

Procedure Name Apply_Discount

inout currency purchase_amount;

if purchase_amount >= 5000 then


purchase_amount = purchase_amount * 7 / 10;
elseif purchase_amount >= 2500 then
purchase_amount = purchase_amount * 8 / 10;
elseif purchase_amount >= 1000 then
purchase_amount = purchase_amount * 9 / 10;
else
purchase_amount = purchase_amount;
end if;

The following script uses the Apply_Discount procedure. The Purchase


Amount field (with the value $4725) is passed to the procedure. The value
returned to the field is $3780.

Script Name Calculate_Purchase

call Apply_Discount, 'Purchase Amount';

PROGRAMMER’S GUIDE VOLUME 2 193


PA RT 5 A D V A N C E D S C R I P T I N G

Optional parameters
To make a parameter optional, simply include the optional keyword when
the parameter is declared. The following is a declaration of an optional in
parameter.
optional in string item_description;

We recommend that optional parameters appear only at the end of the


parameter list. For example, the following parameter list is not in
the perferred format, because the optional parameters are not at the end
of the list.
in string item_ID;
optional in string item_description;
optional in integer category;
out boolean order_status;

If you declare an optional in parameter, you can specify the default value to
use if the calling script doesn’t supply a value. For example, the following
parameter declaration specifies that the initial_quantity parameter will
have the value 1, unless the user supplies another value.
optional in integer initial_quantity = 1;

You can use the missing() function to find out whether optional in, inout or
out parameters contain values.

Example 4
This example checks whether the optional description parameter is
supplied. If the value is supplied, the value is displayed in the Description
field. Otherwise, the value “None” is displayed.
in string item_name;
optional in string description;

'Item Name' of window Item_Maintenance of form Item_Maintenance =


➥ item_name;
if not missing(description) then
'Description' of window Item_Maintenance of form Item_Maintenance
➥ = description;
else
'Description' of window Item_Maintenance of form Item_Maintenance
➥ = "None";
end if;

194 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

When you call a procedure that has several optional parameters, you may
not want to supply values to all of them. Use a set of double commas to
indicate that no value is supplied to an optional parameter. For example,
the second and third parameters of the Calculate_Taxes procedure are
optional. The following call to the procedure doesn’t supply a value to the
second parameter.

call Calculate_Taxes, 'Total Amount',, 'Tax Rate';

If you aren’t supplying values to optional parameters that appear at the end
of the parameter list, you can simply omit the parameters. For example, the
following call to the Calculate_Taxes procedure doesn’t supply a value to
the third (last) parameter, so the parameter is omitted.

call Calculate_Taxes, 'Total Amount', 'Sublet Labor';

Passing parameters to other procedures


All parameters are passed by reference. This means that when an item is
passed as a parameter, a reference to the item is passed, not a copy of the
item’s value. This has implications if you alter the value of the item that has
been passed as a parameter. For example, if you pass a window field as an
in parameter to a procedure and then alter the field’s value directly in the
window, the value of the in parameter in the procedure will have changed.

When a value is passed into a procedure, you may want to pass the
parameter in a call to another procedure. There are restrictions on the type
of parameters that you can pass to other procedures. The following is a list
of the types of parameter passing that are allowed.

• If a value is passed into a procedure as an in parameter, you can pass it


to another procedure only as an in parameter.

• If a value is passed into a procedure as an out parameter, you can pass it


to another procedure only as an out parameter.

• If a value is passed into a procedure as an inout parameter, you can


pass it to another procedure as an in, out or inout parameter.

PROGRAMMER’S GUIDE VOLUME 2 195


PA RT 5 A D V A N C E D S C R I P T I N G

These cases are summarized in the following illustration.

in in

Procedure A Procedure B

out out

Procedure A Procedure B

in, out, or
inout inout

Procedure A Procedure B

Using global fields as parameter types


In addition to the standard storage types, you can also use existing global
field definitions in a dictionary when declaring parameter types. This
second method is used when passing items such as composites to a
procedure. The following example shows how a global field is used to
specify parameter types.

196 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

Example 5
This example procedure uses two composites as in parameters. The
composite parameter type is based upon a composite global field, Account
Number, defined for the application. The procedure is passed two
composites as in parameters and returns a string value indicating whether
the first is equal to the second.

Procedure Name Compare_Accounts

in 'Account Number' Account1;


in 'Account Number' Account2;
out string result;

if Account1 = Account2 then


result = "equal to";
else
result = "not equal to";
end if;

Using global field definitions as parameter types has another use. The
global field definition for a window field can be used as a parameter type.
This allows you to pass a specific window field, such as a list box, to a
procedure as an inout parameter and manipulate it directly in the
procedure. For example, you can show, hide, enable, disable, lock or unlock
a field passed into the procedure in this manner.

Example 6
This procedure declares a parameter type based upon the Shipping Method
global field definition. The Shipping Method field is a list box. The
Shipping Method field is passed into the procedure, an item is added to the
list, and the list is redrawn.

Procedure Name Update_Shipping_Methods

inout 'Shipping Method' Shipping_Method_List;

add item "Federal Express" to Shipping_Method_List;


redraw field Shipping_Method_List;

The following window pre script calls the Update_Shipping_Methods


procedure, passing the Shipping Method window field to the procedure.
call Update_Shipping_Methods, field 'Shipping Method';

PROGRAMMER’S GUIDE VOLUME 2 197


PA RT 5 A D V A N C E D S C R I P T I N G

Table buffers
Each procedure has its own table buffer for each table in the application.
This allows a procedure to access any table in the application. The
procedure’s table buffers exist only as long as the procedure is running.

Using form table buffers


To use a form’s table buffer (the form where the calling script is located), the
table buffer must be passed as an inout parameter to the procedure. After
the form’s table buffer has been passed to the procedure, the procedure will
actually be using the form’s table buffer, not just a copy of the contents of
the table buffer.

Example 7
This example shows how a table buffer is passed to and used in a
procedure. The table buffer passed is the table buffer used by the form
where the calling script is located. The table buffer must be passed as an
inout parameter.

Procedure Name Balance_Warning

inout table Customer_Data;

warning 'Customer Name' of file Customer_Data + " has an unpaid


➥ balance.";

The following script calls the Balance_Warning procedure, passing the table
buffer for the Customer_Data table to the procedure. The Customer Name
field in the table buffer is used in the warning message.
call Balance_Warning, table Customer_Data;

198 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

Local anonymous tables


Refer to the SanScript In a procedure script, you have the flexibility to open a table based upon its
Reference manual for name, rather than by passing the table buffer into the script or explicitly
more information stating the table name in the script. You do this by declaring a local
about the open table anonymous table for the procedure and using the open table statement and
statement. the with name clause to open a table. Anonymous means that the name of
the table being opened isn’t known when the procedure is written. The
ability to open a table by name is useful for routines such as table
maintenance, when you want to specify which table to
perform maintenance on at runtime.

Example 8
This example counts records in a named table. A table name is passed into
the procedure as a string. A local anonymous table is declared. The table is
opened using the open table statement and the with name clause. The
procedure returns the number of records in the table as an out parameter.

Procedure Name Count_Table_Records

in string table_name;
out long record_count;

local anonymous table working_table;

{Open the table named in the table_name in parameter.}


open table working_table with name table_name;

record_count = countrecords(table working_table);

Local anonymous tables don’t allow you to have several instances of the same table
open in a procedure. They allow you only to open a table based upon a name that is
specified at runtime.

PROGRAMMER’S GUIDE VOLUME 2 199


PA RT 5 A D V A N C E D S C R I P T I N G

Form procedures
Refer to Chapter 24, Form procedures are functionally the same as standard procedures, except
“Call Stacks,”, for they’re associated with a specific form. Form procedures can be used to
information about why group procedures that perform tasks associated with a specific form. They
form procedures can also be used to take the place of scripts called with the run script
should replace scripts statement, and when additional table buffers are needed for a form. Form
called with run script. procedures use their own table buffers, not the form’s table buffers.

Creating form procedures


To create a form procedure for a specific form, open the Form Definition
window for the form. Click the Scripts tab and choose Procedures as the
type of script to display. Click New to create a new procedure or select an
existing procedure and click Open. The script editor will appear, allowing
you to edit the procedure script.

Calling form procedures


Form procedures are called like standard procedures, except that the of
form form_name clause must be included in the call statement.

Example 9
The following statement calls the form procedure Delete_Customer_Record
attached to the Customer_Maintenance form.
call Delete_Customer_Record of form Customer_Maintenance;

Anonymous tables and fields


To make procedures more generic, and thus more useful, you can use
anonymous tables and fields as parameters. Anonymous means that the
names of the tables or fields that will be passed to the procedure aren’t
known when the procedure is written. Once the anonymous tables and
fields have been passed to the procedures, they can be used in the
procedure like ordinary tables and fields.

Limited error checking is performed when you’re using anonymous tables


and fields. A procedure relies on the passed parameters to be correct at
runtime. If non-existent table fields are referenced by the procedure, a null
field address error will result. If fields with incompatible storage types are
passed to the procedure, type incompatibility messages will result.

Two configurations are commonly used: an anonymous table with known


fields, and an anonymous table with anonymous fields.

200 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

Anonymous table with known fields


In this case, the name of the table to be passed to the procedure is not
known, but the names of the fields in the table are known. The table name is
passed in by the calling script as an anonymous parameter, while the fields
are referred to explicitly by name in the procedure. The basic syntax is
shown in the following illustration.

Anonymous table
parameter in the in anonymous table source_table;
procedure.

Passing the table to call procedure_name, table table_name;


the procedure.

Example 10
The following procedure builds a master mailing list from several different
tables with known fields. The procedure has an anonymous table as an
inout parameter. All of the tables that will be passed to the procedure must
have fields with names Name, Address, City, State, and ZIP Code. Note that
in the procedure, the table is referenced using the name declared by the
inout parameter line at the top of the script. The procedure takes the fields
from the anonymous table and writes them to the Mailing_List table.

Procedure Name Add_to_Mailing_List

inout anonymous table source_table;

get first table source_table;


while err() <> EOF do
Name of table Mailing_List = Name of table source_table;
Address of table Mailing_List = Address of table source_table;
City of table Mailing_List = City of table source_table;
State of table Mailing_List = State of table source_table;
'ZIP Code' of table Mailing_List = 'ZIP Code' of table
➥ source_table;
save table Mailing_List;
get next table source_table;
end while;

Example 12 shows how this procedure is called and the anonymous table
parameter is passed to the procedure.

PROGRAMMER’S GUIDE VOLUME 2 201


PA RT 5 A D V A N C E D S C R I P T I N G

Anonymous table with anonymous fields


In this case, neither the name of the table nor the names of the fields in the
table are known. Both the table and fields are passed into the procedure as
anonymous parameters. The basic syntax is shown in the following
illustration.

in anonymous table source_table;


in anonymous field table_field_1;
Anonymous table and
field parameters in the in anonymous field table_field_2;
procedure.
in anonymous field table_field_n;

Passing the table


call script_name, table table_name, field field_1,
buffer and fields to the
➥ field field_2, ... field field_n;
procedure.

You can use the datatype() function to find out the data type associated with an
anonymous field.

Example 11
The following procedure builds a master mailing list from records in an
invoice table. The procedure has an anonymous table as an inout parameter
and anonymous fields as in parameters. The tables that will be passed to the
procedure will have address information but won’t necessarily have fields
named Name, Address, City, State and ZIP Code. Note that in the
procedure, the table and fields are referenced using the names declared by
the parameter lines at the top of the script. The procedure uses the
anonymous fields from the anonymous table to build the mailing list.

Procedure Name Add_from_Invoice


Script:

inout anonymous table source_table;


in anonymous field Name_Field;
in anonymous field Address_Field;
in anonymous field City_Field;
in anonymous field State_Field;
in anonymous field ZIP_Field;

202 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

get first table source_table;


if err() <> EOF then
while err() <> EOF do
Name of table Mailing_List = Name_Field of table source_table;
Address of table Mailing_List = Address_Field of table
➥ source_table;
City of table Mailing_List = City_Field of table source_table;
State of table Mailing_List = State_Field of table
➥ source_table;
'ZIP Code' of table Mailing_List = ZIP_Field of table
➥ source_table;
save table Mailing_List;
get next table source_table;
end while;
end if;

Example 12
The following script uses the procedures in the previous two examples to
build the Mailing_List table. The first two lines delete the existing
Mailing_List table. Addresses are then added from the Customer_List table
by passing it to the Add_to_Mailing_List procedure.

Next, addresses are added from the Invoice_Data table by passing the table
and its corresponding fields as anonymous parameters to the
Add_From_Invoice procedure. Note how fields from the Invoice_Data table
correspond to fields in the Add_From_Invoice procedure. For example, the
Customer Name field in the Invoice_Data table corresponds to the
Name_Field in the Add_From_Invoice procedure.

Script Name Build_Mailing_List


Script:

{Delete the existing Mailing_List table.}


open table Mailing_List, exclusive;
delete table Mailing_List;

{Add addresses from the Customer_List table. This is an anonymous


table with known fields.}
call Add_to_Mailing_List, table Customer_List;

{Add addresses from the Invoice_Data file. This is an anonymous table


with anonymous fields. Note how the fields from the Invoice_Data table
are passed to the corresponding fields in the procedure.}
call Add_From_Invoice, table Invoice_Data, field 'Customer Name',
➥ field 'Customer Address', field City, field State, field 'Zip Code';

PROGRAMMER’S GUIDE VOLUME 2 203


PA RT 5 A D V A N C E D S C R I P T I N G

Background and remote processing


In addition to running immediately, procedures can be run in the
background or remotely on a process server.

When creating procedures to run in the background or remotely, be careful not to


reference forms and windows that may not be open when the procedure is actually
run.

Background procedures
Background processing allows a procedure to run while other processing is
occurring, such as opening windows, printing reports and so on. To run a
procedure in the background, include the background keyword in the call
statement. This will add the procedure to a processing queue that will
process it when time is available.

If a procedure is called in the background, any additional procedure or


function calls made from the initial procedure will run in the background.
The background parameter doesn’t have to be specified in such subsequent
calls.

Temporary tables can’t be passed to a procedure running in the background


because the temporary tables may no longer exist when the procedure is
processed. If a temporary table is necessary, it should be created within the
procedure.

You can monitor the progress of background procedures by choosing the


Process Monitor menu item. Background procedures must be completed
before you exit Dexterity. If you attempt to exit Dexterity when a
background procedure is running, a message will alert you that
background processes are still running. For this reason, procedures that run
indefinitely should not be run in the background.

Remote procedures
Refer to Chapter 12, You can also process procedures remotely by sending them to process
“Process Server,” in the servers. To send a procedure to a process server, you must set up a process
Dexterity Stand-alone group and include the remote keyword in the call to the procedure. Process
Application Guide for groups are described in the next section.
more information
about using a process Only procedures meeting certain criteria can be sent to a process server. For
server. instance, the procedure can’t generate any dialog boxes or messages since
no users will be at the server to respond to the message.

204 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

Process groups
Process groups allow you to define a set of procedures that must be
completed in a designated order, without interruption from another
process. This allows a group of related procedures, such as those used to
post transactions, to be processed or deleted as a single group. To set up a
process group, use the begingroup and endgroup statements. These
statements define the beginning and ending points of a process group. The
basic syntax for a process group is shown below:

begingroup group_name assign to group_ID;


call {background|remote} Procedure_2 {, parameter_list};
call {background|remote} Procedure_3 {, parameter_list};
call {background|remote} Procedure_4 {, parameter_list};
endgroup group_ID;

In this example, the procedures Procedure_2, Procedure_3 and Procedure_4


will be processed as a single item in the process queue. Individual
procedures and process groups sent to this queue will then be completed in
the order in which they’re sent to the queue:

Process Queue

1 Procedure_1 Procedure

Procedure_2
Order of 2 Procedure_3 Process Group
completion Procedure_4
3 Procedure_5 Procedure
Procedure_6
4 Process Group
Procedure_7

To view items in the process queue at a workstation, display the Process


Monitor window by choosing the Process Monitor menu item.

PROGRAMMER’S GUIDE VOLUME 2 205


PA RT 5 A D V A N C E D S C R I P T I N G

For example, if the group_name for the process group of Procedure_2,


Procedure_3 and Procedure_4 is “Item Posting,” and the group_name for
Procedure_6 and Procedure_7 is “Item Table Maintenance,” the process
queue example would appear like the following illustration:

A procedure not explicitly


placed in a process group
is automatically placed in
its own process group.
The number in
parentheses represents
the number of procedures
in the process group.

Background and remote process groups


For detailed examples Process groups can be set up for either background processing or remote
of setting up processing.
background and
remote processes with • Background processes are completed at the client workstation’s process
process groups, refer queue and are designated by using the call background statement for
to the explanation of each procedure when you define the process group.
the begingroup
statement in the • Remote processes are sent to a workstation running the Process Server
SanScript Reference and are called using the call remote statement for each procedure when
manual. you define the process group.

Process group guidelines


The following general guidelines apply when using process groups with
remote and background procedures.

• Once in a process group, all procedures in the process group are treated
as a single unit. Actions made to the group, such as moving, deleting
and so on, affect all procedures in the group.

• If a procedure in a process group calls a procedure and includes the


background keyword, the procedure called is placed at the end of the
process group in the process queue. The procedure called in the back-
ground must then run to completion before the process group is consid-
ered completed.

206 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 0 P R O C ED U R E S

• If a procedure in a process group calls a procedure but doesn’t include


the background keyword, the called procedure will be processed
immediately in the background. It must run to completion before pro-
cessing of the other procedures in the process group will continue.

• Prior to being executed, a process group can be deleted only if the


deletable keyword is included in the begingroup statement for the
process group. A process group marked as deletable can be deleted
from the process queue using the Remove button in the Process
Monitor window. A single procedure can be deleted from the process
queue only if it’s defined as a process group for which the deletable
keyword was included.

PROGRAMMER’S GUIDE VOLUME 2 207


208 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 21: User-defined Functions
User-defined functions User-defined functions allow you to create scripts that are used in the same
can be used for way as Dexterity’s built-in functions. You specify the parameters and return
calculated fields. Refer value for the function script, write the script, and use the function just like a
to Chapter 38, built-in function. Information about user-defined functions is divided into
“Calculated Fields,” in the following sections:
Volume 1 of the
Dexterity • Creating user-defined functions
Programmer’s Guide • Using user-defined functions
for more information. • Form functions
• Naming functions

Creating user-defined functions


To create a user-defined function, choose Functions from the Scripts menu
on the tool bar. The Functions window will appear. Select the appropriate
core for the function script. Click New to create a new function or select a
function and click Open to edit an existing function. The script editor will
appear, allowing you to write the script for the function.

The name you give the function script in the script editor is the same name that will
be used when the function is called. You don’t need to include the parentheses in the
name. We also recommend that this name not contain any spaces. If the name is
more than one word, substitute underscores (_) for spaces in the name.

The first non-comment line of the function indicates what the function will
return. It has the following format:

function returns type variable;

For more information The type parameter indicates the type of value returned by the function.
about using global Typically, this is one of the seven standard storage types: boolean, currency,
field definitions as date, integer, long, string or time. You can also use existing global field
parameter types, refer definitions in your application dictionary to specify the return value type.
to Example 5 in This is useful if you want to return something such as composite from the
Chapter 20, function.
“Procedures.”

PROGRAMMER’S GUIDE VOLUME 2 209


PA RT 5 A D V A N C E D S C R I P T I N G

The variable parameter indicates the variable that returns the value from the
function. This value is returned automatically when the function script
finishes. If you don’t specifically set the value of the return variable, it will
be returned with the “empty” value for that type. (For example, an integer
return value that didn’t have its value set would be returned as 0.)

If you don’t want the function to return any value at all, use the keyword
nothing to indicate that the function doesn’t return a value. The first line of
the function would be:

function returns nothing;

Refer to Chapter 20, The parameters for the function follow the first line. The parameters are
“Procedures,” for optional; you can create a function that doesn’t use any parameters. Any
information about parameters for the function are declared and operate the same way that
procedure scripts. parameters do for procedures. With the exception of the return value, a
function script has the same characteristics as a procedure, such as access to
all tables in the application dictionary.

Using user-defined functions


User-defined functions are used in scripts the same way built-in functions
such as mktime() are. Simply use the function in your script, using the
script name you entered in the script editor as the function name and
passing the appropriate parameters. The following examples show how
user-defined functions are created and used.

Example 1
The following example shows a function script that is used to generate
random numbers between 0 and 1. The function requires that a long integer
field named seed be defined as a system variable. The following constants
have also been defined using the Constant Definition window:

MODULUS = 2147483647
MULTIPLIER = 16807
QUOTIENT = 127773
REMAINDER = 2836

No parameters are required for the function.

210 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 1 U S ER - D E F I N E D F U N C TI O N S

The following script, named random, defines the random() function.

function returns currency random_number;

local long temp, low, hi, test;

{Keep the current seed. This will be used to get the next random
number in the stream.}
temp = seed of globals;
{Generate the next seed.}
hi = seed of globals / QUOTIENT;
low = seed of globals % QUOTIENT;
test = (MULTIPLIER * low) - (REMAINDER * hi);
if test > 0 then
seed of globals = test;
else
seed of globals = test + MODULUS;
end if;
random_number = temp * (1.0) / MODULUS;

This script uses the random() function.

local currency result;

seed of globals = 1;
result = random();

Example 2
This example shows a function script named Time_AddSeconds that is
used to add seconds to a time value. The Time_AddSeconds() function
takes a time value and an integer as parameters, and returns a time value.

function returns time result_time;


in time original_time;
in integer add_amount;

local integer t_hour, t_minute, t_second;

if add_amount < 0 or add_amount > 59 then


error "Add amount isn't in the valid range. It must be between 0
➥ and 59";
else
{Get the hours, minutes and seconds from the original_time.}
t_hour = hour(original_time);

PROGRAMMER’S GUIDE VOLUME 2 211


PA RT 5 A D V A N C E D S C R I P T I N G

t_minute = minute(original_time);
t_second = second(original_time);
{Add the seconds to the time.}
if t_second + add_amount > 59 then
t_second = (t_second + add_amount) % 60;
{Need to increment the minutes.}
if t_minute + 1 > 59 then
t_minute = (t_minute + 1) % 60;
{Need to increment the hours.}
if t_hour + 1 > 23 then
t_hour = 0;
else
t_hour = t_hour + 1;
end if;
else
t_minute = t_minute + 1;
end if;
else
t_second = t_second + add_amount;
end if;
result_time = mktime(t_hour, t_minute, t_second);
end if;

The following script uses the Time_AddSeconds() function to add 30


seconds to the current system time.

local time future_time;

future_time = Time_AddSeconds(systime(), 30);

212 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A PT E R 2 1 U S ER - D E F I N E D F U N C TI O N S

Form functions
Form functions operate like global user-defined functions, except they are
associated with a specific form. Form functions are used to provide
functionality that is specific to a form. Form functions use their own table
buffers, not the form’s table buffers.

Creating form functions


To create a form function for a specific form, open the Form Definition
window for the form. Click the Scripts tab and choose Functions as the type
of script to display. Click New to create a new function or select an existing
function and click Open. The script editor will appear, allowing you to edit
the function script.

Calling form functions


To call a form function from a script that is part of the same form, simply
use the function in the script. If you’re calling a form function from a script
that isn’t part of the form, you must qualify the function by including the
form name immediately after the function. For example, the
CalculateMonthlyPayment() function is part of the Calculate_Payments
form. To use this function in a script that isn’t part of the
Calculate_Payments form, you must qualify the function with the form
name:

payment = CalculateMonthlyPayment(price, interest) of form


➥ Calculate_Payments;

Naming functions
We recommend that you preface the name of your functions with an
identifier indicating the developer who defined the function. For example,
if your company is Sophisticated Software Incorporated, use some
identifier such as SSI, at the beginning of your function names. This will
help avoid confusing your functions with sanScript functions and functions
from the Dexterity function libraries.

The names of user-defined functions that are used in calculated fields on


reports must start with the letters RW. User-defined functions whose names
start with these two letters will be the only ones available for use in
calculated fields.

PROGRAMMER’S GUIDE VOLUME 2 213


214 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 22: Dynamic Link Libraries
Dynamic Link Libraries (DLLs) are executable files that enable Windows-
based applications to share code and other resources. These “libraries” of
code contain function calls that can be used and shared by several
applications at once. Information about DLLs is divided into the following
sections:

• Dexterity and DLLs


• Using a DLL with Dexterity
• Setting up the procedure for the DLL
• Calling the DLL
• Paths for accessing DLLs

Dexterity and DLLs


You can use DLLs with Dexterity applications to perform tasks that extend
the capability of the Dexterity development system. They can provide
capabilities such as performing special calculations or allowing Dexterity
applications to communicate with peripheral hardware. For example, if you
were using Dexterity to write a point-of-sale application, you would
probably need to communicate with a cash register. Because Dexterity
doesn’t provide this capability, you could use a DLL to add this
functionality.

Using a DLL with Dexterity


Dexterity applications running can call 32-bit DLLs. 16-bit DLLs cannot be
used. Dexterity has its own DLL, XDLL32.DLL, that provides support for
calling external 32-bit DLLs. This is shown in the following illustration.

PROGRAMMER’S GUIDE VOLUME 2 215


PA RT 5 A D V A N C E D S C R I P T I N G

Before you can use a DLL in your application, you must create a procedure
that will be used to pass parameters to the DLL. This procedure is used only
to specify the type of parameters that are required for the DLL to run
properly when called from another script. The procedure isn’t called in the
typical manner using the call statement; the extern statement is used
instead. The extern statement calls the procedure, using the DLL name and
passing the actual parameters you want to use with the DLL. No statements
in the procedure are executed because the procedure doesn’t actually run.

Setting up the procedure for the DLL


To set up the procedure for the DLL, follow these steps.

1. Name the procedure.


The name of the procedure must have the following form:

functionname@dllname.dll

The functionname is the name of the function in the DLL being called
and dllname.dll is the name of the DLL the function is part of.

2. In the procedure, create the parameters to be used with the


DLL.
The first parameter of the procedure is declared as an out parameter to
handle the return value from the function in the DLL. If the return
value from the DLL is declared as VOID, then the first parameter of the
procedure should be an out parameter of type long.

You can then specify up to 254 additional parameters to pass to or


return from the DLL. Depending upon the DLL’s parameters, you may
need to specify several in parameters to pass to the DLL or out
parameters to accept values returned from the DLL. All strings passed
from Dexterity to the DLL are converted to C-strings. All strings
returned to Dexterity from the DLL are converted to sanScript strings
(P-strings).

216 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 2 D Y N A M I C L IN K L I B R A R I E S

The following example is the procedure for the MessageBoxA function in


USER32.DLL. This function creates and displays a message dialog. The
procedure has the name MessageBoxA@user32.dll. It is set up with the
appropriate in and out parameters for the DLL:

Script Name: MessageBoxA@user32.dll

out long return_value; {The return value from the function.}


in long window_handle; {The handle for the parent window.}
in string text_string; {The text to display.}
in string title_string; {The title of the window.}
in integer style; {The style for the dialog.}

Calling the DLL


To call the DLL from a script, such as a push button change script, call the
procedure script for the DLL using the extern statement. The syntax for the
statement is:

extern procedure, return_value {, parameter list};

Remember that the procedure name must include the name of the function
within the DLL, followed by the @ symbol and the name of the DLL to be
called. In order for the @ symbol to compile properly, the entire procedure
name must be enclosed in single quotation marks. The extern statement
also requires a return_value and a parameter list to handle the parameters
sent to and the values returned from the DLL.

When the DLL is called using the extern statement, it is loaded into
memory. Immediately after the DLL call is complete, Dexterity unloads the
DLL from memory. If the DLL must remain in memory, use the
Utility_LoadDLL() function to load the DLL into memory. When you have
finished calling the DLL, use the Utility_UnloadDLL() function to remove
the DLL from memory.

PROGRAMMER’S GUIDE VOLUME 2 217


PA RT 5 A D V A N C E D S C R I P T I N G

The following example is the script that displays a message using the DLL
and procedure set up on the previous example. Notice that the name of the
procedure script appears in single quotes, otherwise the script won’t
compile properly.

local long return_value;


local string text_string = "This is a DLL test.";
local string title_string = "DLL Test";
local integer style = 0; {Only an OK button is displayed.}
local long window_handle = 0;{No parent window, so handle is 0.}

extern 'MessageBoxA@user32.dll', return_value, window_handle,


➥ text_string, title_string, style;

This is the dialog


produced by the
call to the DLL.

Paths for accessing DLLs


The following is the search order used for locating 32-bit DLLs:

• The directory from which the application loaded.


• The 32-bit Windows system directory. The name of this directory is
SYSTEM32.
• The 16-bit Windows system directory. The name of this directory is
SYSTEM.
• The Windows directory.
• The current directory.
• The directories listed in the PATH environment variable.

We recommend that you place any external DLLs you use in the same directory as
Dexterity or the runtime engine.

218 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 23: Controlling the Compiler
You can use special syntax in your scripts to control the sanScript compiler.
Dexterity has a script preprocessor that allows you to selectively compile
portions of scripts. Selective compiling is useful when you have code that is
used for one version of your application, but not for other versions.

You can also use pragmas in your scripts. Pragmas are special instructions
that the sanScript compiler uses to control how it compiles scripts. For
example, you can control how the compiler responds to potential code
problems such as possible infinite loops.

Information about the controlling the compiler is divided into the following
sections:

• Script preprocessor
• Script preprocessor examples
• Pragmas
• Pragma reference

Script preprocessor
You use the script editor to add preprocessor directives to your scripts.
Preprocessor directives are commands used by the script preprocessor to
determine which portions of a script to compile. All preprocessor directives
start with a pound sign (#) in the first column of the script editor and end
with a carriage return. They do not end with a period. The preprocessor
directives for selective compiling have a structure much like the if
then...end if statement. The structure is shown in the following illustration.

The pound sign (#) must #if expression


appear in the left-most statements
column in the script editor. #elseif expression
statements
#else
statements
#endif

PROGRAMMER’S GUIDE VOLUME 2 219


PA RT 5 A D V A N C E D S C R I P T I N G

Like the if then...end if statement, the #if and #end if clauses are required.
You can include one or more of the optional #elseif clauses. The #else
clause is also optional, but only one can be included.

Refer to Chapter 21, You can use literal values and constants when writing the expressions. Any
“Constants,” in Volume constants you reference must have been defined in the dictionary using the
1 of the Dexterity Constant Definition window.
Programmer’s Guide
for more information The expression clause can be a boolean expression that evaluates to true or
about defining false. It could also be an integer expression for which any non-zero value is
constants. considered true and zero is considered false. The script statements
following the first expression to be evaluated as true will be compiled.

Script preprocessor examples


This section describes two ways the script preprocessor can be used during
application development.

Example 1
Refer to Chapter 4, This example describes how the script preprocessor can be used to
“Script Utilities,” in the selectively compile code for the SQL and non-SQL versions of an
Dexterity Utilities application. A constant named SQL has been added to the dictionary using
manual for information the Constant Definition window. If this constant is set to the value 0 and
about compiling all of scripts are recompiled, the non-SQL code is used. If the constant is set to 1
the scripts in your and scripts are recompiled, the SQL code is used. In this example, a
application. standard Pathname Setup form is opened when the non-SQL code is used.
When the SQL code is used, a SQL version of the Pathname Setup form is
opened.

#if SQL = 0
open form Pathname_Setup;
#else
open form SQL_Pathname_Setup;
#end if

220 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 3 C O N T R O L L I N G TH E C O M PI L E R

Example 2
This example describes how the script preprocessor can be used to
selectively include debugging code in a special “debug” build of an
application. A constant named DEBUG has been added to the dictionary. If
this constant is set to 0 and scripts are recompiled, the debug code isn’t
compiled. If the DEBUG constant is set to 1 and scripts are recompiled, the
debug code is compiled. In this example, the debug code displays any error
that occurred as a result of the change statement.

{Set the value of the key field in the table buffer.}


'Seller ID' of table Seller_Data = 'Seller ID' of window 'Sellers';
{Release the lock on any record currently in the table buffer.}
release table Seller_Data;
{Attempt to retrieve the record from the table.}
change table 'Seller_Data' by Seller_Data_By_ID;

#if DEBUG
{Display the number of any table error that occurred.}
if err() <> OKAY then
warning "Debug: Table error " + str(err()) +
➥ " on change operation in Seller ID script.";
end if;
#end if

if err() = OKAY then


{Record was successfully read. Copy the information to the
window.}
copy from table 'Seller_Data';
{Enable the Delete button and clear the window change flag.}
clear changes form Sellers;
enable '(L) Delete Button';
end if;

{Lock the Seller ID field.}


lock 'Seller ID';

Using the script preprocessor to include or exclude debugging code has two
advantages. First, you have more control over what operations the
debugging code performs. This is more flexible than the debug statement,
which only displays messages in test mode. Second, when you choose not
to include debug code, it’s not compiled. This means it doesn’t use
additional space in the dictionary or increase a script’s execution time.

PROGRAMMER’S GUIDE VOLUME 2 221


PA RT 5 A D V A N C E D S C R I P T I N G

Pragmas
You can add pragmas to your scripts to control the sanScript compiler. All
pragmas begin with the keyword pragma() and use additional arguments
to specify the instruction to give to the compiler. For example, you can
specify how the compiler handles certain syntax issues, such as warnings
for literal strings.

The following script contains a literal string. When you compile this script,
a warning will be generated.

local string error_string;

error_string = "This is an invalid user name.";

You can use a pragma to disable the warning generated for this script. The
following script contains the pragma to disable the warning.

local string error_string;

{Turn off the warning for literal strings}


pragma(disable warning LiteralStringUsed);

error_string = "This is an invalid user name.";

{Turn the literal string warning back on}


pragma(enable warning LiteralStringUsed);

When using a pragma to turn off a compiler warning, usually you need to
re-enable the warning before the end of the script. If you don’t, you will
generate another compiler warning indicating the situation.

Pragma reference
The following is a list of the pragmas available to control warnings
generated by the sanScript compiler. Each warning can be disabled by the
following code:
pragma(disable warning constant);

The warning is re-enabled by the following code:


pragma(enable warning constant);

222 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 3 C O N T R O L L I N G TH E C O M PI L E R

LiteralStringUsed
The LiteralStringUse pragma setting turns off the warning generated by
using literal strings in scripts. The following example shows this setting.

local string error_string;

{Turn off the warning for literal strings}


pragma(disable warning LiteralStringUsed);

error_string = "This is an invalid user name.";

{Turn the literal string warning back on}


pragma(enable warning LiteralStringUsed);

PossibleInfiniteLoop
The PossibleInfiniteLoop pragma setting turns off the warning generated
when a possible infinite loop is detected.The following example shows this
setting.

pragma(disable warning PossibleInfiniteLoop);


while true do

if 'Result' = true then


exit while;
end if;

end while;
pragma(enable warning PossibleInfiniteLoop);

TypeMismatch
The TypeMismatch pragma setting turns off the warning generated when a
possible loss of data is detected when performing assignments. The
following example shows this setting.

local integer int_val;


local long long_val;

pragma(disable warning TypeMismatch);

int_val = long_val;

pragma(enable warning TypeMismatch);

PROGRAMMER’S GUIDE VOLUME 2 223


PA RT 5 A D V A N C E D S C R I P T I N G

UnusedVariable
The UnusedVariable pragma setting turns off the warning generated when
an unused variable or parameter is detected.The following example shows
this setting.

local integer unused;

pragma(disable warning UnusedVariable);

The UnusedVariable setting should not be enabled again before the end of the script.
It will apply only to the current script.

NoExecutableCode
The NoExecutableCode pragma setting turns off the warning generated
when a script with no executable code is detected. For the best runtime
performance, scripts without any executable code should be removed from
the application. However, there are special cases (such as trigger points)
that are appropriate to have non-executing code. Use the
NoExecutableCode pragma to suppress the compiler warning in these
cases. The following example shows this setting.

{This script contains only a comment, and no executable code.}

pragma(disable warning NoExecutableCode);

The NoExecutableCode setting should not be enabled again before the end of the
script. It will apply only to the current script.

224 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 24: Call Stacks
A call stack is an internal Dexterity mechanism that manages the processing
of scripts. Dexterity has eight call stacks; seven are used for foreground
processing while the other is used for background processing. When the
scripts on a particular call stack have finished processing, the call stack is
available to be used again.

One call stack is used for


background processing.
Seven are used for
foreground processing.
BG 1 2 3 4 5 6 7

Information about call stacks is divided into the following sections:

• Call stack usage


• Managing call stacks

Call stack usage


The script type and how the script is called indicate how the script will be
processed. Foreground processes, background processes and special
processes from within Dexterity have different impacts on call stacks.

Foreground processes
An attached script is one that is attached to an object such as a form,
window or field. When an attached script is run, it uses one of the
foreground call stacks. Any procedures or functions called from the
attached script, and any subsequent calls from those procedures or
functions, are processed on the current call stack. For example, if a push
button change script is run, it uses a call stack. If any procedures or
functions are called by the push button change script, those scripts and any
procedures or functions they call are also processed on the same call stack.

Calls to procedures and


functions are processed
on the same call stack.
Each attached script that
runs uses one call stack.

BG 1 2 3 4 5 6 7

PROGRAMMER’S GUIDE VOLUME 2 225


PA RT 5 A D V A N C E D S C R I P T I N G

Background processes
All background processing is handled by the call stack dedicated to
background processing. Any calls to procedures or functions from a script
running in the background will also be processed by the call stack
dedicated to background processing.

Calls to procedures and


functions are also
processed on the
background call stack.
Procedures run in the
background are
processed on the
background call stack. BG 1 2 3 4 5 6 7

Special processes
Two types of special processes use foreground call stacks: procedures that
are called automatically and functions that are called from calculated fields
in reports. Procedures that are called automatically include the Pathname
procedure, Security procedure, and procedures for the process server.

A function in a calculated
field uses one call stack.

Each procedure
automatically called by
Dexterity uses one call
stack. 1 2 3 4 5 6 7
BG

226 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 4 CA LL STAC KS

Managing call stacks


Under normal circumstances, the seven foreground call stacks are adequate
for all processing needs. However, you must exercise caution when you use
the run script statement in your application. The run script statement
suspends the current script and causes a field change script (an attached
script) to be run. Like all other attached scripts, a field change script
requires its own call stack.

Whenever a run script run script


statement is executed,
another call stack is used.

BG 1 2 3 4 5 6 7

How you use the run script statement determines how many call stacks are
required. If a single script executes several run script statements, only one
additional call stack is needed. This is shown in the following example.

Script name: A

run script 'B';


run script 'C';

Script A uses run script to start scripts B and C. Only one additional call
stack is used because once script A starts script B, script A is suspended.
Script B finishes and its call stack is available to process script C.

Script A uses run script run script


to start script B. Script A
is suspended until script A B
B is complete.

BG 1 2 3 4 5 6 7
Script A continues and run script
uses run script to start
script C. Because script B A C
is complete, that call
stack is available to
process script C.
BG 1 2 3 4 5 6 7

PROGRAMMER’S GUIDE VOLUME 2 227


PA RT 5 A D V A N C E D S C R I P T I N G

If run script statements are “nested,” the likelihood of using all of the call
stacks increases. For example, if script A uses run script to start script B,
which uses run script to start script C, three call stacks are used.

Script name: A

run script 'B';

Script name: B

run script 'C';

Script A uses run script run script run script


to start script B. Script B
uses run script to start A B C
script C.

BG 1 2 3 4 5 6 7

If enough nested run script statements are executed, all available call stacks
will be used. If you then execute another nested run script statement, try to
run an attached script, print a report that contains a calculated field which
uses a function, or cause one of the automatically executed procedures to
execute (such as by opening a table which causes the Pathname procedure
to run), you will receive the message “All call stacks are in use. Can’t start
script.”

All call stacks will be run script run script run script run script run script run script
used if a script executes
a run script statement A B
which in turn executes a
run script statement,
and so on.
BG 1 2 3 4 5 6 7

If you use run script in your application, keep track of the number of call
stacks that you will be using. If other processes will require call stacks, such
as the Pathname or Security procedures, be sure to leave enough call stacks
available.

228 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 4 CA LL STAC KS

We recommend that you don’t nest run script statements more than three levels
deep. If you exceed this number, your application may run out of call stacks.

One way to reduce the number of call stacks your application uses is to
move functionality to a procedure script instead of using a field change
script started by the run script statement.

Another possibility is to use the run script delayed statement. The run
script delayed statement runs a field change script after all foreground
scripts have finished. Then the first call stack is available to process
the script that was started using the run script delayed statement. This is
shown in the following illustration.

Script A uses run script B


delayed to start script B.
Script B is not placed on run script delayed
a new call stack. Script A
continues executing. A

BG 1 2 3 4 5 6 7
After script A has finished,
script B is executed in the B
first call stack.

BG 1 2 3 4 5 6 7

PROGRAMMER’S GUIDE VOLUME 2 229


230 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 25: References
A reference points to a specific instance of a resource in the application
dictionary. References are stored in reference fields or in local variables that
have the reference storage type.

In your application, you can create a reference to a specific instance of a


resource. In sanScript, you use the reference to refer to the resource, instead
of referring to the resource directly. This can make your code more general-
purpose, because you can change the reference without affecting the
remainder of your code.

For instance, you can create a reference to a specific table buffer. Then in
your sanScript code, you can use the reference instead of accessing the table
buffer directly. This is shown in the following illustration.

The script uses the


reference to refer to the
Reference
table. It isn’t referring to
the table directly. Seller_Data

If some characteristic of the table buffer changes, such as the table name or
the table buffer location, you can simply change the reference. Your other
sanScript code will be unaffected.

Information about references is divided into the following sections:

• Creating references
• Assigning references
• Using references
• Guidelines
• Reference examples

PROGRAMMER’S GUIDE VOLUME 2 231


PA RT 5 A D V A N C E D S C R I P T I N G

Creating references
To use a reference in your application, you must first create a reference field
or variable.

Reference fields
Reference fields are like other global or local fields. The only difference is
that they use the Reference control type.

Reference fields use the


Reference control type.

In most cases, reference fields are added to windows. Reference fields don’t
display any information, so when you add them to windows, they are
always hidden. A reference field in a window can store a reference as long
as the form it is part of remains open. A reference global variable can store a
reference as long as the application is running.

Reference variables
To create a reference local variable or parameter for a script, simply specify
reference as the variable or parameter type. A reference variable can store a
reference as long as the script it is part of is running.

Assigning references
Refer to the SanScript After you have created a place to store the reference, use the assign
Reference manual for statement to establish a reference to a specific resource. The following
more information example creates a reference to the table buffer for the Seller_Data table
about the assign attached to the current form. The reference is stored in the Main Table
statement. reference field.

assign 'Main Table' of window Sellers as reference to table


➥ Seller_Data;

You will typically assign references to resources before the resources are
first accessed. For example, a reference to a table attached to a form is often
created in the form pre script. The reference would be stored by a reference
field in one of the windows for the form.

When assigning a reference to a hidden window field, be sure the SavedOnRestart


property is set to true. If it is not set to true and the form or window is restarted, the
reference field will be cleared and the reference will be lost.

232 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 5 R E F E R E N C E S

Using references
To use a reference to access a resource, you must dereference the value
contained in the reference field or variable. You do this by specifying the
type of resource contained in the reference and enclosing the reference
value in parentheses. The following example shows how to access the table
using the reference created in the previous example.

copy to table('Main Table');

Notice that the table keyword indicates the type of resource the reference
refers to. The reference field is enclosed in parentheses.

A reference must be valid when you use it to access to a resource. If it is not, results
will be unpredictable. Dexterity doesn’t check the validity of a reference. You are
responsible for keeping track of which references are valid.

Guidelines
Keep the following guidelines in mind when using references in your
application:

• Currently, you can create references to windows, window fields, table


buffers, table fields and menus.

• When a reference is assigned, the resource the reference points to must


be available. For example, you can’t create a reference to a window field
if the form containing the window isn’t open.

• When using a reference to a table, you must refer to the keys for the
table by number. You can’t use the names of the keys, because the table
isn’t known at compile time.

• If a resource is no longer available, any reference to that resource is no


longer valid. For example, if a table is closed, any reference to that spe-
cific table buffer instance is no longer valid. Reopening the resource
does not make the reference valid.

• A reference is not notified when it is no longer valid.

• When creating a reference to an array field, you must reference a single


element in the array. You can’t make a reference to the entire array.

• You can use reference fields as components of a composite fields.

• Reference fields can’t be stored in tables.

PROGRAMMER’S GUIDE VOLUME 2 233


PA RT 5 A D V A N C E D S C R I P T I N G

Reference examples
This section describes two ways references can be used in application
development.

Example 1
This example describes how to create and use a reference to a table buffer.
Main Table is a local field using the Reference control type. It has been
added as a hidden field in the Sellers window. The Main Table field will
store a reference to a table. The SavedOnRestart property is set to true to
ensure the reference value isn’t lost when the form or window is restarted.

Main Table is a local


reference field. It has
been added as a hidden
field in the Sellers
window.

The following is the form pre script for the Sellers form. It creates a
reference to the Seller_Data table and stores it in the Main Table reference
field.

assign 'Main Table' of window Sellers as reference to table


➥ Seller_Data;

The following is the script for one of the browse buttons in the Sellers
window. This script is generic, meaning that it has no knowledge of what
table it is retrieving data from. It simply retrieves the first record in the table
buffer referred to by the (L) Main Table variable. Then it copies the contents
of the table buffer to the window.

{Retrieve the first record from the referenced table and display it.}
change first table('(L) Main Table');
copy from table('(L) Main Table');

234 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 5 R E F E R E N C E S

Example 2
This example describes how to create and use a reference to a window field.
A global reference field named Status Reference has been created for the
application and defined as a global variable.

The following is the form pre script for the Main Menu form. It creates a
reference to a status field in the Toolbar window that is part of the Main
Menu form.

assign 'Status Reference' of globals as reference to field 'Status'


➥ of window Toolbar of form 'Main Menu';

Any procedures that need to display status information can use the field
indicated by the Status Reference global variable. For example, the
following statement sets the status to “Finished”.

field('Status Reference' of globals) = "Finished";

This statement has no knowledge of where it is setting status information. It


is simply sets the field referred to by the Status Reference global variable.

PROGRAMMER’S GUIDE VOLUME 2 235


236 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 26: Structured Exception Handler
Exception handling is a technique for avoiding, recovering from and
documenting errors that occur while an application is running. Exceptions
occur when illegal operations are performed or inappropriate operands are
supplied to a process. Good applications gracefully deal with exceptions. In
contrast, “fragile” applications stop or produce erroneous results when
exceptions occur. A structured exception handler is a mechanism for
dealing with exceptions. Information about exception handling is divided
into the following sections:

• Overview
• User exceptions
• System exceptions
• Implementing an exception handler
• Exception handler examples

Functions from the Exception function library are used when implementing
an exception handler. Refer to them for additional information.

Overview
For Dexterity-based applications, exceptions are divided into two
categories. User exceptions are illegal or inappropriate situations that are
specific to a single application, such as a data value being outside of an
acceptable range. System exceptions are error situations that can occur in any
Dexterity-based application, such as a division-by-zero error or a form not
being found in a dictionary.

To implement structured exception handling in a Dexterity application, use


the try...end try statement. The try clause indicates that a series of sanScript
statements will be executed. As the statements are executed, any exception
that occurs is thrown back to the exception handler to be dealt with. The
throw statement is used to throw user exceptions. System exceptions are
thrown automatically.

The exception handler contains catch clauses to handle specific exceptions


that are thrown. An else clause can be included to handle exceptions that
aren’t specifically caught. An unhandled exception occurs when an exception
isn’t caught and there is no else clause for the try statement. When an
unhandled exception occurs, a message is automatically displayed that
describes the situation to the user.

PROGRAMMER’S GUIDE VOLUME 2 237


PA RT 5 A D V A N C E D S C R I P T I N G

The following illustration shows the basic structure of an exception handler.

try
These statements
statements
will be executed.
catch exception
The catch clauses
handle exceptions
that are thrown. catch exception

The else clause handles else


any exceptions that are
not caught. end try

User exceptions
User exceptions are illegal or inappropriate situations that are specific to a
single application. Exceptions are categorized according to a class and
subclass, which are long integer values that uniquely identify the exception.
When an inappropriate situation occurs in your application, you will use
the throw statement to generate an exception. When you throw an
exception, you supply the class and subclass that identify the exception that
occurred. You can also supply a message that describes the exception.

As an example, the following table lists some exceptions that can occur for
the Real Estate Sales Manager sample application.

Exception Class Subclass


Invalid House ID 22001 22001
Invalid Price 22001 22002
Invalid Seller ID 22002 22001
No Agent 22002 22002

To make your code more readable, you may want to create constants for each
exception class and subclass.

If your application integrates with Microsoft Dynamics GP, the values you use for
the class and subclass must be 22,000 or greater.

238 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 6 S TR U C TU R ED E X C E PT I O N H A N D L E R

System exceptions
System exceptions are error conditions that can occur in any Dexterity-
based application. Any operation that automatically displays an error
dialog to the user is considered a system exception. Common examples of
system exceptions are string overflow errors, division-by-zero errors and
database errors.

Like user exceptions, all system exceptions are identified by a class and
subclass. Both are long integer values. The classes are divided into three
categories: script exceptions, database exceptions and form exceptions. The
subclass tyically indicates the sanScript command that caused the
exception. If the sanScript command that caused the exception is not
known, another appropriate value, such as a table ID or script ID, is
provided as the subclass.

The following tables list the classes and subclasses for system exceptions.

Exception class: Script


Class constant Description
EXCEPTION_CLASS_SCRIPT_ADDRESSING A referenced item isn’t currently
accessible.
EXCEPTION_CLASS_SCRIPT_BAD_TYPE An incompatible data type was used.
EXCEPTION_CLASS_SCRIPT_DIVIDE_BY_ZERO A division by zero error occurred.
EXCEPTION_CLASS_SCRIPT_ERROR A general script error occurred.
EXCEPTION_CLASS_SCRIPT_ILLEGAL_OP An illegal operation was performed.
EXCEPTION_CLASS_SCRIPT_MEMORY Not enough memory available to
perform the operation.
EXCEPTION_CLASS_SCRIPT_MISSING A referenced item is missing from
the dictionary.
EXCEPTION_CLASS_SCRIPT_OUT_OF_RANGE A value is outside the acceptable
range.

Exception class: Object


Class constant Description
EXCEPTION_CLASS_OBJECT_EXCEPTION A COM exception occurred.

PROGRAMMER’S GUIDE VOLUME 2 239


PA RT 5 A D V A N C E D S C R I P T I N G

Exception class: Form


Class constant Description
EXCEPTION_CLASS_FORM_MEMORY There is not enough memory
available to load the form.
EXCEPTION_CLASS_FORM_MISSING The form is missing from the
dictionary.
EXCEPTION_CLASS_FORM_SECURITY Access to a form was denied by the
Security global procedure.

Exception class: Database


Class constant Description
EXCEPTION_CLASS_DB A general database error occurred.
EXCEPTION_CLASS_DB_CHG_TRAN_LVL The transaction level was changed in
a stored procedure that was called.
EXCEPTION_CLASS_DB_DEADLOCK A deadlock error occurred while in a
transaction.
EXCEPTION_CLASS_DB_TRAN_IMP_ROLLBACK A script was terminated and left a
pending transaction that was rolled
back.

Subclasses for script and form exceptions


For most operations, the subclass for a system exception indicates the
sanScript command that caused the exception. The following table lists the
constants for the common exception subclasses.

Subclass constant Command or operator


SCRIPT_CMD_ADD +
SCRIPT_CMD_SUB -
SCRIPT_CMD_MUL *
SCRIPT_CMD_DIV /
SCRIPT_CMD_MOD %
SCRIPT_CMD_NEG -
SCRIPT_CMD_POWER ^
SCRIPT_CMD_EQ =
SCRIPT_CMD_NEQ <>
SCRIPT_CMD_LT <
SCRIPT_CMD_LTEQ <=
SCRIPT_CMD_GT >
SCRIPT_CMD_GTEQ >=

240 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 6 S TR U C TU R ED E X C E PT I O N H A N D L E R

Subclass constant Command or operator


SCRIPT_CMD_NOT not
SCRIPT_CMD_AND and
SCRIPT_CMD_OR or
SCRIPT_CMD_XOR xor
SCRIPT_CMD_LSL << or shiftl
SCRIPT_CMD_LSR >> or shiftr
SCRIPT_CMD_IMP imp
SCRIPT_CMD_BITTEST bittest()
SCRIPT_CMD_BITCLEAR bitclear()
SCRIPT_CMD_BITSET bitset()
SCRIPT_CMD_ADDMONTH addmonth()
SCRIPT_CMD_ASK ask()
SCRIPT_CMD_CALL call
SCRIPT_CMD_CALLBKG call background
SCRIPT_CMD_CALLSERVER call sproc
SCRIPT_CMD_CHANGED changed()
SCRIPT_CMD_CLEARCHANGE clear changes
SCRIPT_CMD_CLOSE close
SCRIPT_CMD_COUNTRECS countrecords()
SCRIPT_CMD_DELETE delete
SCRIPT_CMD_EDIT edit
SCRIPT_CMD_EMPTY empty()
SCRIPT_CMD_ERROR error
SCRIPT_CMD_EXECUTE execute
SCRIPT_CMD_FINDITEM finditem()
SCRIPT_CMD_FIRST get first, change first
SCRIPT_CMD_FOCUS focus
SCRIPT_CMD_FORCECHNG force change
SCRIPT_CMD_FORCECHNGCLR clear force change
SCRIPT_CMD_GETSTR getstring()
SCRIPT_CMD_HEXSTRING() str()
SCRIPT_CMD_HIDE hide
SCRIPT_CMD_ISOPEN isopen()
SCRIPT_CMD_ITEMCOUNT countitems()
SCRIPT_CMD_ITEMNAME itemname()
SCRIPT_CMD_LAST get last, change last

PROGRAMMER’S GUIDE VOLUME 2 241


PA RT 5 A D V A N C E D S C R I P T I N G

Subclass constant Command or operator


SCRIPT_CMD_MAX max()
SCRIPT_CMD_MIN min()
SCRIPT_CMD_MOVEFIELD move field
SCRIPT_CMD_NATIVEFILEERROR naterr()
SCRIPT_CMD_NEXT get next, change next
SCRIPT_CMD_OPEN open
SCRIPT_CMD_OPENEX open table, exclusive
SCRIPT_CMD_PRIOR get prev, change prev
SCRIPT_CMD_RANGEEND range end
SCRIPT_CMD_RANGESTART range start
SCRIPT_CMD_REDRAW redraw
SCRIPT_CMD_RELEASE release
SCRIPT_CMD_REMOVE remove
SCRIPT_CMD_REPLACE replace()
SCRIPT_CMD_REQUIRED required()
SCRIPT_CMD_RESIZEFIELD resize field
SCRIPT_CMD_RESTARTFIELD restart field
SCRIPT_CMD_ROUND round()
SCRIPT_CMD_RNDCURRENCY
SCRIPT_CMD_RUNDELAY run script delayed
SCRIPT_CMD_RUNSCRIPT run script
SCRIPT_CMD_SETCURPRECIS set precision
SCRIPT_CMD_SETPRECISION
SCRIPT_CMD_SHOW show
SCRIPT_CMD_STRING str()
SCRIPT_CMD_THIS get, change
SCRIPT_CMD_TRUNCATE truncate()
SCRIPT_CMD_TRUNCCURRENCY
SCRIPT_CMD_UNLOCK unlock
SCRIPT_CMD_WARNING warning

242 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 6 S TR U C TU R ED E X C E PT I O N H A N D L E R

The preceding table lists the most common commands and operators that
can produce exceptions. If an unlisted command has caused an exception,
you can use the exception dialog that is displayed to find out more
information about the command that caused the exception. The exception
dialog is shown in the following illustration.

Scroll to the end of the


text to see the exception
class and subclass.

Simply scroll down to the end of the message text to see the class and
subclass of the exception that was thrown.

Subclasses for database exceptions


The subclass value that is returned for database exceptions indicates the
database error that occurred, rather than the sanScript statement that
caused the error. The following table lists the constants that correspond to
the subclass values returned for database exceptions.

DB_ERR_MEMORY DB_ERR_DISK_FULL
DB_ERR_NOT_INITIALIZED DB_ERR_UNKNOWN
DB_ERR_NOT_SUPPORTED DB_ERR_KEY_CHANGED
DB_ERR_TOO_MANY_OPEN_TABLES DB_ERR_NOT_VAR_FIELD
DB_ERR_INCORRECT_RECORD_LENGTH DB_ERR_CHANGED
DB_ERR_TOO_MANY_KEYS DB_ERR_DEADLOCKED
DB_ERR_TOO_MANY_SEGMENTS DB_ERR_PATH_NOT_FOUND
DB_ERR_TABLE_NOT_REGISTERED DB_ERR_BUFFER_MISMATCH
DB_ERR_TABLE_NOT_FOUND DB_ERR_COULD_NOT_CREATE
DB_ERR_LOCKED DB_ERR_INCORRECT_NUMBER_OF_KEYS
DB_ERR_BAD_FILENAME DB_ERR_SQL_TOO_MANY_CONNECTIONS
DB_ERR_TABLE_NOT_OPEN DB_ERR_SQL_DATA_ACCESS_ERR
DB_ERR_TABLE_NOT_EXCLUSIVE DB_ERR_SQL_DATA_CONV_ERR
DB_ERR_INVALID_CMD DB_ERR_SQL_GENERATION_ERR
DB_ERR_INVALID_KEY DB_ERR_NO_PRIMARY_KEY
DB_ERR_EOF DB_ERR_SQL_NOT_LOGGED_IN
DB_ERR_DUPLICATE DB_ERR_CANNOT_INIT_CTREE
DB_ERR_MISSING DB_ERR_CANNOT_INIT_BTRIEVE

PROGRAMMER’S GUIDE VOLUME 2 243


PA RT 5 A D V A N C E D S C R I P T I N G

DB_ERR_SET_ALREADY_ACTIVE DB_ERR_CANNOT_INIT_SQL
DB_ERR_TRANS_IN_PROGRESS DB_ERR_SQL_OBJ_NOT_FOUND
DB_ERR_NOT_VAR_LENGTH_TABLE DB_ERR_TRANS_ROLLED_BACK
DB_ERR_TABLE_NOT_DEFINED DB_ERR_SQL_CONNECTION_ERR
DB_ERR_CANNOT_LOCK_TWO_RECORDS DB_ERR_STILL_EXECUTING
DB_ERR_RECORD_NOT_LOCKED DB_ERR_SQL_CONSTRAINT_VIOLATION
DB_ERR_TABLE_DEF_MISMATCH

Implementing an exception handler


This section describes the general process of implementing an exception
handler in your application.

Location
You should implement an exception handler in places where exceptions are
likely to be generated. Common locations include:

• Scripts that perform many database operations


• Procedures or functions that use anonymous parameters
• Scripts that reference items by name, such as forms or procedures
• Scripts that validate data

When implementing an exception handler, begin by deciding which areas


of your code are likely to generate system exceptions or are candidates for
generating user exceptions.

List the exceptions


List the classes and subclasses of the exceptions you expect to occur. These
can be system exceptions or user exceptions. If you listed any user
exceptions, add throw statements to your code to generate the exceptions
for the appropriate circumstances.

Add the exception handler code


The next section Next, add the try...end try statement to your script to “surround” the code
provides examples that that can generate exceptions. Then add catch clauses to deal with the
show common ways of exception classes you listed. Within each catch clause, use functions from
handling exceptions. the Exception function library to retrieve information about the exception
that occurred. Then add code to respond to the exception.

244 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 6 S TR U C TU R ED E X C E PT I O N H A N D L E R

Typical responses to exceptions include:

• Re-executing sanScript statements


• Logging or displaying the exception
• Rethrowing the exception

Re-executing sanScript statements


In some cases, a problem can be resolved by re-executing sanScript
statements. For example, if a record can’t be read and actively locked, you
may want to re-execute your sanScript code until the record can be locked.
Use the restart script statement to restart the current script. Use the restart
try to re-execute the statements in the try...end try block.

Logging or displaying the exception


In some cases, you may simply want to log or display information about the
exception that occurred. Use the Exception_Message() function to retrieve
the message text for the exception that was thrown.

Rethrowing the exception


In some cases, particularly when using object triggers, your exception
handler may be thrown an exception that wasn’t intended for it. For
example, assume within a try...end try block in your script, you call a
Microsoft Dynamics GP procedure for which another product has a trigger
registered. If the trigger processing procedure for the other product throws
an exception that doesn’t get caught, the exception will be thrown back to
your script, the script that caused the trigger to activate. Since your script
wasn’t expecting the exception, it likely won’t be able handle it.

In this situation, use the Exception_Product() function to find out the ID of


the product that threw the exception. If the exception came from another
dictionary, and isn’t an exception you can handle, use the throw statement
to rethrow the exception. Once rethrown, the exception can be handled by
other exception handlers, if available. If no other exception handlers are
available, an unhandled exception message will be displayed.

Checking for string overflows


When an application is run using the runtime engine, any strings that
overflow (exceed the 255 character limit) are automatically truncated. No
message is displayed to the user and no exception will be thrown. For this
reason, we recommend that you don’t use exception handling to handle
string overflow situations.

PROGRAMMER’S GUIDE VOLUME 2 245


PA RT 5 A D V A N C E D S C R I P T I N G

Exception handler examples


This section provides several examples of implementing a structured
exception handler in your application.

Example 1
This procedure contains sanScript code to handle the exception that can
occur when you reference an invalid form by name. If an invalid name is
supplied to the open form with name statement, a system exception is
thrown. The exception is handled by displaying a message that explains the
situation. Notice that the predefined _script_ constant is used to include the
name of the script in the message.

in string form_name;

try
{Open the named form.}
open form with name form_name;
catch [EXCEPTION_CLASS_SCRIPT_MISSING]
{Catch the exception if the form is missing.}
error "Cannot find the form " + form_name + ". Error in script " +
➥ _script_ + ".";
end try;

Example 2
This example calls a procedure that uses anonymous parameters. It uses an
exception handler to log any parameter type incompatibilities that occur
when incorrect parameters are passed to the procedure.

local long exception_subclass;


local string exception_message;

try
call Calculate_Payment, principle, interest, term, method;
catch [EXCEPTION_CLASS_SCRIPT_BAD_TYPE]
{Get the exception subclass.}
exception_subclass = Exception_SubClass();
exception_message = Exception_Message();
call Log_Exception, "Bad Type", exception_subclass,
➥ exception_message;
error "Invalid parameters passed to Calculate_Payment.”;
end try;

246 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 6 S TR U C TU R ED E X C E PT I O N H A N D L E R

Example 3
This example shows how to handle exceptions for common database
operations. The following script attempts to read and actively lock a record
from the Seller_Data table. Note that the throw system exception for table
statement is used to throw a system exception if a database error occurred.
If the record can’t be actively locked, the script will retry 10 times before
displaying a message to the user. The restart try statement causes the
statements in the try...end try block to be executed again, but the values of
local variables are not affected.

local integer read_count = 0;

try
'Seller ID' of table Seller_Data = 'Seller ID' of window Sellers;
{Attempt to actively lock the record.}
change table Seller_Data, lock;
increment read_count;
{Check the error. If an error occurred, an exception will be
thrown.}
throw system exception for table Seller_Data;

catch [EXCEPTION_CLASS_DB]
{A standard database error occurred.}
if err() = LOCKED then
{Retry the read operation 10 times.}
if read_count < 10 then
restart try;
else
error "Unable to read and actively lock the record.";
end if;
end if;
else
{Some other exception occurred.}
error "An unknown exception occurred. Class: " +
➥ str(Exception_Class()) + " Subclass: " +
➥ str(Exception_SubClass());
end try;

PROGRAMMER’S GUIDE VOLUME 2 247


PA RT 5 A D V A N C E D S C R I P T I N G

Example 4
This example is a data verification procedure that uses throw statements to
throw user exceptions when invalid data values are encountered. Constants
have been added to the dictionary for each class and subclass of exception
that can be thrown.

Procedure Name Verify_Buyer_Record

in table Buyer_Data;

if 'Buyer Name' of table Buyer_Data = "" then


throw BUYER_DATA, NO_NAME, "Buyer ID " + 'Buyer ID' of table
➥ Buyer_Data + " has an invalid name.";
end if;

if 'Agent' of table Buyer_Data = "" then


throw BUYER_DATA, NO_AGENT, "Buyer ID " + 'Buyer ID' of table
➥ Buyer_Data + " has an invalid agent.";
end if;

if ('Maximum Price' of table Buyer_Data < 0) or ('Maximum Price'


➥ of table Buyer_Data > 1000000) then
throw BUYER_DATA, INVALID_PRICE, "Buyer ID " + 'Buyer ID' of
➥ table Buyer_Data + " has an invalid maximum price.";
end if;

The following script calls the Verify_Buyer_Record procedure. As records


are verified, any user exceptions that are thrown are handled by the
exception handler. Note that when a user exception is handled, the same
record is read again until it produces no user exceptions.

local long exception_subclass;

{Read the first record in the table, so there is a current record.}


get first table Buyer_Data;

try
{Read the current record.}
change table Buyer_Data;
while err() = OKAY do
call Verify_Buyer_Record, table Buyer_Data;
change next table Buyer_Data;
end while;

248 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 6 S TR U C TU R ED E X C E PT I O N H A N D L E R

catch [BUYER_DATA]
{Get the exception subclass}
exception_subclass = Exception_SubClass();
case exception_subclass
in [NO_NAME]
'Buyer Name' of table Buyer_Data = "Unknown";
in [NO_AGENT]
'Agent' of table Buyer_Data = "Staff";
in [INVALID_PRICE]
'Asking Price' of table Buyer_Data = 0;
end case;
{Save the repaired record.}
save table Buyer_Data;
{Check the record again}
restart try;
else
{Some other exception occurred.}
error "An unknown exception occurred. Class: " +
➥ str(Exception_Class()) + " Subclass: " +
➥ str(Exception_SubClass());
end try;

PROGRAMMER’S GUIDE VOLUME 2 249


250 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 6: ANALYSIS TOOLS
Part 6: Analysis Tools
This part describes tools included in Dexterity to debug and analyze the
performance of scripts. Following is a list of the items that are discussed,
with a brief explanation of each:

• Chapter 27, “Script Debugger,” describes the source-level script debug-


ger for Dexterity.

• Chapter 28, “Script Profiler,” explains how to use the Script Profiler to
analyze application performance.

• Chapter 29, “Script Logger,” explains how to log the scripts that are
executed as a Dexterity application is running.

• Chapter 30, “Resource Usage,” describes how to use the Reference


Information window to find out how resources and scripts are used in
an application.

252 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 27: Script Debugger
Dexterity has a source-level script debugger that you can use to debug
scripts and analyze your application. Using the debugger, you can set
breakpoints in any script, apply conditions to breakpoints, step through
scripts a line at a time, and examine and set the values of variables and
fields in the application.

Information about the script debugger is divided into the following


sections:

• The Debug menu


• The Script Debugger window
• Breakpoints
• Using the debugger
• Examining the state of the application
• Editing scripts
• Debugging runtime errors

The Debug menu


The windows accessed The script debugger is accessed from the Debug menu, which is available in
by these menu items both tools mode and test mode. The following is a list of the debugger-
are discussed in detail related items in the Debug menu.
later in this chapter.
Script Debugger
This menu item opens the Script Debugger window, allowing you to select
scripts and set breakpoints.

Calls
This menu item opens the Calls window, which displays a list of the scripts
currently being run.

Breakpoints
This menu item opens the Breakpoints window, which lists the breakpoints
that have been set in the application. This window also allows setting
options for breakpoints.

Expressions
This menu item opens the Expressions window. This window allows you to
view and alter the contents of variables and fields.

PROGRAMMER’S GUIDE VOLUME 2 253


PA RT 6 A N A L Y S I S T O O L S

Locals
This menu item opens the Locals window, which displays the values of the
variables and fields referenced in the current script.

Table Buffers
This menu item opens the Table Buffers window. The Table Buffers window
allows you to view the contents of the table buffers for the tables in the
application.

Go / Step / Step In / Step Out


These menu items are used to control execution of the application when it is
stopped at a breakpoint. These are discussed in Using the debugger on
page 260.

The Script Debugger window


The Script Debugger window, shown in the following illustration, allows
you to view and set breakpoints in scripts.

These buttons allow you


to select a script, add or
remove breakpoints, and
control the debugger.

You can set or remove


breakpoints in the script
displayed here.

To open this window, choose Script Debugger from the Debug menu. The
Script Debugger window also appears when a breakpoint is encountered
while an application is running.

254 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Debugger controls
The operations The buttons at the top of the Script Debugger window allow you to select
performed by these scripts, insert and remove breakpoints, and control the script debugger
controls are described when a breakpoint is encountered. Each button is described in the
in more detail later in following table.
this chapter.
Button Name Description
Open Script Opens the Open Script window, allowing you to select a
script to debug.

Edit Script Opens the Script Editor, allowing you to edit the script
currently displayed in the Script Debugger window.

Toggle Inserts or removes a breakpoint on the line where the


Breakpoint cursor is located. A breakpoint is indicated by a red dot at
the beginning of the line.
Go When stopped at a breakpoint, the Go button causes the
application to continue executing until all scripts finish or
another breakpoint is encountered.
Step Causes the application to execute the next line in the
current script.

Step In If the application is stopped on a line that calls a


procedure or user-defined function, or uses the run
script statement, clicking Step In causes the called script
to appear in the Script Debugger window. Execution stops
on the first line of that script.
Step Out If stopped in a procedure or user-defined function, or a
script executed with the run script statement, clicking
Step Out causes the current script to run to completion.
The calling script is displayed in the Script Debugger
window, and execution stops on the line following the line
that made the call.
Set Next If stopped at a breakpoint, clicking the Set Next Statement
Statement button makes the line where the cursor is located the next
line that will be executed. Execution will continue when
you choose Go, Step, Step In or Step Out.
Exercise caution when using this feature. It will alter the
order that statements are executed in the application and
may cause different results from when the application
runs normally.

Context menu
The Script Debugger window has a context menu that is available in test
mode. You can use the context menu to copy the selected text, add a watch
based on the selected text, toggle a breakpoint on the current line, or set the
next statement to execute.

PROGRAMMER’S GUIDE VOLUME 2 255


PA RT 6 A N A L Y S I S T O O L S

Opening scripts
To open a script to debug, click the Open Script button in the Script
Debugger window. The Open Script window will appear, as shown in the
following illustration.

1. Indicate the type of script to open.


Click the appropriate tab indicating whether you want to open a form-
level script, a procedure script, or a user-defined function.

2. Select the series or core the script is part of.


If you’re opening a form-level script, select the series the form is part of.
If you’re opening a procedure or user-defined function, select the core
the script is part of.

3. Select the appropriate options indicating the script you


want to open.
If you’re opening a procedure script or a user-defined function, simply
select the script in the Scripts list and click OK. If you’re opening a
form-level script, select the form and then use the drop-down lists and
remaining list boxes to navigate to the type of script you want to open.
When the script name appears in the Scripts list, select it and click OK.

256 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Breakpoints
Editing scripts A breakpoint is a marker you can place on a line in a script. When a
containing breakpoints breakpoint is encountered while the application is running, the application
can affect the will stop just prior to executing the line of code on which the breakpoint
breakpoints. Refer to was placed. When stopped at a breakpoint, you can examine the state of the
the section Editing application.
scripts on page 270 for
more information. Setting breakpoints
Once you’ve selected a script and it appears in the Script Debugger
window, you can set breakpoints. To set a breakpoint, place the insertion
point in the line where you want to set the breakpoint, then click the Toggle
Breakpoint button. A red dot indicates a breakpoint is set. To remove a
breakpoint, place the insertion point in the line containing the breakpoint
and click the Toggle Breakpoint button again.

To set a breakpoint, place the


insertion point in the line
where you want the
application to stop. Then click
the Toggle Breakpoint button.

The red dot indicates a


breakpoint is set.

You can’t set breakpoints on comment lines. The Script Debugger will set a
breakpoint on the next available line if you try to do so.

Breakpoints can be set in either tools mode or test mode. Moving between
tools mode and test mode doesn’t affect breakpoints. The breakpoints you
set will remain in the scripts until you specifically remove the breakpoints
or quit Dexterity.

PROGRAMMER’S GUIDE VOLUME 2 257


PA RT 6 A N A L Y S I S T O O L S

Breakpoints window
To view a list of the breakpoints you’ve set, choose Breakpoints from the
Debug menu. The Breakpoints window will appear, as shown in the
following illustration.

Mark this check


box to ignore all
breakpoints.

Each item lists the


conditional status, enable
status, dictionary, line and
script for the breakpoint.

This is a list of the


breakpoints that are set in
the application.

An asterisk in the first Use these buttons to


column indicates the enable, disable, delete or
breakpoint is conditional. set options for breakpoints.
The second column Click Debug to debug the
indicates the enable status. selected script.

You can enable, disable or delete a breakpoint by selecting it in the list and
clicking the appropriate button. The enabled status for a breakpoint is
indicated by the + or - in the second column of the breakpoints list (+ is
enabled, - is disabled). If the Ignore All Breakpoints check box is marked,
causing all breakpoints to be ignored, all enabled breakpoints will be
indicated with a small “e”, while disabled breakpoints will be indicated
with a small “d”.

You can debug the script containing a breakpoint by selecting the


breakpoint in the list and clicking Debug. To delete a breakpoint, select it
and click Delete. Click Delete All to delete all breakpoints.

258 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Breakpoint options
You can set additional options to specify when a breakpoint should halt
execution. To do so, select a breakpoint in the list and click Options. The
Breakpoint Options window will appear, as shown in the following
illustration.

This is the breakpoint for


which options are being set.

This specifies the type of


breakpoint.

These fields specify the


conditions for a conditional
breakpoint.

Use this window to specify whether the breakpoint will be conditional or


unconditional. Unconditional breakpoints always stop execution when they
are encountered, unless they have been disabled. Conditional breakpoints
stop execution only if the specified conditions are met. The following table
describes the conditions you can specify for a conditional breakpoint.

Condition Description
Break When Expression is Breakpoint is honored when the boolean sanScript
True expression entered in the field below the option is true.
Break After Nth Breakpoint is ignored until it has been encountered the
Occurrence number of times indicated. After this number of
encounters, the breakpoint is honored like a normal
breakpoint.
Break For N Occurrences Breakpoint is honored the until it has been encountered
the number of times indicated. After this number of
encounters, the breakpoint is ignored.

PROGRAMMER’S GUIDE VOLUME 2 259


PA RT 6 A N A L Y S I S T O O L S

Using the debugger


Once you’ve set breakpoints, you can run your application until a
breakpoint is encountered. Then you can use the debugger to view the state
of your application and control further execution.

Encountering a breakpoint
When a breakpoint is encountered while the application is running, the
Script Debugger window will open. The script containing the breakpoint
will be displayed, and a yellow arrow will indicate where execution
stopped. An example of this is shown in the following illustration.

This indicates the


application is stopped
at a breakpoint.

When a breakpoint is
encountered, the script
containing the breakpoint
is displayed in the Script
Debugger window.

The yellow
arrow indicates
where execution
is currently
stopped.

Execution of the application is suspended, allowing you to examine the


current state of the application. The tools available for this purpose are
explained in the next section.

Controlling execution
While the application is stopped at a breakpoint, all application operations
are suspended. You must use the Go or Step menu commands in the Debug
menu (or their corresponding buttons in the Script Debugger window) to
continue executing the application.

260 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Go
Choosing Go from the Debug menu or clicking the Go button in the Script
Debugger window causes the application to continue execution until
another breakpoint is encountered or all scripts finish.

You can’t exit test mode while stopped at a breakpoint. To exit test mode, the scripts
currently running must finish executing. Mark the Ignore All Breakpoints option
in the Breakpoints window and then click Go to allow all scripts to finish executing
without stopping at any breakpoints. Then you can exit test mode.

Step
Choosing Step from the Debug menu or clicking the Step button in the
Script Debugger window causes the next line of the current script to be
executed. The application is then suspended as if another breakpoint had
been encountered. This is useful when you want to step through an
application line-by-line to see how individual statements affect the
application.

Step In
Step In is used when the application is stopped on a line that calls a
procedure or user-defined function, or uses the run script statement.
Choosing Step In from the Debug menu or clicking the Step In button
causes the called script to appear in the Script Debugger window. Execution
stops on the first line of that script.

For example, if execution has stopped on the following line containing a


procedure call, clicking the Step In button in the Script Debugger window
causes the procedure script to open and stop execution on the first line of
the procedure.

Clicking Step In when the


application is stopped at this
call to the Progress_Control
procedure causes the Step In
Progress_Control procedure to
display in the Script Debugger.
Execution stops on the first
line of the procedure.

PROGRAMMER’S GUIDE VOLUME 2 261


PA RT 6 A N A L Y S I S T O O L S

Step Out
Step Out causes the current script to finish executing, then the script that
called the current script is displayed in the Script Debugger window.
Execution stops in the calling script on the line immediately following the
line that caused the called script to be run.

For example, a field change script uses the Calculate_Monthly_Payment


user-defined function. If execution has stopped in the script for the
Calculate_Monthly_Payment function, clicking the Step Out button will
cause the calling script (in this case, the field change script) to appear in the
Script Debugger window. Execution will stop on the line immediately
following the line containing the call to the Calculate_Monthly_Payment
function.

The field change script uses the


Calculate_Monthly_Payment
function.

Step In

If the application is stopped in the


Calculate_Monthly_Payment
function, and you click the Step
Out button, the script containing Step Out
the call is displayed. Execution
stops on the line following the
function call.

Set Next Statement


Set Next Statement makes the line where the cursor is located the next line
to be executed. Execution will continue when you click Go, Step, Step In or
Step Out. Use this to skip over statements or repeat statements in the script.

Exercise caution when using this feature. It will alter the order that statements are
executed in the application and may cause different results from when the
application runs normally.

262 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Examining the state of the application


The debugger has several windows that you can use to examine the current
state of your application. One window lists the scripts that are currently
executing. Other windows allow you to view and, if necessary, alter the
values of fields and variables.

Calls window
To display the Calls window, choose Calls from the Debug menu. This
window is shown in the following illustration.

The scripts in the current


call stack are listed here.
The Open button opens the
script debugger, displaying the
current script in the call stack.
The Unwind button causes the
next line in the script selected in
the call stack to be executed. The
scripts that appear above the
selected script will be terminated.

For more information This window displays the scripts in the current call stack and the line
about call stacks, refer number at which each script is stopped. The call stack indicates the
to Chapter 24, “Call sequence of scripts called in the application. You can debug the script
Stacks.” selected in the Call Stack by clicking Open; you can edit the script by
clicking Edit.

The Calls window contains information only when the application is stopped at a
breakpoint.

Clicking Unwind continues executing the script selected in the call stack
and terminates all scripts that appear above the selected script in the call
stack. (The scripts are terminated as though an abort script statement had
been executed.) Unwind can be useful if you know a process isn’t working
properly and there is little point in allowing the process to continue.

PROGRAMMER’S GUIDE VOLUME 2 263


PA RT 6 A N A L Y S I S T O O L S

As an example, a call stack from the Calls window is shown in the


following illustration.

If the Calculate_Monthly_Payment function is selected in the call stack,


clicking the Unwind button will cause the Progress_Control script to be
aborted. The application will continue running, beginning with next line of
the Calculate_Monthly_Payment script.

Exercise caution when using the Unwind button. It will terminate scripts without
allowing them to finish normally. This could cause problems in your application,
such as if a posting routine isn’t completed.

Locals window
The Locals window displays information about the variables, fields, and
parameters referenced by the script currently selected in the Calls window.
The Locals window is accessed by choosing Locals from the Debug menu,
and is shown in the following illustration.

These are the values of the


parameters, local
variables, global variables,
and fields referenced by
the Progress_Control
procedure script.

When you select a different script from the call stack in the Calls window,
the contents of the Locals window updates automatically.

The Locals window contains information only when the application is stopped at a
breakpoint.

264 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Expressions window
The Expressions window is accessed by choosing Expressions from the
Debug menu. The window is shown in the following illustration.

The Expression field must


be set to a valid sanScript
expression.

Click Evaluate to set the


Value field to the value of
the item referenced in the Click Set to set the item
Expression field. referenced by the
Expression field to the
value in the Value field.

This window allows you to view the value of any valid sanScript
expression. Simply type the expression in the Expression field and click
Evaluate. If the expression can be evaluated, its value will be displayed in
the Value field. Otherwise, the Value field will contain a message indicating
the expression couldn’t be evaluated.

You can also use the Expressions window to set the value of fields or
variables in the application. Enter a sanScript expression indicating the item
whose value you want to set, enter the value in the Value field, then click
Set. Dexterity will attempt to set the item referenced by the expression to
the value you entered. If the item can’t be found or the value isn’t valid, the
Expressions window will beep.

The Expressions window can be accessed any time, regardless of whether


the application is stopped at a breakpoint. If the application isn’t stopped at
a breakpoint, all expressions must be fully qualified. If the application is
stopped at a breakpoint, you can qualify the expression the same way you
would qualify expressions in the script where the application is currently
stopped.

PROGRAMMER’S GUIDE VOLUME 2 265


PA RT 6 A N A L Y S I S T O O L S

Watch window
The Watch window is accessed by choosing Watch from the Debug menu.
The window is shown in the following illustration.

Entries in the Name


column must be set
to a valid sanScript
expression.

Similar to the Expressions window, the Watch window allows you to view
the values of multiple valid sanScript expressions. Simply type the
expression in the Expression column. If the expression can be evaluated, its
value will be displayed in the Value column. Otherwise, the Value column
will contain a message indicating the expression couldn’t be evaluated.

Another way to add a watch expression is to select text in the Script Debugger
window, right-click the text, and then choose Add Watch from the context menu.

The expressions in the Watch window are saved in a c-tree table in the same
location as the dictionary being edited. This means you don’t have to re-
enter them each time you are debugging a dictionary. To remove an
expression from the Watch window, place the focus in the row and click
Remove. To remove all expressions, click Remove All.

The values of the expressions are updated when you click Refresh in the
Watch window. They are also updated in the following cases:

• When execution stops at a breakpoint


• When you step to a new line of sanScript code in the Script Debugger
• When you choose a new stack level in the Calls window

266 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

If you aren’t certain of the status of the expressions in the Watch window, click
Refresh to ensure the expressions are up-to-date.

When execution has stopped at a breakpoint, the expressions in the Watch


window are evaluated in the context of the script where execution has
stopped. For example, assume you entered the expression 'Maximum Price'
in the Watch window. This expression has no supplied context, such as a
window name and form name, so its value cannot be determined. If
execution stops in a script that is part of a window containing the
Maximum Price field, the expression would have a valid context and would
display the value of the window field 'Maximum Price'.

If you fully-qualify the expressions in the Watch window, you can avoid any issues
with context.

Some values returned from expressions in the Watch window are too
complex to display in a single line. Composite fields with multiple
segments, and text fields with multiple lines of text are a common
examples. To view these complex return values, you can use the Visualizer.
Place the focus in the line in the Watch window containing the value you
want to view, and then click Open Visualizer. The Visualizer will show the
content of the expression. For instance, the following illustration shows the
list_object composite used for a card list in Microsoft Dynamics GP.

PROGRAMMER’S GUIDE VOLUME 2 267


PA RT 6 A N A L Y S I S T O O L S

Table Buffers window


The Table Buffer window, shown in the following illustration, allows you to
view the contents of the table buffers in your application.

These lists specify which


table buffer you want to view.

This is the list of keys for the table.


This list displays additional
information about the table.

The table fields and their


contents are displayed here.

Use these buttons to update


the contents of the window.

You can view table buffers for forms, procedures and functions.

• To view the contents of a table buffer for a form, select the dictionary
and form the table buffer is associated with. Then select the table in the
Table list.

• To view the contents of a table buffer for a procedure or function, select


the form from which the procedure or function was called. The Table
drop-down list will contain a list of the table buffers for the table, as
well as qualified names indicating the table buffers for the procedures
and functions.

• To view the contents of table buffers for background procedures or spe-


cial procedure scripts, such as the Security procedure or the Pathname
procedure, choose the form named [Internal Form]. This is a place-
holder form Dexterity uses while processing background and internal
scripts. Then choose the qualified name in the Table list indicating
which table buffer you want to view.

268 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Dictionary
This is a list of products that are currently available in the application.

Form
This is a list of forms that are currently open in the application. You can
view the table buffers that are part of each form. If a form is open but
doesn’t appear in the list, click the Fill Forms button to update the list.

Table
This is a list of the tables that are attached to the currently-selected form.
Select a table in this list to view the contents of its table buffer. If the tables
for a form don’t appear in this list, click the Fill Table Buffers button to
update the list of tables.

Fields
Once you’ve selected the table buffer to view, the Fields list displays the
fields and their values. The values displayed are updated automatically
when a breakpoint is encountered. You can also update the values by
clicking the Update Fields button.

Key
The keys for the selected table are displayed in the Key list. These are for
informational purposes only. They don’t indicate which key was used to
access the record in the table buffer.

Table information
The Info list contains additional information about how the table is being
accessed. The following table describes the items that appear in this list.

Item Description
Pathname The path that was used to access the table.
Use Count The number of table buffers the current client has for the
table.
Open Count The number of instances of the table being open on the
current client.
Record Length The length of the fixed-length portion of the record (in bytes).
Max Variable Len The maximum length of the variable-length portion of the
record (in bytes).
Number of Fields The number of fixed-length fields in the table definition.
Number of Variable The number of variable-length fields (pictures and text fields)
Fields in the table definition.
Number of Keys The number of keys defined for the table.

PROGRAMMER’S GUIDE VOLUME 2 269


PA RT 6 A N A L Y S I S T O O L S

Item Description
Dictionary ID The ID of the dictionary the table definition is part of.
IsTemp A boolean indicating whether the table is a temporary table.
OS Name The physical name for the table (operating system name or
SQL table name).
Active Lock Count The number of active locks the current client has on the table.
Default File Handler The default database type to be used for the table.
Open A boolean indicating whether the table is open.
Open Mode A string indicating whether the table is opened with read-only
access, for shared access or for exclusive access.
Edit non-existing A boolean that is set to true when the edit table statement
record has reserved a record in the table. False indicates no record
was reserved.
FM Error A string indicating the error that occurred on the last table
operation.
Key Range An integer indicating the number of the key used to access
the current range of records. If a range isn’t being accessed,
this will be None.
Active Lock A boolean that is set to true when the record is actively
locked. Otherwise, it is set to false.

Editing scripts
You can edit the script displayed in the Script Debugger window by
clicking the Edit Script button. The script editor will open, allowing you to
edit the script.

Scripts containing breakpoints


If you edit scripts in which breakpoints have been set, Dexterity attempts to
preserve existing breakpoints. In some cases, the breakpoints may no longer
be valid or will not appear on the lines where you set them. For this reason,
we recommend that if you edit a script containing breakpoints, you should
delete the existing breakpoints and reset them.

Editing scripts while at a breakpoint


If you edit a script while stopped at a breakpoint, the changes you make to
the script won’t take affect until the next time the script is run.

270 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 7 S C R I PT D E B U G G E R

Debugging runtime errors


At runtime, the debugger informs you of all errors or unhandled exceptions
that stop script execution. If your application is running in test mode,
certain errors allow you to directly edit scripts to fix them.

When an error halts a script in test mode, the alert message dialog box will
contain two buttons. An example is shown in the following illustration. In
this example, a division by zero error was encountered during script
execution.

Click the Debug button to


see which script
encountered the error.

Click OK to return to test mode. Click Debug to see the name of the script
that encountered the error. An example of the window that displays the
name of halted scripts is shown in the following illustration.

Click the Where button to


open the Script Editor and
see where the script
stopped.

The set of scripts that were being processed at the time the application
stopped will be displayed in the window. The topmost script is the first one
that was called. If it called a second script, the second script will be shown
on the next line, and so on. The script at the end of the list was being run
when the error was encountered. Values shown after a script name are the
parameters that were passed to the script.

Click the Where button to open the Script Editor. The script that halted will
be opened, and the insertion point will appear on the line where execution
halted. You may edit the script normally at this point. Depending upon the
error encountered, it may be necessary to restart your application in test
mode before testing it again.

PROGRAMMER’S GUIDE VOLUME 2 271


PA RT 6 A N A L Y S I S T O O L S

As with any debugging tool, the Dexterity runtime debugging feature can take you
only to the point where it was no longer able to continue script processing. The
actual cause of an error, such as a variable that was assigned an invalid value,
might be in a different location.

272 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 28: Script Profiler
The Script Profiler lets you analyze script and table activity during test
mode, allowing you to optimize your scripts and streamline your
application. Once you’ve started the profiler, it records the name of every
script run and how much time is spent running each script. The Script
Profiler also tracks how many times tables were accessed and the average
and total times for specific operations on each table accessed. The time
required by the profiler itself is automatically deducted from the profile, so
that the profile shows the time requirements for only your application.

Information about the Script Profiler is divided into the following sections:

• Using the Script Profiler


• Understanding the script profile

Using the Script Profiler


The Debug menu contains the items used to control the Script Profiler:
Profile Scripts, Clear Profile and Save Profile.

Profile Scripts
Choose this menu item to start the process of profiling scripts. When you
choose it, Dexterity will begin keeping a record in memory of all the scripts
called by your application and the tables that were accessed. When you
save the profile, it will be copied from memory to a disk file.

You can turn the script profiler off at any time by choosing the Profile
Scripts menu item. If you turn the profiler on again later, the new profile
information will be added to the previous information. This allows you to
selectively control which portions of the application are profiled. For
instance, if you want to profile only the scripts from an invoicing window
and an inventory window, you can turn the script profiler on while the
invoicing window is active, turn it off while using other windows, and turn
it on again when the inventory window is active.

Be sure to turn off the script profiler before leaving test mode. Otherwise, it will
profile scripts called by Dexterity, making it difficult to tell your application’s
scripts from Dexterity’s.

Clear Profile
Choose this menu item to clear current profile information from memory
and start a new profile.

PROGRAMMER’S GUIDE VOLUME 2 273


PA RT 6 A N A L Y S I S T O O L S

Save Profile
Choose this menu item to save the current profile to a disk file. Choosing
this menu item doesn’t clear the current profile from memory or turn off the
script profiler; it simply saves the current profile to the location you specify
so you can examine its contents. When you choose this item, a dialog box
will appear; specify a name, location and file format for the profile. You can
select text format or tab-delimited format.
• Text files are stored as text that can be read by a text editor.

• Tab-delimited files are stored as columns of information separated by


tabs. In addition, some headers are excluded. This format can be read
using spreadsheet software.

The following is an example script profile that has been saved as a text file.

The headers for this Type Name


Monthly_Payment_Window l_Calculate_CHG on form Houses
Count
1
Time in +Children Minimum Maximum
0.08 4.79 0.08 0.08
section won’t be present F Calculate_Monthly_Payment() of form Houses 1 2.40 4.70 2.40 2.40
exit options on form Report Ask 1 3.69 3.69 3.69 3.69
if the profile is saved as a P Progress_Control 360 2.30 2.30 0.00 0.15
House_Entry_Window Lookup Button[1]_CHG on form Houses 1 1.95 1.95 1.95 1.95
tab-delimited file. Houses l_Match Buyers_CHG on form Houses 1 0.02 1.33 0.02 0.02
P Match_House_to_Buyers 1 1.31 1.31 1.31 1.31
Tool_Bar Houses Button_CHG on form Main Menu 1 1.00 1.00 1.00 1.00
House_Entry_Lookup_Window_Select_CHG on form House_Lookup 1 0.93 0.93 0.93 0.93
House_Entry_Lookup_WIN_PRE on form House_Lookup 1 0.83 0.83 0.83 0.83
House_Lookup l_Sort By_CHG on form House_Lookup 1 0.81 0.81 0.81 0.81
Houses House ID_CHG on form Houses 1 0.70 0.70 0.70 0.70
A “P” in the Type column P Calculate_Window_Values of form Houses 5 0.31 0.31 0.03 0.13
House_Lookup_Scroll SCROLL_FILL on form House_Lookup 8 0.31 0.31 0.00 0.23
indicates that the script is sel type on form Report Ask 1 0.11 0.11 0.11 0.11
Monthly_Payment_Window l_DownPayment_CHG on form Houses 1 0.05 0.18 0.05 0.05
a procedure. “F” indicates House_Entry l_Monthly Payment Button_CHG on form Houses 1 0.13 0.13 0.13 0.13
local update screen on form Reports Screen 1 0.05 0.05 0.05 0.05
it’s a function. Monthly_Payment_Window l_Payments_per_Year_CHG on form Houses 1 0.00 0.05 0.00 0.00
Monthly_Payment l_Closing Cost Percentage_CHG on form Houses 1 0.00 0.05 0.00 0.00
Monthly_Payment_Window l_Years_CHG on form Houses 1 0.00 0.05 0.00 0.00

Database Statistics by Number of Operations:


Read Read Read Read Insert Update Single Range Range
Table Name Single Next First Other Remove Remove Sum
House_Descriptions 1 0 0 0 0 0 0 0 0
Seller_Data 9 0 0 0 0 0 0 0 0
House_Data 1 0 0 0 0 0 0 0 0
Candidate_Buyers_List 0 0 0 0 5 0 0 0 0
Buyer_Data 0 8 1 0 0 0 0 0 0

Database Statistics by Average Time per Operation (MSecs):


Read Read Read Read Insert Update Single Range Range
Table Name Single Next First Other Remove Remove Sum
House_Descriptions 10 0 0 0 0 0 0 0 0
Seller_Data 4 0 0 0 0 0 0 0 0
Database information House_Data 10 0 0 0 0 0 0 0 0
Candidate_Buyers_List 0 0 0 0 7 0 0 0 0
Buyer_Data 0 3 3 0 0 0 0 0 0

Database Statistics by Total Time per Operation (Seconds):


Read Read Read Read Insert Update Single Range Range Total
Table Name Single Next First Other Remove Remove Sum
House_Descriptions 0.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01
Seller_Data 0.04 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.04
House_Data 0.01 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.01
Candidate_Buyers_List 0.00 0.00 0.00 0.00 0.03 0.00 0.00 0.00 0.00 0.03
Buyer_Data 0.00 0.02 0.01 0.00 0.00 0.00 0.00 0.00 0.00 0.03

Total Time for All Tables 0.06 0.02 0.01 0.00 0.03 0.00 0.00 0.00 0.00 0.12

Script cache information Script Cache Information:


Number of Calls: 367 Number of Hits: 363 Percent Hit Rate: 99

274 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 8 S C R IP T P R O FI LE R

Understanding the script profile


The script profile contains five sections. The first includes information
about scripts. The next three sections include information about accessing
tables in the database. The last section contains information about the script
cache.

Script information
The script information section describes the performance of scripts in your
application. Each line in the section describes a script that was accessed in
your application while the Script Profiler was on.

Type A “P” in this column indicates that the script is a procedure or a


form-level procedure. An “F” in this column indicates that the script is a
function or a form-level function.

Name This column displays the name of the script.

Count This column displays the number of times the script was accessed
while the profiler was on.

Time in This column displays the amount of time spent running the
script.

+Children This column displays the amount of time spent running the
script plus the amount of time spent in any procedures or functions called
by the script. The scripts are sorted according the values in this column.

Minimum This column displays the shortest completion time recorded


for the script during the profile session.

Maximum This column displays the longest completion time recorded


for the script during the profile session.

The time values shown in the profile are derived from the operating system. The
actual time represented by these numbers will vary between operating
environments, and is affected by a number of system settings. The numbers are best
viewed as relative indicators of the amount of time spent in each script.

PROGRAMMER’S GUIDE VOLUME 2 275


PA RT 6 A N A L Y S I S T O O L S

Database Information
This section displays information about tables that were accessed while the
profiler was on. Three categories are listed:

Number of operations This category lists the number of specific table


operations that were performed on each table.

Average time per operation This category lists the average time
required to perform each specific table operation for each table. The times
are listed in milliseconds.

Total time per operation This category lists the total time required to
perform each specific table operation for each table. It also lists the total
time spent for operations on each table and the total time for all tables. The
times are listed in seconds.

Information is logged for the following table operations:

Table Name These columns display the name of each table for which
information was logged.

Read Single These columns display the number of times individual


records were read from each table, and the average and total times to read
individual records.

Read Next These columns display the number of times a get next or
change next statement was used to read a record from each table, and the
average and total times for these operations.

Read First These columns display the number of times a get first or
change first statement was used to read a record from each table, and the
average and total times for these operations.

Read Other These columns display the number of times any other type
of command read a record from each table, and the average and total times
for these operations. Commands such as get previous, get last and
countrecords() are logged in this column.

Insert These columns display the number of times a new record was
inserted into each table using the save table statement, and the average and
total times for these operations.

276 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 2 8 S C R IP T P R O FI LE R

Update These columns display the number of times an existing record in


each table was changed and saved using the save table statement, and the
average and total times for these operations.

Single Remove These columns display the number of times a remove


statement was used to remove a record from each table, and the average
and total times for these operations.

Range Remove These columns display the number of times a remove


range statement was used to remove a range of records from the table, and
the average and total times for these operations.

Range Sum These columns display the number of times a sum range
statement was used to sum the numeric fields for each table, and the
average and total time for these operations.

Script cache
The last section of the script profile describes the performance of the script
cache. It lists the number of procedures, form-level procedures, functions,
and form-level functions that were executed. It also lists the number of
“hits” or times the procedure or function was read from the cache. The hit
rate percentage is also calculated. This is the ratio of the number of hits and
the total number of calls.

The script cache is cleared only when you recompile a script in the application. This
means that if a script was run in a previous test mode session, it may not have to be
reloaded when it is executed. This will distort the cache hit rate to appear higher
than it actually is. If you are doing benchmarking or performance tuning, we
recommend that you quit Dexterity and restart the application so you see accurate
values for the cache.

PROGRAMMER’S GUIDE VOLUME 2 277


278 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 29: Script Logger
The script logger stores a record of all the attached scripts, procedures, user-
defined functions, and function library functions that were run while your
application was being executed in test mode. It also lists any parameters
passed to the procedures or functions that were called. Information is
divided into the following sections:
• Logging scripts
• Understanding the script log
• Using the Script Logger

Logging scripts
To use the script logger, start your application in test mode. Choose Log
Scripts from the Debug menu. A dialog box will appear, allowing you to
enter a name and location for the script log. The log file created is a text file
that can be viewed with a text editor. The Script Logger will log all scripts
until it’s turned off.

You can turn on the script logger before entering test mode if you want to log the
Main Menu form pre script and any startup scripts. Be sure you turn off the script
logger before leaving test mode. Otherwise, it will log scripts called by Dexterity,
making it difficult to tell your application’s scripts from Dexterity’s.

Understanding the script log


A sample script log is shown in the following illustration.

'Tool_Bar Houses Button_CHG on form Main Menu'


Indented scripts were 'Houses_WIN_PRE on form Houses'
'House_Entry_Window Lookup Button[1]_CHG on form Houses'
called by the script they 'House_Entry_Lookup_WIN_PRE on form House_Lookup'
'House_Lookup l_Sort By_CHG on form House_Lookup'
are indented beneath. 'House_Lookup_Scroll SCROLL_FILL on form House_Lookup'
'House_Lookup_Scroll SCROLL_FILL on form House_Lookup'
'House_Lookup_Scroll SCROLL_FILL on form House_Lookup'
'House_Lookup_Scroll SCROLL_FILL on form House_Lookup'
'House_Entry_Lookup_Window_Select_Button_CHG on form House_Lookup'
'Houses House ID_CHG on form Houses'
'House_Entry l_Monthly Payment Button_CHG on form Houses'
'Monthly_Payment_Window_Pre on form Houses'
'Monthly_Payment_Window l_DownPayment_CHG on form Houses'
Functions from the 'Calculate_Window_Values of form Houses'
'Monthly_Payment l_Closing Cost Percentage_CHG on form Houses'
function libraries are 'Calculate_Window_Values of form Houses'
'RESM_Online_Help'
logged as well. 'Dict_GetPathname'(), "", 2
'Dict_GetName'(), ""
'WinHelp_GetHelpType'(), 0
'WinHelp_GetFieldContextNumber'(), 0
Values following the script 'WinHelp_InvokeHelp'(),0,":Macintosh HD:RESM/RESM.HLP", 1, 1074003977
'Monthly_Payment_Window l_Calculate_CHG on form Houses'
names are parameters that 'Calculate_Monthly_Payment of form Houses'(), 0.00000, 1, 15, 7.95000, 47250.00000
were passed to a procedure 'Progress_Control_WIN_PRE on form Progress_Control'
'Progress_Control', 1, 15
or function. 'Progress_Control', 2, 15

PROGRAMMER’S GUIDE VOLUME 2 279


PA RT 6 A N A L Y S I S T O O L S

The scripts in the log file are listed in the order in which they were
executed. Scripts that appear indented were called by or ran as a result of
the script they are indented beneath. Any values passed to procedures or
functions follow the script name in the log.

Using the Script Logger


You can use the Script Logger as a debugging tool. For example, you can
use it to ascertain whether a specific script has run, or to find out what
parameters were passed to a function or procedure.

You can also use the Script Logger when optimizing the performance of
your application. For example, if some operation seems to be particularly
slow, you can use the Script Logger to list all scripts that were run to
perform the operation. You then have a list of the scripts to target for
optimization.

If your application integrates with Microsoft Dynamics GP, you can use the
Script Logger to list which scripts are run when a particular operation
occurs in the accounting system, such as posting. Simply run Microsoft
Dynamics GP in test mode and start the Script Logger before performing
the operation in question. The script log allows you to see what is
happening in the accounting system without having to look at source code.

280 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 30: Resource Usage
When developing an application, it’s often useful to know how resources
have been used. The following is a description of how to use the Reference
Information window to find out how resources and scripts are used in your
application. Information is divided into the following sections:

• Building the reference information table


• Viewing reference information
• Updating the reference information table

Building the reference information table


Before you can find out how resources have been used in your application,
you must build the reference information table. This table contains
information about how specific resources are used in the application. To
build this table, choose Options from the Edit menu and display the
Reference tab.

Mark the items for which


you want to build
reference information.

Click Build Table to create or


update the reference
information table. Click
Clear Table to delete all
information from the table.

Mark the items for which you want to view reference information. For
example, if you want to find out how tables are used in your application,
mark Tables. To see how scripts refer to the various resources in your
application, mark Scripts. Then click Build Table to build the reference
information table.

For large dictionaries like Dynamics.dic, building the reference information table
for all resource types can take several minutes.

PROGRAMMER’S GUIDE VOLUME 2 281


PA RT 6 A N A L Y S I S T O O L S

Viewing reference information


You can access reference information from the Resource Explorer and the
Script Editor. To view reference information for a specific resource, select it
in the Resource Explorer and choose an item from the References button,
which is shown in the following illustration.

The References button


appears in the Resource
Explorer and the Script Editor.

You can choose the following items from the References button:

Refers To Displays a list of resources that this resource refers to.

Referenced By Displays a list of resources that refer to the resource


whose definition is being displayed.

When you choose an item, the Reference Information window is displayed.

The Reference Information


window is displayed when
you choose an item from the
References button.

282 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 0 R E S O U R C E U S A G E

The tree view on the left side of the window is filled based on the choice
you made from the References button. If you choose Refers To, the tree view
lists the resources and scripts this particular resource refers to.

When you choose Refers


To, the tree view lists the
resources and scripts the
resource refers to.

If you choose Referenced By, the tree view lists the resources and scripts
that refer to the this resource.

When you choose


Referenced By, the tree
view lists the resources
and scripts that refer to
the resource.

The tree view is expandable, allowing you to drill down to view the hierarchy of
resources used. You can use the Print button in the status area to print the contents
of the Reference Information window.

PROGRAMMER’S GUIDE VOLUME 2 283


PA RT 6 A N A L Y S I S T O O L S

When you select an item in the tree view, the list on the right side of the
window displays a detail view of all the items in the dictionary that refer to
the item selected. In the following illustration, the data type STR30 is
selected in the tree view. The list on the right side of the window shows a
detail view of all the other resources that reference the STR30 data type.

When you select an item


in the tree view, this list
shows a detail view of the
resources and scripts that
refer to the selected item.

If your dictionary contains script source, you can double-click the name of any
script to automatically open it in the script editor.

Updating the reference information table


With the exception of scripts, changes you make in your dictionary, won’t
be reflected in the reference information table. (A setting in the Options
window controls whether compiling updates the reference information
table.) Periodically, you will want to update this table to ensure that correct
information is displayed in the Reference Information window.

To update reference information, open the Options window and display the
Reference tab. Mark only the items you want to update. For example, if you
have been changing scripts, but other resources are unchanged, mark only
the Scripts item. Click Build Table to update the reference information table.

If you aren’t sure how up-to-date the reference information table is, you
may want to click Clear Table to remove all information from the table.
Then mark the appropriate items and click Build Table to re-create the table.

284 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 7: SOFTWARE ENGINEERING
Part 7: Software Engineering
Use the information in this portion of the documentation to learn about the
process of creating stand-alone applications with Dexterity and managing
the development process. Following is a brief explanation of the topics
discussed:

• Chapter 31, “The Development Process,” describes a standard


procedure for developing software and describes a suggested process
for developing applications with Dexterity.

• Chapter 32, “Design Guidelines,” provides guidelines for the design of


applications created with Dexterity.

• Chapter 33, “Optimizing Your Application,” provides several


techniques and hints for optimizing applications created with
Dexterity.

• Chapter 34, “Testing Your Application,” describes a procedure for


testing applications created with Dexterity. It also explains how to use
Dexterity’s built-in macro system to test your application.

• Chapter 35, “Creating an International Product,” provides information


to consider when developing Dexterity-based applications for
international markets.

286 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 31: The Development Process
To develop high-quality applications, a standard development process
should be followed. This portion of the documentation describes the steps
of a standard software development process. The information is divided
into the following sections:

• Application development
• Dexterity application development
• Managing development

Application development
Several different methods can be used when developing applications.
Though a complete discussion of development methods is beyond the
scope of this documentation, most development methods share the
following four major steps:

1. Determine the requirements of the application.


This step involves determining exactly what you want the application
to do. By deciding the application’s capabilities before you begin
coding, you can better determine what resources will be required to
complete the application. It’s a good idea to document the application
requirements so everyone working on the application is working from
the same set of requirements.

2. Decide how the application requirements will be


implemented.
Before actual coding begins, you should document how you’re going to
implement each function in the application. This process often will
indicate potential problems that will occur in the implementation. By
carefully working through this process, you’ll be able to solve many
problems in your application design before you begin coding.

3. Code the application.


After you’ve determined how you’re going to implement the
application, you can begin the actual coding.

PROGRAMMER’S GUIDE VOLUME 2 287


PA RT 7 S O F TW A R E E N G I N E E R I N G

4. Test the application.


As parts of the application are completed, you can test them to
determine whether they operate as designed. If you thoroughly
documented how to implement the application, many of the problems
that would ordinarily have been found by testing will already have
been solved.

Dexterity application development


The following steps describe the process of developing a stand-alone
application with Dexterity:

1. Determine the requirements of the application.


As with any application development process, this step involves
determining exactly what you want the application to do.

2. Decide how the application requirements will be


implemented.
For Dexterity applications, this involves defining the tables, designing
the interface, deciding what scripts are needed, and designing the
reports necessary for the application. It may be useful to create
prototypes of parts of the application to test the interface or determine
whether parts of your application are practical to implement.

3. Code the basic functions of the application, such as


navigation or pathname support.
Coding the basic application functions first provides a base on which
the build the remainder of the application. Some of the basic functions
typically found in Dexterity applications are described in the Stand-
alone Application Guide. Refer to that manual for more information.

4. Code the other portions of the application.


After the basic functions of the application are coded, you can code
other portions that perform functions specific to your application.

5. Test the application.


As parts of the application are completed, you will want to run it using
the runtime engine and test the application’s functions. Testing
Dexterity applications is described in Chapter 34, “Testing Your
Application.” There you will also find a description the macro system
that is available to all Dexterity applications. The macro system is
useful for recording test procedures which allows an application to be
retested easily.

288 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 1 TH E D EV EL O P M E N T PR O C E S S

To use the runtime engine to run your application, you’ll enter product
information for the application dictionary and create a launch file to
start the application. Adding product information is described in
Chapter 57 of Volume 1 of the Dexterity Programmer’s Guide. Using a
launch file to start an application with the runtime engine is described
in Chapter 58 of Volume 1 of the Dexterity Programmer’s Guide.

6. Write the online help for the application, if you’re including


it with your application.
After you’ve coded and finished making changes to your application,
write and code any online help. Online help is described in Chapter 7,
“Windows Help,” of the Stand-alone Application Guide.

7. Package the finished application.


Once all of the parts of the application are complete, you’ll package
them in a deliverable form. Packaging an application is described in
Part 11, Packaging Applications of Volume 1 of the Dexterity
Programmer’s Guide.

Managing development
How you manage application development depends on how large the
application is you will be creating, and the number of developers you will
have working on the project.

Small applications with only one or two developers can be managed


manually. You can perform development in a single dictionary, making
regular backups to create an archive of changes. This allows you to revert
back to a previous version if necessary.

If you will be creating a large application, or will have many developers


working on your project, we strongly recommend that you implement
source code control to manage the development process. Source code
control allows many developers to work on a single dictionary without
having to worry about concurrency issues (users trying to change the same
resources at the same time). It also provides revision management, allowing
you to maintain all of the revisions of your product. You can easily re-create
any version of your product at any time. Refer to Part 9, Source Code
Control in Volume 1 of the Dexterity Programmer’s Guide for a complete
description of how to use source code control when developing
applications with Dexterity.

PROGRAMMER’S GUIDE VOLUME 2 289


290 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 32: Design Guidelines
By carefully structuring your Dexterity applications, you can make them
more flexible, easier to use and easier to maintain. The following is a set of
guidelines you should consider as you develop your Dexterity application.
They are divided into the following general categories:

• Resources
• Scripting
• Features

Resources
The following guidelines apply to various resources in your application.

Data types
If a field has a unique purpose, create a separate data type for it. This allows
the characteristics of the field to be easily modified without affecting other
fields in the application.

Formats
Provide common formats in your application so Report Writer and
Modifier users won’t have to create them.

Fields
When possible, use global fields only for data stored in tables. For fields
that appear only on windows, use local fields. Local fields are stored with
the form. This helps encapsulate a form, making it more portable and easier
to transfer to another Dexterity application.

Tables
Consider supplying extra fields in your tables. Extra string, long integer
and currency fields in the table auto-linked to a window allow Modifier
users to add fields to the window. Be sure you use the copy from and copy
to statements to move data between the window and the table buffer. This
ensures that the data in the extra fields will automatically be saved in and
retrieved from the table.

PROGRAMMER’S GUIDE VOLUME 2 291


PA RT 7 S O F TW A R E E N G I N E E R I N G

Provide common table relationships for related tables in your application,


even if you don’t use them for reports you include with your application.
One of the more difficult aspects of the Report Writer is creating table
relationships. Users will find it convenient to use common table
relationships that have already been created.

Forms
Design your forms to be “portable.” Portable forms can be easily
transferred into another and work with little or no modification. Portable
forms allow you to easily re-use your form in another dictionary. To
make forms portable, follow these guidelines:

• Use local fields and local data types whenever possible.

• Use form-level procedures and form-level functions instead of global


procedures and global functions.

• Avoid using global variables.

• Use form-level constants instead of global constants.

Reports
Consider supplying additional data through report legends, even if you
don’t use them in the reports you provide with your application. Report
Writer users may find the values supplied in legends useful on reports. Be
sure to document any legends that you supply for reports.

Pictures
When possible, use pictures instead of native pictures. Pictures are platform
independent, so you don’t need to create separate pictures for each
platform.

Global variables
Minimize the use of global variables in your application. Because of their
global nature, system variables are prone to causing application errors.
Errors can occur when one portion of an application changes the value of a
system variable without taking into account the effects on other portions of
the application.

Document any global variables used in your application. Report Writer


users may find the global variables useful on reports they create.

292 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 2 D E S I G N G U I D EL I N E S

Scripting
Keep the following guidelines in mind when adding scripts to your
application.

Procedures
Use procedures to perform process-intensive tasks. Doing so allows these
tasks to be easily sent to a process server for remote processing. Refer to
Background and remote processing in Chapter 20, “Procedures,” of Volume 2 of
the Dexterity Programmer’s Guide for more information.

Scripts
If your application contains code to validate data such as account numbers
or customer IDs, move this code to form-level procedures or form-level
functions. Don’t put validation code in field scripts. By placing the
validation code in a form-level procedure or function, you make it available
to other parts of the application that may need to perform the same
validation.

To reduce code maintenance, avoid accessing data on other forms directly.


For example, don’t explicitly refer to a window field on another form.
Instead, create functions on that form to set and get the values of the field.
Then you can make changes to the field without breaking code in other
portions of your application.

Consolidate common operations like saving and deleting records into form-
level procedures. Often, these operations are performed in several locations
in the form. By consolidating these operations, you reduce code duplication
and maintenance.

PROGRAMMER’S GUIDE VOLUME 2 293


PA RT 7 S O F TW A R E E N G I N E E R I N G

Features
Consider implementing the following features in your application.

Customization
Make your application customizeable. The most common customization is
support for system colors and custom colors. You could also provide access
to the Modifier and Report Writer.

You may choose to use defaults file settings to store customization options.
Any customizations you make available should be accessed through an
options window. Don’t make users edit the defaults file directly. Be sure to
document any defaults file settings you use. Don’t make defaults file
settings mandatory. Your application should be able to run properly,
regardless of defaults file settings.

Data import and export


If your application can use existing data from other applications, such as a
customer address data, you may want to provide a method of importing
data into your application. Typically data is imported from text files.

Your application should have some means of exporting data. Typically, data
is exported to text files. You could write scripts that export data to text files,
or you could create reports that export the data to text files. The ability to
export data allows users to work with your application’s data in other
applications.

Setup information
Your application should provide information about the current setup.
Typically, this information is provided in the application’s About Box and
includes the following:

• Application version
• Dexterity version
• ODBC driver version (if applicable)
• Platform
• Operating system
• Special features enabled

Having this information accessible makes supporting the application easier,


because you can easily find out characteristics of the system.

294 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 33: Optimizing Your Application
This portion of the documentation contains tips that can help you improve
the performance of applications you create with Dexterity. Information
about optimizing is divided into the following sections:

• Procedures and functions


• Forms and windows
• Tables
• Reports
• Scrolling windows
• Scripts

Procedures and functions


Caching
Dexterity has a built-in script cache to cache procedures, functions, form-
level procedures and form-level functions. By default, 50 scripts are cached.
Use the ScriptCacheEntries defaults file setting to change the number of
scripts cached.

Refer to Chapter 28, Typically, the script cache has about a 97% hit rate. Use the Script Profiler to
“Script Profiler,” for gauge how well the script cache is performing. The cache information is
information about located at the end of the script profile.
using the Script
Profiler. For most applications, the default script cache will be adequate. However, if
your application performs operations that use a combination of more than
50 procedures and user-defined functions, you may want to increase the
size of the script cache. If the cache hit rate is lower than average, increasing
the script cache size could improve performance.

Keep in mind that setting the cache size larger will require more memory.
At a minimum, Dexterity will cache 35 scripts. If Dexterity is running out of
memory and can’t perform actions such as opening forms, the script cache
will automatically be flushed to make more memory available.

PROGRAMMER’S GUIDE VOLUME 2 295


PA RT 7 S O F TW A R E E N G I N E E R I N G

Table buffers
Opening several tables in a procedure or function can affect application
performance. The first table a procedure or function opens takes the most
time to open. Subsequent tables opened by the procedure or function take
less time to open.

If a procedure or function opens a table buffer, then calls another procedure


that uses the same table, pass the table buffer (as an inout parameter) to the
second procedure, rather than having the second procedure reopen the
table. It takes much less time to pass a table buffer as a parameter than to
open a table.

Forms and windows


Form loading
The speed with which a form loads is largely based upon the number of
window elements that must be loaded for the form. Fewer window fields,
invisible fields and other window elements, such as lines, boxes and
pictures, result in faster loading.

To speed up form loading, avoid using scripts attached to hidden window


fields. Instead, use form-level procedures or form-level functions.

Window updating
If possible, use the copy from table, copy to table, copy from table to
window, and copy from window to table commands to update window
fields, instead of using the set statement. These commands provide better
performance when updating windows and result in shorter scripts.

296 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 3 O P T I M I Z I N G Y O U R A P PL I C A T I O N

Tables
Table access
For data-intensive applications, application speed is mainly based upon the
number of records being read from and written to tables. The more records
that are read and written, the slower the application. To improve the speed
of an application, minimize the number of records that are read from and
written to tables.

Clearing tables
If you are removing all records from a table, consider deleting and then
recreating the table. For tables containing many records, this may be faster
than removing the records individually or setting up a range for the entire
table and removing the range.

Keys
The time required to write records to a table is directly proportional to the
number of keys defined for the table. To improve performance, reduce
the number of keys in each table.

The total length of the segments of a key also affects performance. The
longer the segments for the key, the larger the table index becomes. Larger
table indexes take longer to search, increasing the time to read and write
records. To improve table performance, reduce the number of key segments
and the length of the segments for each key.

Ranges
If you are working with groups of records in a table, use ranges when
possible. Some database managers, such as SQL database managers,
perform operations on ranges of records very efficiently. For example, SQL
database managers can remove a range of records much faster than they
can remove the records individually.

Table size
As tables become larger, read and write times become longer. To improve
table performance, keep the size of tables as small as possible.

PROGRAMMER’S GUIDE VOLUME 2 297


PA RT 7 S O F TW A R E E N G I N E E R I N G

Temporary tables
Refer to Temporary In some cases, you may be able to speed up network operations by using
tables in Chapter 9, temporary tables. For example, if you’re doing considerable processing on a
“Tables,” of Volume 1 range of records in a table stored on a network drive, you may want to copy
of the Dexterity those records to a temporary table stored on your local drive, perform the
Programmer’s Guide necessary processing using the temporary table, then copy the records back
for information about to the table on the network. This can greatly reduce network traffic and
creating temporary improve performance.
tables.
When creating temporary tables, create only one key for the table and keep
the length of the key to a minimum. This will improve the performance
when reading and writing records for the temporary table.

Reports
Use text reports when you want maximum performance printing reports.
Text reports are simpler than graphics reports, so they print much faster.
Dexterity has also been optimized for maximum performance when
printing text reports.

Scrolling windows
Fill scripts are typically used to read records from tables other than the table
linked to the scrolling window. Because this increases the time required to
fill the scrolling window, avoid using fill scripts for scrolling windows
whenever possible. Instead, consider adding the fields being read by the fill
script to the table linked to the scrolling window.

Also, try to avoid using the reject record statement in the scrolling window
fill script because many additional records may have to be read and rejected
before the scrolling window is filled. If several records shouldn’t be
displayed in a scrolling window, either set a range on the linked table or
consider using a temporary table.

Scripts
Refer to Chapter 28, Use the Script Profiler to find out which areas of your application are
“Script Profiler,” for potential candidates for optimization. The scripts are listed in order in the
information about script profile, with the scripts at the top of the list taking the most time to
using the Script execute. These are the scripts you should target for optimization.
Profiler.

298 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 34: Testing Your Application
This portion of the documentation describes the characteristics of a good
application, introduces the process of software quality assurance, and
describes special considerations when testing Dexterity applications. It also
describes Dexterity’s built-in macro system, which can be used to automate
testing. Information is divided into the following sections:

• Characteristics of a good application


• The SQA process
• Testing Dexterity applications
• Phases of testing
• The macro system
• The Macro menu
• Additional macro menu items
• Using macros for testing
• Structure and syntax of a macro
• The macro language

Characteristics of a good application


A good application has four basic characteristics:

• The application should be reliable. Users should be able to depend on


the application to perform the tasks described in the documentation.

• The software should have an appropriate user interface. Using your


application shouldn’t be an unnecessarily complex task.

• The application should be efficient. Efficiency means the software


shouldn’t make wasteful use of the system resources.

• The application should be maintainable. It should be coded and docu-


mented so that changes can be made without undue cost.

If you want to have a high-quality application, you can’t just test it when
you’ve finished coding. The process of creating a quality application starts
at the design stage and continues throughout the development cycle. This
process is typically referred to as Software Quality Assurance (SQA).

PROGRAMMER’S GUIDE VOLUME 2 299


PA RT 7 S O F TW A R E E N G I N E E R I N G

The SQA process


SQA is an integral part Software quality assurance (SQA) consists of the procedures, techniques
of the development and tools applied to ensure that an application meets or exceeds prescribed
process. It doesn’t standards during the development cycle. If there are no
enter the process only prescribed standards, quality assurance ensures that a product meets or
after the application is exceeds a minimal commercially acceptable level of excellence.
complete.
The SQA process works to produce high-quality software through a process
called fault-avoidance. This process starts by describing exactly what the
application is to do and how it will do it. This description is essential to
gauge how well the application has met its goals.

After the application has been designed, the coding process can begin.
During the coding process, these guidelines should be followed:

• The principle of information hiding should be used. Information hiding


is used so other parts of the application don’t need to know how a par-
ticular procedure is implemented The other portions of the application
only have an unchanging interface with which to interact.

For example, in a Dexterity application, a procedure or function can


perform a specific operation. This procedure or function has a set of
parameters that are passed to and returned from it. Other parts of the
application interact with the procedure through only these parameters.
Because of this, how the specific operation is performed by the
procedure or function can be changed without affecting other portions
of the application, as long as the procedure’s or function’s parameters
are unchanged.

• Software walkthroughs should be held regularly to validate the design


of the software. In a software walkthrough, programmers, designers
and others involved in the development process meet to discuss the
software design and implementation. This allows potential problems in
the software to be found early in the development process.

• Usability testing should be performed to validate the interface design.

During the development process, software tests should be planned to


expose problems that weren’t discovered during the review process. This
involves writing test procedures that test the software to determine
whether it meets its requirements. These test procedures should also test
boundary conditions and limits of the software.

300 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 4 T E S T I N G Y O U R A P PL I C A T I O N

Many of the test procedures developed to test the software can be recorded
as macros. Macros allow exactly the same test procedures to be repeated,
without introducing the factor of human error. This allows for regression
testing, or retesting the application. After changes have been made to the
application, regression testing is performed to ensure that existing
functionality in the application hasn’t been affected.

A macro system is built into Dexterity and is available to all applications. It is


useful for recording macros used for regression testing. The macro system is
described later in this chapter.

Testing Dexterity applications


You will want to consider the following items when you plan how to test
your Dexterity application.

Database types
You should test all of the different database types your application will
support. Refer to Appendix A, “Dexterity Limits,” in this manual for a list
of the limits for the various database types.

Network operation
If your application will be operating in network environments, you should
run your tests for each environment you will be supporting.

Multiple users
If multiuser operation is supported by your application, be sure to test your
application with multiple users.

Video configurations
Check the sizes of your application’s windows for the different video
configurations you will be supporting. Be sure you haven’t made windows
too large to appear normally when using lower-resolution video displays.
Also, be sure to check how your application looks on a monochrome or
gray-scale display.

Reports and printing


Be sure to test how reports are printed for each platform and printer your
application supports.

PROGRAMMER’S GUIDE VOLUME 2 301


PA RT 7 S O F TW A R E E N G I N E E R I N G

Tool access
If you are licensing and providing access to tools such as the Report Writer
or the Modifier, be sure they can be accessed properly from within your
application.

Windows DLLs
If you have written any DLLs to be used with your Dexterity application, be
sure these are thoroughly tested.

Online help
If your application has online help, be sure you’ve tested it thoroughly to
ensure it is operating properly and that correct information is displayed.

Printed documentation
Verify that descriptions and procedures described in the documentation
match the behavior of the software.

Phases of testing
The first phase of testing is finished when your application performs
according to its requirements, has been thoroughly exercised, and all test
cases you’ve written indicate the application is working properly.

The next phase is beta testing, when you release your application to a select
group of customers. The beta testing phase allows your customers time to
thoroughly work with your application and report any problems or
suggestions. It also allows you an opportunity to fix reported problems and
make necessary changes to improve your application.

When the beta testing phase is complete, you’re ready to send your product
to your customers. Depending upon how comfortable you are with the
quality of your application, you may want to do a controlled release
(releasing to a limited number of customers) before you make your
application generally available.

302 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 4 T E S T I N G Y O U R A P PL I C A T I O N

The macro system


Dexterity and the runtime engine have a built-in macro system that can be
used to record mouse and keyboard events and play them back. The macro
system is available to any Dexterity application, allowing users to automate
common tasks. The macro system can also be used to test applications
created with Dexterity.

Because the macro system is part of Dexterity, the recorded macro


instructions are based on the underlying structure of the application, rather
than on positions of windows and fields. This means changing the position
of fields in windows won’t invalidate a recorded macro.

The Macro menu


Refer to Chapter 14, The macro system is accessed from the Macro menu in Dexterity. In test
“Form-based Menus,” mode or with the runtime engine, the macro system is accessed from the
in Volume 1 of the menu that has inherited the macro system items. The following items are
Dexterity available in the Macro menu:
Programmer’s Guide
for information about Play/Stop Play
adding macro menu This menu item allows you to select and play a macro file. When a macro is
items to your running, this menu item allows you to stop the macro.
application.
Record/Stop Record
This menu item opens a dialog box that allows you to name a new macro
file. You can then begin recording actions. Once you’ve finished recording
the macro, choose Stop Record.

Pause/Continue
This menu item allows you to pause a macro that is currently playing.
Choose Continue to resume playing the macro.

Suspend Recording/Resume Recording


This menu item suspends recording a macro, allowing you to perform other
tasks. When you want to resume recording the macro, choose Resume
Recording.

Step
When a macro is paused, selecting this item causes the next statement in the
macro file to be run.

PROGRAMMER’S GUIDE VOLUME 2 303


PA RT 7 S O F TW A R E E N G I N E E R I N G

Insert Pause
When a macro is being recorded, selecting this item allows you to insert a
pause in the macro. A window will appear, prompting you to enter the
string that will be displayed when the pause is encountered during
playback.

When the macro is played, a dialog box containing the message will be
displayed, as shown in the following illustration.

Close the dialog box and choose Continue from the Macro menu to allow
the macro to continue running.

Additional macro menu items


The macro system can record mouse and keyboard events for procedures
you’ve developed to test your application. Macros allow you to run your
test cases on updated versions of your application without having to
manually work through the test cases each time.

Some additional menu items are available to help you use the macro system
to test your application. To access these additional items in test mode or
with the runtime engine, add the ShowAdvancedMacroMenu=TRUE
setting to the defaults file. To access these additional items from within
Dexterity, hold down the SHIFT key and choose Play from the Macro menu.
Click Cancel in the dialog box that appears. The next time you display this
menu, five additional items will have been added to it. If you quit and
restart your application, the Macro menu will return to its original size.

304 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 4 T E S T I N G Y O U R A P PL I C A T I O N

We strongly recommend that you don’t tell your customers about the additional
items in the Macro menu. These items are for developer use only.

Status
This menu item opens the Macro Status window.

When a macro is being


recorded, these fields list the
name and the number of
lines in the macro.
This is the macro being
played. Click the lookup button
to select a macro to play.

These fields allow you to


move to or pause after a
specific line in the macro file.

This field indicates the


number of lines to be
displayed, starting from line 1.

When a macro is being recorded, the Macro Status window will list the
name of the macro and how many lines it currently has.

Refer to the When a macro is being played, the Macro Status window lists the name of
StdInternationalInfo the macro and the line currently being executed. The
setting in the Dexterity StandardInternationalInfo option will be checked when standard
online help to learn international information is being used while the macro is running. The
about standard status of this check box is determined by the StdInternationalInfo setting
international in the DEX.INI file and can’t be changed by the user.
information.

PROGRAMMER’S GUIDE VOLUME 2 305


PA RT 7 S O F TW A R E E N G I N E E R I N G

The Windows Compatibility option will be marked automatically and


should remain marked when macros are being run on Windows. For other
platforms, marking the Windows Compatibility option allows controls to
behave more like those in Windows. This helps minimize incompatibilities
when macros recorded on Windows are played back on other platforms.

The No User Interface Flash option will prevent the momentary pause that
normally occurs to make push buttons appear as if they have been pressed.
Removing this pause will allow macros to be executed more quickly.

The Macro Status window also allows you to begin executing a macro at a
specific line or insert a pause after a specified line. To start a macro at
a specific line, enter the line number in the Jump to Line field and click OK,
or double-click the line in the scrolling window. To pause after a specific
line, enter the line number in the Pause After Line field.

The scrolling window at the bottom of the window displays the lines in the
macro. The scrolling window is useful when you want to start a macro at a
specific line or when you’re trying to locate an error in a macro.

Because macros can be lengthy, by default only the first ten lines of the
macro are displayed. To allow more than ten lines to be displayed, enter the
number of the last line you want to display in the Lines to Display field and
press the TAB key. The scrolling window will then be able to display from
the first line in the macro to the line you specified. To begin displaying a
macro from a specific line, enter the line number in the Jump To Line field
and press the TAB key.

For example, to display line 435 of a 2000-line macro, enter 500 in the Lines
to Display field and press the TAB key to allow the first 500 lines of the
macro to be displayed. Enter 435 in the Jump to Line field and press the TAB
key. After a moment, the scrolling window will begin displaying the macro
at line 435.

306 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 4 T E S T I N G Y O U R A P PL I C A T I O N

Window Dump
Choosing this item while recording a macro inserts a command to save an
image of an application’s currently active window as a graphics file. When
the macro is run on different versions of the application, the images from
each version can be compared to ascertain whether the results are the same.

The Window Dump menu item opens a dialog box allowing you to name
the graphics file to which the image of the current window will be saved. It
also inserts a command into the macro to save the image when the macro is
played. The image will be saved as a PC Paintbrush (.PCX) file.

Field Dump (All)


Choosing this item while recording a macro inserts a command to save the
names and contents of all fields in the currently active window to a text file.
When the macro is run on different versions of the application, the text from
each version can be compared to ascertain whether the results are the same.

The Field Dump menu item opens a dialog box allowing you to name the
text file to which the names and contents of fields in the current window
will be saved. It also inserts a command into the macro to save the fields’
contents.

Field dumps must not be taken when a change is made to a field and the focus
remains on it. The field dump will not reflect the change made to the field until the
focus leaves the field.

Field Dump (Selected)/Stop Selecting


Choosing this item while recording a macro inserts a command to save
selected fields to a text file. A dialog box will be displayed, allowing you to
name the text file to which the names and contents of fields will be saved.
Dexterity will switch to field selection mode, allowing you to click on the
fields whose contents you want saved. When you have selected the fields
you want, choose Stop Selecting from the Macro menu, or press ESC.

Menu Dump
Choosing this item while recording a macro inserts a command to save the
names and contents of all form-level menus that are attached to the
currently-active form to a text file. A dialog box will appear, allowing you
to name the text file in which the menu information will be saved. When the
macro is run on different versions of the application, the text from each
version can be compared to determine whether the results are the same.

PROGRAMMER’S GUIDE VOLUME 2 307


PA RT 7 S O F TW A R E E N G I N E E R I N G

Menu Dump All


Choosing this item while recording a macro inserts a command to save the
names and contents of all menus in the currently active application to a text
file. A dialog box will appear, allowing you to name the text file in which
the menu information will be saved. Form-level menus will be listed after
application-level menus in the text file. When the macro is run on different
versions of the application, the text from each version can be compared to
determine whether the results are the same.

Toolbar Dump All


Choosing this item while recording a macro inserts a command to save the
names and contents of all toolbars currently displayed to a text file. A
dialog box will appear, allowing you to name the text file.

Background Dump
Choosing this item while recording a macro inserts a command to save the
background HTML document to a text file. A dialog box will appear,
allowing you to name the text file in which the information will be saved.
This is used when testing the “Home Page” functionality in an application.

Shell Dump
Choosing this item while recording a macro inserts a command to save the
contents of the MDI shell (main runtime window) to an XML file. A dialog
box will appear, allowing you to name the text file. This can be useful when
testing the navigation in an integrating application.

Table Dump
Choosing this menu item opens the Table Export window. This window
allows you to export the contents of a table to a text file. During testing, the
contents of the text file can be compared with previous versions to find out
if any differences have occurred.

Open Form
Choosing this item opens the Macro Open Form window. This window
allows you to open a specific form without having to record the steps
necessary to open it using the application’s interface. This allows you to
record macros that are independent of the navigation in the application.

Insert Header
This menu item opens a window allowing you to specify information about
the macro being recorded. This information can include a description of the
macro, a list of the windows that must be open, or any other preconditions
necessary for the macro to run properly. The information you enter in this
window is saved in comment lines at the beginning of the macro file.

308 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 4 T E S T I N G Y O U R A P PL I C A T I O N

Insert Comment
This menu item opens a window allowing you enter comments for the
macro being recorded. Each time you add a comment, it is saved as a
comment in the next line of the macro file.

Using macros for testing


We recommend that you plan your software tests before you begin
recording macros. Properly planned, each macro can perform a specific test
and produce a measurable or observable result. Good planning also
prevents macros from becoming longer than necessary.

For example, it’s not efficient for a macro to open a lookup window when
no information exists to be retrieved. Through careful planning, you can
avoid unnecessary steps and create macros that run more quickly and are
easier to debug.

Be sure to test each macro after you record it to ensure that it is working properly.

Editing macros
Sometimes when you are recording macros you will make a mistake or
forget a step. In these situations, you can use a text editor or word processor
to edit the macro file.

We don’t recommend that you write macros from scratch. Instead, you should use
the macro system to record mouse and keyboard actions, then edit your macros if
necessary.

You can use a text editor or word processor to edit the macro directly. Be
sure you save the macro as a text file with carriage returns at the end of each
line, and assign the file the extension .MAC.

Macro files can become quite large. If you want to edit large macros, you will need
to use a text editor or word processor capable of editing large text files.

Running macros
When you’re running macros, it’s sometimes convenient to store the macro-
related warnings and messages (such as the time a macro took to complete)
in a file, rather than displaying them on the screen. To have a macro’s
messages stored in a file, edit the macro and add the Logging command as
the first line of the macro. Refer to the Logging command in the online help
for specific details about how to use this command.

PROGRAMMER’S GUIDE VOLUME 2 309


PA RT 7 S O F TW A R E E N G I N E E R I N G

Keys.ini file
You can use a special file named Keys.ini when running macros with the
runtime engine. The Keys.ini file contains macro commands that are run at
startup to configure various system behaviors. The macro commands in the
Keys.ini are run only if the file is included in the parameters for the
command to launch the runtime engine.

You create the Keys.ini file using a text editor, such as Notepad. The
Keys.ini file is typically stored in the Data folder of your application
installation.

To work properly, the Keys.ini file must also have a blank line as the last item in the
file.

The following macro commands are typically used in the Keys.ini file:

• SetEbDateTo
• SetEbTimeTo
• Logging
• SetExitAction
• MacroError
• FilePath

The following is an example of a Keys.ini file:

SetEbDateTo date 01/01/1965/3


SetEbTimeTo 'o/s'
Logging file 'Regression_Test.log'
SetExitAction 'o/s'
MacroError limit 5
FilePath relative

310 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 4 T E S T I N G Y O U R A P PL I C A T I O N

Structure and syntax of a macro


A macro is made up of comments and macro commands. Macros must
conform to the following rules:

• The macro language is case-sensitive, as are the names of all fields, win-
dows, forms and other resources.
• Each statement must end with a carriage return.
• Comments in the macro appear with a pound sign (#) preceding the
comment. Comments are ignored when the macro is run.
• Names containing spaces, as well as values entered using the keyboard,
must be enclosed in single quotation marks.
A sample macro is shown in the following illustration.

#************************* KEYSTROKE HEADER **************************


#
Information about the #Keystroke '100'
#
Module 'RSM' Run Time '15:1'

macro is stored at the #Version # '2.0' Date '11/9/1994'


#
Created by 'Steve'

beginning of the macro file. #Integrated w/ 'N/A' Customer Data ? 'No'


#
#Beginning Data 'Standard'
#
#Setup: ''
#
#Main Program 'Seller_Entry' Other Programs 'Seller_Entry_Lookup'
#
#Problem Rpt or Pink Sheet #'s ''
#
#Last Date Updated '10/16/95' By 'Steve'
#
#OUTLINED DESCRIPTION OF KEYSTROKE AND UPDATE NOTES
#
#
A description of the macro # This macro tests whether an existing item can be retrieved from
# the Sellers table, modified, saved, and the changes retrieved
can be included. # and verified.
#
#
#LIST REPORTS GENERATED
#
# 1. 'Seller1.TXT ' 2. ' ' 3. ' '
#
# 4. ' ' 5. ' ' 6. ' '
#
# 7. ' ' 8. ' ' 9. ' '
#
Any window images or #10. ' ' 11. ' ' 12. ' '
#
field lists saved by the #13. ' ' 14. ' ' 15. ' '
#
macro can be listed here. #16. '
#
' 17. ' ' 18. ' '

#19. ' ' 20. ' ' 21. ' '


#
#22. ' ' 23. ' ' 24. ' '
#
#25. ' ' 26. ' ' 27. ' '
#
#
#******************************************************************************
# DEXVERSION=DEX 3.00c004 1 1
ActivateWindow dictionary 'default' form 'Main Menu' window 'Tool_Bar'
MoveTo field 'Sellers Button'
ClickHit field 'Sellers Button'
Comments can be added NewActiveWin dictionary 'default' form Sellers window Sellers
# Attempt to retrieve an existing record.
to the macro. MoveTo field 'Lookup Button'[1]
ClickHit field 'Lookup Button'[1]
NewActiveWin dictionary 'default' form 'Seller_Lookup' window 'Seller_Lookup'
MoveTo line 4 browsewin 'Seller_Lookup_Scroll'
MoveTo field '(L) Select_Button'
ClickHit field '(L) Select_Button'
NewActiveWin dictionary 'default' form Sellers window Sellers
ActivateWindow dictionary 'default' form Sellers window Sellers

PROGRAMMER’S GUIDE VOLUME 2 311


PA RT 7 S O F TW A R E E N G I N E E R I N G

The macro language


The following is a categorized list of the commands used in macros created
with the macro system. The Dexterity online help contains a complete
description of each macro command. Keep in mind that this information is
intended to serve only as a reference when you’re examining or editing the
contents of a macro file. It is not intended that you use this information to
write your own macros from scratch.

Category Macro command


Commands CommandExec
Conditional execution ClearAllVars
ClearVar
IfDefined...EndIf
IfNotDefined...EndIf
SetVar
Layout windows TNT_Event
Macros DCommandBarAll
DContextMenu
DField
DIELinksAll
DWin
DumpField
DumpFieldBegin...DumpFieldEnd
DMenu
DMenuAll
Logging
MacroError
Pause
SetEbDateTo
SetEbTimeTo
SetExitAction
TableDump
Menus MenuSelect
Context menus ContextMenu
Native dialog commands FileOpen
FilePath
FileSave
FileSaveAs
PrintDialog
Forms OpenForm
Shell ShellCommand

312 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 4 T E S T I N G Y O U R A P PL I C A T I O N

Category Macro command


Scrolling windows ScrollByLine
ScrollByPage
ScrollToEnd
TransLinePrepare
Windows ActivateWindow
CheckActiveWin
CloseWindow
NewActiveWin
WindowMove
WindowSize
Window fields CheckFocusSpring
ClickCancel
ClickHit
ClickHitMS
ColSortAsc
ColSortDes
ContNatTypeTo
ContTypeTo
DblClickHit
MoveTo
NatTypeTo
SelChanged
SelectAccel
SelectChars
StateClick
ToggleNode
TypeTo

PROGRAMMER’S GUIDE VOLUME 2 313


314 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 35: Creating an International Product
This portion of the documentation provides information to consider when
developing a Dexterity-based application for an international market. It’s a
good idea to plan your internationalization strategy as you begin designing
your application. When doing so, consider the following issues.

• In which locales do you plan to market your application and how


different are they from one another?

• If the locales are significantly different, do you need to consider


translating the software for each version?

We recommend researching these issues thoroughly. Your own level of


international marketing will determine to what extent you incorporate
strategies to accommodate international accounting practices in your initial
application.

Information about creating an international product is divided into the


following sections:

• Locales
• Designing for eventual translation
• Window design
• Report design
• Coding issues
• International defaults file settings

PROGRAMMER’S GUIDE VOLUME 2 315


PA RT 7 S O F TW A R E E N G I N E E R I N G

Locales
You may wish to think of potential international markets in terms of locales,
not as countries or languages. Some countries may encompass several
languages within their borders, and some languages may be used in
different ways, depending upon the country. Similarly, some locales may
encompass more than one country, depending upon the product being sold.
In addition to language differences, different locales may handle currencies,
dates and times differently.

For example, if you plan to market your application in the United States
and Canada, you may need to make relatively few changes to your
application’s interface to customize the product for either locale. You may
need to update a few string resources to ensure that appropriate
terminology is used – such as “cheque” in Canada and “check” in the
United States. You also may wish to incorporate multicurrency
functionality to enable your customers to handle transactions in either
Canadian or United States dollars, but you wouldn’t have to do so unless
your customers are likely to engage in international business.

However, marketing your application in both the United States and Mexico
would probably require more interface changes, because the official
languages and the currency denominators are different. If you design with
both locales in mind from the beginning, you may be able to minimize the
effort and resources required to adapt your product later.

Even if the interface changes are relatively minor, you may need to significantly
revise parts of your application if it deals with taxes or payroll. Be sure to research
these issues thoroughly when you’re localizing your application.

The process of preparing your application for customers in a particular


locale is sometimes called localization. Localization includes topics such as
translating text and revising graphics. In addition, localization includes
making changes to the application’s functionality to reflect local accounting
practices.

Internationalization is anything you do to your initial product to make the


process of localization easier and faster. Most of the topics addressed here
are related to internationalization.

316 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 5 C R E A T I N G A N I N TE R N A T I O N A L PR O D U C T

Designing for eventual translation


The most visible difference between different language versions of the same
application may be in the translation of the interface text.

Minimizing translation errors


The following design tips can help to minimize potential translation errors:

• Avoid non-standard grammatical construction when


writing messages.
Such messages are more likely to be translated incorrectly. It’s best to
use short, unambiguous sentences that are written without technical
jargon. Be sure that messages describe what’s happening from the
user’s point of view – not the computer’s.

• Avoid “building” messages by concatenating several


different messages.
The individual messages will be translated separately, without regard
to all the situations in which they will appear. If the sentence structure
of the target language is different from that of the language in which
you’re creating your application, the final appearance of a concatenated
message will most likely be incorrect.

• Avoid using the same word for multiple situations with


different meanings.
If a language uses two separate words for those two concepts, it would
be impossible to translate the message correctly for all situations. For
example, the word Period refers both to an amount of time for which
accounting data is tracked and to a type of currency separator.

Minimizing string overflow problems


A well-designed application should minimize the potential problems
associated with translating the interface text.

• When defining string fields, allow more storage than you


need for the English version.
English text commonly expands by about thirty to fifty percent when
translated into other languages. For example, if the English version of
an application requires a string that’s 22 characters long, you may wish
to define it as a 30-character string instead.

• Allow extra space for prompts.


Typically, this means making the area for the prompt thirty to fifty
percent wider than required for an English prompt.

PROGRAMMER’S GUIDE VOLUME 2 317


PA RT 7 S O F TW A R E E N G I N E E R I N G

Using appropriate sorting methods


Depending upon the language you’re translating to and from, you may
need to provide alternate sorting methods. For example, you’ll probably
use ASCII values when sorting the English alphabet. However, languages
that use accented characters that appear in the extended character set – such
as å or ç – typically aren’t sorted correctly when using the ASCII sequence.

Refer to the description One way to addresses this problem is by adding the International=TRUE
of the International setting to the defaults file and adding an alternate collating sequence text
defaults file setting in file, DEX.ACS, to the same directory where the RUNTIME.EXE file is
the Dexterity online located. The .ACS file provides a list of how the characters ought to be
help for more sorted. As long as the .ACS file is in the correct location and International is
information about set to TRUE, any new tables that are created will use the alternate collating
using alternate sorting sequence. Existing tables must be shrunk to enable the alternate collating
sequences. sequence.

Accommodating local business practices


In some cases, local business practices may also require changes in the
application’s functionality. You may wish to do market research in your
target locales to determine which parts of your application may need to
change and try to anticipate those needs as you complete your initial
design.

Window design
Many of the issues discussed in Designing for eventual translation on
page 317 describe changes that will appear in windows in your application.
These issues may be more immediately relevant if you’re in the process of
preparing your application for international markets. However, keeping
these topics in mind as you begin designing your application will help
make future localization easier.

There are four aspects of window layouts that are likely to be different from
one locale to another.

• Allowing extra space for translated text


• Displaying accented characters
• Rearranging fields in a window
• Using graphics

318 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 5 C R E A T I N G A N I N TE R N A T I O N A L PR O D U C T

Allowing extra space for translated text


Translation of English to other languages typically increases the length of
the text by thirty to fifty percent. You can allow for this expansion by
making prompt boxes wider than required for English text. Also, try to
limit the length of the English text. This is especially important in contexts
where the amount of space is limited, such as the menu bar.

The actual space required for translated text depends largely upon the target
language, so your individual requirements may vary. Size these elements according
to your anticipated international needs, but recognize that you’ll probably need to
make additional changes to the interface regardless of your initial planning.

Displaying accented characters


Refer to the description Extended character sets may not always be displayed correctly, depending
of the upon the font that’s being used. If you find that characters such as Å or ç
NativeFontLeading aren’t displayed correctly in the Windows version of your application, add
and the Font defaults the NativeFontLeading=TRUE setting to the defaults file. This setting
file settings in the changes the way fonts are displayed, allowing extra vertical space to
Dexterity online help accommodate accented uppercase letters.
for more information.
Rearranging fields in a window
Some window fields may need to be repositioned to accommodate local
standards for data entry or accounting functions. Translating text may
require changes to window design, since the size of the text may increase.

Using graphics
When designing graphic elements or icons, be aware that some images may
be offensive or inappropriate in certain cultures or contexts. We recommend
that you verify that the graphics in your application are appropriate for the
target country.

PROGRAMMER’S GUIDE VOLUME 2 319


PA RT 7 S O F TW A R E E N G I N E E R I N G

Report design
Some of the issues discussed in the Application design section of this chapter
directly affect the layout and functionality of reports in your application.
These issues may be more immediately relevant if you’re in the process of
preparing your application for an international market. However, keeping
these topics in mind as you begin designing your application will help
make future localization easier.

There are six aspects of report layouts that are likely to be different from one
locale to another.

• Allowing extra space for translated text


• Rearranging fields on a report
• Adjusting for different standard paper sizes
• Verifying calculated fields and restrictions
• Using graphics

Allowing extra space for translated text


Translation of English to other languages typically increases the length of
the text by thirty to fifty percent. You can allow for this expansion by
making the columns for your data wider than required for English text.

The actual space required for translated text depends largely upon the target
language, so your individual requirements may vary.

Rearranging fields on a report


Some report fields may need to be repositioned to accommodate local
standards for reporting.

Adjusting for different standard paper sizes


The standard Dexterity Report Writer text report layouts work best with 8.5
x 11-inch (216 x 279 mm) paper. If you’re planning to market your
application in a locale that uses A4 (210 x 297mm) paper instead, you may
need to adjust the locations of fields on the report to ensure that they’re
printed correctly.

You also can adjust the report layout by marking the Best Text Fit option in
the Dexterity Report Definition window. Reports will take longer to print if
this option is marked, so it’s better to rearrange the layout so the report can
be printed in normal text mode.

320 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 5 C R E A T I N G A N I N TE R N A T I O N A L PR O D U C T

When you display graphics report layouts, guides will indicate the correct
margins for the currently-selected printer and page size. You can use these
guides to reposition fields on the report. Be aware that a graphics report
created according to the specifications for a particular printer may not be
printed correctly when using a different printer. It’s best to create graphics
reports only when you can be sure of the type of printer that will be used to
print the report.

Verifying calculated fields and restrictions


If you’ve created calculated fields or restrictions based upon the value of a
string or message, be sure to translate any necessary text in the calculated
expressions and restriction expressions. Be sure to verify that your
calculated fields and restrictions still work after you’ve completed the
translation process.

Using graphics
As with graphic elements used in windows, be aware that some images
may be offensive or inappropriate in certain cultures or contexts.

Coding issues
This section addresses common coding issues to consider as you’re
completing initial development. By planning your development carefully,
you’ll be able to write scripts for your application that will require minimal
adaptation for international markets and allow you to shorten development
time for those additional markets.

String-related issues
String-related coding issues typically arise when translating an application
into another language in the process of localization. By following the
guidelines listed here, you will minimize the amount of additional effort
required to localize your application.

• Use message resources instead of hard-coding strings or


other text that will appear in windows.
Hard-coded strings can’t be transferred to a text file for translation, like
string and message resources can be. To translate hard-coded strings,
you’ll need to examine the source code for each of your scripts,
translate the appropriate messages and recompile them – a time-
consuming and error-prone process. It’s best to use message resources
for strings that will appear in a window or on a report.

PROGRAMMER’S GUIDE VOLUME 2 321


PA RT 7 S O F TW A R E E N G I N E E R I N G

Dexterity will display compiler warnings every time you use a hard-coded
string in a script.

• Don’t concatenate messages together.


When using message resources, don’t concatenate messages together to
form new messages. Instead, create a complete message for each
unique message that will be used in your application.

• Use integer values instead of strings or messages in


scripts.
Using strings or messages to set values in scripts may result in string
overflow errors if the translated strings and messages are longer than
the original resources. For example, if you have the following script
statement and the value of message 1000 is translated to a word that
contains 12 characters, a string overflow error will result.

'Transaction Source' = getmsg(1000);


{where Transaction Source is a string 10}

You can avoid string overflow errors by storing the integer value of the
message, rather than the message resource itself, as shown in the
following example.

'Transaction Source' = 1000;


{Transaction Source is an integer}

In this example, when you display the transaction source in a window


or print it on a report, you’d need to use local or calculated fields to
retrieve and print the value of the message, rather than the integer
value that’s stored in the table.

• Keep in mind that all message resources in the dictionary


will be translated.
If you create an international version of your application, keep in mind
that all messages resources will be translated to the target language. To
prevent potential problems, don’t store the content of message
resources in tables. After messages are translated, the data previously
stored in tables won’t be compatible with the translated version.

• Use constants for strings that will not be translated.


If you must store constant string values in tables, create constants for
the values that will be stored. Constants are not translated when
creating an international version of an application.

322 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 5 C R E A T I N G A N I N TE R N A T I O N A L PR O D U C T

• Use a pragma to turn off warnings for scripts that contain


hard-coded strings.
In some cases, it’s necessary to use hard-coded strings in a script. When
you compile scripts that contain hard-coded strings, Dexterity will
produce compiler warnings. For situations where you must use hard-
coded strings, these compiler warnings don’t provide any benefit. You
can use a pragma to turn them off within a specific script.

For example, the following script contains a pragma to turn off


compiler warnings for hard-coded strings. Notice that after the hard-
coded string is used, the warning for hard-coded strings are turned
back on.

pragma(disable warning LiteralStringUsed);


set 'Mode' to "Internal";
pragma(enable warning LiteralStringUsed);

If a script contains many hard-coded strings, you may want to use a pragma at
the beginning of the script to turn off the literal string warnings, and then
turn them back on at the end of the script.

• Use functions to retrieve physical and technical names.


If you need to use physical names or technical names in your scripts,
such as for pass-through SQL, don’t hard-code them. Instead, use the
physicalname() and technicalname() functions to retrieve names
within a script.

PROGRAMMER’S GUIDE VOLUME 2 323


PA RT 7 S O F TW A R E E N G I N E E R I N G

Currency and date issues


In many cases, currency and date formats will be handled seamlessly by the
Dexterity system, provided your application uses the operating system’s
control panel settings.

• Specify currency and date formats using the operating sys-


tem’s control panel.
The Dexterity system allows you to specify the number of decimal
places for currency data types. For international use, your customers
may want to use the default control panel settings instead.

• Allow room for international date formats.


When you’re placing date fields in a window or report layout, be sure
to allow room for international date formats. If you’ve used a short date
format, a portion may be truncated when it’s converted to a long date.
For example, if you use a date format that includes only the last two
numbers of the century, allow extra space when converting it to a
format that includes the entire century.

• If necessary, add support for multicurrency transactions.


If your application will support multicurrency transactions, you will
have to add this capability to your application. Typically, your
application will use a functional currency and then use exchange rates
for the other currencies you’re supporting. To help you implement
multicurrency functionality in your applications, Dexterity provides
the following tools:

The Currency function library allows you to define your own custom
currency formats. Refer to the currency function library in the Dexterity
Script Reference manual or the Dexterity online help for more
information about these functions.

The Multiple Format Selector allows you to apply custom currency


formats to window fields and report fields. Refer to Chapter 7,
“Formats,” in Volume 1 of the Dexterity Programmer’s Guide for more
information about the Multiple Format Selector.

Dexterity doesn’t provide built-in support for the following


multicurrency features; you will need to add them to your application if
you wish to support them.

• Currency conversion routines.


• Exchange rate setup and expiration dates.
• Storage and retrieval capability for multicurrency transactions.

324 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 5 C R E A T I N G A N I N TE R N A T I O N A L PR O D U C T

International defaults file settings


The following table lists the defaults file settings that are useful when
internationalizing an application. Refer to the Dexterity online help for a
full description and example of each setting.

Setting Result
International TRUE: Specifies that the application will use the alternate
collating sequence.
FALSE: Specifies that the application will use the standard
ASCII collating sequence. False is the default value.
NativeFontLeading TRUE: Specifies that the application will use the full native
font height (leading) in Windows.
FALSE: Specifies that the application will use a shortened
font height in Windows. False is the default value.
Font This setting allows you to specify equivalent Central
European fonts for each of Dexterity’s built-in fonts. Valid
settings include:
FontArial=Arial CE
FontCourier New=Courier New CE
FontTimes New Roman=Times New Roman CE
Tolerance -1: Allows you to prevent reports from using a printer’s built-
in font. Use this setting in conjunction with the Font setting
to ensure that Central European fonts will be used when
printing reports.

PROGRAMMER’S GUIDE VOLUME 2 325


326 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 8: COM
Part 8: COM
This part describes Dexterity’s support for COM, the Component Object
Model. COM allows Dexterity-based applications to easily integrate with
other applications. Following is a list of the topics that will be discussed,
with a brief explanation of each:

• Chapter 36, “Introduction to COM,” describes Dexterity’s support for


COM.

• Chapter 37, “COM Libraries,” explains how to view COM library


information for applications, and link to the libraries from your
application.

• Chapter 38, “Referencing COM Objects,” describes how to create


references to COM objects.

• Chapter 39, “COM in sanScript,” describes how to work with COM in


sanScript code.

• Chapter 40, “Callbacks and Events,” explains how to create callback


objects that can be accessed by other application. It also explains how to
handle COM events from other applications.

328 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 36: Introduction to COM
Integrating with other applications can be challenging. To make integration
easier, support for the Component Object Model (COM) has been
implemented in Dexterity. Information about COM is divided into the
following sections:

• Automation
• Classes and objects
• Events

Automation
Automation is the general term that describes how applications use COM to
interact with each other. An application can act as an automation server or an
automation client.

• An automation server allows other applications to use COM to access


the server application’s data and resources.

• An automation client is an application that accesses the data and


resources of an automation server. The automation client must be
produced with a development system that supports COM.

Dexterity-based applications can act both as automation servers and


automation clients. All Dexterity-based applications implement a COM
interface that allows them to be controlled by automation clients. This COM
interface is more commonly known as the Continuum interface.

When a Dexterity-based
application acts as an automation
server, other COM-enabled COM-enabled Dexterity-based
applications can control it. application application

PROGRAMMER’S GUIDE VOLUME 2 329


PA RT 8 C O M

Dexterity-based applications can act as automation clients, controlling and


accessing the data of other COM-enabled applications like Microsoft Excel®
and Microsoft Word.

When a Dexterity-based
application acts as an automation
client, it can control other COM- Excel
Dexterity-based
enabled applications such as Excel.
application

Classes and objects


A class is a list of related methods and properties that are used together to
work with a specific item or task. For example, a class may contain methods
and properties used to work with a word processing document. An object is
an instance of a class. It is a combination of data for an item, such as a word
processing document, and the properties and methods used to work with
the item.

Applications that implement COM typically have classes for each of the
items you can work with in the application. You will use the appropriate
class to create an object for each item you want to work with. Once the
object is created, you will use the object’s methods and properties to
interact with the object. For example, Microsoft Excel has classes for each of
the items you typically work with, such as worksheets and charts.

Worksheet Object
An application creates an
object for each item that it will
work with. Objects are based
on the classes implemented
Application
by the COM application.
Chart Object

In your Dexterity-based application, you will use the Class Browser


window to examine the classes an application makes available through
COM. The Class Browser lists the properties and methods available for each
class.

330 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 6 IN T R O D U C T IO N TO C O M

Events
Applications that provide access through COM may also implement events,
which can notify other applications when specific actions occur. For
example, Microsoft Excel provides several workbook events that allow
other applications to be notified when certain activities occur for
workbooks.

Your Dexterity-based application can receive notifications from other COM-


enabled applications. Refer to Chapter 40, “Callbacks and Events,” for more
information.

PROGRAMMER’S GUIDE VOLUME 2 331


332 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 37: COM Libraries
Most COM-enabled applications provide a library that describes the
classes, methods, and properties that are provided by the application. The
information in the library tells other applications how to access resources
through COM. Information about COM libraries is divided into the
following sections:

• Type libraries
• Referencing type libraries

Type libraries
A type library is a special type of file that uses a standard format to describe
the interfaces, classes, methods, properties, and events an application
makes available through COM. Most applications that implement COM
will provide a type library that describes the implementation.

Type library files have the file extension .TLB or .OLB. It’s also possible for
type library information to be embedded into executable files or DLLs.
When a COM-enabled application is installed, it typically adds an entry to
the Windows Registry that tells the system where the type library
information for the application can be found. This makes it easy for other
tools, such as Dexterity, to find out what COM-enabled applications are
installed on the current system.

The information in a type library is useful when you are developing an


integration to a COM-enabled application. Development tools like
Dexterity can use the information in the type library to verify the code you
write. With this information, Dexterity can ensure that you use correct
names for the properties and methods. It can also verify that the values
used for COM methods and properties have the appropriate parameter
types.

Referencing type libraries


‘To access a COM-enabled application, you must create a reference to its
type library. This reference tells Dexterity where to look for the necessary
COM information as you are developing your application. You can add a
library reference once for an entire dictionary, or you can add a reference
that applies only to the current script.

PROGRAMMER’S GUIDE VOLUME 2 333


PA RT 8 C O M

Adding to a dictionary
Use the Library Definition window to add a COM type library reference to
the current dictionary.

1. Open the Library Definition window.


In the Resource Explorer, choose Libraries in the Base group for the
current dictionary. Click the New button in the Resource Explorer to
create a new library reference.

2. Select the library type.


Choose COM Type Library as the library type to be added.

3. Select a registered type library or type library file.


Click the Name lookup button to open the COM Type Libraries
window, which lists all of the type libraries that have been registered on
the current machine. Select the appropriate library and click Select.

If the type library file hasn’t been registered, click the Path lookup
button in the Library Definition window. Use the File dialog to select
the type library file for the application you want to reference.

334 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 7 C O M L I B R A R I E S

4. Save the type library reference.


Click OK to save the type library reference.

Once the type library reference has been added to the dictionary, the Data
Type Definition window, and all scripts in the application will be able to
access the information in the type library.

Adding to a script
To add a type library reference to a specific script, you will use the import
statement. This statement creates a reference to the specified type library
file, allowing the current script to access the methods, properties, and other
items described in the type library file.

Typically, you would use the import statement only if you were using the
COM functionality in a limited number of scripts in your application, or
were using pass-through sanScript. In all other cases, we recommend
creating a type library reference for the entire dictionary.

PROGRAMMER’S GUIDE VOLUME 2 335


336 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 38: Referencing COM Objects
When you create an integration using COM, you will need to create
references to COM objects in that application. Dexterity uses the Reference
data type for this purpose. A reference is one of two types: COM or Generic.
Information about referencing COM objects is divided into the following
sections:

• COM references
• Generic references
• Creating COM references

COM references
A COM reference is also known as a “typed” reference, because it can refer
only to a COM object of a specified type. When you create a COM reference,
you must specify the class of the item that the reference will refer to. For
example, you could create a COM reference that refers to an Excel
workbook. The type library for an application specifies the types of objects
a COM reference can refer to in that application.

Because a COM reference contains type information, checking can be done


at compile-time to verify that the reference always refers to an object of the
specified type. If a COM reference refers to an object that isn’t the
appropriate type, a compiler error will result.

Using COM references can also improve the performance of your COM
integration. Because COM type information is contained in the reference,
the script compiler can use “early binding”. This means all of the necessary
information to connect to the specified object must be retrieved only once,
when the script is compiled.

PROGRAMMER’S GUIDE VOLUME 2 337


PA RT 8 C O M

Generic references
Refer to Chapter 25, A generic reference is also known as an “untyped” reference. It can refer to
“References,” for more any type of COM resource. It could also refer to a resource in the
information about application dictionary, such as a table or window. Prior to Dexterity 7.0, all
using generic references were generic references.
references.
We don’t recommend using generic references to refer to COM objects.
Generic references to COM objects must be used carefully. Because these
references contain no type information, there is no compile-time checking
to verify the reference is being used correctly. If a reference refers to a
different type of object than you are expecting, a runtime exception may
occur.

Your application may not perform as well if you use generic references,
because the information necessary to connect to the specified object isn’t
available at compile-time. Generic references always use “late binding”,
where the information to connect to the specified COM object must be
retrieved at runtime.

Creating COM references


Before you can create references to COM objects, you must link to the type
library that describes the objects to which you want to make references.
Creating a link to a type library is described in Chapter 37, “COM
Libraries.”

Data types
Both global and local data types can refer to COM objects. To create a data
type that refers to a specific type of COM object, use the following
procedure.

1. Create a new data type.


Use the Data Type Definition window to create a new global data type,
or the Local Field Definition window to create a data type for a local
field.

2. Specify a Reference control type.


In the Control Type drop-down list, specify Reference.

3. Select the type of reference.


Use the Reference Type drop-down list to specify COM Object as the
reference type.

338 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 8 R E F E R E N C I N G C O M O B J E C T S

4. Select the COM object to refer to.


Click the COM Object Type lookup button to display the Class Browser
window. Use this window to indicate the type of COM object to refer to.
For example, the following illustration shows creating a reference to an
Acrobat PDF document.

Click Select. The name of COM object type you selected will appear in
the COM Object Type field.

5. Save the data type.


Click OK to save the COM Reference data type. The following
illustration shows the data type that refers to an Acrobat PDF
document.

PROGRAMMER’S GUIDE VOLUME 2 339


PA RT 8 C O M

Script variables and parameters


You can create local variable and script parameters that refer to COM
objects. To do this, simply use the COM object type in the declaration of the
variable or parameter. For example, the following is the declaration of a
local variable that can refer only to an Acrobat PDF document.

local Acrobat.CAcroAVDoc current_document;

Notice that the type used for the variable is Acrobat.CAcroAVDoc, which
indicates the variable can refer only to objects that are of the type
CAcroAVDoc as defined in the Acrobat type library.

You can use the Class Browser window from within the Script Editor to
make looking up COM object types much easier. This is described in Class
Browser on page 345.

340 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 39: COM in sanScript
Most of the interaction with a COM-enabled application is controlled
through sanScript code. This portion of the documentation describes the
various aspects of utilizing COM within scripts. Information is divided into
the following sections:

• Objects
• Properties and methods
• Constants
• Data type conversion
• Class Browser
• Collections
• COM exceptions
• Debugging COM integrations

Objects
Typically, the first action a script must perform when working with a COM-
enabled application is to create or retrieve an object to work with.

Creating objects
There are two ways of creating objects: the new statement and the
COM_CreateObject() function. The following example shows how to use
the COM_CreateObject() function to create a new instance of Microsoft
Word.

local Word.Application app;

app = COM_CreateObject("Word.Application");
if app = null then
error "Could not create Word application object.";
end if;

PROGRAMMER’S GUIDE VOLUME 2 341


PA RT 8 C O M

Whether you use new or COM_CreateObject() will depend on how the


object is being created and will be used. Note the following differences
between the two techniques:

• The new statement uses a COM reference to specify the COM object to
create, while the COM_CreateObject() function uses a string value.
This means the object type can be verified at compile-time for the new
statement.

• The COM_CreateObject() function allows you to implement


Distributed COM (DCOM) by specifying the machine on which the
COM object will be created. The new statement doesn’t allow the
machine to be specified.

Only certain objects can be created with the COM_CreateObject() function


or the new statement. Most objects must be created using methods
provided in the COM library for the specific application. For example, in
Microsoft Excel you can’t use the following statement to create a chart:

chart = new Excel.Chart();

Instead, you must use the Add() method for the workbook object:

chart = workbook.Charts.Add();

Guidelines
Keep in mind the following guidelines when creating objects:

• Use COM_CreateObject() to create application objects by name, and


when using Distributed COM (DCOM). Otherwise, use the new
statement to create application objects.

• When possible, use methods within a library to create additional


objects.

• If a library doesn’t contain methods to create new objects, try the new
statement to create the object.

• If the new statement doesn't work to create an object, then use the
COM_CreateObject() function.

342 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 9 C O M I N S A N S C R I P T

Retrieving objects
In some cases, the application you want to interact with may already be
running. You can use the COM_GetObject() function to retrieve an object
for an application that is already running.

local Excel.Application app;

{Retrieve a reference to a running instance of Excel.}


app = COM_GetObject("Excel.Application");
if app = null then
warning "Excel is not running.";
end if;

Destroying objects
When you have finished working with a COM object, you should properly
dispose of the object. Dexterity keeps track of how many times a specific
object is being referenced. An object will exist as long as there is a valid
reference to it.

A reference to an object is cleared automatically when the field or variable


goes out of scope, such as a script ending or a form being closed. You can
explicitly destroy a reference to a COM object by setting it to null, or by
using the clear statement.

Properties and methods


To access COM properties and methods from sanScript, use the dot notation
similar to that used by Visual Basic. For example, the following sanScript
statement accesses the ActiveWorkbook property and the Calculate()
method for an Excel workbook:

local Excel.Application app;


local Excel.Workbook workbook;

app = COM_GetObject("Excel.Application");

{Use the ActiveWorkbook property to retrieve the active workbook}


workbook = app.ActiveWorkbook;

{Use the Calculate() method to recalculate the workbook)


workbook.Calculate();

PROGRAMMER’S GUIDE VOLUME 2 343


PA RT 8 C O M

If a COM method has optional parameters that you don’t want to supply,
you can use the none keyword in place of the parameter value. If the
optional parameters are at the end of the parameter list, you can simply
exclude them from the method call.

Constants
Many COM libraries provide constant values you can use while working
with the properties and methods in the library. To use a constant from the
library, use the dot notation to indicate the library that defines the constant.
The following example uses the wdWindowStateMinimize constant to
minimize the active window in Microsoft Word. Notice that the constant
uses the dot notation to qualify that it is defined in the Word object library.

local Word.Application app;


local Word.Window active_win;

{Retrieve a reference to Microsoft Word}


app = COM_GetObject("Word.Application");

{Minimize the active window}


active_win = app.ActiveWindow;
active_win.WindowState = Word.wdWindowStateMinimize;

Always use COM constants when possible. They make your COM code much
easier to read.

Data type conversion


When using COM from sanScript, the data types you use for variables and
fields must be compatible with the COM properties and methods you are
accessing. The following table lists the Dexterity data types and the
corresponding COM types.

Dexterity type COM type Description


Boolean VT_BOOL Boolean
Byte VT_UI1 Unsigned character
Integer VT_I2 Short
Long VT_I4 Long
String VT_BSTR String
Text
Currency VT_CY Currency

344 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 9 C O M I N S A N S C R I P T

Dexterity type COM type Description


Vcurrency VT_R4 Single
VT_R8 Double
VT_DECIMAL Decimal
Date VT_DATE Date
Time
Datetime
Reference VT_DISPATCH IDispatch*
A typed COM reference VT_UNKNOWN IUnknown*

Class Browser
The Class Browser window is useful for looking up COM methods,
properties, and constants while you are writing scripts. From the Script
Editor, you can access the Class Browser window by choosing Class
Browser from the Script menu.

The description for the


selected item appears
here.

Select the COM library from which you want to look up information. Use
the Classes and Members lists to select individual items. A description of
the selected item appears at the bottom of the window. Click Copy to copy
the fully-qualified name of the selected item to the clipboard. You can paste
the name into the current script.

Some COM libraries provide online help that describes the members in the
library. If help for a specific library is installed, the Help button will be
enabled in the Class Browser window.

PROGRAMMER’S GUIDE VOLUME 2 345


PA RT 8 C O M

Collections
In COM, objects of the same type are often grouped into special objects
called collections. For example, Microsoft Excel has a Workbooks object,
which is a collection of all of the open workbooks in the application.

In many development tools such as Visual Basic, items in a collection can be


accessed directly using the standard subscript notation. You do not need to
use an additional property or method to access the items in a collection. You
can just use the collection as the method or property to retrieve the item.
For example, the following Visual Basic code retrieves the first item from
the Fields collection of an ADO recordset.

{Visual Basic code to retrieve a field from a recordset.}


local ADODB.Field dbField;
dbField = recordset.Fields(1);

You cannot directly access the values of a collection from sanScript. Instead,
you must use additional properties and methods to access the items in a
collection. Often the Item method or the Item property can be used to
access the items in a collection. For example, the following sanScript code
retrieves the first item from the Fields collection of an ADO recordset.
Notice that the Item property must be used to access the item in the
collection.

{sanScript code to retrieve a field from a recordset.}


local ADODB.Field dbField;
dbField = recordset.Fields.Item[1];

In many cases, the Item method or property is hidden, so it won’t be visible in the
Class Browser window until you mark the Show Hidden option.

COM exceptions
The COM integrations you write may encounter errors (exceptions) as they
run. Use the exception handling capability in Dexterity to deal with COM
exceptions that occur. To learn more about exception handling, refer to
Chapter 26, “Structured Exception Handler.”

346 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 9 C O M I N S A N S C R I P T

Whenever a COM exception occurs in sanScript code, a system exception is


thrown. The constant EXCEPTION_CLASS_OBJECT_EXCEPTION
represents any COM exception thrown by Dexterity. The exception
subclass, returned by the Exception_SubClass() function, indicates the
actual COM exception that occurred.

To find what COM exception occurred, scroll down in the error dialog that
displays the COM exception. The exception subclass will be listed, and
indicates the error that occurred.

Scroll down to see the


exception subclass.

The following example attempts to minimize the active document in


Microsoft Word. If there isn’t an active document, a COM exception is
thrown indicating the action can’t be performed. The code catches the COM
exception (-2146824040), and displays an appropriate message.

local Word.Application app;


local Word.Window active_win;
local long exception_subclass;

{Retrieve a reference to Word}


app = COM_GetObject("Word.Application");

{Minimize the active window}


try
active_win = app.ActiveWindow;
active_win.WindowState = Word.wdWindowStateMinimize;
catch [EXCEPTION_CLASS_OBJECT_EXCEPTION]
{Find out what the subclass of the exception is}
exception_subclass = Exception_SubClass();

if exception_subclass = -2146824040 then


warning "No document is open.";
end if;
end try;

PROGRAMMER’S GUIDE VOLUME 2 347


PA RT 8 C O M

Debugging COM integrations


Developing a COM integration is an iterative process. You write some COM
code, test it, make needed changes, and test again. As you continue this
process, you may encounter a common problem where it appears that code
that worked previously has now stopped functioning. You may be tempted
to suspect your code, but the likely problem is a hidden instance of the
application you’re integrating with.

When you create a new COM reference to an application, an instance of that


application is created invisibly. If your Dexterity-based application
terminates abnormally, which is common during COM development, you
may leave instances of the other application running. When your code
doesn’t seem to be working, it likely is interacting with a hidden instance of
the application you’re integrating with.

If you’re having problems with a COM integration, use the Windows Task
Manager to list all of the processes currently running. If you see multiple
processes for the application you’re integrating with, use the End Process
button to terminate them, and then try your integration again. If you
continue to have problems, restart both Dexterity and the application
you’re integrating with to eliminate any COM communication issues.

Assemblies created with the .NET Framework


You can use the COM interoperability features of the Microsoft .NET
Framework to make the classes, properties and methods in a .NET
assembly available through COM. This allows applications that support
COM, such as Dexterity, to access the functionality available in these
assemblies. To make your .NET assemblies available through COM, do the
following:

1. Specify the items to be accessed through COM.


In the code for your assembly, you must properly structure and qualify
your classes, methods, and properties to have them be accessible
through COM. For assemblies created in C#, you must include a
reference to the InteropServices namespace.

using System.Runtime.InteropServices;

348 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 3 9 C O M I N S A N S C R I P T

Use attributes to specify the items you want to be accessible through


COM. For example, the following attribute indicates that the Customer
class will be available through COM.

[ClassInterface(ClassInterfaceType.AutoDual)]
public class Customer {
...
}

Your code must follow other guidelines for your assemblies to be accessible
from COM. Refer to the .NET Framework documentation for more
information about COM interoperability.

2. Build the assembly.


The attributes you added to your code will indicate which classes,
methods, and properties that will be available through COM.

3. Register the assembly.


Use the REGASM.EXE application to register all of the public classes in
the assembly. For example, the following command registers the
Customer.dll assembly.

regasm Customer.dll

4. Create the registry file for the assembly.


Using the REGASM.EXE application, create a .reg file that describes the
assembly. This file must be merged into the registry on your system.
The following command creates the .reg file for the Customer assembly.
regasm Customer.dll /regfile:Customer.reg

5. Create the type library for the assembly.


Using the REGASM.EXE application, create .tlb file that contains the
definitions of the public types in the assembly. The following command
creates the .tlb for the Customer assembly.
regasm Customer.dll /tlb:Customer.tlb

This is the type library you will reference from within Dexterity to
access the capabilities made available through COM.

The GUIDs in the registry (.reg) file and the .NET assembly must match for
the .NET assembly to be accessed. Be sure the .reg file is generated for the
assembly you are deploying.

PROGRAMMER’S GUIDE VOLUME 2 349


PA RT 8 C O M

When your application accesses the assembly you created with .NET, the
assembly should be located in the same directory as Dexterity or the
Runtime engine. Another option is to be sure the assembly is strongly-
named, so it can be added to the global assembly cache (GAC) where it can
be located by any application accessing it through COM.

To deploy the .NET assembly with your Dexterity-based application, you


must ship both the .NET assembly and the .reg file. It is not necessary to
ship the .tlb file. On the target system, the .reg file must be run so that its
registry entries it contains are added to the system on which the application
is being run.

350 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 40: Callbacks and Events
You can create callback objects in your Dexterity-based application. Like any
other COM objects, callback objects have properties and methods that you
define. Other applications use COM to access the properties and methods
in the callback object. Callback objects are used for the following:

• They allow other applications to access functionality in your


application through COM.

• They allow you to create event handlers so your application can be


notified of events that occur in other applications.

Information about using callbacks is divided into the following sections:

• Callback objects
• Accessing callback objects
• Events
• Creating an event handler

Callback objects
Callback objects are created at runtime, using several functions from the
Dexterity object function library. To create a callback, you must create the
callback object, add methods and properties, and make the object available
to other applications.

Creating a callback object


Use the DexObject_Create() function to create the callback object. This
function returns a reference to the callback that is created. An application
can have multiple callback objects, so you should store this callback
reference in a location where it can be stored safely and easily retrieved.
You will need to use the reference when you add properties and methods to
the callback.

Adding properties
To add properties to the callback object, use the DexObject_AddProperty()
function. Properties store specific data items in the callback object. Their
values can be set or retrieved by both the Dexterity-based application and
external applications accessing the callback object through COM.

PROGRAMMER’S GUIDE VOLUME 2 351


PA RT 8 C O M

Adding methods
To add methods to the callback object, use the DexObject_AddMethod()
function. Methods on the callback object can be called from the Dexterity-
based application, but are primarily called by other applications accessing
the callback object through COM. Methods are the primary way other
applications can initiate actions in your application.

When a method in the callback object is called, the corresponding user-


defined function in the Dexterity-based application is run. The parameters
for the method on the callback are determined by the parameters on the
user-defined function that runs in response to the callback method. Use the
following guidelines when specifying the parameter types for the user-
defined function:

• Use “in” parameters for values that will be passed from the external
application into the callback method.

• Use “inout” parameters for values that can pass values from the
external application into the callback method, and also return a value
from the method.

Making the callback object accessible


To make the callback object accessible to other applications, you must add it
to the running object table. The running object table is managed by the
operating system. It maintains a list of all COM objects that can currently be
accessed. Use the COM_RegisterRunningObject() function to add a
callback object to the running object table. When you use this function, you
specify the name that is given to the callback object. Use a name that
describes the application that created the callback, as well as the purpose of
the callback. Other applications must use this name to retrieve a reference
to the callback object.

Note that other applications have no way of determining the name of any
callback object, or the properties and methods that are part of the object. If
you want other applications to be able to access the callback objects you
create, you must provide documentation for the callback.

352 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 0 C AL LB A C K S A N D E V E N T S

Be sure to include the following:

• The complete name of the callback object. The name is case-sensitive.

• The names of the properties in the callback, along with their associated
data types.

• The names of the methods in the callback, along with the return value
(if any), the parameters for the methods, and their associated data
types.

Responding to method calls


The user-defined function that runs in response to a COM method call is the
code that actually performs the work of the method. Often, it’s useful to be
able to access the callback object from within the user-defined function that
is run for the method. To access the properties or methods for the current
callback object, use the this statement.

You can also throw exceptions in the user-defined function associated with
the method. Any exceptions you throw will be propagated back through
COM to the application that called the method in the callback object. For
example the following sanScript code in the user-defined function
associated with a method will produce a COM exception. The value 1001 is
passed as the exception class, and the value 1 is passed as the exception
subclass.
throw 1001, 1, "User not logged in";

We recommend that you use values greater than 1000, but less than 32,767 for the
exception class.

This example produces the following COM exception dialog in a Visual


Basic application.

Notice that the exception class is passed in as the error number, while the
exception subclass is enclosed in brackets and prepended to the exception
message.

PROGRAMMER’S GUIDE VOLUME 2 353


PA RT 8 C O M

Accessing callback objects


To access the callback object from an external application, you need to
retrieve a reference to it from the running object table. Then you can access
the properties and methods in the callback. For example, the following
Visual Basic code retrieves the “RESM.LoginInfo” callback object created by
a Dexterity-based application and accesses the properties in it.

Private Sub VerifyPassword_Click()


Dim LoginInfo As Object
Dim result As Boolean

'Retrieve a reference to the callback


Set LoginInfo = GetObject(, "RESM.LoginInfo")

'Set the properties


LoginInfo.UserID = "STEVEK"
LoginInfo.Name = "Steve"
End Sub

Events
Some applications that implement COM interfaces also provide events that
can notify other applications of specific actions. For example, Microsoft
Excel provides several events for worksheets that notify other applications
of actions such as a selection change in the worksheet. The Class Browser
window lists the events that an application is making available.

The Class Browser lists the


events that are provided by
an application.

354 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 0 C AL LB A C K S A N D E V E N T S

Creating an event handler


An event handler is the code needed in your application to be notified that a
COM event occurred. To create an event handler, you must do the
following:

• Create a user-defined function in Dexterity to respond to the event.

• Create a callback object and add a method to the callback object for the
event.

• Attach the event handler to the callback object.

User-defined function
You need to create a user-defined function for each event that you want to
be notified of. The function will run each time the event occurs in the
application you are integrating with. The parameters for the user-defined
function must match those specified for the event. For example, the
following is the description of the SheetSelectionChange event available
for an Excel workbook.

Notice that this event returns two parameters, but no actual return value for
the method. The first parameter is a reference to the worksheet for which
the event occurred. The second parameter is range of cells selected in the
worksheet.

The following user-defined function must be added to your Dexterity


application to process this event. Notice that the parameters and return
value correspond to those for the event. The parameters are in the same
order as the event, and of the appropriate type. The event doesn’t have a
return value, so the user-defined function indicates that nothing is
returned. The additional code in the callback function retrieves the row and
column of the new selection in the worksheet.

PROGRAMMER’S GUIDE VOLUME 2 355


PA RT 8 C O M

Function SelectionChangedEvent

function returns nothing;

in reference worksheet;
in Excel.Range selection;

local long current_row;


local long current_column;

{Retrieve the current row and column}


current_row = selection.Row;
current_column = selection.Column;

'(L) Selection' of window Tool_Bar of form 'Main Menu' =


➥ "Row:" + str(current_row) + " Column:" + str(current_column);

Callback object
To respond to a COM event from another application, you must create a
callback object that contains the method or property necessary for the
event. The name of the method or property in the callback must exactly
match the name of the event.

Continuing the previous example, the following code creates the callback
object to handle the SheetSelectionChange event. Notice in the
DexObject_AddMethod() function that the name of the method added to
the callback is the same as the name of the event. Also note that the
COM_AttachEventHandler() function is used to associate the event for the
active Excel worksheet with the corresponding callback object in the
Dexterity-based application.

local Excel.Application app;


local reference callback_obj;
local long handler_id;

{Retrieve a reference to Excel.}


app = COM_GetObject("Excel.Application");

if app <> null then


{Create the callback object to handle the event.}
callback_obj = DexObject_Create();

356 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 0 C AL LB A C K S A N D E V E N T S

{Add the method for the SheetSelectionChange event.}


DexObject_AddMethod(callback_obj, "SheetSelectionChange",
➥ function SelectionChangedEvent);

{Attach the callback object.}


handler_id = COM_AttachEventHandler(app.ActiveWorkbook,
➥ callback_obj);
if handler_id = 0 then
error "Could not attach event handler.";
end if;
end if;

Once the callback object has been created and attached to the event, your
application will begin receiving and processing events. Events will be
processed until either application is shut down, or you detach the event
handler with the COM_DetachEventHandler() function.

Responding to events
When an event occurs, the corresponding method will be called in the
callback object within the Dexterity-based application. Often, it’s useful to
be able to access the callback object from within the user-defined function
that is run for the event. To access the properties or methods for the current
callback object, use the this reference.

Troubleshooting
If the event handler isn’t processing events, check the following:

• Verify the name you used for the method in the callback exactly
matches the event name. The name is case-sensitive.

• Be sure the parameter list and return value for the user-defined
function match the parameter list and return value for the event. If the
parameter types don’t match, the event handler can’t be attached to the
callback object.

PROGRAMMER’S GUIDE VOLUME 2 357


358 P R O G R A M M E R ’ S G U I D E V O L U M E 2
PART 9: USING COM
Part 9: Using COM
This part contains specific information on using Dexterity’s COM
functionality to integrate with other Microsoft applications. The following
topics are discussed:

• Chapter 41, “Microsoft Word,” describes how to automate Microsoft


Word.

• Chapter 42, “Microsoft Excel,” describes how to automate Microsoft


Excel.

• Chapter 43, “Microsoft ADOX,” describes how to create new databases.

• Chapter 44, “Microsoft ADO,” describes how to access information in


databases.

• Chapter 45, “Microsoft Internet Explorer,” describes how to automate


Microsoft Internet Explorer.

• Chapter 46, “Microsoft Outlook,” describes how to automate Microsoft


Outlook®.

• Chapter 47, “Microsoft XML,” describes how to manipulate XML


documents.

360 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 41: Microsoft Word
To automate Microsoft Word, use the Microsoft Word Object Library.
Information about automating Word is divided into the following sections:

• Microsoft Word Object Library overview


• Declared variables
• Application object
• Document object
• Range object
• Paragraph object
• Table object
• Cell object
• Script example

The following examples are written for version 10 of the Microsoft Word
Object Library (Word XP). If you use a different version of the object library,
you may need to change the code to have it work properly.

Microsoft Word Object Library overview


The Microsoft Word Object Library contains objects, methods, and
properties that model the functionality of Word. This introduction to the
Microsoft Word Object Library does not describe every object. Instead, it
focuses on the following objects:

• Application object
• Document object
• Paragraph object
• Table object
• Cell object
• Range object

Refer to the help file for the Microsoft Word Object Library for a complete
description of all of the objects contained in the library.

To use the Microsoft Word Object Library, you should first create an
Application object with a sanScript function. For more information on
creating COM objects with sanScript functions, refer to Chapter 39, “COM
in sanScript.” You can create all of the other objects from methods provided
in the library.

PROGRAMMER’S GUIDE VOLUME 2 361


PA RT 9 U S I N G C O M

The following illustration displays the relationships between the objects


that are discussed.

You should create the


Application object
Application object first.
Document object

Paragraph object

Range object
Create the remaining Table object
objects from methods
provided in the library. Cell object

Range object

Range object

Range object

Declared variables
In the script examples, it is assumed that you have declared the following
variables:

Variable name Variable type


app Word.Application
document Word.Document
paragraph Word.Paragraph
wordTable Word.Table
cell Word.Cell
wordRange Word.Range

Application object
The Application object allows you to work with the Word application.

Creating the application


Use the new keyword to create a new instance of Word.

{Create a new instance of Word.}


app = new Word.Application();

362 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 1 M IC R O S O F T WO R D

When using Distributed COM (DCOM), create a new instance of Word with
the COM_CreateObject() function. In the following example, a new
instance of Word is created on the computer “SystemServer”.

{Create a new instance of Word.}


app = COM_CreateObject("Word.Application", "SystemServer");

Retrieving an existing application


Use the COM_GetObject() function to retrieve a running instance of Word.

{Retrieve a running instance of Word.}


app = COM_GetObject("Word.Application");

Showing and hiding an application


The Visible property from the Application object allows you to show or
hide an application. Setting the Visible property to true shows an
application.

{Show an application.}
app.Visible = true;

Setting the Visible property to false hides an application.

{Hide an application.}
app.Visible = false;

The new keyword and the COM_CreateObject() function return hidden


instances of an application. Use the Visible property to show a hidden instance of
an application.

Hiding and showing warning messages


When you integrate with Word, dialog boxes containing warnings can stop
the application. To hide or show warning messages, set the DisplayAlerts
property to the appropriate constant contained in the wdAlertLevel
enumeration. To hide all messages, set the property to wdAlertsNone.

{Hide messages.}
app.DisplayAlerts = Word.wdAlertsNone;

PROGRAMMER’S GUIDE VOLUME 2 363


PA RT 9 U S I N G C O M

To show all messages, set the DisplayAlerts property to wdAlertsAll.

{Show warning messages.}


app.DisplayAlerts = Word.wdAlertsAll;

Hiding warnings prevents the user from seeing the messages displayed by an
application. Your code must still handle the errors or other exceptional conditions
that caused Word to display warning messages.

Closing an application
After you have finished using an application, you can close it with the Quit
method.

{Close an application.}
app.Quit();

You can use constants contained in the wdSaveOptions enumeration to


specify whether currently open documents are saved when Word is closed.
The following table lists the available values and the behavior they specify.

Constant Behavior
wdDoNotSaveChanges Doesn’t save the changes in the open documents
wdSaveChanges Saves changes without prompting the user
wdPromptToSaveChanges Asks the user if they would like to save changes

{Save the open documents without prompting the user. Then close the
application.}
app.Quit(Word.wdSaveChanges);

Document object
The Document object allows you to work with a document. The
Documents collection contains all of the currently open documents in a
Word application.

Creating a new document


Use the Add method to create a new document and add it to the
Documents collection.

{Add a new document to the Documents collection.}


document = app.Documents.Add();

364 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 1 M IC R O S O F T WO R D

Opening an existing document


Use the Open method to open an existing document and add it to the
Documents collection.

{Open an existing document.}


document = app.Documents.Open("C:\RESM\RESM.DOC");

Retrieving an open document


You can retrieve an open document from the Documents collection with
the Item method by the number associated with the document.

{Retrieve the first document in the Documents collection.}


document = app.Documents.Item(1);

You can also retrieve documents by the name of the document.

{Retrieve the document named "RESM.DOC".}


document = app.Documents.Item("RESM.DOC");

Saving a document
To save a new document, use the SaveAs method.

{Save a new document.}


document.SaveAs("C:\RESM\RESM.DOC");

If you have previously saved a document, use the Save method to save the
document.

{Save an existing document.}


document.Save();

You can use the Saved property to find out if a document has been saved. If
the Saved property returns true, the document has been saved. Otherwise,
it has not.

{If a document has not been saved, save it.}


if(not document.Saved) then
document.Save();
end if;

You can also set the value of the Saved property. If you set the Saved property to
true without saving a document, any messages prompting you to save the
document are suppressed.

PROGRAMMER’S GUIDE VOLUME 2 365


PA RT 9 U S I N G C O M

Closing a document
Use the Close method to close a document. You can use the constants
contained in the wdSaveOptions enumeration to specify whether a
document is saved when it is closed.

{Save changes and then close a document.}


document.Close(Word.wdSaveChanges);

Range object
A Range object specifies an area in a document. Once you have created a
Range object, you can insert text, tables, and paragraphs into a document.

Specifying a range
You can use the Range method from the Document object to specify a
range in a document. You can specify the beginning and ending characters
of the range.

{Specify a range that includes the first ten characters in a


document.}
wordRange = document.Range(0,10);

If you do not specify beginning or ending characters, the returned range is the
entire document.

You can also use the Range property from a Paragraph object, a Cell
object, or a Table object to specify a range. The returned Range object
spans from the beginning to the end of the object associated with the
property.

{Creates a range that spans a paragraph.}


wordRange = paragraph.Range;

Inserting text
To insert text before a range, use the InsertBefore method.

{Insert "Customer List" before a range.}


wordRange.InsertBefore("Customer List");

366 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 1 M IC R O S O F T WO R D

To insert text after a range, use the InsertAfter method.

{Insert "Customer Name" after the range.}


wordRange.InsertAfter("Customer Name");

If you are inserting text after a range retrieved from a Paragraph object, the text
becomes part of the next paragraph.

Paragraph object
The Paragraph object allows you to work with the paragraphs in a
document. The Paragraphs collection contains all of the paragraphs in a
document.

Creating a new paragraph


Use the Add method to add a new paragraph to the document and to the
Paragraphs collection. The paragraph is added before the specified range.

{Add a new paragraph.}


paragraph = document.Paragraphs.Add(wordRange);

If a range is not specified, a paragraph is added at the end of the document.

You can add a new paragraph to the document with the InsertParagraph
method. The InsertParagraph method replaces the Range object with the
range of the new paragraph.

{Insert a new paragraph.}


wordRange.InsertParagraph();

You can also use the InsertParagraphBefore method or the


InsertParagraphAfter method to add a new paragraph. The
InsertParagraphBefore method inserts the paragraph before the range and
expands the Range object to include the range of the new paragraph.

{Insert a paragraph before the specified range.}


wordRange.InsertParagraphBefore();

PROGRAMMER’S GUIDE VOLUME 2 367


PA RT 9 U S I N G C O M

The InsertParagraphAfter method inserts the new paragraph in the


document after the range and expands the Range object to include the
range of the new paragraph.

{Insert a paragraph after the specified range.}


wordRange.InsertParagraphAfter();

Retrieving a paragraph
You can retrieve a paragraph from the Paragraphs collection with the Item
method by the number associated with the paragraph.

{Retrieve the third paragraph from the Paragraphs collection.}


paragraph = document.Paragraphs.Item(3);

You can use the First property to retrieve the first paragraph in the
Paragraphs collection.

{Retrieve the first paragraph from the Paragraphs collection.}


paragraph = document.Paragraphs.First;

You can use the Last property to access the last paragraph in the
Paragraphs collection.

{Retrieve the last paragraph from the Paragraphs collection.}


paragraph = document.Paragraphs.Last;

Formatting a paragraph
The Paragraph object contains several properties to modify the appearance
of a paragraph, such as the Alignment property and the Format property.

Alignment property Use the Alignment property to change the


horizontal alignment of a paragraph. To specify the alignment, use
constants contained in the wdParagraphAlignment enumeration.

{Center the paragraph on the page.}


paragraph.Alignment = Word.wdAlignParagraphCenter;

Format property The Format property returns a ParagraphFormat


object. The properties from the ParagraphFormat object, such as the
Hyphenation property, allow you to format the paragraph.

{Automatically hyphenate the paragraph.}


paragraph.Format.Hyphenation = true;

368 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 1 M IC R O S O F T WO R D

Table object
The Table object allow you to work with a table. The Tables collection
contains all of the tables in a document.

Creating a table
Use the Add method to add a new table to a document and to the Tables
collection. You must specify the location of the table as well as the
dimensions of the table.

{Add a table with eight rows and two columns.}


wordTable = document.Tables.Add(wordRange, 8, 2);

Retrieving a table
You can retrieve a table from the Tables collection with the Item method by
the number associated with the table.

{Retrieve the first table.}


wordTable = document.Tables.Item(1);

Formatting a table
The Table object contains several methods and properties to modify the
appearance of a table, such as the AutoFormat method, the Borders
property, the Shading property, and the Spacing property.

AutoFormat method The AutoFormat method allows you to specify a


predefined format for the table. Use a constant contained in the
wdTableFormat enumeration to specify the format of the table.

{Format the current table.}


table.AutoFormat(Word.wdTableFormatContemporary);

Borders property The Borders property returns a Borders collection


that contains all of the table borders. You can use the Borders collection to
set the properties for the borders, such as width and style.

Use the OutsideLineStyle property or the InsideLineStyle property and a


constant contained in the wdLineStyle enumeration to set the style of the
borders.

{Set the style of the outside borders of the table.}


wordTable.Borders.OutsideLineStyle = Word.wdLineStyleTriple;

PROGRAMMER’S GUIDE VOLUME 2 369


PA RT 9 U S I N G C O M

Use the OutsideLineWidth property or the InsideLineWidth property and


a constant from the wdLineWidth enumeration to set the width of the
borders.

{Set the width of the inside borders of the table to 0.25 points.}
wordTable.Borders.InsideLineWidth = Word.wdLineWidth025pt;

You can also access individual borders in a table with the Borders
collection. To specify a border, use the Item method and the constants
contained in the wdBorderType enumeration.

{Set the line style for the bottom border of the table.}
wordTable.Borders.Item(Word.wdBorderBottom).LineStyle =
➥ Word.wdLineStyleDouble;

Shading property The Shading property returns a Shading object. The


Shading object contains properties, such as the Texture property, that
modify the shading of the table. Use the Texture property and a constant
contained in the wdTextureIndex enumeration to set the texture of the
shading.

{Set the texture of the table’s shading.}


wordTable.Shading.Texture = Word.wdTextureDiagonalCross;

Spacing property The Spacing property sets the spacing between the
cells in the table. You must supply the spacing between the cells in points.

{Set the spacing between the cells in a table to 7 points.}


wordTable.Spacing = 7;

Cell object
The Cell object allows you to change the number of cells in a table as well
as to format individuals cell.

Retrieving a cell
To retrieve a Cell object from a table, use the Cell method. You need
specify the row and column number of the cell.

{Retrieve a cell from the third row and fourth column in a table.}
cell = wordTable.Cell(3,4);

370 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 1 M IC R O S O F T WO R D

Merging and splitting cells


Use the Merge method to merge two cells.

{Merge two cells.}


wordTable.cell(3,4).Merge(wordTable.cell(3,5));

To split a cell, use the Split method. You can supply the number of rows,
the number of columns, or both the number of rows and the number of
columns that you would like to create from the cell.

{Split the cell into two rows.}


wordTable.cell(1,2).Split(2);

Adjusting the dimensions of cells


To adjust the dimensions of a cell, use either the SetHeight method or the
SetWidth method. Use the SetHeight method to set the height of a cell. You
must supply the height of the row in points.

{Set the height of the cell to 24 points.}


wordTable.cell(1,4).SetHeight(24);

Use the SetWidth method to set the width of a cell.

{Set the width the cell to 30 points.}


wordTable.cell(4,5).SetWidth(30);

Fitting text in a cell


Use the FitText property to adjust the width of characters in a cell to the
width of the column. Setting the FitText property to true adjusts the width
of the characters.

{Fit the text in the column.}


cell.FitText = true;

Script example
The following example uses objects from the Microsoft Word Object Library
to create a table in a new document, RESM.DOC. The script adds a record
displayed in the Buyers window of the Real Estate Sales Manager
application to a row in the table.

PROGRAMMER’S GUIDE VOLUME 2 371


PA RT 9 U S I N G C O M

local Word.Application app;


local Word.Document document;
local Word.Table wordTable;
local Word.Range wordRange;

{If Word is running, use it. Otherwise, create a new instance.}


app = COM_GetObject("Word.Application");
if(app = null) then
app = new Word.Application();
end if;

{Make Word visible.}


app.Visible = true;

{Create a new document.}


document = app.Documents.Add();

{Add a table with two rows and four columns to the document.}
wordRange = document.Range(0,0);
wordTable = document.Tables.Add(wordRange, 2, 4);

{Set the values of the cells in the first row in the table.}
wordRange = wordTable.Cell(1,1).Range;
wordRange.InsertAfter("Buyer ID");
wordRange = wordTable.Cell(1,2).Range;
wordRange.InsertAfter("Buyer First Name");
wordRange = wordTable.Cell(1,3).Range;
wordRange.InsertAfter("Buyer Last Name");
wordRange = wordTable.Cell(1,4).Range;
wordRange.InsertAfter("Phone");

{If record is not displayed, warn user. Otherwise, add the record.}
if 'Buyer ID' = "" then
warning "Please display a record in the Buyers window.";
else
wordRange = wordTable.Cell(2,1).Range;
wordRange.InsertAfter('Buyer ID');
wordRange = wordTable.Cell(2,2).Range;
wordRange.InsertAfter('Buyer First Name');
wordRange = wordTable.Cell(2,3).Range;
wordRange.InsertAfter('Buyer Last Name');
wordRange = wordTable.Cell(2,4).Range;
wordRange.InsertAfter(Phone);
end if;

372 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 1 M IC R O S O F T WO R D

{Close the document and prompt the user for a document name.}
document.Close(Word.wdPromptToSaveChanges);

{Close the application.}


app.Quit();

{Clear the variables.}


clear wordRange;
clear wordTable;
clear document;
clear app;

PROGRAMMER’S GUIDE VOLUME 2 373


374 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 42: Microsoft Excel
To automate Microsoft Excel, use the Microsoft Excel Object Library.
Information about automating Excel is divided into the following sections:

• Microsoft Excel Object Library overview


• Declared variables
• Application object
• Workbook object
• Worksheet object
• Range object
• WorksheetFunction object
• Chart object
• Script example

The following examples are written for version 10 of the Microsoft Excel
Object Library (Excel XP). If you use a different version of the object library,
you may need to change the code to have it work properly.

Microsoft Excel Object Library overview


The Microsoft Excel Object Library contains objects, methods, and
properties that model the functionality of Excel. This introduction to the
Microsoft Excel Object Library does not describe every object. Instead, it
focuses on the following objects:

• Application object
• Workbook object
• Worksheet object
• Range object
• WorksheetFunction object
• Chart object

Refer to the help file for the Microsoft Excel Object Library for a complete
description of all of the objects contained in the library.

To use the Microsoft Excel Object Library, you should first create an
Application object with a sanScript function. For more information on
creating COM objects with sanScript functions, refer to Chapter 39, “COM
in sanScript.” You can create all of the other objects from methods provided
in the library.

PROGRAMMER’S GUIDE VOLUME 2 375


PA RT 9 U S I N G C O M

The following illustration displays the relationships between the objects


that are discussed.

You should create the


Application object
Application object first.
Chart object

Workbook object
Create the remaining objects from
Worksheet object
methods provided with the library.
Range object

WorksheetFunction object

Declared variables
In the script examples, it is assumed that you have declared the following
variables:

Variable name Variable type


app Excel.Application
workbook Excel.Workbook
worksheet Excel.Worksheet
chart Excel.Chart
embedChart Excel.ChartObject
cellRange Excel.Range
wsFunction Excel.WorksheetFunction
count integer
intCellValue integer
stringCellValue string

Application object
The Application object allows you to work with the Excel application.

Creating the application


Use new keyword to create a new instance of Excel.

{Create a new instance of Excel.}


app = new Excel.Application();

376 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 2 M I C R O S O F T E X C E L

Use the COM_CreateObject() function to create a new instance of Excel


when using Distributed COM (DCOM). In the following example, a new
instance of Excel is created on the computer “SystemServer”.

{Create a new instance of Excel.}


app = COM_CreateObject("Excel.Application", "SystemServer");

Retrieving an existing application


Use the COM_GetObject() function to retrieve a running instance of Excel.

{Retrieve a running instance of Excel.}


app = COM_GetObject("Excel.Application");

Showing and hiding an application


The Visible property from the Application object allows you to show or
hide Excel. Setting the Visible property to true shows the application.

{Show the application.}


app.Visible = true;

Setting the Visible property to false hides the application.

{Hide the application.}


app.Visible = false;

The new keyword and the COM_CreateObject() function return hidden


instances of an application. Use the Visible property to show a hidden instance of
an application.

Hiding and showing warning messages


When you integrate with Excel, dialog boxes containing warnings can stop
the application. To hide warning messages, set the DisplayAlerts property
to false.

{Hide warning messages.}


app.DisplayAlerts = false;

PROGRAMMER’S GUIDE VOLUME 2 377


PA RT 9 U S I N G C O M

To show warning messages, set the DisplayAlerts property to true.

{Show warning messages.}


app.DisplayAlerts = true;

Hiding warnings prevents the user from seeing the messages displayed by an
application. Your code must still handle the errors or other exceptional conditions
that caused Excel to display warning messages.

Closing an application
After you have finished using the application, you can close it with the Quit
method.

{Close the application.}


app.Quit();

If Excel is closed with an unsaved workbook or worksheet, a warning


message appears. To prevent a dialog from appearing, do one of the
following:

• Save the workbook first


• Set the Saved property to true
• Suppress warning messages with the DisplayAlerts property

Workbook object
The Workbook object allows you to work with a workbook. The
Workbooks collection contains all of the currently open workbooks in an
Excel application.

Creating a new workbook


Use the Add method to create a new workbook and add it to the
Workbooks collection.

{Add a new workbook to the Workbooks collection.}


workbook = app.Workbooks.Add();

Opening an existing workbook


Use the Open method to open an existing workbook and add it to the
Workbooks collection.

{Open an existing workbook.}


workbook = app.Workbooks.Open("C:\RESM\RESM.XLS");

378 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 2 M I C R O S O F T E X C E L

Retrieving an open workbook


You can retrieve an open workbook from the Workbooks collection with
the Item property by the number associated with the workbook.

{Retrieve the third workbook from the Workbooks collection.}


workbook = app.Workbooks.Item[3];

You can also retrieve workbooks by the name of the workbook.

{Retrieve the workbook named "RESM.XLS".}


workbook = app.Workbooks.Item["RESM.XLS"];

Saving a workbook
To save a new workbook, use the SaveAs method.

{Save a new workbook.}


workbook.SaveAs("C:\RESM\RESM.XLS");

If you have previously saved a workbook, use the Save method to save the
workbook.

{Save an existing workbook.}


workbook.Save();

You can use the Saved property to find out if a workbook has been saved. If
the Saved property returns true, the workbook has been saved. Otherwise,
it has not.

{If the workbook has not been saved, save it.}


if(not workbook.Saved) then
workbook.Save();
end if;

You can also set the value of the Saved property. If you set the Saved property to
true without saving a workbook, any message prompting you to save the workbook
is suppressed.

Closing a workbook
Use the Close method to close a workbook.

{Close the workbook.}


workbook.Close();

PROGRAMMER’S GUIDE VOLUME 2 379


PA RT 9 U S I N G C O M

You can also use the Close method to save a workbook before closing it.
You must specify whether to save the workbook and where to save the
workbook.

{Save changes and close the workbook.}


workbook.Close(true, "C:\RESM\RESM.XLS");

Worksheet object
The Worksheet object allows you to work with a worksheet. The
Worksheets collection contains all of the worksheets in a workbook.

Creating a new worksheet


Use the Add method to create a new worksheet and add it to the
Worksheets collection.

{Add a new worksheet to the Worksheets collection.}


worksheet = workbook.Worksheets.Add();

Retrieving an existing worksheet


You can retrieve a worksheet from the Worksheets collection with the Item
property by the number associated with the worksheet.

{Retrieve the fourth worksheet from the Worksheets collection.}


worksheet = workbook.Worksheets.Item[4];

You can also retrieve worksheets by the name of the worksheet.

{Retrieve the worksheet named "Sheet1".}


worksheet = workbook.Worksheets.Item["Sheet1"];

Activating a worksheet
A workbook can contain several worksheets. To activate a specific
worksheet, use the Activate method.

{Activate the second worksheet in the Worksheets collection.}


worksheet = workbook.Worksheets.Item[2];
worksheet.Activate();

380 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 2 M I C R O S O F T E X C E L

Moving a worksheet
Use the Move method to move a worksheet to another position in the
workbook. You can place a worksheet either before or after another
worksheet by specifying the “Before” and “After” parameters. Specify the
“Before” parameter to move a worksheet before another worksheet.

{Place a new worksheet after the fourth worksheet. The "Before"


parameter refers to the fourth worksheet, and the "After" parameter is
set to none.}
worksheet = workbook.Worksheets.Add();
worksheet.Move(workbook.Worksheets.Item[4], none);

Specify the “After” parameter to move a worksheet after another


worksheet.

{Place a new worksheet after the first worksheet in the workbook. The
"After" parameter refers to the first worksheet, and the "Before"
parameter is set to none.}
worksheet = workbook.Worksheets.Add();
worksheet.Move(none, workbook.Worksheets.Item[1]);

Saving a worksheet
To save a worksheet as a new workbook, use the SaveAs method.

{Save the worksheet as a new workbook.}


worksheet.SaveAs("C:\RESM\RESM.XLS");

Range object
A Range object specifies a cell or a group of cells on a worksheet. Once you
have created a Range object, you can format a cell or group of cells.

Specifying a range
You can use the Range property from the Worksheet object to specify a
range in a worksheet.

{Specify a range that includes cells A1 to A5.}


cellRange = worksheet.Range["A1:A5"];

PROGRAMMER’S GUIDE VOLUME 2 381


PA RT 9 U S I N G C O M

You can also use the Columns property to specify a range. The Columns
property can be used with three different objects: the Application object,
the Worksheet object, and the Range object. The Columns property from
the Application object returns a range containing all of the columns in the
active worksheet.

{Return a Range object containing the active worksheet’s columns.}


cellRange = app.Columns;

The Columns property from the Worksheet object returns a range


containing all of the columns on the worksheet.

{Return a Range object containing all of the columns in the


worksheet.}
cellRange = worksheet.Columns;

You can also use the Rows property to specify a range. The Rows property
can also be used with three different objects: the Application object, the
Worksheet object, and the Range object. The Rows property from the
Application object returns a range containing all of the rows in the active
worksheet.

{Return a Range object containing the active worksheet’s rows.}


cellRange = app.Rows;

The Rows property from the Worksheet object returns a range containing
all of the rows on the worksheet.

{Return a Range object containing all of the rows in the worksheet.}


cellRange = worksheet.Rows;

Inserting and retrieving cell values


Use the Value property to insert text into a specified range. If the range
contains multiple cells, the Value property inserts the text into the active
cell.

{Insert text into a cell.}


cellRange.Value = "Customer ID";

382 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 2 M I C R O S O F T E X C E L

You can also use the Value property to retrieve the unformatted value of a
specified range. If the range contains multiple cells, the Value property
returns the value from the active cell.

{Retrieve the unformatted value of the cell.}


intCellValue = integer(cellRange.Value);

To retrieve the formatted value of a cell as a string, use the Text property.

{Retrieve the formatted value of a cell as a string.}


stringCellValue = string(cellRange.Text);

Formatting a range of cells


The Range object contains several properties to modify the appearance of a
worksheet, such as the Font property, the Borders property, the Columns
property, and the Interior property.

Font property The Font property returns a Font object. The Font object
contains properties that modify characteristics of the font, such as style and
size.

{Set the font style.}


cellRange.Font.Bold = true;
{Set the font size.}
cellRange.Font.Size = 8;

Borders property The Borders property returns a Borders collection


that contains all of the cell borders. You can use the Borders collection to set
properties for borders, such as the weight and line style.

{Use a constant from the xlBorderWeight enumeration to set the weight


of the borders.}
cellRange.Borders.Weight = Excel.xlHairline;
{Use a constant from the xlLineStyle enumeration to set the line style
of the borders.}
cellRange.Borders.LineStyle = Excel.xlDot;

PROGRAMMER’S GUIDE VOLUME 2 383


PA RT 9 U S I N G C O M

You can also access individual borders in a range with the Borders
collection. To specify a border, use the Item property and the constants
contained in the xlBordersIndex enumeration.

{Use a constant from the xlLineStyle enumeration to set the line style
for the bottom border.}
cellRange.Borders.Item[Excel.xlEdgeBottom].LineStyle = Excel.xlDot;

Interior property The Interior property returns an Interior object. The


Interior object contains properties that modify the characteristics of the
interior of a cell, such as the cell’s background color and background
pattern.

{Set the background color.}


cellRange.Interior.ColorIndex = 35;
{Use a constant from the xlPattern enumeration to set the background
pattern.}
cellRange.Interior.Pattern = Excel.xlPatternDown;

WorksheetFunction object
The WorksheetFunction object allows you to perform calculations on the
cells in a worksheet.

Creating a worksheet function


To create a WorksheetFunction object, use the WorksheetFunction
property from the Application object.

{Create a WorksheetFunction object.}


wsFunction = app.WorksheetFunction;

Accessing a worksheet function


Use the WorksheetFunction object to access the worksheet functions
available in Excel. In the following example, the CountA method returns
the number of occurrences of the value “Air Conditioned” in the current
range.

{Count the number of cells that contain the value "Air Conditioned".}
count = wsFunction.CountA(cellRange, "Air Conditioned");

The syntax for worksheet functions are listed in the help file for the Microsoft Excel
Object Library.

384 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 2 M I C R O S O F T E X C E L

Chart object
The Chart object allows you to create, modify, and format a chart. The
Charts collection contains all of the currently open chart sheets in a
workbook. It does not contain charts that are embedded in worksheets.

Creating a chart
Use the Add method to create a new chart and add it to the Charts
collection.

{Add a new chart to the Charts collection.}


chart = app.Charts.Add();

Retrieving a chart
You can retrieve a chart from the Charts collection with the Item property
by the number associated with a chart.

{Retrieve the first chart.}


chart = app.Charts.Item[1];

You can also retrieve charts by the name of the chart.

{Retrieve the chart named "Chart1".}


chart = app.Chart.Item["Chart1"];

The Charts collection does not contain charts that you have embedded in a
worksheet. You must use the ChartObjects method to retrieve an
embedded chart as a ChartObject object. You must provide either the name
or number associated with the chart.

{Retrieve the third embedded chart from the worksheet.}


embedChart = worksheet.ChartObjects(3);

Setting the source data


To set the source data for a chart, use the SetSourceData method.

{Specify a range.}
cellRange = worksheet.Range["A1:B5"];
{Set the source data.}
chart.SetSourceData(cellRange);

PROGRAMMER’S GUIDE VOLUME 2 385


PA RT 9 U S I N G C O M

Setting the chart type


To set the type of chart, use the ChartType property. Chart types are
expressed by constants contained in the xlChartType enumeration.

{Set the chart type to a pie chart.}


chart.ChartType = Excel.xlPie;

Setting the chart location


A chart can either be a separate sheet or be embedded in a worksheet. To
specify the location of a chart, use the Location method and the constants
contained in the xlChartLocation enumeration. After using the Location
method, you need use the ActiveChart property to retrieve that chart
again.

{Embed a chart in a worksheet.}


chart.Location(Excel.xlLocationAsObject, "Sheet1");
{Retrieve the chart again.}
chart = app.ActiveChart;

An embedded chart is not contained in the Charts collection.

Using the chart wizard


Use the ChartWizard method to set several properties for a chart at one
time. The ChartWizard method allows you to set the labels, the source data,
the chart type, the properties of the legend, as well as formats for the chart.
All parameters are optional.

{Create a 3D pie chart from the values in the specified cellRange. The
chart does not have a legend and is titled "Sales Performance".}
chart.ChartWizard(cellRange, Excel.xl3DPie, none, none, none, none,
➥ false, "Sales Peformance", none, none, none);

The ChartWizard method does not accept all of the values from the xlChartType
enumeration. Refer to the Microsoft Excel Object Library help file for more
information.

386 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 2 M I C R O S O F T E X C E L

Script example
The following example uses objects from the Microsoft Excel Object Library
to add a worksheet and embed a chart in a new workbook, RESM.XLS.

local Excel.Application app;


local Excel.Workbook workbook;
local Excel.Worksheet worksheet;
local Excel.Range cellRange;
local Excel.Chart chart;

{If Excel is running, use it. Otherwise, create a new instance.}


app = COM_GetObject("Excel.Application");
if(app = null) then
app = new Excel.Application();
end if;

{Make Excel visible.}


app.Visible = true;

{Create a new workbook.}


workbook = app.Workbooks.Add();

{Retrieve the first worksheet in the workbook.}


worksheet = workbook.Worksheets.Item[1];

{Set the values of the cells in the first row in the table.}
cellRange = worksheet.Range["A1"];
cellRange.Value = "Agent ID";
cellRange = worksheet.Range["B1"];
cellRange.Value = "Agent Name";
cellRange = worksheet.Range["C1"];
cellRange.Value = "March Sales";
cellRange = worksheet.Range["D1"];
cellRange.Value = "April Sales";
cellRange = worksheet.Range["E1"];
cellRange.Value = "May Sales";

PROGRAMMER’S GUIDE VOLUME 2 387


PA RT 9 U S I N G C O M

{Add a record to the worksheet.}


cellRange = worksheet.Range["A2"];
cellRange.Value = "10001";
cellRange = worksheet.Range["B2"];
cellRange.Value = "Angela Barbariol";
cellRange = worksheet.Range["C2"];
cellRange.Value = "$400,000";
cellRange = worksheet.Range["D2"];
cellRange.Value = "$200,000";
cellRange = worksheet.Range["E2"];
cellRange.Value = "$100,000";

{Add a new chart.}


chart = app.Charts.Add();

{Use the chart wizard to create a 3D pie chart.}


cellRange = worksheet.Range["C2:E2"];
chart.ChartWizard(cellRange, Excel.xl3DPie, none, none, 0, 0, false,
➥ "Sales Totals");

{Set the chart location.}


chart.Location(Excel.xlLocationAsObject, str(worksheet.Name));

{Set the chart to the active chart.}


chart = app.ActiveChart;

{Prevent the SaveAs method from displaying any warning messages.}


app.DisplayAlerts = false;

{Save the workbook.}


workbook.SaveAs("C:\RESM\RESM.XLS");

{Clear the variables.}


clear chart;
clear cellRange;
clear worksheet;
clear workbook;
clear app;

388 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 43: Microsoft ADOX
To create new databases, use the Microsoft ActiveX® Data Objects
Extensions for Data Definition Language and Security (ADOX) Object
Library. Information about using the Microsoft ADOX Object Library is
divided into the following sections:

• Microsoft ADOX Object Library overview


• Declared variables
• Catalog object
• Table object
• Key object
• Column object
• Script example

The following examples are written for version 2.6 of the Microsoft ADOX
Object Library. If you use a different version of the object library, you may
need to change the code to have it work properly.

Microsoft ADOX Object Library overview


Refer to Chapter 44, The Microsoft ADOX Object Library contains objects, methods, and
“Microsoft ADO,” for properties that allow you to create a database. This introduction to the
additional information Microsoft ADOX Object Library does not describe every object. Instead, it
on working with data focuses on the following objects:
in a database.
• Catalog object
• Table object
• Column object
• Key object

Refer to the help file for the Microsoft ADOX Object Library for a complete
description of all of the objects contained in the library.

To use the Microsoft ADOX Object Library, you should first create a Catalog
object with a sanScript function. For more information on creating COM
objects with sanScript functions, refer to Chapter 39, “COM in sanScript.”
You can create all of the other objects from methods provided in the library.

PROGRAMMER’S GUIDE VOLUME 2 389


PA RT 9 U S I N G C O M

The following illustration displays the relationships between the objects


that are discussed.

You should create the


Catalog object
Catalog object first.
Table object

Create the remaining objects Column object


from methods in the library. Key object

Column object

Declared variables
In the script examples, it is assumed that you have declared the following
variables:

Variable name Variable type


catalog ADOX.Catalog
adoxTable ADOX.Table
tableColumn ADOX.Column
tableKey ADOX.Key
connection ADODB.Connection
conString string
name string
keyType integer

Catalog object
The Catalog object allows you to work with groups, users, views, tables,
and procedures that define the database.

Creating a new Catalog object


Use new keyword to create a new instance of a Catalog object.

{Create a new instance of a Catalog object.}


catalog = new ADOX.Catalog();

390 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 3 M I C R O S O F T A D O X

When using Distributed COM (DCOM), create a new Catalog object with
the COM_CreateObject() function. In the following example, a new
Catalog object is created on the computer “SystemServer”.

{Create a new Catalog object.}


catalog = COM_CreateObject("ADOX.Catalog", "SystemServer");

Creating a Catalog object doesn’t create a database. You must also use the Create
method to create a new catalog.

Creating a new catalog


Use the Create method to create a new catalog. To create a new catalog, you
must specify both the database type and a name for the database in the
connection string.

{Create a catalog.}
conString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb";
catalog.Create(conStringr);

In the previous example, the name of the database is db.mdb, and the
database is a Microsoft Jet database. For more information about specifying
database types, refer to the help file for the Microsoft ADOX Object Library.

Creating a catalog also creates a Connection object from the Microsoft ActiveX
Data Objects (ADO) Object Library. When you close the catalog, you should also
close the connection. If you don’t, you may get unpredictable results.

Retrieving a connection
Refer to Chapter 44, Creating a new catalog also creates or opens a Microsoft ADO connection.
“Microsoft ADO,” for Use the ActiveConnection property to retrieve a connection from a Catalog
more information on object.
ADO Connection
objects. {Retrieve the active connection.}
connection = catalog.ActiveConnection;

Be sure to close all connections to a database. If you don’t, you may get
unpredictable results.

PROGRAMMER’S GUIDE VOLUME 2 391


PA RT 9 U S I N G C O M

Table object
The Table object allows you define the structure of a table in a catalog. The
Tables collection contains all of the tables in a catalog.

Creating a new table


Use the Append method to create a new table. The Append method
automatically adds the table to the Tables collection.

{Append a new table named "BuyerInfo" to the Tables collection.}


adoxTable = catalog.Tables.Append("BuyerInfo");

Retrieving an existing table


You can retrieve an existing table from the Tables collection with the Item
property by the number associated with the table.

{Retrieve the first table from the catalog.}


adoxTable = catalog.Tables.Item[0];

You can also access the tables by the name of the table.

{Retrieve the table named "BuyerInfo".}


adoxTable = catalog.Tables.Item["BuyerInfo"];

Retrieving and setting the name of a table


Use the Name property to retrieve the name of a table.

{Retrieve the name of a table.}


name = str(adoxTable.Name);

You can also use the Name property to set the name of a table.

{Set the name of a table.}


adoxTable.Name = "BuyerInfo";

392 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 3 M I C R O S O F T A D O X

Deleting a table
To delete a table from a catalog, use the Delete method. You can delete a
table by the number associated with the table.

{Delete the first table from the Tables collection.}


catalog.Tables.Delete(0);

You can also delete a table by the name of the table.

{Delete the table named "BuyerInfo".}


catalog.Tables.Delete("BuyerInfo");

Key object
The Key object allows you to define the keys for a table. The Keys
collection contains all of the keys for a table.

Creating a new key


Use the Append method to create a new key. The Append method
automatically adds the key to the Keys collection.

{Append a new key, named "PrimaryKey", to the Keys collection.}


tableKey = adoxTable.Keys.Append("PrimaryKey");

Retrieving an existing key


You can retrieve an existing key from the Keys collections with the Item
property by the number associated with the key.

{Retrieve the first key.}


tableKey = adoxTable.Keys.Item[0];

You can also access keys by the name of the key.

{Retrieve the key named "PrimaryKey".}


tableKey = adoxTable.Keys.Item["PrimaryKey"];

PROGRAMMER’S GUIDE VOLUME 2 393


PA RT 9 U S I N G C O M

Retrieving and setting the name of a key


Use the Name property to retrieve the name of a key.

{Retrieve the name of a key.}


name = tableKey.Name;

You can also use the Name property to set the name of a key.

{Set the name of a key.}


tableKey.Name = "PrimaryKey";

Retrieving and setting the type of a key


Use the Type property to retrieve the type of a key. The returned value is
equivalent to a constant contained in the KeyTypeEnum enumeration.

{Retrieve the type of a key.}


keyType = tableKey.Type;

You can also use the Type property to set the type of a key.

{Set the type of the key as primary.}


tableKey.Type = ADOX.adKeyPrimary;

Column object
The Column object allows you to define the fields contained in a table or a
key. The Columns collection contains all of the columns for a key or a table.

Creating a new column


Use the Append method to create a new column and automatically add the
column to the Columns collection. To set the data type of a column, specify
a constant contained in the DataTypeEnum enumeration.

{Append a column named "Date" with a date data type.}


tableColumn = adoxTable.Columns.Append("Date", ADOX.adDate);

394 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 3 M I C R O S O F T A D O X

The following table lists the Dexterity data types and the corresponding
ADOX types.

Dexterity type ADOX type Description


Boolean adBoolean Boolean
Byte adUnsignedTinyInt Unsigned character
Integer adSmallInt Short
Long adInteger Long
String adWChar String
Text adVarWChar
Currency adCurrency Currency
Vcurrency adSingle Single
adDouble Double
adDecimal Decimal
Date adDBDate Date
Time adDBTime
Datetime adDBDateStamp
Reference adDispatch (unsupported) IDispatch*
A typed COM reference adUnknown (unsupported) IUnknown*

When you create a table, create the table columns before you create key
columns. The columns in a key must also be in the table that the key is
associated with.

Retrieving an existing column


You can retrieve an existing column from the Columns collection with the
Item property by the number associated with the column.

{Retrieve the first column from the table.}


tableColumn = adoxTable.Columns.Item[0];

You can also access columns by the column name.

{Retrieve the column named "BuyerID".}


tableColumn = adoxTable.Columns.Item["BuyerID"]

PROGRAMMER’S GUIDE VOLUME 2 395


PA RT 9 U S I N G C O M

Script example
The following example uses objects from the Microsoft ADOX Object
Library to create a table, named “BuyerInfo”, and a primary key for the
table.

local ADOX.Catalog catalog;


local ADOX.Table adoxTable;
local ADOX.Key tableKey;
local ADODB.Connection connection;
local string conString;

{Define the ADO connection string.}


conString="Provider=Microsoft.Jet.OLEDB.4.0;Data
➥ Source=C:\RESM\RESM.MDB";

{Create a new database.}


catalog = new ADOX.Catalog();
catalog.Create(conString);

{Retrieve the active connection.}


connection = catalog.ActiveConnection;

{Create a table.}
adoxTable = catalog.Tables.Append("BuyerInfo");

{Create the columns in the table.}


adoxTable.Columns.Append("BuyerID", ADOX.adVarWChar);
adoxTable.Columns.Append("FirstName", ADOX.adVarWChar);
adoxTable.Columns.Append("LastName", ADOX.adVarWChar);
adoxTable.Columns.Append("PhoneNumber", ADOX.adVarWChar);

{Create a key for the table.}


tableKey = adoxTable.Keys.Append("ByBuyerID");

{Set the key type.}


tableKey.Type = ADOX.adKeyPrimary;

396 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 3 M I C R O S O F T A D O X

{Create the column in the key.}


tableKey.Columns.Append("BuyerID");

{Close the connection.}


connection.Close();

{Clear variables.}
clear tableKey;
clear adoxTable;
clear catalog;
clear connection;

PROGRAMMER’S GUIDE VOLUME 2 397


398 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 44: Microsoft ADO
To work with data in databases, use the Microsoft ActiveX Data Objects
(ADO) Object Library. Information about using the Microsoft ADO Object
Library is divided into the following sections:

• Microsoft ADO Object Library overview


• Declared variables
• Connection object
• Field object
• Recordset object
• Script example

The following examples are written for version 2.6 of the Microsoft ADO
Object Library. If you use a different version of the object library, you may
need to change the code to have it work properly.

Microsoft ADO Object Library overview


For more information The Microsoft ADO Object Library contains objects, methods, and
on creating a new properties that allow you to work with records in a database. This
database, refer to introduction to the Microsoft ADO Object Library does not describe every
Chapter 43, “Microsoft object. Instead, it focuses on the following objects:
ADOX.”
• Connection object
• Recordset object
• Field object

Refer to the help file for the Microsoft ADO Object Library for a complete
description of all of the objects contained in the library.

To use the Microsoft ADO Object Library, you must first create either a
Connection object or a Recordset object with a sanScript function. For
more information on creating COM objects with sanScript functions, refer
to Chapter 39, “COM in sanScript.” You can create all of the other objects
from methods provided in the library.

The following illustration displays the relationships between the objects


that are discussed.

PROGRAMMER’S GUIDE VOLUME 2 399


PA RT 9 U S I N G C O M

You must create either the Connection object


Connection object or the
Recordset object
Recordset object first.
Field object

Declared variables
In the script examples, it is assumed that you have declared the following
variables:

Variable name Variable type


connection ADODB.Connection
recordset ADODB.Recordset
recordField ADODB.Field
catalog ADOX.Catalog
conString string
fieldValue string

Connection object
To access the data stored in databases, you must first connect to the
database. The Connection object connects your Dexterity-based
application to an existing database.

Creating a Connection object


Use the new keyword to create a new Connection object.

{Create a new Connection object.}


connection = new ADODB.Connection();

When using Distributed COM (DCOM), create a new Connection object


with the COM_CreateObject() function. In the following example, a new
Connection object is created on the computer “SystemServer”.

{Create a new Connection object.}


connection = COM_CreateObject("ADODB.Connection", "SystemServer");

Creating a Connection object doesn’t connect your Dexterity-based application to


a database. You must also use the Open method or the ActiveConnection
property to connect to a specific database.

400 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 4 M I C R O S O F T A DO

Opening a connection
Use the Open method to open a connection to a database. You must specify
both the database type and the name of an existing database in the
connection string.

{Open a connection to a database.}


conString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb";
connection.Open(conString);

In the previous example, the name of the database is db.mdb, and the
specified database type is a Microsoft Jet database. For more information
about specifying database types, refer to the help file for the Microsoft ADO
Object Library.

Retrieving a connection
For more information When a Microsoft ADOX Object Library catalog is created, a connection to
on the Catalog object, the database is also created. You can retrieve the connection with the
refer to Chapter 43, ActiveConnection property from the Catalog object.
“Microsoft ADOX.”
{Retrieve a connection from a catalog object.}
connection = catalog.ActiveConnection;

Closing a connection
Use the Close method to close a connection.

{Close a connection.}
connection.Close();

Be sure to close all connections to a database. If you don’t, you may get
unpredictable results.

Recordset object
The Recordset object allows you to work with the records returned from a
query on a table.

Creating a Recordset object


Use the new keyword to create a new Recordset object.

{Create a new recordset.}


recordset = new ADODB.Recordset();

PROGRAMMER’S GUIDE VOLUME 2 401


PA RT 9 U S I N G C O M

When using Distributed COM (DCOM), create a new Recordset object with
the COM_CreateObject() function. In the following example, a new
Recordset object is created on the computer “SystemServer”.

{Create a new recordset object.}


recordset = COM_CreateObject("ADODB.Recordset", "SystemServer");

Creating a Recordset object doesn’t create a recordset for a table. You must also
use the Open method to add records from a table to a recordset.

Opening a recordset
Use the Open method to add records to a recordset. The Open method
allows you to use a SQL query to select records from tables in a database.

To specify how you work with records in the database, use values from the
CursorTypeEnum enumeration. To specify how the database is locked, use values
from the LockTypeEnum enumeration.

{Open a recordset on the BuyerInfo table.}


recordset.Open("SELECT * FROM BuyerInfo", connection,
➥ ADODB.adOpenDynamic, ADODB.adLockOptimistic);

In the previous example, the recordset is opened dynamically, which allows


you to move both forward and backward through the records. Also, the
recordset is locked record by record.

Moving through a recordset


Several methods are available to move through the records in a Recordset
object, such as the Move method, the MoveFirst method, the MoveLast
method, the MoveNext method, and the MovePrevious method. Use the
Move method to move forward a specified number of records.

{Move forward five records.}


recordset.Move(5);

Use the MoveFirst method to move to the first record in the recordset.

{Move to the first record.}


recordset.MoveFirst();

Use the BOF property to find out if you are at the beginning of a recordset.

402 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 4 M I C R O S O F T A DO

Use the MoveLast method to move to the last record in a recordset.

{Move to the last record.}


recordset.MoveLast();

Use the EOF property to find out if you are at the end of a recordset.

Use the MoveNext method to move to the next record.

{Move to the next record.}


recordset.MoveNext();

Use the MovePrevious method to move to the previous record in the


recordset.

{Move to the previous record.}


recordset.MovePrevious();

Adding a record
To add a new record to a recordset, you must call the AddNew method and
set the values of the fields in the record. Then you must call the Update
method to add the record to the recordset.

{Add a new record to the BuyerInfo table.}


recordset.AddNew();
recordset.Fields.Item[0].Value = 'Buyer ID';
recordset.Fields.Item[1].Value = 'Buyer First Name';
recordset.Fields.Item[2].Value = 'Buyer Last Name';
recordset.Fields.Item[3].Value = Phone;
recordset.Update();

Updating a record
To update a record in a recordset, you must move to the record and set the
values for the fields that you want to update in the record. Then you must
call the Update method to save the changes.

{Update the last record in the BuyerInfo table.}


recordset.MoveLast();
recordset.Fields.Item[1].Value = 'Buyer First Name';
recordset.Update();

PROGRAMMER’S GUIDE VOLUME 2 403


PA RT 9 U S I N G C O M

Deleting a record
To delete a record in a recordset, you must move to the record you want to
delete and call the Delete method. Then you must call the Update method
to update the recordset.

{Delete the last record in the BuyerInfo table.}


recordset.MoveLast();
recordset.Delete();
recordset.Update();

Closing a recordset
Use the Close method to close a recordset.

{Close a recordset.}
recordset.Close();

Field object
The Field object allows you to work with the fields in a record. The Fields
collection contains all of the fields in a record.

Retrieving a field
You can retrieve a field from the Fields collection with the Item property
by the number associated with the field.

{Retrieve the first field from the record.}


recordField = recordset.Fields.Item[0];

You can also access fields by the field name.

{Retrieve the field named "BuyerID".}


recordField = recordset.Fields.Item["BuyerID"];

Retrieving and setting a field’s value


Use the Value property to retrieve the value of a field in a record. The
property returns the field value of the record that the recordset is currently
pointing to.

{Retrieve the value of the first field in the last record.}


recordset.MoveLast();
fieldValue = recordset.Fields.Item[0].Value;

404 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 4 M I C R O S O F T A DO

You can also use the Value property to set the value of a field.

{Set the value of the BuyerID field in the next record.}


recordset.MoveNext();
recordset.Fields.Item[0].Value = 'Buyer ID';
recordset.Update();

Script example
The following example uses objects from the Microsoft ADO Object Library
to add a record displayed in the Buyers window of the Real Estate Sales
Manager application to the “BuyerInfo” table created in the Script example
on page 396.

local ADODB.Connection connection;


local ADODB.Recordset recordset;
local string query;
local string conString;

{Define the ADO connection string.}


conString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
➥ Source=C:\RESM\RESM.MDB";
query = "SELECT BuyerID FROM BuyerInfo";

{Create and open a connection.}


connection = new ADODB.Connection();
connection.Open(conString);

{Create and open a recordset.}


recordset = new ADODB.Recordset();
recordset.Open(query, connection,
➥ ADODB.adOpenDynamic,ADODB.adLockOptimistic);

PROGRAMMER’S GUIDE VOLUME 2 405


PA RT 9 U S I N G C O M

{If the record isn’t displayed, warn the user. Otherwise, add the
record to the table.}
if 'Buyer ID' = "" then
warning "Please display a record in the Buyers window.";
else
recordset.AddNew();
recordset.Fields.Item[0].Value = 'Buyer ID';
recordset.Fields.Item[1].Value = 'Buyer First Name';
recordset.Fields.Item[2].Value = 'Buyer Last Name';
recordset.Fields.Item[3].Value = Phone;
recordset.Update();
end if;

{Close the recordset.}


recordset.Close();

{Close the connection.}


connection.Close();

{Clear the variables.}


clear connection;
clear recordset;

406 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 45: Microsoft Internet Explorer
To automate Internet Explorer, use the Microsoft Internet Controls Object
Library. Information about automating Internet Explorer is divided into the
following sections:

• Microsoft Internet Controls Object Library overview


• Declared variables
• InternetExplorer object
• Script example

Microsoft Internet Controls Object Library


overview
The Microsoft Internet Controls Object Library contains objects, methods,
and properties that model the functionality of Internet Explorer. This
introduction to the Microsoft Internet Controls Object Library does not
describe every object. Instead, it focuses on the InternetExplorer object.

Refer to the help file for the Microsoft Internet Controls Object Library for a
complete description of all of the objects contained in the library.

To use the Microsoft Internet Controls Object Library, you must first create
an InternetExplorer object with a sanScript function. For more information
on creating COM objects with sanScript functions, refer to Chapter 39,
“COM in sanScript.”

Declared variables
In the script examples, it is assumed that you have declared the following
variable:

Variable Name Variable Type


IExplorer SHDocVw.InternetExplorer

PROGRAMMER’S GUIDE VOLUME 2 407


PA RT 9 U S I N G C O M

InternetExplorer object
The InternetExplorer object allows you to work with an Internet Explorer
application.

Creating the application


Use the new keyword to create a new instance of Internet Explorer.

{Create a new instance of Internet Explorer.}


IExplorer = new SHDocVw.InternetExplorer();

When using Distributed COM (DCOM), create a new instance of Internet


Explorer with the COM_CreateObject() function. In the following example,
an instance of Internet Explorer is created on the computer “SystemServer”.

{Create a new instance of Internet Explorer.}


IExplorer = COM_CreateObject("SHDocVw.InternetExplorer",
➥ "SystemServer");

Showing and hiding the application


The Visible property allows you to show or hide the application. Setting
the Visible property to true shows the application.

{Show the application.}


IExplorer.Visible = true;

Setting the Visible property to false hides the application.

{Hide the application.}


IExplorer.Visible = false;

The new keyword and the COM_CreateObject function return a hidden instance
of an application. Use the Visible property to show a hidden application.

Loading a web page


Use the Navigate method to load a web page in Internet Explorer. You can
load a web page with the Navigate method by specifying the URL.

{Use a URL to load a web page.}


IExplorer.Navigate("msdn.microsoft.com");

408 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H AP TE R 4 5 M IC R O S O FT I N TE R N E T E X PL O R E R

You can also load a file with the Navigate method by specifying the full
pathname of the file.

{Use the full pathname to load a local file.}


IExplorer.Navigate("C:\RESM\RESM.XML");

Refreshing a web page


To refresh a web page, call the Refresh method.

{Refresh the web page.}


IExplorer.Refresh();

Stopping a web page from loading


To stop a web page from loading, use the Stop method.

{Stop loading a web page.}


IExplorer.Stop();

Hiding and showing dialog boxes


The Silent property allows you to hide and show dialog boxes in Internet
Explorer. Setting the Silent property to true hides the dialog boxes.

{Hide the dialog boxes.}


IExplorer.Silent = true;

Setting the Silent property to false shows the dialog boxes. This is the
default setting.

{Show the dialog boxes.}


IExplorer.Silent = false;

Hiding dialog boxes prevents the user from seeing warning messages and other
prompts displayed by an application. Your code still must handle the errors or other
exceptional conditions that caused Internet Explorer to display dialog boxes.

Closing an application
After you have finished using the application, you can close it with the Quit
method.

{Close the application.}


IExplorer.Quit();

PROGRAMMER’S GUIDE VOLUME 2 409


PA RT 9 U S I N G C O M

Script example
The following example uses the InternetExplorer object from the Microsoft
Internet Controls Object Library to load an XML file.

local SHDocVw.InternetExplorer IExplorer;

{Create a new instance of Internet Explorer.}


IExplorer = new SHDocVw.InternetExplorer();

{Make Internet Explorer visible.}


IExplorer.Visible = true;

{Load an XML file in browser.}


IExplorer.Navigate("C:\RESM\RESM.XML");

{Clear variable.}
clear IExplorer;

410 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 46: Microsoft Outlook
To automate Microsoft Outlook, use the Microsoft Outlook Object Library.
Information about automating Outlook is divided into the following
sections:

• Microsoft Outlook Object Library overview


• Declared variables
• Outlook security
• Application object
• NameSpace object
• MAPIFolder object
• MailItem object
• Attachment object
• Recipient object
• ContactItem object
• Script example

The following examples are written for version 10 of the Microsoft Outlook
Object Library (Outlook XP). If you use a different version of the object
library, you may need to change the code to have it work properly.

Microsoft Outlook Object Library overview


The Microsoft Outlook Object Library contains objects, methods, and
properties that model the functionality of Outlook. This introduction to the
Microsoft Outlook Object Library does not describe every object. Instead, it
focuses on the following objects:

• Application object
• NameSpace object
• MAPIFolder object
• MailItem object
• Attachment object
• Recipient object
• ContactItem object

Refer to the help file for the Microsoft Outlook Object Library for a complete
description of all of the objects contained in the library.

PROGRAMMER’S GUIDE VOLUME 2 411


PA RT 9 U S I N G C O M

To use the Microsoft Outlook Object Library, first create an Application


object with a sanScript function. For more information on creating COM
objects with sanScript functions, refer to Chapter 39, “COM in sanScript.”
You can create all of the other objects from methods provided in the library.

The following illustration displays the relationships between the objects


that are discussed.

You should create the


Application object
Application object first.
NameSpace object

MAPIFolder object

MailItem object
Create the remaining objects from
methods provided with the library. Attachment object

Recipient object

ContactItem object

Declared variables
In the script examples, it is assumed that you have declared the following
variables:

Variable name Variable type


app Outlook.Application
nameSpace Outlook.NameSpace
folder Outlook.MAPIFolder
housesFolder Outlook.MAPIFolder
mailItem Outlook.MailItem
attachment Outlook.Attachment
recipient Outlook.Recipient
contactItem Outlook.ContactItem
resolved boolean
itemType integer
recipientIndex long
emailAddress string
aName string
jobTitle string
toRecipients text

412 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

Outlook security
Outlook’s security prevents a script from automatically accessing a folder
or sending an e-mail without the user’s permission. When a script accesses
a folder or sends an e-mail, Outlook displays a warning message and asks if
the script should be permitted to access the folder or send the e-mail. The
user can then permit the script to access the folder or e-mail for a specified
length of time.

Application object
The Application object allows you to work with the Outlook application.

Creating the application


Use the new keyword to create a new instance of an Outlook application

{Create a new instance of Outlook.}


app = new Outlook.Application();

When using Distributed COM (DCOM), create a new instance of Outlook


with the COM_CreateObject() function. In the following example, a new
instance of Outlook is created on the computer “SystemServer”.

{Create a new instance of Outlook.}


app = COM_CreateObject("Outlook.Application", "SystemServer");

Retrieving an existing application


Use the COM_GetObject() function to retrieve a running instance of
Outlook.

{Retrieve a running instance of Outlook.}


app = COM_GetObject("Outlook.Application");

Closing an application
After you have finished using an application, you can close it with the Quit
method.

{Close an application.}
app.Quit();

PROGRAMMER’S GUIDE VOLUME 2 413


PA RT 9 U S I N G C O M

NameSpace object
The NameSpace object represents the root folder in Outlook. It allows you
to work directly with default folders and to specify the characteristics of the
current Outlook session.

Retrieving a namespace
Use the GetNameSpace method from the Application object to retrieve a
namespace. You must specify “MAPI” as the namespace type.

{Retrieve a namespace.}
nameSpace = app.GetNameSpace("MAPI");

Logging on to a session
Use the Logon method to log on to a session. You can specify the profile
name and the password.

{Specify the user’s profile name and password.}


nameSpace.Logon("kakers", "password");

Logging off from a session


Use the Logoff method to log off from the current session.

{Log off from a session.}


nameSpace.Logoff();

Retrieving the current user


Refer to Recipient Use the CurrentUser property to return the Recipient object for the current
object on page 421 for user.
more information on
Recipient objects. {Retrieve the Recipient object for the current user.}
recipient = nameSpace.CurrentUser;

414 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

MAPIFolder object
The MAPIFolder object allows you to work with Outlook folders. The
Folders collection contains all of the folders contained in the namespace or
the current folder.

Creating a new folder


Use the Add method from the Folders collection to add a new folder. You
must specify the folder’s display name. Each folder also has a folder type
that specifies the type of items that you can save in the folder. You can
specify the default folder type with one of the following constants from the
olDefaultFolders enumeration:

olFolderCalendar olFolderJournal
olFolderContacts olFolderNotes
olFolderDrafts olFolderTasks
olFolderInbox

If you do not specify a constant, the folder type is set to the same type as the
parent folder.

{Retrieve the default Inbox folder.}


folder = nameSpace.GetDefaultFolder(Outlook.olFolderInbox);
{Create a new folder named "House Matches" with the type of
olFolderInbox.}
housesFolder = folder.Folders.Add("House Matches",
➥ Outlook.olFolderInbox);

The namespace contains a fixed list of default folders. You cannot add any
additional folders to a namespace.

Retrieving an existing folder


You can retrieve a folder from the Folders collection with the Item method
by the number associated with the folder.

{Retrieve the second folder from the Folders collection.}


folder = nameSpace.Folders.Item(2);

You can also a access folder by its display name.

{Retrieve the folder named "House Matches".}


housesFolder = folder.Folders.Item("House Matches");

PROGRAMMER’S GUIDE VOLUME 2 415


PA RT 9 U S I N G C O M

You can also use the GetDefaultFolder method from the NameSpace
object to retrieve the default folders. You must specify the folder item type
with a constant from the olDefaultFolders enumeration.

{Retrieve the default contacts folder.}


folder = nameSpace.GetDefaultFolder(Outlook.olFolderContacts);

Setting and retrieving the display name


Use the Name property to set a folder’s display name.

{Set the display name of the folder.}


folder.Name = "Current Project";

You can also retrieve the folder’s display name with the Name property.

{Retrieve the display name of the folder.}


name = folder.Name;

Displaying a folder
Use the Display method to display a folder in a window.

{Display the folder.}


folder.Display();

Retrieving the default item type


Use the DefaultItemType property to retrieve the default item type of the
folder. The returned value is one of the constants in the olItemType
enumeration.

{Retrieve the default item type for the folder.}


itemType = integer(folder.DefaultItemType);

Deleting a folder
Use the Delete method from the MAPIFolder object to delete a folder.

{Delete the folder.}


folder.Delete();

416 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

You can also use the Remove method to delete a folder from the Folders
collection. You must supply the number associated with the folder.

{Delete the second folder from the Folders collection.}


nameSpace.Folders.Remove(2);

Folders that are deleted are sent to the Deleted Items folder. However, if a folder is
deleted from the Deleted Items folder, it is permanently deleted.

MailItem object
The MailItem object allows you to work with a mail message. An Items
collection is associated with each MAPIFolder object. The collection
contains all of the mail messages in the folder.

Creating a new mail message


Use the CreateItem method from the Application object to create a new
mail message. You must specify the item type with the olMailItem constant
from the olItemType enumeration. The mail message is automatically
added to the Items collection.

{Create a new mail message.}


mailItem = app.CreateItem(Outlook.olMailItem);

You can also use the Add method from the Items collection to create a new
mail message. You must specify the item type with the olMailItem
constant.

{Create a new mail message.}


mailItem = folder.Items.Add(Outlook.olMailItem);

Retrieving an existing mail message


You can retrieve a mail message from the Items collection with the Item
method by the number associated with the mail message.

{Retrieve the third mail message from the Items collection.}


mailItem = folder.Items.Item(3);

You can also access a mail message by the mail message’s subject.

{Retrieve the mail message named "Houses Available".}


mailItem = folder.Items.Item("Houses Available");

PROGRAMMER’S GUIDE VOLUME 2 417


PA RT 9 U S I N G C O M

Displaying a mail message


Use the Display method to display a mail message in a window.

{Display the mail message.}


mailItem.Display();

Adding a recipient
To add a new recipient to a mail message, create a new Recipient object or
add a new recipient to the Recipients collection. For more information,
refer to Recipient object on page 421.

Adding an attachment
To add a new attachment to a mail message, you must add a new
Attachment object to the Attachments collection. For more information,
refer to Attachment object on page 420.

Specifying the subject of a mail message


Use the Subject property to specify a mail message’s subject.

{Specify the subject of the mail message.}


mailItem.Subject = "Houses Available";

Specifying the body of a mail message


Use the Body property to create the body of a mail message.

{Create the body of a mail message.}


mailItem.Body = "We have found several houses that match your
➥ profile.";

Specifying the importance of a mail


message
Use the Importance property to specify a mail message’s importance. Set
the level of importance with a constant from the olImportance
enumeration.

{Set the mail message’s importance to high.}


mailItem.Importance = Outlook.olImportanceHigh;

418 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

Sending a mail message


Use the Send method to send a mail message. The Send method also saves
the mail message to the Sent Items folder.

{Send the mail message.}


mailItem.Send();

You can use the Sent property to find out if a mail message has been sent.
The Sent property returns true if the mail message has been sent.
Otherwise, it returns false. You cannot set the value of the Sent property.

{If a mail message has not been sent, send it.}


if(not mailItem.Sent) then
mailItem.Send();
end if;

Saving a mail message as a file


Refer to Closing a mail If you have previously saved a mail message, use the Save method to save
message on page 420 the mail message.
to save a draft of a mail
message. {Save an existing mail message.}
mailItem.Save();

To save a new mail message, use the SaveAs method. You must specify the
filename for the mail message. You can also specify the saved message’s file
type with a constant from the olSaveTypeAs enumeration. If you do not
specify a constant, the mail message is saved as the message file type.

{Save the new mail message as a a text file.}


mailItem.SaveAs("C:\RESM\HOUSES.TXT", Outlook.olTXT);

You can use the Saved property to find out if a mail message has been
saved. The Saved property returns true if the mail message has been saved.
Otherwise, it returns false. You cannot set the value of the Saved property.

{If a mail message has not been saved, save it.}


if(not mailItem.Saved) then
mailItem.Save();
end if;

PROGRAMMER’S GUIDE VOLUME 2 419


PA RT 9 U S I N G C O M

Deleting a mail message


To delete a mail message, use the Delete method.

{Delete the mailItem.}


mailItem.Delete();

Closing a mail message


Use the Close method to close a mail message. You can use the constants
contained in the OlInspectorClose enumeration to specify whether a mail
message is saved when it is closed. To save a draft of a mail message, use
the Close method and specify the olSave constant.

{Close the mail message and save the message in the Drafts folder.}
mailItem.Close(Outlook.olSave);

Attachment object
The Attachment object allows you to work with an attachment. The
Attachments collection contains all of the attachments associated with a
mail message.

Adding an attachment
Use the Add method to add an attachment to the Attachments collection.
You must specify the full pathname of the attachment. You can also specify
the attachment type, the position number of the attachment, or the display
name of the attachment. The attachment type is specified with a constant
from the olAttachmentType enumeration,

{Add a new attachment to the Attachments collection. The attachment is


placed in the first position with a display name of "Houses".}
attachment = mailItem.Attachments.Add("C:\RESM\HOUSES.TXT", none, 1,
➥ "Houses");

Retrieving an existing attachment


You can retrieve an attachment from the Attachments collection with the
Item method by the number associated with the attachment.

{Retrieve the third attachment from the Attachments collection.}


attachment = mailItem.Attachments.Item(3);

420 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

Retrieving an attachment’s index


Use the Index property to retrieve the index of the attachment in the
Attachments collection.

{Retrieve the attachment’s index.}


itemIndex = attachment.Index;

Removing an attachment
Use the Delete method from the Attachment object to remove an
attachment from a mail message.

{Remove the attachment from the mail message.}


attachment.Delete();

You can also use the Remove method from the Attachments collection to
remove an attachment from a mail message. You must supply the number
associated with the attachment.

{Delete the second attachment from the Attachments collection.}


mailItem.Attachments.Remove(2);

Saving an attachment as a file


Use the SaveAsFile method to save the attachment as a file. You must
specify the filename of the file.

{Save the first attachment in the Attachments collection as a file.}


mailItem.Attachments.Item(1).SaveAsFile("C:\RESM\HOUSES.TXT");

Recipient object
The Recipient object allows you to work with a user in Outlook. The
Recipients collection contains all of the recipients in an Outlook item, such
as a mail message.

Adding a recipient
Use the Add method to add a recipient to the Recipients collection. You
must specify the display name of the recipient.

{Add a new recipient to the Recipients collection.}


recipient = mailItem.Recipients.Add("Kim Akers");

Creating a new recipient does not ensure that the recipient has an entry in the
Outlook address book. Use the Resolve method to verify that an entry exists in the
address book for a recipient.

PROGRAMMER’S GUIDE VOLUME 2 421


PA RT 9 U S I N G C O M

Retrieving a recipient
You can retrieve a recipient from the Recipients collection with the Item
method by the number associated with the recipient.

{Retrieve the third recipient from the Recipients collection.}


recipient = mailItem.Recipients.Item(3);

You can also access a recipient by the display name of the recipient.

{Retrieve the recipient named "Kim Akers".}


recipient = mailItem.Recipients.Item("Kim Akers");

Retrieving a recipient’s index


Use the Index property to retrieve the index of the recipient in the
Recipients collection.

{Retrieve the recipient’s index.}


itemIndex = recipient.Index;

Resolving a recipient’s address


Use the Resolve method to resolve a recipient’s address with the addresses
contained in all of the active address books. The Resolve method returns
true if the recipient’s address is resolved. Otherwise, it returns false.

{Resolve the recipient’s address with the addresses in the active


address books.}
resolved = recipient.Resolve();

You can also use the ResolveAll method from the Recipients collection to
resolve all of the recipients’ addresses simultaneously. The ResolveAll
method returns true if all of the addresses are resolved. Otherwise, it
returns false.

{Resolve all of the mail message’s recipients.}


resolved = mailItem.Recipients.ResolveAll();

422 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

Use the Resolved property to find out if a recipient’s address has been
resolved. The following example warns the user if a recipient in the
Recipients collection has not been resolved.

{Warn the user if an address has not been resolved.}


for i = 1 to mailItem.Recipients.Count do
if(not mailItem.Recipients.Item(i).Resolved) then
warning str(mailItem.Recipients.Item(i).Name) +
➥ " has not been resolved.";
end if;
end for;

Specifying the type of the recipient


Use the Type property and a constant from the olMailRecipientType
enumeration to specify the recipient type.

{Set the recipient type to blind carbon copy.}


recipient.Type = Outlook.olBCC;

Retrieving the display name of a recipient


Use the Name property to retrieve the display name of a recipient.

{Retrieve the recipient’s display name.}


aName = str(recipient.Name);

Retrieving the e-mail address of a recipient


Use the Address property to retrieve the e-mail address of a recipient.

{Retrieve a recipient’s e-mail address.}


emailAddress = str(recipient.Address);

Deleting a recipient
Use the Delete method from the Recipient object to delete a recipient from
a mail message.

{Delete the recipient.}


recipient.Delete();

PROGRAMMER’S GUIDE VOLUME 2 423


PA RT 9 U S I N G C O M

You can also use the Remove method to delete a recipient from the
Recipients collection. You must supply the number associated with the
recipient.

{Delete the third recipient in the Recipients collection.}


mailItem.Recipients.Remove(3);

ContactItem object
The ContactItem object allows you to work with a contact. An Items
collection is associated with each MAPIFolder object. The collection
contains all of the contact items in the folder.

Creating a new contact


Use the CreateItem method from the Application object to create a new
contact. You must specify the item type with the olContactItem constant
from the olItemType enumeration. The contact is automatically added to
the Items collection.

{Create a new contact.}


contactItem = app.CreateItem(Outlook.olContactItem);

You can also use the Add method from the Items collection to create a new
contact. You must specify the item type with the olContactItem constant.

{Add a new contact to the Items collection.}


contactItem = folder.Items.Add(Outlook.olContactItem);

Retrieving an existing contact


You can retrieve a contact from the Items collection associated with the
Item method by the number associated with the contact.

{Retrieve the third contact from the Items collection.}


contactItem = folder.Items.Item(3);

You can also access contacts by the name of the contact.

{Retrieve the contact named "Kim Akers".}


contactItem = folder.Items.Item("Kim Akers");

424 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

Displaying a contact
Use the Display method to display a contact in a window.

{Display the contact.}


contactItem.Display();

Setting and retrieving a contact’s first name


The FirstName property allows you to set or retrieve a contact’s first name.
Setting the FirstName property specifies the first name of a contact.

{Set the contact’s first name.}


contactItem.FirstName = "Kim";

You can also use the FirstName property to retrieve the first name of a
contact.

{Retrieve the contact’s first name.}


aName = str(contactItem.FirstName);

Setting and retrieving a contact’s last name


The LastName property allows you to set or retrieve a contact’s last name.
Setting the LastName property specifies the last name of a contact.

{Set the contact’s last name.}


contactItem.LastName = "Akers";

You can also use the LastName property to retrieve the last name of a
contact.

{Retrieve the contact’s last name.}


aName = str(contactItem.LastName);

Setting and retrieving a contact’s job title


The JobTitle property allows you to set or retrieve a contact’s job title.
Setting the JobTitle property specifies the job title of a contact.

{Set the contact’s job title.}


contactItem.JobTitle = "Accountant";

You can also use the JobTitle property to retrieve the job title of a contact.

{Retrieve the contact’s job title.}


jobTitle = str(contactItem.JobTitle);

PROGRAMMER’S GUIDE VOLUME 2 425


PA RT 9 U S I N G C O M

Saving a contact as a file


If you have previously saved a contact, use the Save method to save the
contact.

{Save an existing contact.}


contactItem.Save();

To save a new contact, use the SaveAs method. You must supply the
filename for the contact. You can also specify the saved contact’s file type
with a constant from the olSaveAsType enumeration. If you do not specify
a constant from the olSaveAsType enumeration, the contact is saved as the
message file type.

{Save a new contact as a text file.}


contactItem.SaveAs("C:\RESM\KIMAKERS.TXT", Outlook.olTXT);

You can use the Saved property to find out if a contact has been saved. The
Saved property returns true if the contact has been saved. Otherwise, it
returns false. You cannot set the value of the Saved property.

{If a contact has not been saved, save it.}


if(not contactItem.Saved) then
contactItem.Save();
end if;

Deleting a contact
To delete a contact, use the Delete method.

{Delete the contact.}


contactItem.Delete();

Contacts that are deleted are sent to the Deleted Items folder. However, if a contact
is deleted from the Deleted Items folder, it is permanently deleted.

Closing a contact
Use the Close method to close a contact. You can use the constants
contained in the olInspectorSave enumeration to specify the whether a
contact is saved when it is closed. To save a contact as a contact, use the
Close method and specify the olSave constant.

{Close the contact and save all changes without asking the user.}
contactItem.Close(Outlook.olSave);

426 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 6 M I C R O S O F T O U TL O O K

Script example
The following example uses objects from the Microsoft Outlook Object
Library to create a mail message, resolve the recipient’s e-mail address, and
send the mail message if the recipient’s e-mail address has been resolved.

local Outlook.Application app;


local Outlook.NameSpace nameSpace;
local Outlook.MAPIFolder folder;
local Outlook.MailItem mailItem;
local Outlook.Recipient recipient;

local boolean resolved;


local integer i;

{If Outlook is running, use it. Otherwise, create a new instance.}


app = COM_GetObject("Outlook.Application");
if(app = null) then
app = new Outlook.Application();
end if;

{Get a namespace.}
nameSpace = app.GetNameSpace("MAPI");

{Retrieve the default Inbox folder and display it.}


folder = nameSpace.GetDefaultFolder(Outlook.olFolderInbox);
folder.Display();

{Create a new mail message.}


mailItem = app.CreateItem(Outlook.olMailItem);

{Add a recipient to the mail message.}


recipient = mailItem.Recipients.Add("Kim Akers");

{Resolve the addresses of the mail message’s recipients.}


resolved = recipient.Resolve();

{Specify the mail message’s subject and body.}


mailItem.Subject = "Houses that matched your profile.";
mailItem.Body = "The attachment details the houses that matched" +
➥ "your profile. -Steve";

PROGRAMMER’S GUIDE VOLUME 2 427


PA RT 9 U S I N G C O M

{Add an attachment to the mail message.}


mailItem.Attachments.Add("C:\RESM\Houses.txt", none, none,
➥ "Matched Houses");

{Display the mail message.}


mailItem.Display();

{If the recipient’s address has been resolved, send the mail message.
Otherwise, warn the user that the message cannot be sent.}
if(resolved) then
mailItem.Send();
else
warning "Cannot send message. E-mail address has not been"
➥ + "resolved.";
end if;

{Close Outlook.}
app.Quit();

{Clear variables.}
clear mailItem;
clear folder;
clear nameSpace;
clear app;

428 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Chapter 47: Microsoft XML
To work with XML, use the Microsoft XML Object Library. Information
about using the Microsoft XML Object Library is divided into the following
sections:

• Microsoft XML Object Library overview


• Declared variables
• DOMDocument object
• IXMLDOMNode object
• IXMLDOMNodeList object
• IXMLDOMProcessingInstruction object
• IXMLDOMElement object
• IXMLDOMText object
• Script example

The following examples are written for version 5.0 of the Microsoft XML
Object Library. If you use a different version of the object library, you may
need to change the code for it to work properly.

Microsoft XML Object Library overview


The Microsoft XML Object Library contains objects, methods, and
properties that allow you to work with XML documents. This introduction
to the Microsoft XML Object Library does not describe every object.
Instead, it focuses on the following objects:

• DOMDocument object
• IXMLDOMNode object
• IXMLDOMNodeList object
• IXMLDOMProcessingInstruction object
• IXMLDOMElement object
• IXMLDOMText object

Refer to the help file for the Microsoft XML Object Library for a complete
description of all of the objects contained in the library.

To use the Microsoft XML Object Library, you must first create a
DOMDocument object with a sanScript function. For more information
about creating COM objects with sanScript functions, refer to Chapter 39,
“COM in sanScript.” You can create all of the other objects from methods
provided in the library.

PROGRAMMER’S GUIDE VOLUME 2 429


PA RT 9 U S I N G C O M

The following illustration displays the relationships between the objects


that are discussed.

You should create the


DOMDocument object
DOMDocument object first.
IXMLDOMNode object

IXMLDOMNodeList object
Create the remaining
objects from methods IXMLDOMProcessingInstruction object
provided with the library.
IXMLDOMElement object

IXMLDOMText object

Declared variables
In the script examples, it is assumed that you have declared the following
variables:

Variable Name Variable Type


xmlDoc MSXML2.DOMDocument
copiedDoc MSXML2.DOMDocument
node MSXML2.IXMLDOMNode
procInstruct MSXML2.IXMLDOMProcessingInstruction
element MSXML2.IXMLDOMElement
nameElement MSXML2.IXMLDOMElement
addressElement MSXML2.IXMLDOMElement
textNode MSXML2.IXMLDOMText
nodeList MSXML2.IXMLDOMNodeList
loaded boolean
i integer
dataLength long
nodeData string
XMLTextField text

430 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

DOMDocument object
The DOMDocument object represents an XML document.

Creating a new XML document


Use the new keyword to create a new DOMDocument object.

{Create a new XML document.}


xmlDoc = new MSXML2.DOMDocument();

When using Distributed COM (DCOM), create a new DOMDocument


object with the COM_CreateObject() function. In the following example,
the COM_CreateObject() function creates a new DOMDocument object
on the computer “SystemServer”.

{Create a new XML document.}


xmlDoc = COM_CreateObject("MSXML2.DOMDocument", "SystemServer");

Loading an existing XML document


Use the loadXML method to load a well-formed string of XML as an XML
document. The loadXML method returns true if the XML string loads
successfully. Otherwise, the method sets the documentElement property to
null and returns false.

{Load a string of XML.}


loaded = xmlDoc.loadXML
➥ ("<seller><ID>20</ID><name>Don Hall</name></seller>");

You can use the load method to load an XML file. The load method returns
true if the XML file loads successfully. Otherwise, the method sets the
documentElement property to null and returns false. You can supply either
the pathname or the URL of the XML file.

{Load an XML file.}


loaded = xmlDoc.load("C:\RESM\HOUSES.XML");

The loadXML method and the load method discard the current document before
loading a new document. If the method fails, the documentElement property
returns null.

PROGRAMMER’S GUIDE VOLUME 2 431


PA RT 9 U S I N G C O M

Setting and retrieving the document element


Refer to The DOMDocument object can reference one IXMLDOMElement object,
IXMLDOMElement called the document element. You can set the document element with the
object on page 437 for documentElement property from the DOMDocument object.
more information on
IXMLDOMElement {Set the document element.}
objects. xmlDoc.documentElement = element;

You can also retrieve the document element with the documentElement
property. If a document element does not exist, the property returns null.

{Retrieve the document element.}


element = xmlDoc.documentElement;

Specifying a document’s selection language


Use the setProperty method to specify the selection language for an XML
document. The selection language allows you to search a document for a
certain element. You must specify both the string “SelectionLanguage” and
either the XSLPattern or XPath selection language. The XSLPattern
language is the default selection language for XML documents.

{Specify XPath as the selection language for the document.}


xmlDoc.setProperty("SelectionLanguage", "XPath");

Refer to the help file for the Microsoft XML Object Library for more
information on the XSLPattern and XPath selection languages.

Representing an XML document as text


Use the xml property to create a text representation of an XML document.

{Represent an XML document as text.}


XMLTextField = xmlDoc.xml;

Copying an XML document


Use the save method to copy an XML document to another
DOMDocument object.

{Copy an XML document.}


xmlDoc.save(copiedDoc);

432 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

Saving an XML document


To save an XML document as a file, use the save method. You must supply
a string containing the complete pathname for the file.

{Save the XML document as HOUSES.XML.}


xmlDoc.save("C:\RESM\HOUSES.XML");

IXMLDOMNode object
The IXMLDOMNode object represents a node from an XML document.
An IXMLDOMNode object can contain an IXMLDOMElement object, an
IXMLDOMProcessingInstruction object, or an IXMLDOMText object.

Refer to Creating a node


IXMLDOMProcessing- Use the createNode method from the DOMDocument object to create a
Instruction object on new node. You must specify the node type with a constant from the
page 436, IXMLNodeType enumeration, the name of the node, and the namespace
IXMLDOMElement for the node.
object on page 437, or
IXMLDOMText object {Create an element as an IXMLDOMNode object.}
on page 440 for more node = xmlDoc.createNode(MSXML2.NODE_ELEMENT, "Seller", "");
information on how to
use the following If you do not want to specify a namespace for the node, specify the empty string
methods. (""). Then node is created with the current document as the namespace.

Creating a node with the createNode method does not add the node to an
XML document. You must add the node to an XML document with the
insertBefore method, appendChild method, or the replaceChild method.

Adding a node
Use the insertBefore method to insert a nodes before another node in a
document. You must specify the node you are adding as well as the node
you are adding it in front of.

{Add the node before the nameElement.}


xmlDoc.insertBefore(node, nameElement);

PROGRAMMER’S GUIDE VOLUME 2 433


PA RT 9 U S I N G C O M

You can also use the appendChild method to add a node after all of the
other nodes in a document.

{Add the node to the XML document.}


xmlDoc.appendChild(node);

Retrieving a node
The childNodes collection contains all of the nodes in an XML document.
You can retrieve a node from the childNodes collection with the item
method by the index associated with the node.

{Retrieve the first node from the childNodes collection.}


node = element.childNodes.item[0];

Replacing a node
Use the replaceChild method to replace a node in a document with another
node. The node you are replacing is returned.

{Replace the element with a node.}


element = xmlDoc.replaceChild(element, node);

Retrieving the text content from a node


Use the text property to retrieve the text content from a node.

{Retrieve the text content from the node.}


nodeData = string(node.text);

Deleting a node
Use the removeNode method to remove a node from a document.

{Remove the node from the document.}


xmlDoc.removeChild(node);

434 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

IXMLDOMNodeList object
The IXMLDOMNodeList object refers to a list of IXMLDOMNode
objects. An IXMLDOMNodeList object immediately reflects changes
made to the nodes in the list.

Creating a node list


Use the selectNodes method to create an IXMLDOMNodeList object that
contains all of the nodes matching a specified pattern. The following
example uses XPath as the selection language to search for all of the
Seller_First_Name elements.

{Specify XPath as the selection language.}


xmlDoc.setProperty("SelectionLanguage", "XPath");
{Retrieve all of the instances of a Seller_First_Name element.}
nodeList = element.selectNodes("Seller_First_Name");

You may use either the XSLPattern or XPath selection languages to specify the
pattern you want to search an element for. For more information on specifying the
selection language, refer to DOMDocument object on page 431.

Retrieving the size of a node list


Use the length property to retrieve the size of a node list.

{Retrieve the size of the node list.}


dataLength = nodeList.length;

Retrieving a node
You can retrieve an object from an IXMLNodeList object with the item
method by the index associated with the object.

{Retrieve the fifth node from the node list.}


node = nodeList.item[5];

You can also access all of nodes in the list sequentially with the nextNode
method.

{Loop through the nodes in the node list and remove them from the
document.}
for i=1 to nodeList.length do
node = nodeList.nextNode();
xmlDoc.removeChild(node);
end for;

PROGRAMMER’S GUIDE VOLUME 2 435


PA RT 9 U S I N G C O M

Use the reset method to allow the nextNode method to return the first
node in the list.

{Reset the node list to the beginning.}


nodeList.reset();

IXMLDOMProcessingInstruction object
The IXMLDOMProcessingInstruction object represents a processing
instruction, or information that specifies how an application should
interpret an XML document. An example of a processing instruction is a
document prolog, which specifies the XML version of a document. The
prolog can also specify the character encoding of a document and whether a
document requires additional information to be interpreted correctly.

Creating a processing instruction


Use the createProcessingInstruction method from the DOMDocument
object to create a new processing instruction. You must supply the target
value and its attributes. In the following example, the target value is “xml”,
and the attribute is “version="1.0"”.

{Create a document prolog processing instruction.}


procInstruct = xmlDoc.createProcessingInstruction("xml", "version=" +
➥ QUOTE +"1.0" + QUOTE);

Creating a processing instruction with the createProcessingInstruction


method does not add the processing instruction to an XML document. You
must add the processing instruction to an XML document or an element
with the insertBefore method or the replaceChild method.

Adding a processing instruction


Use the insertBefore method to insert a processing instruction before the
document element. You must specify the processing instruction as well as
the document element.

{Add the processing instruction before the document element.}


xmlDoc.insertBefore(procInstruct, xmlDoc.documentElement);

A processing instruction can be added to either a DOMDocument object or an


IXMLDOMElement object.

436 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

Retrieving a processing instruction


Refer to The childNodes collection contains all of the nodes in an XML document.
IXMLDOMElement You can retrieve a node from the childNodes collection with the item
object on page 437 and method by the index associated with the node. To find a processing
IXMLDOMText object instruction in the childNodes collection, retrieve each object as an
on page 440 for more IXMLDOMNode object, and then test the object’s node type with the
information on nodeType property.
retrieving elements
and text nodes. {Retrieve the first node in the childNodes collection and find out if
it is an IXMLDOMProcessingInstruction object.}
node = element.childNodes.item[0];
if(node.nodeType = MSXML2.NODE_PROCESSING_INSTRUCTION) then
procInstruct = node;
end if;

Replacing a processing instruction


Use the replaceChild method to replace a processing instruction or element
in a document with a processing instruction. The processing instruction or
element that you are replacing is returned.

{Replace the element with a processing instruction.}


element = xmlDoc.replaceChild(procInstruct, xmlDoc.documentElement);

Deleting a processing instruction


Use the removeNode method to remove a processing instruction from a
document.

{Remove the processing instruction from the document.}


xmlDoc.removeChild(procInstruct);

IXMLDOMElement object
The IXMLDOMElement object represents an element in an XML
document.

Creating an element
Use the createElement method from the DOMDocument object to create a
new element. You must supply the name of the element.

{Create an element named "Seller_Name".}


nameElement = xmlDoc.createElement("Seller_Name");

PROGRAMMER’S GUIDE VOLUME 2 437


PA RT 9 U S I N G C O M

Creating a new element with the createElement method does not add the
element to an XML document. You must add the element to an XML
document or another element with the appendChild method, the
insertBefore method, or the replaceChild method.

Adding an element
Use the insertBefore method to insert an element before another element or
text node. You must specify the element that you are adding as well as the
element or text node that you are adding the element in front of.

{Add the nameElement before addressElement.}


xmlDoc.insertBefore(nameElement,addressElement );

You can also use the appendChild method to add an element after all
elements and text nodes in a document.

{Add the element to the XML document.}


xmlDoc.appendChild(nameElement);

An element can be added to either a DOMDocument object or another


IXMLDOMElement object.

Retrieving an element
The childNodes collection contains all of the nodes in an XML document.
You retrieve a node from the childNodes collection with the item method
by the index associated with the object. To find an element in the
childNodes collection, retrieve each object as an IXMLDOMNode object,
and then test the object’s node type with the nodeType property.

{Retrieve the first node in the childNodes collection and find out if
it is an IXMLDOMElement object.}
node = xmlDoc.childNodes.item[0];
if(node.nodeType = MSXML2.NODE_ELEMENT) then
element = node;
end if;

438 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

Refer to You can also use the selectSingleNode method to retrieve an element. The
IXMLDOMNode object selectSingleNode method searches an element for a specified pattern and
on page 433 for more returns an IXMLDOMNode object representing the first instance of the
information on pattern. If no element matches the pattern, null is returned.
IXMLDOMNode
objects. You may use either the XSLPattern or XPath selection languages to specify the
pattern you want to search for. Refer to the help file for the Microsoft XML Object
Library for more information on the XSLPattern and XPath selection languages.

The following example uses the selection language XPath to search for the
first Seller_First_Name element. For more information on specifying the
selection language, refer to DOMDocument object on page 431.

{Specify XPath as the selection language.}


xmlDoc.setProperty("SelectionLanguage", "XPath");
{Retrieve the first instance of a Seller_First_Name element.}
node = element.selectSingleNode("Seller_First_Name");

Refer to You can also use the selectNodes method to return an


IXMLDOMNodeList IXMLDOMNodeList object that contains all of the nodes matching a
object on page 435 for specified pattern. The following example uses the selection language XPath
more information on to search for all of the Seller_First_Name elements. For more information on
IXMLDOMNodeList specifying the selection language, refer to DOMDocument object on
objects. page 431.

{Specify XPath as the selection language.}


xmlDoc.setProperty("SelectionLanguage", "XPath");
{Retrieve all of the instances of a Seller_First_Name element.}
nodeList = element.selectNodes("Seller_First_Name");

Replacing an element
Use the replaceChild method to replace an node in an XML docuement
with an element. The node that you are replacing is returned.

{Replace the text node with an element.}


textNode = xmlDoc.replaceChild(element, textNode);

PROGRAMMER’S GUIDE VOLUME 2 439


PA RT 9 U S I N G C O M

Normalizing an element
Use the normalize method to normalize an IXMLDOMElement object and
its descendants. Normalizing an element combines adjacent text nodes into
a single text node. When you normalize an element, text nodes can only be
separated by markup, such as tags, comments, and processing instructions.

{Normalize an XML document.}


nameElement.normalize();

Representing an XML element as text


Use the xml property to create an XML representation of an element and its
descendants.

{Represent the element and its descendants as XML.}


XMLTextField = element.xml;

Deleting an element
Use the removeChild method to remove an element from a document or
another element.

{Remove the address element from the element.}


element.removeChild(addressElement);

IXMLDOMText object
An IXMLDOMText object represents the text content of an element. It is
commonly referred to as a text node.

Creating a text node


Use the createTextNode method from the DOMDocument object to create
a new text node. You must supply the text node’s data.

{Create a text node containing a seller’s first name.}


textNode = xmlDoc.createTextNode("Adam");

Creating a new text node with the createTextNode method does not add
the text node to an XML document. You must add the text node to an
element with the appendChild method, the insertChild method, or the
replaceChild method.

440 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

Adding a text node


Use the insertBefore method to insert a text node before an element or
another text node. You must specify the text node that you are adding as
well as the element or text node that you are adding it before.

{Add the text node before the element.}


element.insertBefore(textNode, element);

You can also use the appendChild method to add a text node after all
elements and text nodes.

{Add the text node to the element.}


element.appendChild(textNode);

A text node can be added to an IXMLDOMElement object.

Retrieving a text node


The childNodes collection contains all of the nodes in an XML document.
You retrieve a node from the childNodes collection with the item method
by the index associated with the object. To find a text node in the
childNodes collection, retrieve each object as an IXMLDOMNode object.
Then test the object’s node type with the nodeType property.

{Retrieve the first node in the childNodes collection and ascertain if


it is an IXMLDOMText object.}
node = element.childNodes.item[0];
if(node.nodeType = MSXML2.NODE_TEXT) then
textNode = node;
end if;

Replacing a text node


Use the replaceChild method to replace a text node or an element in an
element with a text node. The element or text node that you are replacing is
returned.

{Replace the element with a text node.}


element = xmlDoc.replaceChild(textNode, element);

Retrieving the length of a text node’s data


Use the the length property to retrieve the length of the data in a text node.

{Retrieve the length of the text node’s data.}


dataLength = textNode.length;

PROGRAMMER’S GUIDE VOLUME 2 441


PA RT 9 U S I N G C O M

Retrieving and setting a text node’s data


Use the data property to retrieve the data stored in a text node.

{Retrieve the data stored in the text node.}


nodeData = textNode.data;

You can also use the data property to set the data stored in a text node.

{Set the data stored in the text node to "Adam Barr".}


textNode.data = "Adam Barr";

When you set the data stored in a text node with the data property, you replace
the data previously stored in the text node.

Adding data to a text node’s data


Use the appendData method to add data to the data currently stored in a
text node.

{Add the string " Barr" to the data stored in the text node.}
textNode.appendData(" Barr");

You can also use the insertData method to add data to a text node at a
specified position.

{Add the string "Robert " to the text node at the fifth position.}
textNode.insertData(5, "Robert ");

Removing data from a text node


Use the deleteData method to delete a string of data from a text node at a
specified position. You must specify the length of the string to remove.

{Remove seven characters from the string, beginning at the fifth


position.}
textNode.deleteData(5, 7);

Deleting a text node


Use the removeChild method to remove a text node from an element.

{Remove the text node from the element.}


element.removeChild(textNode);

442 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

Script example
The following example uses objects from the Microsoft XML Object Library
to create an XML document from a record displayed in the Sellers window
of the Real Estate Sales Manager application. The XML document is saved
as SELLERS.XML.

local MSXML2.DOMDocument xmlDoc;


local MSXML2.IXMLDOMProcessingInstruction procInstruct;
local MSXML2.IXMLDOMElement docElement;
local MSXML2.IXMLDOMElement fieldElement;
local MSXML2.IXMLDOMText textNode;

{If a record is not displayed, warn the user. Otherwise, create an XML
document.}
if 'Seller ID' = "" then
warning "Please display a record in the Sellers window.";
else

{Create an XML document.}


xmlDoc = new MSXML2.DOMDocument();

{Create the document prolog and append it to the document.}


procInstruct = xmlDoc.createProcessingInstruction("xml",
➥ "version =" + QUOTE + "1.0" + QUOTE);
xmlDoc.appendChild(procInstruct);

{Create the document element and append it to the XML document.}


docElement = xmlDoc.createElement("Sellers");
xmlDoc.appendChild(docElement);

{Create a Seller ID element.}


fieldElement = xmlDoc.createElement("Seller_ID");

{Create a text node containing data from the Seller ID field and
append it to the Seller ID element.}
textNode = xmlDoc.createTextNode(str('Seller ID'));
fieldElement.appendChild(textNode);

{Append the Seller ID element to the document element.}


docElement.appendChild(fieldElement);

PROGRAMMER’S GUIDE VOLUME 2 443


PA RT 9 U S I N G C O M

{Create a Seller First Name element.}


fieldElement = xmlDoc.createElement("Seller_First_Name");

{Create a text node containing data from the Seller First Name
field and append it to the Seller First Name element.}
textNode = xmlDoc.createTextNode(str('Seller First Name'));
fieldElement.appendChild(textNode);

{Append the Seller First Name element to the document element.}


docElement.appendChild(fieldElement);

{Create a Seller Last Name element.}


fieldElement = xmlDoc.createElement("Seller_Last_Name");

{Create a text node containing data from the Seller Last Name
field and append it to the Seller Last Name element.}
textNode = xmlDoc.createTextNode(str('Seller Last Name'));
fieldElement.appendChild(textNode);

{Append the Seller Last Name element to the document element.}


docElement.appendChild(fieldElement);

{Create a Phone element.}


fieldElement = xmlDoc.createElement("Phone");

{Create a text node containing data from the Phone field and
append it to the Phone element.}
textNode = xmlDoc.createTextNode(str(Phone));
fieldElement.appendChild(textNode);

{Append the Phone element to the document element.}


docElement.appendChild(fieldElement);

{Save the XML document.}


xmlDoc.save("C:\RESM\SELLER.XML");
end if;

{Clear the variables.}


clear textNode;
clear fieldElement;
clear docElement;
clear procInstruct;
clear xmlDoc;

444 P R O G R A M M E R ’ S G U I D E V O L U M E 2
C H A P T E R 4 7 M I C R O S O F T X M L

The following example uses objects from the Microsoft XML Object Library
to parse an XML document and construct a Buyer_Data record in the Real
Estate Sales Manager application.

local MSXML2.DOMDocument xmlDoc;


local MSXML2.IXMLDOMNode rootNode;
local MSXML2.IXMLDOMNode dataNode;

{Create an XML document.}


xmlDoc = new MSXML2.DOMDocument();

{Load the BUYERS.XML file.}


xmlDoc.load("C:\RESM\BUYERS.XML");

{Retrieve the document’s first child node.}


rootNode = xmlDoc.documentElement;

{Retrieve the 'BuyerID' element and set the 'Buyer ID' field to the
text node’s data.}
dataNode = rootNode.selectSingleNode("BuyerID");
'Buyer ID' of table Buyer_Data =
➥ string(dataNode.childNodes.item[0].text);

{Retrieve the 'BuyerFirstName' element and set the 'Buyer First Name'
field to the text node’s data.}
dataNode = rootNode.selectSingleNode("BuyerFirstName");
'Buyer First Name' of table Buyer_Data =
➥ string(dataNode.childNodes.item[0].text);

{Retrieve the 'Buyer_Last_Name' element and set the 'Buyer Last Name'
field to the text node’s data.}
dataNode = rootNode.selectSingleNode("Buyer_Last_Name");
'Buyer Last Name' of table Buyer_Data =
➥ string(dataNode.childNodes.item[0].text);

{Retrieve the 'Buyer_Last_Name' element and set the 'Buyer Last Name'
field to the text node’s data.}
dataNode = rootNode.selectSingleNode("Buyer_Last_Name");
'Buyer Last Name' of table Buyer_Data =
➥ string(dataNode.childNodes.item[0].text);

PROGRAMMER’S GUIDE VOLUME 2 445


PA RT 9 U S I N G C O M

{Retrieve the 'Agent' element and set the 'Agent' field to the text
node’s data.}
dataNode = rootNode.selectSingleNode("Agent");
Agent of table Buyer_Data = string(dataNode.childNodes.item[0].text);

{Save the record, and clear the table buffer.}


save table Buyer_Data;
clear table Buyer_Data;

{Clear the variables.}


clear dataNode;
clear rootNode;
clear xmlDoc;

446 P R O G R A M M E R ’ S G U I D E V O L U M E 2
APPENDIX
Appendix
The following appendixes are provided:

• Appendix A, “Dexterity Limits,” describes various limits within the


Dexterity development system.

• Appendix B, “Reserved Words,” contains a list of sanScript reserved


words.

• Appendix C, “ASCII Character Codes,” provides a list of ASCII


character codes.

448 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Appendix A: Dexterity Limits
The following is a list of limits for the Dexterity development system.

Resource Category Limit


Arrays Size Up to 32,767 elements in an array.
Constants Name Cannot exceed 79 characters.
Dynamic Link Parameters You can pass a maximum of 255 parameters to a DLL.
Libraries (DLLs)
Fields and data Composites The maximum displayable length is 128 characters,
types including separator characters.
Standard composites can have up to 9 components.
Extended composites can have up to 128 components.
Button drop list Can display a maximum of 32,767 items, each up to 79
Drop down list characters long.
List box
Non-native list box
Visual switch
ListView Maximum of 256 columns.
Can have up to 15 state images.
Can use up to 4 different overlay images at one time.
Multi-select list box Can display a maximum of 32 items.
Can display a maximum of 79 characters per line.
Picture Can store images having sizes up to 32,767 bytes.
Push button One default button per window.
One cancel button per window.
String Maximum keyable length is 255 characters.
Text Can store a maximum of 32,000 characters.
TreeView Can have up to 15 state images.
Can use up to 4 different overlay images at one time.
Forms Total number Maximum of 8191 forms per dictionary for Windows Help
to be supported properly.
Global fields Total number Maximum of 8191 global fields per dictionary for Windows
Help to be supported properly.
Global variables Total size There can be up to 64K of global variables.
Local fields Total number per form Maximum of 8191 local fields per form for Windows Help to
be supported properly.
Menus Displaying Application can display a maximum of 15 menus at a time.
Messages Length The maximum length of the message, including all
arguments in the message, is 255 characters.

PROGRAMMER’S GUIDE VOLUME 2 449


A P P E N D I X A D EX T ER IT Y L IM I T S

Resource Category Limit


Native pictures Size Native pictures can be up to 32,767 bytes.
Pictures Size Pictures in the picture library can be up to 32,767 bytes.
Procedures Parameters Can include a maximum of 255 parameters.
Up to 32K of parameters can be passed to and from a
procedure.
Reports Additional footers Can have up to 15 additional footers.
Additional headers Can have up to 15 additional headers.
Legends Up to 255 legends can be added to a layout.
Text fields Can display up to 10K of text on a report.
Scripts run script statement Can have a maximum of six levels of scripts started with
the run script statement.
Local variables Scripts can have up to 64K of local variable space.
Script size Scripts can be up to approximately 24,000 characters long,
including spaces and comments.
Static strings Length Can be up to 79 characters in length.
Number per dictionary The main product dictionary can have 39,998 strings.
Integrating product dictionaries can have 20,000 strings.
Forms and reports dictionaries can have 4000 strings.
Tables Keys 16 keys per table (Dexterity limit).
255 bytes per key (Dexterity limit).
Open tables The maximum number of open tables is approximately 95.
Ranges Only one range per table buffer.
Record size (Fixed- Maximum of 4,088 bytes (approximately 4K) for
length portion) Pervasive.SQL
Maximum of 32,767 bytes (32K) for c-tree.
Maximum of 8,060 bytes for SQL.
Record size (Variable- 32,767 bytes (32K) for Pervasive.SQL and c-tree.
length portion)
Columns 255 columns per table (SQL limit).
Segments 16 segments per key (Dexterity limit).
119 segments per table for Pervasive.SQL.
384 segments per table for c-tree.
1024 segments per table for SQL.
Sorting Dexterity can sort tables of up to 1,000,000 records.
Table access One table buffer per table per form.
User-defined Parameters A maximum of 254 parameters, plus the return value.
functions Up to 32K of parameters can be passed to and from a user-
defined function.

450 P R O G R A M M E R ’ S G U I D E V O L U M E 2
A P PE N D I X A D E XT E R IT Y LI M IT S

Resource Category Limit


Virtual tables Number of tables Up to 16 standard tables as part of the virtual table.
Keys 16 keys for the virtual table.
Relationships Only one main branch can have 1-to-many relationships.
Windows Auto-linking A window can be auto-linked to one table.
Objects per window A window can contain up to 32,767 objects.
Selecting objects You can select up to 200 objects in a window layout at one
time.
Tool bar windows Only one tool bar window can be open in an application at
one time.
Total number Maximum of 15 windows per form for Windows Help to be
supported properly.

PROGRAMMER’S GUIDE VOLUME 2 451


452 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Appendix B: Reserved Words
Refer to Chapter 21, The following table lists the reserved words in Dexterity. These are
“Constants,” in Volume sanScript keywords and shouldn’t be used as the names of variables in
1 of the Dexterity scripts. Using a reserved word as a name in a script may prevent the script
Programmer’s Guide from being compiled. Dexterity reserved words are case-sensitive. For
for a list of constants in instance, “add” is a reserved word; “Add” is not.
Dexterity. Constants
are also considered abort disable integer range top
sanScript reserved add do is real transaction
words. and dollar item record true
anonymous edit last recur type
application else legends redraw uncheck
array elseif line refresh unlock
as enable load release until
assign end local reject wait
at endgroup lock remote warning
background equals long remove weeks
beep error macro repeat while
begingroup every menu report width
blocksize exclusive minutes resid windows
boolean exit module resize with
bottom expand months restart years
by extern move restriction window
call factor name return
case false next rollback
change field nocase run
changes file nofocus save
check fill none script
clear first not select
close focus notify service
commit for number set
component force of show
continue form open sort
copy from optional sproc
currency get on start
current globals or step
date help out string
days hide override substitute
debug hold page sum
decrement hours palettes system
delayed id precision table
deletable if prev text
delete in print then
descend increment printer time
destination inout priority title
dictionary insert queue to

PROGRAMMER’S GUIDE VOLUME 2 453


454 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Appendix C: ASCII Character Codes
This appendix lists the ASCII codes 0 through 127, the characters they
represent and the keystrokes that generate them.
Value Char Key Value Char Key Value Char Key
0 NUL None 43 + + 86 V V
1 SOH CTRL-A 44 , , 87 W W
2 STX CTRL-B 45 - - 88 X X
3 ETX CTRL-C 46 . . 89 Y Y
4 EOT CTRL-D 47 / / 90 Z Z
5 ENQ CTRL-E 48 0 0 91 [ [
6 ACK CTRL-F 49 1 1 92 \ \
7 BEL CTRL-G 50 2 2 93 ] ]
8 BS CTRL-H 51 3 3 94 ^ ^
9 HT CTRL-I 52 4 4 95 _ _
10 LF CTRL-J 53 5 5 96 ` `
11 VT CTRL-K 54 6 6 97 a a
12 FF CTRL-L 55 7 7 98 b b
13 CR CTRL-M 56 8 8 99 c c
14 SO CTRL-N 57 9 9 100 d d
15 SI CTRL-O 58 : : 101 e e
16 DLE CTRL-P 59 ; ; 102 f f
17 DC1 CTRL-Q 60 < < 103 g g
18 DC2 CTRL-R 61 = = 104 h h
19 DC3 CTRL-S 62 > > 105 i i
20 DC4 CTRL-T 63 ? ? 106 j j
21 NAK CTRL-U 64 @ @ 107 k k
22 SYN CTRL-V 65 A A 108 l l
23 ETB CTRL-W 66 B B 109 m m
24 CAN CTRL-X 67 C C 110 n n
25 EM CTRL-Y 68 D D 111 o o
26 SUB CTRL-Z 69 E E 112 p p
27 ESC ESC 70 F F 113 q q
28 FS CTRL-\ 71 G G 114 r r
29 GS CTRL-] 72 H H 115 s s
30 RS NONE 73 I I 116 t t
31 US NONE 74 J J 117 u u
32 SPACE SPACE 75 K K 118 v v
33 ! ! 76 L L 119 w w
34 " " 77 M M 120 x x
35 # # 78 N N 121 y y
36 $ $ 79 O O 122 z z
37 % % 80 P P 123 { (
38 & & 81 Q Q 124 | |
39 ' ' 82 R R 125 } )
40 ( ( 83 S S 126 ~ ~
41 ) ) 84 T T 127 DEL BACKSPACE
42 * * 85 U U

PROGRAMMER’S GUIDE VOLUME 2 455


A P PE N D I X C AS CII CH ARA C T E R C O DE S

Unprintable characters
In the following table, the unprintable ASCII characters are listed along
with their meaning. Many of these unprintable characters serve different
functions that vary from one operating system to another.

Unprintable character Meaning


NUL Null character
SOH Start of header
STX Start of text
ETX End of text
EOT End of transmission
ENQ Enquiry
ACK Acknowledge
BEL Bell character
BS Back space
HT Horizontal tab
LF Line feed
VT Vertical tab
FF Form feed
CR Carriage return
SO Shift out
SI Shift in
DLE Data link escape
DC1 Device control one (resume transmission)
DC2 Device control two
DC3 Device control three (stop transmission)
DC4 Device control four
NAK Negative acknowledge
SYN Synchronous idle
ETB End of transmitted block
CAN Cancel
EM End of medium
SUB Substitute
ESC Escape
FS File separator
GS Group separator
RS Record separator
US Unit separator
DEL Delete

456 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Glossary Alert message
A message that appears when
AutoLinkTable property
A Dexterity feature that allows the
inappropriate, inadequate or unclear Modifier to add fields to a window from
3-D highlight data or instructions are issued, when data the auto-linked table. Each window can
An Appearance setting for push buttons, is not accessible or when a confirmation have only one auto-linked table.
and button drop lists that causes them to is required.
have a flat appearance until the mouse Auto-chunk
pointer is moved over the button. Then Alphanumeric A utility in Dexterity Utilities that
the button appears with a 3-D border. A combination of numbers and letters. simplifies the process of creating a single
dictionary chunk from an application
Accelerator key Anonymous tables and fields dictionary.
A key or set of keys on the keyboard that Refers to procedures where the names of
can be used as a “shortcut” to select a the tables and/or fields that will be Auto-generated stored
menu or menu option rather than using passed to the script aren’t known when procedures
the mouse. the procedure is written. Anonymous Stored procedures automatically created
tables and fields can make procedures by Dexterity to optimize database
Access key more generic and more useful. performance for SQL tables.
An underlined character in a menu name
or item that allows users to select the Array field Background tasks
item by typing the underlined character A field containing multiple occurrences Processing tasks, such as printing a
or by holding down the ALT key and of the same type of information. The report or running a procedure, that occur
typing the character. individual pieces of information stored while allowing other tasks to be
by an array field are called elements. For completed simultaneously, such as
Active locking example, a seven-element array field entering data in a window. For instance, a
A method of locking that ensures only could be used to store daily sales totals procedure can be run in the background
one user can change or delete the instead of seven individual fields. using the background parameter of the
contents of a record at one time. The data call statement.
in the locked record can’t be changed or Array index
deleted by another user until the lock is The number designating a specific Big line item
released. The lock for the record is element within an array field. Each The area containing the fields that will be
released when the user with the active component field within an array field has displayed for a scrolling window in
lock moves to another record or closes an array index. expanded mode. When the scrolling
the table. window is in standard mode, only fields
When creating calculated fields
within the area marked by the small line
Add-line containing array fields, legends passed
item will be displayed. The mode for a
using the run report statement can be
The blank line at the bottom of an adds- scrolling window is determined with the
used as the array field’s index.
allowed scrolling window that allows expand statement.
you to enter new information using the Ask dialog box
scrolling window. Block
A modal dialog box generated by the
A specified portion of the dictionary. For
Additional headers and footers ask() function. A dialog box displays a
instance, an unused “block” within a
text string, an information icon and up to
Report sections that are printed when a dictionary refers to a portion of the
three push buttons allowing the user to
specified field changes. Additional dictionary that isn’t being used, or a
headers and footers are created using the make a selection.
portion that at one time contained
Report Options and Header/Footer AutoCopy property information that has been deleted. You
Options windows. A Dexterity feature that simplifies can remove unused blocks by using the
copying information between a table compress utility of Dexterity Utilities.
Adds-allowed scrolling window
buffer and a window.
A scrolling window that allows the user Boolean expression
to enter and save new information using An expression that results in a value of
the scrolling window. true or false.

PROGRAMMER’S GUIDE VOLUME 2 457


GLOS SA RY

Breakpoint Called script Chunk dictionary


A marker that can be placed on a line in a The procedure or form procedure that’s A dictionary that contains portions, or
script. When the breakpoint is invoked by a calling script. The “chunks,” of resources from a source
encountered while the script is running, parameters for the called script are dictionary. Chunk dictionaries allow
the application will stop just prior to provided, or passed, by the calling script. large dictionaries to be divided into more
executing the line of code on which the manageable pieces for delivery to
breakpoint is placed. Calling script customers. The runtime engine
The script (such as a procedure, function “unchunks,” or merges the chunk
Browse-only scrolling window or an attached script) that accesses, or dictionaries to re-create the original
A scrolling window that allows the user calls, a procedure. dictionary. Chunk dictionaries can also be
to browse through items in the window, used to deliver updates for an
but not make any changes. Cancel property
A property that can be applied to a push application.
Btrieve button window field. If this property is Chunk utility
See Pervasive.SQL. set to True, pressing the ESC key produces A function of the Dexterity Utilities that
the same result as clicking the push allows you to transfer “chunks,” or
Buffer button. related pieces of information, from a
A temporary storage area in a computer’s
memory. Dexterity uses several types of Cascading menus source dictionary to a chunk dictionary.
This utility is useful for updating specific
buffers, such as table buffers and window Submenus that appear to the right of a
portions of a dictionary when the
buffers. menu item.
dictionary is very large (such as the
Button drop list Catch Dynamics.dic dictionary). When you’ve
A control type used to define data types The process of handling a specific modified or added resources in the chunk
that allow a user to select one item from a exception. See also Exception, Exception dictionary, you can merge it back into
list of values. handler. the source dictionary to implement
modifications.
Change flag
A boolean value associated with each Client buffer
form or window in an application. If the A client buffer is created on the client
contents of the form or window change, computer when a SQL table is opened.
A series of static text values will appear, the change flag is set to true, indicating Data retrieved from the database is
or “drop” when a user clicks a field that the contents have changed. The status of stored in this buffer. Dexterity fills the
uses this control type. the change flag is checked using the table buffer a single record at a time with
changed() script function. data from the client buffer.
c-tree Plus
A key-indexed record management Change script Client/server
system commonly used for LAN-based A script that runs when the focus leaves a An environment in which data is
and client/server applications. Dexterity field, if the information displayed in the managed by a dedicated server
contains built-in support for c-tree Plus. field has changed. Change scripts are the computer, and client computers request
No additional software is required. most common type of script. See also Pre data from the server.
script and Post script.
Calculated field Clustered index
A field containing an expression that Check box A key option available for SQL tables.
combines fields in a report’s table, report A control type used to define data types When marked, the records in the table are
fields, constants, functions and operators. that allow users to mark or unmark a sorted and physically stored in the order
The result of the calculation is displayed selection. specified by the key for which this option
in the field if the field is placed on the is marked. There can be only one
report. Calculated fields are created in the clustered index per table.
Calculated Field window.

Call stack Check boxes have boolean storage types.


An internal Dexterity mechanism that
manages the processing of scripts.

458 P R O G R A M M E R ’ S G U I D E V O L U M E 2
G L O S S A R Y

Combo box Compiler warnings Constant


A control type used to define data types Less serious problems in a script that A fixed numeric or string value used in
that allow users to enter a text value or won’t prevent it from being compiled, scripts. Constants are defined using the
choose that value from a list. but should be resolved. An example of a Constant Definition window. Dexterity
compiler warning is a local variable that also has predefined constants that are
The items in the list are determined by
is declared, but not used. used with specific functions or
the static text values in the data type statements.
definition. Items can be added to the list Component
temporarily using the add item One field of a composite field. Control area
statement. A dark gray band drawn across the top of
Composite a standard window. Push buttons and
Command A group of fields and their associated other controls can be placed in the control
In Dexterity, any function or statement data types that form a single data type. area. The ControlArea property specifies
included in the sanScript language or Composite data types are defined by the whether a window has a control area.
defined by a user. composite control type and the fields that
make up the composite. Control field
Compare A unique field within a record that’s used
To evaluate the variations between two Compress to control access to the record. Typically,
dictionaries, using Dexterity Utilities. The process of removing unneeded the control field is part of the first key for
information, such as script source, and the table.
Compatibility ID unused blocks from dictionaries.
A string that uniquely identifies the Dictionaries are typically compressed Control type
version of your application. You specify
before being sent to customers. The main characteristic of a data type,
the compatibility ID when you add
controlling the type of information that
product information to a dictionary. Compressed key can be stored in fields with the data type,
When you launch your application with A key option that allows the database and some aspects of how the information
the runtime engine, the compatibility ID manager to compress key information to will be displayed. Commonly-used
in the application dictionary is compared save space in index files. Not all database control types are push button, integer,
with the compatibility IDs in the forms managers support this option. check box, date and currency.
and reports dictionaries. If they match,
items in the forms and reports Concatenate Core module
dictionaries can be accessed. To connect two or more strings to form a A group of related resources in a
single string. Dexterity dictionary that can be
Compatibility message referenced by other resources, including
The message that is displayed when the Connection
forms and reports, throughout the
compatibility IDs in the forms or reports The link between a client and a data
dictionary. Each core module contains
dictionaries don’t match the source located on a server. Connections
allow the user at a client computer to one or more specific types of resources
compatibility ID in the main dictionary. such as fields, data types and scripts.
You specify the compatibility message issue commands to be executed on the
when you add product information to a server, and provide a pathway for the Core resources
dictionary. server’s response to the client. Resources such as strings, data types or
Connection pool global fields that are used by several
Compile parts of the application. When forms and
To run a script through a compiler. A A number of currently inactive
reports dictionaries are created, the core
compiler translates the script instructions connections between a client and a SQL
resources in the application dictionary
into a language that the computer can data source, kept open and in reserve.
The defaults file setting are copied to them.
understand. Once the script has been
compiled, the instructions within the SQLMaxInactiveConnections can be If an application being updated uses
script can be executed. used to specify the number of forms and reports dictionaries, the core
connections in the pool. resources in the forms and reports
Compiler errors dictionaries must be updated for the
Problems in a script that prevent it from application to work properly.
being compiled, such as syntax errors.

PROGRAMMER’S GUIDE VOLUME 2 459


GLOS SA RY

Cursor Database Management System Default property


A SQL database object that allows (DBMS) A property that can be applied to a push
Dexterity to work with a portion of a SQL A DBMS is computer software that button window field. If this property is
query’s results set. Dexterity uses a block controls a database. Products like set to True, pressing the ENTER key or
cursor, which can access a single record Pervasive.SQL and Microsoft SQL Server double-clicking a list box or scrolling
or a block of records. are Database Management Systems. window with the DefaultDblClick
property set to True causes the push
Cursor block size Database manager button’s change script to run.
The number of records in a SQL cursor. Software that handles the storage and
The size of this block can be defined retrieval of data on a disk. Dexterity DefaultDblClick property
using the Table Options window, the applications can use a variety of database A property for list box fields, non-native
blocksize clause of the open table managers, including Pervasive.SQL, c- list box fields, and scrolling windows.
statement or the SQLCursorBlockSize tree Plus, or Microsoft SQL Server. Prior Double-clicking the list box or a line in a
defaults file setting. to release 3 of Dexterity, a database scrolling window with this property set
manager was called a file handler. to True runs the change script for the field
Cursor refreshing with the Default property set to True. See
A process that replaces the data in the Date and time expression also Default property.
current cursor block in the client buffer An expression that results in either a date
with fresh data from the database. This or time value. Date and time expressions Defaults file
ensures that the most current data from can also result in a numeric value. A file that stores information specific to
the table is being accessed by the user. the current workstation. This file is
Deadlock condition named DEX.INI for Windows.
Custom dictionaries The error condition that occurs when two
The forms and reports dictionaries users or scripts lock separate records and Definition window
generated by the Modifier and Report then also try to lock the records already A window that allows you to create a
Writer. locked by the other. For example, resource and specify its functional
suppose script A locks record X and characteristics.
Data source script B locks record Y. Script A then also
A data source is a SQL database plus its
attempts to lock record Y and script B
Delete all
associated Database Management System One of two ways that data in a SQL table
also tries to lock record X. Both requests
(DBMS) and any network connections will be denied, forcing both scripts to can be removed from the database. The
that are necessary for a client to access the Table_SetDelete Options() function and
wait endlessly for the desired record.
data in the database. The database is the SQLDropTableOnDelete defaults
Dexterity contains mechanisms to avoid
stored on a server. deadlock conditions. file setting can be used to switch the
delete table statement’s functionality
A data source is set up using the ODBC
Debug statement between delete all and drop.
Administrator.
A Dexterity script statement that allows
Delete all removes all of the data in the
Data type you to create dialog boxes that will
table, but keeps the empty table in the
A Dexterity resource that defines the appear when an application is run in test
database. Drop removes the table and its
characteristics for a field, such as its mode. For example, the messages
auto-generated stored procedures from
keyable length, control type (push appearing in the dialog boxes can be used
the database.
button, check box, string and so on) and to indicate which script is being run or
format. A single data type can be applied the value that should be generated at a Destination dictionary
to several fields, but a field can only have given point. If debug statements aren’t The dictionary to which resources,
one data type applied to it. compiled, the messages can’t be strings and messages, windows or
displayed in test mode. Debug statement dictionary modules are transferred, using
Data types are commonly identified by messages never appear in applications the Dexterity Utilities.
their control type or storage type; for executed with the runtime engine.
instance, a radio button data type, or a
string data type.

460 P R O G R A M M E R ’ S G U I D E V O L U M E 2
G L O S S A R Y

DEX.INI file Disabled field Duplicates


A file that stores information specific to A field that is unavailable to or cannot be A key option that specifies whether the
the current workstation. Also referred to chosen by a user. A Delete button, for key will allow multiple records in the
as the defaults file. example, should be disabled until the table to have the same key value.
user selects an item to delete. A disabled
Dictionary button or field appears dimmed. Dynamic link library (DLL)
A group of Dexterity resources that, A library of code containing function
when interpreted by the runtime engine, Display name calls that can be used and shared by
present a complete functioning One of the names specified for a table. several Windows applications at once.
application. The display name is used when the name Dexterity applications created for
of the table is displayed to the user. See Windows can use DLLs to extend the
Dictionary core also Technical name. capabilities of the application.
A group of related core modules. Each
core module is placed into one of seven Display-only field Editable field
dictionary cores: System, Financial, Sales, A field that displays information but A field whose contents can be changed
Purchasing, Inventory, Payroll and whose value cannot be changed by the by the user.
Project. In Microsoft Dynamics GP, user.
dictionary cores correspond to Series. Editable scrolling window
Distributed processing A scrolling window that allows the user
Dictionary location ID A client/server feature that allows a to edit items in the window.
In a launch file, a line that indicates a set client computer to send processes, such
of dictionary locations. This set of as printing a report, to another client or Element
dictionary locations includes generic server computer. One of the fields in an array field.
pathnames for the locations of the Encrypted field
application dictionary, forms dictionary, Drop
One of two ways data in a SQL table can A field that is altered in the table, making
reports dictionary and any integrating
be removed from the database. The it impossible to view the contents of the
dictionaries. A launch file can contain
Table_SetDeleteOptions() function and field by accessing the table from outside
several sets of dictionary location IDs and of your application.
dictionary locations. the SQLDropTableOn Delete defaults
file setting can be used to switch the Ending script
Dictionary module delete table statement’s functionality One of the two procedures that can be
A group of related resources in a between delete all and drop.
associated with a dictionary chunk.
Dexterity dictionary, which can be
Delete all removes all of the data in the When you create a dictionary chunk, you
viewed and transferred using Dexterity can specify a procedure from the
Utilities. There are three types of table, but keeps the empty table in the
database. Drop removes the table and its application to be the ending script for the
dictionary modules: core, form and
auto-generated stored procedures from dictionary chunk. The ending script will
report modules. Form and report be run with the other starting and ending
modules contain resources used only on a the database.
scripts after all dictionary chunks have
specific form or report, such as local Drop-down list been unchunked. See also Starting script
fields, scripts and calculated fields, while A control type used to define data types and Installation script.
core modules contain resources that can that allow users to select one item from a
be used throughout the dictionary. list. Error dialog box
The modal dialog box generated with the
Directed Hyperspace error statement. A text string, the
The mode that allows users to open a
standard error icon for the operating
lookup form using the change script for a system, and an OK button are displayed
A series of static text values will appear,
lookup button by clicking the lookup
or “drop,” when a user clicks a field with in the dialog box.
button or choosing the Lookup menu
this control type. The integer value
item.
corresponding to the position of the item
chosen, not the item’s static text value, is
stored when the user’s selection is saved
to a table.

PROGRAMMER’S GUIDE VOLUME 2 461


GLOS SA RY

Error trapping Footer Function


To watch for and handle an exceptional A report section that is printed at the A sanScript command that uses
event, such as an error. In Dexterity, the bottom of a report, page or group. parameters and returns a value that must
err() function is used to trap table errors Reports can include report footers, page be used in an expression.
that occur at runtime, allowing the footers and additional footers.
application to respond appropriately. Function library
Form An extension to the core sanScript
Exception A collection of windows, menus, scripts language containing functions that work
An illegal or inappropriate operation and tables that function together for a together to perform a specific system
performed by an application. common purpose. task. A common naming convention
distinguishes members of a particular
Exception handler Form function library. For example, functions in the File
A mechanism for dealing with exceptions A user-defined function that’s associated function library all begin with the word
in an application. with a specific form. File. The File_Delete() function is used to
Exclusive use Form module delete files from the operating system.
A table access mode that allows only one A group of related resources that Generic pathnames
form or user to access a table at a time. A compose a specific form. A Dexterity-specific method of indicating
table must be reserved for exclusive use a location on a hard disk or network
before it can be deleted. Form procedure
drive.
A procedure that’s associated with a
Expression specific form. Generic pathnames use a colon (:) before
A sequence of operands and operators and after DOS or Windows drive letters.
that are evaluated to return a value. Form table
The characters that are used after each
A table that has been attached to a form.
folder or directory in the pathname are
Extended composite Tables must be attached to the form
forward slashes (/).
A composite that can have up to 128 before any window in the form can use
components. See also Standard composite. the tables. Native Generic
Extract Format C:\DEX\TOOLS\ :C:DEX/INVENT/
A function of Dexterity Utilities that The extra characters, spacing and
copies third-party resources (resources attributes that can be applied to a data
See also Native pictures.
with IDs of 22,000 or greater) you’ve type when data is entered or displayed.
defined in a main product dictionary to a Generic provider
new dictionary. Format field
A text-based source code control
An integer field that specifies the format
provider that allows the use of any
Field to use for a string or currency field.
source code management software with
A field contains a single piece of
Format string Dexterity.
information used by the application
dictionary. A field can be displayed in a A data “mask” used for string and
Global field
window or stored in a table. The kind of composite formats. The format string
A field created using the Field Definition
information the field displays or stores allows extra characters to appear in a
window. Global fields can be displayed
depends upon the data type associated field without affecting the way data in
in windows or stored in tables. See also
with it. See also Global field and Local field. the field is stored.
Local field.
File Forms dictionary
Global script
See Table. The dictionary that stores user-modified
A script that isn’t associated with a single
resources from a main dictionary. This
window or form but that can be called
Focus dictionary is created when the Modifier is
from other scripts to perform a common
The indicator that shows the object being accessed for the first time. Only copies of
function. Renamed “procedure” in
controlled in the current window. the main dictionary’s resources are stored
Dexterity 3.0.
in the forms dictionary.

462 P R O G R A M M E R ’ S G U I D E V O L U M E 2
G L O S S A R Y

Global variable Index file Integrating application


A variable available to any script in the A special file stored in the repository that A Dexterity application that runs
application at any time. Global variables is used to maintain consistent resource concurrently with another product, such
are active the entire time a Dexterity IDs in your dictionary. It stores a list of all as Microsoft Dynamics GP. Integrating
application is open. They are created in resources and their corresponding applications can use resources from the
the Resource Explorer window by resource IDs. main product.
assigning global fields to act as global
variables. In parameter Key
A value that is passed from the calling A field or combination of fields within a
Graphics report script to the called script. The called record that is used as a basis by which to
A report on which graphics, colors (if the script cannot change the value of an in store, retrieve and sort records.
printer has color capabilities), patterns parameter.
and fonts other than the default font can Key segment
be printed. Index One field of a group of fields that
For a database, an object that contains compose a key.
Group box information about the location of records
A box drawn around a group of check in a data table. Indexes allow records to Keyable length
boxes or other fields, using the rectangle be located quickly. The information in the The number of characters that can be
tool, to visually group the items. index is based upon the keys for the typed in a field.
table. Keyboard equivalent
Header
A report section that is printed at the top For a Dexterity application, a number A key combination that will activate a
of a report, page or group. Reports can that refers to an object based upon the menu item as an alternative to selecting it
include report headers, page headers, object’s position in a sequence. You can with the mouse.
and additional headers. reference an object by its index, rather
Launch file
than its name. For example, the second
HTML A file that’s used to start your dictionary
key in a table may be called “Customer
HyperText Markup Language. Reports with the runtime engine. This file stores
Name,” but can also be referred to using
created with the Report Writer can be the location of your application
the index “2”.
exported to HTML files. dictionary, the name and location of any
Inout parameter forms or reports dictionaries, and the
Hyperspace A value passed from the calling script to name and location of any integrating
A field property that allows the the called script, then back to the calling dictionaries.
application to run the change script for a script.
push button (most commonly, a Cancel or Launch file ID
Delete button) without moving the focus Installation script An integer that uniquely identifies the
from the currently-selected field. A procedure in your application that launch file. It appears in the second line
performs actions such as adding items to of the launch file. This number is also the
Import utility palettes or setting up default pathnames. product ID of the main product. See also
A runtime tool that allows data from an Installation scripts are specified as Product ID.
ASCII text file to be imported to a starting or ending scripts for dictionary
Dexterity application’s data tables. Layout window
chunks. When the dictionary chunks are
A window in Dexterity that allows you to
unchunked, the installation scripts will
design the layout of a window, scrolling
run automatically.
window or report.
Integral value
A numeric value that doesn’t have a
fractional part. Tiny integers, integers
and long integers are integral values.

PROGRAMMER’S GUIDE VOLUME 2 463


GLOS SA RY

List box A record must be locked before it can be MAPI


A Dexterity control type used to define changed or deleted. An acronym meaning Microsoft’s “Mail
data types that allow users to select one Application Program Interface.” If you
static text value from a list.
Lookup button have a MAPI-compliant mail system, you
A button used to open a lookup window.
can mail Dexterity reports to other users.
Typically, they appear with editable fields
to indicate that a lookup window is Menu
available. The following illustration One of the items displayed on the menu
shows a typical lookup button. bar across the top of the screen.

Menu item
The list will appear with scroll bars if the
One of the selections associated with a
information in the list is greater than the
particular menu.
size of the list box field when it’s added
to the layout window. An integer Loop Message (resource)
position - not the static text - for the A statement in script that runs
A message that was entered using the
corresponding selection in a list box is repetitively until a defined condition is
Dexterity Messages window and that can
stored when the selection is saved to a met. SanScript supports three loop
be referenced by its ID in scripts, using
table. structures: for, while and repeat.
the getmsg() function. The message can
Macro system be displayed using the ask() function or
List field the warning or error statement.
Any field that uses a list box, drop-down A tool used to play and record macros in
list, multi-select list, button drop list, Dexterity or Dexterity applications.
Modal dialog
combo box or visual switch data type. Macros allow users to automate tasks
A window that contains no operating
throughout an application.
system controls and can’t be resized.
List view Modal dialogs are used when you require
A control type used for fields that display Mail enabling
A connectivity technology that allows the user to perform an action before
data in icon form or as a multicolumn list.
reports in a Dexterity application to be continuing.
mailed to other users. Dexterity
Modifiable key
applications can send items through
A key for which the values stored in the
MAPI-compliant mail systems.
key segments can be changed. If a key
Main Menu form isn’t modifiable, changing the contents of
The first form that opens when an a field that is part of the key will generate
application dictionary is run. The form an error and result in the record not being
must use the name Main Menu, without saved.
Local field any additional words or characters.
A field that’s available only within the Modifier
Stand-alone applications must have a
form in which it’s created. Local fields are A Dexterity tool that allows an
Main Menu form. Integrating
used as window fields. See also Global application’s interface to be modified by
applications use the Main Menu form for
field. an end user. A forms dictionary stores
the main application.
these modifications.
Local variable Main product
A variable specific to a single script that Modulus
A Dexterity-based application that can
is active only while the script is running. A numeric operator (%) that returns the
operate on its own. Some main product
Local variables are defined at the remainder of the division of two
applications, such as Microsoft Dynamics
beginning of the script. numbers. For example 15 % 4 returns the
GP are multidictionary capable, allowing
value 3.
Locking other Dexterity-based applications to
integrate with them.
The process of reserving the use of a
record in a table. Locking can be passive, Main window (of a form)
allowing others users to change or delete The window of a form that when closed,
the record, or active, which doesn’t allow closes the form and any other windows
other users to change or delete the record. associated with the form.

464 P R O G R A M M E R ’ S G U I D E V O L U M E 2
G L O S S A R Y

Multi-select list box Numeric expression Operator


A control type used to define fields from An expression that results in a numeric A symbol that indicates the action to
which one or more static text values can value. perform on the operands in an
be selected. expression.
On the fly
The feature that allows users to add Optimistic Concurrency Control
records while entering transactions is A form of record locking that enables
sometimes called entering information several users to update the same record
“on the fly.” For example, when entering in a controlled manner, ensuring that
an invoice for a new customer, the user is record updates are completed properly
The list will appear with scroll bars if the able to create a new customer record and efficiently while placing minimal
items in the list are greater than the size easily. restrictions on the user’s ability to access
of the field when it was added to the a record.
One-to-many
Layout window. Order of precedence
A type of relationship between two
Multidictionary tables. For every record in the first table, The order in which the operations are
A feature of Dexterity that allows the there are many records in the second carried out for an expression. The
runtime engine to interpret two or more table that are related to it. For example, traditional order of precedence for
separate application dictionaries at the an invoice header table contains a list of numeric expressions is: first unary
same time. This capability allows invoices, while an invoice line item table minus, then exponentiation, followed by
multiple third-party dictionaries to contains a list of the items on each multiplication, division and modulus,
function with a main product dictionary invoice. For one invoice in the first table, then addition and subtraction, and finally
such as Microsoft Dynamics GP. there are many line items in the second shift, equality and logical operations.
table, so there’s a one-to-many This is also referred to as the order of
Multiple format selector relationship between the tables. The evaluation.
A feature that allows the format applied relationship between two tables is
to a string or currency field to be selected viewed or defined in the Table Out parameter
at runtime. Relationship Definition window. The value passed from the called script
back to the calling script.
Names window One-to-one
A window available from the Script A type of relationship between two Overflow
Editor that allows you to quickly find the tables. For every record in the first table, The condition that occurs in a numeric
name of a resource and paste it into a there is only one corresponding record expression when an intermediate or final
script. that is related to it in the second table. result of the expression is too large to be
The relation between two tables is stored by the type of data used in the
Native pathnames viewed or defined in the Table expression.
An operating system-specific method of Relationship Definition window.
indicating a location of a file. See also Pad
Generic pathnames. Open Database Connectivity To add additional characters to a string
(ODBC) until the string has certain characteristics.
Native pictures A Microsoft database connectivity
Dexterity pads strings so they have an
Picture objects that are specific, or native, even length value. The additional
specification. Stored on a client computer,
to a particular operating system. characters added are called a pad.
ODBC driver software uses a
Metafiles and bitmap images are used as
standardized set of commands to Palette window
native pictures for Windows. Native
interface between a personal computer A type of window used for navigation in
pictures can be used for graphics that
client and server-based SQL database. Dexterity applications. Palette windows
appear on push buttons.
Operand display nothing in the title bar. If more
Node An item in an expression that is acted on than one palette is open, any additional
One piece of information in a tree view palettes opened will appear cascaded
by an operator.
field. from the opening point of the previously-
opened palettes.

PROGRAMMER’S GUIDE VOLUME 2 465


GLOS SA RY

Parameters Picture library Primary window


Values passed to or returned from a A feature in Dexterity that allows you to A window that appears with all
statement, function or procedure. store graphics in your application operating system controls, such as close
dictionary in a generic format that can be boxes and resize controls. Most windows
Pass used on any platform supported by used in applications are primary
The process of sending data to and Dexterity. windows.
receiving data from a procedure by
including a list of constants, variables or Ping Procedure
fields as parameters when the script is A procedure that sends a small piece of A script that isn’t associated with a single
called. data from one computer to another to test window or form but that can be called
network connectivity between the two on from other scripts to perform a common
Pass-through SQL a TCP/IP network. function. Referred to as a “global script”
Functionality in Dexterity that allows prior to Dexterity 3.0.
you to issue SQL commands from within Pixel
sanScript. The smallest graphical element displayed Process group
on a monitor. The pixel is the smallest A set of procedures that must be
Passive locking unit of measurement in Dexterity’s completed in a designated order, without
A method of locking a record that allows layout windows. You can move objects interruption from another process.
other users to access and make changes one pixel at a time within a Dexterity Process groups are defined using the
to the record. The lock for the record is layout window by using the arrow keys begingroup and endgroup statements.
released when the user with access to the on the keyboard.
record moves to another record or closes Process Server
the table. Point size The application developed to distribute
The vertical size of a font. There are 72 processes in a client/server environment.
Password points to an inch.
A field property that allows you to hide Product ID
entries in a field, such as when a Post script The ID that’s used to uniquely identify an
password is being entered. If this A script that runs upon closing a form or application dictionary. Product IDs for
property is set to True, an X will be window, or when focus leaves a field. applications developed with Dexterity
displayed in place of each character a must be acquired from Microsoft
user enters, so that no one else can read Power operator Business Solutions.
the entry from the screen. An operator symbolized in sanScript by a
caret (^) that is supported in numeric Product information
Pathname procedure expressions. The result is the first Information added to a dictionary that
A procedure that’s called automatically operand raised to the power of the allows the runtime engine to create a
each time a table operation occurs. The second operand. In the current version of launch file properly.
Pathname procedure is used to specify Dexterity, only powers of 10 may be
the path to an application’s tables. calculated. Progress control dialog box
A window that displays the progress of a
Pervasive.SQL Pre script process, such as rebuilding tables or
A key-indexed record management A script that runs immediately before a posting records.
system commonly used for LAN-based form or window is opened, or when the
and client/server applications. focus is moved to a field. Progress indicator
A control type used for fields that show
Physical name Precedence the progress of processes in the
For tables, the name under which a table The order in which operations are application.
is stored by the operating system or performed for a type of expression.
database.
Primary key
For global fields, a shortened version of The key containing the key segments that
the field name that is used as the column Prompt
most readily differentiate the rows in a
name when the field is used in a SQL Text in a window that shows the user the
SQL table. A unique index is
table. information that is displayed or can be
automatically created for the key that is
entered in the corresponding field or
selected as the primary key.
fields.

466 P R O G R A M M E R ’ S G U I D E V O L U M E 2
G L O S S A R Y

Property Radio group Relative decimal position


An attribute that can be assigned to A control type in Dexterity that’s used to An option for currency formats that sets
fields, windows or graphical objects group related radio buttons and store the the number of decimal digits that will be
displayed in a window layout window. value of the selected button. displayed to the indicated value plus the
For example, a window with the number of decimal places specified by
Resizeable property set to False cannot be the operating system. If your operating
resized by the user at runtime. Radio system displays two decimal positions
group and you specify three decimal digits for
Provider the format in the Format Definition
The software that performs the source window, the field will display a total of
code management tasks. Microsoft’s A radio group’s value is stored as an five decimal places.
®
Visual SourceSafe is a source code integer corresponding to the selected
control provider for which Dexterity has radio button’s position in the tab Remote procedure
integrated support. sequence, beginning with 0. For instance, A procedure that is processed remotely
if the second radio button in the tab on a process server.
Push button
sequence is selected, the radio group’s
A control type used to define data types Replacement marker
value is 1.
for buttons users can click to accomplish A placeholder in a string that indicates
tasks. Read only where items may be substituted using the
A table access mode that indicates the substitute statement. A replacement
table can only be read from. marker is a percent sign followed by a
number indicating the position in the
Read/write string, such as %1, %2, %3 and so on.
Static text or pictures can be used to A table access mode that indicates the
indicate the button’s function. If pictures table can be read from and written to. Report field
are used, two are required, one for the In the Calculated Fields window, a report
button “up” position, when the button Record field is a field with a modified display
isn’t being clicked, and the other for the A collection of data made up of one type. Report fields can be used in
button “down” position, when it’s being instance of each field in a table. conditional and calculated expressions in
clicked. calculated fields.
Record size
Qualified name The number of bytes in the fixed-length Report module
A name used in scripts that explicitly portion of the record. This value is the A group of related resources in a
specifies the location of an object being sum of the storage sizes of the fixed- Dexterity dictionary that are used to
referenced. Qualified names consist of a length fields in the record. The record define information that is unique to
qualifier, which specifies the location of size is displayed in the Table Definition reports, such as calculated fields.
the object, and a simple name. window. Resources that aren’t unique to reports,
such as fields and tables, are stored in
Quick report Recursion core modules and are referenced within
A report generated from within The process of a script calling itself. the report definition.
sanScript. Recursion is used when routines can be
broken down into progressively smaller Report Writer
Radio button routines in which the same steps must be A Dexterity tool that allows you to
A control type used to define data types performed again. design and print reports for your
that allow a single selection to be made application.
from a group of two or more selections. Reference
A special type of field or variable that
points to a specific instance of a resource
in an application.

Relationship
See Table relationship.
A group of radio buttons must be used
with a radio group.

PROGRAMMER’S GUIDE VOLUME 2 467


GLOS SA RY

Reports dictionary Results set Script icon


The dictionary that stores modified The data that fulfills the requirements of The icon that indicates that a script has
reports from the main dictionary and a SQL query. In Dexterity, you can use been attached to a form.
new reports created with the runtime pass-through SQL to issue queries and
engine’s Report Writer. The reports view the results set.
dictionary is created when the runtime
engine’s Report Writer is accessed for the Return key processing
first time. All reports you modify or A method of data entry that allows
the user to use either the TAB key If the icon is not present, no script has
create with the runtime engine’s Report been attached to the form.
Writer are stored in the reports or RETURN key to move from field to
dictionary. See also Custom dictionaries. field in a window. The Runtime_ Script logger
SetFieldEnterMode() function allows A scripting tool that stores a record of all
Repository you to change the method of return key the scripts accessed while your
The location where the source code is processing. application is running, as well as any
stored and maintained by the source code parameters passed to the scripts.
control system. Revision management
The process of tracking the versions of an Script lookup mode
Required field application and the resources it is Functionality available in test mode that
A field in which a value must be entered composed of. allows you to open scripts in the Script
to process information, such as an ID or Editor or Script Debugger.
customer name. Fields are marked as Runtime debugger
required using the Required property. A tool that informs you of errors that halt Script preprocessor
script operation and allows you to edit A Dexterity feature that acts as a filter
Required fields are displayed in a the script from test mode to fix the errors. before a script is compiled. The script
different color or type style when a user
Runtime engine preprocessor provides features such as
chooses the Show Required Fields menu
An application that’s used to interpret selective compiling of script statements.
item.
your dictionary. When a user starts your Script profiler
Resource application, the runtime engine will use A scripting tool that lets you analyze
An object such as a field, string, native the resources in the dictionary to present script activity for your application. This
picture, table, window or script that can a functioning application. allows you to optimize scripts and
be used to create applications in
Runtime Script Editor streamline your application.
Dexterity.
A Dexterity feature that allows you to Scrolling window
Resource definition window edit scripts while an application is A window used to display information
See Definition window. running in test mode. from a table. Scrolling windows allow the
Resource descriptions tool sanScript user to “scroll” through records in the
A tool that displays information about The scripting language in Dexterity. table. There are three types of scrolling
the current dictionary’s fields, windows windows: browse-only, editable and
and tables. To access this tool from Script adds-allowed.
Dexterity, choose Field Descriptions, A list of instructions an application uses
to perform tasks.
Sequence numbers
Table Descriptions or Window
Sequence numbers are currency-value
Descriptions from the File menu.
Script drill-down fields stored in the table linked to a
Resource ID A feature of the Dexterity script editor scrolling window. They act as reference
An internal ID applied to each resource that allows you to view and switch values when a scrolling window displays
in your application. For each type of between multiple scripts without having information, ensuring that records are
resource you create, IDs start at 22,000. to leave the script editor. displayed in the proper order.
For instance, the first data type you create Series
is data type 22,000; the second is data
A predefined category to which you can
type 22,001, and so on. Resource IDs for
assign forms, tables and reports in your
Microsoft Dynamics GP start at 1 and
application dictionary. Series allow you
never exceed 19,999.
to more easily organize these resources.

468 P R O G R A M M E R ’ S G U I D E V O L U M E 2
G L O S S A R Y

Series resources the source code control system. Source to the application. In parameters can be
Lists containing the names of forms, files are stored in the repository. passed to stored procedures. In addition
reports, tables and table groups in an to the status code, out parameters also
application dictionary. These lists are
Stand-alone application can be returned.
A Dexterity application that operates
used for security, palettes and table
maintenance. These lists are updated
without integrating with another String
automatically by Dexterity. You can use product. A sequence of up to 255 ASCII characters.
See also String resources.
Dexterity Utilities to update series Standard composite
resources manually. A composite that can have up to nine String expression
Session ID components. See also Extended composite. An expression that results in a string
value.
A unique identification code assigned by Starting script
Dexterity each time a client logs into a One of the two scripts associated with a String resources
SQL database. Applies only when a SQL dictionary chunk. When you create a Sequences of up to 79 characters used
database type is used. dictionary chunk, you can specify a throughout an application dictionary for
Shortcut key procedure from the application to be the window names, field prompts, static text
starting script for the dictionary chunk. values and report text.
A key combination that will activate a
menu item, equivalent to selecting the The starting script will be run with the
other starting and ending scripts after all Structured Query Language
item with the mouse. (SQL)
dictionary chunks have been unchunked.
Shrinking See also Ending script and Installation A language that allows you to define,
A process of copying the contents of one script. manipulate and control access to data in a
table (the original table) to an empty relational database.
duplicate table (the shrink table) to
Statement
A script command used to complete a Synchronize (Utility)
remove excess space in the original table.
specific action in an application, such as A feature that checks all relationships
This process copies only the data; any
running a report, opening a window or between resources in a dictionary and
existing space that may exist in the recalculates all buffer sizes.
original table doesn’t get copied to the saving an item to a table.
shrink table. Static picture value Synchronize (Dexterity)
A picture that’s displayed as part of a In Dexterity, to specify the native picture
Simple name on each platform that should be used as
data type, such as the picture on a button
The name is given to the object when it is
drop list. the static value for a single data type.
created. See also Qualified name. When two pictures are synchronized,
Small line item Static text value Dexterity will assign them the same
Text that’s displayed as part of a data internal ID. Thereafter, when a
The area containing the fields that will be
displayed when a scrolling window is in type, such as the name of a push button synchronized picture is displayed by the
or the items in a list box. application as it runs, the native picture
standard mode. When a scrolling
window is in expanded mode, additional that’s appropriate to the current
Storage type operating system will be displayed.
fields below the small line item mark, but One of the standard forms used to store
above the big line item mark, will be the data in a field. The storage types are: System command
displayed. A scrolling window’s mode is boolean, integer, long, currency, variable Prior to Dexterity 3.0, a sanScript
determined using the expand statement. currency, string, text, date, and time. The command (indicated by a three- or four-
Source code control server control type determines which storage digit number) that used the system
Software that allows Dexterity clients to type is used to store the data in the field. statement. System commands were
communicate with the source code replaced with function libraries in
Stored procedure Dexterity 3.0.
control provider. Queries written in SQL, then compiled
Source files and stored in a database. Called from a
script using the call sproc statement,
The physical files containing source code
or other resources that are managed by stored procedures perform server-based
processing tasks, and return a status code

PROGRAMMER’S GUIDE VOLUME 2 469


GLOS SA RY

System exceptions TCP/IP Transaction rollback


Error situations that can occur in any An acronym for Transmission Control The ability to undo table operations since
Dexterity application, such as a division- Protocol/Internet Protocol. TCP/IP is set a transaction was started. Not all
by-zero error. See also User exceptions. of transmission protocols used to transfer database managers support transaction
data between computers on a network. rollback. The havetransactions() function
Tab sequence verifies whether the current database
The order in which the focus moves from Technical name manager supports transaction rollback.
one field to the next field when a user The name used within scripts to refer to a
presses the TAB key. table or window. See also Display name. Trap
To watch for and handle an exceptional
Table Test mode event, such as an error. In Dexterity, the
A collection of related data formatted in A Dexterity mode that allows you to err() function is used to trap table errors
rows. Each row represents a separate view and operate your application that occur at runtime, allowing the
record, and each column represents a dictionary as it will appear when used application to respond appropriately.
separate field. Although this term with the runtime engine. See also Tools
originated with relational databases, mode. Tree view
Dexterity uses it generically to refer to A control type used for fields that display
both relational database tables and ISAM Text report data in an expandable outline.
database files. A report that can display only characters
in a native printer font.
Table buffer
A buffer that acts as an intermediate Throw
storage area to hold one record from a The process of creating an exception. See
table. also Exception, Exception handler.

Table field Time expression


Unchunking
A global field that’s used to store See Date and time expression.
The process of dictionary chunks being
information in tables. Toolbar converted back into a dictionary or being
A type of window used for navigation in merged with an existing dictionary.
Table group
A group of logically-related tables. For Dexterity applications. Toolbars typically
Unhandled exception
example, a customer master table, a appear across the top of the screen or
An exception that is not caught by any
customer address table and a customer along the left side of the screen. Only one
exception handler. A dialog box is
history table could all compose a table toolbar window at a time can be
automatically displayed that describes
group. Table groups are used for security displayed in an application.
the exception for the user.
and table maintenance. Toolbox
Unique index
Table open mode A window that opens in conjunction with
An index that requires the key values of
The method by which a table is accessed: the Window Layout, Scrolling Window
each record to be unique. Individual key
read/write, read only and exclusive use. Layout and Report Layout windows. It
segments may contain the same data for
contains tools used to place and arrange
multiple records, but there can’t be
Table relationship items in the layout area.
duplicates of the key values as a whole.
A link between tables that have fields in
common. These relationships allow the Tools mode
User-defined constant
Report Writer to select fields from all of A Dexterity development mode that
See Constant.
the related tables and use them on a allows you to edit or add resources to an
single report. Table relationships are set application dictionary. When you first User-defined function
up using the Table Relationship start Dexterity and open a dictionary, the A script in Dexterity that you write and
Definition window. default mode is tools mode. See also Test use in the same manner as Dexterity’s
mode. built-in functions.

470 P R O G R A M M E R ’ S G U I D E V O L U M E 2
G L O S S A R Y

User exceptions Workset


Error situations that are specific to a A group of resources in the Resource
single Dexterity application. See also Explorer. Worksets are useful for
System exceptions. categorizing the resources in a dictionary.

Variable WordWrap
A script item that allows an application A property for text fields that causes text
to store values. They’re called variables to automatically continue to the next line
because their values can change. For when it extends beyond the right edge of
example, a variable could be used to store the field.
the value returned from a dialog box
created with the ask() function. WYSIWYG
An acronym meaning “what you see is
Version numbers (for dictionary what you get.” This applies to intuitive
chunks) design tools used to create windows and
A dictionary chunk can have a version reports in Dexterity.
number associated with it. When the
dictionary chunk is unchunked, the
Zoom pointer
A pointing hand cursor that appears
version numbers are written to the
when the pointer is over a push button
application dictionary. The version
numbers can be retrieved from the field that has the Zoom property set to
True. In Microsoft Dynamics GP, clicking
dictionary and typically are displayed in
the mouse when this pointer is over the
the application’s About Box.
field enables users to “zoom” to the
Virtual table window where records for the field can
A type of table that acts as a single, read- be added.
only, non-physical table. A virtual table
accesses member tables by utilizing a
related field from a primary table and
using it as a key in a secondary table.

Visual Basic for Applications


(VBA)
A development system created by
Microsoft that can be embedded into
applications. VBA is embedded into the
Modifier, providing additional
customization capabilities.

Warning dialog box


The modal dialog box generated with the
warning statement. A text string, the
standard warning icon for the operating
system, and an OK button are displayed
in the dialog box.

Window
The work area used to enter and display
information in an application.

Window field
A global or local field that has been
added to a window layout.

PROGRAMMER’S GUIDE VOLUME 2 471


472 P R O G R A M M E R ’ S G U I D E V O L U M E 2
Index application development (continued)
overview 287
B
background, exporting application
procedure 287 background to text 308
Symbols Application objects background color
« operator, described 20 in Excel Object Library 376 for list view images 138
» operator, described 20 in Outlook Object Library 413 for tree view images 126
in Word Object Library 362 background processing
Numerics applications call stack usage 226
32-bit DLLs 215 developing 289 monitoring 204
3-D border, for push buttons 72 multiuser 176 overview 204
3-D highlight, defined 457 optimizing 295 temporary tables 204
testing 299-312 background tasks, defined 457
A array fields, defined 457 Basic Scripting, part 46-63
accelerator key, defined 457 array indexes, defined 457
accented characters, displaying 319 big line item
arrays defined 457
access keys, defined 457 local variables 24
activate script, for windows 42 described 96
overview 24 for scrolling window 96, 109
active locking using in scripts 24
defined 457 bit operations, described 57
ASCII Character Codes, appendix 455 block indenting, described 26
described 175 ask() function 15, 52
addition operator, use in sanScript 19 blocks, defined 457
ASKBUTTON predefined constants 15 boolean, storage type 12, 14
add-line, defined 457 assemblies for .NET, accessing through
adds-allowed scrolling windows boolean expressions
COM 348 defined 457
characteristics 91 attaching scripts
defined 457 described 18
chapter 39-43 Breakpoint Options window 259
Advanced Scripting, part 188-235 to fields 39
alert messages, defined 457 Breakpoints, menu item 253
to forms 43 breakpoints
alphanumeric, defined 457 to scrolling windows 97, 110
AltLineColor clearing 257
to windows 41 conditional 259
field property 133 Attachment objects, with COM 420
scrolling window property 94, 108 defined 458
Auto-Chunk utility, defined 457 deleting 258
Analysis Tools, part 252-284 auto-complete
anonymous table described 257
adding items 75 disabling 258
with anonymous fields described 74
described 202 enabling 258
disabling 75 encountering 260
script example 202 enabling 75
with known fields ignoring 258
removing items 74, 76 list of 258
described 201 saving items 76
script example 201 options 259
sharing auto-complete values 74 setting 257
anonymous tables and fields AutoCopy, field property 457
defined 457 toggling 257
auto-generated stored procedures, types of 259
overview 200 defined 457
passing as parameters, script unconditional 259
AutoLinkTable, window property 457 Breakpoints window 258
example 203 automation, described 329
appending, strings 58 browse-only scrolling windows
automation client, described 329 characteristics 90
application development automation server, described 329
checklist 288 defined 458
managing 289

PROGRAMMER’S GUIDE VOLUME 2 473


I N D E X

buffers cascading menus COM


defined 458 defined 458 automation client 329
described 148 for button drop lists 68 automation server 329
button drop lists case...end case statement 62 callback objects 351
adding submenus 68 casting, described 23 class browser 345
caption and images 67 Catalog objects, with COM 390 classes 330
defined 458 catch, defined 458 collections 346
drop indicator 68 Cell objects, with COM 370 constants 344
using 67 change flag, defined 458 data type conversion 344
change script, defined 458 debugging 348
C Chart objects, with COM 385 error handling 346
calculated fields, defined 458 charts event handlers 355
calculations, performing with scripts currentcomponent() function events 331, 354
55 return values 87 exceptions 239, 346
call stacks locking scenarios 176 interoperability with .NET 348
chapter 225-229 scrolling window properties 94, libraries 333
defined 458 108 methods 343
described 225 scrolling window scripts 110 methods with optional parameters
effect of run script delayed string comparisons 59 344
statement 229 check boxes .NET assemblies 348
effect of run script statement 227 defined 458 object 330
for background processing 226 static picture values 69 objects 341
for foreground processing 225 Style property 69 overview 329
how used 225 types 69 part 328-357
illustration 225 working with 69 properties 343
managing use 227 child nodes, described 118 references
special processes 226 chunk dictionaries, defined 458 creating 338
unwinding 263 chunk utility, defined 458 data types 338
callback objects Class Browser window 339, 345, 354 described 337
accessing 354 classes script parameters 340
adding methods 352 described 330 script variables 340
adding properties 351 for system exceptions 239 referencing objects 337
adding to running object table 352 client buffer, defined 458 sanScript code 341
creating 351 client/server, defined 458 type libraries 333
described 351 closing using in scripts 341
documenting 352 forms 53 COM in sanScript, chapter 341-350
for event handlers 356 windows 53 COM Libraries, chapter 333-335
making accessible 352 clustered index, defined 458 COM script examples
retrieving current callback object code guidelines 300 with Microsoft ADO 405
353 collections with Microsoft ADOX 396
use 351 accessing with COM 346 with Microsoft Excel 387
Callbacks and Events, chapter 351-357 described 346 with Microsoft Internet Explorer
called script, defined 458 colors, for sanScript syntax 27 410
calling script, defined 458 Column objects, with COM 394 with Microsoft Outlook 427
Calls, menu item 253 columns, for list view fields with Microsoft Word 371
Calls window 263 adding 139 with Microsoft XML 443
Cancel, field property 458 sizing 140 COM Type Libraries window 334

474 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

combo boxes components (continued) context menu scripts


defined 459 defined 79, 459 attaching for fields 40
setting dropped size 70 Composite Definition window 80 attaching for scrolling windows
commands, defined 459 composites 105
comments accessing from within scripts 85 attaching for windows 42
in macros 309 chapter 79-88 control area, defined 459
in sanScript 8 comparing 88 control field, defined 459
communicating with the user component addressing control types, defined 459
ask() function 52 by offset 86 Controlling the Compiler, chapter
chapter 51-54 using a colon 85 219-224
error statement 51 component-based scripts 86 controls
using scripts 51 creating extended, procedure on toolbars 77
warning statement 51 82-83 working with 67
compare, defined 459 creating standard, procedure 80-81 conventions, in documentation 3
comparing currentcomponent() function 86 core modules, defined 459
composites, example 88 defined 79, 459 core resources, defined 459
strings 58 example 81, 83 Creating an International Product,
compatibility ID, defined 459 extended chapter 315-325
compatibility message, defined 459 creating 82-83 c-tree Plus database manager, defined
Compile Messages window 33 defined 79 458
compiler errors example 83 currency, storage type 12, 14
defined 459 items related to 88 currentcomponent() function 86
described 32 standard cursor block size, defined 460
compiler messages, described 32 creating 80-81 cursor refreshing, defined 460
compiler warnings defined 79 cursors, defined 460
defined 459 example 81 custom dictionaries, defined 460
described 32 use 79
suppressing 222 compress, defined 459 D
compiling compressed key, defined 459 data sources, defined 460
all scripts for a form 34 concatenating, defined 459 data types
all scripts in a dictionary 34 conditional breakpoints 259 converting for COM 344
controlling from scripts 219 conditional operator, use in sanScript defined 460
defined 459 21 for COM objects 338
form scripts, in Dexterity 34 Connection objects, with COM 400 how stored 12
pragmas 219 connection pools, defined 459 database exceptions, subclasses 243
script preprocessor 219 connections, defined 459 database management system (DBMS),
scripts 32 constants defined 460
component addressing accessing for COM objects 344 database managers, defined 460
by offset, script example 86 defined 459 database types, testing 301
using a colon, script example 85 in sanScript 15 date and time expressions
component-based scripts predefined constants defined 460
currentcomponent() function 86 described 15 described 17
for composites 86 example of use 15 dates
script example 87 types 15 adding numeric values to,
components user-defined 16 example 19
component-based scripts 86 ContactItem objects, with COM 424 storage type 12, 14
currentcomponent() function 86

PROGRAMMER’S GUIDE VOLUME 2 475


I N D E X

dates (continued) DLLs (continued) event handlers


subtracting numeric values from, extern statement 217 callback object 356
example 19 how supported by Dexterity 215 creating for COM events 355
datetime, storage type 12 loading 217 described 355
deadlock condition parameters 216 responding to events 357
defined 460 paths for accessing 218 troubleshooting 357
when using transactions 182 procedure resource used 216 user-defined function 355
Debug menu, described 253 setting up 215 events
debug statements, defined 460 testing 302 described 331
debugging COM integrations 348 unloading 217 in COM applications 354
debugging runtime errors 271 used to support calling DLLs 215 exception handler
Default, field property 460 where to store 218 chapter 237-249
DefaultDblClick Document objects, with COM 364 COM exceptions 239
defined 460 documentation, symbols and defined 462
scrolling window property 94, 108 conventions 3 examples 246
defaults file, defined 460 DOMDocument objects, with COM 431 form exceptions 240
definition window, defined 460 DraggableCols, field property 133 implementing 244
deleting, records 155, 163 drop indicator, for button drop lists 68 location 244
dereferencing items 233 drop-down lists overview 237
Design Guidelines, chapter 291-294 defined 461 responses 245
destination dictionary, defined 460 setting dropped size 70 script exceptions 239
development process duplicates, defined 461 system exceptions 237, 239
chapter 287-289 user exceptions 237, 238
managing 289 E exceptions
DEX.INI file, defined 461 early binding, described 337 defined 462
Dexterity Limits, appendix 449 Edit Script button, described 255 for COM 346
dialog boxes, displaying 51 editable fields, defined 461 in callback methods 353
dictionaries editable scrolling windows logging 245
compiling all scripts 34 characteristics 90 re-executing statements 245
defined 461 defined 461 rethrowing 245
dictionary cores, defined 461 editing macros 309 exclusive ranges
dictionary location IDs, defined 461 editing text, in the script editor 26 described 169
dictionary modules, defined 461 elements of arrays example 170
directed hyperspace, defined 461 defined 461 exclusive use, defined 462
disabled fields, defined 461 described 24 expand window statement 96
disabling, fields 54 empty scripts, disabling no executable ExpandButtons, field property 120
display names, defined 461 code warning 224 expanded mode
display-only fields, defined 461 enabling, fields 54 for scrolling windows 96
distributed processing, defined 461 encrypted fields, defined 461 illustration 96
division operator, use in sanScript 19 ending scripts, defined 461 switching to normal mode 96
DLLs equality operator, use in sanScript 20 explicit type conversions 13
32-bit 215 error statement 51 exponents, power operator 20
calling from sanScript 215, 217 error trapping Expressions, menu item 253
chapter 215-218 defined 462 expressions
defined 461 for COM 346 boolean 18
described 215 in a multiuser environment 178 converting types 23
example 218 date and time 17

476 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

expressions (continued) fields (continued) forms


defined 462 setting values with script attaching scripts 43
described 16 debugger 265 closing with scripts 53
numeric 16 showing 53 compiling all scripts 34
string 17 state click script, described 41 defined 462
Expressions window 265 viewing with script debugger 264 illustration 148
extended composites, defined 462 focus lookup forms 113
extern statement 217 controlling for a scrolling window opening in macros 308
extract, defined 462 105 opening with scripts 53
defined 462 optimizing loading time 296
F in scrolling windows 95 post script, described 43
fault-avoidance, described 300 moving with scripts 54 pre script, described 43
Field objects, with COM 404 font size forms dictionaries, defined 462
field scripts for Script Debugger 27 FullRowSelect, field property 133
attaching 39 for Script Editor 27 function library, defined 462
change script, described 40 fonts functions
collapse script, described 41 for Script Debugger 27 defined 462
context menu script, described 40 for Script Editor 27 described 11
double-click script, described 41 footer, defined 462 script drill-down 31
expand script, described 41 for do...end for statement 62 user-defined 209
mouse enter script, described 40 foreground processing, call stack usage
mouse exit script, described 40 225 G
post script, described 40 form constants generic pathnames, defined 462
pre script, described 40 described 16 generic provider, defined 462
state click script, described 41 script example 16 generic references, described 338
types 40 form exceptions 240 global constants
fields form functions described 16
as parameter types 196 calling 213 script example 16
attaching scripts 39 creating 213 global fields
auto-complete fields 74 defined 462 as parameter types 196
change script, described 40 described 213 defined 462
collapse script, described 41 form module, defined 462 global variables
context menu script, described 40 form procedures defined 463
controlling with scripts 53 calling, script example 200 described 14
defined 462 creating 200 example 15
disabling 54 defined 462 using in scripts 14
double-click script, described 41 overview 200 Go, menu item 254, 261
enabling 54 form scripts Go button, described 255, 261
expand script, described 41 attaching 43 graphics reports, defined 463
hiding 53 post script, described 43 greater than operator, use in sanScript
locking and unlocking with scripts pre script, described 43 20
54 types 43 greater than or equal to operator, use in
mouse enter script, described 40 form table, defined 462 sanScript 20
mouse exit script, described 40 format field, defined 462 GridLines, field property 133
post script, described 40 format strings, defined 462 group box, defined 463
pre script, described 40 formats, defined 462 guidelines, for Dexterity applications
291

PROGRAMMER’S GUIDE VOLUME 2 477


I N D E X

H interface design, for international keys (continued)


header, defined 463 applications 318 multisegment keys, using ranges
HelpContextID, scrolling window internationalization 168
property 94, 109 accented characters 319 Keys.ini file
hexadecimal values, in sanScript 57 coding issues 321 described 310
hiding, fields 53 currency issues 324 example 310
HTML, defined 463 date issues 324
hyperspace defaults file settings 325 L
locales 316 large icon view, described 130
defined 463
paper size 320 launch file ID, defined 463
for lookup buttons 115
report design 320 launch files, defined 463
I sorting methods 318 layout windows
icon images, for list view fields 136 string issues 321 defined 463
if then...end if statement 61 string overflow 317 for scrolling windows 92
IgnoreActiveLine, scrolling window translation issues 317 less than operator, use in sanScript 20
property 95 window design 318 less than or equal to operator, use in
images InternetExplorer objects, with COM sanScript 20
for list view items 136 408 Library Definition window 334
for push buttons 70 Introduction to COM, chapter 329-331 light bulb symbol 3
for tree view nodes 124 item images, for tree view fields 124 limits, appendix 449
ImageSize, field property 133 ItemChanged script 134 line scripts for scrolling windows
implication operator, use in sanScript items, for list view fields context menu script 105
21 adding 139 line change script 101
implicit type conversions 13 attributes 132 line delete script 105
Import utility, defined 463 described 130 line fill script 102
in parameters sorting 140 line insert script 103
defined 463 IXMLDOMElement objects, with COM line post script 102
described 190 437 line pre script 100
example 191 IXMLDOMNode objects, with COM Lines, field property 120
inclusive ranges 433 Link Lookup, menu item 114
described 169 IXMLDOMNodeList objects, with linked tables, for scrolling windows 92,
example 170 COM 435 108
Indent, field property 120 IXMLDOMProcessingInstruction LinkTable, scrolling window property
index file, defined 463 objects, with COM 436 95, 109
indexes, defined 463 IXMLDOMText objects, with COM 440 LinkTableKey, scrolling window
inequality operator, use in sanScript 20 property 95, 109
information hiding, described 300 K list boxes, defined 464
inout parameters key fields, modifying values of 165 list fields, defined 464
defined 463 Key objects, with COM 393 list view
described 190 key segments, defined 463 adding items 139
example 193 keyable length, defined 463 attaching scripts
installation scripts, defined 463 keyboard equivalent, defined 463 context menu script 135
integers, storage type 12, 14 keys double-click script 135
integral values, defined 463 defined 463 post script 134
integrating applications multiple records with same key pre script 134
defined 463 values 163 selection changed script 134,
transactions in 186 135

478 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

list view (continued) locking macro system (continued)


attaching scripts active 175 Macro menu 303
state click script 135 defined 464 overview 303
chapter 129-143 fields 54 macros
clearing 139 passive 175 adding comments 309
defined 464 records 175 additional Macro menu
described 129, 131 releasing locks 176 commands 304
images Logging, macro command 309 displaying 305
adding 137 logical AND operator, use in sanScript displaying macro status 305
background color 138 21 editing 309
for items 136 logical NOT operator, use in sanScript exporting table data 308
icon images 136 21 exporting toolbar contents 308
overlay images 136 logical OR operator, use in sanScript 21 inserting pauses 304
size 138 logical XOR operator, use in sanScript Keys.ini file 310
specifying 138 21 macro header 308
state images 136 long integers, storage type 12, 14 macro language 312
item attributes 132 lookup buttons No User Interface Flash option 306
object properties 133 creating 114 opening forms 308
scripts 134 defined 464 pausing 303, 304
searching 142 illustration 114 playing 303
selection lookup forms recording 303, 309
changing 141 implementing 113 recording test procedures 300
retrieving 141 opening running 309
sizing columns 140 from a scrolling window 106 sample, illustration 311
sorting items 140 with lookup buttons 114 saving window contents 307
terminology 130 overview 111 saving window images 307
visual properties 133 setting up a return path 114 StandardInternationalInfo setting
ListView Images window 137 lookup linking mode 114 305
LiteralStringUsed pragma 223 lookups, chapter 111-115 starting at a specific line 306
local anonymous tables loops status of 305
described 199 defined 464 stepping through 303
example 199 for loop 62 stopping 303
local fields in scripts 62 storing messages in a file 309
defined 464 PossibleInfiniteLoop pragma 223 structure 311
referencing in scripts 10 repeat loop 63 suspending recording 303
local variables while loop 63 syntax 311
arrays 24 used for testing 304
defined 464 M Windows Compatibility option
described 14 Macro menu 305
example 14 described 303 mail enabling, defined 464
setting initial value 14 displaying additional commands MailItem objects, with COM 417
using in scripts 14 304 Main Menu form, defined 464
viewing 264 Macro Status window 305 main product, defined 464
locales, described 316 macro system main window for a form, defined 464
Locals, menu item 254 defined 464 making decisions, using scripts 61
Locals window 264 for testing applications 303, 304 MAPI, defined 464
macro language 312 MAPIFolder objects, with COM 415

PROGRAMMER’S GUIDE VOLUME 2 479


I N D E X

margin notes 3 Microsoft ADO Object Library Microsoft Excel (continued)


memory-based tables (continued) creating workbooks 378
chapter 173-174 Open method creating worksheets 380
creating 173 with connections 401 formatting cells 383
deleting 174 with recordsets 402 inserting cell values 382
described 173 overview 399-406 integrating with Dexterity-based
guidelines 174 Recordset objects 401 applications 375-388
location on disk 173 script example 405 opening 376
menu items, defined 464 Update method 403, 404 opening workbooks 378
menus, defined 464 Value property 404 retrieving cell values 382
menus in Dexterity Microsoft ADOX saving workbooks 379
Debug menu 253 creating saving worksheets 381
Macro menu 303 catalogs 391 using the chart wizard 386
Script menu 30 columns 394 using worksheet functions 384
messages, defined 464 keys 393 Microsoft Excel Object Library
methods tables 392 Activate method 380
accessing for COM objects 343 deleting tables 393 ActiveChart property 386
adding to callback objects 352 integrating with Dexterity-based Add method
responding to callback methods applications 389-397 with charts 385
353 retrieving connections 391 with workbooks 378
Microsoft ADO Microsoft ADOX Object Library with worksheets 380
adding records 403 ActiveConnection property 391, Application objects 376
closing 401 Borders property 383
connections 401 Append method Chart objects 385
recordsets 404 with columns 394 ChartObject object 385
deleting records 404 with keys 393 ChartObjects method 385
integrating with Dexterity-based with tables 392 ChartType property 386
applications 399-406 Catalog objects 390 ChartWizard method 386
moving through recordsets 402 Column objects 394 Close method 379
opening connections 401 Create method 391 Columns property
opening recordsets 402 Delete method 393 with applications 381
retrieving connections 401 Item property with ranges 381
updating records 403 with columns 395 with worksheets 381
Microsoft ADO Object Library with keys 393 CountA method 384
AddNew method 403 with tables 392 DisplayAlerts property 377
Close method Key objects 393 Font property 383
with connections 401 Name property Interiors property 384
with recordsets 404 with keys 394 Item property
Connection objects 400 with tables 392 with charts 385
Delete method 404 overview 389-397 with workbooks 379
Field objects 404 script example 396 with worksheets 380
Item property 404 Table objects 392 Location method 386
Move method 402 Type property 394 Move method 381
MoveFirst method 402 Microsoft Excel Open method 378
MoveLast method 402 closing 378 overview 375-388
MoveNext method 402 closing workbooks 379 Quit method 378
MovePrevious method 402 creating charts 385 Range objects 381

480 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

Microsoft Excel Object Library Microsoft Outlook (continued) Microsoft Outlook Object Library
(continued) deleting (continued)
Range property 381 folders 416 Delete method 421
Save method 379 mail messages 420 with contacts 426
SaveAs method recipients 423 with mail messages 420
with workbooks 379 displaying with MAPI folders 416
with worksheets 381 contacts 425 with recipients 423
Saved property 379 folders 416 Display method
script example 387 mail messages 418 with contacts 425
SetSourceData method 385 integrating with Dexterity-based with mail messages 418
Text property 382 applications 411-428 with MAPI folders 416
Value property 382 logging off 414 FirstName property 425
Visible property 377 logging on 414 GetDefaultFolder method 415
Workbook objects 378 opening 413 GetNameSpace method 414
Worksheet objects 380 removing attachments 421 Importance property 418
WorksheetFunction objects 384 resolving recipients’ addresses 422 Index property
WorksheetFunction property 384 saving with attachments 421
Microsoft Internet Controls Object attachments 421 with recipients 422
Library contacts 426 Item method
InternetExplorer objects 408 mail messages 419 with attachments 420
Navigate method 408 security 413 with contacts 424
overview 407-410 sending mail messages 419 with mail messages 417
Quit method 409 setting body of mail messages 418 with MAPI folders 415
Refresh method 409 setting importance of mail with recipients 422
script example 410 messages 418 JobTitle property 425
Silent property 409 setting subject of mail messages LastName property 425
Stop method 409 418 Logoff method 414
Visible property 408 Microsoft Outlook Object Library Logon method 414
Microsoft Internet Explorer Add method MailItem objects 417
closing 409 with attachments 420 MAPIFolder objects 415
creating 408 with contacts 424 Name property
integrating with Dexterity-based with mail messages 417 with MAPI folders 416
applications 407-410 with MAPI folders 415 with recipients 423
loading web pages 408 with recipients 421 NameSpace objects 414
refreshing web pages 409 Address property 423 overview 411-428
Microsoft Outlook Application objects 413 Quit method 413
adding, recipients 421 Attachment objects 420 Recipient objects 421
closing 413 Body property 418 Remove method 421
closing contacts 426 Close method with MAPI folders 416
closing mail messages 420 with contacts 426 with recipients 423
creating with mail messages 420 Resolve method 422
attachments 420 ContactItem objects 424 ResolveAll method 422
contacts 424 CreateItem method Resolved property 422
folders 415 with contacts 424 Save method
mail messages 417 with mail messages 417 with contacts 426
deleting CurrentUser property 414 with mail messages 419
contacts 426 DefaultItemType property 416

PROGRAMMER’S GUIDE VOLUME 2 481


I N D E X

Microsoft Outlook Object Library Microsoft Word Object Library Microsoft XML (continued)
(continued) (continued) creating
SaveAs method Hyphenation property 368 processing instructions 436
with contacts 426 InsertAfter method 366 text nodes 440
with mail messages 419 InsertBefore method 366 integrating with Dexterity-based
SaveAsFile method 421 InsertParagraph method 367 applications 429-446
Saved property InsertParagraphAfter method 367 loading XML documents 431
with contacts 426 InsertParagraphBefore method normalizing elements 440
with mail messages 419 367 removing
script example 427 Item method data from text nodes 442
security 413 with documents 365 elements 440
Send method 419 with paragraphs 368 nodes 434
Sent property 419 with tables 369 processing instructions 437
Subject property 418 Last property 368 text nodes 442
Type property 423 Merge method 371 replacing
Microsoft Word Open method 365 elements 439
closing 364 overview 361-373 nodes 434
closing documents 366 Paragraph objects 367 processing instructions 437
creating documents 364 Quit method 364 text nodes 441
formatting paragraphs 368 Range method 366 retrieving
formatting tables 369 Range objects 366 elements 438
inserting tables 369 Range property nodes 434
inserting text 366 with cells 366 processing instructions 437
integrating with Dexterity-based with paragraphs 366 text nodes 441
applications 361-373 with tables 366 saving XML documents 433
merging table cells 371 Save method 365 specifying selection languages 432
opening 362 SaveAs method 365 Microsoft XML Object Library
opening documents 365 Saved property 365 appendChild method
saving documents 365 script example 371 with elements 438
splitting table cells 371 SetHeight method 371 with nodes 433
Microsoft Word Object Library SetWidth method 371 with text nodes 441
Add method Shading property 370 appendData method 442
with documents 364 Spacing property 370 childNodes collection
with paragraphs 367 Split method 371 with elements 438
with tables 369 Table objects 369 with nodes 434
Alignment property 368 Visible property 363 with processing instructions
Application objects 362 Microsoft XML 437
AutoFormat method 369 adding with text nodes 441
Borders property 369 data to text nodes 442 createElement method 437
Cell method 370 elements 438 createNode method 433
Cell objects 370 nodes 433 createProcessingInstruction
Close method 366 processing instructions 436 method 436
DisplayAlerts property 363 text nodes 441 createTextNode method 440
Document objects 364 copying XML documents 432 data property 442
First property 368 creating deleteData method 442
FitText property 371 elements 437 documentElement property 432
Format property 368 nodes 433 DOMDocument objects 431

482 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

Microsoft XML Object Library Microsoft XML Object Library Names window (continued)
(continued) (continued) using to find resource names 27
insertBefore method selectNodes method 438 NameSpace objects, with COM 414
with elements 438 selectSingleNode method 438 native pathnames, defined 465
with nodes 433 setProperty method 432 native pictures, defined 465
with processing instructions text property 434 .NET assemblies, accessing through
436 xml property COM 348
with text nodes 441 with elements 440 networks, testing 301
insertData method 442 with XML documents 432 new symbol 3
item method 435 modal dialogs, defined 464 nodes, for tree view fields
with elements 438 modifiable keys, defined 464 adding 123
with nodes 434 Modifier, defined 464 attributes 119
with processing instructions modulus operator defined 465
437 defined 464 described 118
with text nodes 441 use in sanScript 19 NoExecutableCode pragma 224
IXMLDOMElement objects 437 mouse enter scripts, attaching 40 normal mode
IXMLDOMNode objects 433 mouse exit scripts, attaching 40 for scrolling windows 96,
IXMLDOMNodeList objects 435 moving, focus with scripts 54 illustration 96
IXMLDOMProcessingInstruction multidictionary, defined 465 switching to expanded mode 96
objects 436 multiple format selector, defined 465 nothing keyword, for user-defined
IXMLDOMText objects 440 multiplication operator, use in functions 210
length property 441 sanScript 19 numeric expressions 16
load method 431 MultiSel, field property 133 defined 465
loadXML method 431 multi-select list box, defined 465 overflow in 55
nextNode method 435 multiuser processing
nodeType property adding to applications 176 O
with elements 438 chapter 175-180 object properties
with processing instructions deleting a record example 180 for list view fields 133
437 described 175 for tree view fields 120
with text nodes 441 locking scenarios 176 objects
normalize method 440 retrieving a record example 178 creating 341
overview 429-446 saving a record example 179 creation guidelines 342
removeNode method described 330
with elements 440 N destroying 343
with nodes 434 Name, scrolling window property 95, naming in scripts 8
with processing instructions 109 retrieving 343
437 names one-to-many relationship, defined 465
with text nodes 442 automatic script naming 35 one-to-one relationship, defined 465
replaceChild method finding with the Names window online help
with elements 439 27 for sanScript 34
with nodes 434 objects in scripts 8 from the script editor 34
with processing instructions scripts 35 testing 302
437 scrolling windows 92, 108 Open Database Connectivity (ODBC),
with text nodes 441 Names window defined 465
reset method 435 defined 465 Open Script button, described 255
save method 432 described 27 Open Script window 256
script example 443 illustration 28

PROGRAMMER’S GUIDE VOLUME 2 483


I N D E X

opening parameters (continued) pragmas (continued)


forms 53 global fields as parameter types list of 222
scripts 196 LiteralStringUsed 223
in the script debugger 256 optional 194, 344 NoExecutableCode 224
script drill-down 31 passing to other procedures or PossibleInfiniteLoop 223
windows 53 functions 195 TypeMismatch 223
operands, defined 465 storage types of 191 UnusedVariable 224
operators types 190 using to turn off literal string
defined 465 using 191 warnings 323
descriptions of 19 viewing with script debugger 264 pre scripts, defined 466
script examples 19 parent nodes, described 118 precedence, defined 466
Optimistic Concurrency Control, pass, defined 466 predefined constants
defined 175, 465 passive locking example of use 15
Optimizing Your Application, chapter defined 466 using in scripts 15
295-298 described 175 preprocessor directives
optional parameters pass-through SQL, defined 466 described 219
described 194 Password, field property 466 syntax 219
example 194 Pathname procedure primary key, defined 466
for COM methods 344 call stack usage 226 primary windows, defined 466
Options window 27, 281 defined 466 procedures
order of precedence pathnames, for memory-based tables Creating a scrolling window
defined 465 174 108-110
for sanScript 22 pausing macros 303, 304 Writing and attaching scripts 47-50
out parameters Performing Calculations, chapter 55-59 procedures (resource)
defined 465 Pervasive.SQL database manager, background processing 204
described 190 defined 466 calling 190
example 192 physical names, defined 466 chapter 189-207
overflow picture library, defined 466 creating 190
defined 465 pictures defined 466
described 55 for check boxes 69 described 189
in numeric expressions 55 for push buttons 71 for calling DLLs 216
preventing 56 pictures (resource) grouping 205
overlay images for list view items 136 in parameter example 191
for list view fields 136 for tree view nodes 124 inout parameter example 193
for tree view fields 124 ping, defined 466 local anonymous tables 199
pixel, defined 466 optimizing performance 295
P playing macros 303 optional parameter example 194
pad, defined 465 point size, defined 466 optional parameters 194
palette windows, defined 465 PossibleInfiniteLoop pragma 223 out parameter example 192
Paragraph objects, with COM 367 post scripts, defined 466 parameters 190-197
parameters power operator remote processing 204
defined 466 defined 466 script drill-down 31
described 190 use in sanScript 20 table buffers for 198
disabling unused parameter pragma() statement 222 terminology 189
warning 224 pragmas using form table buffers 198
for COM methods 344 described 222 process groups
for DLLs 216 example 222 creating 205

484 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

process groups (continued) radio buttons (continued) Recordset objects, with COM 401
defined 466 using 73 recursion, defined 467
deleting 207 radio groups reference information, viewing 282
described 205 defined 467 reference information table
guidelines 206 tab sequence 73 building 281
naming 205 using 73 clearing 284
processing remotely 206 random numbers, script example 210 described 281
running in the background 206 Range objects updating 284
viewing in the process queue 205 in Excel Object Library 381 Reference Information window 282
Process Monitor window 206 in Word Object Library 366 references
Process Server, defined 466 ranges assigning 232
product IDs, defined 466 chapter 167-171 chapter 231-235
product information, defined 466 creating with the range statement creating 232
Program Structures, chapter 61-63 165 defined 467
progress control, defined 466 described 167 described 231
progress indicator, defined 466 exclusive ranges 169 examples 234
prompts, defined 466 for multisegment keys 168 guidelines 233
properties inclusive ranges 169 reference fields 232
accessing for COM objects 343 overview 167 reference variables 232
adding to callback objects 351 purpose 167 to COM objects 337
defined 467 range types 169 typed 337
for scrolling windows 94 retrieving records with 165 untyped 338
providers, defined 467 script example 167, 168, 169 using 233
push buttons well-behaved ranges, described references button 282
3-D border 72 171 Referencing COM Objects, chapter
3-D highlight 72 read only, defined 467 337-340
Appearance property 72 read/write, defined 467 REGASM.EXE application 349
Cancel property 73 Recipient objects, with COM 421 regression testing, described 300
caption and images 70 record locking reject record, for scrolling windows 102
Default property 72 active 175 relative decimal position, defined 467
defined 467 described 175 releasing locks on records 176
Hyperspace property 73 passive 175 remote procedures, defined 467
pictures for 71 releasing locks 176 remote processing, overview 204
static picture values 71 recording macros repeat...until statement 63
using 70 described 303, 309 replacement markers, defined 467
suspending recording 303 report fields, defined 467
Q records report modules, defined 467
qualified names defined 467 report view, described 131
defined 467 deleting 155, 163 Report Writer, defined 467
described 9 having the same key values 163 reports, testing 301
examples 10 limiting using ranges 167 reports dictionaries, defined 468
using in scripts 9 locking 175-180 repository, defined 468
Quick Reports, defined 467 modifying values of key fields 165 required fields, defined 468
retrieving 154, 160 Reserved Words, appendix 453
R saving 153, 157 Resource Descriptions, defined 468
radio buttons size, defined 467 resource IDs, defined 468
defined 467 working with using scripts 151 Resource Usage, chapter 281-284
tab sequence 73

PROGRAMMER’S GUIDE VOLUME 2 485


I N D E X

resources script debugger (continued) script debugger (continued)


defined 468 breakpoints Step Out button/menu item
references to 231 clearing 257 described 262
results sets, defined 468 conditional 259 syntax coloring 27
retrieving records deleting 258 using 260
example 154, 160 described 257 viewing
using scripts 154, 160 disabling 258 call stacks 263
with the same key values 164 enabling 258 fields 264
return key processing, defined 468 ignoring 258 parameters 264
revision management, defined 468 list of 258 table buffer contents 268
root-level nodes, described 119 options 259 table information 268
run script delayed statement, use of setting 257 variables 264
call stacks 229 toggling 257 Script Debugger window 254
run script statement, use of call stacks types of 259 Script Debugger, menu item 253
227 unconditional 259 script drill-down
running object table, described 352 Calls window 263 closing scripts 32
runtime debugger chapter 253-272 closing the script editor 32
defined 468 context menu 255 defined 468
described 271 controlling script execution 260 described 31
runtime engine, defined 468 controls opening scripts 31
runtime errors, debugging 271 described 255 Scripts List 31
Runtime Script Editor, defined 468 Edit Script button 255 switching between scripts 32
Go button 255 script editor
S Open Script button 255 block indenting 26
sanScript Set Next Statement button 255 chapter 25-37
casts 23 Step button 255 Close button 26
constants 15 Step In button 255 closing 32
defined 468 Step Out button 255 Compile button 26
described 7 Toggle Breakpoint button 255 Compile Message button 26
expressions 16 Debug menu 253 controls 26
functions 11 described 253 Debug button 26
operators 19 evaluating expressions 265, 266 Delete button 26
order of precedence 22 examining applications 263 editing text 26
part 6-43 font 27 font 27
reserved words appendix 453 font size 27 font size 27
statements 11 Go button/menu item described Names button 26
syntax 8 261 Names window 27
variables 14 Locals window 264 online help support 34
saving opening 254 Print button 26
window field contents 307 opening scripts 256 Script menu 30
window images 307 Set Next Statement button syntax coloring 27
saving records described 262 using 25
example 153, 157 setting application values 265 Script Editor window 25
using scripts 153, 157 Step button/menu item described script exceptions 239
with same key values 164 261 script icon, defined 468
script debugger Step In button/menu item script log
accessing 253 described 261 example 279

486 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

script log (continued) scripts (continued) Scripts List


reading 279 communicating with the user 51 described 31
script logger compiling 32 illustration 31
chapter 279-280 controlling execution with script scroll bars, for text fields 77
defined 468 debugger 260 Scrolling Window Options window 92
overview 279 deciding function of 49 scrolling windows
using to debug scripts 280 defined 468 adds-allowed, characteristics 91
using with Microsoft Dynamics deleting a record, example 155, 163 attaching scripts 97
GP 280 drill-down 31 context menu script 105
script lookup mode, defined 468 editing while stopped at line change script 101
Script menu breakpoints 270 line delete script 105
described 30 elements 8 line fill script 102
searching for items in scripts 30 logging 279 line insert script 103
script preprocessor looping 62 line post script 102
defined 468 making decisions 61 line pre script 100
described 219 maximum length 25 to fields in the window 105
examples 220 naming 35 to specify display mode 99
preprocessor directives 219 naming objects in 8 big line item 96, 109
to include debugging code 221 optimizing 298 browse-only, characteristics 90
using 219 outlining steps 49 chapter 89-110
script profile overview 7 controlling the focus 105
database information 276 referencing local fields 10 creating, procedure 108-110
example 274 retrieving a record, example 154, defined 468
script cache information 277 160 deleting lines 105
script information 275 saving a record, example 153, 157 designing 93, 96
script profiler saving script source 30 display modes 96
chapter 273-277 scrolling window scripts 97 editable, characteristics 90
clearing the profile 273 searching for items 30 expanded mode
controlling 273 syntax 8 described 96
defined 468 to close forms 53 illustration 96
overview 273 to close windows 53 focus behavior 95
reading the profile 275 to control fields 53 inserting lines 103
saving the profile 274 to control windows 53 items related to 110
starting and stopping 273 to disable fields 54 layout 92
using to optimize performance 298 to enable fields 54 linked table 92, 108
scripts to hide fields 53 modes 96
analyzing performance 273 to lock fields 54 naming 92, 108
attaching to move the focus 54 normal mode
to fields 39 to open forms 53 described 96
to forms 43 to open windows 53 illustration 96
to list view fields 134 to perform calculations 55 optimizing performance 298
to scrolling windows 97, 110 to show fields 53 preventing records from
to tree view fields 120 to unlock fields 54 displaying 102
to windows 41 using ranges 167 properties 94, 108
automatic script naming 35 where to attach 49 rejecting records 102
checking syntax 30 working with tables 147, 152 scripts to fill the window 97
closing, script drill-down 32 writing, procedure 47-50 scrolling from scripts 106

PROGRAMMER’S GUIDE VOLUME 2 487


I N D E X

scrolling windows (continued) small line item storage types (continued)


sequence numbers for 103 defined 469 defined 469
single-line scrolling windows 106 described 93, 96 list of 12
small line item 93, 96, 109 for scrolling window 96, 109 of parameters 191
switching between normal and Software Engineering, part 286-325 stored procedures, defined 469
expanded mode 98 software quality string expressions
table buffers 97 characteristics of a good defined 469
types of 90 application 299 described 17
using the Lookup selection 106 process overview 300 string overflow, when translating
ScrollToBottom, scrolling window steps in process 300 applications 317
property 95, 109 testing phases 302 string resources, defined 469
searching software testing strings
see also Scripts menu phases of 302 appending 58
list view fields 142 using the macro system 304 auto-complete 74
tree view fields 127 software walkthroughs, described 300 comparing
Security procedure, call stack usage 226 sorting, for international applications chart 59
selection, for list view fields 318 described 58
changing 141 SortMethod, field property 120, 133 defined 469
retrieving 141 source code control server, defined 469 performing calculations 58
sequence numbers source files, defined 469 storage type 12, 14
defined 468 SQL, defined 469 structured exception handler, chapter
for scrolling windows 103 SQL symbol 3 237-249
script example 103 stacks, call stacks for script processing structured query language (SQL),
series, defined 468 225 defined 469
series resources, defined 469 stand-alone applications, defined 469 subclasses
session ID, defined 469 standard composites, defined 469 for database exceptions 243
Set Next Statement button, described Standard Controls, chapter 67-77 for system exceptions 240
255, 262 Standard International Info option, for subtraction operator, use in sanScript
shell, exporting application shell to macros 305 19
XML file 308 starting scripts, defined 469 suppressing, compiler warnings 222
shiftl operator, described 20 state images suspending recording macros 303
shiftr operator, described 20 for list view fields 136 switching between scripts, script
shortcut keys, defined 469 for tree view fields 124 drill-down 32
ShowHeadings, field property 133 statements symbols in documentation 3
showing fields, with scripts 53 defined 469 synchronizing
ShowSelection, field property 120, 133 described 11 dictionaries, defined 469
shrinking and rebuilding tables, static picture values, defined 469 native pictures 469
defined 469 static text values, defined 469 syntax, of scripts 8
sibling nodes, described 118 Step, menu item 254, 261 syntax coloring
simple names Step button, described 255, 261 described 27
defined 469 Step In, menu item 254, 261 specifying colors 27
described 8 Step In button, described 255, 261 system commands, defined 469
examples 9 Step Out, menu item 254, 262 system exceptions
using in scripts 8 Step Out button, described 255, 262 classes 239
single-line scrolling windows, stopping macros 303 defined 470
described 106 storage types described 237, 239
small icon view, described 130 converting 13 subclasses 240

488 P R O G R A M M E R ’ S G U I D E V O L U M E 2
I N D E X

T testing (continued) tree view


tab sequence, defined 470 DLLs 302 adding nodes 123
Table Buffers, menu item 254 multiple users 301 attaching scripts
table buffers network operation 301 collapse script 122
defined 470 online help 302 context menu script 123
described 148 phases of testing 302 double-click script 123
for scrolling windows 97 reports 301 expand script 121
illustration 148 video configurations 301 post script 120
using with procedures 198 text, storage type 12, 14 pre script 120
viewing contents 268 text fields select script 120
Table Buffers window 268 edit modes 77 state click script 122
table fields, defined 470 properties for 77 chapter 117-128
table groups, defined 470 text reports, defined 470 defined 470
Table objects The Development Process, chapter described 117
in ADOX Object Library 392 287-289 images
in Word Object Library 369 throw, defined 470 adding 125
table open mode, defined 470 time, storage type 12, 14 background color 126
table relationships, defined 470 time values for nodes 124
tables adding numeric values to, item images 124
common operations 147 example 19 overlay images 124
defined 470 subtracting from another time size 126
deleting, records 163 value, example 19 specifying 126
exporting contents to text 308 subtracting numeric values from, state images 124
linked to scrolling windows 92, example 19 node attributes 119
108 Toggle Breakpoint button, described object properties 120
manipulating with scripts 147 255 searching 127
memory-based tables 173 toolbars terminology 118
modifying values of key fields 165 controls on 77 visual properties 120
optimizing access performance defined 470 TreeView Images window 125
296, 297 exporting contents to text 308 try...end try statement 238
overview 147 Toolbox, defined 470 type libraries
retrieving information 160 tools mode, defined 470 adding reference to a dictionary
saving information 153, 157 tooltips, described 77 334
temporary, memory-based 174 transaction rollback, defined 470 adding reference to a script 335
viewing table information 268 transactions described 333
with duplicate records 163 chapter 181-186 referencing 333
TCP/IP, defined 470 deadlocks 182 typed references 337
technical names, defined 470 ending 181 TypeMismatch pragma 223
temporary tables, memory-based 174 error handling 182
test mode, defined 470 for integrating applications 186 U
guidelines 185 unary minus operator 19
test procedures
overview 181 unchunking, defined 470
for Dexterity applications 301
sample code 182 unconditional breakpoints 259
planning 300
starting 181 unhandled exceptions, defined 470
recording as macros 300
template 182 unique index, defined 470
testing
translation errors, minimizing 317 unlocking, fields 54
chapter 299-312
trap, defined 470 untyped referenced, described 338
different database types 301

PROGRAMMER’S GUIDE VOLUME 2 489


I N D E X

UnusedVariable pragma 224 well-behaved ranges 171 windows in Dexterity (continued)


user exceptions while do...end while statement 63 Process Monitor 206
defined 471 window fields, defined 471 Reference Information 282
described 237, 238 window layouts, for scrolling windows Script Debugger 254
example 238 92 Script Editor 25
user-defined function, return value 209 window scripts Scrolling Window Options 92
user-defined functions activate script, described 42 Table Buffers 268
chapter 209-213 attaching 41 Visualizer 267
creating 209 context menu script, described 42 Watch 266
defined 470 post script, described 42 WindowType, scrolling window
described 209 pre script, described 42 property 95, 109
examples 210, 211 print script, described 42 word wrap
for reports 213 types 41 defined 471
naming 213 WindowID, scrolling window property for text fields 77
naming for reports 213 95, 109 Workbook objects, with COM 378
optimizing performance 295 windows Working With Controls, part 66-143
script drill-down 31 activate script, described 42 Working with Records, chapter 151-166
syntax 209 attaching scripts 41 Working with Tables, part 146-186
using 210 closing with scripts 53 worksets, defined 471
without return value 210 context menu script, described 42 Worksheet objects, with COM 380
controlling with scripts 53 WorksheetFunction objects, with COM
V defined 471 384
variable currency, storage type 12 opening in macros 308 writing scripts, procedure 47-50
variable currency values opening with scripts 53 WYSIWYG, defined 471
performing calculations 56 post script, described 42
retrieving characteristics 57 pre script, described 42 X
rounding 57 print script, described 42 XML documents
variables saving data in tables 147 copying 432
defined 471 saving images of 307 creating 431
global variables 14 Windows Compatibility option, for loading 431
in sanScript 14 macros 305 saving 433
local variables 14 windows in Dexterity searching 438
setting values with script Breakpoint Options 259
debugger 265 Breakpoints 258 Z
types 14 Calls 263 zoom pointer, defined 471
VBA, defined 471 Class Browser 339, 345
version numbers, defined 471 Class Browser window 354
video configurations, testing 301 COM Type Libraries 334
virtual tables, defined 471 Compile Messages 33
visual properties Composite Definition 80
for list view fields 133 Expressions 265
for tree view fields 120 Library Definition 334
Visualizer window 267 Locals 264
Macro Status 305
W Names 28
warning statement 51 Open Script 256
warning symbol 3 Options 27, 281
Watch window 266

490 P R O G R A M M E R ’ S G U I D E V O L U M E 2

You might also like