0% found this document useful (0 votes)
6 views

TD Developing With SQLWindows

Uploaded by

rugnayerdo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

TD Developing With SQLWindows

Uploaded by

rugnayerdo
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 605

Team Developer™

Developing with SQLWindows


Team Developer™: Developing with SQLWindows

Open Text Corporation

275 Frank Tompa Drive, Waterloo, Ontario, Canada, N2L 0A1


Tel: +1-519-888-7111 Toll Free Canada/USA: 1-800-499-6544 International: +800-4996-5440
Fax: +1-519-888-0677
Support: http://support.opentext.com
For more information, visit https://www.opentext.com

Copyright © 2023 Open Text. All rights reserved. OpenText is a trademark or registered trademark of Open Text.
The list of trademarks is not exhaustive of other trademarks, registered trademarks, product names, company
names, brands and service names mentioned herein are property of Open Text or other respective owners.
One or more patents may cover this product. For more information, please
visit https://www.opentext.com/patents.
Disclaimer
No Warranties and Limitation of Liability. Every effort has been made to ensure the accuracy of the features and
techniques presented in this publication. However, Open Text Corporation and its affiliates accept no responsibility
and offer no warranty whether expressed or implied, for the accuracy of this publication.
Warning: This software is protected by copyright law and international treaties. Unauthorized reproduction or
distribution of this program, or any portion of it, may result in severe civil and criminal penalties, and will be
prosecuted to the maximum extent possible under the law.

2
Table of Contents

Preface ............................................................................................................................................................................ 31
Purpose and Scope of this Manual .................................................................................................................................. 31
Audience Requirements ...................................................................................................................................................... 31
Summary of Chapters........................................................................................................................................................... 31
Notation Conventions .......................................................................................................................................................... 32
Chapter 1 – SQLWindows ......................................................................................................................................... 34
Team Developer...................................................................................................................................................................... 34
SQLWindows ............................................................................................................................................................................ 34
SQLWindows Environments.............................................................................................................................................. 35
Objects, Messages, and Events.......................................................................................................................................... 36
Chapter 2 – SQLWindows Desktop ........................................................................................................................ 37
SQLWindows User Interface.............................................................................................................................................. 37
Toolbars ..................................................................................................................................................................................... 38
Custom Toolbars............................................................................................................................................................. 39
Docking Toolbars, Palettes, and the Menu Bar .................................................................................................. 39
Resizing Toolbars, Palettes, and the Menu Bar .................................................................................................. 40
Tab Views .................................................................................................................................................................................. 41
Actions Tab ....................................................................................................................................................................... 41
Base Classes Tab ............................................................................................................................................................. 41
Class Variables Tab ........................................................................................................................................................ 41
Components Tab............................................................................................................................................................. 41
Constants Tab .................................................................................................................................................................. 41
Description Tab............................................................................................................................................................... 42
Layout Tab......................................................................................................................................................................... 42
Libraries Tab .................................................................................................................................................................... 43
Outline Tab ....................................................................................................................................................................... 43
Parameters Tab ............................................................................................................................................................... 45
Returns Tab ...................................................................................................................................................................... 45
Static Variables Tab ....................................................................................................................................................... 45
Variables Tab.................................................................................................................................................................... 45
Cursors ....................................................................................................................................................................................... 45
Right Mouse Button Features ........................................................................................................................................... 46
Explore ............................................................................................................................................................................... 46
Open View ......................................................................................................................................................................... 46

3
New ...................................................................................................................................................................................... 46
Quick Info, List Members, Parameter Info, Match Brace................................................................................ 47
Cut, Copy, Paste ............................................................................................................................................................... 47
Delete, Rename ............................................................................................................................................................... 48
Properties ......................................................................................................................................................................... 48
Select in Layout ............................................................................................................................................................... 48
Other Right Mouse Button Menus ........................................................................................................................... 48
Editing Object Attributes .................................................................................................................................................... 48
Attribute Inspector................................................................................................................................................................ 49
Multiple Object Select .................................................................................................................................................. 50
Setting Properties .......................................................................................................................................................... 50
Coding Assistant ..................................................................................................................................................................... 50
Active Coding Assistant ....................................................................................................................................................... 52
Complete Word ............................................................................................................................................................... 52
Parameter Info ................................................................................................................................................................ 52
Quick Info .......................................................................................................................................................................... 53
List Members ................................................................................................................................................................... 53
Match Brace ...................................................................................................................................................................... 54
Controls Palette ...................................................................................................................................................................... 55
Configuring the Controls Palette ............................................................................................................................. 56
Source Control Palette ......................................................................................................................................................... 57
Configuring the Source Control Palette ................................................................................................................ 58
SQLWindows Menus ............................................................................................................................................................. 58
Debugger ................................................................................................................................................................................... 59
Keyboard Shortcuts............................................................................................................................................................... 59
SQLWindows Command Line Arguments .................................................................................................................... 64
Chapter 3 – Deploying and Migrating Applications ........................................................................................ 65
Deploying an Application ................................................................................................................................................... 65
Creating an Executable Application ....................................................................................................................... 65
Installing Deployment Files ....................................................................................................................................... 65
Installing Deployer in Silent Mode.......................................................................................................................... 67
Deploying a Win32 Application Containing .NET Library Code ................................................................. 67
Deploying to Windows Vista or Windows 7 ....................................................................................................... 67
Connecting to a Data Source.............................................................................................................................................. 67
Opening an Application in a Different Version .......................................................................................................... 68
Opening a 5.1+ Application in 4.2 or Earlier ...................................................................................................... 68

4
Opening an Old Application in a Newer TD Version ........................................................................................ 68
Chapter 4 – SQLWindows Menus ........................................................................................................................... 69
File Menu ................................................................................................................................................................................... 69
New ...................................................................................................................................................................................... 69
Open .................................................................................................................................................................................... 70
Save ...................................................................................................................................................................................... 70
Save and Return .............................................................................................................................................................. 70
Save As................................................................................................................................................................................ 70
Page Settings .................................................................................................................................................................... 71
Print ..................................................................................................................................................................................... 72
Most Recently Open List.............................................................................................................................................. 72
Exit ....................................................................................................................................................................................... 72
Edit Menu .................................................................................................................................................................................. 72
Undo .................................................................................................................................................................................... 72
Cut ........................................................................................................................................................................................ 72
Copy ..................................................................................................................................................................................... 72
Paste .................................................................................................................................................................................... 73
Delete .................................................................................................................................................................................. 73
Insert Line ......................................................................................................................................................................... 73
Comment Items............................................................................................................................................................... 73
Uncomment Items ......................................................................................................................................................... 73
Outline menu ................................................................................................................................................................... 73
Active Coding Assistant Items .................................................................................................................................. 74
Find ...................................................................................................................................................................................... 74
Find Again ......................................................................................................................................................................... 75
Replace Tab....................................................................................................................................................................... 75
Properties ......................................................................................................................................................................... 76
Project Menu ............................................................................................................................................................................ 78
Check Out .......................................................................................................................................................................... 78
Check In ............................................................................................................................................................................. 78
Compile .............................................................................................................................................................................. 78
Next Error ......................................................................................................................................................................... 78
Previous Error ................................................................................................................................................................. 78
Execute ............................................................................................................................................................................... 79
Register Server................................................................................................................................................................ 79
Unregister Server ........................................................................................................................................................... 79

5
Regenerate GUIDs .......................................................................................................................................................... 79
Build Settings ................................................................................................................................................................... 79
Build .................................................................................................................................................................................... 84
Component Menu .................................................................................................................................................................. 85
New ...................................................................................................................................................................................... 85
Wizards .............................................................................................................................................................................. 85
QuickObject Editor ........................................................................................................................................................ 85
Go To Item ......................................................................................................................................................................... 85
Show Item Information ............................................................................................................................................... 85
Refresh Libraries ............................................................................................................................................................ 85
Merge Libraries............................................................................................................................................................... 85
Large Icons ....................................................................................................................................................................... 86
Small Icons........................................................................................................................................................................ 86
List Details ........................................................................................................................................................................ 86
Layout Menu ............................................................................................................................................................................ 86
Preview Window ............................................................................................................................................................ 86
Bring To Front ................................................................................................................................................................. 87
Send To Back .................................................................................................................................................................... 87
Align to Grid ..................................................................................................................................................................... 87
Align Edges ....................................................................................................................................................................... 87
Space Evenly .................................................................................................................................................................... 88
Make Same Size............................................................................................................................................................... 88
Grid ...................................................................................................................................................................................... 88
Tab Order........................................................................................................................................................................... 88
Show Sample Text .......................................................................................................................................................... 89
Show Design Scroll Bars.............................................................................................................................................. 89
Show Hidden Windows ............................................................................................................................................... 89
Debug Menu ............................................................................................................................................................................. 90
Stop ...................................................................................................................................................................................... 90
Continue............................................................................................................................................................................. 90
Breakpoints ...................................................................................................................................................................... 90
Break ................................................................................................................................................................................... 90
Step Into............................................................................................................................................................................. 90
Step Over ........................................................................................................................................................................... 90
Breakpoints ...................................................................................................................................................................... 90
No Animate ....................................................................................................................................................................... 91

6
Slow Animate ................................................................................................................................................................... 91
Fast Animate .................................................................................................................................................................... 91
Playback ............................................................................................................................................................................. 91
Playback Rewind ............................................................................................................................................................ 91
Tools Menu ............................................................................................................................................................................... 91
User Tools.......................................................................................................................................................................... 91
Toolbars ............................................................................................................................................................................. 93
Preferences ....................................................................................................................................................................... 94
Output ................................................................................................................................................................................. 99
Coding Assistant ............................................................................................................................................................. 99
Attribute Inspector..................................................................................................................................................... 100
Controls........................................................................................................................................................................... 100
Variables ......................................................................................................................................................................... 100
Call Stack ........................................................................................................................................................................ 100
Messages......................................................................................................................................................................... 100
Expressions ................................................................................................................................................................... 101
Database Explorer ...................................................................................................................................................... 101
ActiveX Explorer .......................................................................................................................................................... 101
Report Builder.............................................................................................................................................................. 101
Team Object Manager................................................................................................................................................ 101
Browse All Classes ...................................................................................................................................................... 101
Diff/Merge ..................................................................................................................................................................... 101
SQLTalk ............................................................................................................................................................................ 102
Create Documentation .............................................................................................................................................. 102
Database Explorer Menu ................................................................................................................................................. 102
New ................................................................................................................................................................................... 102
SQL Script ....................................................................................................................................................................... 103
Table ................................................................................................................................................................................. 104
Stored Procedure ........................................................................................................................................................ 105
Query................................................................................................................................................................................ 105
Add to List ...................................................................................................................................................................... 107
Disconnect ..................................................................................................................................................................... 107
View System Tables .................................................................................................................................................... 107
Close Database Explorer .......................................................................................................................................... 107
ActiveX Explorer Menu ..................................................................................................................................................... 108
Window Menu ...................................................................................................................................................................... 109

7
Cascade............................................................................................................................................................................ 109
Tile Horizontally.......................................................................................................................................................... 109
Tile Vertically ................................................................................................................................................................ 109
Close All .......................................................................................................................................................................... 109
Open Windows List .................................................................................................................................................... 109
Help Menu.............................................................................................................................................................................. 109
Help Topics .................................................................................................................................................................... 110
Functions Messages ................................................................................................................................................... 110
QuickObjects ................................................................................................................................................................. 110
Visual Toolchest........................................................................................................................................................... 110
Books Online ................................................................................................................................................................. 110
About SQLWindows ................................................................................................................................................... 110
Chapter 5 – SQLWindows Objects....................................................................................................................... 111
Adding Objects ..................................................................................................................................................................... 111
Child Object Mouse Pointers .................................................................................................................................. 111
Attributes ....................................................................................................................................................................... 112
Naming Conventions for Objects .................................................................................................................................. 112
Types of Objects .................................................................................................................................................................. 113
Top-Level Objects........................................................................................................................................................ 113
Child Windows ............................................................................................................................................................. 114
Messages that Objects Receive ...................................................................................................................................... 115
MDI Window ................................................................................................................................................................. 116
MDI Window Attributes ........................................................................................................................................... 116
Outline Items ................................................................................................................................................................ 117
MDI Window Handles ............................................................................................................................................... 118
Multiple MDI Windows............................................................................................................................................. 118
Creating an MDI Window at Runtime................................................................................................................. 118
Creating MDI Child Objects at Runtime ............................................................................................................. 118
SAM_Destroy ................................................................................................................................................................. 118
Functions for MDI Windows................................................................................................................................... 119
Windows Menu ............................................................................................................................................................ 119
Form Window....................................................................................................................................................................... 120
Form Window Attributes ......................................................................................................................................... 121
Dialog Box .............................................................................................................................................................................. 122
Modeless ......................................................................................................................................................................... 123
Modal ............................................................................................................................................................................... 123

8
System Modal................................................................................................................................................................ 123
Owned and Ownerless Dialog Boxes................................................................................................................... 123
Message Boxes .............................................................................................................................................................. 124
Dialog Box Attributes ................................................................................................................................................ 124
Standard Dialogs ................................................................................................................................................................. 125
Message Boxes ..................................................................................................................................................................... 126
ActiveX Control .................................................................................................................................................................... 126
Background Text ................................................................................................................................................................. 126
Background Text Attributes.................................................................................................................................... 127
Manipulating Background Text ............................................................................................................................. 127
Check Box ............................................................................................................................................................................... 128
Check Box Attributes ................................................................................................................................................. 128
Child Table Window........................................................................................................................................................... 128
Combo Box ............................................................................................................................................................................. 129
User Interface ............................................................................................................................................................... 129
Combo Box Attributes ............................................................................................................................................... 129
Custom Control .................................................................................................................................................................... 131
Data Field ............................................................................................................................................................................... 131
Data Field Attributes ................................................................................................................................................. 131
Frame ....................................................................................................................................................................................... 132
Frame Attributes ......................................................................................................................................................... 133
Grid ........................................................................................................................................................................................... 133
Grid Attributes ............................................................................................................................................................. 134
Context Menu, Sorting, Grouping ......................................................................................................................... 134
Grouping in the Grid via Sal Functions .............................................................................................................. 135
API Support ................................................................................................................................................................... 135
Grid Column Types ..................................................................................................................................................... 135
Group Box .............................................................................................................................................................................. 136
Group Box Attributes................................................................................................................................................. 136
Line ........................................................................................................................................................................................... 137
Line Attributes ............................................................................................................................................................. 137
List Box.................................................................................................................................................................................... 138
User Interface ............................................................................................................................................................... 138
List Box Attributes ...................................................................................................................................................... 138
Multiline Field ...................................................................................................................................................................... 139
Multiline Field Attributes ........................................................................................................................................ 140

9
Navigation Bar ..................................................................................................................................................................... 141
Navigation Bar Attributes........................................................................................................................................ 141
Navigation Pane Attributes ..................................................................................................................................... 142
Option Button ....................................................................................................................................................................... 142
Option Button Attributes ......................................................................................................................................... 142
Option Button Values ................................................................................................................................................ 143
Option Button Styles .................................................................................................................................................. 143
Option Button Images ............................................................................................................................................... 144
Single-Image Style ...................................................................................................................................................... 145
Multiple-Image Style.................................................................................................................................................. 145
File Open Dialog .......................................................................................................................................................... 145
Picture ..................................................................................................................................................................................... 146
Push Button ........................................................................................................................................................................... 146
Push Button Attributes ............................................................................................................................................. 146
Accelerators .................................................................................................................................................................. 147
Images in Push Buttons ............................................................................................................................................ 147
Radio Button ......................................................................................................................................................................... 149
Radio Button Attributes ........................................................................................................................................... 150
Rich Text ................................................................................................................................................................................. 150
API Support ................................................................................................................................................................... 151
Messaging....................................................................................................................................................................... 151
Rich Text Attributes ................................................................................................................................................... 151
Scroll Bars .............................................................................................................................................................................. 153
Scroll Bar Attributes .................................................................................................................................................. 153
Status Bar ............................................................................................................................................................................... 154
Menu Status Text ......................................................................................................................................................... 154
Tab Bar .................................................................................................................................................................................... 154
Tab Bar Attributes ...................................................................................................................................................... 155
Tab Page Attributes .................................................................................................................................................... 156
API Support ................................................................................................................................................................... 157
Table Window ...................................................................................................................................................................... 157
Table Window Column ..................................................................................................................................................... 157
Toolbar .................................................................................................................................................................................... 157
Toolbar Attributes ...................................................................................................................................................... 158
Outline Items ................................................................................................................................................................ 158
Alt Keys and Toolbars................................................................................................................................................ 159

10
Functions ........................................................................................................................................................................ 159
Tree Control and Tree Items .......................................................................................................................................... 160
Tree Control Events.................................................................................................................................................... 160
Tree Control Functions ............................................................................................................................................. 161
Tree Control Attributes ............................................................................................................................................ 161
Tree Item Attributes ................................................................................................................................................... 162
Object Colors......................................................................................................................................................................... 163
Color Inheritance ........................................................................................................................................................ 163
Functions ........................................................................................................................................................................ 163
Fonts for Objects with Text ............................................................................................................................................. 163
Font Inheritance .......................................................................................................................................................... 164
Changing Default Colors and Fonts ............................................................................................................................. 164
Form Units ............................................................................................................................................................................. 164
Window Handles ................................................................................................................................................................. 165
Docking Windows............................................................................................................................................................... 165
Docking Issues with Attributes in the Attribute Inspector ........................................................................ 165
Using Objects as Variables............................................................................................................................................... 166
Using Object Names as Parameters ............................................................................................................................. 166
Top-Level Window Parameters..................................................................................................................................... 166
Chapter 6 – Application Menus ........................................................................................................................... 168
Popup Menus ........................................................................................................................................................................ 168
Menu Items ............................................................................................................................................................................ 169
Menu Item Properties ............................................................................................................................................... 169
Accelerators .................................................................................................................................................................. 171
Menu Separator ........................................................................................................................................................... 171
Cascading Menus................................................................................................................................................................. 172
Menu Row .............................................................................................................................................................................. 172
Menu Column ....................................................................................................................................................................... 173
Named Menus....................................................................................................................................................................... 173
Predefined Named Menus ....................................................................................................................................... 174
Creating Popup Menus Dynamically at Runtime ........................................................................................... 174
Menu Status Text ................................................................................................................................................................. 175
Windows Menu .................................................................................................................................................................... 175
Ribbon Bar ............................................................................................................................................................................. 175
Application Menus and Win32 API.............................................................................................................................. 176

11
Chapter 7 – SAL (SQLWindows Application Language) .............................................................................. 177
Case Sensitivity .................................................................................................................................................................... 177
Maximum Identifier Length............................................................................................................................................ 177
Data Types ............................................................................................................................................................................. 177
Receive Data Types..................................................................................................................................................... 178
Binary .............................................................................................................................................................................. 178
Boolean ........................................................................................................................................................................... 178
Date/Time ...................................................................................................................................................................... 178
Number ........................................................................................................................................................................... 181
Internal Format for Number and Date/Time Data Types .......................................................................... 181
Session Handle ............................................................................................................................................................. 182
Sql Handle ...................................................................................................................................................................... 182
File Handle ..................................................................................................................................................................... 182
String................................................................................................................................................................................ 182
Long String .................................................................................................................................................................... 182
Window Handle ........................................................................................................................................................... 183
Data Types Treated as Booleans ........................................................................................................................... 184
Variables ................................................................................................................................................................................. 184
Where to Declare Variables .................................................................................................................................... 184
When Variables are Valid ......................................................................................................................................... 185
How SQLWindows Initializes Variables ............................................................................................................. 185
How to Refer to Variables ........................................................................................................................................ 185
Variables in SQL Statements................................................................................................................................... 187
System Variables ......................................................................................................................................................... 187
Arrays ...................................................................................................................................................................................... 188
One-Dimensional Arrays .......................................................................................................................................... 189
Multi-Dimensional Arrays ....................................................................................................................................... 189
Storing Child Window Handles in Arrays ......................................................................................................... 190
Array Functions ........................................................................................................................................................... 191
Constants................................................................................................................................................................................ 191
System Constants ........................................................................................................................................................ 192
Naming Conventions ......................................................................................................................................................... 192
Variables ......................................................................................................................................................................... 192
Constants ........................................................................................................................................................................ 192
Operators ............................................................................................................................................................................... 193
Expressions ........................................................................................................................................................................... 193

12
SAL Statements .................................................................................................................................................................... 194
Where to Code SAL Statements............................................................................................................................. 194
Break ................................................................................................................................................................................ 194
Call .................................................................................................................................................................................... 195
If, Else, and Else If ....................................................................................................................................................... 195
Loop .................................................................................................................................................................................. 196
On ...................................................................................................................................................................................... 196
Return .............................................................................................................................................................................. 197
Select Case ..................................................................................................................................................................... 197
Set ...................................................................................................................................................................................... 198
When SqlError ............................................................................................................................................................. 198
While ................................................................................................................................................................................ 198
Comments .............................................................................................................................................................................. 199
Reserved Words................................................................................................................................................................... 200
Functions ................................................................................................................................................................................ 200
System Functions ........................................................................................................................................................ 201
External Functions ..................................................................................................................................................... 201
Internal Functions ...................................................................................................................................................... 201
Window Functions ..................................................................................................................................................... 201
Class Functions ............................................................................................................................................................ 201
Writing Functions ....................................................................................................................................................... 201
Calling Window Functions .............................................................................................................................................. 203
Unqualified Reference............................................................................................................................................... 203
Object-Qualified Reference ..................................................................................................................................... 203
Fully Object-Qualified Reference .......................................................................................................................... 203
Late-Bound Fully Class-Qualified Reference.................................................................................................... 204
Command Line Arguments ............................................................................................................................................. 204
Using SalLoadApp with Command Line Arguments .................................................................................... 204
Using the Clipboard ........................................................................................................................................................... 204
Clipboard Functions................................................................................................................................................... 205
Resources ............................................................................................................................................................................... 205
Yielding ................................................................................................................................................................................... 205
Chapter 8 – Object-Oriented Programming.................................................................................................... 208
Objects, Classes, and Inheritance ................................................................................................................................. 208
Designing Classes and Objects ...................................................................................................................................... 209
Writing Applications with Classes and Objects ...................................................................................................... 209

13
Class Inheritance................................................................................................................................................................. 209
Single Inheritance ....................................................................................................................................................... 209
Multiple Inheritance .................................................................................................................................................. 210
Types of Classes................................................................................................................................................................... 211
Functional Classes ...................................................................................................................................................... 211
Window Classes ........................................................................................................................................................... 211
General Window Classes .......................................................................................................................................... 212
Types of Objects .................................................................................................................................................................. 212
User-Defined Windows ............................................................................................................................................ 213
User-Defined Variable (UDV) ................................................................................................................................. 213
Defining Classes................................................................................................................................................................... 213
Defining Functional Classes............................................................................................................................................ 214
Window Classes................................................................................................................................................................... 214
Attributes ....................................................................................................................................................................... 214
Window Class Definition Outline Items............................................................................................................. 215
Types of Window Classes ........................................................................................................................................ 216
Child Window Classes ............................................................................................................................................... 216
Dialog Box Classes ...................................................................................................................................................... 217
Form Window, Top-Level Table Window, and MDI Window Classes .................................................... 217
Class Contents Inheritance ............................................................................................................................................. 218
Inheriting Class Children ......................................................................................................................................... 218
Multiple Base Classes ................................................................................................................................................ 219
Class Children ............................................................................................................................................................... 219
Class Child Instances ................................................................................................................................................. 219
Naming Child Objects ................................................................................................................................................ 220
Creating User-Defined Objects ...................................................................................................................................... 221
Changing an Object’s Class ...................................................................................................................................... 221
Creating UDVs....................................................................................................................................................................... 222
Passed by Reference .................................................................................................................................................. 222
Arrays of UDVs ............................................................................................................................................................. 222
Assigning UDVs ............................................................................................................................................................ 223
Dynamic Instantiation .............................................................................................................................................. 225
Object Destructors...................................................................................................................................................... 225
SalObj* Functions........................................................................................................................................................ 226
Creating User-Defined Windows .................................................................................................................................. 226
Using the Controls Palette ....................................................................................................................................... 227

14
Components .................................................................................................................................................................. 227
Overriding Inherited Attributes ............................................................................................................................ 227
Using Message Actions in Classes ................................................................................................................................ 227
Message Actions with Single Inheritance ......................................................................................................... 228
Message Actions with Multiple Inheritance..................................................................................................... 230
Using Message Actions in Objects ................................................................................................................................ 232
Inheriting Message Actions .................................................................................................................................... 232
Overriding Inherited Message Actions............................................................................................................... 233
Invoking Overridden Message Actions .............................................................................................................. 233
Instance Variables .............................................................................................................................................................. 234
Inheritance .................................................................................................................................................................... 235
Using Instance Variables in Classes and Objects.................................................................................................... 235
Internal References .................................................................................................................................................... 235
this Keyword ................................................................................................................................................................. 236
External References ................................................................................................................................................... 237
Class Variables ..................................................................................................................................................................... 239
Inheritance .................................................................................................................................................................... 239
Using Class Variables in Classes and Objects................................................................................................... 240
Class Functions .................................................................................................................................................................... 240
Inheritance .................................................................................................................................................................... 241
Using Class Functions in Classes and Objects ......................................................................................................... 241
Internal References .................................................................................................................................................... 241
External References ................................................................................................................................................... 244
References in Container Objects ................................................................................................................................... 247
MyValue System Variable................................................................................................................................................. 247
SalObjIsValidClassName .................................................................................................................................................. 248
SqlVarSetup ........................................................................................................................................................................... 248
Chapter 9 – Messages ............................................................................................................................................. 249
Types of Messages .............................................................................................................................................................. 249
Message Names and Numbers....................................................................................................................................... 249
SAM_* Messages .................................................................................................................................................................. 249
SAM Events .................................................................................................................................................................... 249
Where SQLWindows Sends SAM_* Messages .................................................................................................. 250
Application-Defined Messages ...................................................................................................................................... 250
Microsoft Windows Messages ....................................................................................................................................... 251
Processing Messages ......................................................................................................................................................... 251

15
System Variables ................................................................................................................................................................. 251
hWndForm ..................................................................................................................................................................... 252
hWndItem ...................................................................................................................................................................... 252
wParam and lParam ................................................................................................................................................... 252
SAM Reference ..................................................................................................................................................................... 252
SAM_Activate ................................................................................................................................................................ 252
SAM_AnyEdit................................................................................................................................................................. 253
SAM_AppExit................................................................................................................................................................. 253
SAM_AppStartup ......................................................................................................................................................... 254
SAM_CacheFull ............................................................................................................................................................. 254
SAM_CaptionDoubleClick ........................................................................................................................................ 255
SAM_Click ....................................................................................................................................................................... 256
SAM_Close ...................................................................................................................................................................... 257
SAM_ColumnSelectClick ........................................................................................................................................... 258
SAM_ContextMenu...................................................................................................................................................... 258
SAM_CornerClick ......................................................................................................................................................... 259
SAM_CornerDoubleClick .......................................................................................................................................... 259
SAM_CountRows.......................................................................................................................................................... 260
SAM_Create .................................................................................................................................................................... 260
SAM_CreateComplete ................................................................................................................................................ 261
SAM_CustControlCmd ............................................................................................................................................... 261
SAM_Destroy ................................................................................................................................................................. 262
SAM_Dock....................................................................................................................................................................... 262
SAM_DockChange........................................................................................................................................................ 263
SAM_DockResize ......................................................................................................................................................... 263
SAM_DockResizeNotify ............................................................................................................................................. 265
SAM_DoubleClick ........................................................................................................................................................ 265
SAM_DragCanAutoStart............................................................................................................................................ 266
SAM_DragDrop ............................................................................................................................................................. 267
SAM_DragEnd ............................................................................................................................................................... 267
SAM_DragEnter ............................................................................................................................................................ 268
SAM_DragExit ............................................................................................................................................................... 268
SAM_DragMove ............................................................................................................................................................ 268
SAM_DragNotify........................................................................................................................................................... 269
SAM_DragStart ............................................................................................................................................................. 269
SAM_DropDown........................................................................................................................................................... 270

16
SAM_DropFiles ............................................................................................................................................................. 270
SAM_EndCellTab .......................................................................................................................................................... 271
SAM_FetchDone ........................................................................................................................................................... 271
SAM_FetchRow ............................................................................................................................................................. 272
SAM_FetchRowDone .................................................................................................................................................. 272
SAM_FieldEdit .............................................................................................................................................................. 273
SAM_Help ....................................................................................................................................................................... 273
SAM_KillFocus .............................................................................................................................................................. 274
SAM_Print....................................................................................................................................................................... 274
SAM_ReportFetchInit................................................................................................................................................. 275
SAM_ReportFetchNext .............................................................................................................................................. 276
SAM_ReportFinish ...................................................................................................................................................... 276
SAM_ReportNotify ...................................................................................................................................................... 277
SAM_ReportStart ......................................................................................................................................................... 277
SAM_RowHeaderClick ............................................................................................................................................... 278
SAM_RowHeaderDoubleClick ................................................................................................................................ 278
SAM_RowValidate ....................................................................................................................................................... 279
SAM_ScrollBar .............................................................................................................................................................. 279
SAM_SessionError ...................................................................................................................................................... 280
SAM_SetFocus ............................................................................................................................................................... 281
SAM_SqlError ............................................................................................................................................................... 281
SAM_Timer..................................................................................................................................................................... 282
SAM_Validate ................................................................................................................................................................ 283
SAM_XMLRowDone .................................................................................................................................................... 284
SAM_* Summary .................................................................................................................................................................. 285
Chapter 10 – Debugging ........................................................................................................................................ 287
Run Mode ............................................................................................................................................................................... 287
Animation .............................................................................................................................................................................. 287
Breakpoints ........................................................................................................................................................................... 288
Setting Breakpoints.................................................................................................................................................... 288
Clearing Breakpoints ................................................................................................................................................. 289
Immediate Breakpoints ............................................................................................................................................ 289
Breakpoints Dialog Box ............................................................................................................................................ 289
Validity Checking......................................................................................................................................................... 290
Advanced Breakpoints Dialog........................................................................................................................................ 290
How It Works ................................................................................................................................................................ 292

17
Debug Toolbar ...................................................................................................................................................................... 292
Commands ..................................................................................................................................................................... 293
Debugging Windows.................................................................................................................................................. 293
Debugging COM Servers................................................................................................................................................... 298
Debugging DLLs................................................................................................................................................................... 298
Tips ........................................................................................................................................................................................... 298
Writing Your Own Debugging Code............................................................................................................................. 298
SalCompileAndEvaluate ........................................................................................................................................... 298
SalContextBreak .......................................................................................................................................................... 299
SalContextCurrent ...................................................................................................................................................... 299
Tracing..................................................................................................................................................................................... 299
SalStartTrace................................................................................................................................................................. 300
SalTrace........................................................................................................................................................................... 300
SalEndTrace................................................................................................................................................................... 300
Event Logging ....................................................................................................................................................................... 300
Chapter 11 – Formatting and Validating.......................................................................................................... 301
Formatting ............................................................................................................................................................................. 301
Setting a Format .......................................................................................................................................................... 301
String and Long String Formats .................................................................................................................................... 301
Date/Time and Number Formats ................................................................................................................................. 302
Picture Formats ................................................................................................................................................................... 302
Creating a Custom Picture Format ....................................................................................................................... 303
Date/Time Picture Format Characters............................................................................................................... 303
Number Picture Format Characters .................................................................................................................... 303
Profile-Driven Formats ..................................................................................................................................................... 305
Country Profiles........................................................................................................................................................... 305
Default Country Profiles ........................................................................................................................................... 305
Country Profile Parameters .................................................................................................................................... 306
Validation ............................................................................................................................................................................... 306
Default Validation ............................................................................................................................................................... 307
Number Data Types ................................................................................................................................................... 307
Date/Time Data Types .............................................................................................................................................. 307
Custom Validation............................................................................................................................................................... 307
Input Masks ........................................................................................................................................................................... 308
Defining Input Masks ................................................................................................................................................ 308
Input Mask Characters .............................................................................................................................................. 309

18
Input Masks for Numbers ........................................................................................................................................ 309
Input Masks for Date/Times .................................................................................................................................. 310
Setting a Field’s Value ............................................................................................................................................... 310
Getting a Field’s Value ............................................................................................................................................... 310
Input Mask Functions................................................................................................................................................ 310
SAM_Validate Processing ......................................................................................................................................... 311
SalIsNull .......................................................................................................................................................................... 311
Chapter 12 – SQL Programming ......................................................................................................................... 312
Using SQL in a SQLWindows Application.................................................................................................................. 312
Requirements ....................................................................................................................................................................... 312
Database Access Cycle ...................................................................................................................................................... 313
Multistep Interface ............................................................................................................................................................. 314
Connecting and Disconnecting .............................................................................................................................. 314
Performing Database Operations ......................................................................................................................... 316
SELECTs (Queries)...................................................................................................................................................... 318
INSERTs, UPDATEs, and DELETEs ....................................................................................................................... 320
Other Operations......................................................................................................................................................... 321
Using Multiple Sql Handles and Database Connections .............................................................................. 321
Single-Step Interface ......................................................................................................................................................... 323
Long Strings .......................................................................................................................................................................... 324
SQL Error Handling ............................................................................................................................................................ 325
Default SQL Error Handling .................................................................................................................................... 325
Application-Defined SQL Error Handling ......................................................................................................... 326
Using both SQL Error Handling Methods.................................................................................................................. 326
SQL Error Handling Functions .............................................................................................................................. 328
Local Error Handling Example for an INSERT ................................................................................................ 328
Global Error Handling Example ............................................................................................................................ 330
ERROR.SQL .................................................................................................................................................................... 331
Transaction Scope .............................................................................................................................................................. 332
Multi-Connection Transactions..................................................................................................................................... 332
Getting and Setting Session Parameters............................................................................................................ 333
Table Windows .................................................................................................................................................................... 334
List Boxes and Combo Boxes .......................................................................................................................................... 334
Other Sql* Functions ......................................................................................................................................................... 335
Database Parameters ........................................................................................................................................................ 335
Functions for Database Parameters .................................................................................................................... 335

19
Getting and Setting Database Parameters ......................................................................................................... 336
DBP_* Parameters ....................................................................................................................................................... 336
System Variables ......................................................................................................................................................... 339
Input Message Buffer ................................................................................................................................................ 340
Output Message Buffer ............................................................................................................................................. 341
Isolation Levels ............................................................................................................................................................ 342
SQL.INI............................................................................................................................................................................. 343
Techniques for Multiuser Databases........................................................................................................................... 343
ROWID Validation ....................................................................................................................................................... 344
Stored Commands .............................................................................................................................................................. 346
Chained Commands ................................................................................................................................................... 347
Using Stored Commands with SalListPopulate and SalTblPopulate...................................................... 348
Setting the Execution Context........................................................................................................................................ 348
Character Conversion........................................................................................................................................................ 349
Named Cursors .................................................................................................................................................................... 350
Database Explorer .............................................................................................................................................................. 350
SQL Troubleshooting ......................................................................................................................................................... 350
Chapter 13 – OLE DB Consumer.......................................................................................................................... 352
SQLWindows as a Consumer .......................................................................................................................................... 352
Session Handle Data Type ............................................................................................................................................... 353
Connecting to a Data Source........................................................................................................................................... 353
Sql* Functions ...................................................................................................................................................................... 354
SqlCloseAllSPResultSets (hSql) ............................................................................................................................. 354
SqlCommitSession (hSession) ............................................................................................................................... 354
SqlCreateSession (hSession, strSessionProperties) ..................................................................................... 354
SqlCreateStatement (hSession, hSql).................................................................................................................. 354
SqlFreeSession (hSession) ...................................................................................................................................... 354
SqlGetCmdOrRowsetPtr (hSql, bCmdOrRowset, numOLEDBPtr) .......................................................... 355
SqlGetDSOrSessionPtr (hSql, bDSOrSession, numOLEDBPtr) ................................................................. 355
SqlGetNextSPResultSet (hSql, strIntoList, bEndOfRS) ................................................................................ 355
SqlGetSessionErrorInfo (hSession, numErrorNumber, strErrorDescription, strSqlState) .......... 355
SqlGetSessionHandle (hSql, hSession) ............................................................................................................... 355
SqlGetSessionParameter (hSession, numPropertyID, numValue, strValue) ........................................ 355
SqlGetStatementErrorInfo (hSql, numErrorNumber, strErrorDescription, strSqlState) .............. 355
SqlPrepareSP (hSql, strStoredProc, strIntoList) ............................................................................................ 356
SqlRollbackSession (hSession).............................................................................................................................. 356

20
SqlSetSessionParameter (hSession, numPropertyID, numValue, strValue) ....................................... 356
OLE DB Stored Procedures ............................................................................................................................................. 356
SAL Mapping to OLE DB Functions.............................................................................................................................. 357
Using SAL Datatypes with OLE DB Databases ........................................................................................................ 357
Using Isolation Levels with OLE DB ............................................................................................................................ 358
Using REF CURSOR with Oracle .................................................................................................................................... 358
Chapter 14 – Report Programming .................................................................................................................... 359
Report Builder...................................................................................................................................................................... 359
Design Time .......................................................................................................................................................................... 360
Report Template .......................................................................................................................................................... 360
Blocks............................................................................................................................................................................... 360
Input Items .................................................................................................................................................................... 361
Input Variables ............................................................................................................................................................. 361
Runtime .................................................................................................................................................................................. 361
SalReportPrint ..................................................................................................................................................................... 363
Error Handling ............................................................................................................................................................. 364
RPT_Err* Constants ................................................................................................................................................... 364
SalReportDlgOptions ................................................................................................................................................. 364
SalReportPrintToFile ......................................................................................................................................................... 367
SalReportView...................................................................................................................................................................... 367
SalReportCmd............................................................................................................................................................... 368
SalReportReset..................................................................................................................................................................... 370
SalReportClose ..................................................................................................................................................................... 371
SalReportCreate (Creating a Report Template)...................................................................................................... 372
Input Variables..................................................................................................................................................................... 372
SAM_ReportNotify .............................................................................................................................................................. 373
RPT_* Constants .......................................................................................................................................................... 373
Creating Reports from Table Windows...................................................................................................................... 374
SalReportTableCreate................................................................................................................................................ 374
SalReportTablePrint .................................................................................................................................................. 375
SalReportTableView .................................................................................................................................................. 375
Chapter 15 – Table Windows ............................................................................................................................... 378
Types of Table Windows .................................................................................................................................................. 379
Top-Level Table Windows ............................................................................................................................................... 379
Child Table Windows......................................................................................................................................................... 380
Table Window Columns ................................................................................................................................................... 382

21
Adding Columns .......................................................................................................................................................... 382
Moving and Sizing Columns.................................................................................................................................... 382
Column Attributes ...................................................................................................................................................... 382
User Interface ....................................................................................................................................................................... 384
Focus Frame .................................................................................................................................................................. 384
Programming Techniques ............................................................................................................................................... 386
Using the Simple Technique ................................................................................................................................... 387
Using the Advanced Technique ............................................................................................................................. 390
Context Row .......................................................................................................................................................................... 395
Populating a Table Window ............................................................................................................................................ 395
Populating with SalTblPopulate (Simple Technique) .................................................................................. 396
Populating with SalTblSetRange (Advanced Technique) ........................................................................... 397
SAM_FetchRow Message .......................................................................................................................................... 398
Using SAM_FetchRow and SAM_FetchRowDone with SalTblPopulate.................................................. 399
Using SalTblPopulate with Stored Commands ............................................................................................... 399
Dynamic Table Windows ................................................................................................................................................. 400
SalTblPopulate ............................................................................................................................................................. 400
SalTblCreateColumn and SalTblCreateColumnEx ......................................................................................... 400
SalTblDestroyColumns ............................................................................................................................................. 400
Referring to Automatic Columns .......................................................................................................................... 401
Messages......................................................................................................................................................................... 401
Sum, Average, and Sort Functions................................................................................................................................ 401
Table Range ........................................................................................................................................................................... 401
Static Table Range....................................................................................................................................................... 402
Dynamic Table Range ................................................................................................................................................ 402
SAM_CountRows Message ....................................................................................................................................... 402
Table Window Cache ......................................................................................................................................................... 403
When SQLWindows Fetches Rows into the Cache ........................................................................................ 404
When SQLWindows Discards Rows from the Cache..................................................................................... 404
SAM_CacheFull Message .......................................................................................................................................... 404
Table Window Flags........................................................................................................................................................... 405
Row Flags ............................................................................................................................................................................... 405
Column Flags ........................................................................................................................................................................ 406
TBL_Error Constant ........................................................................................................................................................... 407
TBL_* Constants .................................................................................................................................................................. 407
Table Window Messages .................................................................................................................................................. 407

22
Window Handles and Message Parameters ..................................................................................................... 407
Messages Sent Only to Table Windows .............................................................................................................. 408
Extended GUI Functions................................................................................................................................................... 410
Setting the Focus Row ....................................................................................................................................................... 410
Focus Cell ............................................................................................................................................................................... 410
Deselecting All Rows ......................................................................................................................................................... 410
Finding the Visible Range ................................................................................................................................................ 411
Scroll Position....................................................................................................................................................................... 411
Table Window Title ............................................................................................................................................................ 411
Table Window Font ............................................................................................................................................................ 411
Table Window Color .......................................................................................................................................................... 411
Column Title.......................................................................................................................................................................... 412
Column Width ...................................................................................................................................................................... 412
Column Identifier and Column Position .................................................................................................................... 412
Referring to Table Window Columns by Identifier ....................................................................................... 413
Locking Columns ................................................................................................................................................................. 413
Row Header ........................................................................................................................................................................... 413
Row Header Messages .............................................................................................................................................. 414
Split Windows ...................................................................................................................................................................... 415
Using the Clipboard with Table Windows ................................................................................................................ 416
Using Database Result Sets with Table Windows .................................................................................................. 416
TBL_Adjust and TBL_NoAdjust Constants ........................................................................................................ 416
TBL_TempRow Constant .......................................................................................................................................... 416
Checking and Setting a Cell's Field Edit Flag ........................................................................................................... 417
Processing WM_* Cell Editing Messages ................................................................................................................... 417
XML Support ......................................................................................................................................................................... 417
Writing to XML ............................................................................................................................................................. 417
Reading from XML ...................................................................................................................................................... 418
SAL and XML Datatypes ........................................................................................................................................... 418
Chapter 16 – Pictures ............................................................................................................................................. 419
Picture Attributes ............................................................................................................................................................... 419
Sources of Pictures at Design Time ............................................................................................................................. 420
Using 256-Color Bitmaps................................................................................................................................................. 420
Picture Messages................................................................................................................................................................. 421
Using SAM_Click and SAM_DoubleClick with Pictures ................................................................................ 421
Picture Functions ................................................................................................................................................................ 421

23
Cutting, Copying, Pasting, and Clearing ............................................................................................................. 422
Storing and Retrieving Picture Images .............................................................................................................. 422
Sources and Destinations for Pictures at Runtime................................................................................................ 424
Storing Pictures in a Database....................................................................................................................................... 424
Inserting Pictures........................................................................................................................................................ 424
Retrieving Pictures ..................................................................................................................................................... 425
Updating Pictures ....................................................................................................................................................... 425
Other SAL Picture Functions ........................................................................................................................................... 425
SalPicGetDescription ................................................................................................................................................. 425
SalPicSet.......................................................................................................................................................................... 426
SalPicSetFit .................................................................................................................................................................... 426
SalQueryFieldEdit ....................................................................................................................................................... 426
SalSetFieldEdit ............................................................................................................................................................. 426
SalPicClear ..................................................................................................................................................................... 426
Chapter 17 – Drag-and-Drop................................................................................................................................ 427
Source and Target Windows .......................................................................................................................................... 427
Drag Mode Events ............................................................................................................................................................... 428
Auto Dragging....................................................................................................................................................................... 428
Application-Initiated Dragging ..................................................................................................................................... 428
Enabling and Disabling Dropping ................................................................................................................................ 428
Application-Defined Cursors.......................................................................................................................................... 428
Functions ................................................................................................................................................................................ 429
Source Window Messages ............................................................................................................................................... 430
Target Window Messages ................................................................................................................................................ 430
Auto-Dragging Example ................................................................................................................................................... 431
Application-Initiated Dragging Example................................................................................................................... 432
Dropping from Explorer................................................................................................................................................... 433
File Dropping Functions ........................................................................................................................................... 433
SAM_DropFiles Message .......................................................................................................................................... 434
Chapter 18 – Libraries ........................................................................................................................................... 435
Include Libraries ................................................................................................................................................................. 435
Tools, Preferences ....................................................................................................................................................... 437
Dynamically Linked Libraries (Dynalibs) ................................................................................................................. 438
How to Write Dynalibs.............................................................................................................................................. 439
Using Non-Exportable Items in Dynalibs .......................................................................................................... 441
Compiling a Dynalib................................................................................................................................................... 441

24
Using Imported Items ............................................................................................................................................... 442
Chapter 19 – Handling XML .................................................................................................................................. 445
XML Overview ...................................................................................................................................................................... 445
Basic Techniques ................................................................................................................................................................. 445
Avoiding Problems when Using XML Objects.................................................................................................. 446
Using Casting ................................................................................................................................................................ 447
Chapter 20 – Introduction to COM and Writing COM Client Applications ........................................... 448
COM Concepts ...................................................................................................................................................................... 448
Component Software ................................................................................................................................................. 448
COM .................................................................................................................................................................................. 448
Interfaces........................................................................................................................................................................ 449
GUIDs ............................................................................................................................................................................... 449
Type Information ........................................................................................................................................................ 449
Proxies and Stubs........................................................................................................................................................ 450
SQLWindows COM Client Applications .............................................................................................................. 450
SQLWindows COM Server Applications ............................................................................................................. 451
COM Entities and the Outline ................................................................................................................................. 451
Getting Started with COM Client Applications ........................................................................................................ 451
Creating a COM Component ........................................................................................................................................... 452
Using the Controls Palette ....................................................................................................................................... 452
Using ActiveX Explorer ............................................................................................................................................. 454
COM Client Class Outline Structure ............................................................................................................................. 459
Using Microsoft Office Components ............................................................................................................................ 461
Learning the Object Hierarchy .............................................................................................................................. 461
MSDN Documentation .............................................................................................................................................. 461
Installing Online Help ............................................................................................................................................... 462
Controls................................................................................................................................................................................... 467
Container Controls (Insertable Objects) ................................................................................................................... 467
Embedded Objects ...................................................................................................................................................... 467
Creating Embedded Objects ................................................................................................................................... 467
SalActiveX Functions ................................................................................................................................................. 468
Automation............................................................................................................................................................................ 469
Static Automation ....................................................................................................................................................... 469
Dynamic Automation................................................................................................................................................. 470
Creating Objects at Runtime ................................................................................................................................... 471
Handling Events .................................................................................................................................................................. 472

25
Properties .............................................................................................................................................................................. 473
Ambient Properties .................................................................................................................................................... 473
In-Place Activation ............................................................................................................................................................. 474
Toolbar and Menu Merging ..................................................................................................................................... 474
Menu Groups................................................................................................................................................................. 474
Collections ............................................................................................................................................................................. 475
Handling Exceptions .......................................................................................................................................................... 475
Custom Error Handling ............................................................................................................................................ 475
Include Libraries ................................................................................................................................................................. 476
Regenerating Include Libraries ............................................................................................................................. 477
Licensing ................................................................................................................................................................................ 477
Object Class ........................................................................................................................................................................... 477
COM Proxy Class.................................................................................................................................................................. 478
Variant Class ......................................................................................................................................................................... 478
Methods .......................................................................................................................................................................... 478
Data Type Mappings .................................................................................................................................................. 479
SafeArray Class .................................................................................................................................................................... 480
COM Client Font and Picture Classes .......................................................................................................................... 481
Chapter 21 – Writing COM Servers .................................................................................................................... 482
Overview ................................................................................................................................................................................ 482
COM Class Wizard ............................................................................................................................................................... 483
Outline ..................................................................................................................................................................................... 491
Local Servers, In-Process Servers, and MTS Servers............................................................................................ 492
Passing Objects Outside the Server ............................................................................................................................. 493
Automation Types .............................................................................................................................................................. 493
Setting the Automation Type for Numbers ...................................................................................................... 493
Defining and Firing Events.............................................................................................................................................. 494
Collections ............................................................................................................................................................................. 494
Enumerations ....................................................................................................................................................................... 495
Setting the Automation Type to an Enum Name ............................................................................................ 497
Dynamic Instantiation ...................................................................................................................................................... 497
Assigning COM CoClass Variables ................................................................................................................................ 497
Setting CoClass Variables to Null .......................................................................................................................... 498
Checking for Null Objects ........................................................................................................................................ 498
Reference Counting ............................................................................................................................................................ 498
Setting Error Information ............................................................................................................................................... 498

26
Interface Inheritance ......................................................................................................................................................... 499
Interface Inheritance Use in Visual Basic.......................................................................................................... 499
Debugging COM Servers................................................................................................................................................... 500
Type Information ................................................................................................................................................................ 501
Registering Servers ............................................................................................................................................................ 501
Registering and Unregistering during Development ................................................................................... 501
Regenerating GUIDs ........................................................................................................................................................... 501
Internal Implementation ................................................................................................................................................. 502
Threading Support ............................................................................................................................................................. 502
Introduction to Threads ........................................................................................................................................... 502
Apartment Model Threading.................................................................................................................................. 503
“None” or Main Single Threaded Apartment (STA) ...................................................................................... 503
Multiple STA .................................................................................................................................................................. 503
COM Client and Server Apartments..................................................................................................................... 503
SQLWindows Support for Threads ...................................................................................................................... 505
Build Settings................................................................................................................................................................ 505
Outlines, Apartments, and the Runtime Environment ................................................................................ 505
MTS (Microsoft Transaction Server) Support ......................................................................................................... 506
What is MTS? ................................................................................................................................................................ 506
MTS Architecture ........................................................................................................................................................ 507
Issues in Writing MTS Components .................................................................................................................... 508
IObjectContext.............................................................................................................................................................. 508
IObjectControl .............................................................................................................................................................. 509
Shared Properties Classes ....................................................................................................................................... 510
Sample Applications .................................................................................................................................................. 510
Chapter 22 – Calling External Functions in Dynamic Link Libraries .................................................... 519
When to Use DLLs............................................................................................................................................................... 519
Dynamic Linking ......................................................................................................................................................... 519
Example Application and DLL ....................................................................................................................................... 520
External Function Outline Sections ............................................................................................................................. 521
Identifying a Function ............................................................................................................................................... 521
Parameter and Return Data Types .............................................................................................................................. 522
Setting the External Data Type .............................................................................................................................. 522
Pass By Value and Pass By Reference ................................................................................................................. 523
External DLLs with HSTRINGs and UDVs ................................................................................................................. 523
Programmer Cautions ............................................................................................................................................... 524

27
Using SAL External Data Types ..................................................................................................................................... 524
External Data Type Quick Reference .................................................................................................................. 524
SAL Number Internal Data Type ........................................................................................................................... 525
SAL Date/Time Internal Data Type ..................................................................................................................... 527
SAL String Internal Data Type ............................................................................................................................... 527
LPSTR............................................................................................................................................................................... 528
LPVOID ............................................................................................................................................................................ 530
HSTRING and LPHSTRING ...................................................................................................................................... 530
HARRAY External Data Type .................................................................................................................................. 533
Other External Data Types ...................................................................................................................................... 536
Using C Structures (structPointer External Data Type) .............................................................................. 537
Calling External Functions .............................................................................................................................................. 540
Writing a DLL ....................................................................................................................................................................... 540
Module Definition File (*.DEF) .............................................................................................................................. 541
Make File (*.MAK)....................................................................................................................................................... 542
Using CDLLI*.DLL ....................................................................................................................................................... 543
Creating an Import Library ..................................................................................................................................... 543
DLLs and the Stack Segment .................................................................................................................................. 544
Using Visual Studio with DLLs............................................................................................................................... 544
Passing UDVs to External Functions ................................................................................................................... 545
Using strci*.dll ...................................................................................................................................................................... 547
Example Files................................................................................................................................................................ 548
Extracting Elements from a C Structure ............................................................................................................ 548
Get Functions ................................................................................................................................................................ 549
Inserting Elements into a C Structure ................................................................................................................ 550
Put Functions ................................................................................................................................................................ 550
Using Global Memory ................................................................................................................................................ 552
Copying Buffers ........................................................................................................................................................... 553
Chapter 23 – Team Developer Win32 API Migration .................................................................................. 554
Migration Process ............................................................................................................................................................... 554
Working with Menus ................................................................................................................................................. 554
Window Handle of Accessory Frame Window ............................................................................................... 555
Use Unicode Version of Win32 API function ................................................................................................... 555
Fix Win32 API Function Declaration.................................................................................................................... 556
Using a String as a Buffer for Binary Data ........................................................................................................ 556
Getting Parent Window Handle Using the Win32 API................................................................................. 556

28
Custom Control “Current DLL” Property ........................................................................................................... 556
Chapter 24 – Custom Controls ............................................................................................................................. 557
Adding a Custom Control to a Window...................................................................................................................... 557
Message Actions .................................................................................................................................................................. 558
SAM_CustControlCmd ............................................................................................................................................... 558
Other Messages ............................................................................................................................................................ 558
Using Classes and Libraries ............................................................................................................................................ 558
Creating Custom Control Classes ........................................................................................................................... 559
Attributes ............................................................................................................................................................................... 559
Example .................................................................................................................................................................................. 560
Include File .................................................................................................................................................................... 560
Window Procedure ..................................................................................................................................................... 561
SQLWindows Application ......................................................................................................................................... 562
Writing a SQLWindows-Aware Custom Control ..................................................................................................... 565
Registering a Window Class ................................................................................................................................... 565
Window Styles.............................................................................................................................................................. 565
Colors ............................................................................................................................................................................... 566
Fonts ................................................................................................................................................................................. 566
Interface .......................................................................................................................................................................... 566
Design Time Behavior ............................................................................................................................................... 567
Validation ............................................................................................................................................................................... 569
Editable Custom Controls ........................................................................................................................................ 570
Non-editable Custom Controls .............................................................................................................................. 570
Calling SalValidateSet in a DLL .............................................................................................................................. 571
Chapter 25 – Symbol Scoping and Qualified References ........................................................................... 572
Symbol Scoping.................................................................................................................................................................... 572
External References ................................................................................................................................................... 572
Examples of External References ......................................................................................................................... 573
Symbol Resolution Steps.......................................................................................................................................... 573
Program Element Nesting ....................................................................................................................................... 574
Scope of Global Symbols .......................................................................................................................................... 575
Names of Templates and MDI Windows ............................................................................................................ 575
Early-Bound and Late-Bound References ......................................................................................................... 575
Unqualified References .................................................................................................................................................... 575
Late-Bound Unqualified References ................................................................................................................... 576
Qualified References .......................................................................................................................................................... 576

29
Object-Qualified Reference ..................................................................................................................................... 577
Fully Object-Qualified Reference .......................................................................................................................... 578
Handle-Qualified Reference.................................................................................................................................... 579
Class-Qualified Reference ........................................................................................................................................ 580
Fully Class-Qualified Reference............................................................................................................................. 581
Design Time Settings ......................................................................................................................................................... 581
Fully Qualified External References .................................................................................................................... 582
Reject Multiple Window Instances ...................................................................................................................... 582
Enable Runtime Checks of External References............................................................................................... 582
Advanced References ........................................................................................................................................................ 583
Nested Objects.............................................................................................................................................................. 583
Child Window Handles .............................................................................................................................................. 583
Non-Simple Window Handle Qualifiers............................................................................................................. 584
Chapter 26 – Constructors and Destructors in Team Developer 6.3 ..................................................... 585
Adding a Constructor ........................................................................................................................................................ 585
Classes that Support Constructors ...................................................................................................................... 586
Default vs. Parameterized Constructors ............................................................................................................ 586
When Constructors Run ........................................................................................................................................... 586
Default Constructors and Inheritance ................................................................................................................ 587
Parameterized Constructors .................................................................................................................................. 588
Overloading Constructors ....................................................................................................................................... 589
Parameterized Constructors and Inheritance................................................................................................. 589
Windows Classes and Constructors .................................................................................................................... 590
Destructors ............................................................................................................................................................................ 590
When a Destructor is Called ................................................................................................................................... 590
Legacy: ObjectDestructor ........................................................................................................................................ 590
Cautions .......................................................................................................................................................................... 590
Chapter 27 – Threading in Team Developer 7.1 ........................................................................................... 592
Adding a Background Worker Class ............................................................................................................................ 592
Adding a Worker Instance to a Window.................................................................................................................... 592
Thread Events .............................................................................................................................................................. 593
SAL Threading API ............................................................................................................................................................. 593
Glossary ....................................................................................................................................................................... 594

30
Preface

Purpose and Scope of this Manual


This manual provides information a developer needs to write applications with SQLWindows.
This manual covers core SQLWindows technical topics. SQLWindows has many extensions that are
documented in other manuals and the online help.

Audience Requirements
This manual assumes you have experience with:
• Microsoft Windows user interface and applications
• A programming language such as COBOL, C, or Basic
• SQL (Structured Query Language) and relational databases
• LANs (Local Area Networks)
• The C programming language and related development tools if want to use DLLs (Dynamic Link Libraries)

Summary of Chapters
Chapter Title Contents

1 About SQLWindows Design-time environment and runtime environment; objects, messages,


and events
2 SQLWindows Desktop Main window, Controls palette, Attribute Inspector, Coding Assistant,
application outline
3 Deploying and Migrating Installing production applications, SQLWindows runtime, migrating to
Applications 32-bit
4 SQLWindows Menus Menu items in the main window

5 SQLWindows Objects Objects that you can add to an application, and their Attribute
Inspector properties
6 Application Menus Popup menus, menu items, named menus, creating menus
dynamically, menu status text
7 SAL (Scalable Application Data types, variables, arrays, constants, operators, expressions,
Language) statements, functions
8 Object-Oriented Classes, inheritance, objects, defining classes, creating objects, message
Programming actions, instance variables, class variables, class functions

31
Chapter Title Contents

9 Messages Types of messages, processing messages, an explanation of each


SAM_* message
10 Debugging Animation, breakpoints, debugging windows, writing custom
debugging code
11 Formatting and Validating Picture formats, profile-driven formats, country profiles, default
validation, custom validation, input masks
12 SQL Programming Database access cycles, error handling, database parameters, multiuser
techniques
13 OLE DB Consumer When to use, Session Handle data type, functions, stored procedures,
SAL/OLE DB mapping
14 Report Programming Writing reporting application for templates created by Report Builder

15 Table Windows Types of table windows, user interface, simple and advanced
programming techniques, table window features, messages
16 Pictures Picture properties, messages, and functions

17 Drag-and-Drop Functions and messages you use to write a drag-and-drop interface in


an application
18 Libraries Creating and using libraries to share common code

19 Overview of COM and Introduction to COM, the Controls palette and ActiveX Explorer,
Writing COM Client outline, events, controls and containers, automation, properties,
Applications exceptions, and include libraries
20 Writing COM Server COM Class Wizard, outline, automation types, events, enumerations,
Applications instantiation and assignment, debugging, type information,
registration, threading and MTS
21 Calling External Functions Using external functions and DLLs, writing a DLL, using SWIN*.DLL
in DLLs
22 Custom Controls Using custom controls in applications

23 Symbol Scoping and SQLWindows's symbol resolution rules, qualifying symbol names in
Qualified References references

Notation Conventions
The following conventions are used in this manual:

Notation Explanation

You A developer who reads this manual

User The end-user of the applications you write

32
Notation Explanation

Courier type Code example

REPBI*.EXE Program names where the asterisk represents the version number. For example, the
program name for Report Builder 1.5 is REPBI15.EXE.
Precaution Warning

Vital information Important

Supplemental Note
information
+ A plus sign between key names means to press and hold down the first key while you
press the second key.
TRUE FALSE The following are numeric boolean constants defined internally in SQLWindows:
Constant Value Meaning
TRUE non-zero Successful, on, set
FALSE zero Unsuccessful, off, clear

33
Chapter 1 – SQLWindows

This chapter introduces SQLWindows, including the design time environment, the runtime environment,
objects, messages, and events.

Team Developer
Team Developer is a 32-bit development environment that enables you to create robust, scalable, and
Internet-enabled applications that provide the intelligence to create and integrate with the systems that run
your business. Use the powerful programming capabilities of GUPTA's productive object-oriented SAL
language to integrate ActiveX components, add intelligence to your relational database, and build
applications that can be deployed on the Web. TD also includes enterprise development tools such as:
• Team Object Manager for source code control and workflow management
• Object Nationalizer for localization of executables
• The CDK (Component Developer’s Extension Kit) for customizing the GUPTA development environment
with your own wizards and productivity tools

SQLWindows
SQLWindows is an application development system that developers (programmers) use to create applications
that run on Microsoft Windows.
An application that you create in SQLWindows has scroll bars, menus, and dialog boxes, and other objects
associated with a graphical user interface (GUI).
To write a SQLWindows application, you draw screen objects in a design window. As you draw, SQLWindows
generates predefined code definitions. You define behaviors in the outline with SAL (SQLWindows Application
Language) and SAM (SQLWindows Application Messages).

The following is a SQLWindows form window application:

34
The following is a SQLWindows table window application:

SQLWindows Environments
SQLWindows has two environments:
• Design time environment
At design time, you first create the user interface. SQLWindows automatically adds definitions in the
application outline for each object that you create.
Next, you code the logic in the outline. The context-sensitive Coding Assistant help you by showing the
items appropriate for where you are in the outline.
Finally, you test and debug an application using the animate and breakpoint features. Animate highlights
each line of code in the outline it executes. Breakpoints let you suspend execution while you examine and
set variables.
• Runtime environment
After you develop an application, you make an executable version of the application. To put an
application into production, you install the application and the SQLWindows Runtime product on the
users’ computer.

35
Objects, Messages, and Events
This section describes the SQLWindows programming model. In SQLWindows, a window is a visual object that
receives and processes messages.
SQLWindows applications are driven by events. Events cause messages. For example, when the user clicks a
push button with the mouse, SQLWindows sends a message to the application.
Events can cause many messages to be sent, but only some of those messages are relevant to an object. You
program objects to perform actions based on the messages they receive (see Chapter 9 – Messages).
In the following example, the user places the cursor on the push button and clicks the mouse button to
activate the push button. When the user clicks the push button, SQLWindows sends a SAM_Click message to
the push button. SQLWindows then executes the code associated with the SAM_Click message.

36
Chapter 2 – SQLWindows Desktop
This chapter explains the SQLWindows user interface.

SQLWindows User Interface


When you start SQLWindows, it displays an MDI frame with a single MDI child that is (usually) maximized
within the frame. This MDI child,called an application view, represents an application written in SQLWindows
Application Language, or SAL.

The left pane of the application view is called the tree view and the right pane is called the tab view.
The tree view displays a hierarchy of the application, while the tab view displays details about the item
selected in the tree. You add and edit objects and actions in the tree view and the tab views. The tree view
contains objects that represent parts of your application. The tabs on the right provide multiple views of your
application. These views include a graphical layout of your application’s interface, as well as an outline of its
underlying code or parts of the code, such as variables and libraries.
You can change the width of the tree view by putting the mouse pointer on the bar separating the left from
the right side of the window. When the mouse pointer changes to a double-headed horizontal arrow, you can
click-drag left or right.
You can also click the Window toolbar buttons to:
• View only the tree view
• View only the tab view
• View both views
37
You can open additional application views for the same application. In the tree view, select an item, click the
right mouse button, and then select Open View. An additional application view opens with the tab view
maximized. When you have more than one application view, you can navigate between them using the
Windows menu.
To write a SQLWindows application, you can add screen objects in a Layout tab or in a preview window.
SQLWindows has a Controls palette that lets you select and create objects directly in top-level windows in
your application. You use the Attribute Inspector to set the properties of objects. With SQLWindows’ Coding
Assistant, you can continue to build and refine your application, defining functions, constants, and variables in
SAL statements, and even create more objects if needed. The Controls palette, the Attribute Inspector, and
the Coding Assistant are explained in this chapter.

Tree View
The tree on the left side of the explorer window contains objects that represent a hierarchical view of the
application. You use the explorer tree to navigate through an application:
• Click a plus sign (+) to expand an item, revealing its contents.
• Click a minus sign (-) to collapse an item, hiding its contents.
• Click an icon or its name to display the contents of the item in the tab view.

Tab View
A tab view can display different views of the item selected in the tree view. Each type of item that is displayed
in the tree view has an associated set of tabs that appear at the bottom right. To select a view for the item,
you click a specific tab. For example, if you select a form window in the tree view and then click the Layout
tab, you see a graphical layout of your form window. If you select this same item, but click the Outline tab,
you see a code outline of the form window. For details on the views, see Tab Views on page 41.

Status Bar
SQLWindows has a status bar at the bottom that shows the setting of the Num Lock, Scroll Lock, and Caps
Lock keys. The status bar also displays a message that shows the currently selected item on the menu or tool
bar and the currently selected outline item.

Turn on the status bar by right-clicking a blank section of a toolbar and selecting Status Bar from the menu.
Turn off the status bar by either right-clicking the status bar and selecting Status Bar from the menu or by
right-clicking a blank section of a toolbar and selecting Status Bar.

Toolbars
SQLWindows has toolbars that let you quickly select often-used menu commands.
You control which toolbars are displayed by selecting Tools > Toolbars. (See Toolbars Tab on page 93). Also,
you can right-click a blank area of a toolbar and select a toolbar from the context menu.

38
If you hold the mouse pointer over any of the toolbar buttons for a second or two, a small popup window (a
“tool tip”) displays the button’s function.

Custom Toolbars
You can add your own programs to the Tools menu and toolbar and create custom toolbars (see Tools Tab on
page 94).

Docking Toolbars, Palettes, and the Menu Bar


Toolbars can float above the main frame or dock at its edges. Toolbars have a horizontal or vertical
orientation. For example, when you drag a vertical floating toolbar to the top edge, its orientation changes.
The same is true when you drag a horizontal toolbar to a side edge.
In addition, SQLWindows has several palettes that can float above the main frame or dock at the left or right
edge. The Coding Assistant, the Controls palette, Attribute Inspector, debug windows, and the compiler error
message window can all be docked alongside the toolbars.
You can undock the menu bar and perform the same types of operations that you can with a toolbar or
palette.
You can put multiple toolbars and palettes on an edge. The toolbars and palettes can be side-by-side or in
rows. You move toolbars and palettes in an edge by click-dragging.
SQLWindows remembers which toolbars and palettes you used last, including their position. A toolbar or
palette appears in the same location, with the same properties, each time you display the toolbar until you
change its properties manually.
To dock a toolbar, palette, or menu bar:
• Click its window border or title bar, hold down the left mouse button, and drag it to an edge of the
window. To prevent the toolbar from docking accidentally, hold down Ctrl when you drag.
OR
• Double-click its window border or title bar.
For a palette, “window border” means just below or above an active button or on the left or right edge.
To undock a toolbar, palette, or menu bar:
• Click its handle (double bar), hold down the left mouse button, and drag.
39
When a toolbar, palette, or the menu bar is horizontally oriented, the handle is on the left. When a
toolbar, palette, or the menu bar is vertically oriented, the handle is at the top.
OR
• Click its window border, hold down the left mouse button, and drag.
OR
• Double-click its window border.
OR
• Hold down Ctrl and click its handle or window border
When palettes are docked, they have a maximize/restore button and a close button.

Resizing Toolbars, Palettes, and the Menu Bar


You can use the resize cursors to change the shape of an undocked toolbar, palette, or menu bar.

40
Tab Views
When you select a tree view item, you see an associated set of right tabs. Each tab provides a different view
of the selected item. The following tabs are provided for each view:
• Actions
• Base classes
• Class variables
• Components
• Constants
• Description
• Layout
• Libraries
• Outline
• Parameters
• Returns
• Static variables
• Variables

Actions Tab
The Actions tab displays all statements in a function or message actions section. You can code any SAL
statements in this section.

Base Classes Tab


The Base Classes tab displays the names of classes from which the selected class is derived.

Class Variables Tab


The Class Variables tab displays class variable declarations of the selected class.

Components Tab
The Components tab lists the major parts of the item selected in the tree view.
You can change the display style of an item in a Components tab. Select Component, View to choose a list
view option (large icons, small icons, list, and details). Each of the display styles is available for all items in the
tree view that have children.

Constants Tab
The Constants tab displays constants declarations in the Global Declarations block of the outline.

41
Description Tab
In a Description tab you can enter text that describes the purpose of the selected item.

Layout Tab
When you select the Layout tab, SQLWindows displays the selected top-level window in a graphical view. You
can change the size of the window, and move and resize any of its child windows.

To create a child window, select a child window type from the Controls palette. When you move the mouse
over the window in the Layout tab the cursor matches the child window type selected in the Controls palette.
Click the mouse at the point in the window where you want to place the child window. If you release the
mouse, the child window is created at its default size. If you drag out a rectangle before releasing the mouse
button, that rectangle is used as the size of the new child window.
When the arrow cursor is selected in the toolbar, you can select, move, and resize the child windows. To
duplicate the currently selected child window, press Ctrl while dragging the child window.
While you are in a Layout tab, the menu of the top-level window is not visible. To see the window as it will
appear to a user, select Layout > Preview Window.
You can also draw child objects graphically using the Controls palette in a Preview window (see Preview
Window on page 86).

42
The difference between the Layout tab and a Preview window is that in a Preview window you can:
• See menus
• See MDI children
• Set the runtime position of a window

Libraries Tab
The Libraries tab displays files and dynalibs that are in the outline. An include library is a collection of
SQLWindows objects such as form windows, dialog boxes, or class definitions that are shared by more than
one application. A dynalib is a compiled SQLWindows module with functions and objects that other
applications can dynamically load at runtime. (See Chapter 18 – Libraries.)

Outline Tab
SQLWindows represents the entire application in the outline. Each line in the outline is called an item. To see
the entire outline, click the highest-level item in the explorer tree and then click the Outline tab on the right.
For other items, the Outline tab presents that part of the outline that corresponds to the selected item.
An item can be a parent item or child item. Outline items can be nested. Therefore, some items can also be
both child and parent items. A parent item has a solid diamond that signifies that subordinate child items are
indented below it. If you double-click, the items expands and the child items appear. Double-click again to
collapse the item and hide the child items. An item with a hollow diamond does not have child items. You can
also select items in the Component menu to expand and collapse the selected item or items in an Outline
view. (See Component Menu on page 85.)

43
Common outline sections
There are standard sections within every outline. The outline contains four items that are permanent and
cannot be deleted:
• Application Description. This is the top-most item in the outline where you enter a description of the
application.
• Design time Settings. SQLWindows maintains information for its own use in this section.
• Libraries. You specify include libraries in this section (see Chapter 18 – Libraries).
• Global Declarations. This section defines default window settings, formats, internal and external
functions, variables, constants, and application actions:

Name Description

Window Defaults The default font, color, display style, font, text color, and background color for each
object. You can change the default values so that each time you add a particular
object, it has the properties specified in this section.
Formats Input masks and output formats for number and date/time values. You can change
the definitions and add new formats. See Chapter 11 – Formatting and Validating.
External Functions DLLs (Dynamic Link Libraries) that contain functions that the application calls. See
Chapter 22 – Calling External Functions in Dynamic Link Libraries.
Constants Global system constants (such as WM_* Messages) and global user constants. See
Chapter 7 – SAL (SQLWindows Application Language).
Resources The names of bitmap, cursor, and icon resource files that you use in the application.
See Chapter 7 – SAL (SQLWindows Application Language).
Variables Global variables. See Chapter 7 – SAL (SQLWindows Application Language).

Internal Functions Global functions that you write. See Chapter 7 – SAL (SQLWindows Application
Language).
Named Menus Popup menus that windows in the application share. See Chapter 6 – Application
Menus.
44
Name Description

Class Definitions Templates for classes. See Chapter 8 – Object-Oriented Programming.

Application Actions Statements to perform when the application receives messages. See Chapter 9 –
Messages.

Commented items and tasks


To insert text that will be ignored by the compiler, begin the line with an exclamation point. Use this feature
to add comments and notes that will make the code easier to understand. You can also use this feature to
“comment out” code that you would like to omit from the application without deleting the code permanently.
Starting in version 6.0, you can also right click on an item in the application outline and select "Insert Task."
This feature allows you to add commented tasks or notes that automatically include a date/time stamp.

Parameters Tab
The Parameters tab displays the outline for a Parameters block that belongs to several item types in the
application such as functions, top-level windows, and some message actions sections.

Returns Tab
The Returns tab displays the return value for functions.

Static Variables Tab


The Static Variables tab displays the static variables for functions. Static variables have values that persist
between calls to a function.

Variables Tab
The Variables tab displays the Variables block of the application or the selected top- level window, class,
class function, or internal function.

Cursors

In the left or right pane, use the left-pointing arrow to select, collapse, and expand items.

On the left side of an Outline tab, use the right-pointing arrow to select, collapse, and expand
outline items.

On an editable item on the right side of an Outline tab, use the I-beam to select and edit text.

45
Right Mouse Button Features
The right mouse button is used on a selected item to quickly perform several operations. When you press the
right mouse button, SQLWindows displays a context-sensitive menu with items that are appropriate to the
selected item. Some of the items are explained next.
You can also press Shift+F10 to display the right mouse button menus for the selected item.

Explore
Displays a submenu with selections for the tabs on the right side of the explorer window. This is a quick way
to switch tabs.

Open View
Opens the selected item in a new MDI child window. The tab view is maximized, but you can use the splitter
to restore the tree view on the left. By using multiple windows, you can maintain different contexts in each
application view. You can access the application views from the Window menu.

New
Displays a submenu with items for each of the item types you can create as a child of the selected item. For
example, when the top-most item is selected in the explorer tree, New displays a submenu with one item for
each top-level window type.

When an item is selected in an Outline tab, the right mouse button menu can have Add Same Level and Add
Next Level selections like the Coding Assistant.

46
You can also use New as follows:

Item Selected in Tree View New Submenu

Windows Top-level window types

External Functions Library Name

Popup Menus Menu, Windows Menu

Internal Functions Function

Quick Info, List Members, Parameter Info, Match Brace

These four menu items are part of the Active Coding Assistant. They are present in the right-click context
menu when you are working in the Outline tab and have the cursor located within a line of code. The
behavior of each of the items is detailed in Active Coding Assistant on page 52.

Cut, Copy, Paste


Perform Clipboard operations.

47
Delete, Rename
Deletes or renames the selected item. (Rename is only displayed in the tree and component views.)

Properties
When the top-level item in the tree view is selected, displays a tabbed dialog that displays application
statistics and lets you change runtime settings.

Select in Layout
When a window item is selected, switches to the Layout tab. If a child window is selected, it will be selected
within the top-level window in the Layout tab.

Other Right Mouse Button Menus


Selected Item Right Mouse Button Menu Items

Included library item Library Item Info, Go To Library Item

ActiveX control Control Properties

Derived class definition Open Base Class, Derive From

Object derived from a class Open Base Class

Outline tab (with item selected) Comment, Uncomment

Outline tab (no item selected) Undo, Cut, Copy, Paste, Select All

Objects in Layout and Preview windows Align Left, Align Top, Align to Grid

Layout windows and window items Preview Window

Toolbar, Coding Assistant, debugging Tools menu items


Windows, compiler error pane
Right tabs Tabs

Editing Object Attributes


All GUPTA objects that have a visible presentation at runtime (top-level windows and child windows) have
attributes that define their appearance in the Layout tab and in preview mode. You can change some
attributes, such as position and size settings, by directly manipulating the object in a layout window. However,
to change other attributes, such as color and font settings, you must use the Attribute Inspector. In addition,
some objects such as QuickObjects and ActiveX controls can have a dialog you use to edit their properties.

48
Changes to an object’s attributes that are made through a layout window or through the Attribute Inspector
override the default attribute values for the objects of that type. Most default values for window objects are
built into GUPTA, but some of the default values are defined in the Windows Default block of the application’s
Global Declarations section. Changes made to the window defaults in the outline are applied to all windows
in that application. You can override window default settings for a particular window in the application.
You can also create custom templates so that each new application you create conforms to the default colors
and fonts you choose (see New on page 63).

Attribute Inspector
You use the Attribute Inspector to set the properties for an object, such as how the object looks, where it
appears, and other characteristics.

The Attribute Inspector uses the following types of child controls to show a property's value:
• Data field
• Drop-down combo box with a value you can edit
• Drop-down list with a value you can select but not edit (such as a Yes/No selection)
• A push button with an ellipsis that displays a dialog (such as for selecting a font or color)
To display the Attribute Inspector:
• Select Tools > Attribute Inspector
OR
• Click the Attribute Inspector toolbar button
OR
• Press Alt+3
You cannot display the Attribute Inspector while in run mode.
If another palette overlaps this palette, you must click in an editable area to bring it to the top.
The Attribute Inspector is a palette that can be docked (see Docking Toolbars, Palettes, and the Menu Bar on
page 39).
49
When using the Attribute Inspector to edit properties:
• Double-clicking an object displays a context menu, but it does not have a Properties menu item
• The application's context menu has a Properties menu item at all times

Multiple Object Select


Multiple objects can be selected in the outline or in the form layout by using ctrl-click (shift-click to deselect
any single item). Multiple objects can also be selected in the form layout by clicking and dragging to draw a
rectangle around the desired objects. A selected item may be unselected using ctrl-click in the outline or
shift-click in the layout.
Attributes that the objects have in common are displayed in the Attribute Inspector, except for positional
attributes and name attributes. When the selected objects share the same value for an attribute, that value is
displayed in the inspector. When the selected objects do not share the same value for an attribute, an empty
string is displayed for the value.
If an attribute is disabled for one or more selected objects, that attribute is not shown in the inspector.
Changing the value for an attribute applies that value to all selected objects. The Undo All button restores the
previous values.

Setting Properties
To set properties for an object, follow these steps:
1. Make the Attribute Inspector visible (through the menu item or toolbar button).
2. Select the object in the tree view, an Outline tab, or a Layout tab. The Attribute Inspector displays
attributes for the selected object.
3. Make your attribute changes in the right hand column of the Attribute Inspector. Your changes are
applied when you have finished editing the attribute.
4. To undo changes made since the last update to this object’s attributes, press Undo All. You can undo
your changes as long as you have not switched to another selection.

Coding Assistant
The Coding Assistant lists items that you can add to the application. You use the Coding Assistant to:
• Define classes
• Define menus
• Define functions, constants, and variables
• Define events
• Code SAL statements
• Set parameters for functions that you call
• Create objects

50
The Coding Assistant is context-sensitive. As you move through the application, the contents change to reflect
the items that you can add where you are positioned in the outline.
To display the Coding Assistant:
• Press Alt+2.
OR
• Select Tools > Coding Assistant.
OR
• Press the Coding Assistant toolbar button.
The Coding Assistant has one or two lists depending on what is selected in the outline:
• Click Add Same Level to add the highlighted item at the same level as the selected item in the outline.
• Click Add Next Level to add the highlighted item at the next level under the selected item in the outline:

When you edit an Actions section or Message Actions block, the Coding Assistant can display several
categories of information. If it can, the Coding Assistant displays the name of the current category in a combo
box at the top of the palette. As you change the selected category, the list changes to those symbols and
constructs that belong to that category.
When you select an item in the Message Actions block of a window, The Coding Assistant lists complete On
statements with message names that are appropriate for the object. For example, when you select an item in
the Message Actions for a push button, the Coding Assistant presents a list of SAM events, such as “On
SAM_Click”.
Type the first few characters of a name in the data field at the top of the palette to scroll to the item that
begins with the prefix.
There are certain items in the outline that will not appear in the lists presented by the Coding Assistant.
SQLWindows presumes that any item whose name begins with two underscore characters (for example,
someFunction) should be treated as “hidden”. Such names do not appear in Coding Assistant lists. You can
designate other such prefixes as “hidden” by using the Preferences dialog as described below.
If another palette overlaps this palette, you must click in an editable area to bring it to the top.
The Coding Assistant is a palette that can be docked (see Docking Toolbars, Palettes, and the Menu Bar on
page 39).
51
You can configure the Coding Assistant by selecting Tools > Preferences (see Preferences on page 94).

Active Coding Assistant


The Active Coding Assistant runs in the background during your editing session. In some cases its actions are
automatic; in others you must invoke its actions. It provides the following features:
Complete Word. Types the rest of a variable, command, or function name once you have entered enough
characters to make the expression unambiguous.
Parameter Info. The Parameter Info option opens the Parameters list to give you information about the
number, names, and types of parameters required by a function or attribute, plus the parameter description
if available.
Quick Info. The Quick Info option displays the complete declaration for any identifier in your code. Move the
mouse so that the cursor is over an identifier (hover over an identifier), and you will see its declaration
displayed in a yellow pop-up box. Quick Info is not available for system-defined variables, constants, and
functions.
List Members. Displays a list of valid member variables, functions or symbols for the appropriate class or
scope. Selecting from the list inserts the text into your code.
Match Brace. When the cursor is presently next to a “brace” character (parenthesis, curly bracket, or square
bracket), moves the cursor to the brace character that matches the current one. Optionally selects al the text
between the braces.
Active Coding Assistant itself, and its individual features, are subject to your preferences. You can configure
the Active Coding Assistant by selecting Tools > Preferences. (See Preferences on page 94).

Complete Word
Complete Word types the rest of a variable, command, function, or symbol name once you have entered
enough characters to make the expression unambiguous.
The Complete Word option is never automatic and always requires user action. The user can select the
toolbar option, menu option, or hot key. The hot key is CTRL+SPACEBAR.
Type the first few letters of the name, and press CTRL+SPACEBAR.
If what you typed has more than one possible match or no match at all, invoking Complete Word will display
the Members list, which you can then use to find the term and insert it into your code (see List Members on
page 53).

Parameter Info
The Parameter Info option opens the Parameters list to give you information about the number, names, and
types of parameters required by a function or attribute, plus the parameter description if available.

The parameter in bold indicates the next parameter that is required as you type the function.
52
The Parameters list is also displayed for nested functions. If you type a function as a parameter to another
function, the Parameters list displays the parameters for the inner function. Then, when the inner function
Parameters list is complete, the Parameters list reverts to displaying the outer function parameters.
Parameter Info can be activated in the following ways:
• If the Preference Setting “Auto Parameter Info” is activated, then whenever the user is in the scope of an
“Actions” outline section, after the name of a function, type an open parenthesis as you normally would
to open the Parameters list.
• If the you select the name of a method and select the toolbar option, menu option, or hotkey.
• If the cursor is inside the parenthesis of a function and the user selects the toolbar option, menu, or
hotkey.

Parameter Info behavior


The Active Coding Assistant displays the complete declaration for the function in a pop-up window just under
the insertion point. The first parameter in the list appears in bold.
As you type the function parameters, the bold changes to reflect the next parameter that you need to enter.
If available, descriptive information about the parameter is displayed in the tooltip on the following lines.
Press ESC at any time to close the list, or continue typing until you complete the function.
Typing the closing parenthesis also closes the Parameters list.

Quick Info
The Quick Info option displays the complete declaration for any identifier in your code. Move the mouse so
that the cursor is over an identifier (hover over an identifier), and you will see its declaration displayed in a
yellow pop-up box.
If the identifier is a function, then the Quick Info also contains descriptive information about the function.

Quick Info can be activated in the following ways:


• If the Preference Setting "Automatic Quick Info tooltips " is activated, whenever an identifier is selected
• If the user selects the identifier and selects the toolbar option, menu option, or hotkey (Ctrl+Q)

List Members
List Members is a floating/modeless dialog box with a list box containing all members of the class or scope
that has focus. This list is intended to allow the user to select the desired member. In the following example,
the user typed “Call tblCompany” and a period:

53
List Members can be activated in the following ways:
• If the Preference Setting “Auto List Members” is activated, whenever the user is in the scope of an
“Actions ” Outline Section and types the name of a class or a class instance followed by a period, List
Members is activated.
• If the user selects the name of a class or a class instance and selects the toolbar option, menu option, or
hotkey.
When activated, this displays all valid members (for a class, an instance, or scope) in a scrollable list. For
example, you can scroll or use the arrow keys to navigate through the list, or, if you know the first few letters
of the member name, begin typing to jump directly to the member in the list.
To insert the selected member in your code, there are two methods that offer slightly different results. Do
one of the following:
• Type the character that will follow the member, such as open parenthesis, comma, space, semicolon, or
others, to insert the selected member followed by the character you just typed. This works for any non-
identifier character.
OR
• Press TAB, CTRL+ENTER, ENTER, or double-click to insert just the member. If no item is selected in the
drop-down menu, ENTER inserts a blank space. CTRL-ENTER inserts the item that has the focus box, even
if it is not selected.
Press ESC at any time to close the Members list.

Match Brace
Match Brace is never automatic; it is always triggered by your action. It can be invoked by a toolbar button, an
item under the Edit menu, an item in the right-click context menu, or by using the hotkey Ctrl-M or
Ctrl-Shift-M.
It is available when you are working in the Outline tab and your cursor is within a line of code in an Actions
section of the outline. Match Brace looks for a “brace” character (a parenthesis, a square bracket, or a curly
brace) near the cursor, either to the right or to the left. If a brace character is found, Match Brace searches for
the matching character and, if found, moves the cursor just “outside” of it. For example, if your cursor is
currently just to the right of a closing parenthesis character “)”, and you invoke Match Brace, it will search to
the left for the first “(“ character and, if found, will place the cursor just to the left of that character.
If the cursor is not currently near a brace character, or if a matching brace character cannot be found, the
cursor stays where it is and a warning sound is played.
In most cases the cursor moves without selecting any text. If you invoke Match Brace with the hotkey
Ctrl-Shift-M, the cursor moves and also selects the pair of braces and all the text inside the braces.

54
Controls Palette
The Controls palette has a set of buttons and list box for selecting objects. The lower part of the Controls
palette lists subclasses of the selected object if any exists in the current application.

The Controls palette has three toolbars:


• The standard child-window toolbar, which contains a button for each window type built into
SQLWindows.
• The custom controls toolbar, which contains a generic custom control push button and buttons for two
QuickObject types: cQuickTable and cQuickGraph. You can add buttons for child window classes to this
toolbar.
• The ActiveX toolbar, which contains a generic ActiveX button. You can add buttons for ActiveX
components to this area. This toolbar also contains a Report button, which represents the ActiveX
interface of GUPTA Report Builder. You can find detailed information about using this interface in chapter
6 of the Business Reporting manual.
As you move the mouse over the Controls palette, it displays as an arrow cursor. If you hold the mouse
pointer over one of the buttons for a second or two, a tool tip window displays the title of the button.
To display the Controls palette:
• Press Alt+4.
OR
• Select Tools > Controls.
OR
• Press the Controls toolbar button.
To add an object, click its button in the Controls palette, move the mouse pointer to the window where you
want to place the child object, and click and drag.

When the mouse pointer is over a child object, it changes to a four-headed arrow. You can then
click to select the child object and move or delete it. You can also cut, copy, and paste objects.
To duplicate a child object, hold down Ctrl when you click it.

55
When an object is selected, it has handles on its sides. If it is the only selected object, you can
move the mouse pointer over one of these handles and click-drag to change the size of the
object.

You can select multiple objects with the arrow cursor by holding down the Shift key and clicking them or by
click-dragging a rectangular region that contains the objects you want to select. When you select multiple
objects, you can use the commands in the Layout menu to neatly arrange and size objects.
You can select multiple objects with the arrow cursor by holding down the Shift key and clicking them or by
click-dragging a rectangular region that contains the objects you want to select. When you select multiple
objects, you can use the commands in the Layout menu to neatly arrange and size objects.
After you drop a child object on a window, SQLWindows changes the Controls palette selection to the arrow
cursor.
You can resize the Controls palette.
If another palette overlaps this palette, you must click a button or make a selection in the list to bring it to the
top.
The Controls palette can be docked (see Docking Toolbars, Palettes, and the Menu Bar on page 39).

Configuring the Controls Palette


You can add buttons to the Controls palette. Any changes you make are global and are in effect for any
application you open on the computer.

Buttons for class-based objects


When you click a button for a standard child window on the Controls palette, the list in the lower part
populates with any classes of that type defined in the application. You can select an item in the list (other
than “Standard”) and drag it over the custom controls toolbar, or to the right of the last button in the toolbar
to add it to the palette.
You can then use the button to add an instance of the class to the application the same as SQLWindows' built-
in objects. You can add more buttons by dragging to the right of existing class buttons. To remove a button,
click and drag it off the palette.
Note: If the current application is new and has not been saved (has no title), you cannot add any classes
defined in it to the custom controls toolbar. SQLWindows needs to associate a file name with the
button.
If you added a button to the custom controls toolbar and you use it to create an object in an application in
which that button's class is not defined, SQLWindows automatically includes the application file that defines
the class. Be aware of this when adding and using such classes. It is recommended that you define such
classes in small APLs that contain a related set of classes and the definitions they require.

Buttons for ActiveX components


When you click the ActiveX button on the Controls palette, the list in the lower part populates with the
registered ActiveX components on the system. You can click the name of an object and drag it just to the
ActiveX toolbar to add it to the palette. You can then use the button to add the object to the application in
the same way as SQLWindows’ built-in objects. You can add more buttons by dragging to the right of existing
ActiveX component buttons. To remove a button, drag it off the palette.

56
When you click the right mouse button while over a list of ActiveX components in the Controls palette, you
can:
• Add a button for the selected component to the Controls palette.
• Choose to display only controls or insertable objects.

Source Control Palette


The Source Control palette can be used to interact with third party source control systems such as Git and
Subversion. When opening the palette for the first time, you must select your preferred source control
provider. Your selection will be saved for future reference, and can be changed in the Preferences dialog
under the Source Control tab.

The Source Control palette has three regions:

• A toolbar at the top that exposes common commands specific to the selected provider:
▪ Check Out (Clone): Checkout/Clone of a respository, you’ll need to provide the repository URL
and a location on disk to store the respository.
▪ Commit: Commits outstanding changes
▪ Update (Pull): Pulls in updates from the repository. For Git, this is a combination of fetch and
merge commands.
▪ Push: Only shown for Git, pushes commited changes to the remote repository.
• A dropdown for switching between configured repositories. Next to the dropdown are buttons for
viewing the selected repository detail information, adding an existing repository, and removing a
repository from the list.
• The bottom portion of the palette shows file info for the currently selected repository. For Git, which
allows developers to accumulate many commits before pushing, a commit list will also be shown.

57
• By default, only application files are shown in the file tree, use the show all button to display all file types.
The nodes are color coded based on their status: Red for modified files, blue for newly added items, and
purple for conflicted files.

Configuring the Source Control Palette


You can configure the source control palette in the IDE Preferences “Source Control” tab.

Provider
Use this setting to switch between supported source control providers, Git or Subversion.

Diff/Merge Tool
By default, Team Developer uses the TOM diff/merge utility to show diffs and do auto merging of Team
Developer application files. Uncheck the checkbox “Use Team Developer…” to use a third-party tool for Team
Developer files. Note that non-TD files will always use the third-party tool selected. Commonly used tools
are available for selection, or a custom tool path can be provided using the “Other” radio option.

SQLWindows Menus
SQLWindows has the following menus:
• File
• Edit
• Project
• Component
58
• Layout
• Debug
• Tools
• Window
• Help
For details, see Chapter 4 – SQLWindows Menus.

Debugger
The debugger enables you to:
• Set breakpoints where the application suspends execution
• Check the values of variables and evaluate expressions
• Monitor messages that an object receives
• Display a function call trace
• Highlight code as it executes (animation)
• Execute an application a statement at a time (step into) with the option to bypass single stepping when
calling a function (step over)
When you are coding statements and building objects at design time, it is called design mode. When you run
the application at design time, it is call run mode.
For details on the SQLWindows debugger, see Chapter 10–Debugging.

Keyboard Shortcuts
Displaying SQLWindows palettes and controls

Window Shortcut

Coding Assistant Alt+2

Controls palette Alt+4

Attribute Inspector Alt+3

Opening, saving, and printing

Action Shortcut

Create new application Ctrl+N

59
Action Shortcut

Open application Ctrl+O

Save application Ctrl+S

Save as F12

Print outline Ctrl+P

Editing

Action Shortcut

Undo (current edit only) Ctrl+Z


Cut Ctrl+X
Copy Ctrl+C
Paste Ctrl+V
Clear Del

Expanding and collapsing sections in Outline tabs

Action Shortcut

Expand a section Double-click collapsed section


at solid diamond or select lines
and press the keypad “+”
Expand all below selected Select lines and press the
section keypad “*”
Collapse all below selected Double-click on expanded
section section at solid diamond or
select line(s) and press the
keypad “-”
Collapse entire outline Ctrl+- (Control key and keypad
minus key)

Selecting and deselecting in Outline tabs

Action Shortcut

Single line Left mouse button

Extend contiguous selection Shift+left mouse button

Extend noncontiguous selection Ctrl+left mouse button

Editable/right portion of line Select line and press the Tab

60
Action Shortcut

key

Line above, same level Up Arrow

Line above, previous level Left Arrow

Line below, same level Down Arrow

Line below, next level Right Arrow

Navigating in Outline tabs

Action Shortcut

To top of current level and Home


select current level
To bottom of current level End

To top of outline Ctrl+Home

Up one screen PgUp

Down one screen PgDn

Right 1/2 screen Ctrl+PgDn

Left 1/2 screen Ctrl+PgUp

Scroll all of selected item into Keypad “5”


view
Jump from a highlighted F2
symbol name in a statement to
the actual declaration of that
symbol elsewhere in the
outline
Jump back from the declaration Ctrl+F2
to the starting point

Adding a new line in Outline tabs


Action Shortcut
At same outline level Ins

Continue current outline item Ctrl+Enter


on next line

61
Ending an edit in Outline tabs

Action Shortcut

And adding another new line Enter


Ending current edit only Esc

Finding and replacing in Outline tabs

Action Shortcut

Find Alt+F3 or Ctrl+F

Find Again F3

Replace Ctrl+H

Moving items in Outline tabs

Action Shortcut

Left one level Alt+Left Arrow

Right one level Alt+Right Arrow

Up one line Alt+Up Arrow

Down one line Alt+Down Arrow

Libraries

Action Shortcut

Edit library F5
Show item information Shift+F5

Working in layout windows

Action Shortcut

Align edges left Ctrl+Left Arrow

Align edges right Ctrl+Right Arrow

Align edges top Ctrl+Up Arrow

Align edges bottom Ctrl+Down Arrow

Align edges vertical center Ctrl+F9

62
Action Shortcut

Align edges horizontal center Shift+Ctrl+F9

Space evenly across Alt+Right Arrow

Space evenly down Alt+Up Arrow

Compiling and executing

Action Shortcut

Compile F8

Display compiler error Alt+1


messages
Next error F4

Previous error Shift+F4

Execute F7

Debugging

Action Shortcut

Execute or resume execution F7

Stop Debugging Shift+F7

Toggle breakpoint F9

Step Into F10

Step over Ctrl+F10

Display Variables window Alt+5

Display Stack window Alt+6

Display Messages window Alt+7

Display Expressions window Alt+8

Other

Action Shortcut

Open online help F1

63
Action Shortcut

Cycle through settings Up/down Arrows

Properties Alt+Enter

Component wizards Ctrl+W

SQLWindows Command Line Arguments


SQLWindows has command line arguments you can specify to control its processing.
You precede an argument with a hyphen (“-”). You can place more than one argument after the hyphen. You
can use the following arguments:
b Compile and save an executable file; for example
-b foo.app foo.exe
c Save the application as a normal (binary) file and exit. You can use this option to convert a text
application to binary.
i Edit an include file. Name the include library with the -n argument; for example
-i -n mylib.apl
m Generate a dynalib (*.APD) file and exit. This example creates a dynalib named FOO.APD:
-m foo.apl
n The name of an include file to edit. Use this argument with the -i argument.

r Start in run mode. This is the same as starting SQLWindows and choosing User Mode from the
Run menu.
x Exit Windows when done; for example
-bx myapp.apt

64
Chapter 3 – Deploying and Migrating
Applications
This chapter explains the following:
• Creating applications that users can run on their computers
• Installing applications on users’ computers
• Connecting to data sources
• Migrating applications from a 16-bit environment to a 32-bit environment
• Opening an application in a previous version of Team Developer.

Deploying an Application
To run a SQLWindows application in a production environment, you must install these components on users'
computers:
• An executable version of the SQLWindows application
• Deployment files that come with SQLWindows
• Other components that connect the application to a data source

Creating an Executable Application


Select Project >Build Settings and specify the type of file you want to build (see Build Settings on page 79).
Select Project > Build to create the file (see Build on page 84).

Installing Deployment Files


There is a set of standard runtime files you must install with SQLWindows applications. You install them on a
user’s computer by calling deploy*.exe, which is a self-extracting program. The files are the following:

Component Destination Location Files Included

Core Files TD Application folder cbawi60.dll, cbtti60.dll, cdki60.dll, cdlli60.dll,


cguti60.dll, cni60.dll, csi60.dll, GAILWrapper.dll,
gctli60.dll, geei60.dll, gtblexi60.dll, gtlsi60.dll,
gxmli60.dll, ProfUIS283u_td.dll, ProfUIS283u-
RDE.dll, maili60.dll, qcdki60.dll, qdlgi60.dll,
qtabi60.dll, qvisi60.dll, qwaxi60.dll, rdwi60.dll ,
RepPdfLib60.dll, snumi60.dll, srvci60.dll, ssti60.dll,
strci60.dll, swcomp.exe, swmsgi60.dll, swosutil.dll,
Gupta.TD.DotNetExplorer.GAIL.dll, windist.exe,
tdclickwrap.pdf, license.txt, graphppr.hlp, icu*.dll

65
Component Destination Location Files Included

MSVC Runtime TD APP Folder\ Microsoft.VC80.CRT.manifest, msvcm80.dll,


Microsoft.VC80.CRT msvcp80.dll, msvcr80.dll
TD APP Folder\ mfc80.dll, mfc80u.dll, mfcm80.dll, mfcm80u.dll,
Microsoft.VC80.MFC Microsoft.VC80.MFC.manifest
Axis2C TD APP Folder\ Axisc2C Check TD Deployer after installation. Needed for TD
WebService apps
TD-SQLBase API TD Application folder Sqlbapw.dll, sqlwntm.dll, sqlws32.dll

SQLBase Client TD Application folder Country.sql,dcc.ini, error.sql,gptcfping.dll,


Connectivity gptcfping.exe,gptconfig.exe,gptutilcom.dll,
message.sql, MFC71.dll, msvcp71.dll, msvcr71.dll,
gptconfig.hlp, gptconfig.cnt
SQLBase OLEDB TD Application folder SQLBaseOLEDB.dll
Provider
SQLRouter For Oracle TD Application folder Sqlora32.dll, orasal32.dll

SQLRouter For ODBC TD Application folder Gotodbu32.dll, sqlodb32.dll, Odbsal32.dll,


odbsal32.apl
SQLRouter For Informix TD Application folder Sqlifx32.dll

SQLRouter for Sybase TD Application folder Sqlsyb32.dll, SybPrivs.exe, SybSal32.dll

Graphic Server Files TD Application folder gsw32.exe, imgman32.dll, imhost32.dll, *.del, *.dil

To install deploy*.exe on a development computer, select GUPTA Runtime Installer in the Team Developer
install program. Include deploy*.exe in your build process and your application installer executes it.

66
The executable file deploy*.exe adds files to the directory the user specifies and to the Windows /system
directory.

Installing Deployer in Silent Mode


The steps for installing the deployer in silent mode are the following:
Step 1: Record deployment installation using the command Deploy60.exe /r /f1"D:\silent.ini". Complete the
installation process. This records all installation selections into D:\silent.ini.
Step 2: Change silent.ini according to your needs. For example, you can change the installdir to some other
directory in silent.ini.
Step 3: Use Deploy60.exe /s /f1"D:\silent.ini" to install in silent mode on other machines.

Deploying a Win32 Application Containing .NET Library Code


If you used the .NET Explorer Wizard to import .NET APLs for a project with a Win32 build target, follow these
steps to deploy the Win32 application:
1. Locate dotnet35sp1 and vc9redistributable packages in the deployment folder. These packages are
installed as part of the deployer setup.
2. Manually install dotnet35sp1 and vc9redist on the deployment machine.

Deploying to Windows Vista or Windows 7


Windows Vista and Windows 7 include the User Acount Control feature, which can interrupt applications that
are not installed with the required permissions. To avoid this problem with your deployed Team Developer
applications, make sure that your users install the deployer in a directory for which they have read and write
privileges. If the deployer was installed elsewhere, your users can do the following:
1. Place the application .exe file in a folder for which they have read/write privileges.
2. Copy the sql.ini from the deployer install into the same directory as the .exe.
3. (If your application uses reports) Copy the .qrp file to the same directory as the .exe.

Connecting to a Data Source


SQLWindows can connect to many SQL databases using its standard deployment files. (For more information,
see the Connecting GUPTA Objects to Databases document.) Depending on your data source, you may need
to purchase and install other software such as:
• SQLBase Server for Windows/Linux
• SQLBase Desktop
• Other SQL database products

67
Opening an Application in a Different Version

Opening a 5.1+ Application in 4.2 or Earlier


Some important changes took place in Team Developer between version 4.2 and version 5.1. Thus, to open an
application created in version 5.1 or later using version 4.2 or earlier, the following must be done:
• Open your Team Developer application in version 5.1+ and save as an apt.
• Open this apt in Notepad.
• Change the outline version (for example, 4.0.37 ) to the corresponding outline version for the Team
Developer version you want. The outline versions that correspond with various Team Developer versions
are the following:

Team Developer Version Outline Version


1.1.x 4.0.26
1.5.x 4.0.27
2.0.x 4.0.28
2.1.x 4.0.28
3.0.x 4.0.31
3.1.x 4.0.32
4.0.x 4.0.34
4.1.x 4.0.35
4.2.x 4.0.35

• Choose Save as in Notepad.


• To use this application outline in version 4.2 or earlier, select ANSI in the encoding combo box.
• Save the file.

Opening an Old Application in a Newer TD Version


Generally, opening an old application in a new version of Team Developer will not cause a problem. However,
library inclusions and DLL references retain their old names. To use the new versions, you must change the
references manually. For example, if you open a 5.2 outline in version 6.0, you must update references like
gtblexi52.dll and qtabi52.dll to gtblexi60.dll and qtabi60.dll if you want to use the new versions of the DLLs.

68
Chapter 4 – SQLWindows Menus
SQLWindows consists of the following menus:
• File Menu
• Edit Menu
• Project Menu
• Component Menu
• Layout Menu
• Debug Menu
• Tools Menu
• Database Explorer Menu
• ActiveX Explorer Menu
• Window Menu
• Help Menu

File Menu
The File menu provides the following options.

New
Creates a new unnamed SQLWindows application. You name the application the first time you save it.
Displays the Templates dialog where you choose an application template for a SQLWindows application. A
template provides basic outline items used as a starting point to write an application.
The Templates dialog displays the default template with a check box in the application icon. To accept the
default template as the new application, click OK. This creates a new unnamed SQLWindows application.
You can also select a template other than the default and Click OK to choose it. SQLWindows then opens the
new application using the template that you selected.
If you click Close, SQLWindows does not create a new application.
If you select the New button on the toolbar, the Templates dialog is not displayed. Instead, a new application
is created using the default template.

Changing the templates list


You can change the template items listed in the Templates dialog by clicking Edit >> which expands the dialog.
You can add or delete a template, change the default template, or update an existing template entry.
• To add a new template entry for an application, click Browse, select the application, and click New. You
can also type the name and an optional description.

69
If you enter an application name without a path, the file must reside in the Templates subdirectory where
you installed SQLWindows or in the template directory path set with Tools > Preferences.
• To change the default template for creating new applications, select the name of the application you
want as the default template and click Set As Default.
The Templates dialog displays the default template with a check box in the application icon. The Set As
Default button is disabled when the default template is selected.
• To update an application name or description, select the application from the list, change the application
name or description, and click Update.
• To delete an application from the list, select it and click Delete.
Click OK to close the dialog box and save any changes you made. Click Cancel to close the dialog box and
undo any changes you made. To save changes to the Templates dialog without closing it, click Apply. You can
then click Close to continue working on the current application.

Open
Displays a dialog that lets you select a different application to work on.
The File Open dialog can display different file types. You can use the Files of type combo box to choose which
you want to see. You can change the initial type shown when the dialog opens by selecting Tools >
Preferences, clicking the General tab, and then editing the Default Application File Extension value.
You can only open one application at a time. However, you can have more than one view of the same
application open at the same time or you can run multiple instances of SQLWindows, each with a different
open application.

Save
Saves the open application to disk, including any changes you made after the last time you saved the
application. After saving, the application stays open.
If you save an unnamed application, SQLWindows displays the Save As dialog where you name the application
and specify its path.

Save and Return


If you open a second instance of SQLWindows by selecting Component > Go To Item (or by pressing F5), you
select this menu item to save and close the library you are editing and return to the main instance of
SQLWindows (see Go To Item on page 85).

Save As
Saves a copy of the open application under a new name. When you open the application, change it, and then
save it under a new name, the changes are not made to the original application. The open application is a
newly saved application.
If you give the application a name that already exists, SQLWindows asks you if you want to replace the
existing application.

70
Save as type
You use this combo box to select how you want to save the application:
• Normal saves the application in an internal format that saves fast and loads fast at design time. This is
also called the binary format. The default extension is *.APP.
• Compiled saves the compiled code. The default extension is *.EXE
• Text saves the application in a form that you can open with a text editor. The default extension is *.APT.
• Indented Text is like Text, but it saves the application with tabs for the indent levels. The default
extension is *.APT.
• Libraries saves the application as an include library.

Page Settings
Displays a dialog where you set printing options.

SQLWindows remembers the settings you make in this dialog and uses them for all sessions and all
applications on the computer.
Collapsed items print exactly as they are currently displayed in the outline (the items under a collapsed item
do not print).

Titles
Set titles for the header and footer at the left, center, and right. You can enter literals and the following
keywords:
• %A – Name of application
• %P – Page number
• %D – Date
• %T – Time

Text Style
Set the font and font size.

Margins
Set the left, right, top, and bottom margins in inches.
71
Options
Code Only. If checked, only lines that have actual SAL statements print. This does not include formats,
external functions, constants, and variables. The Application Description always prints.
Line Numbers. If checked, the lines are numbered.
Include Display Attributes. If checked, the window attributes print in the outline in the same place as when
you save an application as text.
Include Named Properties. If checked, the named properties of QuickObjects print.

Print
Displays a standard Windows Print dialog. When you print, SQLWindows uses the settings you made in File,
Page Settings.
Collapsed items print exactly as they are currently displayed in the outline (the items under a collapsed item
do not print).

Most Recently Open List


SQLWindows lists the names of up to six of the most-recently opened files.

Exit
Closes SQLWindows. If you changed the open application after the last time you saved it, SQLWindows
displays the “Save current changes?” dialog.

Edit Menu
The Edit menu provides the following options.

Undo
Reverses the last editing or formatting action. If the last action is not reversible, this item is disabled.

Cut
Removes the selected items and places them on the Clipboard, overwriting the previous Clipboard contents.
This item is disabled if nothing is selected.

Copy
Copies the selected items to the Clipboard, overwriting the previous Clipboard contents. This item is disabled
if nothing is selected.

72
Paste
Pastes the contents of the Clipboard at the mouse position. This item is disabled if the Clipboard is empty.

Delete
Deletes the selected items without copying them to the Clipboard. This is the same as using the Delete key.

Insert Line
Inserts a new item below the selected outline item.

Comment Items
Makes the selected outline items comments. Commented items start with an exclamation point (!) and a
space.

Uncomment Items
Changes the selected outline item from comments back to their original form.

Outline menu
Displays these options for displaying various levels of the outline.

Expand One Level


Expands the selected item in the outline one level so child items are visible. You can also expand a selected
item by double-clicking its solid diamond.

Collapse
Hides all child items of the selected parent item.
You can also collapse an outline item by double-clicking its diamond.

Expand All Levels


Expands all levels of the selected outline item.

Collapse Outline
Collapses the outline so that only top-level items are visible.

Promote
Moves the selected item one indentation level to the left.

Demote
Moves the selected item one indentation level to the right.

73
Move Up
Moves the selected item above the previous item.

Move Down
Moves the selected item below the next item.

Active Coding Assistant Items


• Quick Info (Ctrl-Q)
• List Members (Ctrl-space)
• Parameter Info (Ctrl-I)
• Match Brace (Ctrl-M)
These four menu items are part of the Active Coding Assistant feature. The actions of these items can be
somewhat complex. All of them are described in detail in Active Coding Assistant on page 52.

Find
Displays a dialog where you specify what to search for in the outline and, optionally, what to replace it with.
Accelerator Alt+P switches to the Replace tab of the dialog, and Alt+F switches to the Find tab of the dialog.
Each time SQLWindows finds the string, it highlights the string and enables Find Next. Click Find Next to
search for the next occurrence of the search string.

Find only works in an Outline tab. If you are in a different tab and you execute a Find, SQLWindows
automatically switches to the Outline tab.
In an Outline tab, you can use this dialog for window attributes such as Background Color, Data Type, and Line
Style. When SQLWindows locates matching text for a window attribute, it displays a field on top of the outline
just below the item that has the matching property. You close the field by clicking elsewhere in the outline or
by pressing Esc or Enter.

74
Options
See the option descriptions following the Replace dialog screenshot, below.

Find Again
Searches for the string you previously specified in the Find dialog.

Replace Tab
Displays a window where you specify what text to use to replace the string that you were searching for.
After you enter a replace string, the push buttons at the edge of the dialog are enabled.

Replace only works in an Outline tab. If you are in a different tab and you execute a Replace, SQLWindows
automatically switches to the Outline tab.
In an Outline tab, you can use this dialog for window attributes such as Background Color, Data Type, and Line
Style. When SQLWindows locates matching text for a window attribute, it displays a field on top of the outline
just below the item that has the matching property. You can edit this field like other outline items.
SQLWindows updates the property when you close the field by clicking elsewhere in the outline or by pressing
Esc or Enter.

Options for Find and Replace


Scope – If the scope is “Selection”, only those lines that are already selected (highlighted) in the outline are
searched. If the scope is “Entire Outline”, all lines in the outline are searched (subject to the limitations of
other options).
Direction – Searches Up toward the beginning of the outline, or Down toward the end of the outline.
Find Whole Words Only – Limits the found lines to those containing whole words that match the Find What
string.
Match Case – Searches based on the capitalization of the strings in Find What and Replace With.

75
Exclude Comments – Commented lines in the outline are not found or changed, even if they contain a string
that matches the “Find What” string.
Exclude Include Libraries – All lines of code in include libraries are ignored, even if they contain a string that
matches the “Find What” string. This option does not apply to the Replace tab and will be disabled in that
tab.
Wrap Search – When not checked, the search process moves in the selected direction (up or down) until the
beginning or end of the outline is reached. At that time you are presented with a dialog box asking whether
you want to continue the search starting from the other end of the outline. If you check this option, the
search automatically continues from the other end of the outline without prompting you with a dialog box.
You can’t do a wrap search if the scope is “Selection”.
Find Next – Searches for the next occurrence of the search string.
Replace – Replaces the current selection and then finds the next occurrence of the search string and waits for
your response.
Replace All – Replaces all occurrences of the search string without pausing.

Properties
If an object is selected in the tree view or a layout window, displays the Attribute Inspector for the object.
If the top-most item is selected in the tree view, displays a tabbed dialog where you can view statistics and
specify runtime settings for the application.

Statistics tab
This tab contains information about resource use and application components.

Most items in the Statistics dialog are self-explanatory.


Outline Space. SQLWindows uses a directory table to organize and locate parts of the outline. Outline Space
is the percentage of space available in this directory table.

76
Runtime tab

Reject Multiple Window Instances. Results in an error at runtime when the application tries to create a
second instance of a form window, table window, dialog box, or MDI window.
If the application never creates more than one instance of a window, you do not need to use window handles
in references; an object-qualified reference is always enough. However, the design of some applications
requires multiple instances of a window.
Enable Runtime Checks of External References. Generates extra code to ensure that a window handle refers
to a window whose type or class is consistent with the SAL statement.
For example, when you turn on this option, SQLWindows performs the following checks for these
expressions:
• hWnd.frm1.var – hWnd refers to a window whose type is frm1.
• hWnd.frm1.fun( ) – hWnd refers to a window whose type is frm1.
• hWnd.cls1.var – hWnd refers to a window that is an instance of the class named cls1.
• hWnd.cls1.fun( ) – hWnd refers to a window that is an instance of the class named cls1.
• hWnd.cls1..fun( ) – hWnd refers to a window that is an instance of the class named cls1 or is an instance
of a class derived from cls1.
It is recommended that you turn on this option during application development and testing to help find
programming errors. This option generates extra code that slightly impacts the performance and size of an
application, so turn off runtime checks for production applications (before making an *.EXE).
You can enable runtime checks to help diagnose incorrect behavior in production applications. Usually you
make an *.EXE with runtime checks enabled only if an application misbehaves. Such an *.EXE causes an error
message if there is a programming error that assigns an incorrect value to a window handle.
Fully Qualified External References. When you turn on this option, the compiler forces you to qualify all
external references.
When you turn off this option, when the compiler cannot find a symbol in an unqualified reference using the
symbol resolution rules, the compiler silently uses any variable, object, or function with a matching name in
any object throughout the application.
This means that you must be sure that:
• You do not misspell a name.

77
• The application only creates one instance of the containing top-level form.
If both of these conditions are not true, then you can get errors at runtime or find that the application
misbehaves. These problems are difficult to diagnose.
This setting sometimes determines how SQLWindows interprets parent object names, as follows:
• hWnd.Variable – The compiler always accepts no matter what the setting.
• Object.Variable – The compiler accepts if you make the reference in the object's scope no matter what
the setting.
If you make the reference outside the object's scope, the compiler only accepts it if both of the following are
true:
• Fully Qualified External References is off.
• The object’s name is unique.

Project Menu
The Project menu provides the following options.

Check Out
Checks the application out of the Team Object Manager Repository. Once you have checked out the
application, you can edit it.

Check In
Returns the application to the Team Object Manager Repository so that others can access it.

Compile
Compiles the application. While compiling, SQLWindows displays a dialog. Click Cancel to stop the compile.
Error message list
When compiling, SQLWindows detects as many errors as possible before stopping. As SQLWindows compiles,
it lists each error as it finds them (see Output on page 99).

Next Error
When the compiler error message list is displayed, moves to the next statement that caused an error.

Previous Error
When the compiler error message list is displayed, moves to the previous statement that caused an error.

78
Execute
Compiles and runs the application. If the application compiles successfully, you can test it. While the
application is running, this item is checked.
While the application is running, you cannot edit the outline.

Register Server
Places information about the currently open COM server in the system registry (see Registering Servers on
page 501).

Unregister Server
Removes information about the currently open COM server in the system registry.

Regenerate GUIDs
Displays a dialog where you select the GUIDs you want to regenerate for a COM server.

Build Settings
Displays a tabbed dialog where you set specify information about what to build.

Build Target tab

79
Win32 Application / .NET Application
Select whether you want to build a native TD application or produce a .NET application.

Target Type
Choose the type of build:
• Standard EXE. A double-clickable version of the application in an *.EXE file. An *.EXE file does not contain
source code and you cannot edit it.
• Dynalib. A compiled SQLWindows module with functions and objects that other applications can
dynamically load at runtime (see Dynamically Linked Libraries (dynalibs) on page 438).
• Include Library. A collection of GUPTA SQLWindows objects such as form windows, dialog boxes, or class
definitions that can be shared by more than one application (see Include Libraries on page 435).
• Local COM Server (EXE). A COM server that runs in a separate address space than its clients.
• In-proc COM Server (DLL). A COM server that runs in the same address space as its clients.
• MTS COM Server (DLL). A COM server that runs in the MTS environment.

ET Target Type

Target Name (or Target Name / Target Directory)


Specify the name and path of what you are building. Click the ellipsis push button to navigate to the file.

Target Icon
You can select the icon that a user double-clicks to start the application. Click the ellipsis push button to
navigate to the file.

Enable Resource Editing


Check this to edit the resources in the target executable using the Object Nationalizer.

Enable Playback
Check this to enable playback mode for COM servers (see Debugging COM Servers on page 500).

Embed Images in Executable


Check this box to store images within the build. Uncheck to store images externally.

Statement Cache Size


How often SQLWindows writes statements to disk while recording execution of a COM server (see Debugging
COM Servers on page 500).

Overwrite Existing XAML Files

Preview Menus as Ribbon Bars

80
Optimization
To optimize memory usage of binaries (EXEs and DLLs) built with SQLWindows, the runtime environment
manages a cache of loaded outline segments. The cache management can reduce the in-memory footprint of
SQLWindows binaries by unloading segments not in use, reloading them as necessary when the running
application refers to their contents. By default, the runtime tries to limit the cache to 50-60 percent of the
total outline segments.
This characteristic of the runtime may affect an application’s performance, with the decrease in memory use
causing a corresponding decrease in performance. To control the trade-off between execution speed and
memory use, you can change this setting:

Setting Description
Default Restrict the application’s outline segments that are in memory to 50-60 percent
of the total outline segments.
Optimize for memory Restrict the application’s outline segments that are in memory to 25-30 percent
of the total outline segments.
Optimize for performance Allow all outline segments to be loaded.

Version Tab and Custom Version Information Dialog


For *.EXE and any type of COM server, this tab creates a Windows version resource in the *.EXE or *.DLL.
When a user selects Properties from the file’s context menu, Windows shows this version information in the
Version tab of the Properties dialog.

Default Entries
Aside from the entries below, SQLWindows automatically adds the following entries to the version resource:

FILEFLAGS 0x00L

FILEFLAGSMASK 0x3FL

81
FILEOS VOS_WINDOWS32

FILETYPE VFT_APP (for EXEs) or VFT_DLL (for DLLs)

FILESUBTYPE VFT_UNKNOWN

Product Name
The name of the product with which the file is distributed.

Company Name
The organization that produced the file.

File Version
The version number of the file. For example, “3.10” or “5.00.0.47”. Version number can consist of up to four
numbers delimited by decimal points. The maximum value for any single number is 65535.

Product Version
The version of the product with which the file is distributed.

Internal Name
The internal name of the file, if one exists. If the file has no internal name, this string should be the original
filename, without an extension.

Original Filename
The original name of the file, not including a path. This information enables an application to determine if a
file has been renamed by a user.

Language
The locale. For example, “English (New Zealand)”.

Encoding
The code page, which is an internal table that the operating system uses to map symbols (letters, numbers,
and punctuation characters) to a character number. Different code pages provide support for the character sets
used in different countries. For example: “Unicode”.

Legal Copyright
All copyright notices that apply to the file. This should include the full text of all notices, legal symbols,
copyright dates, and so on.

Legal Trademarks
All trademarks that apply to the file.

Custom
Click this to display a dialog where you can add your own named string values to the version resource.

82
To add a custom string, enter the name and value in the fields at the bottom of the dialog and click New.
To change an existing custom string, select it in the list, change either or both values in the fields at the
bottom of the dialog, and click Update.
To delete a custom string, select it in the list and click Delete.

COM Server Tab and Thread dialog


This tab sets options for COM *.DLL and *.EXE servers. It is only visible when you have selected an applicable
target type (see Chapter 21 – Writing COM Servers).

Threading Model
None. The application has one apartment and one thread.
Single Threaded Apartment. The application has the number of single threaded apartments that you specify
in Thread Count.
Thread Settings. Displays a dialog where you set the threading model.

83
Multi-Use Server
If checked, a single server process handles multiple clients; if not checked, a separate server process is
created for each client.

Helpfile Name
Sets the helpfile attribute of the type library of the server.

Type Information
Version–Major. Sets the major version number of the type library. This must be an integer in the range 0-
65,535.
Version–Minor. Sets the minor version number of the type library. This must be an integer in the range 0-
65,535.
GUID. The globally unique identifier of the type library.
New. Generates a new GUID. As you refine the design of a server, you may want to associate a new GUID to
its type library.

Custom thread settings


Use this dialog to associate CoClasses with specific threads.

Click Y or N to associate or disassociate a CoClass with a thread number.


Thread Model. The type of threading:

Setting Description
Fixed Associate each CoClass with a specific thread. If you select this, the list in the dialog
contains the names of CoClasses in the application. You can then associate each CoClass
to a distinct thread by clicking the “N” in the column for the thread number.
Thread per Object Each object is created in its own thread even if the client is single threaded.

Thread Count. The number of threads to create at startup.

Build
Creates an executable, dynalib, include library, or COM server as specified in the Build Settings dialog. Click
Settings to go to the Build Settings dialog.

84
Component Menu
The Component menu provides the following options.

New
Displays a submenu where you can select an item to add to the application. The items in the cascading menu
depend on what is selected in the tree view or tab view.

Wizards
Lets you create items using SQLWindows’ wizards that guide you through dialogs.

QuickObject Editor
Lets you associate a dialog with a class. The dialog is invoked at design time on objects of the class, usually to
set properties that are used at runtime.

Go To Item
Starts a new instance of SQLWindows and opens the include library that contains the selected included item.
You can then edit the included item. When you save and close this instance of SQLWindows, the first instance
of SQLWindows resumes.
Unless you uncheck Refresh When Changed in Tools > Preferences (see Preferences on page 94),
SQLWindows detects that one of the included items has changed and automatically reincludes the changed
include library.
When you edit an included item in an include library, the target item is selected in the include library (see
Include Libraries on page 435).

Show Item Information


Displays a window that contains the name of the include library that contains the selected item. This menu
item is only enabled when you have selected an included item in the outline (see Include Libraries on page
435).

Refresh Libraries
Reincludes all libraries. Choose Refresh to include a recently-changed include library without closing the
current application; for example, when another person changes an include library on a file server (see
Include Libraries on page 435).

Merge Libraries
Permanently merges all libraries with the open application. Once merged, the items are a fixed part of the
application. Merging removes the information that relates the included items to their original libraries.

85
GUPTA SQLWindows displays a warning dialog before completing the merge (see Include Libraries on page
435).

Large Icons
Sets the type of view in the Components tab to large icons.

Small Icons
Sets the type of view in the Components tab to small icons.

List Details
Sets the type of view in the Components tab to a list.
Sets the type of view in the Components tab to show details.

Layout Menu
The Layout menu provides the following options.

Preview Window
When a top-level window is selected in the tree or tab view, select this to display the window as it will appear
to the user. The window floats free of the SQLWindows window. The window’s menu will be visible and you
can set the runtime position of the window. You can add, move, and remove child objects and use the
Controls palette as you do in the Layout tab.
While in preview you can select a different tab in the tab view. For example, you can display a top-level
window in preview mode and then change the tab view to display the outline.
While in preview mode, the focus in the Outline tab follows what is selected in the top-level window and vice
versa. For example, if you are displaying a form window in preview mode and you click a push button on the
form window, it is selected in the outline. If you select a push button in the outline, it is selected in the form
window. This is true for the application view from which you launched preview mode.
You cannot display a given window in preview mode more than once.
While in preview mode you can navigate the window's subtree in the tree view. However, the tree view is not
synchronized with the preview window. If you navigate outside the window's subtree, you exit preview mode.
A preview window is associated with its launching view. That is, if you navigate outside window's subtree in
the tree view of the launching view, you exit preview mode. However, in a view not associated with the
preview window, you can navigate outside the window's subtree and remain in preview mode.
To view more than one window in preview mode, open an additional view of the application by right clicking
in the tree view and select Open View from the menu.
While in preview mode, the Layout tab in the tab view is disabled.

86
Bring To Front
Brings the currently-selected objects to the top layer.
If an object is under the top layer, it is not visible and you cannot select it. Select the object on top and
choose Send to Back.

Send To Back
Sends the currently selected objects to the back.

Align to Grid
Aligns the selected items with the nearest grid lines. You can align multiple items or a single item.

Align Edges
Aligns selected objects uses these menu options.
You must select at least two objects before this menu item is enabled.
Click an option to display details.
Important: When you select multiple objects, the first object selected has darker handles than the others. All
operations applied to a selection of objects are relative to the first selected object.

In this example, the developer


selected the top data field first

Left
Aligns all selected objects with the left-hand edge of the first selected object.

Right
Aligns all selected objects with the right-hand edge of the first selected object.

Top
Aligns all selected objects with the top edge of the first selected object.

Bottom
Aligns all selected objects with the bottom edge of the first selected object.

Vertical Center
Aligns all selected objects with the vertical center of the first selected object.

Horizontal Center
Aligns all selected objects with the horizontal center of the first selected object.

87
Space Evenly
Evenly spaces selected objects.
You must select at least two objects before this menu item is enabled.

Across
Evenly spaces objects horizontally.

Down
Evenly spaces objects vertically.

Make Same Size


Makes the selected objects the same size.
You must select at least two objects before this menu item is enabled.
Important: When you select multiple objects, the first one selected has darker handles than the others. All
operations applied to a selection are relative to the first selected object.

Width
Makes all selected objects the same width as the first selected object.

Height
Makes all selected objects the same height as the first selected object.

Both
Makes all selected objects the same width and height as the first selected object.

Grid
Hides or shows the grid dots in top-level windows and toolbars.

Tab Order
Displays a dialog where you can change the tab sequence for objects on a form window or dialog. The tab
sequence defaults to the order in which objects appear on the outline.

88
The tab sequence value is from 1 to the number of objects in the window that are editable or can receive the
focus.
The objects in the window display a number that shows their current tab sequence and the Tab Order dialog
displays the tab sequence to assign to the next object that you select.
To assign tab order:
1. Click the Up (increment) and Down (decrement) arrows in the Tab Order dialog to select a tab sequence.
2. Position the mouse pointer (shown below) on the object to which you want to assign that tab sequence
to and press the left mouse button. The object is assigned the tab sequence displayed in the Tab Order
dialog.

3. Click Reset to set the tab sequences of the objects to their original values.
To save changes and close the Tab Order dialog, click Close.

Show Sample Text


When you check this, SQLWindows fills data fields, table window columns, and multi-line fields with
sample data at design time:
• For Number and Date/Time data types, SQLWindows displays the sample data using the format specified
in the Attribute Inspector
• For String and Long String data types, SQLWindows formats the sample data using the input mask if there
is one

Show Design Scroll Bars


If you uncheck this, SQLWindows does not display scroll bars on form windows and table windows at design
time. Uncheck this item when you are designing a window that does not have scroll bars at runtime.

Show Hidden Windows


If you check this, SQLWindows displays windows at design time even if you set their visible property to No in
the Attribute Inspector.
89
Debug Menu
The Debug menu provides the following options. For details on debugging, see Chapter 10 – Debugging.

Stop
Stop execution of the application and returns you to SQLWindows.

Continue
Resumes execution after it has suspended at a breakpoint

Breakpoints
Displays the Breakpoints dialog, which controls all breakpoints currently active in your application (see
Breakpoints on page 288).

Break
Suspends execution.

Step Into
Executes the next statement and returns control to SQLWindows. If the application calls a function,
SQLWindows takes you to the function and you can step through the function a statement at a time before
returning to the statement after the function call.
If the selected item is a call to an internal function, SQLWindows takes you to the first line but does not
execute it. If the item is a call to an external function, SQLWindows behaves the same way as Debug, Step
Over.

Step Over
Executes the next statement and returns control to SQLWindows. If the application calls a function,
SQLWindows executes all the function's statements in one step and stops at the statement after the function
call.

Breakpoints
Contains a cascading menu that displays the following sub-options:

Toggle
If the selected statement is not a breakpoint, selecting this makes it one. If the selected statement is a
breakpoint, selecting this makes it a normal statement.
Execution suspends before executing the statement. When you run the application, SQLWindows stops at
each breakpoint and displays the Debug toolbar.

90
Clear All
Permanently removes all breakpoints in the application.

Disable All
Temporarily removes all breakpoints in the application.

Enable All
Restores all breakpoints in the application.

No Animate
Stops Fast Animate or Slow Animate. No Animate is the default. A check mark means that animation is not
on.

Slow Animate
Highlights each item as it executes, but at a slower speed than Fast Animate. A check mark means that Slow
Animate is on.
You set the time interval between the execution of each item with Tools, Preferences.

Fast Animate
Highlights each item as it executes. A check mark means that Fast Animate is on.

Playback
Debugs a COM server application in the same way as a desktop application (see Debugging COM Servers on
page 500).

Playback Rewind
Debugs a COM server application in the same way as a desktop application (see Debugging COM servers on
page 500).

Tools Menu
The Tools menu provides the following options.

User Tools
Displays a dialog where you edit the items that appear in the group at the bottom of the Tools menu and in
the Tools toolbar.

91
Tools
The current items in the Tools toolbar.

Ask for Argument


Creates a prompt asking for command line arguments each time before the program starts.

Ask to Save Outline


Creates a prompt to save the outline each time before the program starts.

Command
The program name.

Browse
Selects a program using the standard File Open dialog.

Parameters
Command line arguments to pass to the program each time it starts.

Ellipsis push button


Selects a keyword macro that passes information about the open application to the program:
• $File – Fully qualified outline file name
• $FileName – Outline file base name and extension
• $FileDir – Outline file drive and directory (ending in \)
• $Outline – Passes a decimal number that represents the current outline.
• $MainWindow – Passes a decimal number that represents the handle of the main window.
• $DesignItem – Passes a decimal number that represents the item of the current layout window (form
window, table window, MDI window, or dialog). Passes zero if there is not a current layout window.

92
• $MarkedItem – Passes a decimal number that represents the current marked item in the application.
Passes zero if no item is marked.

Working Directory
The name of the directory that contains files the program uses.

Menu Text
The name that appears in the Tools menu. Use an ampersand (&) for the mnemonic.

Tool Tip
The text that appears when the mouse pointer pauses over the program’s button in the Tools toolbar.

Available Icons
The icon to use for the program’s button in the Tools toolbar.

Toolbars
The Toolbars menu provides the following options.

Toolbars tab
Displays a dialog where you select the toolbars you want to display.

Toolbar. Check a toolbar in the list to display it. Uncheck a toolbar to hide it.
Show Tooltips. If checked, SQLWindows displays a small popup window that contains a single line of text that
describes a button when the cursor is over it.
Cool Look. If checked, buttons are displayed with flat appearance:

If not checked, buttons are displayed with a three-dimensional appearance:

93
Large Buttons. Buttons are displayed larger than the default size.

Tools tab
Enables you to create custom toolbars.

To create a custom toolbar:


1. Click New and name the toolbar. SQLWindows displays an empty toolbar.
2. Drag buttons from a displayed toolbar to your new toolbar.
OR
Click the Tools tab, select an existing toolbar in the list, and drag buttons from the dialog to your new
toolbar.
To delete a custom toolbar:
Select the toolbar in the list and click the Delete button
To change an existing toolbar:
1. If not already displayed, click the toolbar in the list to display it.
2. To add buttons, drag them from other displayed toolbars
OR
Select a toolbar, and drag buttons from the dialog to the toolbar.
3. To remove buttons, drag them from the toolbar.
4. To change the position of a button in a toolbar, click-drag the button.
To reset a toolbar to its default settings:
Select the toolbar in the list and click the Reset button.

Preferences
Displays a tabbed dialog with items that you use to customize SQLWindows’ environment.
94
To see the effect of changing a setting without closing the dialog, click Apply.

General tab: Settings group

• Slow Animate Interval (In Seconds). The speed of Slow Animate in seconds.
• Maximum Compile Errors. SQLWindows continues to compile an application when finds an error.
However, you can set the maximum number of errors at which SQLWindows will stop compiling. The
default is 100.
• SQL.INI File Name. Specifies the database connectivity configuration file that will be used at design time,
whenever a database connection needs to be made. That file’s default name is SQL.INI, but its actual
name and location are controlled by you. The configuration file used at runtime might not be the same.
To learn about system variable SqlINI, see Chapter 12 – SQL Programming.
Warning: If you change the SQL.INI setting while database connections or transactions are open, those are
disconnected immediately, and any work you were performing is aborted. This applies to SQLWindows
applications running from the IDE, and also to database-dependent tools SQLTalk, Team Object Manager,
Database Explorer, and Report Builder. Those tools report SQL errors and must be restarted. Therefore, use
careful timing when changing this setting.

General tab: Files group


Default Application File Extension. The default extension the standard File Open uses when you open an
application. The default is *.app.
Save Automatically Before Starting User Mode. Check this to automatically save modified applications before
going into user mode. If this option is not checked, SQLWindows prompts you to save. This applies to
applications you previously saved and named and those you are changing.
For new applications you have not yet saved and named, SQLWindows always prompts you to save instead of
automatically displaying the Save As dialog.
Refresh Libraries When Changed. If you check this, SQLWindows reincludes all included items each time it
detects that an included item changes (see Include libraries on page 435). You might want to turn off this
option when a reinclude is time-consuming, such as when a library is in a remote location.

95
Outline tab: Font Settings group

Click Choose Font to select the font used in the outline.

Outline tab: Text Enhancements group


Specifies the display property for breakpoints, included items, and comments in the outline. You can select a
different color in the lists or you can choose none, bold, italic, or underline.

Coding Assistant tab: Layout group

Split Horizontally. Displays Coding Assistant's Add Same Level and Add Next Level lists stacked one on top of
the other.
Split Vertically. Displays Coding Assistant's Add Same Level and Add Next Level lists side by side.

Coding Assistant tab: Hidden symbols group


Certain symbols do not appear in the list of names presented by Coding Assistant. SQLWindows presumes that
symbols whose names begin with two underscores—for example, someFunction—should be treated as private
or “hidden”. Depending on your naming conventions, you might want to treat other name prefixes as hidden,
too. If so, you can enter them into this text box, separated by semicolons.

96
Coding Assistant tab: Symbols group
Show Symbols in Global Scope. If you check this, SQLWindows lists global variables, system functions,
internal functions, external functions, constants, and resources in Coding Assistant. Checking this disables the
other two check boxes in this group.
Show Symbols in Parent Scope. If checked, SQLWindows list symbols that are local to the item where the
cursor is positioned and its parent item. For example, when you edit a data field in a form window,
SQLWindows lists the data field and its sibling objects and the form window's variables and functions.
Show Symbols in Class Scope. If checked, SQLWindows lists class function and class variables defined or
inherited by the class of the item where the cursor is positioned. For example, if you edit a data field that is
an instance of a class named clsField1 in a for window that is an instance of a class name clsForm1,
SQLWindows lists the class variables and class functions defined by clsField1 and clsForm1. If clsField1 or
clsForm1 is derived from other classes, SQLWindows lists those classes' symbols also.

Presentation tab: Grid group

Cell Width and Cell Height. The units for the granularity are based on the character size of the font selected
for the form window or dialog:
• 1 width unit = 1/2 character width
• 1 height unit = 1/4 character height
The default granularity is 2 for the width and 2 for the height.
Visible. Check this to display a grid pattern in layout windows. When not checked, SQLWindows does not
display the grid pattern in layout windows, but the grid can still be active. By default, the grid is visible.
Active. Check this to align (snap) items automatically to the grid when you draw, move, or resize in a layout
window. When not checked, you can change the size and location of the items independent of the grid. By
default, the grid is active.

97
Directories tab: Locations group

Templates. The directory where SQLWindows looks for templates to use as starting points for new
applications.
ActiveX Libraries. The directory where SQLWindows stores ActiveX include libraries.

Directories tab: Searching group


This group specifies where SQLWindows looks for libraries, pictures, and icons. Note that this setting controls
only searches that occur in the design-time environment, not at runtime. This setting also does not affect the
search for DLL files mentioned in the External Functions section of the outline.
Separate each path in the list with a semicolon as in a DOS PATH environment variable; for example:
C:\INCLUDES;C:\PROJECT1
Use Global Search Path. If checked, SQLWindows looks for files first in the specified Application Path and then
in the specified Global Path. If not checked, SQLWindows looks only in the Application Path.
SQLWindows stores both the Application Path and the Global Path in the application.
It is recommended that you specify relative paths.

Active Coding Assistant tab: Features group

98
This group specifies whether you want to use Active Coding Assistant, and which features you want to use.
Enable. If unchecked, the Active Coding Assistant background process does not run at all. If checked, the
process runs, subject to additional preferences listed below. For an explanation of the various features, see
Active Coding Assistant on page 52.
Quick Info. If checked, the Quick Info feature is active during editing sessions.
List members. If checked, the List Members feature is active during editing sessions.
Parameter Info. If checked, the Parameter Info feature is active during editing sessions.
Complete Word. If checked, the Complete Word feature is active during editing sessions.

Active Coding Assistant tab: Automatic group


You can manually invoke all the features of the Active Coding Assistant tab using menu choices or toolbars. In
addition, some features are able to start automatically when certain conditions in the editing session are met.
The preferences in the Automatic group control whether you allow such automatic actions to occur.
Quick Info. The Quick Info feature can start automatically.
List members. The List Members feature can start automatically.
Parameter Info. The Parameter Info feature can start automatically.

Output
Displays the compiler error message list.
When compiling, SQLWindows detects as many errors as possible before stopping. As SQLWindows compiles,
it lists each error as it finds them. After the compilation completes, you can:
• Single-click an error message to select the corresponding source item in the outline without closing the
error list.
• Double-click an error message to change the focus to the corresponding source item in the outline.
SQLWindows compiles until it reaches the maximum number of errors that you set in Tools, Preferences,
General.
The error list can be a palette or a toolbar. You dock and undock it the same way you dock and undock
toolbars (see Docking Toolbars, Palettes, and the Menu Bare on page 39).
To change the width or height of a docked error list, move the mouse pointer to an inner edge and drag after
the splitter cursor appears.
You can also move from one offending source item to another with Project > Next Error (see Next Error on
page 78) and Project > Previous Error (see Previous Error on page 78).
If you close the compile error message window after an unsuccessful compilation, you can display it again
with the messages by selecting Tools > Output.
You can send the contents of the output window to an error log. Right-click on the output window, then
choose the menu item to save the contents to a file.

Coding Assistant
Displays the Coding Assistant (see Coding Assistant on page 50).

99
Attribute Inspector
Displays the Attribute Inspector (see Attribute Inspector on page 49).

Controls
Displays the Controls palette (see Controls Palette on page 55).

Variables
Displays the names and values of variables at a breakpoint. SQLWindows updates the variable values at each
breakpoint.
Click the plus/minus button to display the Select Watch Variable dialog where you can choose the variables to
monitor.
To add a watch variable:
1. Select a section name in the outline from the top list in Select Watch Variables on the left side of the
dialog. You can type the first few characters of the name in the data field to scroll to the section that
starts with that prefix. SQLWindows displays the variables defined in the selected section in the lower
list.
2. Select a variable by double-clicking it, or by selecting it and clicking Add. Click Add All to add all the
variables in the section. After you make a selection, SQLWindows adds the variables to Current Watch
Variables on the right side of the dialog.
To remove a watch variable:
Double-click it in Current Watch Variables or select it and click Clear. Click Clear All to remove all variables
from the list.
You can use Edit Watch Variables in the lower right side of the dialog to:
• Type variable names.
• Add qualifiers to variable names.
• Enter expressions to add to the watch variables list. SQLWindows evaluates the expression and displays
the result when you display the Watch Variables window. (This is like entering an expression in the
Expressions window.)
Click OK to save your selections and return to the Variables window. Click Cancel to return to the Variables
window without saving your selections.

Call Stack
Displays the name of the current function (if any) and the name of the function or outline section that called
it. For nested calls (where one function has called another function that has called another function, and so
on), the Call Stack window shows the complete call path.

Messages
Displays every message sent in an application. Each line displays a message name or number, the handle of
the window receiving the message, and the wParam and lParam values.

100
Click SAM messages only to display only SQLWindows messages (SAM_*). The values displayed under the
Message heading are SQLWindows message names.

Expressions
Evaluates an expression you type in the dropdown at the top of the window. After typing the expression,
either click Evaluate or press Return.
You can use this window with Step Into and Step Over to evaluate a variable's value before and after a
statement uses or changes the variable's value.
This window remembers all the expressions you entered for this instance of SQLWindows. You can select an
expression entered earlier in the session by choosing it from the combo box list.
You can evaluate any expression that results in a number or string. For example, you can evaluate expressions
like the following:
SalDateCurrent( )
2+2

Database Explorer
Starts Database Explorer.
While you display Database Explorer, SQLWindows has a Database Explorer menu to the right of the Tools
menu (see Database Explorer Menu on page 102).

ActiveX Explorer
Starts ActiveX Explorer. You use ActiveX Explorer to display the contents of an ActiveX server type library
(*.OLB, *.TLB, *.DLL, *.OCX, *.EXE) (see Using ActiveX Explorer on page 454).
While you display ActiveX Explorer, SQLWindows has an ActiveX Explorer menu to the right of the Tools menu
(see ActiveX Explorer Menu on page 108).

Report Builder
Starts Report Builder.

Team Object Manager


Starts Team Object Manager.

Browse All Classes


Starts the class browser that displays the class hierarchy of the application graphically.

Diff/Merge
Starts the diff/merge tool, which compares files and performs three-way merges.

101
SQLTalk
Starts SQLTalk.

Create Documentation
Displays the Create Documentation dialog. With this tool, you can create documentation for the application
source code. It creates a file named index.html in the specified subfolder.

Database Explorer Menu


The Database Explorer menu is only available when you display Database Explorer by selecting Tools >
Database Explorer.

Database Explorer lets you work with all the databases you can connect to using a graphical user interface.
The tree view of Database Explorer displays your database environment with an expandable/collapsible tree
hierarchy. The tab view displays information appropriate to the element you have selected in the tree view.

New
Provides following sub-options:

Table
Displays the table Definition tab.

Index
Displays the New Index dialog.

Stored Procedure
Displays the New Stored Procedure dialog.

102
Stored Procedure Package
Displays the Create Stored Procedure Package dialog.

Database
Displays the New Database dialog.

SQL Script
Provides the following sub-options:

Execute Command
Executes the SQL command located at the current cursor position.

Execute Script
Executes the specified SQLTalk script.

Cancel Script
Stops a currently executing SQLTalk script or command.

New Script
Clears the command area and allows the entry of new commands. All current cursor connections remain.

Open Script
Allows a file of previously saved set of commands to be loaded.

Save Script
Writes the current command session to a file.

Save Script As
Writes the current command session to a file you specify.

Commit
Commits specified changes to the database.

Rollback
Rolls back the specified (committed) changes to the database. The entire transaction is rolled back when
there is a lock time-out. If rollback is OFF, only the current command is rolled back when there is a lock time-
out. The default is ON.

Options
The following options are available:
Execute. Displays the Script Execution Settings dialog.
Connections. Displays the Connections Settings dialog.
Sessions. Displays the Session Settings dialog.
103
Verbose Messages. Toggle to receive more detailed error messages.
Show Execution Time. Toggle command time on to display the time elapsed to obtain the results of a given
SQL command. Command time resolution is 0.01 seconds. Execution times below this resolution will be
reported as 0.01 seconds.
Split Vertically. Changes the split of the screen to and from horizontal and vertical orientation. (Note that
while the output portion of the main SQLTalk Script screen cannot be edited, you can use the clipboard to
copy portions of the output information.

SQLTalk Output
Writes current output to a file or printer you specify.

Table
Provides the following sub-options:

Define Filter
Displays the Define Table Filter property pages: Conditions, Sort, and SQL. Use Define Filter to limit the
amount of data being viewed or to rearrange the data into a sorted order.

Copy SQL
Copies the SQL statement to the clipboard. The SQL statement that is copied is the one used to populate the
table: SELECT with all the column names.

New Row
Adds a new row to the table.

Clear Row
Marks the selected row(s) in the table for deletion.

Switch Set
Activates after you select New Row or Paste and allows you to switch back and forth between the top and
bottom window panes in the right-hand side of the window. This menu item is disabled after you use Apply
Edits or Discard Edits.

Apply Edits
Applies all the changes you made to the table to the database and refreshes the table. Apply Edits is enabled
after you make a change to the data in the table (update a row, delete a row, or insert a new row).

Discard Edits
Discards all the changes you made to your table since the last time you clicked Apply Edits and refreshes the
table. All table information is restored to its previous state. It does not reverse changes that you have already
applied to the database with Apply Edits. This command is enabled when you have made a change to the data
in the table.

104
Refresh
Refreshes the table by retrieving the new result set. If you have been away from your computer, select this
command to see if anyone else has updated the table or if you need to apply any edits. If you select this
command and have not applied your edits yet, you are prompted to do so.

Stored Procedure
Provides the following sub-options:

Stored Procedure Class Wizard


Enables you to create SAL functional classes based on stored procedures.

Compile
Compiles a SQLBase or Oracle stored procedure.

Copy Text to File


Saves the stored procedure as an ASCII file.

Copy Text From File


Imports the contents of an ASCII file into the stored procedure editor.

Query
Provides the following sub-options:

Define Query
Accesses the property pages to the query you are currently defining. These property pages enable you to
graphically edit the SQL SELECT statement used in the query.

Copy SQL
Copies the query’s SQL statement to the clipboard.

New Query
Creates a new query using the Query property pages. When you select this, you lose the current query.

Open Query
Opens a query you previously saved.

Save Query
Saves the current query to a file. The first time you select this, you are asked to name the file and directory in
which to store the query.

Save Query As
Saves query with another name in a directory you select.

105
First Page
Goes to the first page of the report containing the results of the query.

Next Page
Goes to the next page of the report containing the results of the query.

Previous Page
Goes to the previous page of the report containing the results of the query.

Last Page
Goes to the last page of the report containing the results of the query.

Go to Page
Goes to the specified page of the report containing the results of the query.

Save Pages As
Saves the specified pages of the report containing the results of the query as an RTF file. You are asked to
specify the name of the file and the directory in which it is to be located.

Format
Enables you select the following items to format:
Report. Displays the Format Report dialog box to determine how to print the report.
Input. Enables you to select the following sub-items:
• Variables: Displays the Format Variables dialog box.
• Totals: Displays the Format Totals dialog box.
• Crosstabs: Displays the Format Crosstabs dialog box.
Break Groups. Displays the Format Break Groups dialog box. Break Groups are typically used with queries
that contain a Group By clause.
Block. Displays the Format Block dialog box. A block can be a Report Header, a Page Header, a Detail Block, a
Page Footer, or a Report Footer.
Line. Displays the Format Line dialog box.
Fields. Displays the Format Fields dialog box.
Background Text. Displays the Format Background Text dialog box. You can control character fonts, position of
the text, justification, borders, tab stops, colors.
Box. Displays the Format Box dialog box.
Picture. Displays the Format Picture dialog box.
Graph. Displays the Format Graph dialog box.
Borders. Displays the Format Border dialog box.
Tabs. Displays the Format Tab Settings dialog box.
Colors. Displays the Format Text Colors dialog box. This dialog controls background, border, and text colors.

106
Link Fields. Physically links the selected fields on a line together for the current report.
Unlink Fields. Unlinks the selected fields from their associated fields in the report template.
Align Left Sides. Align the left sides of the selected design elements of the report.
Align Centers. Align the centers of the selected design elements of the report.
Align Right Sides. Align the right sides of the selected design elements of the report.
Align to Grid. Align the design elements of the report to the grid.
Grid On. Toggles the design grid on and off.

Print
Prints the report.

Report Design
Switches to design mode. In design mode you can change how the report look.

Report Preview
Switches to preview mode. In preview mode you can see how the current design of the report looks.

Show as Report
Displays the results of the query as a report.

Show as Table
Displays the results of the query as a table.

Add to List
Displays the Add To List dialog. Use this dialog to add or remove the names of remote SQLBase or DB2
servers. You also use this dialog to add to or remove from the Database Explorer tree (tree view) a remote
SQLBase database.

Disconnect
Disconnects from the database you selected in the Explorer (left) pane. You can also select any of the nested
nodes underneath that database, and then select the Disconnect menu item.

View System Tables


Toggles back and forth between showing and hiding system tables and views.

Close Database Explorer


Closes Database Explorer.

107
ActiveX Explorer Menu
The ActiveX Explorer menu is only available when you display ActiveX Explorer by selecting Tools > ActiveX
Explorer (see Using ActiveX Explorer on page 454).

Open Library
Displays the ActiveX Explorer open type library dialog.

Library Help
Displays the help file for the open type library.

Generate Full

Generate Stub

Generate Deep
Generates an *.APL for the open type library. The menu item wording depends on the generate options
setting.

Generation Option
Sets the options for generating an *.APL.

Refresh
Regenerates the *.APL for the open type library.

Include APL
Includes the *.APL for the open type library in the outline.

Show CoClasses
Shows or hides CoClasses in the open type library.

Show Interfaces
Shows or hides interfaces in the open type library.

Show Events
Shows or hides events in the open type library.

Show Enumerations
Shows or hides enums in the open type library.

Show Functions
Shows or hides functions in the open type library.

108
Show Get Properties
Shows or hides get properties in the open type library.

Show Put Properties


Shows or hides put properties in the open type library.

Show SAL Types


Displays data types as SAL data types or as automation data types.

Window Menu
The Windows menu provides the following options.

Cascade
Displays the MDI Windows layered on top of each other so that only their title bars are visible except the top-
most view. If any MDI windows are minimized, their icons are under the open outline views.

Tile Horizontally
Displays all MDI Windows one above another. If any windows are minimized, their icons are under the open
outline views.

Tile Vertically
Displays the MDI Windows side by side. If any outline views are minimized, their icons are under the open
outline views.

Close All
Closes all windows except the main window.

Open Windows List


The end of the Windows menu lists open windows. Choose a window to make it active.
If you have more than nine open windows, select the More Windows item to display a dialog where you can
pick a window from a scrolling list.

Help Menu
The Help menu provides the following options.

109
Help Topics
Displays the main topic list. Double-click a topic to select it.

Functions Messages
Displays help topics for system functions and messages.

QuickObjects
Displays help topics for QuickObjects.

Visual Toolchest
Displays help topics for Visual Toolchest.

Books Online
Opens the GUPTA Books Online collection. You can perform full-text searches across the entire document
suite, navigate the table of contents using the expandable/collapsible browser, or print any chapter.

About SQLWindows
Displays the version number of SQLWindows.

110
Chapter 5 – SQLWindows Objects
This chapter describes most of the objects that can be added to an application and explains the attributes for
each object.

Adding Objects
Add objects with the Controls Palette (page 55), the New menu (page 46), or the Coding Assistant (page 50).
To add a new object:
• Click the right mouse button and select New.
OR
• Click a push button in the Controls palette, move the mouse pointer over a top-level window, and click.
OR
• Cut, copy, paste, and duplicate existing objects.
OR
• Type an object's definition directly into the outline.
OR
• Double-click an object in the Coding Assistant.

Child Object Mouse Pointers


When you select a child object in the Controls palette, the mouse pointer changes to a symbol that
represents the object.
The mouse pointers are the following:

111
Attributes
You use the Attribute Inspector to set properties of an object (see Editing Object Attributes on page 48).

Naming Conventions for Objects


Using prefixes in the names of objects makes the outline self-documenting. The table below lists the standard
name prefixes.

Object Name Prefix Example


Form window frm frmName
Table window tbl tblName

112
Object Name Prefix Example
Dialog box dlg dlgName
MDI window mdi mdiName
Data Field df dfName
Multiline Field ml mlName
Push Button pb pbName
Date Picker dd ddName
Date Time Picker dt dtName
Tab tab tabName
Radio Button rb rbName
Check Box cb cbName
Option Button ob obName
List Box lb lbName
Combo Box cmb cmbName
Picture pic picName
Horizontal Scroll Bar hsb hsbName
Vertical Scroll Bar vsb vsbName
Custom Control cc ccName
Column col colName
ActiveX ax axName
Rich Text rtc rtcName

Types of Objects
The two types of objects are top-level and child.

Top-Level Objects
There are three top-level objects:
• Form window
• Table window
• Dialog box
These objects are called “top level” because of their position in the outline. An application contains at least
one of these objects.
Table windows can be either top-level objects or child objects.
All top-level objects have:

113
• A border and a title bar
• A system menu
All top-level objects can optionally have:
• A toolbar
• A status bar
All top-level objects (except for dialog boxes) can:
• Have a menu (the next chapter explains menus).
• Have minimize and maximize push buttons.
• Be created automatically when the application starts or created dynamically by the application on
demand. Dialog boxes are only created dynamically on demand.
• Have an initial state (normal, minimized, or maximized).
• Have an icon that is displayed when the window is minimized.
• Be resizable at runtime.
All top-level objects are capable of docking operations with child dialog boxes. You can dock a dialog to a top-
level window at runtime by dragging it to one edge of the top-level window, or by double-clicking in a non-
client area of the dialog such as the caption or border. Dialog boxes can be un-docked in the same manner.
For additional information about docking, see the SAM_Dock message or the functions SalDlgGetDockStatus
and SalDlgSetDockStatus.
In the outline, all top-level objects have:
• A Contents section where you add child windows
• A Message Actions section
• A Window Variables section
• A Functions section
Note: MDI windows are in the top level of the outline, but they are different from top-level windows. You
can place a form window or a top-level table window in the contents section of an MDI window.

Child Windows
You place child windows in top-level objects. Each top-level object has a Contents section where you add child
objects. Child objects are created and destroyed with their parent.
The table below lists the objects that you can add to top-level objects.

These top-level objects... Can have these child objects...

Form window Dialog Box Background text


Group box
Frame
Line
Data field
Multiline field
Push button
Radio button
114
Check box
Option button
List box
Combo box
Table window
Picture
Scroll bar (horizontal and vertical)
Custom control
Rich Text control
Table window Column

Child objects cannot be parents of other objects, except for child table windows, which can have columns as
children.

Mnemonics
When the user presses a mnemonic key at the same time as the Alt key, the input focus moves to the object.
You can assign a mnemonic to background text, columns, radio buttons, push buttons, option buttons, group
boxes, and check boxes.
You can also use mnemonics with menu items. A mnemonic for a menu item does more than move the input
focus; it also invokes the menu item's actions.
Create a mnemonic by typing an ampersand character (&) before the character in the object's title that you
want to be the mnemonic. A mnemonic character appears in an object's title with an underscore.

The user can press Alt+A instead of clicking to invoke the push button's actions.
You can give a label (name) to a data field using background text. A background text mnemonic is associated
with a data field to move the input focus to that data field. For example, if the background text for the data
field dfName is &Name, pressing Alt+N moves the focus to dfName. The background text must come
immediately before the data field in the outline; the background text can appear visually anywhere in the
form window or dialog box.

Accelerators
An accelerator is a key that invokes the actions for a push button or menu item:
• You assign an accelerator to a push button using the Attribute Inspector. A cascading menu lists the keys
that you can assign.
• You assign an accelerator to a menu item in the Keyboard Accelerator section of the outline. Coding
Assistant lists the keys that you can assign.

Messages that Objects Receive


Most objects receive SAM_* messages. The tables in SAM_* summary on page 285 show the messages that
each object can receive.

115
MDI Window
You use an MDI window to create a workspace for an application. You can place form windows and top-level
table windows in the workspace. MDI windows are useful for managing a large number of top-level windows
that you need to display at the same time. This example has a toolbar and child windows (three table
windows):

A form or table window within an MDI window is called an “MDI child window”.
An MDI child window has a title bar, a menu, a sizing border, a system menu, and minimize and maximize
push buttons. However, an MDI child window does not have a menu bar. MDI child windows use the menu
bar of the MDI window. When an MDI child becomes active, its menu replaces the MDI window's menu.
Only one child MDI window is active at a time. An active MDI child has a highlighted title bar and it appears in
front of all other MDI child windows. MDI child windows can be minimized and appear at the bottom of the
MDI window as an icon. When an MDI child window is maximized, its title bar disappears and it use the MDI
window's title bar.
MDI means Multiple Document Interface, which is a user interface model created by Microsoft.
You can place an MDI window anywhere you can place a top-level window.

MDI Window Attributes


The table below describes the attributes for an MDI window.

Property Description

Object Name The name you use to refer to the MDI window in statements.

Object Title The name that appears on the MDI window's title bar.

Accessories If Yes, then the MDI window has a tool bar and a status bar and you can modify the
Enabled next six attributes, associated with the tool bar and status bar. If it is No, the next six
attributes cannot be edited. The default is No.

116
Property Description

Tool Bar Visible If Yes, a portion of the client area of the window is used to display the toolbar.

Tool Bar Size Either Default or a size that you specify.

Tool Bar Position By default, the toolbar is docked at the top of the client area. Other choices are Left,
Right, and Bottom.
Tool Bar Docking Indicates whether the tool bar is capable of being docked and undocked (free-
Enabled floating). Default value is No. You may also select Yes.
Tool Bar Docking If Tool Bar Docking Enabled is Yes, you can specify which sides of the parent window
Orientation are available for docking. Choices are Top, Bottom, Left, and Right.
Status Bar Visible If Yes, a portion of the bottom of the client area of the window is used to display the
status bar. You may also select No.
Automatically If Yes (default), the MDI window is created and displayed at application startup. If No,
Create you must call SalCreateWindow to create the MDI window.
Maximizable If Yes (default), the MDI window has a maximize button in the upper right corner. If No,
the MDI window does not have a maximize button and the user cannot maximize the
MDI window.
Minimizable If Yes (default), the MDI window has a minimize button in the upper right corner. If No,
the MDI window does not have a minimize button and the user cannot minimize the
MDI window.
System Menu If Yes (default), the MDI window has a system menu.

Resizable If Yes (default), the user can resize the MDI window using sizing pointers.

Initial State The window's state when created: Maximized, Minimized, or Normal (default).

Icon File A file that contains an icon used when the MDI window is minimized. The icon file
must be in *.ICO format.
Left Horizontal position of left edge of window.

Top Vertical position of top edge of window.

Width Width of window.

Height Height of window.

Allow child Set this property to Yes if you want this top-level window to allow docked windows..
docking Default value is No.
Docking This property is enabled only if the “Allow child docking” property is set to Yes. This
orientation property controls which directions can a child window dock itself to this top-level
window.

Outline Items
An MDI window outline has the following items:

117
MDI Window: <name>
Named Menus
Menu
Toolbar
Contents
Functions
Window Parameters
Window Variables
Message Actions

Contents
You can put form windows and top-level table windows in the contents section.

Menu
A menu bar in an MDI window is active when there is not an MDI child active that defines its own menu bar.
When an MDI child becomes active, its menu bar replaces the MDI window's menu in the MDI window's
menu bar.

Toolbar
When an MDI child becomes active, the MDI window continues to display its toolbar if it has one.

MDI Window Handles


The hWndMDI system variable contains the handle of the MDI window in the execution context.
The system variable hWndForm never refers to an MDI window. When used in the window functions or
message actions of an MDI window, hWndForm always contains the window handle of the MDI child window
executing the message actions or functions.

Multiple MDI Windows


An application can have more than one MDI window. You can create multiple instances of the same MDI
window.

Creating an MDI Window at Runtime


An MDI window can appear automatically when the application starts or you can create one with
SalCreateWindow:
Set hWndMyMDI = SalCreateWindow( mdiMine, hWndNULL )

Creating MDI Child Objects at Runtime


Call SalCreateWindow to create an instance of an MDI child window at runtime:
Call SalCreateWindow( frm1, hWndMyMDI )

SAM_Destroy
SQLWindows sends SAM_Destroy to an MDI window and its children in th following order:

118
MDI window
Form window or table window
Form window or table window children and grandchildren (columns)
Form window or table window toolbar children and grandchildren
MDI window toolbar children and grandchildren

Functions for MDI Windows


SalMDITile
This function tiles the child windows in an MDI window:
Call SalMDITile( hWndMyMDI, TRUE )
The first parameter is the window handle. The second parameter is a boolean that specifies how to tile the
child window:
• TRUE = tile windows vertically
• FALSE = tile windows horizontally

SalMDICascade
This function arranges the child windows of an MDI window in a cascading style:
Call SalMDICascade( hWndMyMDI )

SalMDIArrangeIcons
This function arranges the child window icons in an MDI window:
Call SalMDIArrangeIcons( hWndMyMDI )
This function only affects child windows that are minimized.

SalParentWindow
This is how SalParentWindow behaves with MDI windows:

SalParentWindow
Where called parameter Return
Toolbar child in MDI window hWndItem Handle of containing MDI
window (hWndMDI)
Top-level object in an MDI hWndForm Handle of containing MDI
window window (hWndMDI)

Windows Menu
A windows menu is a special type of popup menu that you use in MDI windows and their children. A windows
menu automatically lists all the MDI window's child windows without any coding. An end-user can shift the
focus to a different MDI child by selecting the child from the menu or by using its accelerator key.
You can add your own menu items to a windows menu.
The following is an example of a windows menu:

119
The developer specified the first four items in the menu in the same way as regular popup menu items.
SQLWindows added the last three items and the menu separator automatically.
The default title of the popup menu is “Windows”, but you can change it. This is the code in the outline for
the menu:
MDI Window: mdi1
...
Menu
...
Windows Menu: &Windows
...
Menu Item: &Tile Vertical
...
Menu Actions
Call SalMDITile( hWndForm, TRUE )
Menu Item: &Tile Horizontal
...
Menu Actions
Call SalMDITile( hWndForm, FALSE )
Menu Item: &Cascade
...
Menu Actions
Call SalMDICascade( hWndForm )
Menu Item: &Arrange Icons
...
Menu Actions
Call SalMDIArrangeIcons( hWndForm )

Form Window
Form windows are used to enter and display data. You can place child windows such as data fields, push
buttons, and background text on a form window. The following form window contains a toolbar, menus, data
fields, and background text:

120
Form Window Attributes
The table below describes the attributes for a form window.

Property Description

Object Name The name you use to refer to the form window in statements.

Object Title The name that appears on the form window's title bar.

Accessories Enabled If Yes, the form window has a toolbar and a status bar and the Accessories item is
enabled where you can turn off the toolbar or status bar. The default is no.
Accessories If Accessories Enabled is Yes, then you can modify the next six attributes, associated
with the tool bar and status bar. If it is No, the next six attributes cannot be edited.
Tool Bar Visible If Yes, a portion of the client area of the window is used to display the toolbar.

Tool Bar Size Either Default or a size that you specify.

Tool Bar Position By default, the toolbar is docked at the top of the client area. Other choices are Left,
Right, and Bottom.
Tool Bar Docking Indicates whether the tool bar is capable of being docked and undocked (free-
Enabled floating). Default value is No. You may also select Yes.
Tool Bar Docking If Tool Bar Docking Enabled is Yes, you can specify which sides of the parent window
Orientation are available for docking. Choices are Top, Bottom, Left, and Right.
Status Bar Visible If Yes, a portion of the bottom of the client area of the window is used to display the
status bar. You may also select No.
Display Style The visual appearance of child objects in the form window:
Default Uses the setting in the Window Defaults section of Global Declarations
(standard or etched)
Standard Child objects appear two-dimensional
Etched Child objects appear three-dimensional
Automatically Create If Yes (default), the window is created and displayed at application startup. If No, you
must call SalCreateWindow to create the window.

121
Property Description

Maximizable If Yes (default), the form window has a maximize button in the upper right corner. If
No, the form window does not have a maximize button and the user cannot
maximize the form window.
Minimizable If Yes (default), the form window has a minimize button in the upper right corner. If
No, the form window does not have a minimize button and the user cannot minimize
the form window.
System Menu If Yes (default), the form window has a system menu.

Resizable If Yes (default), the user can resize the form window using sizing pointers.

Initial State The window's state when created: Maximized, Minimized, or Normal (default).

Icon File A file that contains an icon used when the form window is minimized. The icon file
must be in *.ICO format.
Form Pages Displays a cascading menu where you can set the page dimensions and number of
pages to use when printing the form window with SalPrtPrintForm.
Left Horizontal position of left edge of window.

Top Vertical position of top edge of window.

Width Width of window.

Height Height of window.

Background Color The background color of the form window.

Text Color The color of text in the form window.

Font Name The font of text in the form window.

Font Size The font size of text in the form window.

Font Enhancement The font enhancement of text in the form window.

Allow child docking Set this property to Yes if you want this top-level window to allow docked windows..
Default value is No.
Docking orientation This property is enabled only if the “Allow child docking” property is set to Yes. This
property controls which directions can a child window dock itself to this top-level
window.

Dialog Box
You can use dialog boxes to let the user enter data, or to display warning or error messages. You can place
child windows such as data fields, push buttons, and background text in a dialog box.

122
A dialog box is like a form window, but it cannot be resized at runtime, it does not have a menu, and it does
not have minimize and maximize push buttons. Also, you cannot create a dialog box automatically when the
application starts. You must call SalCreateWindow or SalModalDialog to create a dialog box.
There are three types of dialog boxes: modeless, modal, and system modal.

Modeless
A modeless dialog box does not suspend application processing. The user can switch from the dialog box to
another window in the application or to a window in a different application.
You create a modeless dialog box with SalCreateWindow and close it with SalDestroyWindow.

Modal
A modal (also called application modal) dialog box suspends application processing until the user closes the
dialog box. The user cannot switch from the dialog box to another window in the application. However, the
user can switch to a window in a different application.
You create a modal dialog box with SalModalDialog and close it with SalEndDialog.

System Modal
A system modal dialog box suspends processing of the entire system until the user closes the dialog box. The
user cannot switch between the dialog box and another window in the application or to a window in a
different application.
You create a system modal dialog box with SalModalDialog and close it with SalEndDialog.

Owned and Ownerless Dialog Boxes


You can create a dialog box with or without an owner. When the dialog box has an owner:
• It always stays on top of the owner window
• When the owner window closes, the dialog box closes

123
• When the user minimizes the owner, the dialog box disappears; when the user restores the owner, the
dialog box reappears

Message Boxes
If the application only needs to display a simple message or needs simple input from the user, you can call
SalMessageBox to display a message box. For more about SalMessageBox, read the SQLWindows Function
Reference or the online help.

Dialog Box Attributes


Dialog boxes have the following attributes:

Property Description

Object Name The name you use to refer to the dialog box in statements.

Object Title The name that appears on the dialog box's title bar.

Allow Dock to Parent Whether this dialog box can be docked to its parent window. Default value is No. This
attribute is only enabled when Type of Dialog is Modeless.
Docking Orientation If Allow Dock to Parent is Yes, this attribute determines which edges of the dialog box
can be used in docking. More than one edge can be used. A drop-down combo box
displays all possible combinations of edges.
Accessories Enabled If Yes, the dialog box has a toolbar and a status bar and the Accessories item is
enabled where you can turn off the toolbar or status bar. The default is no.
Accessories If Accessories Enabled is Yes, then you can modify the next four attributes,
associated with the tool bar and status bar. If it is No, the next four attributes cannot
be edited.
Tool Bar Visible If Yes, a portion of the client area of the window is used to display the toolbar.

Tool Bar Size Either Default or a size that you specify.

Tool Bar Position By default, the toolbar is docked at the top of the client area. Other choices are Left,
Right, and Bottom.
Status Bar Visible If Yes, a portion of the bottom of the client area of the window is used to display the
status bar. You may also select No.
Display Style The visual appearance of child objects in the dialog box:
Default Uses the setting in the Window Defaults section of Global Declarations
(standard or etched)
Standard Child objects appear two-dimensional
Etched Child objects appear three-dimensional
Resizeable If Yes, the user can resize the dialog box at runtime, using the standard Windows
double- headed arrow cursor. If No, that cursor does not appear, and the dialog
cannot be resized. Default value is Yes.
Type of Dialog The type of dialog box: Modal (default), Modeless, or System modal.

124
Absolute Screen If Yes, the position of the dialog box is relative to the upper left corner of the screen.
Location If No, the position of the dialog box is relative to the owner of the dialog box (you
specify the owner in SalModalDialog or SalCreateWindow). If No and the dialog box
does not have an owner, the position of the dialog box is absolute (as if Yes).
Left Horizontal position of left edge of dialog box

Top Vertical position of top edge of dialog box

Width Width of dialog box

Height Height of dialog box

Vertical Scroll If Yes, the dialog box can be scrolled vertically. Only enabled when Resizeable is Yes.

Horizontal Scroll If Yes, the dialog box can be scrolled horizontally. Only enabled when Resizeable is
Yes.
Background Color The background color of the dialog box.

Text Color The color of text in the dialog box.

Font Name The font of text in the dialog box.

Font Size The font size of text in the dialog box.

Font Enhancement The font enhancement of text in the dialog box.

Allow dock to parent (Enabled only for modeless dialog boxes.) Set this property to Yes if you want this
dialog box to get docked and undocked. The value of this property can be changed
programmatically by a call to SalDlgSetDockStatus. Note: Even if docking is enabled,
the initial state of the dialog box will be floating. The application has to call
SalDlgSetDockStatus to dock this dialog box.
Docking orientation This property is enabled only if “Allow dock to parent” property is set to Yes. This
property controls which directions a dialog can dock itself to the top-level window.

Standard Dialogs
You can call these functions to display standard Windows dialog boxes:
• SalDlgChooseColor
• SalDlgChooseFont
• SalDlgOpenFile
• SalDlgSaveFile
The SQLWindows Function Reference describes these functions.

125
Message Boxes
You can use a message box instead of a dialog box when you only need a simple response from the user or
when you only need to display a message.

You do not create message boxes at design time. Instead, you call the SalMessageBox function. The
SQLWindows Function Reference describes SalMessageBox.

ActiveX Control
Chapter 20 – Introduction to COM and Writing COM Client Applications describes ActiveX controls.

Background Text
You use background text for titles, labels, and instructions. The following shows background text for a data
field:

126
At design time, you can edit background text by pressing the Shift key and clicking the right mouse button.
You can give a label (name) to a data field using background text. A background text mnemonic is associated
with a data field to move the input focus to that data field. For example, if the background text for the data
field dfName is &Name, pressing Alt+N moves the focus to dfName. The background text must come
immediately before the data field in the outline; the background text can appear visually anywhere in the
form window or dialog box.

Background Text Attributes


Background text has the following attributes:

Property Description

Object Title The title of the background text. Create a mnemonic by putting an ampersand (&)
before the letter that you want to be the mnemonic.
Visible If Yes (default), the background text is visible at runtime.
If No, the background text is not visible at runtime.
Location and Size Displays a cascading menu with the background text's position (top and left) and size
(width and height).
Justify The justification of the background text. The default is Left.

Background Color The background color of the background text.

Text Color The color of the background text.

Font Name The font of the background text.

Font Size The font size of the background text.

Font Enhancement The font enhancement of the background text.

Manipulating Background Text


A label is background text that comes immediately before a child object in the outline. Use these functions to
manipulate the label of a child object:
• SalEnableWindowAndLabel
• SalDisableWindowAndLabel
• SalGetWindowLabelText
• SalHideWindowAndLabel
• SalSetWindowLabelText
• SalShowWindowAndLabel

127
Check Box
When the user clicks a check box, it turns an option on or off. More than one check box can be on at the
same time.
The following shows check boxes with a group box:

Check Box Attributes


Check boxes have the following attributes:

Property Description

Object Name The name you use to refer to the check box in statements.

Object Title The title of the check box. Create a mnemonic by putting an ampersand (&) before
the letter that you want to be the mnemonic.
Visible If Yes (default), the check box is visible at runtime. If No, the check box is not visible
at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the check box's position (top and left) and size
(width and height).
Background Color The background color of the check box.

Text Color The color of the check box text.

Font Name The font of the check box text.

Font Size The font size of the check box text.

Font Enhancement The font enhancement of the check box text.

ToolTip This text will be displayed when the user hovers the mouse cursor over the check
box.

Child Table Window


Chapter 15 – Table Windows describes child table windows.

128
Combo Box
A combo box contains a data field and a list box. The list box contains predefined scrollable items that a user
chooses to fill the data field.

The list box part of a combo box can have these features:
• Sorted items
• Vertical scroll bar
• Can always be dropped
The data field part of a combo box can be editable or non-editable. If the data field is non-editable, there is
no space between the right side of the data field and the down arrow; if the data field is editable, there is a
space between the right side of the data field and the down arrow.
One or no items in a combo box list are selected at any given time.

User Interface
This is the user interface for a combo box:
• Click an item in the list box to select it, put it in the data field part of the combo box, and close the list
box.
• The arrow keys scroll the list box, change the selection, and the contents of the data field part of the
combo box. If the list box is not down, the arrow keys change the selection in the data field.
• If the combo box is editable, press a key to scroll to an item that starts with that letter.
• Alt+up arrow and Alt+down arrow open and close the list box.

Combo Box Attributes


Combo boxes have the following attributes:

Property Description

Object Name The name you use to refer to the combo box in statements.

129
Property Description

Visible If Yes (default), the combo box is visible at runtime.


If No, the combo box is not visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the combo box's position (top and left) and size
(width and height).
String Type The data type of the combo box:
String—Default
Long String—Use to read and write SQL database columns longer than 254 bytes.
Max Data Length The maximum number of characters that the user can enter in the data field part of
the combo box. The maximum length of a String or Long String data type varies and
depends on the number of child objects in the parent window. This option is only
available if the combo box is editable.
The maximum number of characters that can be in the list box part is 54 kilobytes
(for all items combined).
Important: The value you specify in Max Data Length is the maximum capacity of the
object, not the number of bytes that SQLWindows allocates for the object’s value. At
runtime, SQLWindows allocates the number of bytes in the actual value of the object
at any one time. Also, when you set a variable or another object with the value,
SQLWindows only copies the number of bytes in the actual value, not the number of
bytes in the Max Data Length setting of the source object.
Editable If Yes (default), the user can enter or edit text in the data field part of the combo box.
If No, the user cannot enter or edit text.
At runtime, you can change the setting of this property with SalEnableWindow and
SalDisableWindow.
Input Mask Input validation criteria for the data field (see Chapter 11 – Formatting and
Validating).
Sorted If Yes, (default) the items in the list box part of the combo box are sorted. The sort
order (collating sequence) is determined by the Windows character set and the
country setting.
Always Show List If Yes, the list box part of the combo box is always displayed.
If No (default), the list box only drops down when the user clicks the arrow.
Vertical Scroll If Yes (default), the list box part of the combo box has a vertical scroll bar on the right
side.
Background Color The background color of the combo box.

Text Color The color of text in the combo box.

Font Name The font of text in the combo box.

Font Size The font size of text in the combo box.

Font Enhancement The font enhancement of text in the combo box.

ToolTip This text will be displayed when the user hovers the mouse cursor over the combo
box.
130
Property Description

Auto Fill If Yes, the user can select an option from the combo box by typing the first letter(s).
The rest of the text fills in automatically.
If No (default), the combo box scrolls to the closest match, but the user's text entry
will not auto-complete.

Custom Control
Chapter 24 – Custom Controls describes custom controls.

Data Field
A data field displays output or accepts input. The following shows a data field with background text:

You can give a label (name) to a data field using background text. A background text mnemonic is associated
with a data field to move the input focus to that data field. For example, if the background text for the data
field dfName is &Name, pressing Alt+N moves the focus to dfName. The background text must come
immediately before the data field in the outline; the background text can appear visually anywhere in the
form window or dialog box.
A non-editable data field only receives SAM_Create, SAM_Destroy, and SAM_Timer.

Data Field Attributes


Data fields have the following attributes:

Property Description

Object Name The name you use to refer to the data field in statements.

Visible If Yes (default), the data field is visible at runtime. If No, the data field is not visible at
runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the data field's position (top and left) and size (width
and height).
Data Type The data type of the data field:
Date/Time Number
String – Default
Long String – Use to read and write SQL database columns longer than 254 bytes.

131
Property Description

Max Data Length The length of the data field. The default is 100. The maximum length of a String or
Long String data type is 32 kilobytes.
Important: The value that you specify in Max Data Length is the maximum capacity
of the object, not the number of bytes that SQLWindows allocates for the object’s
value. At runtime, SQLWindows allocates the number of bytes in the actual value of
the object at any one time. Also, when you set a variable or another object with the
value, SQLWindows only copies the number of bytes in the actual value, not the
number of bytes in the Max Data Length setting of the source object.
Editable If Yes (default), the user can enter or edit text in the data field. If No, the user cannot
enter or edit text.
At runtime, you can change the setting of this property with SalEnableWindow and
SalDisableWindow.
Border If Yes (default), the data field has a border. If No, the data field does not have a
border.
Justify The justification for the data field. The default is left.

Format The output format of the data field. The default is unformatted (see Chapter 11 –
Formatting and Validating).
Input Mask Input validation criteria for the data field (see Chapter 11 – Formatting and
Validating).
Country The country profile for the data field (see Chapter 11 – Formatting and Validating).

Background Color The background color of the data field.

Text Color The color of text in the data field.

Font Name The font of text in the data field.

Font Size The font size of text in the data field.

Font Enhancement The font enhancement of text in the data field.

ToolTip This text will be displayed when the user hovers the mouse cursor over the data
field.

Frame
A frame is a border that surrounds an object. A frame is visual only. It does not receive mouse or keyboard
input and it does not have a message actions section. The following frame has a raised-shadow border
style:

132
Frame Attributes
Frames have the following attributes:

Property Description

Visible If Yes (default), the frame is visible at runtime. If No, the frame is not visible at
runtime.
Location and Size Displays a cascading menu with the frame's position (top and left) and size (width
and height).
Corners The corner shape of the frame (square or round). The default is square.

Border Style The border style of the frame (no border, solid, drop-shadow, raised-shadow,
etched). The default is solid.
Border Thickness The thickness of the border. The default is 1.

Background Color The background color of the frame

Border Color The border color of the frame

Grid
The grid control is implemented as an outlook-like table view. There are two ways you can add a grid control
to your form window:
• Drop a grid control onto your form window
• Add a child grid class and then add the grid control to your form window
The grid control supports the reuse of the colwnn class or colwnn control.
To adda column class or colwnn control to a grid, right-click the Colwnns folder, select New, and then select
either Colwnn orthe colwnn class name.

133
Grid Attributes
Grids have the following attributes:

Property Description

Visible If Yes (default), the grid is visible at runtime. If No, the grid is not visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Left Horizontal position of left edge of grid.

Top Vertical position of top edge of grid.

Width Specifies the width of the grid control.

Height Specifies the height of the grid control.

Lines Per Row By default, the amount of lines per row is one. When you set the lines per row to two
or more, text wraps in columns where you turn on Word Wrap (See Column
Attributes on page 382).
Allow Row Sizing Allows you to resize a row. It is turned off by default.

Background Color Displays a palette where you can set the background color for the grid contents.

Text Color Sets the color of text in the displayed grid contents.

Font Name The font of the text in the displayed grid contents.

Font Size The font size of text in the displayed grid contents.

Font Enhancement The font enhancement of text in the displayed grid contents.

Discardable If Yes (default), rows in the table window cache are discardable. SQLWindows makes
space for new rows by discarding unused rows. If No, SQLWindows does not
automatically discard rows and keeps all data in the cache.
Max Rows in Memory The maximum number of records (table rows) that are held in memory.

In WPF applications, when a top-level grid window’s “Resizable” property is set to “No,” the maximize and
minimize buttons will not be visible.
The “System” property is not supported in WPF, so the close button will still be visible even when System is
set to “No.”
Child table control and child grid control are mapped to single telerik grid control. The default properties of
child grid control are effective at runtime.

Context Menu, Sorting, Grouping


By default, the grid includes a context (right-click) menu that contains items for sorting and grouping. To
disable the context menu, return FALSE from SAM_ContextMenu:

134
On SAM_ContextMenu Return false
Once you disable the context menu, you can still use sorting or grouping via Sal functions (see following
section).

Grouping in the Grid via Sal Functions


The grouping for a grid column can be enabled and disabled using the SalTblSetColumnFlags function with
the COL_IsGroupBy flag. Note that when the flag is turned off, by default the column will be placed at the far
right of the grid. The SalTblSetColumnPos function can be used to place the column at the desired position.
See the following code sample:
Actions
! Set Grouping:
Call SalTblSetColumnFlags( grid1.fname, COL_IsGroupBy, TRUE)
! Ungroup & return column to proper position:
Call SalTblSetColumnFlags( grid1.fname, COL_IsGroupBy, FALSE)
Call SalTblSetColumnPos( grid1.fname, 1)
You can then call SalTblSortRows if you want to sort the rows.

API Support
The grid control supports the following grid-specific APIs:
• SalGridPrint
• SalGridPrintPreview
• SalGridGetCellProp
• SalGridGetColumnType
• SalGridSetCellPicture
• SalGridSetCellProp
• SalGridSetColumnType
• SalGridSortRowsMultiColumn
The grid control also supports all child table window APIs (SalTblXXX) except the following:
• SalTblDefineSplitWindow
• SalTblQuerySplitWindow
• SalTblScroll
• SalTblSetLockedColumns
For details on these APIs, go to sqlwindows menu item Help > Help Topics.

Grid Column Types


Columns in a grid can be of the following types:
• Standard *
• Drop Down List *

135
• Popup Edit *
• Checkbox *
• Radio Button
• CheckBox Title
• Progress
• Password
• Duration
• Date Time
• Hyperlink
• Button
• Picture
* Table windows can also have columns of these four types

Group Box
You use a group box to label a set of related objects such as radio buttons. The following radio buttons have a
group box around them:

At design time, you can edit the title of a group box by pressing the Shift key and clicking the right mouse
button.

Group Box Attributes


Group boxes have the following attributes:

Property Description

Object Title The title of the group box. Create a mnemonic by putting an ampersand (&) before
the letter that you want to be the mnemonic.
Visible If Yes (default), the group box is visible at runtime. If No, the group box is not visible
at runtime.
Location / Size The group box's position (top and left) and size (width and height)

Line Thickness The thickness of the group box border (1-8)

136
Property Description

Background Color The background color of the group box

Text Color The color of the group box text

Line Color The color of the group box border

Font Name The font of the group box text

Font Size The font size of the group box text

Font Enhancement The font enhancement of the group box text

Group Box Style The style of the group box. The following options haveline thicknesses 1, 2, 3, and 4.

The “System” option is a placeholder for an upcoming feature in future versions.

Line
You can draw a line on a form window or dialog box at any angle. A line is visual only; it does not receive
mouse or keyboard input and it does not have a message actions section. The following shows a line
separating the objects:

Line Attributes
Lines have the following attributes:

Property Description

Visible If Yes (default), the line is visible at runtime. If No, the line is not visible at runtime.

Coordinates The X and Y coordinates of the start and end of the line

137
Property Description

Line Style The visual appearance of the line (solid or etched)

Line Thickness The thickness of the line. The default is 1.

Line Color The color of the line

List Box
A list box displays a single-column list that lets the user select one or more items. A list box is read-only.
You can create list boxes with these features:
• Single selection or multiple selection. With multiple selection, more than one item can be selected at a
time.
• Vertical and horizontal scroll bar.
• Sorted items

User Interface
A single selection list box has this user interface:
• One item in the list box is always selected.
• Click an item to select it or deselect it.
• The arrow keys move the selection and scroll the list box.
• Press Page Up or Page Down to move the selection and scroll the list box.
• Press a key to scroll to an item that starts with that letter and select the item .
A multiple selection list box has this user interface:
• None, one, or more than one item in the list box can be selected at a time.
• Click an item to select it; the previous selection remains.
• Click to deselect an item.
• The space bar does the same thing as a mouse click: selects or deselects.
• The arrow keys scroll the list box without changing the selection.
• Page Up or Page Down scrolls the list box without changing the selection.
• Press a key to scroll to an item that starts with that letter without changing selections.

List Box Attributes


List boxes have the following attributes:

138
Property Description

Object Name The name you use to refer to the list box in statements.

Visible If Yes (default), the list box is visible at runtime. If No, the list box is not visible at
runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the list box's position (top and left) and size (width
and height).
Multiple Selection If Yes, user can select more than one item at a time in the list box. The default is no.

Sorted If Yes (default), the items in the list box are sorted. The sort order (collating
sequence) is determined by the Windows character set and the country setting.
Vertical Scroll If Yes (default), the list box has a vertical scroll bar on the right side when there are
more entries than can fit in the list box.
Horizontal Scroll If Yes, SalListAdd adds a horizontal scroll bar to the list box if the string being added is
wider than the list box. The default is No.
Background Color The background color of the list box.

Text Color The color of text in the list box.

Font Name The font of text in the list box.

Font Size The font size of text in the list box.

Font Enhancement The font enhancement of text in the list box.

ToolTip This text will be displayed when the user hovers the mouse cursor over the list box.

Multiline Field
A multiline field accepts and displays multiple lines of data. The following shows a multiline field with
background text:

The user can press Enter or Ctrl+Enter to move the cursor to the next line when entering or editing text in a
multiline field.

139
Multiline Field Attributes
Multiline fields have the following attributes:

Property Description

Object Name The name you use to refer to the multiline field in statements.

Visible If Yes (default), the multiline field is visible at runtime. If No, the multiline field is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the multiline field's position (top and left) and size
(width and height).
String Type The data type of the multiline field:
String Default
Long String Use to read and write SQL database columns longer than 254 bytes
Max Data Length The length of the multiline field. The default is 1000. The maximum length of a String
or Long String data type is 32 kilobytes.
Important: The value that you specify in Max Data Length is the maximum capacity
of the object, not the number of bytes that SQLWindows allocates for the object’s
value. At runtime, SQLWindows allocates the number of bytes in the actual value of
the object at any one time. Also, when you set a variable or another object with the
value, SQLWindows only copies the number of bytes in the actual value, not the
number of bytes in the Max Data Length setting of the source object.
Editable If Yes (default) the user can enter or edit text in the multiline field. If No, the user
cannot enter or edit text in the multiline field.
At runtime, you can change the setting of this property with SalEnableWindow and
SalDisableWindow.
Border If Yes (default), the multiline field has a border.

Word Wrap If Yes, the text in the multiline field wraps. The default is no.

Vertical Scroll If Yes (default), the multiline field has a vertical scroll bar on the right side.

Background Color The background color of the multiline field.

Text Color The color of text in the multiline field.

Font Name The font of text in the multiline field.

Font Size The font size of text in the multiline field.

Font Enhancement The font enhancement of text in the multiline field.

ToolTip This text will be displayed when the user hovers the mouse cursor over the multiline
field.

140
Navigation Bar
A navigation bar contains labeled buttons and an associated pane for each button, much like a tab bar control
and its tabs. A popular example of a Navigation Bar control is the left-hand side of Microsoft Outlook. In fact,
the navigation bar can be used to create applications that resemble Microsoft Outlook in appearance and
functionality (see the DemoApp in your \Samples\SQLWindows\User Interface\NavBar directory).
Like the pages of a Tab Bar, the panes of a Navigation Bar can contain child items. However, unlike tab pages,
navigation panes typically occupy a rather small, vertically-oriented space. They do not include a “right-hand
side,” but you can easily use a form window to display as a “right-hand side” associated with each pane
(again, see the DemoApp).
A navigation bar contains an indefinite number of panes, which are referenced in function calls by a zero-
based index number. Each pane can contain an indefinite number of groups, which are also identified by a
zero-based index (the count starts over on each pane). Groups are delineated by pane separators, which can
be added to a pane via the outline. The pane or group closest to the top (in outline or layout view) has an
index of zero. If you reorder the panes in either the outline or layout view, the other view will automatically
update to reflect your changes.
The user can expand and collapse groups by clicking on the group’s separator, which appears immediately
above the group. If you place controls above the first (highest) separator, these controls will not pertain to a
separator, and will not be collapsible by clicking. If you want the group to be collapsible by clicking a
separator, you must place a separator above the controls, at the top of the pane. The topmost group will
retain its index of zero either way, and a group without a separator can still be collapsed and expanded by
calling SalNavExpandGroup.
See the online help for documentation on the SalNav functions.

Navigation Bar Attributes


Navigation bars have the following attributes:

Property Description

Visible If Yes (default), the navigation bar is visible at runtime. If No, the navigation bar is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Left Horizontal displacement of the navigation bar from the left edge of the parent
window. Default is zero. Enter a number to specify the horizontal position of the tab
bar (in inches).
Top Vertical displacement of the navigation bar from the top edge of the parent window.
Default is zero. Enter a number to specify the vertical position of the tab bar (in
inches).
Width Width of the navigation bar in inches. Default is 3.6.

Height Height of the navigation bar in inches. Default is 4

Tile to Parent If Yes, the navigation bar expands to fill its parent window. Default is No.

141
Property Description

ToolTip This text will be displayed when the user hovers the mouse cursor over the
navigation bar.

Navigation Pane Attributes


Navigation panes have the following attributes:

Property Description

Pane Title The text that will appear on the button and title for this navigation pane.

Expanded Picture File File name of the image to display for this pane when it is expanded.
Name
Collapsed Picture File File name of the image to display for this pane when it is collapsed.
Name

Option Button
Option buttons are rectangular buttons that display an image and text on a window, toolbar, or palette.
Option buttons do not display in applications that are running in web mode under Web Application Manager,
so do not use option buttons in that situation.

Option Button Attributes


Option buttons have the following attributes:

Property Description

Object Name The name you use to refer to the option button in statements.

Object Title The name that appears as the option button's title.

Visible If Yes (default), the option button is visible at runtime. If No, the option button is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the option button's position (top and left) and size
(width and height).
File Name Name of the image file to be displayed in the button. In the attribute inspector, click
the "..." button to browse for an image file.
Image Style Whether the object is single image or multiple image (see Option Button Images on
page 144).

142
Property Description

Image Size to Fit Determines whether the image will be resized when its associated button is resized.
None: This is the default value. No image scaling occurs.
Size to Fit: Stretches or shrinks the image to fit in the available space.
Size for Best Fit: Sizes the image to fit either the width or height of the available
space.
Picture Transparent Displays a palette where you select a color in the image that you want to replace
Color with the background color of the option button. This makes parts of the image
transparent. This applies to bitmaps only (*.BMP). The default is None.
At runtime, you can call SalColorGet and SalColorSet to get or set the transparent
color of the bitmap. COLOR_IndexTransparent identifies the color. To clear the
transparent color, pass COLOR_None to SalColorSet.
Button Style Displays a cascading menu where you select the option button style (Palette, Radio,
or Check).
Background Color The background color of the option button

Text Color The color of text in the option button

Font Name The font of text in the option button

Font Size The font size of text in the option button

Font Enhancement The font enhancement of text in the option button

Button Appearance The appearance of the borders around the button. Choices are Standard (relief-style
borders) or Flat (no borders). Default is Standard.
Image Alignment The position of an image on the button

Text Alignment The position of text on the button

Text Image Relation The position of the text and image in relation to each other (image above, text
above, image before, etc.) See Image and Text Alignment on page 148.

Option Button Values


Like radio buttons and check boxes, option buttons have a boolean value:
• When an option button is down, its value is TRUE
• When an option button is up, its value is FALSE

Option Button Styles


There are three styles of option buttons:
• Radio
• Check box
• Palette

143
You set the option button style in the Attribute Inspector.
You use radio-style option buttons and check box-style option buttons in any place where you can use
standard radio buttons and check boxes. Radio-style option buttons behave like radio buttons and check
box-style option buttons behave like check boxes.
You place palette-style option buttons in a modeless dialog box to create a floating dialog like the toolbars in
SQLWindows and in other Windows products. Palette-style option buttons behave like radio buttons, but
SQLWindows paints them differently and they do not have a focus frame.
The attributes of each option button style are the following:

Style Focus Frame Behavior State Changes

Radio Yes Radio Up

Check Box Yes Check Box Up

Palette No Radio Down

• Focus frame means whether the option button displays a focus frame when it has the focus.
• Behavior means whether the option button behaves like a check box or a radio button. When the user
selects a radio button in a group, the others are deselected. The user can select more than one check box
in a group.
• State changes means whether the option button changes state when the user presses the mouse button
(down) or when the user releases the mouse button (up). SQLWindows sends SAM_Click when the state
changes.

Option Button Images


If an option button has an image, there are two image styles that you can use:
• Single
• Multiple image
You set the image file and the image style in the Attribute Inspector.

Images and titles


When an option button has both a title and an image, SQLWindows displays the title is at the bottom of the
option button. SQLWindows does not display the default title (“untitled”) when an option button has an
image.

Storing image files


SQLWindows must be able to find the images in external files at design time. When you make an *.EXE
version of an application, SQLWindows copies the images from the external files into the application. You do
not need to distribute the external files with production versions of an application.

Image size
You can set properties for image resizing behavior by using the Attribute Inspector. See Image Size to Fit,
above.

144
Images in disabled option buttons
If the image in an option button is a bitmap (not an icon) and the Image Style is Single, SQLWindows grays the
image when the option button is disabled (by implicitly calling SalDisableWindow). This gives the bitmap a
“tin foil” look. For a different disabled appearance, use a multiple-image bitmap.

Using 256-color bitmaps


For form windows or dialog boxes with multiple images (in picture objects, push buttons, or option buttons),
use the Send to Back command on the object that you want to have the best color quality. SQLWindows
creates a single palette for painting all objects on a form window or dialog box. This palette is based on the
bottom-most object. This only affects 256-color images.

Single-Image Style
For the single-image style, SQLWindows creates an up, down, and disabled picture from a single image. The
image file can be an icon (*.ICO) or a bitmap (*.BMP).

Multiple-Image Style
A multiple-image bitmap gives you complete control over the look of an option button, but you must
draw four images in the bitmap. SQLWindows expects the bitmap file for the option button to contain
images for these states:
• Image when unchecked/up on a color display.
• Image when checked/down on a color display.
• Image when disabled on a color display.
• Image for monochrome display. SQLWindows inverts this image when the option button is checked or
down and dithers it when the option button is disabled.
A multiple-image file must be a bitmap (*.BMP). Arrange the four images vertically in the bitmap. In each
image, use the same width and the same height.
To make a multiple-image bitmap template:
1. Create a white bitmap of the desired size. SQLWindows finds the height of each image by dividing four
into the height (in pixels) of the bitmap. Calculate the height as:
4 * (ImageHeight + 1)
In Microsoft Paint, you can set the size of the bitmap with Image > Attributes.
2. Draw a single-pixel horizontal line between each image and after the last image to delimit them.
SQLWindows does not draw these lines when it displays the option button.
3. Save this bitmap as a template for drawing other multiple-image bitmaps.
4. To create a new bitmap, open the template, save it with a new name, and then fill in each of the four
images.

File Open Dialog


When you select File Name in the Picture Contents cascading menu, SQLWindows displays this dialog where
you can select the name of a file (*.ICO or *.BMP) that contains an image.
145
Picture
If you check Append Path To File Name, SQLWindows stores the full path name of the image file in the
application. If you do not check Append Path To File Name, SQLWindows only stores the name of the image
file.
Chapter 16 – Pictures describes picture objects.

Push Button
When the user clicks a push button, the application performs an action.

At design time in a Layout tab or a Preview window you can edit the title of a push button by pressing the
Shift key and clicking the right mouse button.

Push Button Attributes


Push buttons have the following attributes:

Property Description

Object Name The name you use to refer to the push button in statements.

Object Title The title of the push button. Create a mnemonic by putting an ampersand (&) before
the letter that you want to be the mnemonic.
Visible If Yes (default), the push button is visible at runtime. If No, the push button is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the push button's position (top and left) and size
(width and height).
File Name Name of the image file to be displayed in the button. In the attribute inspector, click
the "..." button to browse for an image file.
Image Style Whether the object is single image or multiple image (see Images in Push Buttons on
page 147).
Picture Contents Displays a cascading menu where you enter a description, specify the name of the
file that contains an image, and set the image style (single or multiple).

146
Property Description

Image Size to Fit Determines whether the image will be resized when its associated button is resized.
None: This is the default value. No image scaling occurs.
Size to Fit: Stretches or shrinks the image to fit in the available space.
Size for Best Fit: Sizes the image to fit either the width or height of the available
space.
Picture Transparent Displays a palette where you select a color in the image that you want to replace
Color with the background color of the option button. This makes parts of the image
transparent. This applies to bitmaps only (*.BMP). The default is None.
At runtime, you can call SalColorGet and SalColorSet to get or set the transparent
color of the bitmap. COLOR_IndexTransparent identifies the color. To clear the
transparent color, pass COLOR_None to SalColorSet.
Keyboard Accelerator The accelerator that activates the push button. None is the default. The table below
lists The keyboard accelerators.
Background Color Displays a palette where you can set the color of the background (the area of the
push button not covered by an image).
Text Color The color of text in the push button title.

Font Name The font of text for the push button.

Font Size The font size of text for the push button.

Font Enhancement The font enhancement of text for the push button.

Button Appearance The appearance of the borders around the button. Choices are Standard (relief-style
borders) or Flat (no borders). Default is Standard.
ToolTip This text will be displayed when the user hovers the mouse cursor over the push
button.
Image Alignment The position of an image on the button

Text Alignment The position of text on the button

Text Image Relation The position of the text and image in relation to each other (image above, text
above, image before, etc.)

Accelerators
Function Keys Other Keys

F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12 Enter, Esc

Images in Push Buttons


Push buttons can display bitmaps or icons. You specify the name of the icon or bitmap in the Picture Contents
cascading menu in the Attribute Inspector.

147
Push button title
When a push button contains an image, SQLWindows displays its title in the bottom of the push button by
default. SQLWindows does not display the default title (“untitled”) when a push button contains an image.
At design time, SQLWindows displays the image centered, in actual size. You can use the SalPic* functions to
change a push button's image or its characteristics at runtime.

Image and Text Alignment


The last three attributes in the push button attribute inspector (see the table above) allow you to reposition
the text and image in a push button. These attributes are Image Alignment, Text Alignment, and Text Image
Relation. Use these attributes to customize your pushbuttons. Here are a few examples:

The three attributes are interrelated. Text Image Relation must always be set to something other than
"Default" for Image Alignment and Text Alignment to have an effect.

Image size
You can set properties for image resizing behavior by using the Attribute Inspector. See Image Size to Fit,
above.

Storing image files


SQLWindows must be able to find the images in external files at design time. When you make an *.EXE
version of an application, SQLWindows copies the images from the external files into the application. You do
not need to distribute the external files with production versions of an application.

Images in disabled push buttons


If an image in a push button is a bitmap (not an icon) and the Image Style is Single, SQLWindows grays the
image when the push button is disabled (by implicitly calling SalDisableWindow). This gives the bitmap a “tin
foil” look. For a different disabled appearance, use a multiple-image bitmap.

Using 256-color bitmaps


For form windows or dialog boxes with multiple images (in picture objects, push buttons, or option buttons),
use the Send to Back command on the object that you want to have the best color quality. SQLWindows
creates a single palette for painting all objects on a form window or dialog box. This palette is based on the
bottom-most object. This only affects 256-color images.

Multiple-image push buttons


You can use a multiple-image bitmap in a push button. If you set the Image Style of a push button to Multiple
(instead of Single), then SQLWindows expects the *.BMP file associated with the push button to contain
multiple images. A setting of Multiple does not affect the behavior of *.ICO files.
148
A multiple-image bitmap gives you complete control over the look of a push button, but you must draw three
images in the bitmap. SQLWindows expects the bitmap file for the push button to contain images for these
states:
• Image when enabled on a color display
• Image when disabled on a color display
• Image for a monochrome display. This is grayed when the push button is disabled.
A multiple-image file must be a bitmap (*.BMP). Arrange the 3 images vertically in the bitmap. In each image,
use the same width and the same height.
To make a multiple-image bitmap template:
1. Create a white bitmap of the desired size. SQLWindows finds the height of each image by dividing three
into the height (in pixels) of the bitmap. Calculate the height as:
3 * (ImageHeight + 1)
In Microsoft Paint, you can set the size of the bitmap with Image, Properties.
2. Draw a single-pixel horizontal line between each image and after the last image to delimit them visually.
SQLWindows does not draw these lines when it displays the push button.
3. Save this bitmap as a template for drawing other multiple-image bitmaps.
4. To create a new bitmap, open the template and save it with a new name and then fill in each of the three
images.

Radio Button
When the user clicks a radio button, it turns an option on or off.
You use a group of radio buttons for mutually exclusive options. Only one radio button in a group can be on at
a time. When the user clicks a radio button in the group, the others are turned off.
When a group of radio buttons is contiguous, but processed as two different groups, you must use a group
box, as shown in the following:

The user can press Tab to move to a checked radio button in a group and then use the arrow keys to move the
input focus to another radio button in the group.

149
Radio Button Attributes
Radio buttons have the following attributes:

Property Description

Object Name The name you use to refer to the radio button in statements.

Object Title The title of the radio button. Create a mnemonic by putting an ampersand (&) before
the letter that you want to be the mnemonic.
Visible If Yes (default), the radio button is visible at runtime. If No, the radio button is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the radio button's position (top and left) and size
(width and height).
Background Color The background color of the radio button.

Text Color The color of text for the radio button.

Font Name The font of text for the radio button.

Font Size The font size of text for the radio button.

Font Enhancement The font enhancement of text in the radio button.

ToolTip This text will be displayed when the user hovers the mouse cursor over the radio
button.

Rich Text
Rich text is a standard format for displaying, printing, and exchanging text. Many vendors implement rich text
as an intermediary format for text documents. Microsoft defined and maintains the rich text specification
(they generally update it with each release of Microsoft Word) and have made the specification publicly
available.

The rich text control includes a toolbar, text editing area, ruler, and status bar. It supports static, program
generated, and user-entered text, as well as images.
150
You can use the control to create a basic word processor by placing it on a window, setting a few properties,
and providing common dialogs, such as open, save, and print. The control, however, is not meant to be a
replacement for full-fledged tools, such as Star Office, Word, or Word Perfect.

Note: The link and unlink buttons do not appear in the Rich Text toolbar in a WPF application.
The underlying control for WPF does not support this feature.

API Support
The rich text control supports all SalRTFXXX APIs.
For details on these APIs, go to the sqlwindows menu item Help > Help Topics.

Messaging
Messages for the rich text control are the following:

Message Description

SAM_RTFFileExists This event occurs when the document in the Rich Text Edit control is saved to a file,
but that file already exists.
SAM_RTFFileModified When the first change is made to the contents of the RichTextEdit control and it has
not been saved. In the modified event script you can set a flag indicating that the
document needs to be saved.

Rich Text Attributes


Rich text controls have the following attributes:

Property Description

Visible If Yes (default), the control is visible. If No, the control is not visible.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Background Color The numeric value of the background color of the text editing area. Values are –2 to
16,777,215.
Border If yes, the rich text control has a bord. If no, then the control has no border.

Left Margin The width of the left margin on the printed page.

Right Margin The width of the right margin on the printed page.

Top Margin The width of the top margin on the printed page.

Bottom Margin The width of the bottom margin on the printed page.

Editable If yes, users can edit the content, including text and input files. If no, the user cannot
edit the content.

151
Property Description

Horizontal Scroll Bar If yes, the horizontal scroll bar displays. If no, the scroll bar does not display.
Enables
Vertical Scroll Bar If yes, the vertical scroll bar displays. If no, the scroll bar does not display.
Enabled
Resizable If yes, users can resize the control. If no, users cannot resize the control.

Tool Bar Visible If yes, the formatting toolbar is visible. If no, the bar is not visible.
The toolbar appears above the editing area. If the pop-up menu is enabled, users can
use it to turn toolbar display on and off (see the PopMenu property).
Ruler Bar Visible If yes, the ruler bar is visible. If no, the bar is not visible.
The ruler bar appears above the editing area. If visible, the user can use it to see
measurements while setting tabs and margins on the tab bar (see the TabBar
property).
Status Bar Visible If yes, the status bar is visible. If no, the bar is not visible.

Text Color The default color of text in the control.

Left The position of the rich text control from the left edge of the parent window.

Top The position of the rich text control from top edge of the parent window.

Width The width of the rich text control.

Height The height of the rich text control

String Type The data type of the rich text control:


String—Default
Long String—Use to read and write SQL database columns longer than 254 bytes
Max Data Length The maximum number of characters that the user can enter in the text area of the
rich text control. The maximum length of a String or Long String data type varies and
depends on the number of child objects in the parent window.
Important: The value that you specify in Max Data Length is the maximum capacity
of the object, not the number of bytes that SQLWindows allocates for the object’s
value. At runtime, SQLWindows allocates the number of bytes in the actual value of
the object at any one time. Also, when you set a variable or another object with the
value, SQLWindows only copies the number of bytes in the actual value, not the
number of bytes in the Max Data Length setting of the source object.
ToolTip This text will be displayed when the user hovers the mouse cursor over the rich text
control.

152
Scroll Bars
You can add vertical and horizontal scroll bars to an application.

A scroll bar has an associated numeric value:


• When a user clicks a scroll bar arrow one time, the integer value of the scroll bar increases or decreases
by the line unit, and the scroll box moves accordingly.
• When a user clicks the scroll bar area one time, the value increases or decreases by the page unit and the
scroll box moves accordingly.
• When a user drags the scroll box, the scroll bar value increases or decreases accordingly.
A scroll bar also has a range, which is a pair of integers that represent the scroll bar's minimum and maximum
value. When the scroll box is at the top (or left) of the scroll bar, the position of the scroll box is the minimum
value of the range. When the scroll box is at the bottom (or right) of the scroll bar, the position of the scroll
box is the maximum value of the range.

Scroll Bar Attributes


Scroll bars have the following attributes:

Property Description

Object Name The name you use to refer to the scroll bar in statements.

Visible If Yes (default), the scroll bar is visible at runtime. If No, the scroll bar is not visible at
runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the scroll bar's position (top and left) and size (width
and height).
ToolTip This text will be displayed when the user hovers the mouse cursor over the scroll bar.

153
Status Bar
You can place a status bar at the bottom of a top-level window or MDI window. The status bar shows the
setting of the Num Lock, Scroll Lock, and Caps Lock keys.

To display a status bar, set the Accessories Enabled attribute to Yes for the top-level window or MDI window.
You can turn the status bar on and off with SalStatusSetVisible. You can display a message in a status bar with
SalStatusSetText. You can retrieve the text in a status bar with SalStatusGetText.

Menu Status Text


These outline items have a Status Text property:
• Popup menus
• Menu items
• Object menu
• Windows menu
• Named popup menu
If a window with one of these types of menu items has a status bar, SQLWindows displays the status text
when the user selects the menu item with the mouse.
Popup menus that you create with SalTrackPopupMenu also display the status text when the user selects the
menu item with the mouse.

Tab Bar
The Tab Bar control is a container object. Each Tab Bar control can have zero or more tab pages, and each tab
page can contain an indefinite number of child objects and have an associated icon.

When you create a Tab Bar control, it initially has zero or one tab pages (zero pages if you create it from the
tree view; one page if you create it from the controls palette in Layout view). As you add pages, their tabs

154
will appear in the Layout view. Click on a tab to view its page, and drag objects onto a page to make them
child objects of the page. Note that child objects that exceed the border of the tab page will be clipped.
A child object can be associated with more than one tab page. To associate an object with a tab page, select
the tab page in the outline, right click on it, and select “Add Next Level.” Then choose the child object you
want to associate with this page (see the screenshot below). If the object is already associated with
another page, it will retain that association as well as gain the new one you just specified. In other words,
the child object will appear on both tab pages. Repeat this process to associate any number of objects to
any number of tab pages.

You can also fill a tab page with the contents of a Form Window or Dialog Box. This provides another method
of designing tab pages. Simply create and design a Form Window or Dialog Box and then assign it to the Tab
Page’s “Child Window” attribute.
Note: If a tab bar control has many tab pages, creating all the child objects at startup time can introduce a
performance issue. Starting in version 6.0, you can prevent this problem with the system variable
bDeferCreatingTabChild. When this variable is set to TRUE, child items will not be created until their
parent tab page is actvated. The default value of bDeferCreatingTabChildren is FALSE for backward
compatibility.
Further customizations of the tab bar and tab pages can be accomplished via their many attributes listed
below.

Tab Bar Attributes


Bar bars have the following attributes:

Property Description

Visible If Yes (default), the scroll bar is visible at runtime. If No, the scroll bar is not visible at
runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Left Horizontal displacement of the tab bar from the left edge of the parent window.
Default is zero. Enter a number to specify the horizontal position of the tab bar (in
inches).
Top Vertical displacement of the tab bar from the top edge of the parent window. Default
is zero. Enter a number to specify the vertical position of the tab bar (in inches).
155
Property Description

Width Width of the tab bar in inches. Default is 6.

Height Height of the tab bar in inches. Default is 3.333

Border Select whether the Tab Bar control should have a border around its pages (Yes) or
not (No). Default is Yes.
Font Name The font of the text on the tab titles. Click “...” to display a dialog box that allows you
choose a font. You can also set the font size and some font enhancements in this box.
Font Size The size of the text on the tab titles. Default is 12.

Font Enhancement Font enhancement for the text on the tab titles. Select Bold, Italic, Strikeout,
Underline, any combination of these, or None. Default is None.
Orientation Position of the tabs relative to the tab pages. Choose either Top (default), Bottom,
Left, or Right.
Style The general appearance of the tab bar. Five styles are available: Standard, One Note,
Whidbey, Flat, and Buttons.
Enable Scroll If Yes (default), the next/previous scroll buttons will be visible even when all tabs are
visible (buttons will be disabled). If No, the scroll buttons will automatically hide
when all tabs are visible. With either setting, the scroll buttons will be visible and
enabled when there is not enough room to display all tabs.
Tile to Parent If Yes, the tab control expands to fill its parent window. Default is No.

Top Margin Distance between the upper border of the parent window and the top edge of the
tab bar control (only applicable if “Tile to Parent” is activated). Default is 0.0”.
Left Margin Distance between the left border of the parent window and the left edge of the tab
bar control (only applicable if “Tile to Parent” is activated). Default is 0.0”.
Bottom Margin Distance between the lower border of the parent window and the bottom edge of
the tab bar control (only applicable if “Tile to Parent” is activated). Default is 0.0”.
Right Margin Distance between the right border of the parent window and the right edge of the
tab bar control (only applicable if “Tile to Parent” is activated). Default is 0.0”.
Invert Vertical Font When Orientation is set to Left or Right, the text on the tabs is vertical (rotated 90
degrees) to match the tab orientation. The “Invert Vertical Font” setting determines
whether the text reads from top to bottom or from bottom to top.

Tab Page Attributes


Tab pages have the following attributes:

Property Description

Object Title The text that will appear on the tab for this tab page

156
Property Description

Visible If Yes (default), the scroll bar is visible at runtime. If No, the scroll bar is not visible at
runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
File Name Name of an image file for use as an icon on the tab for this page

Background Color The background color for the panel portion of this page (not the tab). Type the name
of a common color, or click “...” to select a custom color.
ToolTip This text will be displayed when the user hovers the mouse cursor over the tab.

Child Window Assign a Form Window or Dialog Box to this attribute, and the contents of the
specified Form Window or Dialog Box will be displayed in this tab page.
Be careful when assigning a child window to a tab page that already has child
objects. Objects might overlap.

API Support
The Tab Bar control supports all SalTabXXX APIs.
For details on these APIs, go to the sqlwindows menu item Help > Help Topics.

Table Window
See Chapter 15 – Table Windows.

Table Window Column


See Chapter 15 – Table Windows.

Toolbar
A toolbar is a rectangular area where you place objects for the most often used functions of an
application. This is an example of a toolbar:

You define toolbars in top-level windows and MDI windows. To display a toolbar, set the Accessories Enabled
attribute to Yes for a top-level window or MDI window.

157
Specify the toolbar’s position (top, left, right, or bottom) in the Accessories attribute of the top-level window
or MDI window. If you place the toolbar at the top or bottom, you can adjust its height. If you place the
toolbar at the left or right, you can adjust its width.
The outline for these windows has a section called toolbar where you can place child windows.

Toolbar Attributes
Toolbars have the following attributes:

Property Description

Display Style The visual appearance of child objects in the toolbar:


Default Uses the setting in the Window Defaults section of Global Declarations
(standard or etched)
Standard Child objects appear two-dimensional
Etched Child objects appear three-dimensional
Resizeable Whether the toolbar itself can be resized. This attribute is enabled when the toolbar
can be docked (the “Docking Toolbar” attribute of a top-level window). Toolbars are
"stateful", remembering their modified sizes when docked and undocked. Default
value is No.
Background Color The background color of the toolbar.

Text Color The color of text in the toolbar.

Font Name The font of text in the toolbar.

Font Size The font size of text in the toolbar.

Font Enhancement The font enhancement of text in the toolbar.

Outline Items
The outline items for a toolbar are after the menu section:
Menu
...
Toolbar
...
Contents
...
You can place any child object (except for a column) in the Contents section of a toolbar. This is an example of
a toolbar definition:

158
Toolbar
...
Contents
...
Pushbutton: pb7
...
Picture File Name: cut.bmp
...
Message Actions
On SAM_Click
If NOT SalEditCut( )
Call SalMessageBeep( MB_Ok )
...
Combo Box: cmb1
...
List Initialization
Text: P1
...
Background Text: P#:
...

Alt Keys and Toolbars


You can use mnemonics in objects in toolbars. SQLWindows searches the active window for an object with a
matching mnemonic in this order:
MDI window
The active MDI child form, if it is a form window
The toolbar, if any, of the active MDI child
The toolbar, if any, of the MDI window
Table window
The toolbar, if any
Form windows and dialog boxes
The form window or dialog box
The toolbar, if any

Functions
You can hide or show a toolbar by calling SalTBarSetVisible.
Call SalGetFirstChild to get the handle of the toolbar window. The following statement returns the handle of
the form window’s toolbar, if any. You can use the window handle to change the properties of the toolbar
(such as color or font) or to find the window handles of the toolbar’s children using SalGetFirstChild and
SalGetNextChild:
Set hWndToolBar = SalGetFirstChild( hWndForm, TYPE_FormToolBar )
This is how SalParentWindow behaves with toolbars:

Where Called SalParentWindow Return


Parameter
Toolbar child in top-level object hWndItem Handle of containing top-level object (hWndForm)

159
Toolbar child in MDI window hWndItem Handle of containing MDI window (hWndMDI)

Child table window in toolbar hWndForm Handle of containing top-level object (hWndForm is
the handle of the table window)

Tree Control and Tree Items


A tree control provides a visual representation of hierarchical data, and allows the end user to navigate and
interact with that data. An example of a tree control is pictured below:

A tree control in a Team Developer application can contain an indefinite number of items. Each item in the
control can contain other items as children. A tree item cannot exist independently; it must be a child of
another item or of the tree control itself.
If a tree item contains other items as children, it can be expanded to display the child items, or collapsed to
hide them. You can also assign icons to each item, including two different icons for selected and non-selected
states.
The tree control supports many kinds of user interactions at run time, including the following:
• Expand or collapse parent items by clicking on the “+” and “-” symbols.
• Edit item names.
• Drag and drop.
• Navigate and expand/collapse items using arrow keys.
Dozens of Sal functions allow for manipulation of the tree control at run time. See below for a list of these
fuctions. Details on each function can be found in the in-build help.
See the TreeControl.app sample application in [Install Directory]/Samples/ SQLWindows/User Interface/Tree/.

Tree Control Events


The tree control supports three new events: SAM_ItemSelected, SAM_ItemExpanded, and
SAM_ItemCollapsed. It also supports the following:

160
• SAM_Click
• SAM_DoubleClick
• SAM_Create
• SAM_Destroy
• SAM_KillFocus
• SAM_SetFocus
• SAM_Timer
• SAM_User
The SAM_Click event is only triggered when the user checks or unchecks a tree item checkbox (either with a
click or with the keyboard). This is different from SAM_ItemSelected, which is triggered when the tree item is
selected (again, either by the mouse or keyboard). Thus, if the user clicks on a tree item’s text, the
SAM_ItemSelected event is executed, but SAM_Click is not.
The other tree-specific messages, SAM_ItemExpanded and SAM_ItemCollapsed, are triggered when the user
expands or collapses a tree item, either by clicking on the “+” or “-” symbol or by double-clicking on an item.

Tree Control Functions


See the online help for details on the following functions:

SalTreeCollapseItem SalTreeGetItemText SalTreeItemIsSelected

SalTreeDeleteItem SalTreeGetItemTooltip SalTreeSetItemData

SalTreeEditItem SalTreeGetNextItem SalTreeSetItemChecked

SalTreeEnableItem SalTreeGetPrevItem SalTreeSetItemEditable

SalTreeExpandItem SalTreeGetSelectedItem SalTreeSetItemFontEnh

SalTreeFindItemByTitle SalTreeInsertItem SalTreeSetItemImage

SalTreeGetDropItem SalTreeItemCount SalTreeSetItemTextColor

SalTreeGetFirstItem SalTreeItemHasCheckbox SalTreeSetItemTooltip

SalTreeGetItemData SalTreeItemIsChecked SalTreeSetSelectedItem

SalTreeGetItemParent SalTreeItemIsExpanded SalTreeShowItemCheckbox

Tree Control Attributes


Tree controls have the following attributes:

Property Description

161
Property Description

Object Title The title of the tree control. The title will appear as the topmost tree item unless you
set the Show Root attribute to No.
Visible If Yes (default), the tree control is visible at runtime. If No, the tree control is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow
Left Horizontal displacement of the tree control from the left edge of the parent window.
Default is zero. Enter a number to specify the horizontal position of the tab bar (in
inches).
Top Vertical displacement of the tree control from the top edge of the parent window.
Default is zero. Enter a number to specify the vertical position of the tree control (in
inches).
Width Width of the tree control in inches. Default is 1.2

Height Height of the tree control in inches. Default is 0.833

Background Color The background color of the tree control.

Text Color The color of text for the tree control. All tree items will use this color unless
individually overridden.
Font Name The font of text for the tree control. All tree items will use this font.

Font Size The font size of text for the tree control. All tree items will use this font size.

Font Enhancement The font enhancement of text in the tree control. All tree items will use this font
enhancement. Choose any combination of Bold, Italic, Strikeout, and/or Underline.
Normal Image The image that will be displayed next to all non-selected tree items.

Selected Image The image that will be displayed next to a selected tree item.

Show Root If Yes (default), the topmost tree item will be the Object Title. If No, Object Title will
not be displayed.
Has Checkbox If Yes, each tree item will have a checkbox.

Track Select If Yes, each tree item’s text will turn blue and be underlined whenever the mouse
cursor hovers over it. The item will not actually be selected unless the user clicks. If
No, the tree items’ appearance will not change unless clicked.

Tree Item Attributes


Tree items have the following attributes:

Property Description

162
Property Description

Editable If Yes, the name of the tree item can be edited at run time. To edit, the user must
click on a selected tree item (click to select, wait a moment, and then click to edit). In
a WPF application, right-click and choose Edit.
Text Color The text color for this tree control item. Overrides the tree control attribute for this
item.
Disabled If Yes, the item (as well as its associated image, if any) is grayed out and is not
selectable.
ToolTip This text is displayed when the user hovers the mouse cursor over the check box.

Object Colors
When you add an object, you set its color in the Attribute Inspector. Instead of choosing a color, you can also
choose Default, System Text Color, System Frame Color, or System Window Color:
• For top-level objects, Default means the system-defined text color or background color. For child objects,
Default is the color set in the Windows Defaults section of the outline. Unless you change the Windows
Defaults setting, this is the color of the top-level object.
• System Text Color, System Frame Color, and System Window Color are the defaults set in the control
panel.
If you choose a color that does not exist in the computer, SQLWindows uses the closest color. On
monochrome computers, SQLWindows ignores the color of objects.

Color Inheritance
By default, child objects inherit their color from their top-level objects. For example, when you first add a
child object, it appears in the color of its top-level object. To make the child object a different color, change
the Text Color or Background Color property.

Functions
At runtime you can get and set an object’s color with SalColorGet and SalColorSet. The SQLWindows Function
Reference describes these functions.

Fonts for Objects with Text


You set the font for form windows, data fields, multiline fields, background text fields, push buttons, radio
buttons, check boxes, group boxes, table windows, list boxes, combo boxes, and dialog boxes in the Attribute
Inspector.
Font properties are the following:

163
Property Description

Font Name For top-level objects, Default means to use the system font For child objects, Default
means to use the parent's font
Font Size For child objects, Default means to use the parent's font size A given font is only
available in certain sizes
Font Enhancement A text style
For top-level objects, Default means no font enhancement
For child objects, Default means to use the parent's font enhancement

When choosing fonts, always design applications for the lowest resolution that is used. This ensures that the
windows will fit within the monitor's screen.

Font Inheritance
By default, child objects inherit their font properties from their top-level object. For example, when you first
add a child object, it appears in the font of the top-level object. If you want the child object to use different
font properties, change the font name, font size, or font enhancement.
Table windows are the exception to this rule. You can only set font properties for the entire table window. You
cannot set different font properties for a table window column.

Changing Default Colors and Fonts


You can change the default font and color for objects by editing the Window Defaults section in Global
Declarations. Put the mouse pointer on the property setting and do one of these:
• Type a new value
• Select a value in Coding Assistant
• Cycle through settings with the up and down arrow keys

Form Units
SQLWindows uses form units as the unit of measure for objects. Form units are independent of the screen
resolution that allows applications to run with different resolutions. Windows sizes and locations are
proportional across different resolutions, although the physical size changes as expected. Form units are
based on the selected font to allow the screen resolution independence.
All SAL functions that involve window location or sizes use form units as the unit of measure. If you want to
convert form units to pixels on the current screen, you can use the SalFormUnitsToPixels function. If you are
using external functions that return values in pixels, you can convert them to form units with the
SalPixelsToFormUnits function.

164
Window Handles
When a window is created, a window handle is established for that instance of the window. The window
handle uniquely identifies the window. You can use the handle to access the window.
SQLWindows has a specific data type for window handles (see Window Handle on page 183).

Getting a Window Handle


To get the handle of a window:
• Save hWndMDI, hWndForm, or hWndItem in the SAM_Create message processing of the object whose
handle you want.
• Save the value returned by SalCreateWindow.
You can call SalGetFirstChild and SalGetNextChild to return the child window handle of the parent. Do not
write code that assumes the order of child objects. There is no guaranteed order in which SalGetFirstChild
and SalGetNextChild returns window handles.

Docking Windows
In SQLWindows, top-level windows (MDI windows, form windows, and top-level table windows) are capable
of docking with some child windows. In version 2005, these child windows include modeless dialog boxes and
the toolbars of the top-level windows themselves.
Docking can occur through user actions, like dragging a child window to an edge of a top-level window. It can
also occur programmatically, using the functions SalDlgSetDockStatus, SalDlgGetDockStatus, and
SalWindowGetDockSettings. Docking events are made available to SAL developers through the messages
SAM_Dock and SAM_DockChange.
Top-level windows and child windows must specify which edges are available for docking. This is known as
the “docking orientation.” Top-level windows cannot do this at runtime; you must specify the docking
orientation using the Attribute Inspector at design time. Toolbar docking orientation must also be specified at
design time.
However, dialog boxes can change their docking orientation at design time and also at run time, using the
functions shown above.
Windows can only dock on the edges specified by their docking orientation. If there is an incompatibility
between the orientation of the child window and the orientation of the top-level window, docking will not
occur. If you design a modeless dialog box that docks on the left edge, and it belongs to a top-level window
that only permits docking on the top edge, attempts to dock the dialog will fail and it will remain free-
floating.
If a tool bar has been designed as docking-enabled, and the orientation specified for the toolbar is not
compatible with the orientation of the top-level window, the toolbar will not be displayed at all.

Docking Issues with Attributes in the Attribute Inspector


Tool bars whose “Docking Tool Bar” attribute is Yes cannot edit the “Tool Bar Position” attribute. A tool bar
can either be assigned to a fixed edge of the parent window, or can be docked, but not both.

165
If the tool bar attribute “Tool Bar Visible” is No (tool bar is hidden), the “Docking Tool Bar” attribute is
disabled.
For dialog boxes, “Type of Dialog” must be Modeless for “Allow Dock to Parent” and “Docking Orientation” to
be enabled. Otherwise they are disabled.
For dialog boxes, if the “Allow Dock to Parent” attribute value is yes, “Docking Orientation” is enabled, and
“Accessories Enabled” is disabled. If no, the situation is reversed. You cannot specify accessory information
for a dialog that can be docked.

Using Objects as Variables


Many objects in SQLWindows are variables that hold a value.
Some objects such as data fields and table window columns can contain values with different data types. For
example, you can set the data type of a data field to Date/ Time, Number, String, or Long String (see Data
Types on page 177).
Some objects can only contain values for one data type:
• Radio buttons, check boxes, and option buttons are booleans.
• Multiline fields are Strings or Long Strings.
• Scroll bars are numbers.
You can use variables and objects interchangeably. For example, if a form window has a data field called
dfName, the followin g SAL language statement sets the field if dfName is a String data type:
Set dfName = 'Hello'

Using Object Names as Parameters


You can use an object's name as a function parameter. The actual value that SQLWindows passes depends on
the parameter's data type:
• If the parameter is a window handle, SQLWindows passes the handle of the object
• If the parameter is a data type such as a number or string, SQLWindows passes the value of the object
You can use an object's name (such as frmMain or tblCustomer) as a window handle except when multiple
instances of the window exist.

Top-Level Window Parameters


When you call SalCreateWindow or SalModalDialog, you can pass extra parameters after the hWndOwner
parameter. For example, the statement below passes a variable (nGlobal) and the contents of a data field
(df1) to a form window:

166
Call SalCreateWindow( frmMain, hWndNULL, nGlobal, df1 )
The parameters that you pass must be defined in the Window Parameters section of the outline for the
window that you are creating. SQLWindows uses the values that you pass to fill the window parameters in the
order that they are defined in the Window Parameters section. You can define window parameters in top-
level windows and for MDI windows.
Before sending SAM_Create to the window being created, SQLWindows sets the window parameters with the
values that you pass. You can refer to the window parameters in the message actions of the window that you
are creating.
Note: You cannot pass the value of a window object such as a data field to a receive window parameter.
However, you can pass the value of a window object to a non-receive window parameter.
You cannot use receive window parameters as receive function arguments. You can use a temporary variable
as the function argument and then assign the temporary variable to the receive function parameter.
SalCreateWindow and SalModalDialog accept a string or a window name as the first parameter. When you
pass a string, you cannot also pass window parameters.

167
Chapter 6 – Application Menus
This chapter explains the elements of menus you can add to applications:
• Popup menus
• Menu items
• Named menus
• Creating menus dynamically at runtime
• Displaying menu text in the status bar
• Window menus
You can add menus to form windows, top-level table windows, and MDI windows.
Menus are like other objects, but you do not use the Controls toolbar to create them. Instead, you use Coding
Assistant to add popup menus and menu items, and to define menu features.

Popup Menus
A popup menu groups menu items in a list.
You define properties for a popup menu in the Menu section of the outline for form windows, top-level table
windows, and MDI windows:
Popup Menu: &Edit
Enabled when:
Status Text:
Menu Item: &Undo
...
Menu Separator
Menu Item: Cu&t
...
Menu Item: &Copy
...
Menu Item: &Paste
...
Menu Item: C&lear
...
Select Popup Menu in the Coding Assistant to create a Popup Menu section under the Menu section or type a
menu definition directly into the outline.

Property Description

Menu Title The name of a popup menu that appears in the menu bar.
Create a mnemonic for a menu by putting an ampersand (&) before a menu title
character. The & causes the character to be underlined.

168
Property Description

Enabled When You can place an expression here that controls when the popup menu is enabled.
When the expression is TRUE, the menu is enabled. When the expression is FALSE,
the menu is disabled.
The expression is TRUE by default: if Enabled When is blank, the menu is always
enabled.
The expression is only evaluated when you call SalDrawMenuBar.
Status Text Text to display in the status bar of the window (see Menu Status Text on page 175).

Picture File Name Image file to display in the popup menu when the application is executed.

Menu Items
When the user selects a menu item, the statements in its Actions section execute:
Menu Item: Cu&t
Keyboard Accelerator: Shift+Del
Status Text:
Menu Settings
Enabled when: SalEditCanCut()
Checked when:
Menu Actions
Call SalEditCut()
You can place a menu item in a:
• Menu bar as a top-level command
• Popup menu
When positioned on a popup menu in the outline, you can add menu items at the same level or at the next
level using Coding Assistant. This controls whether the menu item is in the popup menu (next level) or is on
the menu bar (same level) as a top-level menu item.
Select menu item in Coding Assistant to create a Menu Item section. The table below lists the menu item
properties.

Menu Item Properties


Property Description

Menu Item The name that appears in the popup menu or on the menu bar.
Create a mnemonic for a menu item by typing an ampersand (&) before a character.
The & causes the character to be underlined.
A mnemonic for a menu item moves the input focus and invokes the menu item's
actions.
Status Text Text to display in the status bar of the window (see Menu Status Text on page 175).

169
Property Description

Keyboard Accelerator A keystroke combination that selects the menu item. The accelerator appears on the
menu to the right of the menu item. The default is None.
Use Coding Assistant to display a list of accelerators (see Accelerators on page 171).
Enabled when You place an expression here that controls when the menu item is enabled. When
the expression is TRUE, the menu item is enabled and the user can select it to invoke
the associated action. When enabled, the menu item name is black.
When the expression is FALSE, the menu item is disabled and the user cannot select
it to invoke the associated action. When disabled, the menu item name is gray.
For example, if you only want the Cut menu item to be enabled when the user has
highlighted something to cut:
Enabled when: SalEditCanCut ( )
The expression is TRUE by default: if Enabled When is blank, the menu item is always
enabled.
For a top-level menu item, the expression is only evaluated when you call
SalDrawMenuBar.
Checked when You place an expression here that controls when the menu item has a check mark.
When the expression is TRUE, the menu item has a check mark on its left side. When
the expression is FALSE, the menu item does not have a check mark. The expression
is FALSE by default: if Checked When is blank, the menu item does not have a check
mark.
Menu Actions SAL statements that execute when the user selects the menu item.

Picture File Name Image file to display next to the menu item when the application is executed.

170
Accelerators
Ctrl + Character Key Function Keys Shift + Function Key Other
Combinations Combinations
Ctrl+A Ctrl+N F1 Shift+F1 Ins
Ctrl+B Ctrl+O F2 Shift+F2 Shift+Ins
Ctrl+C Ctrl+P F3 Shift+F3 Alt+BkSp
Ctrl+D Ctrl+Q F4 Shift+F4 Del
Ctrl+E Ctrl+R F5 Shift+F5 Ctrl+Del
Ctrl+F Ctrl+S F6 Shift+F6 Ctrl+Fkey
Ctrl+G Ctrl+T F7 Shift+F7 Ctrl+Ins
Ctrl+H Ctrl+U F8 Shift+F8 - (minus)
Ctrl+I Ctrl+V F9 Shift+F9 + (plus)
Ctrl+J Ctrl+W F10 Shift+F10 Shift+Ctrl+<char>
Ctrl+K Ctrl+X F11 Shift+F11 Shift+Ctrl+Fkey
Ctrl+L Ctrl+Y F12 Shift+F12 Shift+Ctrl+Del
Ctrl+M Ctrl+Z Shift+Ctrl+Ins
Shift+Del

Menu Separator
A menu separator is a horizontal line between menu items that groups related items in a menu.

A menu separator looks like this in the outline:

171
Popup Menu: &Edit
...
Menu Item: &Undo
...
Menu Separator
Menu Item: &Find
...

Cascading Menus
A cascading menu is a child popup menu inside another popup menu. A menu item that displays a cascading
menu has an arrow on its right side.
A popup menu can contain both menu items and cascading menus. Both levels can have accelerators and
mnemonics.

Cascading menus have the same properties as popup menus.


A cascading menu looks like this in the outline:
Popup Menu: Films
...
Popup Menu: Sunset Boulevard
...
Menu Item: William Holden
...

Menu Row

A menu row starts a new row of menu items and popup menus. All popup menu names or top-level menu
items after a menu row are on the next row of the menu bar.

172
A menu row looks like this in the outline:
Popup Menu: &Distribution
...
Menu Row
Popup Menu: &Strategy
...

Menu Column
A menu column groups menu items in vertical columns.

A menu column looks like this in the outline:


Menu Item: The Gold Rush
...
Menu Column
Menu Item: Citizen Kane
...

Named Menus
You use named menus to create popup menus that windows in an application can share. You can also use
named menus to create popup menus dynamically that can appear anywhere on the screen.
You define a named menu in the section called Named Menus in Global Declarations; for example:
Named Menus
Menu: menuEdit
Description: Edit menu
Title: &Edit
Enabled when:
Status Text: Undo, Cut, Copy, Paste, Clear
Menu Item: &Undo
Menu Separator
Menu Item: C&ut
Menu Item: &Copy
Menu Item: &Paste
Menu Item: &Clear
Place the name of the menu after the colon. This is different from other popup menus that only have a
display title. You use this name when you add a named menu to a window.
There is also a Named Menus section in window definitions where you can add named menus that you create
dynamically at runtime or share between an MDI window's children.
173
A named menu can have two types of children: Menu and Windows Menu. To use a named menu, specify its
name in the menu definition of a window:
Menu
Popup Menu: &File
Named Menu: menuEdit
A Windows Menu can refer to any of its own named menus or any global named menus. An MDI child
window can also refer to named menus in its MDI window parent.
If a reference to a named menu is unresolved the menu will display the referenced name surrounded by
“<“and “>”. For example, if the menuEdit example above was not a named menu, the menu of this window
would display “File <menuEdit>”.
You can only use named menus for top-level popup menus, not for cascading menus in a popup menu.

Predefined Named Menus


NEWAPP.APP contains these predefined named menus:

Menu Description

menuEdit An Edit menu with Undo, Cut, Copy, Paste, and Clear

menuMDIWindows An MDI window's menu with commands to manage MDI child windows

Creating Popup Menus Dynamically at Runtime


You can create popup menus dynamically anywhere on the screen at runtime with SalTrackPopupMenu:
SalTrackPopupMenu( hWnd, strMenuName, Flags, nX, nY )
The parameters are the following:
hWnd The window handle for a top-level window that processes messages that the popup
menu sends
strMenuName A named menu defined in one of the following:
–The Named Menus section of hWnd
–The Named Menus section of hWnd's MDI window parent
–The Named Menus section of Global Declarations
nFlags How to display the popup menu.
You can combine these flags using the “|” operator:
TPM_CursorX—Display the menu at the location of the mouse cursor instead of nX
TPM_CursorY—Display the menu at the location of the mouse cursor instead of nY
TPM_LeftButton—The user can click items in the menu with the left button (default)
TPM_RightButton—The user can click items in the menu with the right button
TPM_LeftAlign—Left-align the menu with its horizontal screen coordinate
TPM_CenterAlign—Center-align the menu with its horizontal screen coordinate
TPM_RightAlign—Right-align the menu with its horizontal screen coordinate
nX, nY The location of the menu in screen coordinates

174
Example
This example creates an Edit popup menu when the user clicks the mouse button. The menu appears where
the mouse is positioned when the user clicks.
On SAM_Click
Call SalTrackPopupMenu( hWndForm, 'menuEdit',
TPM_CursorX | TPM_CursorY | TPM_CenterAlign, 0, 0 )

Menu Status Text


The following outline items have a Status Text item:
• Popup menus
• Menu items
• Object menu
• Windows menu
• Named popup menu
• Named windows menu
If a window with one of these types of menu items has a status bar, SQLWindows displays the status text
when the user selects the menu item with the mouse.
Popup menus that you create with SalTrackPopupMenu also display the status text when the user selects the
menu item with the mouse.

Windows Menu
A windows menu is a special type of popup menu that you use in MDI windows and their children. A windows
menu automatically lists all the MDI window's child windows without any coding. You can add your own
menu items to a windows menu (see MDI Window on page 116).

Ribbon Bar
The ribbon bar is an alternative to the standard Team Developer menus. It is turned off by default but can be
enabled by setting the system variable bMenuBarAsRibbonBar to TRUE as follows:
• Go to the outline editor of your application.
• Expand ‘Global Declarations’
• Under ‘Application Actions’ add the following code:
On SAM_AppStartup
-- Set bMenuBarAsRibbonBar = TRUE
The look of this ribbon bar is only visible at runtime. The following is an example of the ribbon bar with its
equivalent outline editor source:
175
Note: According to Microsoft's Ribbon UI Guidelines and Vista UI Guidelines, a ribbon bar is not designed to
allow disabling of tabs. Instead, you should hide tab pages.

Application Menus and Win32 API


• We do not provide the ability to manipulate (check/enable) a ribbon bar with a Win32 API.
• For menu items created by Team Developer (TD) or Visual ToolChest (VT), the expression defined in
TD/VT takes precedence over a Win32 API.
• For menu items created by a Win32 API, you can modify (check/enable) with both TD/VT functions and
Win32 API. As long as you don't call SalMenuUpdate or SalDrawMenuBar, TD/VT functions take
precedence. But if you call SalMenuUpdate or SalMenuDraw, the latest WIN32 API takes precedence.

176
Chapter 7 – SAL (SQLWindows Application
Language)
This chapter explains the elements of SAL:
• Data types
• Variables
• Constants
• Arrays
• Operators
• Expressions
• Statements
• Reserved Words
• Functions
• Command line arguments

Case Sensitivity
SQLWindows is case sensitive. Uppercase and lowercase characters are seen as different.

Maximum Identifier Length


The maximum length of an identifier in SQLWindows is 500 characters.

Data Types
Variables must be one of the following data types:
• Binary
• Boolean
• Date/Time
• File Handle
• Long String
• Number
• Sql Handle
177
• String
• Window Handle
Constants must be one of these data types:
• Boolean
• Date/Time
• Number
• String

Receive Data Types


All data types can be an alternate form called a receive data type (see Functions on page 200).

Binary
This data type provides better support for binary data within SAL, including data from BLOB columns.
To assign a value to a BINARY variable, use SalPicSetBinary, the BINARY_Null constant, or another BINARY
variable.

Example
Variables
BINARY: binInput
BINARY: binPic
Set bOk = SalPicGetBinary(hWndPic,PIC_FormatObject,binInput)
if (bOk)
Set binPic=binInput

Boolean
Use this data type for variables that can be TRUE or FALSE. These values are system constants: TRUE is 1 and
FALSE is 0.

Example
Set bBool = TRUE
Set bBool3 = bBool2

Date/Time
Use this data type for dates and times. The default output format is ISO:
YYYY-MM-DD-HH.MM.SS.MSMSMS
The only valid input format for Date/Time values in Set statements is ISO:
• The year must be four digits.
• The month, day, hour, minute, and seconds must be two digits. Include a leading zero when the value is
less than 10.
• You must use the hyphens and periods as separators in the positions shown above.
178
• The microseconds (MS) can be up to six digits.
You can use the DATETIME_Null system constant to set a Date/Time to a null value, or to check if a Date/Time
value is null.

Example
Variables
Date/Time: dtBirthday
Date/Time: dtOrder
...
Set dtBirthday = 1983-10-25
Set dtOrder = 1986-01-12-05.23.10.875345

Internal format
Internally, SQLWindows stores Date/Time data in its own floating point format. This format interprets a
Date/Time value as a number in this form:
DAY.TIME
DAY is a whole number that represents the number of days since December 30, 1899. December 30, 1899 is
0, December 31, 1899 is 1, and so on.
TIME is the fractional part of the day. Zero represents 12:00 AM, .25 is 6:00 AM, .5 is 12:00, .75 is 3:00, and so
on.
For example, March 1, 1900 12:00:00 PM is represented by the floating value 61.5 and March 1, 1900
12:00:00 AM is 61.0.
If you omit a part of an input Date/Time value, SQLWindows supplies the default of 0, which converts to
December 30, 1899 (date part) 12:00:00 AM (time part).
Say you define the following variable:
Date/Time: dtExample
You then execute the following Set statement that does not specify a time:
Set dtExample = 1983-10-02
The value in dtExample is therefore:
1983-10-02-00.00.00
When the microseconds part is zero, SQLWindows omits the microseconds in its default output format.

Date/Time arithmetic
You can perform these arithmetic operations with Date/Time values:
• Add a Number value to a Date/Time value, giving you a Date/Time value
• Subtract a Number value from a Date/Time value, giving you a Date/Time value
• Subtract one Date/Time value from another Date/Time value, giving you a Number value
If you add or subtract a Number value to or from a Date/Time value, the result is a Date/Time value.
The next sections show examples of each type of Date/Time arithmetic. The following variables are used in
the examples:

179
Date/Time: dtExample1
Date/Time: dtExample2
Number: nResult

Adding a number to a Date/Time


When you add an integer to a Date/Time, SQLWindows adds that many days to the value. If you execute
these statements:
Set dtExample1 = 1983-10-02
Set dtExample2 = dtExample1 + 32
The result in dtExample2 is:
1983-11-03-00.00.00

Subtracting a number from a Date/Time


When you subtract an integer from a Date/Time, SQLWindows subtracts that many days from the value. If
you execute these statements:
Set dtExample1 = 1983-10-02
Set dtExample2 = dtExample1 - 32
The result in dtExample2 is:
1983-08-31-00.00.00

Subtracting a Date/Time from a Date/Time


When you subtract a Date/Time from another Date/Time, SQLWindows finds the number of days between
the two dates. If you execute these statements:
Set dtExample1 = 1986-01-12
Set dtExample2 = 1983-10-02
Set nResult = dtExample1 - dtExample2
The result in nResult is:
833

Using decimal numbers in Date/Time arithmetic


SQLWindows treats the digits to the right of the decimal as the percentage of a day. If you execute these
statements:
Set dtExample1 = 1986-01-12
Set dtExample2 = dtExample1 + .25
The result in dtExample2 is:
1986-01-12.06.00.00
If you execute these statements:
Set dtExample1 = 1986-01-12
Set dtExample2 = dtExample1 + .99999
The result in dtExample2 is:
1986-01-12.23.59.59.136000

180
Year 2000 support
Team Developer determines the value for a user's 2-digit century entry as follows:

When last 2 digits of When the 2-digit entry is 0-49 When the 2-digit entry is 50-99
current year are:
0-49 The input date is in the The input date is in the
current century previous century
50-99 The input date is in the next The input date is in the
century current century

Examples:
• Assume the current year is 1996:
If 05 is entered, the computed date is 2005 If 89 is entered, the computed date is 1989
• Assume the current year is 2014:
If 05 is entered, the computed date is 2005 If 34 is entered, the computed date is 2034 If 97 is entered,
the computed date is 1997
• Assume the current year is 2065:
If 05 is entered, the computed date is 2105 If 70 is entered, the computed date is 2070
For details on setting SQLBase for year 2000 support, read the Date/Time values section in the SQLBase
Language Reference.

Number
Use this data type for numbers with up to 44 digits of precision.
You can use the NUMBER_Null system constant to set a Number to a null value, or to check if a Number value
is a null.
If you use a Number data type as a bind variable to write a SQLBase DECIMAL data type column, truncation
can happen because SQLBase DECIMAL data types have a maximum of 22 digits of precision.

Example
Variables
Number: nMonth
...
Set nMonth = SalDateMonth( SalDateCurrent( ) )

Internal Format for Number and Date/Time Data Types


SQLWindows stores Number and Date/Time data types in base 100 floating point format. This is the same
internal format that SQLBase uses that is described in the SQLBase C Application Programming Interface
Reference Manual.

181
Session Handle
You use this data type for multi-connection transactions and OLE DB provider connections. See Multi-
Connection Transactions on page 332 and Session Handle Data Type on page 353.

Sql Handle
Use this data type to identify an open connection to a database. All access to a database requires a Sql
handle. You use Sql Handles in Sql* functions to execute SQL statements.
See Chapter 12 – SQL Programming.

Example
SqlConnect returns the handle. Before you call SqlConnect, hSql does not have a valid value.
Variables
Sql Handle: hSql
...
Call SqlConnect( hSql )

File Handle
Use this data type to identify an open file. When you open or create a file, SQLWindows returns a file handle.
You then use the file handle to identify the file.

Example
Variables
File Handle: hFile
...
Set bOk = SalFilePutStr( hFile, strOneLine )

String
Use this data type for character data. The only limit on the length of a String data type is available system
memory.
Enclose literal strings in single quotes. You can also enclose literal Strings in double quotes. When you do, you
do not need to put escape characters before embedded single quote characters; for example:
String: strSelect = "select * from customers where name = 'smith'"

Example
This example defines the string strQuery and assigns it a literal value.
Variables
String: strQuery
...
Set strQuery = 'SELECT APPT INTO :FLDAPPT FROM CLIENT'

Long String
Use this data type for character data. The only limit on the length of a Long String data type is available
system memory.
182
Use this data type to read and write SQL database columns longer than 254 bytes.

Example
Variables
Long String: sLong
...
Set sLong = 'Long String'

When to use Long Strings


You need to use the Long String data type for bind and INTO variables for database columns that are longer
than 254 bytes, as the table below shows:

Database Data Types

AS/400 CHAR, VARCHAR

DB2 LONG VARCHAR

Informix-Online CHAR, VARCHAR, BYTE, TEXT

Informix-SE CHAR

Ingres CHAR, VARCHAR, TEXT, C

Oracle CHAR, VARCHAR, LONG, LONG RAW

SQLBase LONG VARCHAR

SQL Server Sybase TEXT, IMAGE

Internally, SQLWindows uses the SQL/API functions sqlrlo and sqlwlo to read and write these column data
types.

Window Handle
Use this data type to identify a single instance of a window. At runtime, each instance of a window has a
unique handle. Until you assign a value to this data type, it contains hWndNULL (see Window Handles on
page 165).

183
Example
Variables
Window Handle: hWndItem
...
Form Window: frmMain
...
Contents
Data Field: dfClock
...
Message Actions
On SAM_Create
Call SalTimerSet( hWndItem, 1, 1000)

Data Types Treated as Booleans


Strings, numbers, dates, and handles (file, window, and SQL), are automatically converted (“cast”) to a
boolean when used as an operand of an “If”, “While”, or “Enabled when” statement, or used as an operand of
an “AND”, “OR”, or “NOT” operator.
• An uninitialized variable, of any data type, when converted to a boolean, evaluates to FALSE.
• A variable of any data type that has been assigned a null value from a database, evaluates to FALSE.
• A string variable or constant with the value '' (null string) evaluates to FALSE.
• A number variable or constant with the value 0 (zero) evaluates to FALSE.
• A window handle matching hWndNULL evaluates to FALSE.
Everything else evaluates to TRUE.

Variables
A variable can hold any value of its data type.

Where to Declare Variables


Variables are defined in the following places:
• Global Declarations (Variables section)
• Class, Internal, and Window Functions (Parameters, Static Variables, and Local Variables sections)
• External Functions (Returns and Parameters sections)
• Class Definitions (Class Variables and Instance Variables sections)
• Form windows (Window Parameters and Window Variables sections)
• Top-level table windows (Window Parameters and Window Variables sections)
• Child table windows (Window Variables section)
• MDI windows (Window Parameters and Window Variables sections)
• Dialog box (Window Parameters and Window Variables sections)

184
Syntax
Use the following syntax to declare a variable:
Data Type: VariableName

Examples
The following are examples of variable declarations:
Boolean: bReturn
Date/Time: dtBirthday
Long String: strLong
Number: nCount
Sql Handle: hSql
String: strName
Window Handle: hWndHelp

When Variables are Valid


Variables in the Global Declarations are valid as soon as the application starts. You can refer to global
variables in any SAL statement.
Variables in the Local Variables section of a function definition are valid when you call the function and
become invalid when the function returns.
Variables in a Window Variables section are valid as soon as you create an instance of the window and
become invalid when you destroy the window.

How SQLWindows Initializes Variables


Data Type Initial Value

Number Zero (0)

Date/Time Null Date/Time

String Null string (the buffer length is 1 for the null character)

Window hWndNULL
Handle

How to Refer to Variables


Variables can be referred to in two ways:
• In an unqualified (or simple) reference, you only specify the name of the variable.
• In a qualified reference, you add a prefix that contains one or more other names to a variable name. You
separate the names with periods:
hWnd1.df1
References are qualified to:
• Eliminate ambiguity with duplicate names

185
• Refer to a window that has multiple instances
• Refer to a variable in a child from its parent
• Refer to a variable in a different top-level window or MDI window
The next sections show examples of qualified references. Also see Chapter 7 – SAL (SQLWindows Application
Language).

Referring to duplicate symbols


In the following example, two form windows (frm1 and frm2) contain a data field named dfName:
Form Window: frm1
...
Contents
Data Field: dfName
...
Form Window: frm2
...
Contents
Data Field: dfName

When a dialog box (dlg1) refers to dfName, it is ambiguous:


Dialog Box: dlg1
...
Window Variables
String: strName
Message Actions
On SAM_Create
Set strName = dfName
To eliminate the ambiguity, qualify the variable name:
Dialog Box: dlg1
...
Window Variables
String: strName
Message Actions
On SAM_Create
Set strName = frm1.dfName

Referring to multiple instances of a window


In the following example, frm1 contains a data field named dfName:
Form Window: frm1
...
Contents
Data Field: dfName
These statements create two instances of frm1:
hWnd1 = SalCreateWindow( frm1, hWndOwner )
hWnd2 = SalCreateWindow( frm1, hWndOwner )
Two windows exist with identical names (frm1) and identically-named variables (dfName). SQLWindows
cannot determine the copy of dfName to which the dialog box dlg1 refers:

186
Dialog Box: dlg1
...
Window Variables
String: strName
Message Actions
On SAM_Create
Set strName = frm1.dfName
To eliminate the ambiguity, specify:
• The window handle that the variable is associated with (hWnd1 or hWnd2)
• The template name with which the variable is associated (frm1)
The following example eliminates the ambiguity:
Message Actions
On SAM_Create
Set strName = hWnd1.frm1.dfName

Referring to child symbols from its parent


You declare a child variable in a child object of a parent window. When you refer to a child variable in the
parent window, you must qualify the name with the name of the child object in which it is declared.
For example, if you refer to a variable in a form window and the variable is declared in one of the form's child
table windows, you must qualify the variable name with the child table name:
ChildWindowName.VariableName
You must qualify the reference because it is in the form and is not in the scope of the child variable. In the
following example, a form window makes a reference to a window variable defined in its child table window:
Form Window: frm1
...
Contents
Data Field: df1
Child Table: tblChild
...
Window Variables
String: strInfo
Window Variables
Message Actions
On SAM_Create
Set df1 = tblChild.strInfo

Variables in SQL Statements


You use variables in SQL statements in two ways:
• To bind input data to a SQL statement. Variables used in this way are called bind variables.
• To specify where to put the output of a SQL SELECT statement. The INTO clause specifies the variables
where query data is placed. Variables in an INTO clause are called into variables.
When you use variables in a SQL statement, you must prefix them with a colon (:). For more about how to use
variables in SQL statements, see Chapter 12 – SQL Programming.

System Variables
The table below lists SQLWindows's system variables.
187
System Variable Data Type Description

MyValue Data type of current The value in the current window.


window
hWndMDI Window Handle The current MDI window.

hWndNULL Window Handle Returned when a window does not exist.

hWndForm Window Handle The current top-level window (form window, table
window, or dialog box).
hWndItem Window Handle The current object.

wParam Number A generic message parameter.

lParam Number A generic message parameter.

nArgCount Number The number of command line arguments that the


user entered when starting the application.
strArgArray[*] Array The command line arguments that the user
entered when starting the application.
SqlDatabase String

SqlUser String

SqlPassword String
You use these system variables to access SQL
SqlNoRecovery Boolean databases. See Chapter 12 – SQL Programming.

SqlInMessage Number

SqlOutMessage Number

SqlResultSet Boolean

SqlIsolationLevel String

Arrays
An array is a collection of variables (elements) of the same data type that you refer to with a common name.
You refer to an individual element in an array with a number that represents the index offset.

An array can be static or dynamic:


• A static array contains a fixed number of elements.
• A dynamic array contains a variable number of elements.
An array can be one-dimensional or multi-dimensional (an array of arrays).

188
SQLWindows always passes array elements to functions by reference even if the function parameter is
declared with the Receive keyword.
The maximum number of arrays in an application is 64 kilobytes.

One-Dimensional Arrays
Static arrays
If you know the maximum number of elements that an array can contain at one time, specify that number
when you declare the array:
String: strEmployees[10]
The ten elements in the array above are numbered 0-9. An array like this with a fixed number of elements is
called a static array. You must specify a numeric literal for the number of elements.
You can put any expression that evaluates to a number between the square brackets.

Dynamic arrays
If you cannot predict the maximum number of elements in an array, use an asterisk instead of a number to
tell SQLWindows that it is a dynamic array:
String: strEmployees[*]
The elements in the array above are numbered 0-n, where n depends on available system resources.
Dynamic arrays initially have zero elements. Call SalArrayIsEmpty to determine if an array contains data. You
can reset a dynamic array to zero elements by calling SalArraySetUpperBound and setting the nBound
parameter to -1.

Setting array bounds


By default, you refer to the first element of an array with zero. To control how you refer to the elements in an
array, specify the lower bound (or lower “range”) and the upper bound (or upper “range”). Separate the two
numbers with a colon:
String: strEmployees[1:10]
The ten elements in the array above are numbered 1-10. You can set the lower bound in a dynamic array:
String: strEmployees[1:*]
The elements in the array above are numbered 1-n, where n depends on available system resources.
Important: You cannot specify an asterisk for the lower bound.

Referring to arrays
You refer to an element in an array by specifying its index:
Set df1 = strEmployees[5]
The index can be any expression that evaluates to a number.

Multi-Dimensional Arrays
You declare a multi-dimensional array like a one-dimensional array, but you also specify the number of
elements in the second and subsequent dimensions after the number of elements in the first dimension. You
separate each dimension specification with a comma.
189
The maximum number of dimensions in an array is limited only by available system resources.

Static arrays
This example declares a 2-dimensional array with a fixed number of elements in both dimensions:
String: strEmployees[10, 3]
The array above has ten elements in its first dimension (numbered 0-9) and three in its second dimension
(numbered 0-2).

Dynamic arrays
You can make the first dimension dynamic:
String: strEmployees[*,3]
The array above has a dynamic number of elements in its first dimension (numbered 0-n) and three in its
second dimension (numbered 0-2).
Note: You can make only the first dimension of a multi-dimensional array dynamic.

Setting array bounds


You can control how you address the elements in any dimension:
String: strEmployees[1:10, 1:3]
The array above has ten elements in its first dimension (numbered 1-10) and three in its second dimension
(numbered 1-3).
You can set the lower bound if the first dimension is dynamic:
String: strEmployees[1:*, 1:3]
The array above has a dynamic number of elements in its first dimension (numbered 1-n) and three in its
second dimension (numbered 1-3).

Referring to multi-dimensional arrays


You refer to elements in a multi-dimensional array the same as you would in a one- dimensional array. The
difference is that for a multi-dimensional array you specify the second and subsequent dimensions' index
after the first dimension's index. You separate each index with a comma; for example:
Set df1 = strEmployees[2, 5]
Note: When you refer to a multi-dimensional array, you must explicitly specify an index for every
dimension.

Storing Child Window Handles in Arrays


You can assign a Window Handle variable or array element using the name of a child window. This is useful
for storing arrays of window handles; for example:

190
Window Variables
Window Handle: hWndKeyFields[*]
...
Message Actions
On SAM_Create
Set hWndKeyFields[0] = dfLastName
Set hWndKeyFields[1] = dfFirstName

Array Functions
You use these functions with arrays:
• SalArrayAvg
• SalArrayDimCount
• SalArrayGetLowerBound
• SalArrayGetUpperBound
• SalArrayIsEmpty
• SalArrayMax
• SalArrayMin
• SalArraySetUpperBound
• SalArraySum
For more about these functions, read the SQLWindows Function Reference or the online help.

Constants
A constant contains a single, unchanging value. You can declare a constant as one of these data types:
• Boolean
• Date/Time
• Number
• String
You can only declare constants in the Global Declarations section. You can refer to a constant wherever you
can refer to a variable.
You can declare numeric constants with hexadecimal values. For example: 0x1234ABCD.

Syntax
Use this syntax to declare a constant:
Data Type: ConstantName = expression

Examples
These are examples of constant declarations:

191
Constants
Number: BASE = 500
Number: MAXNUM = BASE+1000
String: STATE = 'New Jersey'
String: City = 'Newark'
String: PLACE = CITY || ',' || STATE
Date/Time: July_4 = 1994-07-04
Boolean: bDone = FALSE

System Constants
SQLWindows has many system constants that are explained in the online help.

Naming Conventions

Variables
Use the following prefixes in the names of variables to make the outline self-documenting:

Data Type Name Prefix Example

Boolean b bVarName

Date/Time dt dtVarName

File Handle fh fhFileVarName

Long String ls lsVarName

Number n nVarName

Sql Handle hSql hSqlVarName

String s (or) str sVarName

Window Handle hWnd hWndVarName

Constants
Use an uppercase prefix with an underscore followed by a mixed-case or uppercase name; for example:

192
TYPE_ConstantName TYPE_CONSTANTNAME

Operators
An operator is a symbol or word that represents an operation to perform on one or more values. The
operators are the following:

Operator Symbols Operator Type

+, -, *, / Numeric

unary - Unary

=, !=, >, <, >=, <= Relational

AND, OR, NOT Boolean

& Bitwise AND

| Bitwise OR

|| Concatenate String

Expressions
An expression is a combination of constants, variables, and operators that yields a single value. An expression
can be:
• The result of a function
• A variable
• A constant
• Two or more expressions connected with an operator
SQLWindows uses these precedence rules to evaluate expressions:
• Evaluate expressions with AND, OR, and NOT from left to right
• Stop evaluating AND/OR as soon as the result is known
• Evaluate expressions in parentheses first

193
Examples
nSalary[grade] + .1*nSal[3]
bQueryOn
MAXNO
1 + 1
SalDateCurrent( )

SAL Statements
SAL statements are used to code actions that you want the application to execute. The sections on the next
pages explain each SAL statement:
• Break
• Call
• If, Else, and Else If
• Loop
• On
• Return
• Select Case
• Set
• When SqlError
• While

Where to Code SAL Statements


SAL statements are coded in:
• Message Actions.
• Function Actions
• Application Actions
• Menu Actions

Break
Ends a Loop statement. If you specify a loop name, that loop ends. This lets you break out of more than one
level of loop. If you do not specify a loop name, the statement breaks out of the nearest level of loop.

Syntax
Break [loopname]

Example
This example fetches rows and breaks out of one level of the loop when SqlFetchNext returns FALSE.

194
Loop
If NOT SqlFetchNext (hSql, nInd)
Break
If nInd = FETCH_EOF
Call SalMessageBox ('No more rows', 'Select', MB_Ok)
Break

Call
Executes a function.

Syntax
Call FunctionName( parameters )

Examples
Call SalStrUpper(fldName, fldName)
Call SqlImmediate('delete from cust where name = :fldName')

If, Else, and Else If


These statements express decisions. The Else part is optional.
You can code as many Else If sections as you want, but there can be only one Else section.
Indentation determines the conditional flow of control.

Syntax
If expression1
statement1
Else If expression2
statement2
Else
statement3
SQLWindows evaluates expression1. If expression1 is TRUE, SQLWindows executes statement1. If expression1
is FALSE, SQLWindows evaluates expression2. If expression2 is TRUE, SQLWindows executes statement2. If
expression2 is FALSE, SQLWindows executes statement3.

Examples
If Fldb = 'M'
Call ProcessMale(fldSex)
Else If Fldb = 'F'
Call ProcessFemale(fldSex)
Else
Call ProcessOther(fldSex)
You can nest If statements. You can rewrite the example above as:

195
If Fldb = 'M'
Call ProcessMale(fldSex)
Else If Fldb = 'F'
Call ProcessFemale(fldSex)
Else
Call ProcessOther(fldSex)

Loop
Repeats statements indented under it until a Break or Return statement.

Syntax
Loop [loopname]
The loopname is optional.

Example 1
Loop
If count = 100
Break
Set count = count + 1

Example 2
Set y = 0
Set z = 0
Loop Outer
If z > 10
Break
Loop Inner
If y > 10
Break
If GetData = 10
Break Outer
Set GetData = ValCheck( )
Set y = y + 1
Set z = z + 1

On
Relates a message to SAL statements indented under it that execute when that message is received. You code
On statements only in the Message Actions and Application Actions sections.
Messages are identified with a message number or with a constant that represents the message number.

Syntax
On message

Example
When the Application Actions section receives the SAM_AppStartup message, the SAL statements that are
under the On statement execute:

196
Application Actions
On SAM_AppStartup
Call SalModalDialog (LogBox, hWndNULL)

Return
Breaks the flow of control and returns a value to a caller. Use this statement to end a:
• Function
• Message action
• Menu action

Syntax
Return expression

Example
Message Actions
On SAM_KillFocus
Return SalIsNull(fldName)

Select Case
Tests a series of conditions. The value of an expression is successively compared against the Case constants.
Both the expression and the constants must be number data types.
The Break statement terminates the Select Case statement. You must have a Break at the end of every Case
statement unless you want the application to continue execution through to the next Case statement.
The Default case is optional and is executed if the value of the expression does not match any of the Case
constants.
You can add as many Case constants as you want, but there can only be one Default section.

Syntax
Select Case (expression)
Case constant1
statement1
Break
Case constant2
statement2
Break
Default
statement3
SQLWindows evaluates expression. If expression matches constant1, then SQLWindows executes statement1.
If expression matches constant2, then SQLWindows executes statement2. If no Case constant matches
expression, then SQLWindows executes the statements under Default.

197
Example
Select Case ( SalDateQuarter( dtDate ) )
Case 1
Set strQuarter = 'First Quarter'
Break
Case 2
Set strQuarter = 'Second Quarter'
Break
Case 3
Set strQuarter = 'Third Quarter'
Break
Case 4
Set strQuarter = 'Fourth Quarter'
Break
Default
Set strQuarter = 'Error'

Set
Assigns a value to a variable.

Syntax
Set VariableName = Expression

Examples
Set MsgTxt = 'Not a valid number'
Set Errno = SqlError (hSql)
Set fldName = 'Washington'
Set fldName = GetName( )

When SqlError
By default, when a SQL function fails, SQLWindows displays a dialog that contains an error number, error
description, and error position. You can override this default error processing at a local level using the When
SqlError statement in any outline section.
You must code the When SqlError statement:
• Before the Sql* function
• At the same indent level as the Sql* function
You can also control SQL error handling at a global level by processing SAM_SqlError in the application actions
section (see SQL Error Handling on page 325).

While
The While statement repeats until the expression being evaluated becomes FALSE.

198
Syntax
While expression
statement
SQLWindows evaluates expression. If expression is TRUE, SQLWindows executes statement and re-evaluates
expression. When expression becomes FALSE, SQLWindows executes the next statement after the While
statement.

Example
Set n=0
While n < 10
Set nArray [n] = 0
Set n = n + 1

Comments
A line that starts with an exclamation point (!) is a comment. If you put an exclamation point anywhere
except at the beginning of a line, the rest of the line is a comment.

Example
! Ask for destination
Call SalModalDialog (OutBox, hWndForm)

Text style
SQLWindows displays comments in gray by default. You can change this to a different color or style (see
Preferences on page 94).

Collapsible comments
You can create collapsible comments. For example, you can have a one-line summary description for a
section of code with several lines of detailed explanation at the next level. When collapsed, the details are
hidden. Here is how to create collapsible comments:
• Add a comment line that is the one-line summary and press Enter.
• Display Coding Assistant. There is an exclamation point in the Add Next Level list.
• Double-click the exclamation point to add a line at the next level. Enter the comment text and press
Enter.
• When a nested comment line is selected, Coding Assistant displays an exclamation point in both the Add
Same Level and Add Next Level lists. You can continue adding to the current comment at the same level
or the next level or you can start a new comment.
The following is an example of a collapsible comment with nested levels (shown without the diamonds):

199
! Short pithy description
! Some details ...
! More details ...
! More details ...
! Even more details ...
! Even more details ...
! Even more details ...
! More details ...
! More details ...

Reserved Words
Some words cause compile errors when used as function names or variable names in SAL. The following
words case-sensitive. Using a word with a different case might work, but using any of these words as function
names or variable names is not recommended.

Word Used as function name Used as variable name

This Not allowed Allowed

New Not allowed Not allowed

Break Allowed Not allowed

Call Allowed Not allowed

Else Allowed Allowed

If Allowed Not allowed

Loop Allowed Not allowed

On Allowed Allowed

Return Allowed Not allowed

Select Allowed Allowed

Set Allowed Not allowed

When Allowed Not allowed

While Allowed Not allowed

Functions
A function performs a specific task. There are five types of functions:
• System functions
200
• External functions
• Internal functions
• Window functions
• Class functions
You write internal functions, window functions, and class functions. In some cases, you write external
functions.

System Functions
SQLWindows has built-in system functions that you can call in an application:
• Functions with names that begin with Sal perform tasks such as handling windows, validating fields,
managing files, managing lists, and manipulating strings
• Functions with names that begin with Sql perform database operations
The SQLWindows Function Reference explains the system functions. Chapter 12, SQL Programming, also
explains the Sql* functions.

External Functions
In a SQLWindows application, you can call external functions in a DLL (Dynamic Link Library). See Chapter 22 –
Calling External Functions in Dynamic Link Libraries.

Internal Functions
You write internal functions in the Internal Functions section under Global Declarations.

Window Functions
You write window functions in top-level windows (form windows, dialog boxes, and table windows) and in
MDI windows.
Within the function definition, you can access all variables and objects defined by the window without
qualification.

Class Functions
You write class functions in the Class Definitions section under Global Declarations.
Chapter 8, Object-Oriented Programming, explains class functions.

Writing Functions
This section shows how to code internal, window, and class functions. The next sections explain the parts of
the outline for a function.

201
Function Name
This is the name of the internal function. You refer to this name when you call the function.

Description
What the function does.

Returns
If the function returns a value, enter the data type and name of the return value. Leave this blank if the
function does not return a value.
If the result of the function is assigned to a variable, the data type of the variable and the data type of the
function return value must match.

Parameters
A list of the parameters that a caller passes to the function. You declare each parameter in the same way as a
variable, specifying a variable name and a data type.
The caller of a function must pass data that matches parameter's data type.
Receive data types. If a function changes the value of the parameter, you must prefix the data type of the
parameter with the keyword Receive. For example:
Parameters
Receive Number: nVarContainsNumber
Receive data types are passed by reference, which means that SQLWindows passes the variable's storage
address, and the function can change the value of the variable and that change is visible after the function
returns. If you do not code the Receive keyword, the parameter is passed by value, which means that
SQLWindows only passes a copy of the variable. If the function changes the parameter, the change is not
visible after the function returns.

Static Variables
Static variables have values that persist between calls to a function. Their scope is the function where they
are defined. You access them in the same way as local variables in a function.

Local Variables
This section contains local variables available to this function only. SQLWindows creates local variables when
you call the function and destroys local variables when the function returns.
You declare each local variable with a variable name and a data type.
Note: Never use a local variable for a bind or into variable if the SQL statement is prepared in the function
and is then executed/fetched outside the function.

Actions
This section contains statements that execute when you call the function. You can code any SAL statements in
this section.
The function terminates when:
• A Return statement executes. The value of the Return expression is returned to the caller.
• The last statement executes.

202
Example
Function: DoQuery
Description: Prepare and open a SQL query and fetch 1 row
Returns
Boolean:
Parameters
! Sql Handle Sql
Handle: hSql
! Sql statement
Receive String: strSql
Static Variables
Local Variables
Actions
Call SqlPrepare(hSql, strSql)
Call SqlOpen(hSql, 'QUERY')
Return SqlFetchNext( hSql )

Calling Window Functions


This section explains the ways that you can call window functions.

Unqualified Reference
Only call a window function with an unqualified reference in:
• The window object that defines the function
• A child window contained in the window, regardless of its depth of nesting Use the same syntax that you
use to call an internal function:
Call WindowFunction( parameters )

Object-Qualified Reference
To call a window function defined by a child of the current window, use an object- qualified reference that
qualifies the function name with the object name of the child:
Call childWndName.WndFunc( parameters )
You can also use this syntax to call a function:
• Defined in the current window
• Defined in a window unrelated to the current window if the window name is a top-level window or MDI
window and only one instance has been created
• Defined or inherited by the object's class, if the named object is an instance of a class

Fully Object-Qualified Reference


From outside a window, you can use a fully object-qualified reference. Specify a window handle:
Call hWnd.objectName.WndFunc( parameters )
You can use this type of qualification to call a function for a window with multiple instances.
203
Late-Bound Fully Class-Qualified Reference
Use this syntax when the object identified by the handle is one of the following:
• An instance of the specified class (cls in the following example)
• An instance of a class derived from the specified class; for example:
Call hWnd.cls..function( parms )
See Chapter 8 – Object-Oriented Programming.

Command Line Arguments


When you start a SQLWindows application, you can specify arguments. Within the application, you can find
the number of command line arguments and the value of each command line argument by checking these
system variables:
• nArgCount contains the number of arguments on the command line including the application name.
• strArgArray[*] is an array of strings. Each argument is read into an element of strArgArray when the
application starts. The 0th element contains the application name.

Using SalLoadApp with Command Line Arguments


You can start another application by calling SalLoadApp. You can use SalLoadApp to pass command line
arguments from one application to another.
The format for SalLoadApp is:
SalLoadApp( strAppName, strParameters )
where strAppName is the application to start and strParameters is the command line arguments.
A space in strParameters marks the end of one argument (token) and the start of the next (if any). For
example, if you pass this string in strParameters:
SalLoadApp( 'example.exe', 'one two three' )
then strArgArray[1-3] contains “one”, “two”, and “three” respectively and nArgCount contains 4. SQLWindows
does not pass the spaces to the application.
To pass a space in an argument, place a double quote character before and after it. For example, to pass the
string “Hello there” in strArgArray[1] and “SQLWindows” in strArgArray[2]:
SalLoadApp( 'example.exe', 'Hello" "there ' || 'SQLWindows' )
Those are double quote characters before and after the space between “Hello” and “there”. Also, there is a
space after “there,” which tells SQLWindows that this is the end of this token and the start of the next.

Using the Clipboard


The Clipboard is a common area that Windows applications use to exchange formatted data.

204
Clipboard Functions
You use the following SQLWindows functions to cut and paste with the Clipboard:

Function Name Description

SalEditCut Cuts selected text from a data field, multiline field, or table window cell and puts it
on the Clipboard.
SalEditCanPaste Returns TRUE if there is anything on the Clipboard to paste.

SalEditPaste Pastes text from the Clipboard to the text insertion point.

SalEditPasteString Pastes text from the Clipboard to a string.

SalTblPasteRows Pastes text from the Clipboard to one or more table window rows. The text to be
pasted must have tabs separating each column and an end-of-line character at the
end of each row.
SalEditCopy Copies selected text from a data field, multiline field, or table window cell and puts it
on the Clipboard.
SalEditCopyString Copies a string to the Clipboard as text.

SalTblCopyRows Copies one or more table window rows to the Clipboard. Tabs are placed between
columns and an end-of-line character is placed at the end of each row.

Resources
You can specify bitmaps, icons, or cursors in the Global Declarations and refer to them with the SalPicSet or
SalCursorSet functions. Resources appear in Coding Assistant. This is an example of the Resources section in
Global Declarations:
Global Declarations
...
Resources
Bitmap: Bm1
File Name: bm1.bmp
Icon: Icon1
File Name: icon1.ico
Cursor: Cur1
File Name: cur1.cur
When you go into run mode at design time, SQLWindows must be able to find the resources in external files.
When you make an *.EXE version of the application, SQLWindows copies the resources from the external files
into the application. You do not need to distribute the external files with production versions of an
application.

Yielding
Yielding is the ability of an object to give control to another object. SQLWindows has two types of yielding
that you can control:
205
• Intra-application: between objects in the same SQLWindows application
• Interapplication: between a SQLWindows application and other Windows applications

Intra-application (SalYieldStartMessages and SalYieldStopMessages)


By default, while actions for a given object execute, no other object in the same application can get control.
Once execution starts in an actions section, all statements logically execute. (However, objects in other
applications can get control.) In other words, the default execution is synchronous within the application. You
can change the default behavior with SalYieldStartMessages and make the actions for a object asynchronous.
The following example shows this:
Form Window: frmMain
...
Contents
Data Field: dfCount
! The data type of this data field is Number.
...
Pushbutton: pbStart
Message Actions
On SAM_Click
Call SalYieldStartMessages( pbStop )
Call SalDisableWindow( pbStart )
Call SalEnableWindow( pbStop )
Set bStopped = FALSE
Set dfCount = 0
While dfCount <= 1000
Set dfCount = dfCount + 1
If bStopped = TRUE
Break
Pushbutton: pbStop
Message Actions
On SAM_Create
Call SalDisableWindow( pbStop )
On SAM_Click
Set bStopped = TRUE
Call SalYieldStopMessages( )
Call SalDisableWindow( pbStop )
Call SalEnableWindow( pbStart )
Window Variables
Boolean: bStopped
...
In the example, the SAM_Click processing for the pbStart push button calls SalYieldStartMessages for the
pbStop push button and then goes into a simple loop. When you run this example, you can click pbStop after
clicking pbStart to end the loop. When you click pbStop, SQLWindows suspends the loop for pbStart and
executes the SAM_Click processing for pbStop, which sets the bStopped variable to TRUE. After the
SAM_Click processing for pbStop completes, SQLWindows resumes executing the loop for pbStart. Because
pbStop set the bStopped variable to TRUE, pbStart breaks the loop and processing ends.
When you specify hWndNULL as the parameter for SalYieldStartMessages, SQLWindows lets all other objects
receive messages:
Call SalYieldStartMessages( hWndNULL )
If you specify hWndNULL as the parameter, be sure to call SalDisableWindow for any user interface object
that you do not want users to access.
You can call SalYieldStopMessages to stop yielding to the object specified in the earlier call to
SalYieldStartMessages.

206
Interapplication (SalYieldEnable and SalYieldQueryState)
Microsoft Windows is a cooperative multitasking environment. While an application executes, it must
periodically let Windows run other applications (yield). C or C++ applications do this by calling a Windows API
function such as PeekMessage.
SQLWindows automatically does this for you (this is called autoyielding). When SAL code executes,
SQLWindows periodically lets other applications run. If SQLWindows did not do this, no other applications
would run while long blocks of SAL code execute.
Also, when a Sql* function starts a long operation on a server, SQLWindows tries to give other applications a
chance to run on the client. However, this may be limited by the server vendor’s connectivity software.
You can disable autoyielding by calling SalYieldEnable( FALSE ). This prevents the user from switching to any
other application while code is executing:
Pushbutton: pbNoYield
Message Actions
On SAM_Click
Call SalYieldEnable( FALSE )
Set dfCount = 0
While dfCount <= 1000
Set dfCount = dfCount + 1
When you run this example and click the pbNoYield push button, the application never yields to other
applications. You can verify this by starting Microsoft CLOCK.EXE, setting it to analog mode with a second
hand, and then running the example above. While the loop above executes, the second hand on the clock
does not move because CLOCK.EXE never gets control. Also, if you press Ctrl+Alt+Del while the loop above
executes, Windows displays the message “this Windows application has stopped responding to the system”
because not even Windows can get control.
Call SalYieldQueryState to find if autoyielding is set to TRUE or FALSE.

207
Chapter 8 – Object-Oriented Programming
This chapter shows how to use SQLWindows object-oriented programming features and covers these topics:
• Classes, inheritance, and objects
• Defining classes
• Creating objects
• Message actions
• Instance variables
• Class variables
• Class functions
Object-oriented programming (OOP) gives you the ability to:
• Define classes
• Derive new classes based on existing classes
• Create objects that belong to a class

Objects, Classes, and Inheritance


Object
An object is a software entity that combines:
• Data that represents the object
• Procedural code that retrieves or changes the object's data (this is called the object's behavior)
An object can represent:
• A tangible concept such as a window
• An intangible concept such as a checking account
An object is an instance of a class. An object has the data and behavior of its class.
Objects that are instances of classes are called user-defined because you specify their behavior in classes.

Class
A class is a blueprint for making objects. In a class, you define a shared data structure and behavior for
objects that you later create as instances of the class. You define the same data and behavior for a set of
objects without duplicating the code for that data and behavior in each object.
The objects of a class share a common data structure and common behavior, but each object in a class has its
own private data values.

208
Inheritance
Inheritance lets you define new classes in terms of existing classes. A new class that you derive from a base
class inherits data and behavior from its base class. As well, a derived class can:
• Extend the base class by adding new data and behavior. New data and behavior that you add becomes
part of the derived class in addition to the data and behavior inherited from the base class.
• Modify the base class' behavior by redefining inherited behavior.
SQLWindows uses the extended or modified data and behavior for the derived class, but the original data and
behavior remain valid for the base class.
All of a derived class' data and behavior-new, modified, or inherited-is inherited in turn by its derived classes.

Designing Classes and Objects


Follow these general steps to design classes and objects:
Step 1. Decide which classes of objects to use.
Step 2. Choose variables and functions for each class. For windows classes, also choose message actions.
Step 3. Arrange the classes in a hierarchy.

Writing Applications with Classes and Objects


There are two main steps in writing an application that uses classes and objects:
Step 1. Create classes in the class definitions section under global declarations in the outline.
Step 2. Create objects that are instances of the classes. This is like creating standard window objects.

Class Inheritance
You can define classes in terms of other classes. One class inherits behavior from one or more other classes.
There are two types of inheritance:
• Single inheritance
• Multiple inheritance

Single Inheritance
With single inheritance, you derive a class from another class called the base class:

209
The word single in single inheritance means that a class has only one direct base class.
Multiple levels of inheritance are allowed. In other words, you can use inheritance to create a class hierarchy,
as follows:

The diagram shows that class A is a base class of classes B and C:


• Class A is a direct base class of class B and an indirect base class of class C.
• Class C is directly derived from class B and indirectly derived from class A.

Multiple Inheritance
With multiple inheritance, a class has more than one direct base class. The following diagram shows that class
D inherits behavior from two direct base classes, B and C:

210
Types of Classes
SQLWindows has three types of classes:
• Functional class
• Window class
• General window class

Functional Classes
A functional class supplies behavior through its functions. You use functional classes to:
• Create user-defined variables (UDVs) (see page 213)
• Define behavior that is shared by more than one window class
A functional class can be:
• A base class of another functional class
• A base class of a window class
• Derived from another functional class, but not from a window class

If behavior needs to be shared by more than one window type, you can place the behavior in a functional
class and then derive window classes from that functional class. The derived classes inherit the common
behavior as well as behavior appropriate to their window type.

Window Classes
There is a class for each standard window type. A window class can be:
• A base class only of the same window class type. For example, a data field class can be the base class only
of another data field class
• Derived from another window class of the same type or from a functional class

211
General Window Classes
With general window classes, you can create classes with both message actions and functions that you can
use with any type of window. A general window class is like a functional class, except that it has a message
actions section.
General Window Class: <name>
Description:
Derived From Class
Variables Instance
Variables
Functions
Message Actions
These are the inheritance rules for general window classes:
• A general window class can be a base class of any window class, including other general window classes
• A general window class can be derived from functional classes or another general window class
• Multiple inheritance is supported
A general window class cannot be a base class of a functional class
You cannot create an instance of a general window class. You can only use a general window class as a base
class of a concrete window class.

Types of Objects
SQLWindows has three types of objects:
• Standard window objects
• User-defined window objects
• UDVs
You use classes and inheritance to create two types of user-defined objects:
• Visual objects are user-defined windows
• A non-visual object is a UDV

212
User-Defined Windows
You create a user-defined window as an instance of a window class:

A user-defined window object is like a standard window object because it:


• Has visual properties (you can see it, unless it is hidden or invisible)
• Is associated with a window handle that identifies it
• Can receive Windows messages and SAM_* messages
You customize the window's behavior through its class definition.

User-Defined Variable (UDV)


You create a UDV as an instance of a functional class:

UDVs are non-graphic objects. They are different from other variables because the only way you can access a
UDV is through functions defined in its class. These functions are the UDV's public interface.
You can place a UDV in any variables section in the outline. A UDV:
• Does not have a handle like a user-defined window.
• Cannot respond to messages.
• Has no value and cannot be used in an expression.

Defining Classes
You define classes in the class definitions section near the bottom of the global declarations in the outline.
The following example shows six collapsed classes: cls1, clsMDIFrame1, clsDataEntryForm, clsDlgStandard,
and clsDatabaseField.

213
Global Declarations
...
Class Definitions
Functional class: cls1
MDI Window Class: clsMDIFrame1
Form Window Class: clsDataEntryForm
Dialog Box Class: clsDlgStandard
Data Field Class: clsDatabaseField
The next sections discuss functional classes and window classes.

Defining Functional Classes


Outline items for a functional class are the following:
Functional Class: <class name>
Description: <text>
Derived From
Class Variables
Instance Variables
Functions

Item Description
class name The name of the class.
Description Optional text that describes the purpose of the class.
Derived From A list of class names from which this class is derived. Only list other functional
classes. You can select classes in Coding Assistant.
Class Variables Variables shared by all objects of this class.
Instance Variables Variables replicated and private to each object of this class.
Functions Functions accessible only to objects of this class.

Later sections in this chapter explain class functions, class variables, and instance variables.
Functional classes cannot inherit from window classes; therefore, functional classes do not have a message
actions section.

Window Classes
This section discusses characteristics that are common to all window classes. Later sections discuss the
unique characteristics of classes for the different types of window classes.

Attributes
Attributes that you set are inherited by:
• Derived classes
• Objects of the class
214
You can redefine inherited window properties in a derived class or in an object you create as an instance of
the class.
For multiple inheritance with conflicting attributes, SQLWindows uses the first non- default setting it finds
and ignores other non-default settings.

Class Default property


To inherit an attribute from base classes, select the Class Default property. Any other value you specify for an
property overrides the value inherited from base classes. If all base classes define Class Default for an
property, then SQLWindows sets the property to its internal default.
The attributes Object Title, Icon File, and Picture File Name use an empty string to indicate the Class Default.
For example, if the Object Title of a class object contains nothing, it inherits the Object Title of its base
classes.
Group boxes and background text class objects inherit their title from an property called Object Title in a class
definition.
A class or class object can inherit almost every other attribute. Exceptions are Window Top and Window Left,
which are explained below.

Window position
You do not specify position information for a window class. You specify position information when you
create a window that is an instance of the class.

Window size
For most class types, you can define the Initial Width and Height of objects. This sets the initial size of an
object when created on a form window or dialog box using the Controls palette or Coding Assistant.
However, setting the initial width and height does not prevent you from resizing the object with the mouse.
Once you resize an object, it no longer inherits the initial width and height from its base class (for example,
subsequent changes to the object’s base class initial width and height do not affect the object’s size).
Classes have two additional properties that you can use to control the sizing behavior of objects: Width
Editable and Height Editable:
• Setting these to Yes before creating an object prevents that object from being sized differently than the
class definition
• Setting these to Yes after creating an object forces the size of all existing object to the Initial Height or
Initial Width defined by the class

Window Class Definition Outline Items


All window classes have these common outline items:

Item Description
Class Type and Name The class type is to the left of the colon (for example, Data Field Class). The class
name is to the right of the colon (for example, clsDataField1)
Description Optional text that describes the purpose of the class.

215
Item Description
Derived From A list of class names from which this class is derived. Only list functional classes or
window classes of the same window type as the current class. You can select
classes in Coding Assistant.
Class Variables Variables shared by all objects of this class.
Instance Variables Variables replicated and private to each object of this class.
Functions Functions accessible only to objects of this class.
Message Actions Standard message handlers.

Later sections in this chapter explain class functions, class variables, instance variables, and message actions.

Types of Window Classes


The window class types are grouped into these categories:
• Child window and dialog box classes
• Form window, top-level table window, and MDI window classes

There is separate class for each type of window. The definition for each type of window class is almost the
same, but there are a few differences.

Child Window Classes


You can place objects that you create as instances of these classes in the contents section of top-level
windows (dialog boxes, form windows, and table windows).

Outline items
The outline items for child window classes are:

216
<class type>: <class name>
Description: <text>
Derived From
Class Variables
Instance Variables
Functions
Message Actions

Multiple inheritance with list initialization


If a class for a list box or combo box inherits from more than one base class, SQLWindows uses the
first list initialization and ignores the others.

Dialog Box Classes


A dialog box class has the same outline items as the child window classes. A dialog box class also has a
contents section and can have a toolbar.

Form Window, Top-Level Table Window, and MDI Window Classes


These classes have two items that child window and dialog box classes do not:
• Menu
• Status bar

Outline items
These are the outline items for form window, top-level table window, and MDI window classes:
<class type>: <class name>
Description: <text>
Derived From
Menu
Toolbar
Class Variables
Instance Variables
Functions
Message Actions
The following outline items are unique to these types of window classes:

Item Description
Menu Default menu definition for window objects that are instances of the class
Toolbar Default toolbar definition for windows that are instances of the class

Later sections in this chapter explain class functions, class variables, instance variables, and message actions.

Menu
If you do not define a menu in the class, then it inherits the complete menu definition of its base class.
If you define a menu in an application window class, then it completely overrides an inherited menu
definition.

217
With multiple inheritance, if a derived class inherits a menu from more than one direct base class,
SQLWindows uses the menu of the first class that defines a menu in the Derived From list and ignores the
other menus.

Toolbar
If you do not define a toolbar in the class, then it inherits the complete toolbar definition of its base class.
If you define a toolbar in an application window class, then it completely overrides an inherited toolbar
definition.
With multiple inheritance, if a derived class inherits a toolbar from more than one direct base class, you get
an error when you compile unless you define a toolbar in the derived class.

Status bar
Use the Attribute Inspector to specify whether the window has a status bar.
The setting that you specify is inherited by derived classes and objects of the class.
You can redefine an inherited status bar setting in a derived class or in an objects of the class.
With multiple inheritance, if a derived class inherits conflicting settings for the status bar from its base
classes, you get an error when you compile. If this happens, use the the Attribute Inspector to clarify the
ambiguity in the derived class.

Class Contents Inheritance


With class contents inheritance, you can define window classes with child items that are common across all
objects of the class. You can place child objects in the class definitions of:
• Top-level objects (form windows, table windows, and dialog boxes), including child objects in toolbars
• MDI windows (in the toolbar only)
A child item defined in the contents of a class or in a class’ toolbar is called a class child.

Inheriting Class Children


When you create an object that is an instance of a class with class children, the object inherits all the class
children. The inherited children are called class child instances.
A class child instance inherits all the properties defined by the class child such as color, size, position, and
data type. You can override these properties by editing the class child instance. The Attribute Inspector
displays all the attributes of a class child instance.
Class child instances also inherit the actions defined by the class child. These are not displayed in the outline,
but they execute at runtime. You can add additional actions to a class child instance to supplement the
actions defined by the class child.

218
Multiple Base Classes
If you derive a class from multiple base classes that contain class children, SQLWindows combines the class
children when you create an object that is an instance of the class. Here are examples of what you can do
with multiple inheritance:
• Define one class with class children in the toolbar and another class with class children in the contents.
You then use both classes as base classes to derive a single class that has both sets of class children.
• Define several classes, each with a group of related class children. You can then derive new classes that
combine the groups.

Class Children
Add class children to a class definition by:
• Editing the outline with Coding Assistant
OR
• Editing the outline directly by typing
A class child can be a standard SQLWindows object or an instance of a class. You can use the Attribute
Inspector to change class child attributes.
Classes that you derive from a parent class inherit the class children. When you edit a class derived from a
base class with class children, SQLWindows displays the class children of the base class. You can edit the
attributes of inherited class children.
When you add or change a class child, objects that are instances of the parent class are affected immediately.
For example, when you add a class child, SQLWindows updates all windows that are instances of the class.
You can define the tab order of class children by selecting Layout > Tab Order. SQLWindows uses this tab
order when you create an object that is an instance of the class. However, later changes to the tab order in
the class definition do not affect an object that is an instance of the class. You must use the Tab Order
command on the object.
You refer to a class child by its name. For example, this statement is valid for a class child called df1:
Set df1 = 'abc'
SQLWindows uses the same rules for default names for class children as for other objects.

Class Child Instances


SQLWindows displays class child instances the same as other child objects.
The attributes of the object can be inherited from the class child or overridden (including the top and left
coordinate of the class child). Most properties have a Class Default setting that uses the properties of the
class child. Also, you can supplement or override actions inherited from a class child.
You can set the tab order of an object with class child instances by selecting Layout > Tab Order. By default,
the tab order for all class child instances is the order defined in the parent class.
You cannot use the Object Duplicator to copy a class child instance. A class child instance has a name with this
format:

219
ClassChildName from ClassName: ObjectName
ClassChildName is the name of the class child as declared in the base class (such as df1). ClassName is the
name of the class (such as clsForm). ObjectName is the name of the class child instance.

Example
By default, ObjectName is the same as the ClassChildName.
You cannot edit ClassName and ClassChildName. You can edit ObjectName. For example, you can change
ObjectName when it is a duplicate symbol.
You refer to a class child instance by its name. For example, this statement is valid for a class child instance
called df1:
Set df1 = 'abc'
In this example, the Class Definitions section of the outline has two classes:
• A data field class named CdfDateTime.
• A form window class named CForm1 with two class children. The push button (pb1) is a standard
SQLWindows object and the data field (df1) is an instance of the class CdfDateTime.
Class Definitions
Data Field Class: CdfDateTime
...
Form Window Class: CForm1
...
Contents
Pushbutton: pb1
...
CdfDateTime: df1
...
When you create an instance of the form window class, it appears in the outline as:
CForm1: frm2
...
Contents
pb1 from CForm1: pb1
...
df1 from CForm1: df1
...

Naming Child Objects


If you use inheritance with window classes, give each child object in the class its final name immediately after
you create it. This applies to both base classes and new child objects that you add to derived classes in the
hierarchy.
SQLWindows does not propagate child object name changes to existing derived classes or instances.
For example, if you already have this hierarchy and you add a data field to CDerived, its default name is df1 in
both CDerived and frm1. If you rename the data field in CDerived, the change does not propagate down to
frm1 where its name if still df1. If you then add a data field to CBase, its default name is df1 in CBase,
CDerived, and frm1.

220
If you rename the data field in CBase, its name does not change in CDerived and frm1. The result is two data
fields in frm1 with the same name.

Creating User-Defined Objects


After you define classes, you can create objects that are instances of those classes.
When collapsed, a standard object definition and a user-defined object definition look similar. Each has:
• An object type
• A colon
• An object name
For example, this is a standard object definition:
Data Field: df1
In the example above:
• Data Field is the type of standard object
• df1 is the name of the standard data field object For example, this is a user-defined object definition:
ClassDbField: dbField1
In the example above:
• ClassDbField is the name of a class. The class name is also called a type.
• dbField1 is the name of the user-defined object.
When you define an object, you need to specify the object's name and other properties. The next sections
describe the properties that you need to specify when you create an object that is an instance of a class.

Changing an Object’s Class


You can change an object’s class name by editing the title in the outline. For example, in an application that
has the data field classes “clsdf1” and “clsdf2”, you can change “Data Field” to “clsdf1”, “clsdf1” to “Data
Field”, and “clsdf1” to “clsdf2”.

221
Creating UDVs
To insert a UDV (an instance of a functional class) in the outline:
• Choose a UDV in Coding Assistant.
OR
• Type a UDV directly into the application outline. You can insert a UDV in any variables section of the
outline.
UDVs are specified completely by their classes. The only properties you specify in the outline are the name of
its class and the name of the object.
This outline fragment is for a UDV (buf1) that is an instance of functional class (ClassBuffer):
Form Window: frmMain
...
Window Variables
ClassBuffer: buf1
...
A UDV does not have a “value”. This means that you cannot use a UDV:
• As the source or target of a Set statement
• In any other expression
The only interface for a UDV is through the functions defined in its class. A later section discusses how to call
class functions. You can access variables defined in a UDV with object-qualified references:
If emp.salary > 2000
...
In the SAM_Create action below, a class named ClassBuffer has defined or inherited a function called insert
that accepts a number and string as arguments:
Form Window: frmMain
...
Window Variables
ClassBuffer: buf1
...
Message Actions
On SAM_Create
Call buf1.insert( 37, 'Hello' )

Passed by Reference
SQLWindows always passes UDVs by reference. A called function or top-level window can both read and write
the UDV’s instance variables.

Arrays of UDVs
You can declare instances of functional classes as arrays. The arrays can be dynamic.
You can use arrays of UDVs to create multidimensional arrays. The following example defines a functional
class called Employee that contains instance variables for the employee’s name, department, and salary and a
function called ChangeSalary:

222
Functional Class: Employee
...
Instance Variables
String: Name
String: Dept
Number: Salary
...
Functions
Function: ChangeSalary
Parameters
Number: NewSalary
Actions
Set Salary = NewSalary
...
The form window declares an array of Employee objects in its Window Variables section:
Form Window: frm1
...
Window Variables
Employee: emp[*]
...
You access instance variables or functions defined or inherited by a class of a user- defined variable by
indexing the array name and qualifying it with a period and the instance variable name; for example:

emp[1].Name reference

emp[2].ChangeSalary( 100000 ) function call

You can also make qualified references and qualified function calls:

hWnd.frm1.emp[1].Name reference

hWnd.frm1.emp[2].ChangeSalary( 100000 ) function call

Assigning UDVs
You can assign one UDV to another using the standard syntax:
Set functionalClassVar2 = functionalClassVar1
functionalClassVar2 and functionalClassVar1 must be the same type, or functionalClassVar2 is of a type from
which the type of functionalClassVar1 derives.
Note: Functional class variables are references, not actual values. After you perform an assignment, both
variables refer to the same object and changes made through one variable changes the object itself
and that change is visible in any other variable that refers to that object.

Example
Assume this class/object hierarchy in the code that follows:

223
Functional Class: fClassBase1
...
Functional Class: fClassBase2
...
Functional Class: fClassDerived1
...
Derived From
Class: fClassBase1
Functional Class: fClassDerived2
...
Derived From
Class: fClassBase2
These assignments are always legal:
Set vBase1 = vDerived1 Set vBase2 = vDerived2
These assignments are always illegal:
Set vBase2 = vDerived1 Set vBase1 = vDerived2
This assignment is legal only if vBase1 has most recently been assigned to a value of type vDerived1:
Set vDerived1 = vBase1
If vBase1 is actually a reference to an object of type fClassBase1, the assignment fails at runtime.

Type safe casting


A cast is an action that converts an object from one type or class to another. In SQLWindows, you can safely
cast an object to a class higher in its class hierarchy (upcast) or lower in its class hierarchy (downcast).
Consider this class/object hierarchy:

224
Functional Class: fClassBase1
...
Functional Class: fClassBase2
...
Functional Class: fClassDerived
...
Derived From
Class: fClassBase1
Class: fClassBase2
...
fClassBase1: vBase1
fClassDerived: vDerived1
fClassDerived: vDerived2
Given the hierarchy above, this is an example of a type safe upcast:
Set vBase1 = vDerived1
This is an example of a type safe downcast:
Set vDerived2 = vBase1

Setting UDVs to null


Use the OBJ_Null constant to make a UDV null:
Set functionalClassVar1 = OBJ_Null
To force release of an object safely, assign OBJ_Null to an object variable. This causes the same sequence as
going out of scope and causes the referenced object to be freed if there are no other references to it in your
application.

Checking for null objects


You can call SalObjIsNull to test an object to see if it is null:
If SalObjIsNull( functionalClassVar1 )
...
The code above is equivalent to:
If functionalClassVar1 = OBJ_Null
...

Dynamic Instantiation
When you declare a UDV, SQLWindows creates it at runtime and you can refer to it. However, you can re-
initialize it at any time using the new keyword:
Set functionalClassVar = new functionalClassName
The new keyword takes as an argument the type of object being created and returns a reference to an object
of that type. functionalClassVar must be a variable of type functionalClassName.

Object Destructors
SQLWindows maintains reference counts on UDVs, destroying them when their count drops to zero. If you
want to perform some cleanup operation before an object is destroyed, then you must define a destructor for
it.

225
Define a method in the class with the name “ObjectDestructor”. This method must not have a return type
and must not have any parameters, local variables, or static variables. Otherwise, the compiler displays an
error message.
SQLWindows destroys objects in three different ways:
• When the reference count of the object drops to zero.
• When an object goes out of scope during execution (such as a local variable going out of scope when a
function exits) and as execution terminates (this is relevant only to global objects and the objects to
which they refer).
• When the runtime system for the process or thread is terminating.
Warning: When objects are destroyed in either of the first two cases, there is a SAL execution environment
in which the ObjectDestructor function (if one exists) can be called. However, objects that are
“leaked” (that is, there are no application references to them during shutdown) are only detected
after the SAL execution environment has terminated, and so it is not possible to run the
ObjectDestructor function. The memory used by these leaked objects will be freed, but the
destructors are not executed.
Warning: Do not refer to globals in an ObjectDestructor method. The order in which globals are destroyed
is unpredictable and a global that you refer to can no longer exist. You can control the order that
globals are destroyed somewhat by assigning OBJ_Null to them.

SalObj* Functions
You can use the following SalObj* functions with UDVs:

Function Description
SalObjCreateFromString Creates an instance of a functional class name that you specify.
SalObjGetType Gets the class name of a UDV that you specify.
SalObjIsDerived Determines if a UDV is an instance of a specified class.
SalObjIsNull Determines if a UDV is null. See Checking for null objects on page 225.

Creating User-Defined Windows


To insert a user-defined window (an instance of a window class) in the outline:
• Click the right mouse button, select New, and then choose a user-defined window in the menu.
OR
• Select Component and then choose a user-defined window in the menu.
OR
• Choose a user-defined window in Coding Assistant.
OR
• Choose a user-defined window from the Controls palette.
OR
226
• Type a user-defined window directly into the application outline.

Using the Controls Palette

For child window types, the Controls palette displays the names of child window classes in a list box. For
example, when the data field tool is selected, the Controls palette displays “Standard” for a standard data
field and displays the class name for each data field class. Click on one of the names in the list before you
place the object. The most-recently selected name is at the top of the list.

“List in Controls palette” attribute


When you set this to No, SQLWindows does not list the class name in the Controls palette. You can set this to
No for classes that you only intend use as base classes. This keeps the Controls palette list from getting
cluttered with classes that you do not intend to create instances of. This item defaults to Yes.

Components
A user-defined window object definition has the same components as a standard window definition for the
same window type; for example:
• A user-defined form window and a user-defined data field have message actions sections and you can set
their window attributes
• A user-defined form window has a contents section and a menu section like a standard form window
• A user-defined data field does not have contents or menu sections because a standard data field does not

Overriding Inherited Attributes


You can use the Attribute Inspector to override inherited attributes.

Using Message Actions in Classes


This section explains how a window class:
• Inherits messages actions

227
• Overrides inherited message actions
• Invokes overridden message actions

Message Actions with Single Inheritance


The following sections explain how you can use inheritance with message actions in a class that has one
direct base class.

Inheriting message actions


A derived class inherits all message actions that its base class defines or inherits. The inherited message
actions execute automatically.

Overriding inherited message actions


To change the behavior of an inherited message action in a derived class, you must redefine the message
action. A message action in a derived class overrides the corresponding message action that its direct base
class defines or inherits. This means that a base class' message action is not executed.

228
Invoking overridden message actions
Even if you override an inherited message action, you can still invoke it. To invoke the message action in the
closest base class that defines a specified message, call SalSendClassMessage in a derived class:
SalSendClassMessage( wMessage, wParam, lParam )

You usually call SalSendClassMessage in a derived class' own definition of the same message action (as shown
in the diagram). This is an example of how a derived class “adds behavior” to its base class’ behavior.
Normally, this is all that you need because the closest base class usually invokes its own base class' version of
the message action. If you need to, you can invoke a message action in a distant base class with
SalSendClassMessageNamed:
SalSendClassMessageNamed( clsName, wMessage, wParam, lParam )
SalSendClassMessageNamed is used more often with multiple inheritance.

229
SalSendClassMessage and SalSendClassMessageNamed are synchronous (they send the message directly to
the receiving object). There are not corresponding asynchronous (post) calls (which send the message to the
Windows message queue).

Message Actions with Multiple Inheritance


The sections below explain how you can use inheritance with message actions in a class that has more than
one direct base class.

Inheriting message actions


A derived class inherits all message actions that its direct base classes define or inherit.

Overriding inherited message actions


A message action in a derived class overrides the corresponding message action that its direct base classes
define or inherit.

230
If more than one direct base class defines or inherits a message action, you get an error when you compile.
You must redefine the message action in the derived class to avoid ambiguity.

If you redefine the conflicting message in the derived class and invoke the message in the base class, you can
avoid getting an error when you compile. This technique is described in the next section.

Invoking overridden message actions


If more than one direct base class defines or inherits the same message action, you can select the message
action to invoke in the derived class with SalSendClassMessageNamed:

231
SalSendClassMessageNamed( clsName, wMessage, wParam, lParam )

You usually specify the name of a direct base class and the SalSendClassMessageNamed function finds the
closest base class of the specified class that defines the message action. You can also use this function to
invoke a message action of a distant base class.
You usually call SalSendClassMessageNamed in a derived class’s own definition of the same message action
(as shown in the diagram). This is an example of how a derived class “adds behavior” to its base class’s
behavior.
SalSendClassMessageNamed is synchronous (it sends the message directly to the receiving object). There is
not a corresponding asynchronous (post) call (which sends the message to the Windows message queue).

Using Message Actions in Objects


This section explains how a window object that is an instance of a class:
• Inherits messages actions
• Overrides inherited message actions
• Invokes overridden message actions

Inheriting Message Actions


A user-defined window inherits the message actions that its direct base class defines or inherits:

232
Overriding Inherited Message Actions
You can override an inherited message action by redefining it in the object:

Invoking Overridden Message Actions


You can invoke a class’s message action that has been overridden by calling SalSendClassMessage:

233
SalSendClassMessage( wMessage, wParam, lParam )

You usually call SalSendClassMessage in an object's own definition of the same message action. This is an
example of how an object “adds behavior” to its class behavior.
SalSendClassMessage and SalSendClassMessageNamed are synchronous (they send the message directly to
the receiving object). There are not corresponding asynchronous (post) calls (which send the message to the
Windows message queue).

Instance Variables
Instance variables in a class are replicated for each object that you create. Each object has its own private
copy of an instance variable.
The following example shows three user-defined data fields (df1, df2, and df3) that are instances of the data
field class cls_df1. Each instance has its own copy of the instance variable str1.

234
Inheritance
If you define child objects with an instance variable, each child object has its own copy. For example, if you
place a data field with an instance variable in a form and then create multiple instances of the form, each
instance of the data field has its own copy of the instance variable.
An instance variable defined in a derived class hides one with the same name defined or inherited by a base
class. If you hide an inherited instance variable, you can still access the base class' version by qualifying the
name of the instance variable with the name of the base class.
With multiple inheritance, if more than one base class defines or inherits the same instance variable, you
get an error when you compile if you refer to the instance variable. Eliminate the ambiguity by qualifying
the name of the instance variable with the name of a class.

Using Instance Variables in Classes and Objects


You can refer to instance variables in two ways:
• Internally for an object that operates on itself. “Operate on itself” means that the object accesses its own
copy of instance variables.
• Externally for an object that operates on another object.

Internal References
In an object that operates on itself, you can access an instance variable with an unqualified reference.
SQLWindows searches an object’s class for variables before searching the containing object or globals. The
search of the object’s class includes the class’s base classes.

235
this Keyword
Each object that is based on a functional class has access to a reference to itself, which is called the this
reference.
There are two situations where you need to use the this reference:
• To pass a reference to the current object as a parameter to a method
• To access a “hidden” variable in a class
• Return the current object from a function
To pass a reference to the current object as a parameter, specify “this”:

236
Service.add( this )
Normally, when you refer to a variable within a class you do not need to qualify the reference because the
variable is in scope. However, if a method defines a variable with the same name as a variable with class
scope (such as an instance variable), the class-scope variable is “hidden” by the method-scope variable. A
hidden variable can be accessed in the method by preceding its name with the keyword this and the dot
operator as in this.x; for example:
Functional Class: fTest
...
Instance Variables
String: str1
String: str2
Functions
Function: f1
...
Parameters
String: str1
String: str2
...
Actions
Set this.str1 = str1
Set this.str2 = str2
...
In the example, the object’s str1 and str2 variables are set with the values of the method’s str1 and str2
parameters respectively.

External References
An object that operates on another object must identify the other object to access one of its instance
variables. You can use:
• An object-qualified reference
• A fully class-qualified reference
• A fully object-qualified reference

Object-qualified reference
If one object contains another object, the containing object can refer to an instance variable in the
contained object (target object).
Qualify the instance variable name with the name of the target object and a period:
Set obj.var = 'test'

237
An object-qualified reference tells the compiler to “look inside” the named object for the instance variable.
The compiler searches for an instance variable with the specified name in these places in this order:
1. The target object
2. The class of the target object
3. A base class of the target object
You can also use an object-qualified reference to access an instance variable in a containing object. In the
diagram on the next page, col1 uses:
• An object-qualified reference:
Set tbl1.str4 = 'test4'
This tells the compiler to look in its containing object (tbl1) for the variable defined in the class MyTable.
• An unqualified reference:
Set str4 = 'test4'
This sets the variable defined in the containing object (frm1).
• An object-qualified reference:
Set frm1.str4 = 'test4'
This sets the variable defined in the containing object (frm1).

Fully class-qualified reference


Use this syntax when the object identified by the handle is an instance of the specified class (cls in the
following example):
Set hWnd.cls.str5 = 'test5'

Fully object-qualified reference


In this syntax, you specify a window handle and an object name:
Set hWnd.obj.str6 = 'test6'
At runtime, SQLWindows searches for the instance variable in these places in this order:
1. The object identified by hWnd
238
2. The object's class
3. A base class of the object's class
If the window is an instance of a class, and both the window and the class define variables with the given
name, then SQLWindows accesses the window variable instead of the class variable.
If the object you specify does not define or inherit the variable you specify, you get an error when you
compile.

Class Variables
Class variables are:
• Allocated only once for a class
• Shared by all objects in the class
A class variable is like a global variable, but it is only visible to the defining class, derived classes, and objects
of the class.
The following diagram shows three user-defined data fields (df1, df2, and df3) that are instances of the data
field class cls_df1. Each instance shares the same copy of the class variable str1.

If you define child objects that have class variables, they all share the same copy. For example, if you place a
data field with a class variable in a form and then create multiple instances of the form, all instances of the
data field share the same value of the class variable.

Inheritance
A class variable defined in a derived class hides one with the same name defined or inherited by a base
class. If you hide an inherited class variable, you can still access the base class version by qualifying the
name of the class variable with the name of the base class.

239
With multiple inheritance, if more than one base class defines or inherits the same class variable, you get
an error when you compile if you refer to the class variable. Eliminate the ambiguity by qualifying the name
of the class variable with the name of a class.

Using Class Variables in Classes and Objects


You can refer to class variables for an object that operates on itself. You access a class variable with an
unqualified reference.

Class Functions
Functions in classes (along with message actions) determine the behavior of an object of the class. The
outline syntax for a class function is the same as an internal function in the global declarations.
240
You can use class functions in both functional classes and in window classes.

Inheritance
A class function defined in a derived class overrides one with the same name defined or inherited by a base
class. If you override an inherited class function, you can still access the base class version by qualifying the
name of the class function with the name of the base class.
With multiple inheritance, if more than one base class defines or inherits the same class function, you get an
error when you compile if you refer to the class function. Eliminate the ambiguity by qualifying the name of
the class function with the name of a class.

Using Class Functions in Classes and Objects


You can call class functions in two ways:
• Internally for an object that operates on itself. “Operate on itself” means that the called function accesses
the calling object's own copy of variables.
• Externally for an object that operates on another object.

Internal References
In an object that operates on itself, you can use:
• An unqualified reference
• A class-qualified reference

241
Unqualified reference
Only use an unqualified reference in:
• The class that defined the function
• A class derived from the defining class
Use the same syntax that you use to call an internal function:
Call classFunction( parms )

Class-qualified reference
Use a class-qualified reference:
• When you normally use an unqualified reference, but you need to eliminate ambiguity. You get an error
when you compile if more than one direct base class defines or inherits the same function.
• When you normally use an unqualified reference, but you need to access an overridden function.
242
• In an object that is an instance of the class.
• In an object that is an instance of a class that is derived from the class. Qualify the function name with
the name of a class and a period:
Call className.classFunction( parms )

Late-bound unqualified reference


A late-bound reference calls the function defined by the class of the current object or defined by the object
itself, instead of the function defined in the class that calls the function.
Warning: You can only make a late-bound unqualified reference in a class that defines or inherits the named
function. Late binding adds flexibility, but it is significantly slower, so only use it when necessary.
Qualify the function name with two periods:
Call ..classFunction( parms )

In the following example, ClassA defines the functions F1 and Print. The F1 function calls Print.
If the current object's class is ClassB (derived from ClassA) and it makes the unqualified reference F1(), then
the F1 function defined in ClassA executes because ClassB inherits F1 from ClassA. F1 calls ClassB's Print
function and not ClassA's because F1 uses a late-bound reference, ..Print():

243
Form Window Class: ClassA
...
Functions
Function: F1
...
Actions
...
! Print the current object. If a derived class
! or the current object defines a function
! called Print, call it instead of the one
! defined in this class.
Call ..Print()
...
Function: Print
...
Actions
! Print ClassA's contents.
...

Form Window Class: ClassB


Derived From
Class:ClassA
...
Functions
Function: Print
...
Actions
! Print ClassB's contents.
...

External References
An object that operates on another object must identify the other object to call one of its functions. You can
use:
• A fully object-qualified reference
• An object-qualified reference
• A fully class-qualified reference

Fully object-qualified reference


If you know the object’s name, use this syntax:
Call hWnd.obj.func( )
Use this syntax when the calling object does not contain the target object.
The compiler searches for a function with the specified name in the these places in this order:
1. The target object
2. The class of the target object
3. A base class of the target object
You do not need to know whether the object defines the function or inherits it. However, within a class you
do not usually know the object name, so you can use a fully class-qualified reference (explained later).

244
Early-bound object-qualified reference
If one object contains another object, then the containing object can call a function of the contained object
(target object).
Qualify the function name with the name of the target object and a period:
Call obj.Function( parms )

An object-qualified reference tells the compiler to “look inside” the named object for the function. The
compiler searches for a function with the specified name in the these places in this order:
1. The target object
2. The class of the target object
3. A base class of the target object
You can also use an object-qualified reference to call a function in a containing object. In the diagram on the
next page, col1 uses:
• An object-qualified reference:
Call tbl1.F()
This tells the compiler to look in its containing object (tbl1) for the function defined in the class MyTable.
• An unqualified reference:
Call F()
This calls the function defined in the containing object (Form1).
• An object-qualified reference:
Call Form1.F()
This calls the function defined in the containing object (Form1).

245
Early-bound fully class-qualified reference
Use this syntax when the object identified by the handle is:
• An instance of the specified class (cls in the following example)
• An instance of a class derived from the specified class (hWnd) The specified class defines or inherits the
function:
Call hWnd.cls.function( parms )
This reference is more efficient than the late-bound references in the next sections.

Late-bound fully class-qualified reference


Use this syntax when the object identified by the handle is one of the following:
• An instance of the specified class (cls in the following example)
• An instance of a class derived from the specified class; fr example:
Call hWnd.cls..function( parms )
At runtime, SQLWindows searches for the function in this order:
1. The object identified by hWnd
2. The class (cls2) of the object identified by hWnd, assuming cls2 is derived from cls
3. Class (cls)
4. A base class of cls
This is the least-efficient reference and is significantly slower than the other types of references.

Efficiency of external references for class functions


The following diagram shows the relative efficiency of external references for class functions:

246
References in Container Objects
An unqualified reference resolves to an instance variable or function inherited from the object’s class. For
example, the reference to str1 below resolves to clsDf1.str1:
Data Field Class: clsDf1
Instance Variables
String: str1
...
Form Window: frmMain
Contents
clsDf1: df1
Actions
On SAM_Click
If str1 = 'abc' ! Refers to clsDf1.str1
...
Window Variables
String: str1
...

MyValue System Variable


Use this system variable to get or set the value of an object in a window class when an object name is not
available. Standard window objects usually do this by referring to their own object names; for example:
Set df1 = strValue
For SAL statements in a class, an object name is not available so you can use MyValue instead of an object
name; for example:

247
Data Field Class: ClassStringField
...
Functions
SetValue
...
Parameters
String: strValue
Actions
Set MyValue = strValue
...

SalObjIsValidClassName
Call SalObjIsValidClassName to determine if the specified class name exists in the outline.

SqlVarSetup
Before GUPTA performs a SQL execute or fetch operation, it compiles the bind and into variables that is
looking up the symbols and generating the code that gets the values (for bind variables) or that fetches the
values (for an into variable). By default, GUPTA compiles:
• Bind variables at execute time
• Into variables at fetch time
You can change this default behavior by calling SqlVarSetup, which saves the current execution context. When
you execute or fetch later, GUPTA uses that execution context to resolve references to bind variables and into
variables. This means that you can use bind and into variables in a different context than where you call Sql*
functions. You must call SqlPrepare for the Sql Handle before you call SqlVarSetup.
Use this function to write:
• Global functions that store bind and into variables in local variables
• A hierarchy of classes where a base class can prepare and fetch and a derived class can specify the into
variables
This function does not affect the lifetime of the bind and into variables and does not guarantee that the
variables will exist when you execute or fetch. You must ensure that the variables are still valid when you use
them.

248
Chapter 9 – Messages
This chapter explains the types of messages and how they are processed, and describes each SAM_*
message.
SQLWindows sends a message to an object when an event happens. An application processes a message by
taking an action.
Messages drive a SQLWindows application. Actions are associated with objects (such as dialog boxes, push
buttons, and check boxes). At runtime, actions execute based on the messages that the objects receive.
Messages are triggered by:
• Keyboard actions
• Mouse actions
• A timer
• The application

Types of Messages
There are three types of messages:
• SQLWindows Application Messages (SAM_*)
• Windows Messages (WM_*)
• Application-defined messages

Message Names and Numbers


Messages are identified by a name and number. The message name is a constant that represents the message
number. You can refer to a message by its name or its number. Use message names, not numbers.

SAM_* Messages

SAM Events
Examples of events that cause SAM_* messages are:
• Application startup
• Application termination
• Entering a field
• Leaving a field
249
• Clicking a button
• Closing a window

Where SQLWindows Sends SAM_* Messages


SQLWindows sends messages to all objects, except for background text, group boxes, lines, and frames.
SQLWindows also sends messages to the Application Actions section of the outline.
Not all messages are sent to all types of windows; for example:
• The SAM_AppStartup message is sent only to the Application Actions section of the outline
• The SAM_Click message is not sent to a data field
For a complete list of the SAM_* messages that each object receives, see SAM_* Summary on page 285.

Application-Defined Messages
The application itself can also send messages to its objects or to other applications by calling SalSendMsg,
SalPostMsg, and SalSendMsgToChildren.
Messages can be posted or sent:
• Posted (queued) messages are placed in an application's message queue. If there are other messages in
the application's queue, the object does not receive the message until the application processes the
messages ahead of it.
• Sent (nonqueued) messages are sent to an object directly. You send a nonqueued message when you
want the application to do something immediately.
SalPostMsg queues the message and returns immediately. SalSendMsg sends the message directly to an
object and returns only after the receiver processes the message.
For more about these functions, read the SQLWindows Function Reference or the online help.
Define values for application-defined messages in the User part of Constants in Global Declarations.
Constants you define with the PM_* or PAM_* prefix appear automatically in Coding Assistant. (“PM” means
Program Message and “PAM” means Program Application Message.)
Constants that you define for messages must be greater than the SAM_User constant. Define message
constants like this:

250
Global Declarations
System
...
User
Number: PAM_Ok = SAM_User + 2
Number: PAM_Cancel = SAM_User + 4

Microsoft Windows Messages


Microsoft Windows messages are defined in WINDOWS.H. These messages have a WM_ prefix, such as
WM_Close or WM_Paint. You can process these messages in SQLWindows applications; to do this, you need a
Microsoft Windows development tool.
Define values for Windows messages in the System part of Constants in Global Declarations. Constants you
define with the WM_* prefix appear automatically in Coding Assistant.

Processing Messages
Most objects have a Message Actions section where you code statements to process messages. For example,
a SAM_Validate message—sent when the user changes a value in a field and then clicks or tabs out of it—can
invoke field validation actions in the Message Actions section under an On SAM_Validate statement.
An event can cause several messages to be sent, but not all of them are relevant to an application. For
example, when the user moves the input focus after editing a data field or table window column,
SAM_Validate, SAM_KillFocus, and SAM_SetFocus are all sent, although an application does not process all of
them.
You code On statements in the Application Actions section and in Message Actions sections.
The statements under an On statement process a message. The following example shows how the On
statement processes the SAM_Click message in the Message Actions section of a push button. Each time the
user clicks the push button, the actions under SAM_Click execute:
Data Field: df1
...
Pushbutton: pb1
...
Message Actions
On SAM_Click
Set df1= ’Hello World’
For more about the On statement, see page 196.
For some SAM_* messages, SQLWindows expects you to Return a value to control processing. After executing
a Return statement, message processing ends. In other words, SQLWindows ignores any statements after a
Return statement.

System Variables
You use these system variables to process messages:

251
• hWndForm
• hWndItem
• hWndMDI
• wParam
• lParam
• MyValue

hWndForm
This system variable contains the handle of the top-level window (form window, dialog box, or table window)
that received the message.

hWndItem
You can use this variable to pass a window handle to a function.
This system variable contains the handle of the child object that received the message. For example, when an
application processes the SAM_Click message for a push button, hWndItem contains the handle of the push
button.
You can use this variable to pass a window handle to a function.

wParam and lParam


These system variables are used by some SAM messages. You use these variables as defined by the message.
Some messages do not use the wParam and lParam variables.

SAM Reference
The following are descriptions of the SAM_* messages.

SAM_Activate
Sent to Top-level windows and MDI windows
Event When the window is activated or deactivated. The wParam indicates whether the
window is being activated or deactivated.
Message Variables
hWndForm Handle of top-level window
hWndItem Object handle
wParam Whether the window is being activated or deactivated:
TRUE = Activated
FALSE = Deactivated
lParam Not used

252
Example None

SAM_AnyEdit
Sent to Data field, combo box, multiline field, and table window column
Event The user changes the field's value. For example, an editable data field receives one
SAM_AnyEdit message for each keystroke as the user enters data.
Processing Check the value of the field as the user enters it.
Message Variables For a data field or multiline field:
hWndForm Handle of top-level window
hWndItem Object handle
wParam Not used
lParam Not used
For a column of a table window:
hWndForm Table window handle
hWndItem Column handle
wParam Not used
lParam Table window row number
Example
Data Field: dfCompanyId
...
Message Actions
On SAM_AnyEdit
! Check if last character the user entered is a valid number.
! If not valid, strip it off and let user re-enter the character.
If SalIsValidInteger( dfCompanyId ) = FALSE
! StripLastCharacter is an internal function that
! discards any invalid characters that the user entered.
Call StripLastCharacter( dfCompanyId )

SAM_AppExit
Sent to Application Actions section of the outline
Event After all of the application's windows have been destroyed (closed).
When the user exits an application or you go from user mode to design mode, the
application's form windows, table windows, and dialog boxes are destroyed. After the
windows are destroyed, SQLWindows sends SAM_AppExit.
This is the last message SQLWindows sends to an application.
Processing Perform cleanup tasks such as disconnecting from the database.
SQLWindows sends SAM_AppExit after destroying all windows. Do not refer to
windows in the message processing statements.
Message Variables
hWndForm Not used
hWndItem Not used
253
wParam Not used
lParam Not used
Example
Application Actions
On SAM_AppExit
! Leaving application. Disconnect Sql Handle.
Call SqlDisconnect( hSql )

SAM_AppStartup
Sent to Application Actions section of the outline
Event Before the application's windows are created, including those created automatically
at runtime.
This is the first message SQLWindows sends to an application.
Processing Perform initialization tasks such as displaying a dialog box where the user logs on to a
database.
Message Variables
hWndForm Not used
hWndItem Not used
wParam Not used
lParam Not used
Example
Application Actions
On SAM_AppStartup
Set SqlDatabase = 'CLIENTS'
Set SqlUser = 'SYSADM'
Set SqlPassword = 'SYSADM'
When SqlError
Call SalMessageBox( 'Could not connect to database',
'Customer List', MB_Ok )
Return FALSE
If NOT SqlConnect( hSql )
Call SalQuit

SAM_CacheFull
Sent to Table window
A table window receives SAM_CacheFull when a user scrolls if Maximum Rows in
Memory is less than the number of rows to display and Discardable is No. The
minimum value for rows in memory is 78, regardless of the setting of Maximum Rows
in Memory.
Event A row is to be fetched, but the table window cache is full and no rows can be
discarded.
Processing The meaning of SAM_CacheFull depends on whether the table window has a
discardable cache:

254
– If the cache is not discardable, SAM_CacheFull means that no more data can be
loaded in the table window
– If the cache is discardable, SAM_CacheFull means that there are too many rows of
modified data and that they must be saved
Message Variables
hWndForm Handle of table window
hWndItem Not used
wParam Not used
lParam Not used
Example
Table Window: twTabWinEmployee
...
Message Actions
On SAM_CacheFull
! Cache is full! User cannot change any more rows in
! the table window.
Call SalMessageBox(
'Please save changes to Table Window.',
'Customer List', MN_Ok | MB_IconHand )
Return FALSE

SAM_CaptionDoubleClick
Sent to Table window and column
Event The user double-clicks a column title.
Processing Retrieve the window handle of the column in the wParam with
SalNumberToWindowHandle.
Message Variables For a table window:
hWndForm Handle of table window
hWndItem Handle of table window
wParam Column handle
lParam Not used
For a column:
hWndForm Handle of table window
hWndItem Column handle
wParam Column handle
lParam Not used
Example

255
Table Window: tbl1
...
Message Actions
On SAM_CaptionDoubleClick
Set hWndCol = SalNumberToWindowHandle( wParam )
Call SalTblSetColumnFlags( hWndCol, COL_Selected, TRUE )
Set nMaxLength = 15
Set nColLength = SalTblGetColumnTitle( hWndCol, sColTitle, nMaxLength )
Call SalMessageBox( 'You double-clicked the title ' || sColTitle,
'Info', MB_Ok )
Call SalTblSetColumnFlags( hWndCol, COL_Selected, FALSE )

SAM_Click
Sent to Table window, table window column, push button, radio button, check box, option
button, combo box, list box, and picture
Table Windows and Columns
SQLWindows sends SAM_Click to both the table window and to the column. If a user
clicks an editable column, SQLWindows also sends SAM_SetFocus.
SQLWindows sends SAM_Click to a table window when a user double-clicks it. If a
user double-clicks a non-editable column, both the table window and the column
receive two SAM_Click messages and one SAM_DoubleClick message.
List Box
SQLWindows sends SAM_Click to a list box when a user:
– Clicks an entry, even if the list box entry is already selected
– Double-clicks it; the list box receives SAM_Click followed by a SAM_DoubleClick
SQLWindows does not send SAM_Click when a user clicks:
– An empty list box
– A part of the list box that contains no entries
Combo Box
SQLWindows sends SAM_Click to a combo box when a user clicks an entry in the list
box, even if the entry is already selected. SQLWindows does not send SAM_Click to a
combo box when a user clicks the:
– Data field part of a combo box
– The down arrow that displays the list box
Radio Button
SQLWindows sends SAM_Click to a currently-unselected radio button when a user
clicks it. If the radio button is already selected, SQLWindows does not send
SAM_Click.
Event The user clicks the object with the mouse or performs a keyboard action (such as
pressing an arrow key) that simulates a mouse click.
Message Variables For a table window or table window column:
hWndForm Table window handle

256
hWndItem Column handle
wParam Not used
lParam Row number
For a picture:
hWndForm Handle of form window or dialog box
hWndItem Handle of item receiving message
wParam X coordinate in the picture where the user clicked
lParam Y coordinate in the picture where the user clicked
For a push button, radio button, list box, option button, or combo box:
hWndForm Handle of form window or dialog box
hWndItem Handle of object receiving message
wParam Not used
lParam Not used
Example
Pushbutton: pbAddNewCustomer
...
Message Actions
On SAM_Click
! Push button to add a new customer to the database
Call SqlImmediate( 'INSERT INTO company (name,address,phone )
VALUES ( :CompanyName, :CompanyAddress, :PhoneNumber ) ' )
Call SalMessageBox( 'Customer has been added!', ’Customer List',
MB_Ok )

SAM_Close
Sent to Form window, dialog box, top-level table window, and MDI window
Event The user chooses the Close command from the window's system menu or double-
clicks the window's system menu.
A form window, dialog box, or top-level table window receives SAM_Close when the
user closes it with the Close item in the system menu. A child table window does not
receive SAM_Close.
SQLWindows does not send SAM_Close when you call SalQuit, SalEndDialog, or
SalDestroyWindow.
Processing Warn the user or perform other tasks. For example, check a form window or table
window to see if there is data that needs to be saved in a database.
Call SalMessageBox when a modal or system modal dialog box receives SAM_Close to
prevent a user from accidentally closing the dialog box. Default processing closes the
dialog box.
If a user selects the Close menu item in a dialog box’s system menu and the
application does not process SAM_Close, SQLWindows implicitly calls SalEndDialog(
hWnd, 0 ).
Message Variables
hWndForm Handle of current window

257
hWndItem Not used
wParam Not used
lParam Not used
Example
Dialog Box: dlgEmployees
...
Contents
Data Field: dfCompanyName
...
Message Actions
On SAM_Close
Set nRetValue = SalMessageBox(
'Are you sure you want to close this window?',
'Customer List', MB_YesNo )
If nRetValue = IDNO
! Return FALSE to prevent the window from being destroyed
Return FALSE

SAM_ColumnSelectClick
Sent to Table window and column
Event The user selects or deselects a column by clicking the column title.
To receive this message, you must set TBL_Flag_SelectableCols to TRUE by calling
SalTblSetTableFlags (it is FALSE by default).
Processing Retrieve the window handle of the column in wParam with
SalNumberToWindowHandle.
Message Variables
hWndForm Handle of table window
hWndItem Table window handle in table window message actions,
column handle in column message actions
wParam Column handle
lParam Not used
Example
Table Window: tbl1
...
Message Actions
On SAM_ColumnSelectClick
Set hWndCol = SalNumberToWindowHandle( wParam )
Set nMaxLength = 15
Set nColLength = SalTblGetColumnTitle( hWndCol, sColTitle,
nMaxLength )
Call SalMessageBox( 'You selected the title ' || sColTitle,
'Info' , MB_Ok )

SAM_ContextMenu
Sent to Window

258
Event The user right-clicks a top-level or child window, or presses Shift+F10. Note: Most
applications do not need to process this message. Instead, call
SalContextMenuSetPopup to define a popup menu that displays automatically when
a window receives SAM_ContextMenu.
Process this message by calling SalTrackPopupMenu to display a popup menu. Use
the TPM_ContextMenu flag with SalTrackPopupMenu for this purpose.
Message Variable
hWndForm Handle of table window
hWndItem Handle of table window
wParam X coordinate in screen pixels relative to the upper left corner
of the screen
lParam Y coordinate in screen pixels relative to the upper left corner
of the screen
Example None

SAM_CornerClick
Sent to Table window
Event The user clicks the title of a row header. The row header is a non-editable column on
the left side of a table window.
Message Variable
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Table window context row (first row is 0, second row is 1,
and so on)
Example
Table Window: tbl1
...
Message Actions
On SAM_CornerClick
Set nContextRowLength = SalNumberToStr( lParam, 0, sContextRow )
Call SalMessageBox( 'You clicked the row header title context
row: ' || sContextRow ,'Info' , MB_Ok )

SAM_CornerDoubleClick
Sent to Table window
Event The user double-clicks the title of a row header. The row header is a non-editable
column on the left side of a table window.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used

259
lParam Table window context row (first row is 0, second row is 1,
and so on)
Example
Table Window: tbl1
...
Message Actions
On SAM_CornerDoubleClick
Set nContextRowLength = SalNumberToStr( lParam, 0, sContextRow )
Call SalMessageBox(
'You doubled-clicked the row header title context row: ' ||
sContextRow ,'Info' , MB_Ok )

SAM_CountRows
Sent to A table window with a dynamic scroll range
Event The user scrolls to the last row in a table window (such as by pressing the End key).
Processing Return the number of rows in the table window. For example, count the number of
rows in the result set.
If the application does not process this message, SAM_FetchRow messages are used
to determine the last row in the table with a TBL_NoMoreRows return from the
message. However, the application performs better if you process SAM_CountRows.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Not used
Example
Table Window: tblEmployee
...
Message Actions
On SAM_Create
Call SqlPrepare( hSqlPrimary, strSqlTableWindow )
Call SqlExecute( hSqlPrimary )
Call SalTblReset( hWndForm )
Call SalTblSetRange( hWndForm, 0, TBL_MaxRow )
On SAM_CountRows
! Count the number of rows in the result set.
Call SqlGetResultSetCount( hSqlPrimary, nRowCount )
Return nRowCount

SAM_Create
Sent to Top-level window and its children; MDI window
Event After the top-level window and its children have been created, but before the
windows are made visible. For example, SQLWindows does the following to create a
form window that has data fields:
1. Creates the form window.

260
2. Creates each of its data fields.
After SQLWindows creates all the windows, but before making them visible,
SQLWindows sends SAM_Create to the objects in this order:
– The form window
– Each of the form's data fields
After SQLWindows sends the SAM_Create messages, SQLWindows makes the form
window and data fields visible.
Processing Perform initialization tasks such as setting data fields or populating table windows
and list boxes with data from a database.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object being created
wParam Not used
lParam Not used
Example
Data Field: dfCompanyName
...
Message Actions
On SAM_Create
! Fill company name data field when window is created
Set dfCompanyName = 'Gupta Technologies LLC'

SAM_CreateComplete
Sent to Windows with contents: top-level windows and child table windows
Event After creating the window’s children and displaying the window and its children.
Processing Perform initialization tasks such as setting data fields or populating table windows
and list boxes with data from a database.
Message Variables
hWndForm Handle of parent window
hWndItem Handle of object being created
wParam Not used
lParam Not used
Example None

SAM_CustControlCmd
Sent to Custom control
Event When the parent window receives a notification message (WM_COMMAND) from
the custom control.
Processing SQLWindows ignores any value that you Return when you process this message.
Message Variables

261
hWndForm Handle of top-level window
hWndItem Handle of custom control.
wParam Notification message number
lParam Not used
Example None

SAM_Destroy
Sent to Top-level window and its children; MDI window
Event Just before the windows are destroyed.
SQLWindows sends SAM_Destroy messages after sending SAM_Close to the top-
level window. For example, if a form window has data fields, SQLWindows sends the
messages to the objects in this order:
– SAM_Close to the form window
– SAM_Destroy to the form window
– SAM_Destroy to each of the form window's child windows
After sending the SAM_Destroy messages, SQLWindows destroys the top-level
window and child windows.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object being destroyed
wParam Not used
lParam Not used
Example
Table Window: twTabWinEmployee
...
Message Actions
On SAM_Destroy
! Set a global Boolean variable informing the
! application this window is no longer active
Set bEmployeeWinDestroyed = TRUE

SAM_Dock
Sent to MDI window, form window, top-level table window
Event Sent to a top-level window just before a child dialog box changes its current docking
orientation to the parent window. This message precedes SAM_DockChange, which is
sent to the dialog box.
Processing None
Message Variables
hWndForm Handle of top-level window.
hWndItem
wParam Handle of dialog box whose docking orientation is changing.

262
lParam Contains two items. The low-order word of lParam contains
the dialog’s current docking status/orientation and the high-
order word of lParam contains the new docking
status/orientation.
See also For detailed discussions of docking capabilities and orientations, read the
SQLWindows Function Reference, for the functions SalDlgSetDockStatus and
SalWindowGet DockSettings. Also read about the docking attributes of top-level
windows in Chapter 5 – SQLWindows Objects.

SAM_DockChange
Sent to Dialog box
Event This message is only sent to a dialog box if that dialog box has attribute "docking
enabled" TRUE. Sent to a dialog box after a docking change orientation is completed.
Processing Does not apply. Returning FALSE or TRUE will have no effect.
Message Variables
hWndForm Handle of dialog box whose docking orientation is changing.
hWndItem Handle of dialog box whose docking orientation is changing.
wParam Not used.
lParam Contains two items. The low-order word of lParam contains
the current docking status/orientation and the high-order
word of lParam contains the new docking status/orientation.
Note: When processing the actions of this message, do not call SalModalDialog or SalSetWindowSize. Calls
to these functions cause an event loop that will freeze your application.
See also For detailed discussions of docking capabilities and orientations, read the
SQLWindows Function Reference, for the functions SalDlgSetDockStatus and
SalWindowGetDockSettings. Also read about the docking attributes of top-level
windows in Chapter 5 – SQLWindows Objects.

SAM_DockResize
Sent to A dialog box or toolbar that can be docked
Event SAM_DockResize is sent to a dialog box that can be docked or toolbar when it is
changing its docking orientation, or when it is about to be resized programmatically
or through user action. This message gives the developer an opportunity to request a
specific size for the object.
This message is only sent to dialog boxes or toolbars that have the Docking Enabled
attribute set to Yes.
Message Variables
hWndForm The handle of the dialog box or toolbar.
hWndItem The handle of the dialog box or toolbar.
wParam The size of the object prior to resizing. The low-order word
contains the width in pixels, and the high-order word
contains the height in pixels.

263
lParam The proposed size of the object after resizing. The low- order
word contains the width in pixels, and the high-order word
contains the height in pixels.
Return value None: Resizing will continue as proposed.
True (1): Resizing will continue as proposed.
False (0): Resizing is negotiated, using the last value for size when the object was in a
floated state.
Positive number greater than 1: Resizing is negotiated, using the return value. In that
value, the low-order word contains the requested width in pixels, and the high- order
word contains the requested height in pixels. Function VisNumberMakeLong is
helpful in constructing such a value.
Negotiating object sizes
Negotiation does not guarantee that the size you requested will be granted. There
may be competing requests for space from other objects that are located inside the
same dock bar as the object you want to resize. For example, it’s common for two or
more toolbars to share the same dock bar. There may also be other dock bars active
in the parent window, with other objects inside them.
All of the docked objects in a dock-bar share the same height. If two objects request
different heights in a dock bar the bar sizes itself to fit the larger of the requests.
(Height refers to the vertical dimension if the dock bar is on the top or bottom edge
of the parent window, and the horizontal dimension if the dock bar is on the left or
right edge of the parent window.)
When a size is requested for a given width the dock bar must fit all of the objects’
widths in the row. If the dock bar does not have enough space to honor the all of the
requests for widths (plus other non-requesting dockable object widths) the
requesting windows are given priority when the hosting dock bar is divided up. All
non-size- requesting windows are first minimized and if there is still not enough to
honor all of the requested space then each object is given a percentage of the space
they requested. That is, if there is available only 75% of the total space requested
then each object will only get 75% of the space they requested. For example, a dialog
that requested 100 pixels will get 75 and a dialog that requested 200 pixels will get
150.
Cautions when calling functions within SAM_DockResize
Some SAL functions related to window layout will fail (return FALSE) when called
from within the context of this message. This is to be expeected because an ongoing
window layout is already in progress and has not yet completed. Such functions
include:
SalSetWindowLoc
SallDlgSetStatus
SalGetWindowLoc
SalMoveWindow
SalSetWindowSize
See also SAM_DockResizeNotify

264
SAM_DockResizeNotify
Sent to A dialog box or toolbar that can be docked
Event SAM_DockResizeNotify is sent to a docking dialog box or toolbar when it has finished
resizing itself in response to changes in its docking orientation, or in response to
resizing programmatically or through user action. This message gives the developer
an opportunity to make changes to the contents of the dialog box or toolbar to
compensate for the new object size.
This message is only sent to dialog boxes or toolbars that have the Docking Enabled
attribute set to Yes.
Message Variables
hWndForm The handle of the dialog box or toolbar.
hWndItem The handle of the dialog box or toolbar.
wParam The size of the object prior to resizing. The low-order word
contains the width in pixels. The high-order word contains
the height in pixels.
lParam The proposed size of the object after resizing. The low- order
word contains the width in pixels. The high-order word
contains the height in pixels.
Return value The return value is ignored.
Cautions when calling functions within SAM_DockResizeNotify
Some SAL functions that deal with window layout should be used with care from
within the context of this message because of the risk of creating an endless loop of
events. They include:
SalDlgSetDockStatus
SalSetWindowLoc
SalSetWindowSize
SalHideWindow
SalShowWindow
As mentioned in the documentation for SAM_DockResize, there are sometimes
competing demands for space in dock bars that contain multiple objects, and an
object may get assigned a smaller size than it requested. If, for example, your code
tries to insure that an object always has at least a minimum width, you may set off
another resizing event, ending with your object again not getting its requested size
due to negotiation, resulting in another SAM_DockResizeNotify message, thus
causing an endless loop.
See also SalNumberHigh, SalNumberLow, and SAM_DockResize

SAM_DoubleClick
Sent to List box, combo box, table window, column, and picture
SQLWindows only sends SAM_DoubleClick to a combo box when you set its Always
Show List property to Yes in the Attribute Inspector.

265
Event The user double-clicks the object.
When the user double-clicks a row in a table window or list box, SQLWindows sends
the messages in this order:
– Two SAM_Click messages
– SAM_DoubleClick to the table window column or list box
– SAM_DoubleClick to the table window
Processing A double-click can select a row in a list box or table window and then start an action
for that row. For example, a list box can contain a list of file names. When the user
double-clicks a name in the list box, the application opens the file.
Message Variables For a combo box and list box:
hWndForm Handle of form window or dialog box
hWndItem List box handle
wParam Not used
lParam Not used
For a table window:
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Row number
For a table window column:
hWndForm Handle of table window
hWndItem Column handle
wParam Not used
lParam Row number
For a picture:
hWndForm Handle of form window or dialog box
hWndItem Handle of picture receiving message
wParam X coordinate in the picture where the user clicked
lParam Y coordinate in the picture where the user clicked
Example
List Box: lbEmployee
...
Message Actions
On SAM_DoubleClick
! When user double-clicks a row, get the index of that
! row and put row text in dfEmployeeName
Set nIndex = SalListQuerySelection( lbEmployee )
Call SalListQueryText( lbEmployee, nIndex, dfEmployeeName )

SAM_DragCanAutoStart
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event SQLWindows sends this message to ask a window whether it wants auto dragging.
266
Processing Return TRUE to enable auto dragging. If you do not process this message or you
return FALSE, then SQLWindows does not enable auto dragging.
SQLWindows starts drag mode automatically when the application returns TRUE from
SAM_DragCanAutoStart. This is the minimum that an application does to let a user
drag from a window. However, you must write additional code to do something when
the user drops in a window.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam X coordinate in the window
lParam Y coordinate in the window
Example
List Box: lb1
...
Message Actions
On SAM_DragCanAutoStart
If SalListQuerySelection( hWndItem ) != LB_Err
Return TRUE
Else
Return FALSE

SAM_DragDrop
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event The user drops the mouse on a target window.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Handle of a source window.
lParam Not used
Example
Data Field: df1
...
Message Actions
On SAM_DragDrop
Set hWndSrc = SalNumberToWindowHandle( wParam )
If hWndSrc != hWndItem
AND SalParentWindow( hWndSrc ) = hWndForm
Call SalGetWindowText( hWndSrc, sSource, 1000 )
Call SalSetWindowText( hWndItem, sSource )

SAM_DragEnd
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event Drag mode has ended.
Message Variables

267
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Not used
lParam Not used
Example None

SAM_DragEnter
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event The user moved the mouse into this target window while in drag mode.
Processing Change the mouse pointer to an appropriate symbol.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Handle of a source window
lParam Not used
Example None

SAM_DragExit
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event The user moved the mouse out of this target window while in drag mode.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Handle of a source window
lParam Not used
Example None

SAM_DragMove
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event The user moved the mouse within this target window while in drag mode.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Handle of a source window
lParam Not used
Example None

268
SAM_DragNotify
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event A mouse action happened in drag mode.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Handle of a target window
lParam One of these constants:
SAM_DragEnter – The user moved the mouse into a target
window
SAM_DragDrop – The user dropped the mouse in a target
window
SAM_DragExit – The user moved the mouse out of a target
window
SAM_DragMove –The user moved the mouse within a target
window
Example
Global Declarations
...
Class Definitions
Picture Class: clsDragPict
...
Message Actions
On SAM_DragNotify
Set hWndTarget = SalNumberToWindowHandle( wParam )
Select Case lParam
Case SAM_DragEnter
If SalGetType( hWndTarget ) = TYPE_Picture
Call SalDragDropEnableDrop( )
Else
Call SalDragDropDisableDrop( )
Break
Case SAM_DragDrop
If hWndTarget != hWndItem AND
SalGetType( hWndTarget ) = TYPE_Picture
Set nColorSource =
SalColorGet( hWndItem, COLOR_IndexWindow )
Set nColorTarget =
SalColorGet( hWndTarget, COLOR_IndexWindow )
Call SalColorSet( hWndTarget, COLOR_IndexWindow,
nColorSource )
Call SalColorSet( hWndItem,
COLOR_IndexWindow,nColorTarget )
Break

SAM_DragStart
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event Drag mode has started.
Message Variables

269
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Y coordinate in the window
lParam X coordinate in the window
Example
List Box: lb1
...
Message Actions
On SAM_DragStart
! Store the current selection as window text so we can
! use it on the drop
Call SalListQueryText( hWndItem, SalListQuerySelection( hWndItem ),
sList )
Call SalSetWindowText( hWndItem, sList )

SAM_DropDown
Sent to Combo box
Event The user clicks the down arrow. SQLWindows sends this message before the list box
of the combo box drops down.
Message Variables
hWndForm Handle of form window or dialog box
hWndItem Handle of combo box
wParam Not used
lParam Not used
Example None

SAM_DropFiles
Sent to Column, data field, multiline field, list box, combo box, picture, and custom control
SQLWindows only sends this message to windows that have enabled file dropping.
Event The user dropped a file or files from Explorer or File Manager on the object.
Processing Call the SalDropFilesQueryFiles function to get the names of the files dropped on the
object. SalDropFilesQueryFiles returns the number of files that were dropped or 0 if
the function fails. You can only call SalDropFilesQueryFiles during SAM_DropFiles
message processing.
Call the SalDropFilesQueryPoint function to get the location of the mouse in the
window where the user dropped the file or files.
By default, file dropping is enabled for editable picture objects. To avoid this default
processing, execute a Return statement in the SAM_DropFiles message processing for
a picture object and do not perform any other processing. For example, when a user
drops on a picture, you can call SalDropFilesQueryFiles or SalDropFilesQueryPoint in
the SAM_DropFiles message processing and decide whether to process what the user
is dropping or to ignore it by executing a Return statement with no other processing.

270
You can completely disable file dropping for an editable picture by calling the
SalDropFilesAcceptFiles function. The default for editable picture windows is TRUE.
The default for all other window types is FALSE.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Not used
lParam Not used
Example None

SAM_EndCellTab
Sent to Table window
Event The user tries to tab past the last editable cell.
Processing You can use this message to automate row insertion. When the table window
receives this message, add a blank row.
By default, if you do not explicitly return a value, SQLWindows returns FALSE and
selects the row. Return TRUE to prevent this behavior.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Table window context row that the user is trying to tab away
from (first row is 0, second row is 1, and so on)
Example
On SAM_EndCellTab
If IDYES = SalMessageBox(’Move to next row?’,
’What Do You Want to Do?’,
MB_IconQuestion | MB_YesNo )
Set nNewRow = SalTblInsertRow( hWndTbl, TBL_MaxRow )
Call SalTblSetFocusCell( hWndTbl, nNewRow, col1, 0, 0 )
Return TRUE
Else
! Null leg:
! If we don’t explicitly return a value, SQLWindows returns
! FALSE and selects the current row.

SAM_FetchDone
Sent to Table window
Event SalTblPopulate, using the TBL_FillAllBackground population method, has completed
populating the table window.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window

271
wParam Not used
lParam Not used
Example None

SAM_FetchRow
Sent to Table window
Event Before a row must be copied into the table window cache. When you populate a
table window, SQLWindows sends SAM_FetchRow for every row in the table window
that needs to be displayed. When the user scrolls the table window, SQLWindows
sends more SAM_FetchRow messages to the table window for rows not in the cache
that need to be displayed.
SQLWindows sends SAM_FetchRow before populating the row and
SAM_FetchRowDone after populating the row.
Processing You usually call SqlFetchRow to fetch the row into the table window based on the
row number in lParam.
Setting a breakpoint on a statement that executes while processing SAM_FetchRow
can cause incomplete painting of a table window.
Return a value based on the fetch result:

Constant Description
TBL_RowFetched The row was fetched successfully
TBL_NoMoreRows There are no rows at the specified row number and beyond
TBL_RowDeleted The row has been deleted

Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Row number of row to be affected
Example
Table Window: twTabWinEmployee
...
Message Actions
On SAM_FetchRow
! The table window needs a row from the database
If SqlFetchRow( hSql, lParam, nFetch )
If nFetch = FETCH_Delete
Return TBL_RowDeleted
Else
Return TBL_RowFetched
Else
Return TBL_NoMoreRows

SAM_FetchRowDone
Sent to Table window
272
Event After SQLWindows has populated a row.
SQLWindows sends SAM_FetchRow before populating the row and
SAM_FetchRowDone after populating the row.
Processing SQLWindows ignores any value you return.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Row number that was populated
Example None

SAM_FieldEdit
Note: Use SAM_Validate instead of SAM_FieldEdit. SAM_FieldEdit is provided for compatibility with earlier
SQLWindows versions.
Sent to A table window, column, data field, combo box, and multiline field
Event The user changes the value and then moves the focus away from the item. For
example, if a user enters a value in a data field and then presses the Tab key or clicks
the mouse to move to another field, SQLWindows sends SAM_FieldEdit to the data
field.
Processing SAM_FieldEdit is different from SAM_AnyEdit:
SAM_AnyEdit is sent for every change that the user makes to an object
SAM_FieldEdit is sent once when the user tries to leave an object that has been
changed
Message Variables For a data field or multiline field:
hWndForm Handle of top-level window
hWndItem Handle of data field or multiline field
wParam Not used
lParam Not used
For a table window column:
hWndForm Table window handle
hWndItem Column handle
wParam Not used
lParam Table window row number
Example None

SAM_Help
Sent to Top-level window and MDI window
Event The user pressed the F1 key.

273
Processing Call SalWinHelp to start an application help system that you created. The wParam
contains the handle of the child object that has the focus that you can use for a
context-sensitive help system.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of top-level window
wParam Handle of child object with the focus
lParam Not used
Example None

SAM_KillFocus
Sent to Table window, data field, multiline field, push button, radio button, check box, option
button, combo box, list box, column, and horizontal and vertical scroll bar
When the focus changes, SQLWindows first sends SAM_KillFocus to the object losing
the focus and then sends SAM_SetFocus to the object getting the focus.
For focus changes in table windows:
– The wParam of SAM_KillFocus is the window handle of the column getting the
focus and the lParam is the row number getting the focus
– The wParam of SAM_SetFocus is the window handle of the column losing the
focus and the lParam is the row number losing the focus
Event As the user moves the focus off an object.
SQLWindows sends this message whether or not the used changed data in the
object.
Processing Warning: You cannot call SalSetFocus in SAM_KillFocus processing because of a
Windows limitation.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Handle of object getting focus
lParam Not used
Example
Data Field: dfHireDate
...
Message Actions
On SAM_KillFocus
! When user exits this data field, disable push button
! pbPartialSearch
Call SalDisableWindow( pbPartialSearch )

SAM_Print
...
Sent to Form window, data field, multiline field, combo box, and push button
274
Event SQLWindows is printing the object.
Processing Some applications supplement window painting by drawing on the display. To
perform the same drawing when printing an object, call SalPrtExtractRect to draw on
the object that is printing.
SQLWindows does not have window painting functions. You must define the
Windows DLL GDI32.EXE as an external library and call its functions.
Message Variables
hWndForm Form window handle
hWndItem Handle of the object printing
wParam Printer HDC (display context handle)
lParam Rectangle that is printing
Example This example draws a diagonal line when a form window is printing. The MoveTo and
LineTo functions are in the DLL GDI.EXE.
On SAM_Print
Call SalPrtExtractRect( hWndForm, lParam, nLeft, nTop, nRight, nBottom )
Call MoveTo( wParam, nLeft, nTop )
Call LineTo( wParam, nRight, nBottom )

SAM_ReportFetchInit
Sent to Top-level window or MDI window that started a report
Event When Report SQLWindows is ready to format the first page of a report. Report
SQLWindows sends SAM_ReportFetchInit after sending SAM_ReportStart.
SAM_ReportFetchInit means that Report SQLWindows is ready to receive data from
the application.
Processing If the report contains data from a database, call SqlExecute. If SqlExecute returns
TRUE, then Return TRUE.
If you Return FALSE, the report stops. If you do not Return a value, or you do not
process the message, the report continues.
Message Variables
hWndForm Not used
hWndItem Not used
wParam Handle of the window that started the report
lParam Not used
Example

275
Form Window: frmMain
...
Message Actions
On SAM_ReportFetchInit
If NOT SqlPrepare( hSql, SQL_Select )
Return FALSE
Else
If NOT SqlExecute( hSql )
Return FALSE
Else
Return TRUE

SAM_ReportFetchNext
Sent to Top-level window or MDI window that started a report
Event When Report SQLWindows is ready for the next row of data from the application.
Report Builder sends SAM_ReportFetchNext after SAM_ReportFetchInit.
Processing If an application fetches data from a database for a report, call SqlFetchNext to get
the next row. If the fetch is successful, return TRUE. If there is no more data, return
FALSE.
Message Variables
hWndForm Not used
hWndItem Not used
wParam Handle of the window that started the report
lParam Not used
Example
Form Window: frmMainForm
...
Message Actions
On SAM_ReportFetchNext
! Get next row from database and
! send it to Report Builder
If SqlFetchNext( hSql, nRetVal )
Return TRUE
Else
Return FALSE

SAM_ReportFinish
Sent to Top-level window or MDI window that started a report
Event Report Builder sends SAM_ReportFinish when the report is finished.
Processing Perform cleanup tasks.
Report Builder ignores any value you Return in SAM_ReportFinish processing.
Message Variables
hWndForm Not used
hWndItem Not used
wParam Handle of the window that started the report

276
lParam Not used
Example
Form Window: frmMainForm
...
Message Actions
On SAM_ReportFinish
Call SqlDisconnect( hSql )

SAM_ReportNotify
Sent to Top-level window or MDI window that started a report
Event Report Builder is ready to format a part of a report.
Processing Check the lParam to find the part of the report Report Builder is ready to format (see
RPT_Err* Constants on page 364).
Report Builder ignores any value that you return during SAM_ReportNotify
processing.
Message Variables
hWndForm Not used
hWndItem Not used
wParam Handle of the window that started the report
lParam RPT_Before* constant (see table above)
Example This example checks the lParam to find if Report Builder is ready to process the first
break header:
On SAM_ReportNotify
If lParam = RPT_BeforeBreakHeader1
! strPic contains an image. Set the report variable
! named PICTURE to the contents of strPic.
Call SalReportSetObjectVar( frmMain, 'PICTURE', strPic )

SAM_ReportStart
Sent to Top-level window or MDI window that started a report
Event Report Builder sends SAM_ReportStart after the application calls SalReportView or
SalReportPrint. SAM_ReportStart means that the report is starting. Report Builder
sends SAM_ReportStart before the report prints or displays.
Processing Perform initialization tasks that are needed before the application can send data to
Report Builder.
Report Builder ignores any value that the application returns.
Message Variables
hWndForm Not used
hWndItem Not used
wParam Handle of the window that started the report
lParam Not used
Example
277
Form Window: frmMainForm
...
Message Actions
On SAM_ReportStart
! Prepare SQL statement for Report Builder
Call SqlPrepare( hSql, 'SELECT name, address, phone
from customer into :CompanyName, :Address, :phone' )

SAM_RowHeaderClick
Sent to Table window
Event The user clicks a row header.
SQLWindows only sends this message when TBL_RowHdr_Visible is TRUE (which is
the default). If TBL_RowHdr_Visible is FALSE, you can set it to TRUE by calling
SalTblDefineRowHeader.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Table window context row (first row is 0, second row is 1,
and so on)
Example
Table Window: tbl1
...
Message Actions
On SAM_RowHeaderClick
Set nContextRowLength = SalNumberToStr( lParam, 0, sContextRow )
Call SalMessageBox( 'You clicked the row header Context row: ' ||
sContextRow ,'Info' , MB_Ok )

SAM_RowHeaderDoubleClick
Sent to Table window
Event The user double-clicks a row header.
SQLWindows only sends this message when TBL_RowHdr_Visible is TRUE (which is
the default). If TBL_RowHdr_Visible is FALSE, you can set it to TRUE by calling
SalTblDefineRowHeader.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Table window context row (first row is 0, second row is 1,
and so on)
Example

278
Table Window: tbl1
...
Message Actions
On SAM_RowHeaderDoubleClick
Set nContextRowLength = SalNumberToStr( lParam, 0, sContextRow )
Call SalMessageBox( 'You double-clicked the row header Context row: ' ||
sContextRow ,'Info' , MB_Ok )

SAM_RowValidate
Sent to Table window
Event The user tries to move the focus off a row.
SQLWindows only sends this message when the user tries to change the row focus
within the table window, not when the user moves the focus off the table window.
SQLWindows sends SAM_RowValidate regardless of the row flag and cell-edit flag
settings.
Processing Validate the contents of the row and return one of these values:

Constant Description
VALIDATE_Cancel The application detected an error in the row data. The focus
stays on the row.
VALIDATE_Ok The row data is valid. The focus changes to a different row.

Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Table window context row (first row is 0, second row is 1,
and so on)
Example
Table Window: tbl1
...
Message Actions
On SAM_RowValidate
If SalIsNull( col1 )
Call SalMessageBox( 'You must enter a value',
'Validation Error', MB_Ok )
Return VALIDATE_Cancel
Else
Return VALIDATE_Ok

SAM_ScrollBar
Sent to Horizontal and vertical scroll bar
Event The user scrolls using the mouse or keyboard.
Processing To find the scrolling action, check the wParam:

Constant Description
SB_Bottom Scrolled to maximum.

279
SB_Top Scrolled to minimum.
SB_PageDown User clicked in scroll box area; scroll box scrolled down one
page.
SB_PageUp User clicked in scroll box area; scroll box scrolled up one page.
SB_ThumbTrack Scroll box moved to new position. Use SB_ThumbTrack when
you want the client area updated each time the user drags the
scroll box.
SB_LineUp Scrolled up one line.
SB_LineDown Scrolled down one line.
SB_ThumbPosition Scroll box dragged to new position. If you want to repaint the
client area when the user releases the thumb, use
SB_ThumbTrack.
Avoid processing SAM_ScrollBar when wParam is SB_ThumbTrack because tracking is
dynamic and can send many messages.
Message Variables
hWndForm Handle of form window or dialog box
hWndItem Scroll bar handle
wParam One of the SB_* constants (see above)
lParam Scroll bar value
Example
Vertical Scroll Bar: sbScrollBar
...
Message Actions
On SAM_ScrollBar
! Show scroll bar position in data
! field 'dfScrollBarPos'
If wParam = SB_ThumbTrack
Set dfScrollBarPos = lParam

SAM_SessionError
Sent to Application Actions section of the outline
Event A SQL function fails within an OLE DB session.
This message is quite similar to SAM_SqlError, which is sent when a SQL function fails
outside the scope of an OLE DB session.
Processing Control how the application responds to SQL errors on a global level instead of using
the default error processing, which displays a dialog with the error number and error
text.
Call SqlExtractArgs to get the error code, error position, and Session Handle from the
wParam and lParam.
Message Variables
hWndForm Handle of top-level window that executed the Sql*
statement that failed except when code in applications
actions calls a Sql* function and it fails when hWndForm is
null (hWndNULL)
hWndItem Unused
280
wParam Sql Handle
lParam SQL error code and position

SAM_SetFocus
Sent to Table window, data field, multiline field, push button, radio button, check box, option
button, combo box, list box, column, and scroll bar
When the focus changes, SQLWindows first sends SAM_KillFocus to the object losing
the focus and then sends SAM_SetFocus to the object getting the focus.
For focus changes in table windows:
The wParam of SAM_KillFocus is the window handle of the column getting the focus
and the lParam is the row number getting the focus
The wParam of SAM_SetFocus is the window handle of the column losing the focus
and the lParam is the row number losing the focus
Event The user moves the focus to the object.
Processing Start actions that take place when the user enters an object.
Do not call functions that can change the focus (such as SalMessageBox,
SalModalDialog, and SalSendMsg) while processing SAM_SetFocus.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of the object receiving the message
wParam Handle of object getting focus
lParam Not used
Example
PushButton: pbPartialSearch
Data Field: dfDate
...
Message Actions
On SAM_SetFocus
! When user enters this field, enable push button
! pbPartialSearch
Call SalEnableWindow( pbPartialSearch )

SAM_SqlError
Sent to Application Actions section of the outline
Event A SQL function fails. Note that if the SQL function is called within the scope of an OLE
DB session, message SAM_SessionError will be sent instead of SAM_SqlError.
Processing Control how the application responds to SQL errors on a global level instead of using
the default error processing, which displays a dialog with the error number and error
text.
Call SqlExtractArgs to get the error code, error position, and Sql Handle from the
wParam and lParam.

281
You can also use When SqlError in any actions section of the outline to process an
error at a local level (see SQL Error Handling on page 325).
Message Variables
hWndForm Always hWndNULL
hWndItem Unused
wParam Sql Handle
lParam SQL error code and position
Example The code below shows the SAM_SqlError processing in the Application Actions
section. These statements are only executed when the When SqlError statements for
local processing do not return a value:
Q) SqlExtractArgs gets the error number (nErr).
C9 SalNumberToStr converts nErr to a displayable string.
C) SqlGetErrorText gets the error message text for nErr.
¢l: The code displays a message box with the error number, error message, and a
message saying to report the error. The user clicks the OK push button to quit
the application.
� The code returns a value to tell SQLWindows not to invoke the default error
processing.

Application Actions
On SAM_SqlError
!
! If processing gets to here on a SQL error, there is
! little to do except report the error and gracefully quit
!
Q) Call SqlExtractArgs( wParam, lParam, hSqlError, nErr, nPos )
C9 Call SqlGetErrorText( nErr, strErrmsg )
C) Call SalNumberToStr( nErr, 0, strNum )
!
¢l: Call SalMessageBox( strNum || ' - ' || strErrmsg || '.
Please report to your system administrator.
Click OK to quit the application.',
'Database Error', MB_Ok | MB_IconStop )
!
! The Return statement tells SQLWindows **not** to invoke
! default error processing
!
�Return FALSE

SAM_Timer
Sent to Application Actions, top-level window and its children; MDI window
Event Every n milliseconds, as specified by SalTimerSet.
Processing Check the wParam to find the identifier of the timer that sent the message. This way,
one object can process SAM_Timer messages from more than one timer.
Timers are a limited resource in Windows, so use as few of them as possible.
Message Variables

282
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Timer identifier
lParam Not used
Example
Form Window: frmMainForm
...
Contents
Data Field: dfDateTime
...
Message Actions
On SAM_Timer
! Use SalTimerSet to set timer to send SAM_Timer
! messages once every minute. Update time display
! on screen.
Set dtDateTime = SalDateCurrent( )

SAM_Validate
Sent to Data field, multiline field, combo box, and column
Event The user changes the value of the object and then moves the focus away from the
object.
The user can move the focus by several actions such as tabbing to another object,
clicking another object, or using a mnemonic or accelerator to activate another
object.
When a user changes one of these objects, the object's field edit flag changes to
TRUE. You can get and set the field edit flag using SalQueryFieldEdit and
SalSetFieldEdit.
Processing Validate the data that the user entered or changed.
Whenever the user changes an object, SQLWindows sends SAM_Validate. If an object
is valid, return VALIDATE_Ok (this resets the field edit flag to FALSE).
The value you return from SAM_Validate processing controls whether the focus
changes.
SQLWindows does not send SAM_Validate when the user selects a menu item (a
menu selection does not change the focus). You can force SQLWindows to send
SAM_Validate by calling SalSendValidateMsg in the menu actions of a menu item.
This forces field validation before processing a menu selection (without changing the
focus). SalSendValidateMsg returns the value that the SAM_Validate message
processing returns.
To control the action that happens, return one of these values:

Constant Description
VALIDATE_Cancel Does not let the attempted action take place and returns
the focus to the current edited item if the item has lost
the focus (validation failed).

283
VALIDATE_Ok Lets the attempted action take place. This is the default
action if you do not process SAM_Validate or do not
Return a value when processing SAM_Validate.
VALIDATE_OkClearFlag Lets the attempted action take place and sets the field-
edit flag to FALSE.

Unless you return VALIDATE_Cancel, SQLWindows also sends SAM_FieldEdit to the


object.
Message Variables For a table window column:
hWndForm Handle of top-level window
hWndItem Handle of column receiving message
wParam Handle of column getting the focus; zero if the focus is not
changing (such as when calling SalSendValidateMsg in menu
lParam Table window context row (first row is zero, second row is
actions)
one, and so on)
For all other objects:
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Handle of object getting the focus; zero if the focus is not
changing (such as when calling SalSendValidateMsg in menu
actions)
lParam Not used
Example
Data Field: dfName
...
On SAM_Validate
If SalIsNull( dfName )
Call SalMessageBox( 'You must enter a value', 'Data Error', MB_Ok )
Return VALIDATE_Cancel
Else
Return VALIDATE_Ok

SAM_XMLRowDone
Sent to Table window
Event After SQLWindows has populated a row from an XML document.
Processing SQLWindows ignores any value you return.
Message Variables
hWndForm Handle of table window
hWndItem Handle of table window
wParam Not used
lParam Row number that was populated
Example None

284
SAM_* Summary
In the table below:
• “Y” means that SQLWindows sends the message to the object
• A blank entry means that SQLWindows does not send the message to the object

Application Actions

Custom Control
Multiline Field

Option Button
Form Window

Table window

Radio Button
MDI window

Push Button

Combo Box
Dialog Box

Check Box
Data Field

Scroll Bar
Column

List Box

Picture
Message
Activate Y Y Y Y
AnyEdit Y Y Y Y
AppExit Y
AppStartup Y
CacheFull Y
Caption-DoubleClick Y Y
Click Y Y Y Y Y Y Y Y Y
Close Y Y Y Y
Column-SelectClick Y Y
ContextMenu Y Y Y Y Y Y Y Y Y Y Y Y Y Y
CornerClick Y
Corner-DoubleClick Y
CountRows Y
Create Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
CreateComplete Y Y Y
CustControlCmd Y
Destroy Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
DoubleClick Y Y Y Y Y
DragCan-AutoStart Y Y Y Y Y Y Y Y Y
DragDrop Y Y Y Y Y Y Y Y Y
DragEnd Y Y Y Y Y Y Y Y Y
DragEnter Y Y Y Y Y Y Y Y Y
DragExit Y Y Y Y Y Y Y Y Y
DragMove Y Y Y Y Y Y Y Y Y
DragNotify Y Y Y Y Y Y Y Y Y
DragStart Y Y Y Y Y Y Y Y Y

285
Application Actions

Custom Control
Multiline Field

Option Button
Form Window

Table window

Radio Button
MDI window

Push Button

Combo Box
Dialog Box

Check Box
Data Field

Scroll Bar
Column

List Box

Picture
Message
DropDown Y
DropFiles Y Y Y Y Y Y Y
EndCellTab Y
FetchDone Y
FetchRow Y
FetchRowDone Y
FieldEdit Y Y Y Y Y
Help Y Y Y Y
KillFocus Y Y Y Y
Print Y Y Y
ReportFetch-Init Y Y Y Y
ReportFetch-Next Y Y Y Y Y Y Y Y
Report-Finish Y Y Y
ReportNotify Y Y Y Y
ReportStart Y Y Y Y
RowHeader-Click Y Y Y Y
RowHeader-DoubleClick Y Y Y Y
Row-Validate Y Y Y Y
ScrollBar Y Y
SetFocus Y Y Y Y
SqlError Y
Timer Y Y Y Y Y
Validate Y Y Y Y Y Y Y Y
XMLRowDone Y

286
Chapter 10 – Debugging
Debugging is an important part of developing an application. SQLWindows has many features you can use to
debug an application. This chapter covers:
• Run mode
• Debug menu
• Animation
• Breakpoints
• Debug toolbar
• Debugging windows
• Tips
• Writing custom debugging code
• Tracing
• Event logging

Run Mode
SQLWindows lets you run an application at design time in run mode. Besides testing the application, you can
use animation, breakpoints, the Debug toolbar, and the debugging windows to analyze an application’s
behavior.
To enter run mode, select Project > Execute or press F7. To exit run mode, select Debug > Stop Debugging or
press Shift+F7.

Animation
Animation displays an application's code as it executes. As SQLWindows executes a statement, it highlights
the next statement in the Outline tab so that you can follow the application's progress. You can see which
branch of an If, Else, or Else If statement executes, how many times a loop repeats, whether an error is
processed locally or globally, and so on.
The Debug menu has three items that control animation. You can only check one at a time:
• No Animate turns off animation (default)
• Slow Animate turns on slow animation
• Fast Animate turns on fast animation
For Slow Animate, you can set the time interval (in seconds) between the execution of each statement. Select
Tools, Preferences, General. By default, slow animation executes a statement once a second:

287
Breakpoints
A breakpoint is a point in an application where SQLWindows suspends execution and displays the Debug
toolbar where you can:
• Examine the values of variables and expressions
• Track messages
• Check the call stack
• Continue to execute the application in restricted mode, such as a line at a time, run to a specific point,
step into or out of an indented section of code, etc.
• Resume normal application execution
Breakpoints can be linked to an expression. Whenever that expression evaluates to TRUE, regardless of the
line of code being executed, execution is suspended.
Breakpoints linked to expressions can only be managed from the Breakpoints dialog box (see page 289).
Breakpoints can also be linked to a specific line of code in the application. When execution reaches that line,
it is suspended. To manage breakpoints that are linked to a line of code, use the Debug menu's cascading
Breakpoints menu items.

Setting Breakpoints
You can set breakpoints in design mode or run mode. To set a breakpoint:
• Select the statement you want to make a breakpoint. In design mode, click the diamond at the beginning
of the statement. In run mode, click anywhere in the statement.
• Select Breakpoints > Toggle or press F9.
If multiple statements are highlighted when you select Toggle, only the first statement becomes a breakpoint.
You can only toggle breakpoints on SAL statements. If the line of code highlighted when you select Toggle is
not a SAL statement, SQLWindows sets a breakpoint on the next SAL statement.
By default, breakpoints are red on color monitors and are highlighted on monochrome monitors. Instead of
displaying breakpoints in color, you can display them with bold, italic, or underline styles, or without a style.
Select Tools > Preferences (see Preferences on page 94).

288
Clearing Breakpoints
Select Breakpoints > Toggle or press F9 to turn off the breakpoint on the selected statement.
Select Debug > Breakpoints > Clear All to permanently remove all breakpoints in the application.
Select Breakpoints > Disable All to permanently turn off all breakpoints in the application. Later, select
Breakpoints > Enable All to turn on all breakpoints in the application.
If you comment a line of code that had contained a breakpoint, that breakpoint is permanently removed.

Immediate Breakpoints
You can cause an immediate breakpoint while an application is running by selecting Debug > Break.

Breakpoints Dialog Box


The Breakpoints dialog box can be invoked using Alt-F9 or by choosing Debug > Breakpoints. It is available at
design time and runtime. It allows you to do the following debugging operations in a SQLWindows outline:
• View all existing breakpoints and see whether or not they are enabled and whether or not they have
conditions.
• Enable/disable existing breakpoints.
• Create new breakpoints based on expressions. (Breakpoints anchored to a line of code must be created
by using Toggle. See Setting Breakpoints on page 288.)
• Create conditions for breakpoints that are anchored to a line of code.
• Specify the number of iterations, so that the breakpoint occurs only every Nth time the condition is met.
• Remove individual breakpoints or all breakpoints

In the example, the first and third breakpoints are anchored to a line of code in the outline. Part of the line
text is shown. The second breakpoint is a data breakpoint, which is not anchored to a line of code but is
based on an expression. Whenever the expression’s value changes, regardless of where in the outline the
289
change occurs, execution will be paused and a message box will notify you of the change in value. Note that
the iteration count for this breakpoint, as shown, is four. That means only every fifth change in value would
cause a pause in execution because the first four changes are skipped. Execution can pause at any point in the
outline – this breakpoint is not anchored to a line of code.
The third breakpoint is a conditional breakpoint - it is anchored to a line of code, but also has a condition
based on an expression. Execution will not pause on this line of code unless the expression evaluates to TRUE.
The third breakpoint is presently disabled. It is toggled as a breakpoint, and that line of code will show up in a
different color in the outline, but execution will not pause on that line unless you enable the breakpoint using
this dialog box.
The Remove All button will remove all breakpoints, whether or not they are anchored to specific lines of
code.

Validity Checking
All expressions are checked for validity. If you enter an expression at design time, the validity check occurs
when the application first enters runtime. If there are invalid expressions at that time, the associated
breakpoints are disabled and a warning message is displayed. An expression might be valid at specific times
and invalid at others. If an expression has an unqualified reference to a local variable of a function, it would
be valid while that function is executing, but invalid at all other times. Such an expression would fail when the
application first enters runtime because the app would not be within the scope of the function at that time.
If, at runtime, you create a new breakpoint that contains an expression, that expression will be checked for
validity when you click the Apply button. If it is invalid, the breakpoint will not be added.
If, at runtime, you click to enable a currently disabled breakpoint that has an expression, the expression will
be checked for vailidty upon the click. If it is invalid, the breakpoint will remain disabled.

Advanced Breakpoints Dialog


When you are working with a data breakpoint or conditional breakpoint in the Breakpoints dialog, you can
click on the ellipsis (...) symbol, next to the Expression data field, to display the Advanced Breakpoints dialog.
This dialog uses a tree view to show all the available variables in your application. By clicking on one or more of
these variables, you can build a list of variable names. This list of names, separated by spaces, becomes the
basis of your expression. You then add parentheses, operators, function calls, and other elements to complete
the expression.
If this dialog supplies only a list of names and leaves the other work for you to do, why bother using it?
Because it satisfies two very important requirements: All of the variable names will be properly spelled, and
fully and accurately qualified. In complex applications the use of proper scope can mean long and involved
qualifications before the variable name, and typing these strings manually can lead to ambiguity and outright
errors.
The tree view in this dialog presents information from the two major parts of your application. First the
variables from the top-level windows are shown:

290
In the example the variable pb3.nInstVar is shown for a pushbutton. That is because pb3, in the sample outline
used here, is an instance of a class. Ordinary pushbuttons would not have variables associated with them, but
all class instances will display all available class and instance variables.
The other variables shown under Window Variables are sometimes simple datatypes (sVar) and sometimes
complex UDVs derived from class definitions. In the case of UDVs, the tree structure continues inside the UDV
down to the level of the simple datatypes within the UDV. Note that both class variables and instance
variables are shown for aUDVBase[3] because the class definition defines both types.
The other major part of the application shown in the Tree View is the Global part.

The Global Items are divided into class definitions and variables. The global variables may be simple datatypes
or UDVs. Notice that in the class definitions, only class variables are shown, not instance variables. That’s
consistent with how scoping and referencing rules work in SAL (see Advanced References on page 583). It is
291
legal to make a reference to fClass.nClassVar because that is a global value that occurs only once in the
application. But it makes no sense to say fClass.nInstanceVar because there can be many instances of fClass
within the application and the particular instance you want has not been specified. Therefore, the classes
shown here on this tree view are only those that contain class variables. If a class has lots of instance variables
but has no class variables at all, it will not even appear here.

How It Works
If you are modifying an existing expression, it will be completely overwritten by what you select from this tree
display.
To build a list of names, click on the first name you want. If the list will contain more than one name, use Ctrl-
click to select the remaining names. Each name will be separated from the next with a space. When you click
OK, that list of names will be returned to the “Expression” data field in the Breakpoints dialog, and this dialog
will close. You can then edit the list of names in the Breakpoints dialog, adding operators to finish your
expression.

Debug Toolbar
The Debug toolbar lets you:
• Resume execution of the application
• Execute the application one statement at a time
• Cause the application to break at its current point
• Evaluate expressions
• Display a stack trace
• Examine the values of an application's variables
• Monitor messages

The buttons on the Debug toolbar execute commands and display debugging windows. Both the commands
and windows are explained below.
To display the Debug toolbar:
292
• Run an application with one or more breakpoints. SQLWindows stops at each breakpoint and displays the
Debug toolbar.
• Select Debug > Break at any time while in run mode. The application does not have to be stopped at a
breakpoint.
At a breakpoint, SQLWindows displays the word “(Break)” in its title bar. When the application is running,
SQLWindows displays the word “(Run)” in its title bar.

Commands
You can also execute these commands by selecting their items in the Debug menu.

Go
Resumes executing the application until the next breakpoint, if there is one, or until you exit the application.

Break
Causes an immediate break.

Step Into
Executes the next statement and returns control to the Debug toolbar. If the application calls a function,
SQLWindows takes you to the function and you can step through the function a statement at a time before
returning to the statement after the function call.

Step Over
Executes the next statement and returns control to the Debug toolbar. If the application calls a function,
SQLWindows executes all the function's statements in one step and returns to the statement after the
function call.

Step Out
Executes until control returns to the caller: the block of code at a lower level of indentation than the current
code, or the code that called the function that is currently executing.

Run to Cursor
Executes until control reaches the line of code in the outline where the cursor is currnetly located.

Debugging Windows
You use the debugging windows to analyze an application’s behavior. You can also display these windows in
run mode from the Tools menu.
Each debugging window can be a dialog or a pane. You dock and undock them the same as you do toolbars
(see Docking Toolbars, Palettes, and the Menu Bar on page 39).
To change the width or height of a docked debugging window, move the mouse pointer to an inner edge and
drag after the splitter appears.

293
Expressions window
Evaluates an expression you type in the dropdown at the top of the window. After typing the expression,
either click Eval or press Return.

You can use this window with Step Into and Step Over to evaluate a variable's value before and after a
statement uses or changes the variable's value.
This window remembers all the expressions you entered for this instance of SQLWindows.
You can evaluate any expression that results in a number or string. For example, you can evaluate expressions
like these:
SalDateCurrent( ) 2+2

Messages window
Displays every message sent in an application. Each line displays a message name or number, the handle of
the window receiving the message, and the wParam and lParam values.

Click SAM messages only to display only SQLWindows messages (SAM_*). The values displayed under the
Message heading are SQLWindows message names.
Click Stop Watching to end the message tracking.

Variables windows (Variables, Local, and Auto)


Displays the names and values of variables. SQLWindows updates the variable values at each breakpoint.
There are three kinds of variable windows. The illustration below shows all three displayed at once, during a
breakpoint in an application.

294
The Variables window can be invoked by the Debug toolbar button that is noted with “1” in the illustration
above. It can also be invoked from the Tools, Variables menu item, or by hot key Alt+5. By default, it initially
contains a few global variable names, as shown in the illustration. In addition, you can add other variables of
your choice to this window. There are two ways to do this. You can simply click in a blank line at the bottom of
the Variables window, then type the name of a variable into the left cell of that line. (Or delete the variable
name in a cell to stop monitoring that variable.)
You can also click the “+/-” button in the window to bring up a more full-featured dialog for choosing
variables, as shown below.

295
To add a watch variable:
• Select a section name in the outline from the top list in Select Watch Variables on the left side of the
dialog. You can type the first few characters of the name in the data field to scroll to the section that
starts with that prefix. SQLWindows displays the variables defined in the selected section in the lower list.
• Select a variable by double-clicking it or by selecting it and clicking Add. Click Add All to add all the
variables in the section. After you make a selection, SQLWindows adds the variables to Current Watch
Variables on the right side of the dialog.
To remove a watch variable, double-click it in Current Watch Variables or select it and click Clear. Click Clear
All to remove all variables from the list.
You can use Edit Watch Variables in the lower right side of the dialog to:
• Type variable names.
• Add qualifiers to variable names.
• Enter expressions to add to the watch variables list. SQLWindows evaluates the expression and displays
the result when you display the Watch Variables window. (This is like entering an expression in the
Expressions window.)
Click OK to save your selections and return to the Variables window. Click Cancel to return to the Variables
window without saving your selections.
Locals variable window. This window is invoked by clicking the Debug toolbar button denoted with “2” in the
application full-screen illustration above. You cannot control which variables are displayed in this window. It
automatically shows only those variables that are in “local scope” at the time of the breakpoint.
Auto variable window. This window is invoked by clicking the Debug toolbar button denoted with “3” in the
application full-screen illustration above. You cannot control which variables are displayed in this window. It
automatically shows only those variables that are present in the current line of code (the breakpoint line) and
the line of code preceding the current line.

Additional variable window features


Complex data types

All three variable windows are capable of displaying the values of complex datatypes such as UDVs. In its
most basic form, a UDV is either considered Null or Not Null. You can click on the + icon to expand the UDV to
its more detailed parts, to inspect or change the values of those parts.
Color formatting in variable windows. In all three variable windows, the value of a variable can appear in a
color different from the default. This indicates that the value of the variable has changed since the last
breakpoint. In the case of the Auto variable window, it indicates a value that changed between the preceding
line of code and the current line of code.
Changing the value of variables. The Expressions window, described earlier in this chapter, allows you to
evaluate any line of SAL code. This includes lines beginning with Set, which can change the value of variables

296
at runtime. All three of the variable windows also permit you to change the value of variables. Simply click in
the cell that displays the current value, and type a new value.

Quick Info

Quick Info is an automatic feature that works at runtime. If you “hover” your mouse cursor over the name of a
variable or other object, after a short time a tooltip appears with the definition (datatype) and the value of
that variable or object. This works for simple datatypes, but not for complex datatypes such as UDVs.

Call Stack window


Displays the name of the current function (if any) and the name of the function or outline section that called
it. For nested calls (where one function has called another function that has called another function, and so
on), the Call Stack window shows the complete call path.

Threads window
Displays a list of all running threads in the application. This list will include the main “UI” thread, and any
background worker threads that are running.

Right click on a thread to access a context menu with debug commands specific to that thread:
▪ Contine/Step*: Perform standard debugger commands on the thread. The thread must be in
the debugging state for this to be enabled.
▪ Select in Outline: Highlights the current active line of code in the outline window.
▪ Break: If the thread is running, will issue a break command.

297
▪ Debug: Switches debug context to that thread. Usefull if multiple threads are running at the
same time, and you want to switch between them.

Debugging COM Servers


To debug COM servers that you write, see Debugging COM Servers on page 500.

Debugging DLLs
To debug DLLs that you write, see Using Visual Studio with DLLs on page 544.

Tips
Test SQL statements:
Run SQL statements you plan to use in a SQLWindows application in Database Explorer first. This lets you
verify that the SQL statements work correctly and produce the intended results. You can then copy and paste
the SQL statements to the outline. This prevents typing errors.
Isolate the problem:
If you found the code causing the problem, isolate it by opening a new application and pasting the code into
it. If the new application does not reproduce the problem, then you know that the problem is application-
specific and not a SQLWindows bug.
Substitute constants for variables so you explicitly know the values the application is using.
Run the application against a local database to eliminate the network as a possible source of the problem.

Writing Your Own Debugging Code


You can write custom debugging code with these functions.

SalCompileAndEvaluate
This function lets you access the value of a variable without specifying its name until runtime.
SalCompileAndEvaluate evaluates an expression (strExpression) and returns the expression's value in the
nReturn, strReturn, dtReturn, or hWndReturn parameter as appropriate for the value's data type:
nType = SalCompileAndEvaluate ( strExpression, nError, nErrorPos, nReturn,
strReturn, dtReturn, hWndReturn, bInhibitErrors, strContext)
In strContext, you supply the handle to an execution context returned by SalContextBreak or
SalContextCurrent. The execution context is only meaningful to SQLWindows.

298
The nType return value is one of the these values if the function succeeds:
• EVAL_Date
• EVAL_Handle
• EVAL_If
• EVAL_Number
• EVAL_Set
• EVAL_String
• EVAL_Template
If this function does not succeed, it returns an error number in nError and the position in strExpression at
which the error occurred in nErrorPos.
If you set bInhibitErrors to FALSE, SQLWindows reports compile and evaluation errors by displaying a message
box. If you set bInhibitErrors to TRUE, SQLWindows does not report compile or evaluation errors. Set
bInhibitErrors to TRUE when the application handles error processing.

SalContextBreak
This function retrieves the context of the most-recently executed Break statement. Pass strContext as the last
parameter of SalCompileAndEvaluate.
strContext = SalContextBreak ( )

SalContextCurrent
This function retrieves the current execution context. Pass strContext as the last parameter of
SalCompileAndEvaluate.
strContext = SalContextCurrent ( )

Tracing
Tracing means inserting lines of code that make calls to the trace functions and cause text strings to be
written to the trace output target. You can output any text you like at any point in your application. There are
four possible output targets:
• The Windows event log
• A named data file
• The SQLWindows output window normally used for displaying compiler errors. This option is only
available when the application is running in Debug mode.
• Directly to device stdout, so that trace output can be integrated with third- party debugging tools
The following three functions are used for implementing tracing.

299
SalStartTrace
This function enables tracing, and specifies which of the four output targets to use.
bOk = SalStartTrace ( nOutputType, strTraceFile, bClearExisting )
If you specify output to the event log (nOutputType is TRACE_Event) for Windows 98 and ME, a data file is
used instead because the event log doesn't exist for these versions. The data file’s name is TDEvent.log and it
is placed in the Windows TEMP directory.

SalTrace
If bClearExisting is TRUE, any trace information currently in the target is cleared before tracing begins. Note
that it is your responsibility to monitor the size of any files used in tracing.
This function outputs a line of text to the tracing target.
bOk = SalTrace ( nSeverity, strText )
nSeverity is one of the constants EVENT_INFORMATION, EVENT_WARNING, or EVENT_ERROR. If the trace
output target is the Windows event log, these numeric constants will be used. If the target is something other
than the event log, these numeric constants will converted to text such as “Warning”.
SalTrace can only work in an application that previously called SalStartTrace. So if you write an out-of-process
COM server, and your COM client application calls SalStartTrace before a server call, and your server calls
SalTrace, nothing will happen on the server side because there was no SalStartTrace in that application.

SalEndTrace
This function ends tracing. If you call SalTrace() after calling SalEndTrace(), no action will occur, and nothing
will be written to the output target.

Event Logging
Event logging is used when applications should not be interrupted by error message dialog boxes. COM
servers in particular will benefit from event logging because they may be running unattended on remote
machines.
When event logging is active, any SQLWindows runtime SQL error that would otherwise cause a dialog box
will instead be written to the Windows event log. You can also set a continuation option, which will make the
application behave as if you had clicked a “Continue” or “Yes” pushbutton, when present in a dialog box. Non-
SQL events will continue to halt execution and display a dialog box, just as they did in earlier versions.
Windows 98 and Windows ME do not have event logging. For these operating systems, logging information is
instead written to file TDEvent.log and it is placed in the Windows TEMP directory. You can override the name
and location of this file by editing registry key HKEY_CURRENT_USER\Software\Gupta\SQLWindows
2005\EventLogFile, value LogFilePath.
Event logging is controlled by calls to function SalUseEventLog:
bOk = SalUseEventLog ( bUseLog, bContinuationOption )

300
Chapter 11 – Formatting and Validating
This chapter explains:
• How SQLWindows can format data in data fields and table window columns
• How to define a picture format
• Profile-driven formats based on Window's country profiles
• How SQLWindows validates input
• How to write custom validation code
• How to define input masks

Formatting
You can apply a format to objects such as data fields and table window columns. The format determines how
the data is displayed. After the user enters data, the application displays in the format that you set.
Formatting is related to validation. Validation, the process of ensuring that data the user enters fulfills certain
conditions, is explained on page 306.
The formats that you can apply depend on the data type of the object. You format string and long string data
types differently than number and date/time data types.

Setting a Format
Select Format in the Attribute Inspector to display the formats available for the object. The default format for
all objects is unformatted.

String and Long String Formats


You can format string and long string data types as:
• Unformatted

301
• Invisible
• Uppercase
• Lowercase

Date/Time and Number Formats


You can use two types of formats for number and date/time objects:
• Picture format
• Profile-driven format
Picture formatting is the recommended method. For number or date/time data types, you can:
• Select a built-in picture format
• Enter a custom picture format
• Select a profile-driven format
You can format date/time or number data types in different ways. For example, you can format a date/time
data type so that the date is displayed as 7/1/91 or July 1, 1991.
You can format a number data type as a decimal, percentage, or currency.

Picture Formats
Picture formats are a visual template of the formatted data. They “look like” the data after the data is
formatted. For example, the date/time picture format m/d/yy formats a date as 7/1/91, and a number picture
format #.## formats a number as 1234.56. These same types of formats are used in Excel and COBOL.
You can only use picture formats for date/time or number data types.
You can use a built-in picture format, or you can create a custom picture format.

302
Creating a Custom Picture Format
Using the picture characters in the following tables, enter the format in the Attribute Inspector you want for
an object. SQLWindows adds the new format to the Formats section in Global Declarations. The format then
appears in the format list for existing objects and new objects.
You create a new picture format using the characters in the following tables.

Date/Time Picture Format Characters


Format characters are case-sensitive.

Character Description
M Month: 1-12 (without leading zero)
MM Month: 01-12 (with leading zero)
MMM Month: Jan-Dec (abbreviated name)
MMMM Month: January-December (full name)
d Day: 1-31 (without leading zero)
dd Day: 01-31 (with leading zero)
ddd Day: Sun-Sat (abbreviated name)
dddd Day: Sunday-Saturday (full name)
yy Year: 2-digit
yyyy Year: 4-digit
hh Hour: 12 hour clock
hhhh Hour: 24-hour clock
mm Minute: 0-59
ss Second: 0-59
mmmmmm Microseconds: 000000-999999
AMPM International AM or PM string

Number Picture Format Characters


Character Description
# Zero suppression:
SQLWindows does not add extra zeros if the value has fewer digits on either side of the
decimal point than there are #'s on either side of the format.
You can place the '#' character before any '0' characters on the left side of the decimal or after
any '0' characters on the right side of the decimal.
For example, ##0.0# is legal but 0#.#0 is not.

303
Character Description
0 Zero fill:
SQLWindows adds extra zeros if the value has fewer digits on either side of the decimal point
than there are zeros on either side of the decimal point in the format.
If the number has more digits to the right of the decimal point than there are zeros to the right
of the format, SQLWindows rounds the number to as many decimal places as there are zeros
to the right.
If the number has more digits to the left of the decimal point than there are zeros to the left of
the format, SQLWindows displays the extra digits.
, Thousands separator:
Commas must be three positions to the left of the decimal point. For example, '#,###, ##0.00'
is legal but '#,##,##0.00' is not.
% Percentage. SQLWindows multiplies the number by 100 and adds the % character if the
percent character is immediately after the last zero.
$ Fixed or floating dollar sign:
A fixed dollar sign is always in the same position at the start of a field; a floating dollar sign is
next to the most significant digit.
You cannot put the $ symbol to the right of a 0, #, or decimal point.
When a dollar sign appears by itself, it means formatting for international currency.
E+ Scientific notation (exponential):
If a format has a 0 or # to the right of an E-, E+, e-, or e+, SQLWindows displays the value in
e+
scientific format and adds an E or e. The number of digits (#'s or 0's) sets the exponent's
E- number of digits. E- or e- places a minus sign by negative exponents. E+ or e+ places a plus sign
e- by positive exponents
You must start this format with '0' and a period, followed by '0' and/or '#' characters. Place a
'+', '-', '#', or '0' after the 'E' or 'e'.
0.00E+00 and 0.00###e-00# are examples.
. Decimal point:
The number of digits (#'s or 0's) to display to the right and left of the decimal point.
If the format has only #'s to the left of the decimal point, SQLWindows begins values less than
1 with a decimal point. To avoid this, use 0 as the first format character to the left of the
decimal point instead of #.
* Character fill:
Repeat the next character enough times to fill the field width. Place this character before the
first # or 0 character. For example, $*, ###0.00 results in a fixed dollar sign.
; Separator:
Separates positive and negative formats. For example, ##0.00; -##0.00. There can only be one
“;” character in a format. If there is no “;” character and the value is negative, SQLWindows
adds a “-” to the value.
_ Alignment:
Leaves a space for the character that follows the _ (underscore). This is useful for aligning
fields. If this character is used at the end of a number, place the “_<some character>” as the
last two characters in the format.
For example, $#,##0.00_); ($#,##0.00) ensures that positive values align with negative values
that contain parentheses.

304
Profile-Driven Formats
Warning: The profile-driven formats have been deprecated. The code that enables this functionality is still
present in SQLWindows but only for the purpose of backwards compatibility. GUPTA recommends using the
SQLWindows Picture formats instead (see Picture Formats on page 302).
You can use profile-driven formats for Date/Time and Number data types.
Profile-driven formats use Microsoft Windows country profiles. The formatting used depends on the settings
in the International control panel in Windows NT or the Regional Settings control panel in Windows 95 (see
the next section, Country Profiles).
The data type of the field determines its possible formats. For example, you can format a number field as
currency, decimal, percentage, or unformatted. You can use the following data types with each profile-driven
format:

Format Data type Description


Date Date/Time Formats data with the date specified in the profile
Date/Time Date/Time Formats data with the date/time specified in the profile
Time Date/Time Formats data with the time specified in the profile
Unformatted Date/Time or Leaves data as is
Number
Invisible Date/Time or Hides data
Number
Currency Number Formats the data with the currency specified in the profile
Decimal Number Converts the number to the decimal value specified in the profile
Percentage Number Converts the number to a percentage

Country Profiles
Because countries use different ways to express formatted data (such as the currency symbol), SQLWindows
associates a format with a country profile.
The country item specifies the country profile to use to format table window columns and data fields.
A country profile is a collection of format specifications for different countries. SQLWindows has internally-
defined profiles for certain countries.
When you set Country, SQLWindows uses the format characteristics from the associated profile.
For example, when you select USA as the country for a formatted currency field, SQLWindows uses two
decimal places to the right of the decimal point and the dollar sign ($) currency symbol. These currency
parameters are defined in the USA profile.

Default Country Profiles


When you set the Country to Default, SQLWindows uses the country profile settings in the control panel.
Usually, the default profile is for the country where you live.

305
Country Profile Parameters
The table below describes the parameters for a profile and lists the corresponding format.

Parameter Format Description


iCurrency Currency Currency format. Set to 0 for ($1), 1 for (1$), 2 for ($ 1), and 3 for (1 $).
sCurrency Currency Currency symbol. This string can be up to 40 characters.
iCurrDigits Currency Number of digits in the fractional part of a currency amount
sDecimal Currency Symbol that separates the integer and fractional parts of a number
Decimal
Percentage
iDigits Currency Number of significant digits after the decimal
Decimal
Percentage
iLZero Currency Whether to use a leading zero with decimal values less than 1.0 and
Decimal greater than -1.0. Set to 0 for no leading zero (.7); set to 1 for a leading zero
Percentage (0.7).
sLongDate Date DateTime Date picture for the long date format, such as d MMMM, yyyy
iNegCurr Currency Negative currency format. Set to 0 for ($1), 1 for -$1, 2 for $-1, 3 for $1-, 4
for (1$), 5 for -1$, 6 for 1-$, and 7 for 1$-.
sShortDate Date DateTime Date picture for the short date format, such as M/d/yy.
iTLZero DateTime Time Whether hours have a leading zero. If set to 0, a leading zero is not used.
sThousand Currency Thousands separator character
Decimal
iTime DateTime Time Time format: 0 is a 12-hour clock, 1 is a 24-hour clock.
sTime DateTime Time Time-separator character. For example, (:) is the time separator in (9:25).
s1159 DateTime Time Trailing string for times from 0:00 to 11:59 (AM). This string can up to 3
characters.
s2359 DateTime Time Trailing string for times from 12:00 to 23:59 (PM). This string can up to 3
characters.

Validation
Validation is the process of ensuring that data the user enters meets certain requirements.
Validation is related to, but separate from, formatting. Formatting determines how data is displayed after it is
entered; validation ensures that data meets conditions before it is accepted and displayed.
There are three types of validation you can use in SQLWindows applications:
• Default validation (for Number and Date/Time data types)
• Input masks
• Custom validation that you write

306
Default Validation
SQLWindows performs default validation for number and date/time data types.
SQLWindows performs default validation as soon as the focus leaves the object. If an entry is invalid,
SQLWindows does not let the user move the focus away from the object until the entry is correct or the entry
is blank.

Number Data Types


For number objects, any sequence of numeric characters is valid.
If the object has a number picture format, SQLWindows first checks if the format matches the settings in the
Regional Setting control panel. If it does not, SQLWindows then accepts the entry if it exactly matches the
picture format. This is useful for entering numbers in scientific notation.

Date/Time Data Types


To validate date/time data types, SQLWindows follows the steps below. As soon as the entered data meets
one of the following criteria, the entry is valid and SQLWindows formats and displays the data.
1. SQLWindows looks in the Regional Settings control panel for the sShortDate
2. setting. If the entered data matches sShortDate, the data is valid.
3. If the data does not match sShortDate, SQLWindows checks if the data matches the sLongDate setting. If
the entered data matches sLongDate, the data is valid.
4. If the data does not match sLongDate, SQLWindows checks it using the following standard date formats,
shown here in picture format:
 MM d,yyyy
 MMM dd,yyyy
 MMMM d,yyyy
 MMMM dd,yyyy
 yyyy-MM-dd
 d MMMM, yyyy
 dd MMMM, yyyy
If the entered data matches any of the formats above, the data is valid.
5. If the data does not match any of the formats above and the object has a date/time picture format,
SQLWindows checks the entry against the picture format. If the entered data matches the picture format,
the data is valid.
If the entered data does not match any of the above, then the data fails validation and SQLWindows displays
an “invalid data” message.

Custom Validation
You can replace the SQLWindows default validation with custom validation. For custom validation, you
process the SAM_Validate message for an object.

307
Whenever the user changes an object, SQLWindows sends SAM_Validate. Usually, you Return
VALIDATE_Cancel if validation fails or VALIDATE_Ok (this resets the field edit flag to FALSE) if validation
succeeds. If you do not return a value when processing SAM_Validate, SQLWindows performs its default
validation. The value you return from SAM_Validate processing controls whether the focus changes; for
example:
Data Field: dfName
...
On SAM_Validate
If SalIsNull( dfName )
Call SalMessageBox( 'You must enter a value', 'Data Error', MB_Ok )
Return VALIDATE_Cancel
Else
Return VALIDATE_Ok
SQLWindows does not send SAM_Validate when the user selects a menu item (a menu selection does not
change the focus). You can force SQLWindows to send SAM_Validate by calling SalSendValidateMsg in the
menu actions of a menu item. This forces validation before processing a menu selection (without changing
the focus). SalSendValidateMsg returns the value that the SAM_Validate message processing returns.
For a table window, process the SAM_RowValidate message to check the contents of a row:
Table Window: tbl1
...
Message Actions
On SAM_RowValidate
If SalIsNull( col1 )
Call SalMessageBox( 'You must enter a value', 'Validation Error',
MB_Ok )
Return VALIDATE_Cancel
Else
Return VALIDATE_Ok
See Chapter 9 – Messages.

Input Masks
An input mask validates data as a user enters it. You use an input mask to specify a criteria for a value. These
are the criteria that you can specify:
• Alphabetic or numeric characters. If the user types a character that is invalid, SQLWindows beeps.
• Uppercase or lowercase characters. SQLWindows automatically converts the character if the user enters
it in the wrong case.
• Constants. SQLWindows inserts a constant (such as a hyphen) in a position automatically without the
user typing it.

Defining Input Masks


You can set input masks for fields. In this section, field means:
• Combo box
• Data field
• Table window column
308
You can set an input mask for any data type.
You define an input mask for a field using the Attribute Inspector.
You can choose an existing input mask or define a new one. The existing input mask formats are in the
Formats section (under Global Declarations) with the Date/Time and Number picture formats. SQLWindows
adds new input masks that you define to the Formats section.

Input Mask Characters


You can use the following characters in input masks:

Mask Character Matches


X Any character

! Any character, uppercase

a Alphabetic characters

A Alphabetic characters, uppercase

9 Digits 0-9

n Alphanumeric characters

N Alphanumeric characters, uppercase

^ In the first position of an input mask, this character means not to unmask the value
on get operations. This only applies to String fields and overrides the setting of
SalFmtKeepMask for the field.

All other characters (including spaces) in an input mask are a constant that SQLWindows inserts
automatically.
These are examples of input masks:

Example Explanation
999-99-9999 Social Security number

(999) 999-9999 Telephone number

AA-9999 Code: two uppercase letters, a dash, and four numbers

99/99/99 Date

AAA !!!!!!!!!!!!! Code: three uppercase letters, a blank, and any other uppercase characters

Input Masks for Numbers


SQLWindows treats masked number fields in this way:
• When the user moves the focus off a masked number field, SQLWindows formats the field contents
according to its output display format
• When the user moves the focus back to a number field, SQLWindows formats the contents using the
input mask
This lets you to create both a mask for input and a format for display (such as for currency).
309
Input Masks for Date/Times
You can define an input mask such as 99/99/9999 or 99-99-9999 for a Date/Time field so that the user does
not have to type the date separator (such as slash or hyphen). However, if the user moves the focus off the
field and then moves the focus back to the field, SQLWindows does not use the input mask when the user
edits the value.
Warning: Because of this behavior, it is recommended that you not use input masks with Date/Time fields.

Setting a Field’s Value


When you set a field, SQLWindows applies the input mask and truncates, if necessary. In the following
example, the df1 data field has this input mask: “XX-XX”. When the user clicks the pb1 push button, the df1
data field is displayed as “ab-c-”.
Data Field: df1
! This field is a String data type and has
! this input mask: "XX-XX"
...
Pushbutton: pb1
Message Actions
On SAM_Click
Set df1 = 'abc-d' ! df1 displays "ab-c-"

Getting a Field’s Value


When you set a variable with the value of a field, SQLWindows removes input mask characters. In the
following example, the df2 data field does not have an input mask.
When the user clicks the pb2 push button, df2 is displayed as “abc-”.
Data Field: df2
! This field is a String data type and does not
! have an input mask
...
Pushbutton: pb2
Message Actions
On SAM_Click
Set str1 = df1 ! Assume that df1 displays "ab-c-"
Set df2 = str1 ! df2 contains "abc-"
...
Window Variables
String: str1
You can change this behavior by calling SalFmtKeepMask (see the next section).

Input Mask Functions


You can use the input mask functions below at runtime.

SalFmtGetInputMask
This function returns the input mask of field hWnd in strMask:

310
bOk = SalFmtGetInputMask( hWnd, strMask )

SalFmtSetInputMask
This function sets the input mask of the field hWnd to the value in strMask:
bOk = SalFmtSetInputMask( hWnd, strMask )

SalFmtIsValidInputMask
This function validates the input mask in strMask and returns TRUE if the mask is valid:
bOk = SalFmtIsValidInputMask( strMask )

SalFmtKeepMask
By default, SQLWindows removes input mask characters when you copy the value in a data field, table
window column, or combo box. For example, if you create a data field with the input mask “AA-AA” and copy
its value to another data field, SQLWindows removes the hyphen. You can call SalFmtKeepMask to change the
default behavior and include input mask characters when you copy the value in a field:
bRet = SalFmtKeepMask( bKeep )
If bKeep is FALSE (default), SQLWindows removes input mask characters when you copy a value. If bKeep is
TRUE, SQLWindows keeps the input mask characters when you copy a value.
This function returns the value you specified in bKeep.
If a field has a “^” character in its input mask (see above), it overrides the setting you make with this function.

SalFmtUnmaskInput
This function unmasks the contents of hWnd and puts the result in strInput:
bOk = SalFmtUnmaskInput( hWnd, strInput )
Only use this function in SAM_Validate message processing.

SAM_Validate Processing
You can process SAM_Validate messages for fields that have input masks.
You can call SalFmtUnmaskInput in the SAM_Validate processing to get the value the user entered without
the input mask constants.

SalIsNull
SalIsNull works the same for a field that has an input mask as for other fields. If the field is empty, SalIsNull
returns TRUE, even if the input mask has constants.

311
Chapter 12 – SQL Programming
This chapter shows how to access a SQL database from a SQLWindows application and covers these topics:
• Database access cycles
• Error handling
• Database parameters
• Multiuser techniques

Using SQL in a SQLWindows Application


SQL (Structured Query Language) can create, query, change, and control data in a relational database.
However, SQL is not a programming language and does not provide:
• Procedural logic
• Extensive data typing
• Variables
The Sql* functions in SQLWindows are a language interface that you use to access a database with SQL
statements. You can combine SQL statements with the power and flexibility of SAL.
You can access database servers such as SQLBase with a SQLWindows application. SQLBase has a complete
implementation of SQL that is compatible with IBM's DB2. In addition, SQLBase has extensions to DB2.
The Sql* functions are database-independent. You can use the Sql* functions with GUPTA’s connectivity
components to access IBM DB2, Oracle, Microsoft SQL Server, Sybase, Informix, and other databases.
The applications that you write with SQLWindows are client (or front end) applications. The database (such as
SQLBase or DB2) is the server (also called backend or engine).

Requirements
This chapter assumes that you know SQL and, therefore, does not explain SQL statements or syntax:
• If you are using SQLBase, read the SQLBase SQL Reference.
• If you are using another vendor's database, read that vendor's SQL documentation and Connecting
GUPTA Objects to Databases.
The examples in this chapter use SQLBase SQL. Also, this chapter shows examples of setting database
parameters for SQLBase.
If you are using a different database, check Connecting GUPTA Objects to Databases to find the parameters
supported for your database. There are many variations in how a SQLWindows application would connect to a
non-SQLBase database, particularly in the area of stored procedures, so it is well worth reading about.

312
Database Access Cycle
You can access a SQL database in two ways in a SQLWindows application:
• Multistep interface
• Single-step interface
You can combine the two interfaces in an application.

Multistep Interface
With the multistep interface, you must connect to a database before you perform any database operations.
For each operation you perform, you compile and execute a SQL statement. For SELECTs, you must also fetch.
When you complete the database operations, you disconnect from the database.

In the multistep interface, you can fetch rows from a result set created with a SELECT statement. The
multistep interface is more flexible and gives you more control over database parameter settings than the
single-step interface.

Single-Step Interface
With the single-step interface, you can perform a database operation in one function call. The single-step
interface is easier to use, but SELECTs can only return one row. Every function call using this interface requires
a database connect and disconnect, which may impact performance.

Choosing the Best Interface


The single-step interface is faster and simpler to code. However, it is usually the wrong choice for applications
of medium to high complexity. In such applications, the multistep interface has the advantages of faster
performance, lower resource usage, more graceful error recovery, and better control of locking and
concurrency. It is generally worth the extra effort to use the multistep interface.

313
Multistep Interface

Connecting and Disconnecting


You must connect to a database before you can perform database operations. You must disconnect from the
database before you exit from the application.
The table below shows the functions you call to connect to and disconnect from a database:

Function Description
SqlConnect Connects to a database
SqlDisconnect Disconnects from a database

Calling SqlConnect
To connect to a database, you must:
• Specify the database you want to connect to
• Specify the user name and password to use in the connection
• Alternately, specify a UDL file name that contains connection information.
• Call the SqlConnect function that returns a Sql Handle
Database name, user name, and password. SQLWindows has four system variables that identify the
database, user name, and password, and OLE DB connection information:
• SqlDatabase
• SqlUser
• SqlPassword
• SqlUDL designates an OLE DB configuration file (UDL file) or an OLE DB provider name or connection
string.
You can set these in the Application Actions section; for example:
On SAM_AppStartup
Set SqlDatabase = 'SPA'
Set SqlUser = 'username'
Set SqlPassword = 'userpswd'
Set SqlUDL = ‘c:\\My Documents\\gupta.udl’
The default values for these system variables are the following:

System Variable Default Value


SqlDatabase DEMO
SqlUser SYSADM
SqlPassword SYSADM
SqlUDL No default

It is important to understand the relationship between SqlUDL and the other three variables.

314
• The presence of a value in SqlUDL means the SqlConnect function will establish an OLE DB connection to
the database. If SqlUDL is null, an API connection (using native routers) will be made.
• If the connection string formed by reading SqlUDL (or reading the file pointed to by SqlUDL) is
incomplete, SqlConnect will attempt to fill in missing values by looking at the values in SqlDatabase,
SqlUser, and/or SqlPassword.
• If there is a value in SqlDatabase, SqlUser, or SqlPassword, even if the connection string is already
complete, that value will always override whatever is already in the connection string. The most
significant aspect of this behavior is that you can omit password information from a UDL file that is
pointed to by SqlUDL, and instead supply the password at runtime from variable SqlPassword. By avoiding
the storage of passwords in disk files you can increase database security.
Sql Handles. The SqlConnect function returns a Sql Handle that identifies a specific connection to a database.
A Sql Handle is opaque and you do not care about its actual value, but you use it to identify the connection in
functions you call later. A Sql Handle is also called a cursor.
The term Sql Handle refers to three things in SQLBase:
• A name that identifies a database connection
• A row position in a result set
• A work space in memory used to process a SQL statement
You must declare a variable with the Sql Handle data type for each connection you make to a database:
Global Declarations
...
Variables
Sql Handle: hSqlFetch
Sql Handle: hSqlChange
Before you call SqlConnect, a Sql Handle does not have a valid value.
Example. In the following example, the code connects two Sql Handles:
Set bConnect = SqlConnect( hSqlFetch )
If bConnect
Set bConnect = SqlConnect( hSqlChange )
When you call SqlConnect, it allocates these resources on the client and server:
• Sql Handle work space
• Input message buffer and output message buffer (this chapter explains these later)

Calling SqlDisconnect
Call the SqlDisconnect function after you perform all database operations. Always disconnect all Sql Handles
before exiting an application:
On SAM_AppExit
If bConnect
Call SqlDisconnect( hSqlFetch )
Call SqlDisconnect( hSqlChange )
When you call SqlDisconnect, it frees resources on the client and server.
Always call SqlDisconnect for all Sql Handles that you connected with SqlConnect. The last SqlDisconnect for a
database causes an implicit COMMIT.

315
Performing Database Operations
This section explains how to:
• Code bind variables and INTO variables in a SQL statement
• Compile and execute a SQL statement
• Fetch data for a SELECT
• INSERT, UPDATE, and DELETE

Bind variables and INTO variables


There are two types of variables in SQL statements: bind variables and INTO variables.
Bind variables. Use bind variables for input values, such as column names in a WHERE clause. Data from a
bind variable defined in the application is bound (associated) to a statement each time you execute it. Bind
variables send data from an application variable to the database.
You use bind variables for:
• Values in conditions in WHERE clauses in SELECT statements
• VALUES clauses in INSERT statements
• SET clauses in UPDATE statements
You can compile a SQL statement once and execute it repeatedly with a new set of input values each time.
You cannot use constants for bind variables.
INTO variables. Use INTO variables for the output of a SQL SELECT statement. The INTO clause specifies the
variables defined in the application where SQLWindows returns query data.
Bind variable and INTO variable names. You must prefix each bind variable and INTO variable in a SQL
statement with a colon (:).
Maximum number of bind variables and INTO variables. The maximum number of bind variables in a SQL
statement is 255; the maximum number of INTO variables in a SQL statement is 255. These limits apply to SQL
statements that you refer to in these functions:
• SqlImmediate
• SqlPrepare
• SqlPrepareAndExecute
• SqlRetrieve
• SqlStore
Example
The following example shows how to code bind variables and INTO variables in SQL statements:
¿ strSelectByName contains INTO variables (:dfGuestName, :dfInWeight, :dfTargetWeight, and
:dfROWID) and one bind variable (:dfGuestName). The ROWID column is explained later in this
chapter.
¡ strInsert only contains bind variables (:dfGuestName, :dtCheckIn, :dfIn- Weight, and :dfTargetWeight).
¬ strUpdateByName only contains bind variables (:dfInWeight, :dfTarget- Weight, and :dfGuestName).

316
Global Declarations
...
Variables
String: strSelectByName
String: strInsert
String: strUpdateByName
...
Application Actions
On SAM_AppStartup
¿ Set strSelectByName = 'select name, in_weight, target_weight, rowid
into :dfGuestName, :dfInWeight, :dfTargetWeight, :dfROWID
from guest
where name = :dfGuestName'
¡ Set strInsert = 'insert into guest(name, check_in, in_weight,
target_weight )
values( :dfGuestName, :dtCheckIn, :dfInWeight, :dfTargetWeight )'
¬ Set strUpdateByName = 'update guest
set in_weight = :dfInWeight, target_weight = :dfTargetWeight
where name = :dfGuestName'

Compiling and executing SQL statements


You call the following functions to compile and execute SQL statements:

Function Description
SqlPrepare Compiles a SQL statement
SqlExecute Executes a SQL statement
SqlPrepareAndExecute Compiles and executes a SQL statement in one step

The SqlPrepare function compiles a SQL statement. When you call SqlPrepare, SQLWindows checks the INTO
clause (for a SELECT statement) and verifies bind variables. SQLWindows sends the statement to the server
where SQLBase:
1. Parses the statement, detects syntax errors, and verifies that the database objects exist.
2. Checks security.
3. Determines how to access the data. Finds the indexes (if any) that provide the best path to the data. This
information is called the execution plan.
4. Translates the statement into a series of executable modules. SQLBase stores the compiled statement in
the Sql Handle work space.
After you compile a statement, you execute it with the SqlExecute function, which sends the bind variable
values to the server.
You can also prepare and execute SQL statements in one step by calling SqlPrepareAndExecute.

317
Once you prepare a SQL statement, you can call SqlExecute as many times as you need. However, these
actions destroy a compiled statement:
• Compiling another statement on the same Sql Handle
• A COMMIT or ROLLBACK if DBP_PRESERVE is off (see Transaction Scope on page 332).

SELECTs (Queries)
To perform a SELECT, follow these steps:
1. Prepare (compile) the SELECT statement.
2. Execute the SELECT statement.
3. Call a SqlFetch* function to fetch the row data to the INTO variables.
Use these functions for result sets produced by a SELECT:

Function Description
SqlFetchNext Fetches the next row in a result set.
SqlFetchPrevious Fetches the previous row in a result set.
SqlFetchRow Fetches a specific row from a result set.
SqlGetResultSetCount Returns the number of rows in a result set after a SqlExecute.
SqlSetResultSet Turns result set mode on and off for the specified Sql Handle. You can
also set this parameter with the SqlResultSet system variable.

Result sets and fetches (row-at-a-time processing)


A result set (or result table) is a set of database table rows produced by a query (SELECT statement). An
application fetches one row at a time from the result set and processes it.
After you compile and execute a SELECT statement, you call the SqlFetchNext function to fetch the first row
from the result set. After that, each time you call SqlFetchNext, SQLWindows fetches the next row from the
result set.
These actions destroy a result set:
• Compiling another statement on the same Sql Handle
• A COMMIT or ROLLBACK if DBP_PRESERVE is off for that Sql Handle (see Transaction Scope on page 332).

Result set mode


You can use result set mode for queries. This feature is useful for a browsing application. When a
SQLWindows application first starts up, the value of the global system variable SqlResultSet is undefined
(null). As long as the variable's value remains undefined, result set mode is initially on for all your connections
to SQLBase and initially off for all your connections to all other database servers. You can turn on/off result
set mode with the SqlSetResultSet function or by changing the value of the SqlResultSet system variable.
Note that when connected to an Oracle database, you must first set SqlResultSet to FALSE before calling
SqlFetchRow. When connected to SQLBase or any non- Oracle database, you must first set SqlResultSet to
TRUE before calling SqlFetchRow.

318
In result set mode, after executing a SELECT statement, you can get any row in the result set with the
SqlFetchRow function without sequentially fetching forward. Once the Sql Handle is positioned, later fetches
start from that row. You can also call the SqlFetchPrevious function in result set mode to fetch backward.

Example
The following example shows how to perform a SELECT statement:
¿ Declare a Sql Handle, a boolean for return values, a string to hold the SELECT statement, and a
number for the fetch indicator.
¡ Assign the SELECT statement.
¬ The form window has two push buttons that let the user fetch the next and previous rows. The
SAM_Create actions for the form window disable the push buttons. The push buttons are enabled
later after a successful fetch.
Ð Compile the SELECT statement with SqlPrepare. The first parameter is the Sql Handle returned by
SqlConnect. The second parameter is the variable that contains the SQL statement.
ƒ Execute the SELECT statement with SqlExecute. The SqlExecute function executes the previously
compiled statement.
The following lines can be replaced:
Set bOk = SqlPrepare( hSqlFetch, strSelect )
Set bOk = SqlExecute( hSqlFetch )
Replace them with the following:
Set bOk = SqlPrepareAndExecute( hSqlFetch, strSelect )
Call SqlFetchNext to get the first row.
Ý

ý After calling SqlFetchNext, check the fetch indicator. The fetch indicators are the following:
Constant Description
FETCH_Delete Failure: the row has been deleted since it was last fetched
FETCH_EOF Failure: there are no more rows to fetch (end of fetch)
FETCH_Ok Success: the row was fetched
FETCH_Update Failure: the row has been updated since it was last fetched

319
Global Declarations
...
Variables
¿ Sql Handle: hSqlFetch
Boolean: bOk
String: strSelect
Number: nFetch
...
Application Actions
On SAM_AppStartup
¡ Set strSelect = 'select name, in_weight, target_weight, rowid
into :dfGuestName, :dfInWeight,
:dfTargetWeight, :dfROWID from guest'
...
Form Window: frmMain
Contents
...
Pushbutton: pbPreviousRow
...
Pushbutton: pbNextRow
...
Message Actions
On SAM_Create
¬ Call SalDisableWindow( pbPreviousRow )
Call SalDisableWindow( pbNextRow )
...
Ð Set bOk = SqlPrepare( hSqlFetch, strSelect )
ƒ Set bOk = SqlExecute( hSqlFetch )
Ý Set bOk = SqlFetchNext( hSqlFetch, nFetch )
ý If nFetch = FETCH_Ok
Call SalEnableWindow( pbNextRow )
After successfully fetching the first row, the code enables the pbNextRow push button. The user can then click
pbNextRow to fetch other rows.
The following examples show the SAM_Click actions for the pbNextRow and pbPreviousRow push buttons:
Pushbutton: pbNextRow
...
On SAM_Click
Set bOk = SqlFetchNext( hSqlFetch, nFetch )
If nFetch = FETCH_Ok
Call SalEnableWindow( pbPreviousRow )
Else If nFetch = FETCH_EOF
Call SalDisableWindow( pbNextRow )

Pushbutton: pbPreviousRow
...
On SAM_Click
Set bOk = SqlFetchPrevious( hSqlFetch, nFetch )
If nFetch = FETCH_Ok
Call SalEnableWindow( pbNextRow )
Else If nFetch = FETCH_EOF
Call SalDisableWindow( pbPreviousRow )

INSERTs, UPDATEs, and DELETEs


The following example shows how to perform an UPDATE statement. You perform other SQL DML (Data
Manipulation Language) statements in the same way:

320
¿ Compile the SQL statement with SqlPrepare.
¡ Call SqlExecute to execute the SQL statement.
¬ COMMIT or ROLLBACK the transaction. You can COMMIT by calling the SqlCommit function or
you can compile and execute a string that contains “COMMIT”. You can ROLLBACK by compiling
and executing a string that contains “ROLLBACK”.
After you execute a DML statement, you can call SqlGetModifiedRows to find the number of rows that the
INSERT, UPDATE, or DELETE changed.
Global Declarations
...
Variables
Sql Handle: hSqlChange
...
String: strUpdate
On SAM_AppStartup
Set strUpdateByName = 'update guest set in_weight = :dfInWeight,
target_weight = :dfTargetWeight where name = :dfGuestName'
...
! The code below can be in any actions section
...
¿ Set bOk = SqlPrepare( hSqlChange, strUpdateByName )
¡ Set bOk = SqlExecute( hSqlChange ) If bOk
¬ Call SqlCommit( hSqlChange )

Other Operations
You perform DDL (Data Definition Language) statements such as CREATE or DROP and database
administration statements such as GRANT or REVOKE in the same way you perform DML statements.

Using Multiple Sql Handles and Database Connections


You can use more than one Sql Handle in an application. Each Sql Handle keeps track of a different database
connection.
If you need to use more than one SQL statement at a time, you must connect a second Sql Handle:
• An application can set up multiple connections (Sql Handles) to the same database
• An application can connect to multiple databases. The databases can be on the same or on different
servers

Multiple connections to same database


An application can set up multiple connections (Sql Handles) to the same database.
For example, you can UPDATE a column in one table based on a value in another table. You use one Sql
Handle for the SELECT statement and another for an UPDATE statement. As you fetch each row with the first
Sql Handle, you execute the UPDATE statement with the second Sql Handle. You can also use a second handle
to INSERT or DELETE rows.
The scope of a transaction is all Sql Handles that an application has connected to a database for a given user
name. This means that a COMMIT or ROLLBACK (implicit or explicit) applies to the work done for all Sql
Handles connected to a database for that user name (see Transaction Scope on page 332).

321
Multiple connections to different databases
An application can connect to multiple databases on the same server or on different servers.
Each database maintains its own transaction and ROLLBACK information. Again, the scope of a transaction is
all Sql Handles that an application has connected to a database for a given user name. This means that a
COMMIT or ROLLBACK applies to the work done for all Sql Handles connected to that database for that user
name, but not to the work done for other connected databases or other user names (see Transaction Scope
on page 332).

Example
The following example shows how to use two Sql Handles connected to the same database to SELECT and
UPDATE. One Sql Handle is for a SELECT statement and the other Sql Handle is for an UPDATE statement.
After a row is fetched with the first Sql Handle, the UPDATE is executed with the second Sql Handle.
¿ Declare two Sql Handles.
¡ Declare variables for the SELECT statement and the UPDATE statement.
¬ Assign values to the variables that hold the SELECT statement and the UPDATE statement.
Ð Perform two SqlConnect functions. Both connections are to the same database, but each
connection is associated with a different Sql Handle.
ƒ Compile and execute the SELECT statement with SqlPrepare and SqlExecute. The SELECT
statement is associated with the first Sql Handle.
Ý Fetch a row of data with SqlFetchNext.
ý Compile and execute the UPDATE statement with SqlPrepare and SqlExecute. The UPDATE
statement is associated with the second Sql Handle.
« Before exiting the application, disconnect both Sql Handles.

322
Global Declarations
Variables
¿ Sql Handle: hSqlFetch
Sql Handle: hSqlChange
¡ String: strSelect
String: strUpdate
...
Application Actions
¬ On SAM_AppStartup
Set strSelect = 'select name, in_weight, target_weight, rowid into
:dfGuestName, :dfInWeight, :dfTargetWeight, :dfROWID
from guest'
Set strUpdate = 'update guest
set name = :dfGuestName,
in_weight = :dfInWeight,
target_weight = :dfTargetWeight
where rowid =:dfROWID'
On SAM_AppExit
« If bConnect
Call SqlDisconnect( hSqlFetch )
Call SqlDisconnect( hSqlChange )
...
! The code below can be in any actions section
...
Ð Set bConnect = SqlConnect( hSqlFetch )
If bConnect
Set bConnect = SqlConnect( hSqlChange )
...
Ƒ Call SqlPrepare( hSqlFetch, strSelect ) Call SqlExecute( hSqlFetch )
Ý Call SqlFetchNext( hSqlFetch, nFetch )
...
! User changes row data
...
Ý Call SqlPrepare( hSqlChange, strUpdate )
Set bOk = SqlExecute( hSqlChange )
If bOk
Call SqlCommit( hSqlChange )

Single-Step Interface
The single-step interface has two functions:

Function Description
SqlImmediate Connects an internal Sql Handle and prepares and executes a SQL statement
SqlClearImmediate Disconnects the Sql Handle created with SqlImmediate

SqlImmediate executes SqlConnect, SqlPrepare, SqlExecute, and (for a SELECT) SqlFetchNext:

323
The first time you call SqlImmediate, SQLWindows performs all of these functions. On later calls, SQLWindows
does not perform the SqlConnect if the Sql Handle is still connected.
For the SqlConnect, SQLWindows uses the current values of the system variables SqlDatabase, SqlUser, and
SqlPassword.
You can use SqlImmediate to:
• SELECT one row from a database.
• Perform Data Manipulation Language (DML) statements that INSERT, UPDATE, or DELETE.
• COMMIT or ROLLBACK the current transaction.
• Perform Data Definition Language (DDL) statements.
• Perform Data Control Language (DCL) statements.
SQLWindows manages the Sql Handle internally and you cannot refer to it in a later Sql* function.
If you call SqlImmediate twice for different databases, SQLWindows reuses the internal Sql Handle by
disconnecting and reconnecting.
SqlClearImmediate disconnects the internal Sql Handle and frees resources. SqlClearImmediate causes an
implicit COMMIT if it disconnects the last Sql Handle connected to a database.

Example
The following example SELECTs and UPDATEs a row using two calls to SqlImmediate:
Global Declarations
Variables
String: strSelectByName
String: strUpdateByName
...
Application Actions
On SAM_AppStartup
Set strSelectByName = 'select name, in_weight, target_weight, rowid
into :dfGuestName, :dfInWeight, :dfTargetWeight, :dfROWID
from guest
where name = :dfGuestName'
Set strUpdateByName = 'update guest
set in_weight = :dfInWeight, target_weight = :dfTargetWeight
where name = :dfGuestName'
...
! The code below can be in any actions section
...
Set bSelect = SqlImmediate( strSelectByName )
...
! User changes row
...
Set bOk = SqlImmediate( strUpdateByName ) If bOk
Call SqlImmediate( 'commit' )

Long Strings
Use the Long String data type for bind and INTO variables for SQL database columns that are longer than 254
bytes, as follows:

324
Database Data types
AS/400 CHAR, VARCHAR
DB2 LONG VARCHAR
Informix-Online CHAR, VARCHAR, BYTE, TEXT
Informix-SE CHAR
Ingres CHAR, VARCHAR, TEXT, C
Oracle CHAR, VARCHAR, LONG, LONG RAW
SQLBase LONG VARCHAR
SQL Server Sybase TEXT, IMAGE

Internally, SQLWindows uses the SQL/API functions sqlrlo and sqlwlo to read and write these column data
types.

SQL Error Handling


All Sql* functions (except for SqlError) return TRUE if successful or FALSE if not successful. If a function fails,
an application uses:
• SQLWindows default error handling
• Application-defined error handling (optional)

Default SQL Error Handling


If you do nothing to handle SQL errors, SQLWindows uses its default error handling, which displays a dialog
with information about the error:

The dialog has three push buttons:

325
• If the you click Continue, the application continues to run and the Sql* function that caused the error
returns FALSE.
• If you click Halt, the application ends.
• If you click Copy, the text of the error message is copied to the clipboard.
Important: The default error dialog is for development use. Design production applications so that they
handle all SQL errors and that the default error handling never takes places. For most production applications,
the default error dialog is not appropriate.

Application-Defined SQL Error Handling


You can code your own SQL error handling:
• Use the When SqlError statement in any actions section to handle errors on a local level
• Use SAM_SqlError handling in the Application Actions section to handle errors on a global level

Using both SQL Error Handling Methods


You can combine application-defined error handling with SQLWindows default error handling.
The following flowchart summarizes how to use When SqlError, SAM_SqlError, and default error handling:

326
The flowchart shows the steps SQLWindows follows when a Sql* function fails.
1. SQLWindows looks for When SqlError in the local actions section. You must code When SqlError
statements: before the Sql* function and at the same indent level as the Sql* function.
If there is a When SqlError, SQLWindows performs its statements:
 If When SqlError has a Return statement, the Return value becomes the return value of the failed
Sql* function and there is no further error handling
327
 If When SqlError does not have a Return statement, SQLWindows looks for the On SAM_SqlError
statement in the Application Actions section
If there is not a When SqlError in the local section, SQLWindows looks for On SAM_SqlError in the
Application Actions section.
2. SQLWindows looks for On SAM_SqlError in the Application Actions section if there is not a local When
SqlError statement or if the local When SqlError did not return a value.
If there is an On SAM_SqlError statement, SQLWindows performs its statements:
 If On SAM_SqlError has a Return statement, the Return value becomes the return value of the failed
Sql* function and there is no further error handling
 If On SAM_SqlError does not have a Return statement, SQLWindows performs its default error
handling
If there is not an On SAM_SqlError in the application actions, SQLWindows performs its default error
handling.
For the default error handling, if a user clicks the Halt push button, the application ends. If a user clicks the
Continue push button, the Sql* function that caused the error returns FALSE and the application continues.

SQL Error Handling Functions


Use the following functions to process errors:

Function Description
SqlError Returns the most-recent error code for the specified Sql Handle (zero if the
operation was successful).
SqlErrorText Gets one or more of the following for a given error code: error message text,
error reason, and error remedy.
SqlExtractArgs Extracts error information.
SqlGetError Returns the last backend error number and message text.
SqlGetErrorPosition Returns the offset of an error within a SQL statement. The first character is
position 0.
SqlGetErrorText Gets the message text for a SQL error number.
SqlGetErrorTextX
SqlGetRollbackFlag Returns the database rollback flag. The rollback flag is set to TRUE after a
deadlock or system failure, but not set after a user-initiated ROLLBACK.

Local Error Handling Example for an INSERT


The following code shows a menu item that the user selects to INSERT a row in a database. The first
statement in the Menu Actions is When SqlError. If a later Sql* function fails, the statements under When
SqlError execute:

¿ SqlExtractArgs gets the error number (nErr). The first parameter is the wParam of the
SAM_SqlError message. (“When SqlError” is actually a form of handling SAM_SqlError on a local
level.)
¡ SalNumberToStr converts nErr to a displayable string.

328
¬ SqlGetErrorText gets the error message text for nErr.

Ð The code checks to find if nErr is DB_ERR_Dup_Key (805), which means that the user tried to
add a row with a duplicate key. If nErr is 805, the code displays a message box with the error
number, error message, and a message saying to enter a unique value and try again. After
clicking the OK push but- ton, the user can change the key value and try to INSERT again.
ƒ If nErr was 805, the code returns FALSE, which does two things:
• Makes the Sql* function that caused the error return FALSE. For example, if the SqlExecute
fails because of duplicate key, the SqlCommit does not execute:
Set bOk = SqlExecute( hSqlChange )
If bOk
Call SqlCommit( hSqlChange )

• Tells SQLWindows not to invoke SAM_SqlError handling or default error handling.

Ý If nErr was not 805, the code does not return a value to tell SQLWindows to invoke the handling
for SAM_SqlError in the Application Actions (this is shown in the next section).

329
Global Declarations
...
Constants
...
Number: DB_ERR_Dup_Key = 805
...
Application Actions
...
On SAM_AppStartup
...
Set strInsert = 'insert into guest( name, check_in, in_weight,
target_weight )values( :dfGuestName, :dtCheckIn, :dfInWeight,
:dfTargetWeight )'
...
Menu
...
Popup Menu: Insert
...
Menu Item: Insert Row
...
Menu Actions
When SqlError
¿ Call SqlExtractArgs( wParam, lParam, hSqlError, nErr, nPos )
¡ Call SalNumberToStr( nErr, 0, strNum )
¬ Call SqlGetErrorText( nErr, strErrmsg )
!
! A "normal" error on an INSERT is a duplicate key value
Ð If nErr = DB_ERR_Dup_Key
Call SalMessageBox( strNum || ' - ' || strErrmsg || '.
Enter a unique value and try again.',
'Insert Error', MB_Ok | MB_IconExclamation )
!
! The Return statement tells SQLWindows **not** to invoke
! SAM_SqlError handling (Application Actions) or
! default error handling
ƒ Return FALSE
!
Ý ! If we get to here, do not Return a value to tell SQLWindows
! to invoke the SAM_SqlError handling in the Application Actions
Set dtCheckIn = SalDateCurrent( )
Call SqlPrepare( hSqlChange, strInsert )
Set bOk = SqlExecute( hSqlChange )
If bOk
Call SqlCommit( hSqlChange )

Global Error Handling Example


The following code shows the SAM_SqlError handling in the Application Actions section. These statements
are only executed when the When SqlError statements for local handling do not return a value:
¿ SqlExtractArgs gets the error number (nErr).
¡ SalNumberToStr converts nErr to a displayable string.
¬ SqlGetErrorText gets the error message text for nErr.
Ð The code displays a message box with the error number, error message, and a message saying to
report the error. The user clicks the OK push button to quit the application.
ƒ The code returns a value to tell SQLWindows not to invoke the default error handling.

330
Application Actions
On SAM_SqlError
!
! If handling gets to here on a SQL error, there is
! little to do except report the error and gracefully quit
!
¿ Call SqlExtractArgs( wParam, lParam, hSqlError, nErr, nPos )
¡ Call SqlGetErrorText( nErr, strErrmsg )
¬ Call SalNumberToStr( nErr, 0, strNum )
!
Ð Call SalMessageBox( strNum || ' - ' || strErrmsg || '.
Please report to your system administrator.
Click OK to quit the application.',
'Database Error', MB_Ok | MB_IconStop )
!
! The Return statement tells SQLWindows **not** to invoke
! default error handling
!
ƒ Return FALSE

ERROR.SQL
All error messages are stored in a common error message file called ERROR.SQL. ERROR.SQL contains all error
codes the Sql* functions can cause. ERROR.SQL must be on the client computer. SQLBase servers also use
ERROR.SQL.
As the following example shows, for each error message there is:
• Error message text
• An error reason
• An error remedy

00353EXE NSY Not a synonym

Reason:Attempting to execute a DROP SYNONYM and the named synonym


is not a synonym but a table name.

Remedy:Modify the DROP SYNONYM statement to use a synonym name or


if you really want to drop a table then use a DROP TABLE
statement.
The lines with the error message text contain the error code, a mnemonic, and the message text for that
code. When an application detects an error, it uses the error code to look up the error message.

Search path
SQLWindows looks for ERROR.SQL in these places in this order:

331
1. As specified by the SQLBASE environment variable (if the variable exists)
2. Current directory
3. \SQLBASE directory
4. The root directory
5. As specified by the PATH environment variable

Transaction Scope
Each database maintains its own transaction and ROLLBACK information. The scope of a transaction is all Sql
Handles that the application has connected to a database for a given user name. This means that a COMMIT
or ROLLBACK (implicit or explicit) applies to the work done for all Sql Handles connected to that database for
that user name, but not to the work done for other connected databases or other user names.
If cursor-context preservation ( DBP_PRESERVE) is off, a COMMIT destroys all compiled statements and
results sets for all Sql Handles that the application has connected to the database. The COMMIT can be
explicit or implicit, including implicit by autocommit ( DBP_AUTOCOMMIT) or by change in isolation level. If
DBP_PRESERVE is on, compiled statements and results sets remain after a COMMIT for that Sql Handle.
If DBP_PRESERVE is off, a ROLLBACK destroys all compiled statements and results sets for all Sql Handles that
the application has connected to the database. The ROLLBACK can be implicit or explicit, including a
ROLLBACK caused by a deadlock. If DBP_PRESERVE is on, compiled statements and results sets remain after a
ROLLBACK if both of the following are true:
• The application is in the Release Locks (RL) isolation level
• A DDL operation was not performed
If you change isolation levels, it causes an implicit COMMIT for all Sql Handles that the application has
connected to the database. In turn, an implicit COMMIT destroys all compiled statements and results sets for
all Sql Handles that the application has connected to the database. However, changing to an isolation level
that is the same as the current isolation level does not cause an implicit COMMIT.
When you are connected to an OLE DB data source, setting autocommit ON forces a rollback of any existing
uncommitted work. For this reason, be certain to do an explicit COMMIT before setting autocommit to ON, or
risk unexpected data loss.
The last SqlDisconnect for a database causes an implicit COMMIT. SqlClearImmediate also causes an implicit
COMMIT if it disconnects the last Sql Handle for a database.

Multi-Connection Transactions
You can have multiple database connections in a single transaction by using the Session Handle data type and
these functions:
• SqlCreateSession
• SqlCreateStatement
• SqlCommitSession
• SqlRollbackSession
332
• SqlFreeSession
• SqlGetSessionParameter
• SqlSetSessionParameter
Using these functions, you create a session and then associate one or more Sql Handles to it. You then
perform normal SQL operations and rollback or commit all work done for all Sql Handles in the session.
Internally, SQLWindows uses sqlcch to create the session.
When connected to SQLBase, or when using an OLE DB connection, a call to SqlCreateSession will create a
new database connection. When connected to other databases, Gupa first checks the combination of
database name, user ID, and password. For each new combination, a new database connection is created.
However, if the combination has already been used in the application, only a new cursor is created, not a new
database connection.
Note: The functions above are part of the OLE DB consumer interface, but they can be used independently
of OLE DB (see Chapter 13 – OLE DB Consumer).
To use multiple connections in a transaction, follow these steps:
1. Set the second parameter of the function SqlCreateSession to null if you are not connecting to the
database through OLE DB:
Set strSessionProperties = ''
2. Set the database name, user name, and password:
Set SqlDatabase = 'ISLAND'
Set SqlUser = 'SYSADM'
Set SqlPassword = 'SYSADM'
3. Create the session:
Set bOK = SqlCreateSession( Session_Handle,
strSessionProperties )
4. Add a Sql Handle to the session:
If bOK = TRUE
Set bOK = SqlCreateStatement( Session_Handle, Sql_Handle )
5. Use the Sql Handle as normal.
6. Commit or rollback work done in the session as needed:
Call SqlCommitSession( Session_Handle )
OR
Call SqlRollbackSession( Session_Handle )
7. Before the application exits, release the session handle:
Call SqlFreeSession( Session_Handle )

Getting and Setting Session Parameters


When you use Session Handles, you get and set session parameters through SqlGetSessionParameter and
SqlSetSessionParameter. Each of these functions has a Number argument that identifies a SQLBase database
parameter. DBP_* parameters on page 336 describes the parameters. The standard include file sqlnwkcn.apl
contains constant definitions for these parameters. You use these constant names to identify parameters.

333
The parameter settings affect all Sql Handles in the session.

Table Windows
Use the following functions to display and change database data in table windows. Chapter 15 – Table
Windows explains the following functions:

Function Description
SalTblDoDeletes Applies a DELETE statement for specified rows.
SalTblDeleteSelected Applies a DELETE statement for all selected rows.
SalTblDoInserts Applies an INSERT statement for all new rows.
SalTblDoUpdates Applies an UPDATE statement for all changed rows.
SalTblFetchRow Sends a SAM_FetchRow message to a table window.
SalTblPopulate Populates a table window with a result set: prepares a SELECT statement, executes it,
and fetches the rows. If the statement is already prepared, only executes the
statement and fetches the rows.

List Boxes and Combo Boxes


Use the SalListPopulate function to populate a list box or the list box part of a combo box with a result set.
SalListPopulate prepares the SQL statement, executes it, and fetches the rows. If the SQL statement is already
prepared, SalListPopulate only executes the statement and fetches the rows.
Here are examples of how you can use SalListPopulate:
• To fill a list box or combo box with the results of a SELECT one time. You provide a SELECT statement and
SalListPopulate compiles, executes, fetches, and fills the list box or combo box.
• If you do not specify an INTO clause, SalListPopulate creates columns automatically.
• To fill a list box or combo box many times using the same SELECT statement, but with different WHERE
criteria. You do not supply a SELECT statement for SalListPopulate, but you do supply a Sql Handle that
has a prepared SELECT already (call SqlPrepare or SqlRetrieve first). SalListPopulate binds (for the new
criteria), executes, fetches, and fills the list box or combo box. This avoids recompiling the SELECT.
These are the steps that SalListPopulate follows if you specify a non-null string in the strSelect parameter:
• SqlPrepare
• Bind (gets the current values of bind variables)
• SqlExecute
• Fills list box or combo box
These are the steps that SalListPopulate follows if you specify a null string in the strSelect parameter:
• Bind (gets the current values of bind variables)
• SqlExecute

334
• Fills list box or combo box
Is it not efficient to call SqlPrepareAndExecute and then call SalListPopulate with a null strSelect parameter.
Instead use SqlPrepare (or SqlRetrieve) because SalListPopulate performs the bind and execute before
fetching.
For more about SalListPopulate, see the SQLWindows Function Reference.

Other Sql* Functions


You can also use these Sql* functions in an application. For more about these functions, see the SQLWindows
Function Reference.

Function Description
SqlDirectoryByName Returns the database names on a given server
SqlExists Checks to find if a specific row exists
SqlExecutionPlan Returns the execution plan for a SQL statement

Database Parameters
This section describes the parameters you can set to control data operations:
• Functions you call to get and set parameters
• DBP_* parameters
• System variables
• Input message buffer
• Output message buffer
• Isolation levels
• SQL.INI

Functions for Database Parameters


Use the following functions to set and get database parameters:

Function Description

SqlGetParameter Gets and sets parameters identified by the DBP_* system constants (see
SqlSetParameter explanation below).
SqlGetParameterAll Gets and sets parameters identified by the SQLP* constants defined in SQL.H (see
SqlSetParameterAll explanation below).
SqlGetSessionParameter Gets and sets session-level parameters identified by constants defined in
SqlSetSessionParameter sqlnwkcn.apl (see Getting and Setting Session Parameters on page 333).

335
SqlSetInMessage Sets the size of the input message buffer for a specified Sql Handle. You can also
set this parameter with the SqlInMessage system variable.
SqlSetIsolationLevel Sets the isolation level. You can also set the isolation level with the
SqlIsolationLevel system variable.
SqlSetLockTimeout Sets the time-out for waiting for a lock.

SqlSetOutMessage Sets the size of the output message buffer for a specified Sql Handle. You can also
set this parameter with the SqlOutMessage system variable.

Getting and Setting Database Parameters


SQLWindows has two sets of functions that you call to get and set database parameters:
• SqlGetParameter and SqlSetParameter
• SqlGetParameterAll and SqlSetParameterAll
The difference between these sets of functions is how you identify parameters:
• When you call SqlGetParameter and SqlSetParameter, identify a parameter with a DBP_* constant (see
below)
• When you call SqlGetParameterAll and SqlSetParameterAll, identify a parameter with a SQLP* constant
value defined in SQL.H, not a DBP_* constant
The SQLP* parameters are a superset of the DBP_* parameters and include parameters not only for SQLBase
but also for other servers. For more information, see the SQLBase API Reference Manual (Chapter 7) or the
documentation for the connectivity product you are using.
Note: When using a connection to database servers other than SQLBase you cannot manipulate parameters
that are specific to those databases with SqlGetParameter or SqlSetParameter. You must use
SqlGetParameterAll and SqlSetParameterAll instead.
A set of the SQLP* constants in SQL.H have the same values as the DBP_* constants, but the values
identify different parameters. Be sure to specify the correct number.

DBP_* Parameters
You can get and set the following parameters with SqlGetParameter and SqlSetParameter:

DBP_AUTOCOMMIT (get or set)


If this parameter is on (TRUE), the database is committed automatically after each SQL statement. Otherwise,
the database is committed only after a COMMIT statement.
Any operation performed on the Sql Handle causes a commit for all Sql Handles that the program has
connected to the database. However, an operation on a Sql Handle where autocommit is not turned on does
not cause an automatic commit.
The default setting is off (FALSE).

DBP_BRAND (get)
This parameter shows the brand of the database:

336
Constant Database
DBV_BRAND_AS400 IBM AS/400
DBV_BRAND_DB2 IBM DB2
DBV_ BRAND_INFORMIX Informix
DBV_BRAND_INFORMIX-ONLINE Informix Online
DBV_BRAND_ORACLE Oracle
DBV_BRAND_ORACLE7 Oracle v. 7
DBV_BRAND_SQL SQLBase
DBV_BRAND_SYBASE SQL Server

DBP_FETCHTHROUGH (get or set)


Use this parameter to avoid retrieving rows from the client's input message buffer that have been updated.
When fetchthrough is off (FALSE), SQLBase fetches rows from the client's input message buffer when
possible.
When fetchthrough is on (TRUE), SQLBase always fetches data from the server, ensuring the most up-to-date
data. Only one row is fetched from the server at a time. There is no multi-row buffering when fetchthrough is
on.
Fetchthrough slows response time. Only use fetchthrough when you need the most up-to-date row.
The default setting is off (FALSE).
This setting applies only to the specified Sql Handle.
If the result set was created with a SELECT statement that contains DISTINCT, GROUP BY, HAVING, UNION,
ORDER BY, an aggregate function, or a complex view, then SQLBase creates a virtual table. In these cases,
rows in the result set cannot be mapped to the rows in the database. If you UPDATE in this situation and later
fetch an UPDATEd row, the row does not reflect the UPDATE even if fetchthrough is on.

DBP_ISOLEVEL (get or set)


Use this parameter to either get or set the isolation level (locking behavior) to be used for the current
database connection. Possible values for the parameter include:
• CSCursor Stability
• RLRelease Locks
• RORead Only
• RRRead Repeatability
See Isolation Levels on page 342.

DBP_LOCKWAITTIMEOUT (get or set)


This parameter is the number of seconds to wait for a database lock to be acquired. After the specified time
has elapsed, the transaction or statement rolls back.

337
Valid time-out values are:

Value Description
1 - 1800 Seconds to wait for a lock (from 1 second to 30 minutes)
-1 Wait forever for a lock held in an incompatible mode by another transaction
(infinite time-out)
0 Never wait for a lock and immediately return a time-out error (nowait locking)

The default setting is 300 seconds.


This setting applies only to the specified Sql Handle.
The time-out remains in effect until you change it with SqlSetLockTimeout, SqlSetParameter, or
SqlSetParameterAll.
This parameter is not meaningful for a single-user database. You can also set this parameter with
SqlSetLockTimeout.

DBP_NOPREBUILD (get or set)


If this parameter is off (FALSE), result sets are prebuilt on the database server. The client must wait until the
entire result set is built before it can fetch the first row.
When this parameter is on (TRUE), the client does not have to wait very long to fetch the first row. The result
set is built as the data is fetched. The server releases shared locks before control returns to the client.
If parameter is on (TRUE), the client must be:
• In result set mode
• In the Release Locks (RL) isolation level
This setting applies only to the specified Sql Handle. The default setting is off (FALSE).

DBP_PRESERVE (get or set)


When this parameter is on (TRUE), SQLBase maintains compiled statements and result sets after a COMMIT. A
COMMIT does not destroy a compiled statement and active result set (cursor-context). This enables an
application to maintain its position after a COMMIT, INSERT, or UPDATE.
The cursor context is not preserved after an isolation level change. The context is preserved after a ROLLBACK
if both of the following are true:
• The application is in the Release Locks (RL) isolation level.
• A DDL operation was not performed.
This setting applies only to the specified Sql Handle.
For fetch operations, locks are kept on pages required to maintain the fetch position. This can block other
applications that are trying to access the same data. Also, locks can prevent other applications from doing
DDL operations.
This feature can be on with or without result set mode.
If the result set was created with a SELECT statement that contains DISTINCT, GROUP BY, HAVING, UNION,
ORDER BY, an aggregate function, or a complex view, then SQLBase creates a virtual table. In these cases,
rows in the result set cannot be mapped to the rows in the database. If you UPDATE in this situation and later
fetch an UPDATEd row, the row does not reflect the UPDATE even if cursor- context preservation is on.

338
The default setting is off (FALSE).

DBP_ROLLBACKONTIMEOUT (get or set)


If this parameter is on (TRUE), the entire transaction is rolled back when there is a lock timeout. If this is off
(FALSE), only the current statement is rolled back when there is a lock timeout.
The default setting is on (TRUE).

DBP_SQLCONFIGFILENAME (get or set)


This contains the location and name of the configuration file (often named SQL.INI) that is being used for
client connectivity.

DBP_VERSION (get)
This is the version number of the connectivity software.

System Variables
The following system variables contain parameters that apply to later connections you make to databases.

SqlDatabase
This system variable sets the database name to use to connect (see Calling SqlConnect on page 314).

SqlINI
This system variable designates which configuration file should be used to obtain client database connection
settings. This variable’s value should not be changed while database connections are open because the next
reference to such connections will return an error. Close all connections before changing it.

SqlInMessage
This system variable contains the size of the input message buffer (see Input Message Buffer on page 340).

SqlIsolationLevel
This system variable contains the isolation level (see Isolation Levels on page 342).

SqlNoRecovery
If this system variable is off (FALSE), transaction logging is performed. Changes that the application makes to a
database before a COMMIT can be rolled back, and the database can recover from a system failure.
If this system variable is on (TRUE), transaction logging is not performed. Changes to the database before a
COMMIT cannot be rolled back if the transaction fails, and the database cannot be recovered if it is damaged
by a user error, media failure, or power failure.
Important: In most situations, you should leave recovery turned on. However, when recovery is off, there is
less file I/O (and a corresponding increase in performance). You can turn off recovery when loading large
amounts of data.
After you set this system variable to TRUE, you can only connect to a database if no other user is connected
to the database. Any other user must set SqlNoRecovery to TRUE before connecting to the database. If other
users try to connect later without setting SqlNoRecovery to TRUE, they get an error.
If you turn off recovery, SQLWindows resets these parameters to their default settings:
339
• DBP_AUTOCOMMIT
• DBP_LOCKWAITTIMEOUT
• DBP_PRESERVE
• DBP_ROLLBACKONTIMEOUT
• Isolation level
• Result set mode
The default setting is off (FALSE).

SqlOutMessage
This system variable contains the size of the output message buffer (see Output Message Buffer on page 341).

SqlPassword
This system variable sets the password to use connect to databases (see Calling SqlConnect on page 314).

SqlResultSet
This system variable turns result set mode on and off for the next connection to a database (see Result set
mode on page 318).

SqlUDL
This system variable can contain the name of a configuration file (UDL file) that contains connection
information for an OLE DB data provider, or it can contain an OLE DB provider name. SQLConnect now looks
first at variable SqlUDL and, if it finds a file name in that variable, reads connection information from that file.
If it finds a provider name in SqlUDL, it uses the provider name. If the database name or user name or
password was not specified, SQLConnect will obtain the needed value from the values of variables
SqlDatabase, SqlUser or SqlPassword. It forms a connection string, then makes an OLE DB connection with
that string. If SqlUDL is null, SqlConnect uses the older (API and routers) method of connecting with the
values of SqlDatabase, SqlUser, and SqlPassword.

SqlUser
This system variable sets the user name to use to connect to databases (see Calling SqlConnect on page 314).

Input Message Buffer


Use the SqlInMessage system variable or the SqlSetInMessage function to set the size (in bytes) of the input
message buffer. The input message buffer refers to input to the application (such as the result of a query).
The input message buffer is allocated on both the client computer and on the database server. The database
server builds an input message in this buffer on the database server computer and sends it to a buffer of the
same size on the client. It is called an input message buffer because it is input from the client's point of view.
There is one input message buffer for each Sql Handle on the client computer. On the server, there is one
input message buffer that is the size of the largest input message buffer on the client computer.

340
You can set a different size for each input message buffer, even if more than one Sql Handle is connected to
the same database.
The input message buffer receives data fetched by the client that the server has sent. While fetching data
from the database, SQLBase compacts as many rows as possible into one input message buffer.
Most query data does not exceed the default input message buffer size, but if it does, you can use this
parameter to increase the size of the input message buffer.
A large input message buffer can improve performance while fetching data from the database because it
reduces the number of network messages. Note that a large input message buffer can affect system
throughput because of concurrency. Any row currently in the input message buffer can have a shared lock on
it (depending on the isolation level) preventing other users from changing that row. Therefore, a large input
message buffer can cause more shared locks to remain than are necessary.
A large input message buffer improves performance when reading LONG VARCHAR columns.
You can also improve overall system performance by decreasing the size of the input message buffer when an
application does not need to fetch data.
SQLBase automatically maintains an input message buffer large enough to hold at least one row of data.
Despite the specified input message size, SQLBase dynamically allocates more space if necessary.
See the explanation of isolation levels in the SQLBase SQL Reference (SET ISOLATION) for more about how
each isolation level uses the input message buffer.
The default setting is 1,024 bytes. The maximum setting is 32,767 bytes.
The actual size of a row of SELECTed data is not the same as the sum of the column lengths. SQLBase converts
row data to a computer-independent format before sending it to the client. Also, there are overhead bytes in
each message.

Output Message Buffer


Use the SqlOutMessage system variable or the SqlSetOutMessage function to set the size (in bytes) of the
output message buffer. Examples of messages that a client sends to a database server are SQL statements to
compile or a row of data to insert.

341
The output message buffer is allocated on both the client computer and on the database server. The client
builds an output message in this buffer and sends it to a buffer of the same size on the database server. It is
called an output message buffer because it is output from the client's point of view.
One input message buffer on the client serves all Sql Handles connected to a given database.
If you are inserting very wide table rows or creating large tables, you can increase the buffer size. Usually the
default is sufficient.
A large output message buffer can help performance when writing LONG VARCHAR columns.
A large output message buffer does not necessarily increase performance because the output message buffer
only needs to be large enough to hold:
• The largest SQL statement to compile
• The largest row of data to insert
A large output message buffer can allocate space unnecessarily on the both the client and the server. Rows
are always inserted and sent one row at a time. A large output message buffer does not reduce network
traffic.
SQLBase automatically maintains an output message buffer large enough to hold any SQL statement or a row
to insert of any length (given available memory). Despite the specified output message buffer size, SQLBase
dynamically allocates more space for the output message buffer if needed.
The default setting is 1,000 bytes. The maximum setting is 32,767 bytes.

Isolation Levels
The SqlSetIsolationLevel function or the SqlIsolationLevel system variable sets the isolation level for the
application when accessing a multi-user SQLBase database server.
The isolation level controls the effect that changes made by one user have on another user accessing the
same tables. SQLBase has these isolation levels:
• Read Repeatability (RR) (default)
• Cursor Stability (CS)
• Read Only (RO)
• Release Locks (RL)
For OLE DB connections, RL and RO map to READ COMMITTED.
Choose an isolation level based on the application's requirements for consistency and concurrency.
The isolation level you set applies to all the Sql Handles for that user name that the application connects to
the database.
If you change isolation levels, it causes an implicit COMMIT for all Sql Handles that the application has
connected to the database. In turn, an implicit COMMIT destroys all compiled statements and results sets for
all Sql Handles that the application has connected to the database. However, changing to an isolation level
that is the same as the current isolation level does not cause an implicit COMMIT.
For more information, read the explanation of isolation levels in the SQLBase SQL Reference (SET ISOLATION).

342
SQL.INI
SQLWindows reads the configuration file (default name SQL.INI) to determine the database servers that the
application can access. The diagram below shows how SQLWindows and other Team Developer clients search
for the configuration file:

For more about SQL.INI, see the SQLBase Database Administrator's Guide.
Note: The configuration file used by SQLWindows at design time can be specified in the Preferences dialog.
This file might differ from the one used at runtime, as described above.

Techniques for Multiuser Databases


This section suggests settings and techniques for applications that access multiuser SQLBase databases. These
settings and techniques maximize data concurrency and performance:

343
• Use the Release Locks (RL) isolation level.
Release Locks releases all shared locks (for maximum concurrency) and minimizes network traffic (by
filling the input message with as many rows as it will hold). Release Locks does not ensure a consistent
view of data (another application can change a row after an application has read the row), but you can
use ROWID validation (see below) to detect if another application has changed a row.
• Use ROWID validation with unique keys for UPDATEs and DELETEs.
If the row has changed, turn on DBP_FETCHTHROUGH (which tells SQLWindows to fetch data from the
database, not from the input message buffer), refetch the row, and then turn off DBP_FETCHTHROUGH
(see Example on page 345).
• Do not change DBP_NOPREBUILD from its default setting (off).
Prebuilding result sets on the server increases the time it takes to fetch the first row, but it releases
shared locks as soon as possible. Result set mode must be on (default setting).

ROWID Validation
Each row in a SQLBase database has a hidden column called ROWID (row identifier) that uniquely identifies
the row. A ROWID changes when the row is updated.
With ROWID validation, an application can ensure that another application did not UPDATE or DELETE a
SELECTed row while the user was browsing the data. If another application updates a row after your
application reads it, you can detect it by the changed ROWID.
The following flowchart shows the steps in ROWID validation:
1. If an UPDATE or DELETE is not successful, check the SQL error code to find if it is a ROWID error.
2. If it is a ROWID error, perform the “changed-row processing”, which depends on the nature of the
application.
The example after the flowchart shows one type of changed-row processing.

344
Example
In the following example, if the SQL error is an invalid ROWID, the When SqlError statements do the
following:
¿ Turn on DBP_FETCHTHROUGH to tell SQLWindows to fetch from the database server and not the
input message buffer
¡ Compile and execute a SELECT statement
¬ Fetch the row
Ð Turn off DBP_FETCHTHROUGH

345
Global Declarations
...
Constants
...
User
Number: DB_ERR_Row_ID = 806
...
Menu Item: Update
...
Menu Actions
When SqlError
Call SalNumberToStr( nErr, 0, strNum )
Call SqlExtractArgs( wParam, lParam, hSqlError, nErr, nPos )
Call SqlGetErrorText( nErr, strErrmsg )
!
If nErr = DB_ERR_Row_ID
!
! An invalid row ID can happen if a second user UPDATEs
! a row after the first user retrieves it or the user
! UPDATEs a row once and then UPDATEs it
! again without refetching it
!
Call SalMessageBox('You or another user have updated this row.
Click OK to retrieve the row again.
You will need to enter your changes again.',
'Update Error',
MB_Ok | MB_IconExclamation )
¿ Call SqlSetParameter( hSqlFetch2, DBP_FETCHTHROUGH, TRUE,
strNull )
¡ Call SqlPrepareAndExecute( hSqlFetch2, strSelectByName )
¬ Set bOk = SqlFetchNext( hSqlFetch2, nFetch )
Ð Call SqlSetParameter( hSqlFetch2, DBP_FETCHTHROUGH, FALSE,
strNull )
!
Return FALSE
!
Set bOk = SqlPrepare( hSqlChange, strUpdate )
Set bOk = SqlExecute( hSqlChange )
If bOk
Call SqlCommit( hSqlChange )

Stored Commands
Call the following functions to use SQLBase stored commands:

Function Description
SqlStore Compiles and stores a statement
SqlRetrieve Retrieves a stored statement
SqlDropStoredCmd Removes a stored statement

You can store compiled SQL statements in a database (in the SYSCOMMANDS system catalog table) with the
SqlStore function and retrieve them with the SqlRetrieve function.
You do not call SqlPrepare before you call SqlStore. SqlStore compiles the SQL statement before storing it.

346
When you store a statement with SqlStore, you:
• Do not specify an INTO clause
• Specify bind variables with numeric names instead of actual variable names When you retrieve a stored
statement with SqlRetrieve, you specify:
• An INTO clause to use when executing it
• A list of variable names to use as bind variables
For example, if you store this SQL statement:
SELECT * FROM PRESIDENT
WHERE LASTNAME = :1 AND AGE > :2
When you retrieve the statement, you supply the bind variables that replace “:1” and “:2”, such as
“:dfLastName” and “:dfAge”.
After you retrieve a statement with SqlRetrieve, execute it with SqlExecute. Once you retrieve a statement, a
COMMIT or ROLLBACK does not destroy it.
If you are not the creator of the stored statement, you must qualify the statement name with the creator
name and a period. For example, if SYSADM created the statement:
SYSADM.statement-name
When you store a statement, SQLBase creates an optimized execution plan based on the data in the database
at that time. If the data later changes (for example, if the distribution of values in index columns changes),
then the execution plan is no longer optimal. For production applications where data changes often, drop
stored statements and restore them on a scheduled basis to keep the execution plans up-to- date.
If you change the structure of a table that a stored command uses, you get an error when you try to retrieve
the stored command. These are examples of actions that change the structure of a table:
• ALTERing columns
• Adding or removing columns
• Dropping tables
• Dropping indexes

Chained Commands
You can retrieve several stored commands with one call to SqlRetrieve and execute them with one
SqlExecute. To do this, specify a list of stored command names separated by commas when you call
SqlRetrieve.
When using UPDATE in a chained command, you can specify the CHECK EXISTS clause to return an error if at
least one row is not updated.
You can use a SELECT statement in a chained command with the following restrictions:
• Only one SELECT statement can be in a chained command
• The SELECT statement must be the last statement in the chain
Statements with a CURRENT OF clause cannot be part of a chained command.

347
Using Stored Commands with SalListPopulate and SalTblPopulate
If you call SqlPrepare or SqlRetrieve for a stored command before you call SalListPopulate or SalTblPopulate,
set the strSelect parameter for SalListPopulate or SalTblPopulate to null ('') to use the compiled command. If
the strSelect parameter is null, these functions look for a previously-prepared command on the Sql Handle.
Also, if you call SqlRetrieve before SalListPopulate, set the strIntoList parameter for SqlRetrieve to null ('').
The following example shows how to call SalTblPopulate for a stored command:
Call SqlStore( hSql, 'mystoredfunction', 'SELECT build FROM guests')
...
Call SqlRetrieve( hSql, 'mystoredfunction, 'build', ':tbl1.col1')
...
Call SalTblPopulate( tbl1, hSql, '', TBL_FillNormal)
The following example shows how to call SalListPopulate for a stored command:
Call SqlStore( hSql, 'mystoredfunction', 'SELECT build FROM guests')
...
Call SqlRetrieve( hSql, 'mystoredfunction, 'build', '')
...
Call SalListPopulate( tbl1, hSql, '')

Setting the Execution Context


The execution context determines the meaning of bind variable names and into variable names. SQLWindows
compiles:
• Bind variables at execute time
• Into variables at fetch time

SqlVarSetup
Call SqlVarSetup to change the default behavior:
bOk = SqlVarSetup( hSql )
SqlVarSetup saves the current execution context. When you execute or fetch later, SQLWindows uses that
execution context to resolve references to bind variables and into variables.
Use this function to write:
• Global functions that store bind and into variables in local variables
• A hierarchy of classes where a base class can prepare and fetch and a derived class can specify the into
variables
For new applications, call SqlVarSetup instead of these functions:
• SqlContextSet
• SqlContextClear
• SqlContextSet
• SqlContextSetToForm
• SqlImmediateContext

348
Sql* context functions
This function sets the execution context for future processing (for example, calls to SqlPrepare, SqlFetchNext,
SqlFetchPrevious, and SqlFetchRow):
bOk = SqlContextSet ( hSql )
Sql* functions you call after SqlContextSet behave as if they are in the window identified by hWndForm. Call
SqlContextSet in a class to perform SQL processing for the current window without fully qualifying bind and
into variables. This function is also useful for internal functions.
This function is like SqlContextSet, but you explicitly set the context to a specified window:
bOk = SqlContextSetToForm ( hSql, hWndMyForm)
This function clears the context set by SqlContextSet or SqlContextSetToForm:
bOk = SqlContextClear ( hSql )
After you call SqlContextClear, SQLWindows evaluates the bind and into variables associated with the
specified Sql Handle in the local context.
This function prepares and executes a SQL statement, and evaluates any bind or into variables in the context
of the window identified by SqlContextSet or SqlContextSetToForm:
bOk = SqlImmediateContext( strSqlStatement )
Call this function to perform SQL processing for the current window without fully qualifying bind and into
variables.
If you call functions in the following order, you might get a runtime error (such as “<identifier> is defined by
more than one form, dialog, or table window. Must qualify the reference.”) when you call SqlExecute because
SQLWindows compiles bind variables at execute time:
1. SqlContextSet
2. SqlPrepare
3. SqlContextClear
4. SqlExecute
The example above clears the context before the execute. To change the code so that it runs without errors,
call SqlContextClear after the execute (or after the first fetch).

Character Conversion
PCs use two different character sets:
• DOS command line applications (character mode) use an OEM character set.
• Windows applications use the ANSI character set.
The first 128 characters are the same in both character sets, but the characters above 128 are different.
If you enter data in one character set and then read it with the other character set, the data does not display
properly. For example, if you enter data with SQLTalk/ Character and then display the same data with
SQLTalk/Windows, the characters above 128 are different.

349
To avoid this problem, always maintain data in one environment. If you need to maintain data in both the
Windows and DOS command-line environments, you can call functions in the Windows DLL KEYBOARD.DRV
that convert between the character sets. The functions are called AnsiToOem and OemToAnsi.

Named Cursors
Function Description
SqlOpen Names a cursor and executes a SQL statement
SqlClose Frees a named cursor

The cursor name you specify in SqlOpen can also be used in the:
• WHERE CURRENT OF clause for an UPDATE or DELETE statement
• ADJUSTING clause of an INSERT statement
Named cursors lock pages in the database. Instead, use the Release Locks isolation level, ROWID validation,
and DBP_FETCHTHROUGH to maximize performance and concurrency (see ROWID Validation on page 344).
You cannot use named cursors with chained commands.

Database Explorer
The Database menu contains items that let you browse database objects and prototype SQL statements (see
Database Explorer on page 101).

SQL Troubleshooting
Question: I get “Cannot open the database” message (401) on a SqlConnect.
Answer: There are two common causes:
• The database (*.DBS) files are incompatible with the version of SQLWindows.
• The section called [DBWINDOW] contains the DBDIR keyword that tells DBWINDOW.EXE where to look for
the database files. If the database files are not in the directory that DBDIR points to, you get the error
message.
Question: I call SqlPrepare and SqlExecute, but data fields are not being populated.
Answer: SqlPrepare compiles the SELECT statement and SqlExecute executes the query, but does not populate
the data fields. To populate the data fields, you must call SqlFetchRow or SqlFetchNext.
SalTblPopulate and SalListPopulate perform all three functions. SqlPrepareAndExecute combines the
SqlPrepare and SqlExecute in one function.
Question: I use one Sql Handle in an application to call SqlPrepare, SqlExecute, and SqlFetchNext to build a
result set and fetch data into data fields. Using the same Sql Handle, I call SqlPrepare and SqlExecute after this

350
to INSERT data. When I then try to fetch another row from the result set, I get a “Not a SELECT command”
message (202).
Answer: A single Sql Handle is associated with only one compiled statement at a time.
Calling SqlPrepare and SqlExecute again on the same handle destroys the previous result set. To perform the
INSERT without destroying the result set, you need to use two separate Sql Handles, one for each compiled
statement.
Question: I have two Sql Handles in an application. I call SqlPrepare, SqlExecute, and SqlFetchNext for the first
Sql Handle. Then I call SqlCommit for the second Sql Handle. Finally, I perform another SqlFetchNext for the
first Sql Handle and I get a “No compiled command” message (201).
Answer: A COMMIT, ROLLBACK, or change in isolation level destroys the compiled statements associated with
Sql Handles connected to the same database. COM- MITting on the second Sql Handle destroys the result set
built by the first Sql Handle because both Sql Handles are connected to the same database. To preserve the
result set so that it is not destroyed by COMMITs, ROLLBACKs, or changes in isolation level, call
SqlSetParameter on the Sql Handle for the result set and set DBP_PRESERVE to TRUE. This turns on cursor-
context preservation and preserves the result set.
Question: I have a table window with data in it. I change information in one row and then call
SalTblDoUpdates to make the changes in the database. Later, when I try to update the same row again, I get
an “Invalid ROWID” message (806).
Answer: The problem is that the ROWID has changed. SQLBase automatically defines ROWIDs. SQLBase uses
ROWIDs to identify a particular version of a row in a database table. Each time you change a row, its ROWID
changes.
The example builds a result set that contains ROWIDs that match the ROW- IDs in the database. However,
once you UPDATE, the ROWID in the database changes. At this point, the ROWID in the result set and the
ROWID in the data- base are different. If you try to refer to that row again using the result set ROWID,
SQLBase is not be able to find that row in the database.
Handle this problem by calling SqlSetParameter to turn on DBP_FETCHTHROUGH. Then, call SqlFetchRow
immediately after each UPDATE. The row, along with its new ROWID, is fetched from the database into the
result set. Later, when you UPDATE that row again, the ROWID in the result set and the ROWID in the database
match, and SQLBase is able to find the row.
For best performance, turn on DBP_FETCHTHROUGH immediately after the UPDATE, perform the fetch, and
then turn off DBP_FETCHTHROUGH after the fetch. Otherwise, you always fetch rows from the database
instead of from the input message buffer, which degrades performance.

351
Chapter 13 – OLE DB Consumer
This chapter discusses how to access relational and non-relational data sources from SQLWindows. It
describes:
• When to use the OLE DB consumer
• Session Handle data type
• How to access OLE DB data sources
• Sql* functions
• OLE DB stored procedures
• SAL/OLE DB mapping

SQLWindows as a Consumer
SQLWindows is an OLE DB consumer that can work with any OLE DB provider to access both relational
databases using existing SQL language statements and access functionality.
The OLE DB architecture is:

An OLE DB provider responds to queries and returns data in a usable form; an OLE DB consumer accesses a
data source.
To learn more about OLE DB, read Microsoft OLE DB 2.0 Programming Reference and Data Access SDK.

352
Session Handle Data Type
In a non-OLE DB connection, SQLWindows uses the Sql Handle data type to access a database. Internally, a
new session is established only once for every unique combination of database name, user ID, and password.
With OLE DB, there are two separate data types for accessing databases: one to identify a connection and
another to identify a statement (cursor). The Session Handle data type is provided to support multiple
transactions and to identify a transaction as a separate identity so there is a one-to-one association with a
session and a transaction. You also use a Sql Handle to identify individual statements.
You call SqlCreateSession and SqlFreeSession to create a session and free a session. These functions let you
create multiple concurrent transactions in a straightforward manner. To execute SQL statements as part of a
transaction call SqlCreateStatement to create cursor (statement) handles.

Connecting to a Data Source


You do all of the work to support OLE DB providers from your application through SAL functions. You use SAL
functions to create a session, define properties, perform database transactions, and close the session. For
descriptions of these functions, see Sql* Functions on page 354.
A typical consumer session goes like this:
1. Identify the OLE DB provider you want to connect to:
Set strSessionProperties = "Provider=SQLOLEDB;"
Determine the progID or provider name for the provider. Each provider you own has a provider name. For
example, the provider name for the Microsoft SQL Server OLE DB provider is SQLOLEDB (see Sql*
Functions on page 354).
To set optional session properties at the creation of a session itself, add the keyword and its value after
the provider name keyword/ value pair in the strSessionProperties variable. For example, to set the initial
catalog (database) for Microsoft SQL Server, set it as follows:
Set strSessionProperties = "Provider=SQLOLEDB;"
Set strSessionProperties = strSessionProperties || "Initial Catalog=pubs;"
2. Set the server name, user ID, and password for the session:
Set SqlDatabase = 'SQL70' Set SqlUser = 'sa'
Set SqlPassword = 'sa'
For example, for Microsoft SQL Server 7.x, the server name can be SQL70, the user ID can be sa, and the
password can be sa. (For SQLBase, the server name can be ISLAND, user ID can be SYSADM, and the
password can be SYSADM.)
3. Create a session using SqlCreateSession to acquire an individual Session Handle:
Set bOk = SqlCreateSession ( Session_Handle, strSessionProperties)
To support multiple connections or transactions, you identify a transaction as a separate identity. You use
the Session Handle to create a one-to-one association between a session and a transaction.
4. Call SqlCreateStatement to acquire a Sql Handle:
Set bOk = SqlCreateStatement ( Session_Handle, Sql_Handle )
You can use this Sql Handle (cursor) with most SAL functions that take a Sql Handle as a parameter.

353
You can also use SqlCreateSession and SqlCreateStatement to connect to SQLBase for multi-connection
transactions without the access going through OLE DB (see Multi-Connection Transactions on page 332).
5. Perform tasks using SAL functions.
6. Free the session and release the Session Handle using SqlFreeSession.
You can enable client-side cursors using CLIENTCURSOR=TRUE parameter in an OLEDB connection string.
To enable client cursor, add switch ";CLIENTCURSOR=TRUE" (no spaces at =) to the connection string. For
example, after setting up the SqlUDL variable, add the following line:
Set SqlUDL= sSqlUDL || ";CLIENTCURSOR=TRUE"

Sql* Functions
The following Sql* functions, listed in alphabetical order, support SQLWindows as a consumer. Refer to the
SQLWindows Function Reference or the online help for details.

SqlCloseAllSPResultSets (hSql)
This function closes any result sets generated by the execution of a stored procedure. This function is useful
when you want to retrieve the return status of the stored procedure without having to go through all the
result sets and close them individually.

SqlCommitSession (hSession)
This function commits the current transaction associated with the specified session. The SQL operations
currently active on all the statements belonging to this session commit.

SqlCreateSession (hSession, strSessionProperties)


This function creates a new session. This function takes a string that specifies all the properties for this
session. It takes the database name, user ID and password values from the SAL global variables SqlDatabase,
SqlUser, and SqlPassword, respectively.

SqlCreateStatement (hSession, hSql)


This function creates a new statement belonging to the specified session. The Sql Handle specified here is the
same as that used with SqlConnect. There can be any number of statements within a session. To free a
statement, the call SqlDisconnect.

SqlFreeSession (hSession)
This function frees the session. If there are any open statements belonging to this session, they are closed
before the session is freed.

354
SqlGetCmdOrRowsetPtr (hSql, bCmdOrRowset, numOLEDBPtr)
This function gives the caller either the ICommand or the IRowset interface pointer of the command or the
OLE DB rowset object. You can then pass this interface pointer to an external DLL (for example, to access
other interfaces/methods that SAL does not expose).

SqlGetDSOrSessionPtr (hSql, bDSOrSession, numOLEDBPtr)


This function gives the caller the IDBInitialize interface pointer of the data source OLE DB object or the
IDBCreateSession interface pointer of the OLE DB session object. You can then pass this interface pointer to
an external DLL and use it (for example, to access other interfaces/methods that SAL does not expose).

SqlGetNextSPResultSet (hSql, strIntoList, bEndOfRS)


If the stored procedure invoked by calling SqlPrepareSP (and later executed by calling SqlExecute or
SalTblPopulate) returns more than one result set, call this function to get the second and subsequent result
sets.
Once all the rows in a given result set have been retrieved, get the next result set (if any) by calling
SqlGetSPNextResultSet again.

SqlGetSessionErrorInfo (hSession, numErrorNumber, strErrorDescription,


strSqlState)
This function returns the error information associated with the specified session. Use this function if one of
the other functions that take a Session Handle as a parameter returns FALSE.

SqlGetSessionHandle (hSql, hSession)


This function returns the session handle to which the specified statement handle belongs. The Sql Handle
must have been created by SqlCreateStatement, not SqlConnect.

SqlGetSessionParameter (hSession, numPropertyID, numValue, strValue)


This function gets the value of the specified session parameter. This function knows the data type of the
property ID and accordingly returns either the number value or the string value. Refer to OLE DB Initialization
Properties in the online help for a list of property IDs.

SqlGetStatementErrorInfo (hSql, numErrorNumber, strErrorDescription,


strSqlState)
This function returns the error information associated with the specified statement handle
(command/cursor).
This function works with Sql Handles created either with SqlCreateStatement or SqlConnect. In the case of Sql
Handles created with SqlConnect, strSqlState is always null.

355
SqlPrepareSP (hSql, strStoredProc, strIntoList)
This function prepares a stored procedure. This function handles any input parameters passed to it by the
caller. The function also handles output parameters, but the output parameters are not updated after a
successful execution. The values of the SAL variables specified for any output parameters are updated only
after any result set generated by the stored procedure has been completely processed.
Once the stored procedure has been prepared, it can be executed either by calling SqlExecute on the same
Sql Handle or by calling SalTblPopulate.

SqlRollbackSession (hSession)
This function rolls back the current transaction associated with the specified session. The SQL operations
currently active on all the statements belonging to this session roll back.

SqlSetSessionParameter (hSession, numPropertyID, numValue, strValue)


This function sets the value of the specified session parameter. This function takes the session handle and the
property ID. This function knows the data type of the property ID and accordingly uses either the number
value or the string value. Refer to OLE DB Initialization Properties in the online help for a list of property IDs.

OLE DB Stored Procedures


Stored procedures are handled by the various relational databases in different ways. For example, the
different databases handle the input and output parameters differently. The result sets generated by stored
procedures vary significantly.
There are three SAL functions (described previously) you can use with stored procedures regardless of the
underlying relational database:
• SqlPrepareSP
• SqlGetNextSPResultSet
• SqlCloseAllSPResultSets
The following are supported:
• Input parameters. All SAL data types are supported as input parameters to a stored procedure.
• Output parameters are support for the Oracle OLE DB provider, except for array parameters. Output
parameters for Miscrosoft SQL Server OLE DB provider are not supported.
• Return values
• Multiple result sets
Note: If you are using an OLE DB connection to SQL Server, and you are executing a stored procedure that
returns a result set, do not set SqlResultSet to TRUE. SQL Server does not support scrollable result
sets for stored procedures.
If you are calling a SQL Server procedure that does not have any input or output parameters, make
sure to omit the parentheses after the procedure name. Do not use a set of empty parentheses.

356
SAL Mapping to OLE DB Functions
This table lists SAL functions not supported for OLE DB connections. If you use any of the SAL functions in the
first column, you get an error. Either do not use the function or use the function listed in the second column.

SAL Functions Supported or Deprecated


SqlClearImmediate Not supported for OLE DB connections
SqlCommit Use SqlCommitSession
SqlConnect Use SqlCreateSession and SqlCreateStatement
SqlConnectUsingCursor Use SqlGetCmdOrRowsetPtr or SqlGetDSOrSessionPtr
SqlDisconnectWithoutCursor Use SqlGetCmdOrRowsetPtr or SqlGetDSOrSessionPtr
SqlDropStoredCmd Not supported for OLE DB connections
SqlExists Not supported for OLE DB connections
SqlGetCursor Use SqlGetCmdOrRowsetPtr or SqlGetDSOrSessionPtr
SqlGetError Use SqlGetSessionErrorInfo
SqlGetErrorText Use SqlGetSessionErrorInfo
SqlGetErrorTextX Use SqlGetSessionErrorInfo
SqlImmediate Not supported for OLE DB connections
SqlImmediateContext Not supported for OLE DB connections
SqlPLSQLCommand Not supported for OLE DB connections
SqlSetIsolationLevel Use SqlSetSessionParameter
SqlStore Not supported for OLE DB connections
Syb* functions Not supported for OLE DB connections; use native router connectivity

Using SAL Datatypes with OLE DB Databases


String and Long String vs. OLE DB DateTime datatype
When using a SAL String as an input bind variable to read a DateTime value from an OLE DB database, be sure
that the OLE DB value retrieved is formatted in a date format likeYYYY-MM-DD HH:MM:SS without including
milliseconds in the format.
Reading an OLE DB DateTime value into a SAL Long String bind variable is not supported.
Both String and Long String datatypes can be used for bind variables that will write to DateTime columns in
OLE DB databases. Note that most SAL date functions include milliseconds when manipulating dates as
strings. The millisecond portion should be removed before writing to an OLE DB database.

String and Long String vs. OLE DB stored procedures


The String and Long String datatypes have varying levels of support when used as bind variables in stored
procedures and matched to char/varchar datatypes in OLE DB databases.

357
SQL Statement and SAL On SQL Server On Oracle with Oracle On Oracle with
Datatype Provider Microsoft Provider
INSERT string Supported Supported Supported
UPDATE string Supported Supported Supported
SELECTstring Supported Supported Supported
INSERT long string Supported Supported Not supported
UPDATE long string Supported Supported Not supported
SELECT long string Not supported Not supported Not supported

Using Isolation Levels with OLE DB


There are two general ways to set database isolation levels:
• Call function SqlSetIsolationLevel()
• Change the value of system variable SqlIsolationLevel
In both of these cases you are limited to the four levels supported in general (RL, RO, RR, and CS). Note that
the GUPTA SQLBase OLE DB Data Provider interprets these levels as follows:

Level Requested SQLBase Implements


RL CS
RO CS
RR RR
CS RR

Using REF CURSOR with Oracle


Oracle’s REF CURSOR can be used with SQLWindows. You must use Oracle’s OLE DB provider, not Microsoft’s
OLE DB provider for Oracle.
To have all your database connections be enabled for REF CURSOR, use the following phrase in the OLE DB
connection string:
PLSQLRSet =1
To enable REF CURSOR for a specific connection, do not use that phrase in the OLE DB connection string.
Instead, make the connection, then do a function call similar to this one:
Call SqlSetStatementProperty ( hSql, ORAPROP_PLSQLRSet, TRUE, STRING_Null)

358
Chapter 14 – Report Programming

This chapter explains how a SQLWindows application can print and display reports based on report templates
created with Report Builder, including:
• SalReport* functions
• SAM_Report* messages
• RPT_* constants
This chapter assumes that you know how to:
• Create report templates with Report Builder (see the Business Reporting manual)
• How to connect to a database and fetch data (see Chapter 12 – SQL Programming)
• Create and populate table windows (see Chapter 15 – Table Windows)

Report Builder
Report Builder lets you design, display, and print reports using data that a SQLWindows application supplies.
You can use Report Builder for:
• Tabular reports
• Multi-level control break reports
• Mailing labels
• Cross-tab reports
Report Builder has two environments:
• At design time, you create a report layout.
• At runtime, a SQLWindows application passes data for the report to Report Builder. The application can
print or display the report. An application can also create a report template at runtime.
The following diagram shows the design time and runtime environments of Report Builder:

359
The term Report Builder means the collection of files that make up the design time and runtime
environments.

Design Time
At design time, you use Report Builder to define the format of a report. You do not associate a report
template with a specific data source. A SQLWindows application that you write (using the functions and
messages explained in this chapter) supplies the data.
The sections below explain the Report Builder concepts that are relevant for a SQLWindows application. Read
Business Reporting for how to create a report template with Report Builder.

Report Template
A report template describes the layout and format of a report. The report template shows how the data
appears in the parts of a report.

Blocks
A report is divided into blocks. A block is a group of related lines on a report. These are the types of blocks:
• A report header at the beginning (such as the title of a report or summary information).
• A page header at the top of each page.
• Detail block that is the body of a report.
• Header and footer blocks for each break group you define. A break group separates detail blocks into
logical groups such as regions or departments. A break group controls when subtotals are printed.
• A page footer at the bottom of each page.

360
• A report footer at the end (such as grand totals).

Input Items
A SQLWindows application supplies values for the report fields associated with input items. An application
passes a set of values for the input items each time it receives a SAM_ReportFetchNext message.
At design time, you specify input items with the Input menu:

Input Variables
Input variables are like input items, but you have more control over when you can set them. These are the
types of input variables:
• String
• Number
• Date/Time
• Object
At design time, you specify input variables through the Format menu.

Runtime
At runtime, Report Builder requests and receives data from a SQLWindows application, formats it, performs
calculations, and displays or prints the report.
A SQLWindows application communicates with Report Builder by calling SalReport* functions; Report Builder
communicates with SQLWindows applications through SAM_Report* messages. The SQLWindows application
is called the server because it supplies data; Report Builder is the client because it requests data.
At runtime, a SQLWindows application can:
• Print or display a report using an existing report template
• Create a new report template
• Create a new report template based on a table window
• Print or display a report using table window data

361
Sections in this chapter show examples for each of these.
The report template and the SQLWindows application are independent of each other. The SQLWindows
application calls a SalReport* function that specifies the name of the report template. Then, Report Builder
sends messages to the SQLWindows application to ask for data. The data that the application sends must
correspond to the input items defined in the report template.
The following diagram shows the basic steps you follow to display or print a report:

The steps are as follows:


Q) Call SalReportView or SalReportPrint.
C9 Process the SAM_ReportStart message by performing initialization needed before sending
report data to Report Builder:
 If the data source is a database, you can call SqlConnect and then call SqlPrepare for a
SELECT statement
 If the data source is a file, you can open the file
Report Builder ignores a value you Return in SAM_ReportStart processing.
C) Process SAM_ReportFetchInit. Report Builder sends SAM_ReportFetchInit when it is ready to
format the first page of a report. To process SAM_ReportFetchInit, the application can initialize
variables and do what- ever is needed to get the start of the report data. For example:
 For a database, you can call SqlExecute or SqlPrepareAndExecute
 For a file, you can set the file pointer to the start of the file
If you Return FALSE, the report stops. If you do not Return a value, or you do not process the
message, the report continues.
C9 Process SAM_ReportFetchNext messages. Report Builder sends SAM_ReportFetchNext when it
is ready for the next set of data. The appli- cation processes SAM_ReportFetchNext by setting
variables and objects that the report needs. For example:
 For a database, you can call SqlFetchNext

362
 For a file, you can set the file pointer to the position of the next record
Return TRUE in the SAM_ReportFetchNext processing if the application successfully fetched or
read data. When you return TRUE, SQLWindows sends the report data to Report Builder. Return
FALSE when the application has sent the last set of data for the report.
� Process SAM_ReportFinish by performing cleanup operations:
 For a database, you can call SqlDisconnect
 For a file, you can close the file
Report Builder ignores any value you Return in SAM_ReportFinish processing.

SalReportPrint
Call SalReportPrint to print a report using an existing report template:
Call SalReportPrint( frmServer, strReportTemplate, strVariables, strInputs,
nCopies, nOptions, nFirstPage, nLastPage, nError )
The frmServer parameter is the name or handle of a window that processes SAM_Report* messages. This is
not the same window that SalReportPrint returns.
SalReportPrint is synchronous and does not return until the report has been formatted and sent to Windows
or Windows print manager for printing. When printing a report, Report Builder creates a hidden window that
it uses to communicate with SQLWindows. For all SAM_Report* messages, the wParam contains the handle
of this window.
When this function executes, SQLWindows sends the application SAM_Report* messages.
The strReportTemplate parameter is the name of the report template created with Report Builder.
The strVariables parameter is a list of variables in the application that contain data to use for the report at
each SAM_ReportFetchNext.
The strInputs parameter is a list of the input items that are defined in the report template. The order of the
input items must match the order of the variable names in strVariables. This parameter is optional and is
provided so that an application can use:
• A order different than specified for the input items in the report template
• Variable names that are different than the input items in the report template
The nCopies parameter is the number of copies of the report to print. You must set nCopies greater than zero.
You can set the nOptions parameter to the values in the table below:

Constant Description
RPT_PrintAll (default) Print all pages of the report
RPT_PrintDraft Print the report in draft quality (fastest)
RPT_PrintNoAbort Do not display the dialog that lets the user cancel the report
RPT_PrintNoErrors Suppress error message dialogs during printing
RPT_PrintNoWarn Suppress warnings about margin overflow and tiled pages
RPT_PrintRange Print a range of pages in the report

363
You can combine RPT_PrintDraft with RPT_PrintRange using the OR (|) operator. If you specify
RPT_PrintRange, you specify the page numbers in the range in nFirstPage, and nLastPage.
If successful, SalReportPrint returns 0 in nError. If not successful, SalReportPrint returns an RPT_Err* constant
in nError. The table on the next page lists the RPT_Err* constants.
The value that SalReportPrint returns is reserved for future use and can be ignored.

Error Handling
In run mode at design time, SQLWindows always displays a dialog with an explanation if an error happens:

This dialog is useful while you are developing an application. However, for *.EXE applications, SQLWindows
only displays an error dialog if you set the nError parameter to one before calling SalReportPrint.

RPT_Err* Constants
The SalReport* functions return these RPT_Err* constants:

Constant Description
RPT_ErrBind A bind error happened
RPT_ErrCount Too many bind/input variables
RPT_ErrFilenameLength The report file name is too long
RPT_ErrFileOpen Cannot open the report template
RPT_ErrInput Mismatch between an input variable and a bind variable
RPT_ErrLoadDLL Cannot load the required DLLs
RPT_ErrMaxRpts Exceeded the maximum number of reports
RPT_ErrPrtOpen Cannot open the printer
RPT_ErrRptOpen Cannot open the report
RPT_ErrRptWindow Cannot open the report window
RPT_ErrType Input variable data type does not match bind variable data type

SalReportDlgOptions
By default, SalReportPrint displays this dialog while printing:

364
You can change the messages in this dialog by calling SalReportDlgOptions:
bOk = SalReportDlgOptions( hWndReport, strCaption, strLine1,
strLine2, strDocName )
Call SalReportDlgOptions after SalReportPrint, but before printing begins, such as when processing the
SAM_ReportFetchInit or SAM_ReportStart message. To get the window handle while processing these
messages, use the wParam of the SAM_ReportStart or SAM_ReportFetchInit message (you need to convert
the wParam to a window handle with SalNumberToWindowHandle). Do not use the hWndReport value that
SalReportPrint returns because it may not yet be valid.

Example
The strCaption, strLine1, and strLine2 parameters are strings that SQLWindows displays in the dialog. The
strDocName parameter is the string that Windows print manager displays.
This example shows a menu item that calls SalReportPrint:
Q) Set nOptions to RPT_PrintAll to print all pages in the report.
Set nCopies to 1 to print 1 copy of the report.
C9 Call SalReportPrint.
C) The SAM_ReportStart processing:
Calls SalReportDlgOptions to create a custom dialog that is displayed while printing.
Connects to a database.
¢l: The SAM_ReportFetchInit processing calls SqlPrepare and SqlExecute for the SELECT statement.
� The SAM_ReportFetchNext processing calls SqlFetchNext. After the last row is fetched, the
message processing returns FALSE to tell Report Builder that there is no more data for the
report.
<: The SAM_ReportFinish processing disconnects from the database.

365
Global Declarations
...
Constants
...
String: RPT_Template = 'salesumm.qrp'
String: RPT_Variables = ':strSalesAgent, :dtSaleDate, :strCustFirst,
:strCustLast, :nStyleID, :nStylePrice'
String: RPT_Inputs = 'SALES_AGENT, SALE_DATE, CUST_FIRST_NAME,
CUST_LAST_NAME, STYLE_ID, STYLE_PRICE'
String: SQL_Select = 'select sd.sales_agent, sd.sale_date, c.first_name,
c.last_name, sd.style_id, s.style_price
into :strSalesAgent, :dtSaleDate, :strCustFirst,
:strCustLast, :nStyleID, :nStylePrice from sales_data sd,
customers c, styles s where sd.customer_id = c.customer_id
and sd.style_id = s.style_id order by sales_agent,
sale_date'
String: strCaption = 'The Haberdashery'
String: strLine1 = 'Fine Men\'s Clothing Since 1895' String: strLine2 =
'Sales Summary Report'
String: strDocName = 'Sales Summary Report'

Variables
Window Handle: hWndReport
String: strSalesAgent
Date/Time: dtSaleDate
String: strCustFirst
String: strCustLast
Number: nStyleID
Number: nStylePrice
Number: nCopies
Number: nOptions
Number: nFirstPage
Number: nLastPage
Number: nError
Sql Handle: hSql
Number: nFetch
...

Form Window: frmMain


...
Menu Item: &Print Report
...
Menu Actions
Q) Set nOptions = RPT_PrintAll
Set nCopies = 1
Set nError = 1
C9 Set hWndReport = SalReportPrint( frmMain, RPT_Template,
RPT_Variables, RPT_Inputs,
nCopies, nOptions, nFirstPage, nLastPage, nError )
...
Message Actions
C) On SAM_ReportStart
Call SalReportDlgOptions( SalNumberToWindowHandle( wParam ),
strCaption, strLine1, strLine2, strDocName )
Set SqlDatabase = 'SALES'
Call SqlConnect( hSql )
¢l: On SAM_ReportFetchInit
If NOT SqlPrepare( hSql, SQL_Select )
Return FALSE
Else

366
If NOT SqlExecute( hSql )
Return FALSE
Else
Return TRUE
�On SAM_ReportFetchNext
If SqlFetchNext( hSql, nFetch )
If nFetch = FETCH_Ok
Return TRUE
Else
Return FALSE
<: On SAM_ReportFinish
Call SqlDisconnect( hSql )

SalReportPrintToFile
Call SalReportPrint to File to write a report to a file in RTF format or ASCII text format:
hWndReport = SalReportPrintToFile ( hWndFrm, strTemplate
strDestFile, strVariables,strInputs, nCopies,
nOptions, nFirstPage, nLastPage, bFormat, nErr )
The parameters are the same as for SalReportPrint except for strDestFile, which is the name of the file, and
bFormat, which you set to TRUE if you want the report file to be saved in RTF (Rich Text Format) or FALSE for
an ASCII text file.
SalReportPrintToFile returns before printing begins.

SalReportView
Call SalReportView to display a report using an existing report template:
hWndReport = SalReportView( frmServer, frmDisplay,
strReportTemplate, strVariables, strInputs, nFlag )
The return value (hWndReport) is the same as for SalReportPrint. Also, the frmServer, strReportTemplate,
strVariables, and strInputs parameters are the same as for SalReportPrint.
You can let Report Builder display the report in its standard view window or you can supply your own view
window:
• To use the standard view window, pass hWndNULL in the frmDisplay parameter
• To use your own view window, pass its name or handle in the frmDisplay parameter
The standard view window is almost the same as the Report Builder design time preview window. The
standard form window has menu items and push buttons that let the user page forward and backward
through the report, size the report, and print the report. If you use your own view window, you can supply
these same functions by calling SalReportCmd (explained later).

367
SalReportView returns after report formatting begins.
Before you call SalReportView, you can set nFlags to one of the constants below to turn off the printer icon on
the default report view tool bar or turn off the tool bar completely:
• RPT_NoPrint—No print button on the tool bar
• RPT_NoToolbar—No tool bar in the preview window
After the functions returns, the nFlags parameter functions the same as the nError parameter for
SalReportPrint.
Note: If there is a print button on the toolbar, and the user clicks it while viewing the report, the sequence
of report messages that was diagrammed earlier in this chapter will start again. SAM_ReportStart will
not be sent again, but SAM_ReportFetchInit will be. Therefore, you must make sure to respond to
that message by providing a full set of data, with your application’s logic pointed to the beginning of
that set. That might mean repositioning a file pointer to the beginning of a file, or calling
SqlPrepareAndExecute to prepare a new database result set.

SalReportCmd
If you use your own view window to display a report, you can provide the same functions as the standard
report view window's menus and toolbar by calling SalReportCmd:
bOk = SalReportCmd( hWndReport, nCommand )
The hWndReport parameter is the window handle returned by SalReportView. The nCommand parameter is
one of the RPT_Cmd* constants in the table below.
You can only call SalReportCmd if you supplied your own window handle or name (in the frmDisplay
parameter) when you called SalReportView.

RPT_Cmd* constants
These are the RPT_Cmd* constants:

Constant Description
RPT_CmdFirstPage Displays the first page of the report

368
Constant Description
RPT_CmdGoToPage Display a dialog where the user can enter the page number in the report to scroll to
RPT_CmdLastPage Displays the last page of the report
RPT_CmdNextPage Displays the next page of the report
RPT_CmdPrevPage Display the previous page of a report
RPT_ CmdPrint Prints the report
RPT_CmdPrinterSetup Displays the Printer Setup dialog so the user can change the print settings
RPT_CmdSizeActual Displays the report in its actual size in the report window
RPT_CmdSizeFit Displays the report sized to fit in the report window

Example
The constants, variables, and message processing are the same as for the SalReportPrint example and are not
repeated here. When the user selects the Display Report menu item:
Q) Call SalReportView. The second parameter tells Report Builder the name of a form window
defined in the application to use to display the report.
C9 The frmView form window that displays the report has top-level menu items that call
SalReportCmd.

369
Form Window: frmMain
...
Menu Item: &Display Report
...
Menu Actions
Set nError = 1
Q) Set hWndReport = SalReportView( frmMain, frmView, RPT_Template,
RPT_Variables, RPT_Inputs, nError )
...
Form Window: frmView
...
C9 Menu Item: First!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdFirstPage )
Menu Item: Last!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdLastPage )
Menu Item: Next!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdNextPage )
Menu Item: Print!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdPrint )
Menu Item: Setup!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdPrinterSetup )
Menu Item: Actual!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdSizeActual )
Menu Item: Fit!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdSizeFit )

SalReportReset
SalReportReset clears a report window so you can display or print again with a new set of data:
bOk = SalReportReset( hWndReport )
The hWndReport parameter is the window handle returned by SalReportPrint or SalReportView.

Example
SalReportReset causes SAM_ReportFetchInit and SAM_ReportFetchNext messages.
Except as explained below, the constants, variables, and message processing are the same as for the
SalReportPrint example. The frmView window has a menu item that lets the user change the current report
to a slightly different one:
Q) Set the b300 boolean to TRUE.

370
C9 Call SalReportReset.
C) The SAM_ReportFetchInit processing checks the b300 boolean. If it is set, the code prepares and
executes the SELECT statement. The SELECT statement is the same as for the SalReportPrint example
except that the WHERE clause restricts the query to rows with a STYLE_PRICE value greater than 300.

Global Declarations
...
Constants
...
User
String: SQL_Select3 = 'select sd.sales_agent, sd.sale_date,
c.first_name, c.last_name, sd.style_id, s.style_price
into :strSalesAgent, :dtSaleDate, :strCustFirst,
:strCustLast, :nStyleID, :nStylePrice
from sales_data sd, customers c, styles s
where sd.customer_id = c.customer_id
and sd.style_id = s.style_id and s.style_price > 300
order by sales_agent, sale_date'
...
Variables
Boolean: b300
...
Form Window: frmView
...
Menu Item: Over &300
...
Menu Actions
Q) Set b300 = TRUE
C9 If NOT SalReportReset( hWndReport )
Call SalMessageBox( 'Report Error', 'SalReportReset',
MB_Ok | MB_IconHand )
Set b300 = FALSE
...
Form Window: frmMain
...
Message Actions
C) On SAM_ReportFetchInit
If b300
If NOT SqlPrepare( hSql, SQL_Select3 )
Return FALSE
Else
If NOT SqlExecute( hSql )
Return FALSE
Else
Return TRUE
Else
...

SalReportClose
Use SalReportClose after SalReportPrint or SalReportView returns to end printing before the end of a report.
For example, you can call SalReportClose in the actions for a cancel menu pick or a push button.

371
With SalReportView, SalReportClose is the same as the user double-clicking the system menu of the report
view window and the application calling SalDestroyWindow.

SalReportCreate (Creating a Report Template)


Call SalReportCreate to create a new report template:
bOk = SalReportCreate( strReportTemplate, strVariables,
strInputs, bDefault, nError )
The strReportTemplate, strVariables, strInputs, and nError parameters are the same as for SalReportPrint and
SalReportView.
If the bDefault parameter is FALSE, SalReportCreate creates a report template with the input items that you
specify in strInputs. You can then open the report template and complete its definition.
If bDefault is TRUE, SalReportCreate creates a report template with the input items that you specify in
strInputs, fields, and captions for the input items, and page headers and footers. You can then specify this
report template in calls to SalReportPrint or SalReportView.

Example
The following example creates a report template named “salesum2.qrp”. The bDefault parameter is TRUE, so
the report template will have the input items specified in RPT_Inputs, fields, captions, page headers, and
page footers.
Menu Item: &Create Report Template
...
Menu Actions
Call SalReportCreate( 'salesum2.qrp', RPT_Variables,
RPT_Inputs, TRUE, nError )

Input Variables
The earlier examples showed generating reports with input items that the application passes each time it
receives SAM_ReportFetchNext. At each SAM_ReportFetchNext, the application passes the same set of input
items to Report Builder.
With input variables, you have additional control over:
• Data you pass to Report Builder
• When you pass data to Report Builder
• Data you can retrieve from a report
You set and get input variables with the SalReportSet*Var and SalReportGet*Var functions:

Function Description
SalReportSetDateTimeVar Sets a Date/Time input variable
SalReportSetNumberVar Sets a Number input variable
SalReportSetObjectVar Sets an object input variable

372
Function Description
SalReportSetStringVar Sets a String input variable
SalReportGetDateTimeVar Gets a Date/Time input variable
SalReportGetNumberVar Gets a Number input variable
SalReportGetObjectVar Gets an object input variable
SalReportGetStringVar Gets a String input variable

You can call SalReportGet*Var and SalReportSet*Var while processing:


• SAM_ReportStart
• SAM_ReportFetchInit
• SAM_ReportFetchNext
• SAM_ReportNotify
If you process SAM_ReportNotify, you can detect which part of the report Report Builder is processing and
set or get input variables as appropriate (see Example on page 374).

SAM_ReportNotify
Report Builder sends the SAM_ReportNotify message when it is ready to format a part of a report. When you
process SAM_ReportNotify, you can check the lParam to find the part Report Builder is ready to process. The
lParam is one of the RPT_* constants in the following tables.
Report Builder ignores any value that you return during SAM_ReportNotify processing.

RPT_* Constants
The RPT_* constants for SAM_ReportNotify are grouped in three categories according to when sent:

Category When Sent


RPT_Before* Just before a report block is about to be formatted
RPT_Output* After a report block is formatted, but before it is output
RPT_Done* After the report block is output

These are the RPT_* constants:

Constant Report Block


RPT_BeforePageHeader Top of every page
RPT_OutputPageHeader
RPT_DonePageHeader
RPT_BeforePageFooter Bottom of every page
RPT_OutputPageFooter
RPT_DonePageFooter

373
Constant Report Block
RPT_BeforeDetail RPT_OutputDetail Detail block
RPT_DoneDetail
RPT_BeforeReportHeader Once at the beginning
RPT_OutputReportHeader
RPT_DoneReportHeader
RPT_BeforeReportFooter Once at the end
RPT_OutputReportFooter
RPT_DoneReportFooter
RPT_BeforeBreakFooter1 - RPT_BeforeBreakFooter8 After detail block
RPT_OutputBreakFooter1 - RPT_OutputBreakFooter8
RPT_DoneBreakFooter1 - RPT_DoneBreakFooter8
RPT_BeforeBreakHeader1 - RPT_BeforeBreakHeader8 Before detail block
RPT_OutputBreakHeader1 - RPT_OutputBreakHeader8
RPT_DoneBreakHeader1 - RPT_DoneBreakHeader8

Example
This example checks the lParam to find if Report Builder is ready to process the first break header:
On SAM_ReportNotify
If lParam = RPT_BeforeBreakHeader1
! strPic contains an image. Set the report variable
! named PICTURE to the contents of strPic.
Call SalReportSetObjectVar( frmMain, 'PICTURE', strPic )

Creating Reports from Table Windows


SQLWindows has three functions that you can use to print and display reports based on table window data.
This is the fastest and easiest way to generate a report.
You can use these functions with all table windows.

SalReportTableCreate
You can create a report template by calling SalReportTableCreate:
bOk = SalReportTableCreate( strReportTemplate, hWndTable,nError )
The strReportTemplate parameter is the name of the report template. The hWndTable parameter is the
handle of the table window. The nError parameter is the same as for the other SalReport* functions.
Here is how SQLWindows creates the report template:
• The column titles are used for the input item names. SQLWindows translates spaces in column titles to
underscores.
• The page header contains the table window title, the date, and the column titles as background text.
However, a report with data from a child table window does not have a title.
• The detail block contains the table window columns.

374
• The page footer contains a page number.

SalReportTablePrint
This function prints a report using table window data:
hWndReport = SalReportTablePrint( hWndTable, strReportTemplate,
nParameterArray, nError )
The return value (hWndReport) is the same as for SalReportPrint and SalReportView.
The hWndTable parameter is the handle of the table window. The strReportTemplate parameter is the name
of the report template.
The nParameterArray parameter is a numeric array that contains settings for printing parameters:

Offset Offset constant Description


0 RPT_PrintParamOptions Same as nOptions for SalReportPrint and SalReportPrintToFile
1 RPT_PrintParamFirstPage First page number to print
2 RPT_PrintParamLastPage Last page number to print
3 RPT_PrintParamCopies Number of copies to print

The nError parameter is the same as for the other SalReport* functions.

SalReportTableView
This function displays a report using table window data:
hWndReport = SalReportTableView( hWndTable, hWndDisplay,
strReportTemplate, nError )

Example
The return value (hWndReport) is the same as for SalReportPrint and SalReportView.
The hWndTable parameter is the handle of the table window. The hWndDisplay parameter is the same as for
SalReportView. The strReportTemplate parameter is the name of the report template. The nError parameter
is the same as for the other SalReport* functions.
This example shows three menu items that call:
Q) SalReportTableCreate
C9 SalReportTableView
C) SalReportTablePrint

375
Global Declarations
...
Constants
...
User
...
String: SQL_Select2 = 'select sd.sales_agent, sd.sale_date,
c.first_name, c.last_name, sd.style_id, s.style_price
into :tblReport.colSalesPerson, :tblReport.colSalesDate,
:tblReport.colFirstName, :tblReport.colLastName,
:tblReport.colItem, :tblReport.colPrice
from sales_data sd, customers c, styles s
where sd.customer_id = c.customer_id
and sd.style_id = s.style_id
order by sales_agent, sale_date'
...
Variables
Window Handle: hWndReport
Window Handle: hWndTable
Number: nError
Sql Handle: hSql
Number: nFetch
Number: nPrintParmArray[4]
...
Form Window: frmMain
...
Q) Menu Item: &Create
...
Menu Actions
Set hWndTable = SalCreateWindow( tblReport, frmMain )
If NOT SalTblPopulate( hWndTable, hSql, SQL_Select2,
TBL_FillNormal )
Call SalMessageBox( 'Cannot populate table window',
'Table Window Error', MB_Ok )
Else
Set nError = 1
Call SalReportTableCreate( 'salesum3.qrp', hWndTable, nError )
C9 Menu Item: &View
...
Menu Actions
Set hWndTable = SalCreateWindow( tblReport, frmMain )
If NOT SalTblPopulate( hWndTable, hSql, SQL_Select2,
TBL_FillNormal )
Call SalMessageBox( 'Cannot populate table window',
'Table Window Error', MB_Ok )
Else
Set nError = 1
Set hWndReport = SalReportTableView( hWndTable, hWndNULL,
'salesum3.qrp', nError )
C) Menu Item: &Print
...
Menu Actions
Set hWndTable = SalCreateWindow( tblReport, frmMain )
If NOT SalTblPopulate( hWndTable, hSql, SQL_Select2,
TBL_FillNormal )
Call SalMessageBox( 'Cannot populate table window',
'Table Window Error', MB_Ok )
Else
Set nError = 1
Set nPrintParmArray[RPT_PrintParamCopies] = 1

376
Set hWndReport = SalReportTablePrint( hWndTable, 'salesum3.qrp',
nPrintParmArray, nError )
...
Table Window: tblReport
...
Title: Sales Summary
...
Contents
Column: colSalesPerson
...
Title: Sales Person
...
Data Type: String
...
Column: colSalesDate
...
Title: Sales Date
...
Data Type: Date/Time
...
Column: colFirstName
...
Title: Cust First Name
...
Data Type: String
...
Column: colLastName
...
Title: Last Name
...
Data Type: String
...
Column: colItem
...
Title: Item
...
Data Type: Number
...
Column: colPrice
...
Title: Price
...
Data Type: Number

377
Chapter 15 – Table Windows
This chapter explains table windows including:
• Types of table windows
• User interface
• Simple and advanced programming techniques
• Table window features
• Table window messages
• XML support for table windows
A table window displays data in row and column format, like a spreadsheet. Through a table window, a user
can:
• Display a query
• Browse through rows of data
• Insert, update, or delete rows of data
Table windows have many features that give a developer flexibility in creating powerful applications.
A table window is a matrix of rows (records) and one or more columns. The intersection of a row and column
is called a cell.
A table window represents a relational table well. This makes a table window suited for displaying queries.

378
Types of Table Windows
A table window can be:
• A top-level window
• A child of a form or dialog box
The intersection of each column and a row is a cell Both types of table windows refer to the entire window as
a single entity.

Top-Level Table Windows


Top-level table windows have the same features as form windows (title, menu, and icon).

Top-level table window attributes


Top-level table window attributes are the following:

Property Description
Object Name The name you use to refer to the table window in statements.
Object Title The name of the table window that appears in the title bar.
Accessories Enabled If Yes, then the table window has a tool bar and a status bar and you can modify the
next six attributes, associated with the tool bar and status bar. If it is No, the next six
attributes cannot be edited. The default is No.
Tool Bar Visible If Yes, a portion of the client area of the window is used to display the toolbar.
Tool Bar Size Either Default or a size that you specify.
Tool Bar Position By default, the toolbar is docked at the top of the client area. Other choices are Left,
Right, and Bottom.
Tool Bar Docking Indicates whether the tool bar is capable of being docked and undocked (free-
Enabled floating). Default value is No. You may also select Yes.
Tool Bar Docking If Tool Bar Docking Enabled is Yes, you can specify which sides of the parent window
Orientation are available for docking. Choices are Top, Bottom, Left, and Right.
Status Bar Visible If Yes, a portion of the bottom of the client area of the window is used to display the
status bar. You may also select No.
Automatically Create If Yes (default), the window is created and displayed at application startup. If No, you
must call SalCreateWindow to create the window.
Maximizable If Yes (default), the table window has a maximize button in the upper right corner. If
No, the table window does not have a maximize button and the user cannot maximize
the table window.
Minimizable If Yes (default), the table window has a minimize button in the upper right corner. If
No, the table window does not have a minimize button and the user cannot minimize
the table window.
System Menu If Yes (default), the table window has a system menu.
Resizable If Yes (default), the user can resize the table window using sizing pointers.

379
Property Description
Initial State The window's state when created: Maximized, Minimized, or Normal (default).
Icon File A file that contains an icon used when the table window is minimized. The icon file
must be in *.ICO format.
Location and Size Displays a cascading menu with the table window's position (top and left) and size
(width and height).
Lines per row By default, the lines per row is one. When you set lines per row to two or more, text
wraps in columns where you turn on word wrap.
Allow row sizing If Yes, users can drag and resize rows at runtime. You can also change this setting
dynamically at runtime by calling SalTblDefineRowHeader and specifying
TBL_RowHdr_RowsSizable.
Background Color The background color of the table window.
Text Color The color of text in the table window.
Font Name The font of text in the table window.
Font Size The font size of text in the table window.
Font Enhancement The font enhancement of text in the table window.
Discardable If Yes (default), rows in the table window cache are discardable. SQLWindows makes
space for new rows by discarding unused rows. If No, SQLWindows does not
automatically discard rows and keeps all data in the cache.
Max Rows in Memory The number of table window rows that can be stored in the cache. The default is 100
and the maximum is 2,147,423,632 rows. See Table Window Cache on page 403.
Allow child docking Set this property to Yes if you want this top-level window to allow docked windows..
Default value is No.
Docking orientation This property is enabled only if the “Allow child docking” property is set to Yes. This
property controls which directions can a child window dock itself to this top-level
window.

Child Table Windows


A child table window is a child of a form window or dialog box. A child table window is like a top-level
window, but it does not have a menu, title, system menu, icon, toolbar, or status bar. Also, a child table
window is not resizable and does not have minimize and maximize push buttons. A child table window is
created and destroyed along with its parent.
The following is a child table window in a form window:

380
Child table window attributes
The attributes for a child table window are the following:

Property Description
Object Name The name you use to refer to the table window in statements.
Visible If Yes (default), the table window is visible at runtime. If No, the table window is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the table window's position (top and left) and size
(width and height).
Location and Size Displays a cascading menu with the table window's position (top and left) and size
(width and height).
Lines per row By default, the lines per row is one. When you set lines per row to two or more, text
wraps in columns where you turn on word wrap.
Allow row sizing If Yes, users can drag and resize rows at runtime. You can also change this setting
dynamically at runtime by calling SalTblDefineRowHeader and specifying
TBL_RowHdr_RowsSizable.
Background Color The background color of the table window.
Text Color The color of text in the table window.
Font Name The font of text in the table window.
Font Size The font size of text in the table window.
Font Enhancement The font enhancement of text in the table window.
Discardable If Yes (default), rows in the table window cache are discardable. SQLWindows makes
space for new rows by discarding unused rows. If No, SQLWindows does not
automatically discard rows and keeps all data in the cache.
Max Rows in Memory The number of table window rows that can be stored in the cache. The default is 100.
The theoretical maximum is 2,147,423,632 rows. See Table Window Cache on page
403.

381
Table Window Columns
Columns are the only content item in a table window. Each column is a child window of the parent table
window. You add columns as child content items.

Adding Columns
You can add columns like other child objects by:
• Clicking the column push button in the Controls palette.
OR
• Selecting Column in Coding Assistant.
OR
• Entering the column definition directly into the outline.

After you click the column push button in the Controls toolbar, move the mouse pointer to the
left side of the table window until the mouse pointer changes to the one shown on the left. Click
to add the first column. To add more columns, more the mouse pointer to the right side of an
existing column and click.

Moving and Sizing Columns


You can size columns using the column sizing mouse pointer shown on the left. This mouse
pointer appears when on the right edge of a column title. When this mouse pointer appears,
hold down the mouse button and drag to the left or right. Changing the column width with the
mouse is called “drag-sizing”. You can also change the column width in the Attribute Inspector.

You can move columns using the column moving mouse pointer shown on the left. This mouse
pointer appears when on the bottom edge of a column title. When this mouse pointer appears,
hold down the mouse button and drag to the left or right to move the column. This is called
“drag-moving”.

A user can also move and resize columns using these mouse pointers at runtime.

Column Attributes
The attributes for a table window column are the following.
To display the Attribute Inspector for a column, position the mouse pointer on the column heading and right-
click.

Property Description
Object Name The name you use to refer to the column in statements.
Object Title The title in the column heading. Create a mnemonic by adding an ampersand (&)
before the letter that is the mnemonic.

382
Property Description
Visible If Yes (default), the column is visible at runtime. If No, the column is not visible at
runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Column Width The width of the column in inches. The default is 1.2 inches.
Data Type The data type of the column:
String Default
Long String Use to read and write SQL database columns longer than
254 bytes
Number
Date/Time
Max Data Length The maximum number of characters that the user can enter in the column. The
default is 100. The maximum length of a String or Long String data type is 32
kilobytes. This option is only available if the column is editable.
Important: The value you specify in Max Data Length is the maximum capacity of
the object, not the number of bytes that SQLWindows allocates for the object’s
value. At runtime, SQLWindows allocates the number of bytes in the actual value of
the object at any one time. Also, when you set a variable or another object with the
value, SQLWindows only copies the number of bytes in the actual value, not the
number of bytes in the Max Data Length setting of the source object.
Cell Type You can set this item to:
Standard
Drop Down List Behaves like a combo box when a cell gets the focus. When
you set this, you can set properties for the list (read the
entry for Drop Down List).
Popup Edit Behaves like a multiline field when a cell gets the focus.
Check Box Behaves like a check box when a cell gets the focus. When
you set this, you can set properties for the check box (read
the entry for Check Box). At runtime, a user cannot enter
characters in this cell type.
Drop Down List When you set the Cell Type to Drop Down List, you can set this to:
Sorted Items in the list are sorted.
Vertical Scroll The list has a vertical scroll bar.
Auto Drop Down The list drops automatically when a cell gets the focus.
Allow Text Editing The user can type new text and also choose an item from
the list.
You can call any SalList* function for a column that you set as a drop down list,
except for:
– SalListFiles
– SalListGetMultiSelect
– SalListQueryFile
– SalListQueryMultiCount
– SalListSetMultiSelect

383
Property Description
Check Box When you set Cell Type property to Check Box, you can set this to:
Checked Value When the cell contains this value, the check box is checked
Unchecked Value – When the cell contains this value, the check box is not checked
Ignore Case – The values you specify for checked and unchecked are compared to
the cell value without regard for case
Editable If Yes (default), the user can enter and edit the column text. If No, the user cannot
enter or edit text.
At runtime, you can change the setting of this property with SalEnableWindow and
SalDisableWindow.
Justify Justification for the column. The default is left.
Format The output format of the column. The default is unformatted. See Chapter 11 –
Formatting and Validating.
Input Mask Input validation criteria for the column. See Chapter 11 – Formatting and
Validating.
Country The country profile for the column. See Chapter 11 – Formatting and Validating.
Word Wrap When the lines per row is two or more, you can set this property to Yes so that text
in the cell wraps automatically.

User Interface
This section explains basic table window functions from the point of view of a user.
A user can also move and resize columns using the mouse pointers explained in Moving and Sizing Columns
(page 382).

Focus Frame
The focus frame is a double-lined border that surrounds the entire row. The row that has the focus frame
surrounding it is referred to as the row that has the focus. To put the focus frame on a row, click anywhere on
that row. Use the up or down arrow key to move the focus frame to a different row.

Selecting rows and cells


A table window can be in row mode or cell mode:
The tables on the following pages show the keyboard and mouse actions that you can use in row mode and
cell mode.

Row mode
In row mode, you can select one or more entire rows.
When a row is selected, it has a dark background and light characters (sometimes called inverse-video or
reversed). When a row is not selected, it has a white or light background and the characters in it are black or
dark unless the user has changed the system colors.
Selected rows can be non-contiguous.

384
Cell mode
In cell mode, you can enter or edit data in the cells of a row. For example, the right and left arrow keys move
the insertion point between characters.

Insertion point
In cell mode, the row with the focus frame contains the insertion point.
The insertion point is a blinking vertical line. When you type, text appears at the insertion point.

Row mode keyboard and mouse actions

Keyboard / Mouse Description


Actions
Ins Selects the first editable cell on the focus row. Puts the table in cell mode.
Tab If the table is a top-level window, puts the table in cell mode and selects the first
editable cell on the focus row. If the table is a child window, moves to the next cell
if the table is in cell mode, otherwise moves from object to object on the form
window or dialog box.
Space Bar Toggles the selection of the focus row.
Up Arrow Moves the focus frame up. Selects the focus row.
Shift+Up Arrow Moves the focus frame up. Selects or deselects the focus row as the previous focus
row.
Ctrl+Up Arrow Moves the focus frame up. Table selection is not affected.
Down Arrow Moves the focus frame down. Selects the focus row.
Shift+Down Arrow Moves the focus frame down. Selects or deselects the focus row just as the
previous row.
Ctrl+Down Arrow Moves the focus frame down. The table window selection is not affected.
Right Arrow Scrolls into view the window columns to the right.
Left Arrow Scrolls into view the window columns to the left.
Page Up Displays the previous window of rows.
Ctrl+Page Up Displays the previous window of rows. The table window selection is not affected.
Page Down Displays the next window of rows. The first row is selected.
Ctrl+Page Down Displays the next window of rows. The table window selection is not affected.
Home Displays the rows at the beginning of the table window.
Ctrl+Home Displays the rows at the beginning of the table window. The table window selection
is not affected.
End Displays the rows at the end of the table. Selects the last row in the table window.
Ctrl+End Displays the rows at the end of the table. The table window selection is not
affected.
Shift+PgUp Selects all displayed rows.
Shift+PgDown

385
Cell mode keyboard and mouse actions

Keyboard / Mouse Description


Actions
Ins Selects the focus row. Puts the table window in cell mode.
Tab Selects the next editable cell in the table window.
Shift-Tab Selects the previous editable cell in the table window.
Up Arrow Moves the focus frame up. Selects the cell in the focus frame.
Down Arrow Moves the focus frame down. Selects the cell in the focus frame.
Left Click Clicking an editable column sets the focus to the cell. Clicking a non-editable
column selects a row and deselects any other rows.
Shift+Left Click Clicking a non-editable column toggles the selection of a row without deselecting
any other rows.
Left Click Drag If a row was selected, holding the left button down while dragging up or down
selects additional rows.
Right Click Selects a row and deselects all others.
Shift+Right Click Toggles the selection of a row without deselecting any other rows.
Right Click Drag Holding the left button down while dragging up or down selects additional rows.

Programming Techniques
There are two general programming techniques that you can use with table windows:
• Simple technique
You use this technique when the data for the table window comes from a SQL database.
• Advanced technique
You use this technique when the data for the table window comes from a non- database source such as
an array, a flat file, or variables.
You can also use the advanced technique when the source of data is a SQL database, although it is easier
to use the simple technique. However, the advanced technique is more flexible. For new database
applications, you probably want to use the simple technique.
You can mix and match the two techniques.
This section shows how to use both techniques for the following operations:
• Populating the table window with rows of data
• Deleting rows of data
• Inserting rows of data
• Updating rows of data
The rest of this section covers how these operations work with the two techniques.

386
Code examples
In this section, only code directly related to processing a table window is shown. Unrelated details such as
changing the cursor or displaying a confirmation dialog box are not shown.
SQL database processing is done in result set mode.

Using the Simple Technique


You can only use the simple technique when the source of data is a SQL database. Assume that the
application has already connected to the database using SqlConnect.

Populating a table window


Call SalTblPopulate to populate the table window with the result set of a query:
Call SalTblPopulate( tblCompanyInfo, hSqlA,
'SELECT ID, ..., FAX FROM COMPANY ORDER BY ID ' ||
'INTO: twCompanyInfo.cnID, ..., :twCompanyInfo.csFAX',
TBL_FillNormal )
The first parameter is a table window handle. The second parameter is a Sql Handle. The third parameter is a
SELECT statement. If the SELECT statement has not been prepared, specify it in this parameter (as done in this
example). If a SELECT statement has already been prepared, specify an empty string (''). The fourth parameter
specifies the way in which to populate the table. TBL_FillNormal means to populate only the visible portion of
the table window. Additional rows are populated as the user scrolls them into view.

Deleting a row
In the delete operation described below, the user selects one or more rows in the table window and then
chooses the Delete menu item. The steps below are performed in the Menu Actions section.
1. Call SalTblAnyRows to find if any row has the ROW_Selected flag set to TRUE:
Call SalTblAnyRows( tblCompanyInfo, ROW_Selected, 0 )
The second parameter says to find rows that have these flags on (ROW_Selected in this example). The
third parameter says to find rows that have these flags off. This is not appropriate in this example, so zero
is specified.
2. Call SqlPrepare and specify a DELETE statement:
Call SqlPrepare( hSqlA, 'DELETE FROM COMPANY ' ||
'WHERE ID = :tblCompanyInfo.cnID' )
3. Call SalTblDeleteSelected to deleted the selected rows:
Call SalTblDeleteSelected( tblCompanyInfo, hSqlA )
SalTblDeleteSelected finds all rows that have the ROW_Selected flag set to TRUE and deletes the rows
from both the table window and the database. The Sql Handle (hSqlA) must be associated with a DELETE
statement.
You can also use SalTblDoDeletes to delete rows. SalTblDoDeletes is like SalTblDeleteSelected, except that
you specify the flags that of the rows to delete (such as ROW_MarkDeleted or ROW_Selected):
Call SalTblDoDeletes( tblCompanyInfo, hSqlA, ROW_Selected )
4. COMMIT or ROLLBACK the DELETE.

387
Inserting rows
There are two parts to inserting rows:
• The user chooses an Insert menu item that creates a new, empty row in the table window
• After the user has created and entered data in one or more new rows, the user chooses the Apply
Changes menu item to INSERT the new rows into the database.
For the first part, the steps below are performed in the Menu Actions section for the Insert menu item.
1. Create a new row in the table window by calling SalTblInsertRow:
Set nIndex = SalTblInsertRow( twCompanyInfo, TBL_MaxRow )
SalTblInsertRow adds a blank row at the location you specify. In the example above, the second
parameter is a flag that says to add the new row at the end of the table window. SalTblInsertRow returns
the row number in nIndex, which is used in the next two function calls.
2. Set the focus to the new row and position the text insertion bar to a cell in the row by calling
SalTblSetFocusCell:
Call SalTblSetFocusCell( twCompanyInfo, nIndex, csName, 0, -1 )
The second parameter is the row number returned by SalTblInsertRow. The third parameter specifies
where to set the column focus in the row. The fourth and fifth parameters select specific characters
within the focus cell. This is not needed for this example, so 0, -1 is used for these parameters to select
the entire cell.
The user can now enter data in the cells of the new table window row.
For the second part, the following steps are performed in the Menu Actions section of the Apply Changes
menu item. They INSERT one or more new rows into the database that the user entered:
3. The user might not have moved the cursor off a newly-inserted row. Call SalTblKillEdit to force the setting
of the ROW_Edited flag, the result of which is the validation (checking of the data type) of the value that
the user entered:
Call SalTblKillEdit( twCompanyInfo )
4. Call SalTblAnyRows to find if any row has the ROW_New flag set to TRUE:
If SalTblAnyRows( tblCompanyInfo, ROW_New, 0 )
The second parameter says to find rows that have these flags on (ROW_New in this example). The third
parameter says to find rows that have these flags off. This is not appropriate in this example, so zero is
specified. ('If' is used instead of 'Call' because 'Call' would ignore the boolean return. The function returns
TRUE if any row has ROW_New set to TRUE.)
Call SqlPrepare and specify an INSERT statement:
Call SqlPrepare( hSqlA, 'INSERT INTO COMPANY( ID, ..., FAX)' ||
'VALUES( :twCompanyInfo.cnID, ' ||
...
':twCompanyInfo.csFAX ) ' )
5. Call SalTblDoInserts:
Call SalTblDoInserts( tblCompanyInfo, hSqlA, FALSE )
SalTblDoInserts finds and INSERTs all rows that have the ROW_New flag set to TRUE. The second
parameter is the Sql handle that must be associated with an INSERT statement. The third parameter says
not to clear the ROW_New flag of each row after inserting it in the database. You do not want to insert
part of the rows and then have a rollback happen. If that happened, you lose flags for the partial

388
transaction. It is better to wait until you have successfully inserted all rows are before clearing the
ROW_New flag.
6. COMMIT or ROLLBACK the INSERT.
7. Set the table window row number to TBL_MinRow:
Set nRow = TBL_MinRow
8. Call SalTblFindNextRow and SalTblSetRowFlags in a loop:
Loop
If NOT SalTblFindNextRow( tblCompanyInfo, nRow, ROW_New, 0 ) Break
Call SalTblSetRowFlags( tblCompanyInfo, nRow, ROW_New | ROW_Edited, FALSE )
 Call SalTblFindNextRow to find the next row with the ROW_New flag set to TRUE. The second
parameter is the table window row number that indicates where the search is to start (this was set to
TBL_MinRow in the previous step). When it finds a row that matches the flag (ROW_New),
SalTblFindNextRow returns the row number in this parameter. The third parameter specifies flags for
the row. The fourth parameter specifies flags that the row does not have; this is not appropriate for
this application, so zero is specified. The loop repeats until there are no more rows with the
ROW_New flag set to TRUE.
 Call SalTblSetRowFlags to clear the ROW_New and ROW_Edited flags for the processed row. The third
parameter are the flags to set to FALSE (ROW_New and ROW_Edited ORed together). The fourth
parameter specifies the setting for the flags (FALSE means off).
The loop above can be replaced with one call to the new function SalTblSetFlagsAnyRows:
Call SalTblSetFlagsAnyRows( twCompanyInfo, ROW_New | ROW_Edited,

FALSE, ROW_New, 0 )

Updating rows
For this application, the user can change values in one or more table window rows. However, the changes
are not made in the database until the user selects the Apply Changes menu item.
The steps below (in the Menu Actions section for the Apply Changes menu item) UPDATE one or more rows
in the database that the user changed.
1. The user might not have moved the cursor off an updated row. Call SalTblKillEdit to force the setting of
the ROW_Edited flag, the result of which is the validation of the value that the user entered:
Call SalTblKillEdit( twCompanyInfo )
2. Call SalTblAnyRows to find if any row has the ROW_Edited flag set to TRUE:
If SalTblAnyRows( tblCompanyInfo, ROW_Edited, 0 )
The second parameter says to find rows that have the ROW_Edited flag set to TRUE. The third parameter
says to find rows that have these flags off. This is not appropriate in this example, so zero is specified.
3. Call SqlPrepare and specify an UPDATE statement:
Call SqlPrepare( hSqlA, 'UPDATE COMPANY ' ||
'SET NAME = :twCompanyInfo.csName, ' ||
...
'FAX = :twCompanyInfo.csFAX) ' , ||
'WHERE ID = :twCompanyInfo.cnID' )
4. Call SalTblDoUpdates:

389
Call SalTblDoUpdates( tblCompanyInfo, hSqlA, FALSE )
SalTblDoUpdates finds all rows with the ROW_Edited flag set to TRUE and UPDATEs them. The second
parameter is the Sql Handle that must be associated with an UPDATE statement. The third parameter says
not to clear the ROW_Edited flag of each row after it has been updated in the database.
5. COMMIT or ROLLBACK the UPDATE.
6. Set the table window row number to TBL_MinRow:
Set nRow = TBL_MinRow
7. Call SalTblFindNextRow and SalTblSetRowFlags in a loop:
Set nRow = TBL_MinRow Loop

If NOT SalTblFindNextRow( tblCompanyInfo, nRow, ROW_Edited, 0 ) Break

Call SalTblSetRowFlags( tblCompanyInfo, nRow, ROW_Edited, FALSE )

 Call SalTblFindNextRow to find the next row with the ROW_Edited flag set to TRUE. The second
parameter is the table window row number that indicates where the search is to start (this was set to
TBL_MinRow in the previous step). When it finds a row that matches the flag, SalTblFindNextRow
returns the row number in this parameter. The third parameter specifies flags that the row has. The
fourth parameter specifies flags that the row does not have; this is not appropriate for this
application, so zero is specified. The loop repeats until there are no more rows with the ROW_Edited
flag set to TRUE.
 Call SalTblSetRowFlags to clear the ROW_Edited flag for the processed row. The third parameter is
the flag to set to FALSE (ROW_Edited). The fourth parameter specifies the setting for the flag (FALSE
means off).
The loop above can be replaced with one call to SalTblSetFlagsAnyRows:
Call SalTblSetFlagsAnyRows( twCompanyInfo, ROW_Edited, FALSE, ROW_Edited, 0 )

Using the Advanced Technique


You can use the advanced technique with any source of data. In this example, the source of data is a SQL
database. The explanation below points out where you would need to process data from a non-database
source.
This example does SQL database processing with CURRENT OF cursor.
Assume that the application has already connected to the database using SqlConnect.

Populating a table window


1. Prepare the SELECT statement.
Call SqlPrepare( hSqlA,
'SELECT ID, NAME, ADDR1, ..., FAX ' ||
'FROM COMPANY ORDER BY NAME ' ||
'INTO:twCompanyInfo.cnID, ' ||
':twCompanyInfo.csName ' ||
':twCompanyInfo.csAddr1 ' ||
...
':twCompanyInfo.csFAX ' )
The INTO clause names the table window columns that receive the data. Each column name in the INTO
clause is qualified with the table window handle:

390
:twCompanyInfo.cnID
2. Execute the SELECT statement.
Call SqlExecute( hSqlA )
3. Reset the table window.
Call SalTblReset( twCompanyInfo )
4. Find the number of rows in the data source.
Call SqlGetResultSetCount( hSqlA, nRowCount )
If the source of data is not a database, you must determine the row count for the table window. For
example, if the data comes from an array, you can use SalQueryArrayBounds to determine the number of
elements.
5. Set the table range with SalTblSetRange. The table range is the number of rows in the table window.
Call SalTblSetRange( twCompanyInfo, 0, nRowCount -1 )
The first parameter is a table window handle. The second parameter is the lower bound of the table
range and the third parameter is the higher bound of the table range.
SalTblSetRange causes SQLWindows to send SAM_FetchRow messages to the table window.
6. Process SAM_FetchRow messages.
Table Window: twCompanyInfo
...
Message Actions
...
On SAM_FetchRow
If Not SqlFetchRow( hSqlA, lParam, nFetchResult )
Return FALSE
Else
Return TRUE
SQLWindows sends a SAM_FetchRow to a table window when the table window needs the contents of a
row that is not already in memory (cache). For example, when the application first displays a table
window, SQLWindows sends one SAM_FetchRow message for each row that is visible on screen. As the
user scrolls, SQLWindows sends additional SAM_FetchRow messages, one for each row that the user
scrolls to.
To process a SAM_FetchRow message, get the data from its source and assign values to the table window
columns. Return a value to indicate the status of the SAM_FetchRow processing. This application calls
SqlFetchRow to retrieve a row of data. The INTO clause in the SELECT statement (from step 1) mapped
the database table columns to the table window columns.
The second argument to SqlFetchRow is the current row number (context) in the table window. The
lParam for a SAM_FetchRow message is the number of the row currently being processed.

Deleting a row
In the following delete operation, the user selects a row in the table window and then chooses the Delete
menu item. The steps below are performed in the Menu Actions section.
1. Delete the source data (in an array, variables, or flat file).
For a SQL database, call SqlPrepare and specify a DELETE statement:

391
Call SqlPrepare( hSqlB, 'DELETE FROM COMPANY' ||
'WHERE ID = :twCompanyInfo.cnID' )
The column name in the WHERE clause is qualified with the table window handle (:twCompanyInfo.cnID).
This tells SQLWindows to use the value for cnID in the row that has the context. You set the context row
with SalTblSetContext.
After calling SqlPrepare, call SqlExecute for the Sql Handle.
2. Remove the row from the table window with SalTblDeleteRow.
If the data comes from a database, the call looks like this:
Call SalTblDeleteRow( twCompanyInfo,
SalTblQueryContext( twCompanyInfo ),TBL_Adjust )
The first parameter is the handle of the table window. The second parameter is the row to delete. This
example calls SalTblQueryContext to get the row that has the context. The third parameter is a flag that
specifies to maintain correspondence between the table window row and the row in the database result
set.
Important: SalTblDeleteRow deletes the row from the table window only. You must prepare and execute
a DELETE statement to delete the row from the database (read step 1).
If the data does not come from a database, the call looks like this:
Call SalTblDeleteRow( twCompanyInfo,
SalTblQueryContext( twCompanyInfo ), TBL_NoAdjust )
If the source of data is not from a database, there is no need to maintain correspondence with a result
set, so specify TBL_NoAdjust for the third parameter.
3. For a SQL database, COMMIT or ROLLBACK after deleting the row from the table window.

Inserting a row
There are two parts to inserting rows:
• The user chooses an Insert menu item that creates a new, empty row in the table window.
• After the user creates and enters data in one or more new rows, the user chooses the Apply Changes
menu item to INSERT the new rows into the database.
Part 1 – In the Menu Actions section, follow these steps:
1. Create a new row in the table window by calling SalTblInsertRow:
Set nIndex = SalTblInsertRow( twCompanyInfo, TBL_MaxRow )
SalTblInsertRow adds a blank row at the location that you specify. The second parameter is a flag
(TBL_MaxRow) that says to add the new row at the end of the table window. The row number (nIndex)
that SalTblInsertRow returns is used in the next two function calls.
2. Set the focus to the new row and position the text insertion bar to a cell in the row by calling
SalTblSetFocusCell:
Call SalTblSetFocusCell( twCompanyInfo, nIndex,
csName, 0, -1 )
The second parameter is the row number returned by SalTblInsertRow. The third parameter specifies
where to set the column focus in the row. The fourth and fifth parameters select specific characters
within the focus cell. This is not needed for this example, so 0, -1 is used for these parameters (this
selects the entire cell).

392
The user can now enter data in the cells of the new table window row.
Part 2 – In the Menu Actions section, follow these steps. Choose the Apply Changes menu item to INSERT
into the database one or more new rows that the user entered:
3. The user might not have moved the cursor off a newly inserted row. Call SalTblKillEdit to force the setting
of the ROW_Edited flag, the result of which is the validation of the value the user entered:
Call SalTblKillEdit( twCompanyInfo )
4. For a SQL database, call SqlPrepare and specify an INSERT statement:
Call SqlPrepare( hSqlB,'INSERT INTO COMPANY( ID, ..., FAX )' ||
'VALUES(:twCompanyInfo.cnID, ' ||
...
':twCompanyInfo.csFAX) ' , || 'ADJUSTING C ' )
The column names in the VALUES clause are qualified with the table window handle (:twCompanyInfo.*).
This tells SQLWindows to use the value for the columns in the row that has the context.
5. Set the table window row number to TBL_MinRow:
Set nIndex = TBL_MinRow
6. In a loop, search for newly inserted rows to process:
Loop
If SalTblFindNextRow( twCompanyInfo, nIndex, ROW_New, 0 )
Call SalTblSetContext( twCompanyInfo, nIndex )
Call SqlExecute( hSqlB )
Call SalTblSetRowFlags(twCompanyInfo, nIndex,
ROW_New | ROW_Edited, FALSE )
Else
Break
 Call SalTblFindNextRow to find the next row with the ROW_New flag set to TRUE. The second
parameter is the table window row number where to start the search (this was set to TBL_MinRow in
the previous step). When it finds a row that matches the ROW_New flag, SalTblFindNextRow returns
the row number in this parameter. The third parameter specifies flags that the row has. The fourth
parameter specifies flags that the row does not have; this is not appropriate for this application, so
zero is specified. The loop repeats until there are no more rows with the ROW_New flag set to TRUE.
 Call SalTblSetContext to set the context on the row. SalTblFindNextRow returns the row number in
nIndex that matches the ROW_New flag.
 Using the data from the table window cells, process the insert in the data source (such as an array,
variables, or a flat file).
 For SQL database, call SqlExecute.
 Call SalTblSetRowFlags to clear the ROW_New and ROW_Edited flags for the processed rows. The
third parameter are the flags to set to FALSE (ROW_New and ROW_Edited ORed together). The fourth
parameter specifies the setting for the flags (FALSE means off).
7. For a SQL database, COMMIT or ROLLBACK after inserting the rows.

Updating a row
For this application, the user can change values in one or more table window rows. However, the changes are
not made in the data source until the user selects the Apply Changes menu item. The following steps are
executed in the Menu Actions section to UPDATE one or more rows in the database that the user changed:

393
1. The user might not have moved the cursor off an updated row. Call SalTblKillEdit to (indirectly) force the
validation of the value entered by the user:
Call SalTblKillEdit( twCompanyInfo )
2. For a SQL database, call SqlPrepare and specify an UPDATE statement.
Call SqlPrepare( hSqlB,'UPDATE COMPANY ' ||
'SET NAME = :twCompanyInfo.csName, ' ||
...
'FAX = :twCompanyInfo.csFAX ' , ||
'WHERE CURRENT OF C' )
The column names in the SET clause are qualified with the table window handle (:twCompanyInfo.*). This
tells SQLWindows to use the value for the columns in the row that has the context.
3. Set the table window row number to TBL_MinRow:
Set nIndex = TBL_MinRow
4. In a loop, search for updated rows to process:
Loop

If SalTblFindNextRow( twCompanyInfo, nIndex, ROW_Edited, 0 )


Call SalTblSetContext( twCompanyInfo, TBL_TempRow )
Call SqlFetchRow( hSqlA, nIndex, nFetchResult )
Call SalTblSetContext( twCompanyInfo, nIndex )
Call SqlExecute( hSqlB )
Call SalTblSetRowFlags( twCompanyInfo, nIndex, ROW_Edited, FALSE )
Else
Break
 Call SalTblFindNextRow to find the next row with the ROW_Edited flag set to TRUE. The second
parameter is the table window row number where to start the search (this was set to TBL_MinRow in
the previous step). When it finds a row with the ROW_Edited flag set to TRUE, SalTblFindNextRow
returns the row number in this parameter. The third parameter specifies the flag (ROW_Edited) that
the row has. The fourth parameter specifies flags that the row does not have; this is not appropriate
for this application, so zero is specified. The loop repeats until there are no more rows with the
ROW_Edited flag set TRUE.
 Call SalTblSetContext to set the context to TBL_TempRow.
 Call SqlFetchRow. SQLWindows fetches the row pointed to by the second parameter from the
database. However, instead of fetching the column values into the row indicated by the second
parameter, the values are fetched into TBL_TempRow. This step synchronizes the table window row
with the corresponding result set row.
 Call SalTblSetContext to set the context back to the table window row.
 Using the data from the table window cells, process the update in the data source (such as an array,
variables, or a flat file).
 For a SQL database, call SqlExecute.
 Call SalTblSetRowFlags to clear the ROW_Edited flag for the processed rows. The third parameter is
the flag to set to FALSE (ROW_Edited in this case). The fourth parameter specifies the setting for the
flag (FALSE means off).
5. For a SQL database, COMMIT or ROLLBACK after updating the row in the database.

394
Context Row
The context row is the row whose individual column values are referenced when used as variables. When a
user edits a table, the context row is the row being edited. The context row is usually the same as the row
that has the focus, but it can be different.
Internally, SQLWindows numbers each row beginning from zero. The context row identifies the row number
that is addressed when you refer to a table window column.
The context row is the row used when you refer to a column name in:
• SQL statements
• Function calls
• Set statements
• Comparisons
For example, in the following statement, :twCompanyInfo is the table window handle and colName is a
column in the table window. A name such as this refers to a cell in the current context row:
Set varName = :twCompanyInfo.colName
SQLWindows sets the context row (in lParam) when it sends a SAM_FetchRow message to a table window.
Changing the context row does not affect the focus row.
You can set the context row with SalTblSetContext. This function does not fetch a row automatically if it is not
already in the table window cache. If the context row is set to a row not already in cache, a blank row appears
in the table window. To avoid this, use SalTblFetchRow to set the context.
Rows are normally numbered 0 to 2,147,423,631. However, for a split-window (described later in this
chapter):
• Rows in the top-half of the table window are numbered 0 to 2,147,423,631.
• Rows in the lower-half of the table window are numbered -2,147, 423,630 to -1.
For more information, see Table Window Cache on page 403.

Populating a Table Window


The section in this chapter called Programming Techniques showed the steps to follow to populate a table
window. This section provides more detail on populating a table window.
Populating a table window means:
• Filling the rows in the visible portion of the table window with data (such as when the application starts)
• Filling rows in the table window with data when the user (or the application) scrolls
You can populate a table windows in two ways:
• SalTblPopulate (simple technique), which populates a table window with a result of a database query
• SalTblSetRange (advanced technique), which populates a table window with data from any source
For the advanced technique, the data for a table window can come from one or more of the following
sources:

395
• Database tables
• Flat files
• Arrays
• Variables
• Constants

Populating with SalTblPopulate (Simple Technique)


The following example tells SalTblPopulate to populate the visible rows in the table window and then
populate additional rows as the user scrolls:
Call SalTblPopulate( tblCompanyInfo, hSqlA, '', TBL_FillNormal )
In order, the parameters are:
• Table window handle.
• Sql Handle.
• SELECT statement. If you have already prepared the SELECT statement, specify an empty string (' '). If you
have not prepared the SELECT statement, specify it in this parameter.
• A constant that specifies how to populate the table:

Constant Description

TBL_FillAll Populates the entire table window.

TBL_FillNormal Populates only the visible portion of the table window. Additional rows are
populated as the user scrolls them into view.
TBL_FillAllBackground Populates the visible portion of the table window and returns control to the
application. Additional rows are populated at a rate of 4 per second. Once all rows
have been populated, the table window receives a SAM_FetchDone message.

The following example prepares the SQL statement before calling SalTblPopulate:
Table Window: tblExample
Message Actions
...
On SAM_Create
Set strSql = 'select name, trainer, room from guest_roster' ||
' into :tblExample.colname, ' ||
':tblExample.colTrainer, :tblExample.colRoom'
Call SqlPrepare( hSql, strSql )
Pushbutton: pbPopulate
...
Message Actions
On SAM_Click
Call SalTblPopulate( tblExample, hSql, ' ', TBL_FillNormal )
The following are examples of how you can use SalTblPopulate:
• To fill a table window with the results of a SELECT one time. You provide a SELECT statement and
SalTblPopulate compiles, executes, fetches, and fills the table window.
• If you do not specify an INTO clause, SalTblPopulate creates columns automatically.

396
• To fill a table window many times using the same SELECT statement, but with different WHERE criteria.
This is useful for a detail table window in a master-detail application or for query-by-example (QBE). You
do not supply a SELECT statement for SalTblPopulate, but you do supply a Sql Handle that has a prepared
SELECT already (call SqlPrepare or SqlRetrieve first). SalTblPopulate binds (for the new criteria), executes,
fetches, and fills the table window. This avoids recompiling the SELECT.
These are the steps that SalTblPopulate follows if you specify a non-null string in the strSelect parameter:
• SqlPrepare
• Bind (gets the current values of bind variables)
• SqlExecute
• Fills table window (how it does this depends on the constant you specify in the third parameter)
These are the steps that SalTblPopulate follows if you specify a null string in the strSelect parameter:
• Bind (gets the current values of bind variables)
• SqlExecute
• Fills table window
Is it not efficient to call SqlPrepareAndExecute and then call SalTblPopulate with a null strSelect parameter.
Instead use SqlPrepare (or SqlRetrieve) because SalTblPopulate performs the bind and execute before
fetching.
You can find the number of rows that the SELECT returned by calling SqlGetResultSetCount.
You can process these messages when using SalTblPopulate:
• SQLWindows sends SAM_FetchRow is sent to the table window before
• fetching a row
• SQLWindows sends the SAM_FetchRowDone message after fetching a row, so you can perform additional
processing on the fetched values
• SQLWindows sends SAM_FetchDone after all rows have been populated by SalTblPopulate with the
TBL_FillAllBackground option

Populating with SalTblSetRange (Advanced Technique)


The table range is the number of rows in the table window. The table range can be smaller or larger than the
number of rows visible on the screen.
Set the table range by calling SalTblSetRange:
SalTblSetRange( hWndTbl, 0, nMaximum )
In order, the parameters are:
• Table window handle
• The lower bound of the table range
• The higher bound of the table range
To create an empty table window, set the second and third parameters to 0 and -1:
SalTblSetRange( hWndTbl, 0, -1 )
To set a dynamic table range, set the second and third parameters to 0 and TBL_MaxRow:
397
SalTblSetRange( hWndTbl, 0, TBL_MaxRow )
A dynamic table range has some important features that are discussed in a separate section.
When you call SalTblSetRange, SQLWindows sends one SAM_FetchRow message for each visible row in the
table window. The application does two things to process SAM_FetchRow messages:
• Gets the data from the source
• Assigns the data values to the table window columns
When the user scrolls in a table window and a row needs to be displayed that is not currently in the cache,
SQLWindows sends a SAM_FetchRow message to the table window for each row.

SAM_FetchRow Message
SQLWindows sends this message to a table window for each row in the table range that needs to be fetched
(from the data source) if the row is not already in the cache.
SQLWindows sends a SAM_FetchRow to a table window when a row must be copied into the table window
cache:
• When the application first displays a table window, SQLWindows sends a SAM_FetchRow message for
each row that is visible on screen
• As the user scrolls, SQLWindows sends a SAM_FetchRow message for each row
SQLWindows assigns lParam to be the row number for a SAM_FetchRow message.
If the source of data is a SQL database, you process a SAM_FetchRow message by calling SqlFetchRow to
retrieve the row into the table window based on the row number in lParam.
SqlFetchRow returns TRUE or FALSE, and updates a fetch indicator variable that specifies the status of the
fetch. SQLWindows stops sending SAM_FetchRow messages when you return FALSE. The fetch indicator
variable can be one of these values:

Constant Description
TBL_NoMoreRows Row could not be fetched and there are no more rows
TBL_RowDeleted Row was not fetched because it has been deleted
TBL_RowFetched Row was successfully fetched

For example:
Table Window: twTabWinEmployee
...
Message Actions
On SAM_FetchRow
! The table window needs a row to be fetched from the
! database
If SqlFetchRow( hSql, lParam, nFetch )
If nFetch = FETCH_Delete
Return TBL_RowDeleted
Else
Return TBL_RowFetched
Else
Return TBL_NoMoreRows
If the source of data is not a SQL database, process a SAM_FetchRow message by retrieving the data from its
source and assigning it to columns in the current row.
398
Important: Setting a breakpoint on a statement that executes while processing a SAM_FetchRow message
can cause incomplete painting of the table window.
The following example uses an array to populate a table window:
Table Window: twStuff
...
Message Actions
On SAM_Create
! Set up tw_array ...
...
Call SalQueryArrayBounds (tw_array, nMin, nMax)
...
Call SalTblReset (twStuff)
! Use tw_array size to set table range
Call SalTblSetRange (twStuff, nMin, nMax)
On SAM_FetchRow
! Assign tw_array fields to table window columns
Set twStuff.col1 = tw_array[lParam]
The example sets the table range to the number of elements in the array. This means that SQLWindows sends
exactly the number of SAM_FetchRow messages as there are elements in the array. For applications that
cannot set the table range to the exact size of the data source, return TBL_NoMoreRows during
SAM_FetchRow processing to signal that there is no more data to fetch.

Using SAM_FetchRow and SAM_FetchRowDone with SalTblPopulate


If you process SAM_FetchRow and Return after calling SalTblPopulate, SalTblPopulate does not fetch that row
into the table window. If you process SAM_FetchRow but do not Return, SalTblPopulate does fetch the row
into the table window.
SQLWindows sends SAM_FetchRow before fetching the row from the result set. Therefore, you cannot refer
to the row you are trying to retrieve in the SAM_FetchRow message processing because SQLWindows has not
fetched it yet.
SQLWindows sends the SAM_FetchRowDone message to the table window after fetching the row. Therefore,
you can refer to the row you are trying to retrieve in the SAM_FetchRowDone message processing because
SQLWindows has already fetched it. The lParam for SAM_FetchRowDone is the row number fetched.

Using SalTblPopulate with Stored Commands


If you call SqlPrepare or SqlRetrieve for a stored command before you call SalTblPopulate, set the strSelect
parameter for SalTblPopulate to null ('') to use the compiled command. If the strSelect parameter is null,
SalTblPopulate looks for a previously-prepared command on the Sql Handle.
This example shows how to call SalTblPopulate for a stored command:

399
Call SqlStore( hSql, 'mystoredfunction', 'SELECT build FROM guests')
...
Call SqlRetrieve( hSql, 'mystoredfunction', 'build', ':tbl1.col1')
...
Call SalTblPopulate( tbl1, hSql, '', TBL_FillNormal)

Dynamic Table Windows


Dynamic table windows let you use table windows without defining as much about them at design time.

SalTblPopulate
There are two ways to use SalTblPopulate with dynamic table windows:
• You can call SalTblPopulate for a table window that does not have columns. SQLWindows creates the
columns at runtime based on the columns in the query. This feature only works if the table window does
not have columns.
• You can call SalTblPopulate and specify a SELECT statement that does not have an INTO clause. The table
window must have the correct number of columns and the data types of the columns must match those
in the query. SQLWindows automatically assigns the query columns to the table window columns.
SalTblPopulate destroys automatic columns before populating a table window. This means that
SalTblPopulate can populate a table window with different queries which were not assigned columns at
design time.

SalTblCreateColumn and SalTblCreateColumnEx


These functions create a table window column automatically at runtime:
bColID = SalTblCreateColumn( hWndTbl, nColumnPos,
nDispWidth, nMaxChars, strTitle )
bColID = SalTblCreateColumnEx( hWndTbl, nColumnPos,
nDispWidth, strTitle, nMaxChars, nDatatype)
The columns that this function creates are not available at design time.
SQLWindows assumes that the data type of a column you create with SalTblCreateColumn is String. If you
want to specify the datatype yourself, use SalTblCreateColumnEx.
If you set Discardable attribute to Yes, SQLWindows discards rows when you call these functions. If you set
Discardable to No, SQLWindows expands rows when you call these functions.

SalTblDestroyColumns
This function destroys columns that SalTblCreateColumn or SalTblPopulate created:
SalTblDestroyColumns( hWndTbl )
This function only destroys automatic columns created by SalTblCreateColumn. This function returns FALSE if
the table window does not contain automatic columns.

400
Referring to Automatic Columns
Refer to automatic columns with the column identifier (position of a column in the outline or its order of
creation). Use the ‘#’ character as a separator between the table window name and the column number:
tblMain#1 The first column of tblMain
frm1.tbl1#3 The third column of tbl1, a child table of frm1

Messages
SQLWindows sends SAM_Validate to a table window itself when the user edits an automatic column created
by SalTblPopulate. This is needed because automatic table columns do not exist in the outline. You can use
hWndItem to get the handle of the automatic column.
SQLWindows sends SAM_FetchRowDone to a table window when one row has been populated. The lParam
for this message is the row number that was populated. SQLWindows ignores any value you return when you
process this message.

Sum, Average, and Sort Functions


This function computes the sum of the values of a table window column:
nSum = SalTblColumnSum( hWndTbl, nColumnID, nFlagsOn, nFlagsOff )
The nFlagsOn and nFlagsOff parameters are row flags that specify rows to include in the sum (such as all
modified rows).
This function computes the average value of a table window column:
nAverage = SalTblColumnAverage( hWndTbl, nColumnID, nFlagsOn, nFlagsOff )
The nFlagsOn and nFlagsOff parameters are row flags that specify rows to include in the average (such as all
modified rows).
This function sorts a table window:
bRet = SalTblSortRows( hWndTbl, nColumnID, nOrder )
The nColumnID parameter identifies the sort key column. The sort key column cannot be an automatic
column. The nOrder parameter specifies the direction of the sort: TBL_SortIncreasing (default) or
TBL_SortDecreasing.
The table window cache must not be discardable and the setting of maximum rows in memory must be large
enough to hold the rows that you are sorting (see Table Window Cache on page 403).

Table Range
The table range defines the number of rows in the table window. A table window can have a static range or a
dynamic range.

401
Static Table Range
You make the table range static by calling SalTblSetRange and specifying a number for the third parameter:
SalTblSetRange ( hWndTbl, 0, nRows )
With a static table range, SQLWindows knows the row number when the user moves the slider box to the
bottom of the vertical scroll bar.

Dynamic Table Range


A dynamic table range allows a table window to be displayed before the row count is known. Use a dynamic
table range when determining the row count is time- consuming.
With a dynamic table range, the table window determines the table range incrementally. For example,
assume you set a dynamic range and the source of data is a database table with 100 rows. If you fetch 20
rows into the table window and then call SalTblSetRowFlags for row 50, SQLWindows does not know if row 50
exists, so it fetches rows 21 through 50.
Make the table range dynamic by calling SalTblSetRange and specifying TBL_MaxRow for the third parameter:
SalTblSetRange ( hWndTbl, 0, TBL_MaxRow )
...
On SAM_FetchRow
If DoFetch( hWndTbl )
Return TBL_RowFetched
Else
Return TBL_NoMoreRows
The actual number of rows in the table window is determined when TBL_NoMoreRows is returned to the
application.
With a dynamic table range, SQLWindows does not know the row number when the user moves the slider
box to the bottom of the vertical scroll bar. As a result, when the user attempts to move the slider to the
bottom, SQLWindows sends a SAM_CountRows message to the table window.
You can use a dynamic table range for a split table window where the user displays existing rows in the top
half of the table window and inserts new rows in the lower half of the table window.
Scroll bar operation is not as smooth as it is with a static scroll range.

SAM_CountRows Message
SQLWindows sends this message to a table window when both of the following are true:
• The table window has a dynamic scroll range
• The user moves the scroll box to the bottom of the vertical scroll bar
Process a SAM_CountRows message by returning the number of rows in the table. For example:
• Count the number of rows in a result set (SqlGetResultSetCount)
• Count the number of records in a flat file
• Determine the number of elements in an array
The application is not required to process this message. If the application does not process this message,
SQLWindows sends SAM_FetchRow messages until the application returns TBL_NoMoreRows. However, the
application performs better if it processes SAM_CountRows.

402
SAM_CountRows does not use lParam.
The following example calls SalTblSetRange and specifies TBL_MaxRow in the third parameter (dynamic table
range). When the user moves the slider box to the bottom of the vertical scroll bar, SQLWindows sends a
SAM_CountRows message to the table window.
The application calls SqlGetResultSetCount and returns the number of rows.
Table Window: tblEmployee
...
Message Actions
On SAM_Create
Call SqlPrepare( hSqlPrimary, strSqlTableWindow )
Call SqlExecute( hSqlPrimary )
Call SalTblReset( hWndForm )
Call SalTblSetRange( hWndForm, 0, TBL_MaxRow )
On SAM_CountRows
! Count the number of rows in the result set.
Call SqlGetResultSetCount( hSqlPrimary, nRowCount )
Return nRowCount

Table Window Cache


The table window cache is the memory used to store rows that are in the table window.
Theoretically, there can be up to 2,147,423,632 rows in the table window cache at any one time. However,
the actual maximum size of the table window cache is dependent on the available resources provided by the
operating system. With contemporary hardware and operating systems, the realistic maximum number of
rows varies between 100,000 to 200,000 depending on available RAM and the amount of memory needed to
store a single row. When the cache fills, SQLWindows discards rows as additional rows are fetched.
The table window cache is independent of:
• SQLBase input message buffer
• Backend and frontend result sets
• Disk cache
Although the theoretical maximum capacity of a table window is 2,147,423,632 rows, the limiting factors are:
• The size for the cache you set for the Max Rows in Memory item in the Attribute Inspector. The number
that you specify is the maximum number of rows that can be in the cache at any one time. The default
value is 100 rows.
• System memory.
• The amount of memory required to store one row.
The cache and other limiting factors determine how many rows can be in a table window at any one time.
However, if the table window cache is discardable, the table window can theoretically address 2,147,423,632
rows in the top half and 2,147,423,632 rows in the bottom half.
Rows are normally numbered 0 to 2,147,423,631. However, for a split-window (described later in this
chapter):
• Rows in the top-half of the table window are numbered 0 to 2,147,423,631.
• Rows in the lower-half of the table window are numbered -2,147,423,630 to -1.

403
When SQLWindows Fetches Rows into the Cache
For both static and dynamic table ranges, SQLWindows sends a SAM_FetchRow message to a table window at
these times:
• When the table window needs to display a row that is not in the cache
• When the application calls SalTblFetchRow and the row is not in the cache
An exception to these rules is made for a dynamic table range. SalTblSetContext, SalTblFindNextRow,
SalTblFindPrevRow, and SalTblSetRowFlags cause SQLWindows to send a SAM_FetchRow message if the row
has not already been fetched.

When SQLWindows Discards Rows from the Cache


Whether or not rows are discardable from the cache depends on the Discardable? attribute setting for the
table window.
SQLWindows discards rows from the cache when a row needs to be fetched and the cache limit has been
reached if:
• The Discardable attribute is set to Yes.
• The Max Rows in Memory attribute defines a cache limit. This limit applies to all rows except those with a
modified (ROW_Edited) flag and those with an inserted (ROW_New) flag. Modified and inserted rows are
only discarded when they are deleted. This is also true for rows that have their text color set to a color
other than the default table text color. The only rows in this category that are discardable are those
whose color is set with SalTblSetCellTextColor and whose last parameter of this function is TRUE.
SalTblReset sets cache to zero rows, which results in all rows being discarded.
If you try to fetch a row already in the cache, but the user has changed the row without applying an UPDATE,
SQLWindows sends SAM_CacheFull if:
• The Discardable item is set to yes.
• All rows in the table have been edited or UPDATEd This ensures that you do not lose uncommitted
changes.

SAM_CacheFull Message
SQLWindows sends this message to a table window when a row is to be fetched, but the table window cache
is full and SQLWindows cannot discard any rows.
SQLWindows sends a SAM_CacheFull message to the table window when scrolling if:
• The Maximum Rows in Memory value has been reached.
• The Discardable item is set to No.
The minimum value for rows in memory is 78, regardless of the maximum number of rows in the memory
item setting. The theoretical maximum value for rows in memory is 2,147,423,632 (see Table Window Cache
on page 403).
The lParam for SAM_CacheFull is the row number the table window tried to fetch.

404
Table Window Flags
A table window has flags that define its properties and capabilities. The flags are represented by SQLWindows
constants that start with TBL_Flag_*. You get and set the flags in the table below by calling
SalTblSetTableFlags and SalTblQueryTableFlags.

Constant Default Description


TBL_Flag_EditLeftJustify FALSE By default, when a user edits a cell, SQLWindows justifies the text
as defined for the column. For example, when a user edits a right-
justified column, SQLWindows right-justifies the text. For right-
justified and centered cells, the user cannot enter more text than
can fit in the cell. When TBL_Flag_EditLeftJustify is TRUE, then
SQLWindows always left justifies cell text when the user edits.
TBL_Flag_GrayedHeaders TRUE Uses same color and shading for column headings and row
headings as used for push buttons. This hides the row header.
TBL_Flag_HScrollByCols TRUE Users can horizontally scroll a column at a time. Otherwise,
horizontal scrolling is a character at a time.
TBL_Flag_MovableCols TRUE Users can drag-move columns at runtime.
TBL_Flag_SelectableCols FALSE Users can select columns by clicking the column title.
TBL_Flag_ShowVScroll FALSE Displays the vertical scroll bar all the time. Otherwise, it is only
displayed when there are more rows than displayed in the table
window.
TBL_Flag_ShowWaitCursor TRUE When TRUE, SQLWindows displays a wait cursor while responding
to a user action that scrolls the table window (such as when the
user presses the PgUp, PgDn, Home, or End key, or when the user
clicks the vertical scroll bar).
Functions such as SalTblScroll do not display a wait cursor
automatically. You must call SalWaitCursor before and after calling
Sal* functions.
TBL_Flag_SingleSelection FALSE When TRUE, users can only select one row at a time in the table
window.
TBL_Flag_SizableCols TRUE Users can drag-size columns at runtime.
TBL_Flag_SuppressLast- FALSE When TRUE, SQLWindows does not display the last vertical column
ColLine separation line.
TBL_Flag_SuppressRow- FALSE When TRUE, SQLWindows does not display the dotted lines
Lines between rows.

Row Flags
Each row has flags that define the properties of the row. The ROW_* constants represent row flags:

Constant Description
ROW_Edited Row has been edited.

405
Constant Description
ROW_Hidden Row is hidden.
ROW_HideMarks Do not use the symbols in the default row header. See Row Header on page 413.
ROW_MarkDeleted Row is marked for deletion.
ROW_New Row is newly inserted.
ROW_Selected Row is selected.
ROW_UnusedFlag1 Application defined.
ROW_UnusedFlag2 Application defined.

Row flags are not stored with data in the table window cache, so even if a row is swapped out, row flags are
lost.
A row can have more than one flag set to TRUE. For example, after the user edits a newly-inserted row, it has
both the ROW_New and the ROW_Edited flags set to TRUE.
The loop in the following example uses SalTblFindNextRow to search for rows with the ROW_New flag set to
TRUE. Once SQLWindows finds a row with ROW_New set to TRUE, SalTblSetRowFlags clears (sets to FALSE)
the ROW_New and the ROW_Edited flags:
Loop
Set nRow = TBL_MinRow
If NOT SalTblFindNextRow( tblCompanyInfo, nRow, ROW_New, 0 ) Break
Call SalTblSetRowFlags( tblCompanyInfo, nRow, ROW_New | ROW_Edited, FALSE )
The code in the loop above can be done in one call to SalTblSetFlagsAnyRows:
Call SalTblSetFlagsAnyRows(tblCompanyInfo,
ROW_New | ROW_Edited, FALSE, ROW_New, 0 )
This example determines if there are any rows that the user has inserted or changed:
If SalTblAnyRows( tblCompanyInfo, ROW_New | ROW_Edited, 0 )
! Do something
You can define your own use for the flags ROW_UnusedFlag1 and ROW_UnusedFlag2. To assign a meaningful
name to these flags, define a constant as follows:
Constants
User
Number: ROW_MyFlag = ROW_UnusedFlag1

Column Flags
Use these constants to specify column properties for SalTblSetColumnFlags and SalTblQueryColumnFlags:

Constant Description
COL_Editable Users can edit text.
COL_RightJustify Right-justify or center text.
COL_CenterJustify Only set one of these flags to TRUE at the same time. If neither flag is set to
TRUE, the column if left-justified.
COL_Selected Column is selected.

406
COL_IndicateOverflow Fill the column cell with '#' when the text does not fit (except when the cell has
the focus).

TBL_Error Constant
SQLWindows returns TBL_Error when a table window function is unsuccessful.

TBL_* Constants
These constants are the starting and ending row numbers in a table window:

Constant Description
TBL_MaxRow Highest row number
TBL_MinRow Lowest row number
TBL_MinSplitRow Low row number in bottom half of a split table window

Use TBL_MinRow and TBL_MaxRow with SalTblFindNextRow and SalTblFindPrevRow to search for rows from
the beginning or end of the table window respectively.
You can use TBL_MinRow to append a row to the bottom half of a split window:
Set nIndex = SalTblInsertRow( tblCompanyInfo, TBL_MinRow )
You can use TBL_MaxRow to append a row to the top half of a split table window:
Set nIndex = SalTblInsertRow( tblCompanyInfo, TBL_MaxRow )
You can also use TBL_MinRow with SalTblSetFocusRow to set the focus to the first row in the split window,
and use TBL_MaxRow with SalTblSetRange (see Split Windows on page 415).

Table Window Messages


This section explains messages for table windows that are not explained elsewhere in this chapter.

Window Handles and Message Parameters


Whether you create a top-level table window or a child table window, the value of hWndForm is set to the
handle of the table window whenever a message is processed in a table window or in the table windows
Message Actions itself.
The lParam for a message usually contains the row number.
When you refer to a column value, the value at the current row number (context) is used.

407
Messages Sent Only to Table Windows
SQLWindows sends the messages below only to table windows, and in some cases, to the relevant table
window column.
For all of these messages, lParam contains the context row.

SAM_CaptionDoubleClick
SQLWindows sends this message to a table window and a table column when the user double-clicks a column
title.
For this message, wParam is the column window handle. You can use SalNumberToWindowHandle to
get the window handle from wParam.

SAM_ColumnSelectClick
SQLWindows sends this message to a table window and column window when the user selects or deselects a
column by clicking the column title. TBL_Flag_Selectable must be TRUE (default).
For this message, wParam is the column window handle.

SAM_EndCellTab
SQLWindows sends this message to a table window when the user tries to tab past the last editable cell in the
table window. The application must return TRUE if it processes this message.
This example shows how to use SAM_EndCellTab to insert a row when the user tabs past the last row in the
table.
Table Window: tbl1
...
Message Actions
On SAM_EndCellTab
Call SalTblInsertRow( hWndForm, TBL_MaxRow )
Return TRUE
The user must be positioned in the last editable cell of the last row.

SAM_RowValidate
SQLWindows sends this message when the user tries to move the focus off a row:
Table Window: tbl1
...
Message Actions
On SAM_RowValidate
If SalIsNull( col1 )
Call SalMessageBox( 'You must enter a value',
'Validation Error', MB_Ok )
Return VALIDATE_Cancel
Else
Return VALIDATE_Ok

Row header messages


See Row Header on page 413.

408
Other table window messages
SQLWindows sends the messages below to table windows and to other objects. Considerations for table
windows are discussed below.
For all of these messages, lParam contains the context row.
See Chapter 9 – Messages.

SAM_AnyEdit
SQLWindows sends this message to a table window and column when the user edits a cell.

SAM_Click
SQLWindows sends this message to the table window and the non-editable column when the user clicks in a
non-editable column.

SAM_DoubleClick
SQLWindows sends this message to a table window and the non-editable column when the user double-
clicks a non-editable column.
If the user double-clicks a non-editable column, SQLWindows sends the table window and the non-editable
column:
• SAM_Click
• SAM_DoubleClick

SAM_KillFocus and SAM_SetFocus


SQLWindows sends SAM_SetFocus to the table window and the editable column when the user clicks in an
editable column.
Clicking an editable column sets the focus there.
When the focus changes, SQLWindows first sends SAM_KillFocus to a table window and then SAM_SetFocus:
• The wParam of SAM_KillFocus is the window handle of the column getting the focus and the lParam is the
row number getting the focus
• The wParam of SAM_SetFocus is the window handle of the column losing the focus and the lParam is the
row number losing the focus
When the focus changes, SQLWindows sends SAM_KillFocus to the column losing the focus and
SAM_SetFocus to the column getting the focus.

SAM_FieldEdit
SQLWindows sends this message to a table window and column when the user edits a column and moves the
focus away from the cell.

SAM_Validate
SQLWindows sends this message to a table window column when the user changes the value of the item
and then moves the focus away from that item, or when the user changes the value of the item and then
calls SalSendValidateMsg or SalTblKillEdit.

409
SAM_Close
SQLWindows sends a top-level table window this message when the user chooses the Close Menu item from
the system menu of the table window.
SQLWindows does not send a SAM_Close message to a child table window because a child table window does
not have a system menu and cannot be closed.

Extended GUI Functions


In addition to the regular functions with names beginning with SalTbl*, there is a group of Visual Toolchest
functions that let you manipulate the appearance of an entire table, a table row or row header, a table
column or column header, or an individual table cell.
To make this group of functions available to your application, do a File Include for GTABLEX.APL in the
Libraries section of your outline. For documentation of these functions, search index entry “Table Window
Extended GUI ” in SQLWindows online help.

Setting the Focus Row


You can set the focus row by calling one of these functions:
• SalTblSetFocusRow
• SalTblSetFocusCell
• SalTblSetRow
Call SalTblKillFocus to turn off the focus frame.
Changing the focus row also changes the context row (the context follows the focus).

Focus Cell
Use SalTblKillEdit to end editing and force SQLWindows to validate (check the data against the column data
type). After calling SalTblKillEdit, the table window is in row mode.
You can also call SalSendValidateMsg to force SQLWindows to validate the data. After calling
SalSendValidateMsg, the table window is in cell mode.

Deselecting All Rows


SalTblClearSelection deselects all rows in a table window.

410
Finding the Visible Range
You can find the starting and ending row number of the currently-displayed rows by calling
SalTblQueryVisibleRange.

Scroll Position
The scroll position is the top-most visible row in the table window. To find the current scroll position, call
SalTblQueryScroll.
You can change the scroll position by calling SalTblScroll. These constants specify table scrolling for
SalTblScroll:

Constant Description
TBL_AutoScroll Scroll as needed so that the row is visible
TBL_ScrollBottom Scroll the row to the bottom of the table window
TBL_ScrollTop Scroll the row to the top of the table window

Table Window Title


Only top-level table windows have a title. At design time, you set the title of the table window in the
Attribute Inspector. At runtime, call SalGetWindowText to find the current title of a table window. You can
change the title of the table window by calling SalSetWindowText.

Table Window Font


At design time, you can set the font for a table window in the Attribute Inspector.
At runtime, you can change the font for a table window with SalFontSet. Changing the font:
• Resizes top-level table windows.
• Resizes columns to display approximately the same number of characters.
The font you set with the Attribute Inspector or with SalFontSet applies to the entire table window. You
cannot set the font for an individual column. Call SalFontGet to find the current font of the table window.

Table Window Color


At design time, you can set the color for a table window in the Attribute Inspector.
At runtime, you can change the background color and text color of a table window with SalColorSet.
You can change the color of an individual cell's text by calling SalTblSetCellTextColor.
411
You cannot set the background color for an individual column.
To find the color of the current table window or cell text, call SalColorGet.

Column Title
To find the current column title, call SalTblGetColumnTitle. To set a new column title, call
SalTblSetColumnTitle.

Column Width
Call SalTblQueryColumnWidth to get the current column width. Set a new column width by calling
SalTblSetColumnWidth.

Column Identifier and Column Position


SQLWindows has two ways to identify a column:
Column position. A column position is its visual position. A column position is a relative, changeable number
associated with a column. The first (left-most) column in a table window is column position one, the one to its
immediate right is column position two, and so on. If you or a user changes the order of the columns, their
positions change to reflect the visual order.
Column identifier. A column identifier is the position of a column in the outline or its order of creation. A
column identifier is a permanent, non-changing number associated with a column. The first column created is
column one, the next column two, and so on. A column identifier does not change if you or a user changes
the order of the columns.
You pass a column position to these functions:
• SalTblCreateColumn
• SalTblGetColumnWindow
This function returns a column position:
• SalTblQueryColumnPos
You pass a column identifier to these functions:
• SalTblColumnAverage
• SalTblColumnSum
• SalTblGetColumnText
• SalTblGetColumnWindow
• SalTblSetColumnPos
• SalTblSetColumnText
• SalTblSortRows
412
These functions return a column identifier:
• SalTblCreateColumn
• SalTblQueryColumnID
You can also use column identifiers in references.
To get the window handle of a column, call SalTblGetColumnWindow and specify either the column identifier
or the column position.

Referring to Table Window Columns by Identifier


You can refer to a table window column with its identifier (position of the column in the outline or its order of
creation) instead with its name. This is useful for columns you create dynamically with SalTblCreateColumn
because these columns do not have a name.
Use the ‘#’ character as a separator between the table window name and the column number. For example:
tblMain#1 The first column of tblMain
frm1.tbl1#3 The third column of tbl1, a child table of frm1

Locking Columns
You can lock columns on the left-side of a table window. Locked columns do not scroll horizontally. Columns
to the right of locked columns appear to scroll under the locked columns.
You lock columns with SalTblSetLockedColumns:
Call SalTblSetLockedColumns( hWndTbl, 2 )
The example above locks the left-most two columns in the table window.
Before calling SalTblSetLockedColumns, you can call SalTblSetColumnPos to move columns to the left side of
the table window.
Call SalTblQueryLockedColumns to find out how many columns are locked. The user can edit the data in the
cells of an editable locked column.
The user cannot:
• Move a locked column.
• Move an unlocked column on top of a locked column.

Row Header
The row header is a non-editable column fixed on the left side of the table window. A row header can display
a row number or other value (key) that identifies the data in the row.
You can set row header properties with SalTblDefineRowHeader:

413
Call SalTblDefineRowHeader(hWndTbl, strTitle, nWidth, TBL_RowHdr_Visible |
TBL_RowHdr_ShareColor, colRowHeader )
In order, the parameters are:
• Table window handle
• Title of the row header
• Width of the row header
• Properties for the row header (TBL_RowHdr_*)
• Window handle of a table window column that is mirrored in the row header
You can determine row header properties with SalTblQueryRowHeader.

Row Header Messages


Clicking a row header
When a user clicks a row header in a table window, SQLWindows only sends SAM_RowHeaderClick and not
SAM_Click.

SAM_RowHeaderClick
SQLWindows sends this message to a table window when the user clicks a row header. For this message,
lParam is the context row.

SAM_RowHeaderDoubleClick
SQLWindows sends this message to a table window when the user double-clicks a row header. For this
message, lParam is the context row.

SAM_CornerClick
SQLWindows sends this message to a table window when the user clicks the title of a row header. The row
header title is in the upper-left hand corner of the table window.

SAM_CornerDoubleClick
SQLWindows sends this message to a table window when the user double-clicks the title of a row header. The
row header title is in the upper-left hand corner of the table window.

Row header flags


Use these constants to specify row header properties for SalTblQueryRowHeader and
SalTblDefineRowHeader:

Constant Description
TBL_RowHdr_Sizable Users can drag-size the row header.
TBL_RowHdr_Visible Row header is visible. Set this to FALSE to hide the row header.
TBL_RowHdr_ShareColor Sets the row header color to the text color of the cells. If
TBL_RowHdr_ShareColor is FALSE, the row header uses the table window's
default text color.

414
Constant Description
TBL_RowHdr_MarkEdits Displays a graphic depending on the setting of the row flags:
4 – Row is modified (ROW_Edited).
7 – Row is marked for deletion (ROW_MarkDeleted).
‹ – Row is new (ROW_New). This is the default row header.
Use ROW_HideMarks to turn off the symbols.

Split Windows
A table window can be split horizontally. The lower-half of a split table window can be used to insert new
rows or to display dynamic summary data. You split a table window horizontally using
SalTblDefineSplitWindow:
Call SalTblDefineSplitWindow( hWndTbl, 3, TBL_Split_Adjustable )
In order, the parameters are:
• Table window handle.
• Number of rows in the lower-half of the table window.
• The TBL_Split_Adjustable constant is the row header flag passed as the last parameter of
SalTblDefineSplitWindow. If set to TRUE, this enables the user to drag-adjust the number of visible rows
in the upper and lower halves of the split window.

If you specify TBL_Split_Adjustable, when the user moves the mouse pointer to the black
bar (splitter bar) between the upper and lower part of the table window, the mouse
pointer changes to the “splitter” on the left. A user can drag up or down to change the size
of a split window.

Call SalTblQuerySplitWindow to determine the number of rows in the lower-half of a split table window.

Row numbering in split windows


Rows in the top-half with the table window are numbered 0 to 2,147,423,630. Rows in the lower-half of the
table window are numbered -2,147,423,630 to -1 (see Table Window Cache on page 403).

Using a dynamic table range with a split window


You can use a dynamic table range for a split table window where the user displays existing rows in the top
half of the table window and inserts new rows in the lower half of the table window.

Inserting new rows into a split table window


The table below shows the values that you can set in the last parameter for SalTblInsertRow:

Value Description
Zero (0) Inserts a new row at the top of the upper half of a split table window
TBL_MaxRow Appends a new row to the upper half of the split table window
TBL_MinSplitRow Inserts a new row at the top of the lower half of a split table window
TBL_MinRow Appends a new row to the lower half of a split table window
415
Using the Clipboard with Table Windows
You use the SQLWindows functions in the table below to cut and paste with the Clipboard. SQLWindows only
cuts and pastes CF_TEXT format data to and from a table window.

Function Description
SalEditCanCut Returns TRUE if text in a data field, multiline field, or table window cell is selected for
cut or copy.
SalEditCut Cuts selected text from a data field, multiline field, or table window cell and puts it on
the clipboard.
SalEditCanPaste Returns TRUE if there is anything on the clipboard to paste.
SalEditPaste Pastes text from the clipboard to the text insertion point.
SalTblPasteRows Pastes text from the clipboard to one or more table window rows at the end of the
table. The text to be pasted must have tabs separating each column and an end-of-line
character at the end of each row. This function returns FALSE if none of the columns are
editable.
SalEditCopy Copies selected text from a data field, multiline field, or table window cell and puts it on
the clipboard.
SalTblCopyRows Copies one or more selected table window rows to the clipboard. Tabs are placed
between columns and an end-of-line character is placed at the end of each row.

Using Database Result Sets with Table Windows


You can use the following constants when the source of data for a table window comes from a database.

TBL_Adjust and TBL_NoAdjust Constants


SalTblDeleteRow uses these two constants to synchronize a table window row number with the row number
in a database result set:

Constant Description
TBL_Adjust Synchronize row number with row number in result set
TBL_NoAdjust Do not synchronize row number with row number in result set

Use TBL_Adjust when you delete data from both the result set and the table window:
Call SalTblDeleteRow( hWndForm, nRow, TBL_Adjust )

TBL_TempRow Constant
You can fetch a row from the database into TBL_TempRow without overwriting values in the actual table
window row.
Fetching a database row usually places the values in the corresponding table window row. However, when
you update, avoid overwriting edited values. TBL_TempRow lets you fetch the database row into a special
table window row, establish the current SQL cursor position and enable the update to take place.
416
For more information, see Updating rows on page 389.

Checking and Setting a Cell's Field Edit Flag


You can call SalSetFieldEdit and SalQueryFieldEdit for a table window cell. Use this format for the window
handle parameter for either of these functions:
TableWindow.Column
The specific cell that SQLWindows checks or set is at the intersection of the context row and the column you
specify.

Processing WM_* Cell Editing Messages


SQLWindows sends these WM_* messages to a table window column when a user edits a cell:
• WM_KEYFIRST through WM_KEYLAST
• WM_MOUSEFIRST through WM_MOUSELAST
• Greater than WM_USER
You can process these messages in the message actions of a table window column. For example, to let a user
scroll through a list of values for a cell by pressing the Up and Down arrow keys, process WM_KEYDOWN and
check the wParam for the virtual key codes VK_UP and VK_DOWN.

XML Support
A group of functions and messages allow you to do these XML tasks:
• Write the contents of a table window to an XML document and/or schema.
• Read an XML document into a table window..
See the SQLWindows Function Reference book for detailed information on the functions. A summary is
provided below.

Writing to XML
Function SalTblWriteXMLAndSchema writes all rows of a table window to an XML document, an XML schema,
or both. It captures all available attributes of rows and columns, including flags ROW_UnusedFlag1 and
ROW_UnusedFlag2. The names of the output files are based on the name of the table window.
Function SalTblWriteXMLAndSchemaEx is very similar to SalTblWriteXMLAndSchema, but it provides extra
parameters to determine which rows of the table window should be written, instead of writing every row.

417
Reading from XML
Function SalTblSetFromXMLSchema has two purposes. If the target table window has automatic columns,
this function resets the columns to match the schema, in preparation for the actual reading of XML data. If
the table has static columns, this function checks the datatypes of the schema and table window and verifies
that they match. If you want to be sure of the integrity of the data loaded through SalTblPopulateFromXML,
you should call this function first and be sure the return value is TRUE.
Function SalTblPopulateFromXML loads a table with XML data. Existing rows in the table are erased before
loading begins. Note that the XML document and schema must be built in a manner understandable to this
function, with specific names for the various nodes. The easiest way to understand the necessary structures is
to use SalTblWriteXMLAndSchema in a test app, produce a document and schema, and study their structures.
Message SAM_XMLRowDone is sent after each row is loaded in SalTblPopulateFromXML. lParam contains the
row number just loaded.

SAL and XML Datatypes


The format of the table window column determines the XML datatype. Here is how those formats map to
XML:

SAL Datatype Column Format XML Datatype


Date/Time Date date
Time time
DateTime dateTime
unformatted date
Picture format, including a “y” date
Picture format, including an “h” time
Picture format, including both “y” and “h” dateTime
Number Decimal fixed 14.4
Currency fixed 14.4
Percentage fixed 14.4
Picture format, more than 4 zeros to the right of the float
decimal point
Picture format, 1 to 4 zeros to the right of the decimal fixed 14.4
point
Picture format, no decimal point or no zeros to the right integer
of the decimal point
String (all) string
Long String (all) string

418
Chapter 16 – Pictures
This chapter shows how to create and use picture objects in SQLWindows applications. It explains picture
properties and messages and functions you can use with pictures.
A picture displays a graphic image. A picture is a child of a form window or dialog box.
A picture object can contain graphic images and DOS files. Examples of pictures are:
• An organization's logo
• Graphics that indicate instructions
• Images that give an application visual appeal, such as an image that fills the background of a form
• Images that a user can cut, copy, and paste
• Images retrieved from a database or a file

Picture Attributes
The attributes for a picture are the following:

Property Description
Object Name The name you use to refer to the picture window in statements.
Visible If Yes (default), the picture is visible at runtime. If No, the picture is not visible at
runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the form window's position (top and left) and size
(width and height).
Editable If No (default), a user cannot edit the object. You can still change the contents of the
picture within the application (such as with a Set statement).
If Yes:
A user can cut, copy, and paste the picture.
A user can shift the input focus to the picture. The focus is indicated by the focus
frame.
At runtime, you can change the setting of this property with SalEnableWindow and
SalDisableWindow.
File name Displays a dialog where you select a file that contains an image to display in the
picture. If you set the File Storage item to Internal, SQLWindows copies the image file
into the application. If you set the File Storage item to External, SQLWindows finds and
displays the image file at runtime and design time.

419
Property Description
File storage The method that SQLWindows uses to store the image:
External. SQLWindows reads the image from a disk file at both runtime and design
time. You must distribute the external file with production versions of an application.
Internal. SQLWindows stores the picture image in the application at runtime.
SQLWindows must be able to find the image in an external file at design time. When
you make an *.EXE version of an application, SQLWindows copies the image from the
file into the application. You do not need to distribute the external file with production
versions of an application.
Picture Transparent Displays a palette where you select a color in the image that you want to replace with
Color the background color of the option button. This makes parts of the image transparent.
This applies to bitmaps only (*.BMP). The default is None.
At runtime, call SalColorGet and SalColorSet to get or set the transparent color of the
bitmap. COLOR_IndexTransparent identifies the color. To clear the transparent color,
Picture Fit pass
How COLOR_None toinSalColorSet.
to fit the image the picture:
Scale – Scales the image by a specified percentage (default)
Size to Fit – Stretches or shrinks the image to fit in the picture
Size for Best Fit – Sizes the image to fit either the width or height of the picture
At runtime, call SalPicSetFit to set the picture fit.

Scale Width The scaling percentage. The default is 100.


Scale Height The scaling percentage. The default is 100.
Tile to Parent If Yes, the picture fills the background of the parent object.
Corners The corner shape (square or round) for the picture. The default is square.
Border Style The border style for the picture (no border, solid, drop-shadow, raised-shadow, or
etched). The default is solid.
Border Thickness The border thickness. The default is 1.
Background Color Displays a palette where you can set the color of the background (the area of the
picture not covered by an image).
Border Color Displays a palette where you can set the color of the picture border.
ToolTip This text is displayed when the user hovers the mouse cursor over the picture object.

Sources of Pictures at Design Time


At design time, the source of a picture is a file chosen from the dialog that is presented by the File Name
property of the Attribute Inspector.

Using 256-Color Bitmaps


For form windows or dialog boxes with multiple images (in picture objects, push buttons, or option buttons),
use the Send to Back command on the object that you want to have the best color quality. SQLWindows

420
creates a single palette for painting all objects on a form window or dialog box. This palette is based on the
bottom-most object. This only affects 256-color images.

Picture Messages
A picture receives these messages:
• SAM_Click
• SAM_Create
• SAM_Destroy
• SAM_DoubleClick
• SAM_KillFocus (only editable pictures receive this message)
• SAM_SetFocus (only editable pictures receive this message)
• SAM_Timer
Most of these messages work the same as they do for other application objects. Some special features of the
SAM_Click and SAM_DoubleClick messages are explained next.

Using SAM_Click and SAM_DoubleClick with Pictures


The table below shows the meaning of the message variables for SAM_Click and SAM_DoubleClick. Note that
wParam and lParam contain the X and Y coordinates where the user clicked in the picture. This lets you define
“hot spots” in an image.

Message Variable Description


hWndForm Handle of the current form window or dialog box
hWndItem Window handle of the picture
wParam X coordinate (in pixels) where the user clicked in the picture relative to the
upper left-hand corner of the picture
lParam Y coordinate (in pixels) where the user clicked in the picture relative to the
upper left-hand corner of the picture

Picture Functions
The SAL functions for pictures are grouped into these categories:
• Cutting, copying, pasting, and clearing
• Storing and retrieving images
• Other functions
The next sections discuss these categories.

421
Cutting, Copying, Pasting, and Clearing
Call these edit functions to cut, copy, paste, and clear pictures. To call these functions, you must turn on the
editable attribute in the Attribute Inspector. These functions operate as they do for other objects.
• SalEditCanCut
• SalEditCanPaste
• SalEditCanUndo
• SalEditClear
• SalEditCopy
• SalEditPaste
• SalEditUndo

Storing and Retrieving Picture Images


SalEditCanCopyTo
This function returns TRUE if an editable picture has the focus and contains an object that can be copied to a
file:
bOk = SalEditCanCopyTo( )

SalEditCopyTo
This function displays a dialog so a user can copy the image with the focus to a file:
bOk = SalEditCopyTo( )

A user can store the file as one of these types:

Type Extension Description


TIFF *.TIF Tag Image File Format
PCX *.PCX Paintbrush
GIF *.GIF Graphics Interchange Format
DIB *.DIB Device-Independent Bitmap
BMP *.BMP Device-Independent Bitmap

422
Type Extension Description
WMF *.WMF Windows MetaFile
JPEG *.JPG Joint Photographic Experts Group

SalEditPasteFrom
This function displays a dialog so a user can select a file to paste into the picture with the focus:
bOk = SalEditPasteFrom( )
A user can select any type of file. If the file type a user selects is not one of those listed in the
previous table, SQLWindows pastes it in the picture using the generic document icon shown to
the left.

A user can retrieve the image file types listed in the table for SalEditCopyTo above.
SQLWindows converts the image from one of these formats to display a bitmap.
The contents of the file are available to SQLWindows through the SalPicGetString function. For example, you
can use SalEditPasteFrom to copy a file into a picture and then use SalPicGetString to copy the file to a string.
Then, you can write to a database or file.

SalPicSetFile
This function sets the contents of a picture from a file without user interaction:
bOk = SalPicSetFile( hWndPict, strFileName )

SalPicGetString
This function copies the contents of a specified picture to a string:
nLength = SalPicGetString( hWndPict, nFormat, strDest )
For an example, see Storing Pictures in a Database on page 424. You use a constant in the second parameter
to specify the format:

Constant Description
PIC_FormatBitmap The contents of the picture is a bitmap
PIC_FormatIcon The contents of the picture is an icon
PIC_FormatObject The contents of the picture is a graphic image

SalPicSetString
The function copies a string to the picture you specify:
bOk = SalPicSetString( hWndPict, nFormat, strSource )
You use the same constants as for SalPicGetString in the second parameter to specify the format.
For an example, see Storing Pictures in a Database on page 424.

423
Sources and Destinations for Pictures at Runtime
The following illustrates the sources and destinations for a picture at runtime.

At runtime, the source of a picture can be:


• An image that was stored in the application at design time.
• The Clipboard using SalEditPaste.
• A file using SalEditPasteFrom or SalPicSetFile. You can also read a file and use SalPicSetString to move the
file's contents to a picture.
• A LONG VARCHAR column in a database using SalPicSetString to move the column's contents to a picture.
At runtime, you can write the contents of a picture to:
• The Clipboard using SalEditCopy
• A file using SalPicGetString to move the contents of a picture to a file
• A LONG VARCHAR column in a database using SalPicGetString to move the contents of a picture to the
column

Storing Pictures in a Database


You can store picture contents in a LONG VARCHAR column. For example, a user can paste an object from
the clipboard and the application can store it in a database. Later, the same application or a different
application can retrieve the object and display it.

Inserting Pictures
To insert an picture in a database:
Q) Call SalPicGetString to move the object from the picture to the bind variable in the INSERT's
VALUES clause. In this example, the object in the picture named picObject is moved to the
:lsImage bind variable.
C9 Prepare, execute, and commit the INSERT command.

424
Q) Call SalPicGetString( picObject, PIC_FormatObject, lsImage )
C9 Call SqlPrepare(hSql,
'insert into SWOBJECT values ( :nKey, :cbFit, :mlDescr, :lsImage )')
If SqlExecute(hSql)
Call SqlCommit( hSql )

Retrieving Pictures
To retrieve a picture from a database:
Q) Prepare and execute the SELECT command.
C9 Call SalPicSetString to move the object from the INTO clause's variable to a picture. In this
example, the object in the :lsImage INTO variable is moved to the picture named picObject.

Q) Call SqlPrepare( hSql,'select fit, descr, image, numkey


into :cbFit :mlDescr, :lsImage, dfKey from SWOBJECT
where ROWID = :strRowIDs[nCurrentRow]')
Call SqlExecute(hSql)
If SqlFetchNext( hSql, nFetch )
C9 Call SalPicSetString( picObject, PIC_FormatObject, lsImage )

Updating Pictures
To update a picture in a database:
Q) Call SalPicGetString to move the object from the picture to the bind variable in the UPDATE's SET
clause. In this example, the object in the picture named picObject is moved to the :lsImage bind
variable.
C9 Prepare, execute, and commit the UPDATE command.

Q) Call SalPicGetString( picObject, PIC_FormatObject, lsImage )


C9 Call SqlPrepare(hSql, 'update SWOBJECT
set descr = :mlDescr, image = :lsImage, fit = :cbFit
where ROWID = :strRowIDs[nCurrentRow]')
If SqlExecute(hSql)
Call SqlCommit( hSql )

Other SAL Picture Functions

SalPicGetDescription
The following function retrieves the description of the contents in a picture:
nLength = SalPicGetDescription( hWndPict, strDesc, nMaxLen )
For a graphic image, SalPicGetDescription returns the following strings:

Image Type String Returned by SalPicGetDescription


Tag Image File Format GUPTA:TIFF

425
Image Type String Returned by SalPicGetDescription
Paintbrush GUPTA:PCX
Graphics Interchange Format GUPTA:GIF
Device-Independent Bitmap GUPTA:BMP
Icon file GUPTA:ICO

SalPicSet
For a file, SalPicGetDescription returns this string: GUPTA:DOSFILE

This function inserts a resource (bitmap or icon file that you specified in the Resources section of the
outline) into a picture:
bOk = SalPicSet ( hWndPic, tResource, nFormat )

SalPicSetFit
This function sets the fit for a picture:
bOk = SalPicSetFit( hWndPict, nFit, nScaleWidth, nScaleHeight )
You specify the fit with a constant in the second parameter:

Constant Description
PIC_FitScale Stretches or shrinks the image to fit within the picture
PIC_FitSizeToFit Scales the image by the scaling percentages you specify in the third and
fourth parameters
PIC_FitBestFit Sizes the image to fit either the width or height of the picture

SalQueryFieldEdit
This function returns the setting of the field edit flag for a picture:
bSet = SalQueryFieldEdit( hWndPict )

SalSetFieldEdit
This function sets or clears the field edit flag for a picture:
bOk = SalSetFieldEdit( hWndPict, bSet )

SalPicClear
This function clears the contents of a picture:
bOk = SalPicClear( hWndPict )

426
Chapter 17 – Drag-and-Drop
This chapter explains the functions and messages that you use to write a drag-and- drop interface in a
SQLWindows application.
You can write applications where the user can use the mouse to drag from one window and drop into
another. For example, you can add drag-and-drop features to applications so that the user can:
• Fill a data field by dragging a list box entry to a data field
• Select a picture by dragging from one picture object to another
You can specify the mouse cursors that a window displays while the user drags.
You cannot use drag-and-drop to drag a file from a Explorer window to an application window.

Terms Used
• Drag mode. While in drag mode, SQLWindows suspends the mouse's normal operation until the user
releases the mouse button. Also, SQLWindows reports the window where the mouse is positioned to the
application while in drag mode.
• Drag. Moving the mouse while in drag mode.
• Drop. Releasing the mouse button in a valid window while in drag mode.
• Source window. The window from which a user drags.
• Target window. The window where the mouse is while in drag mode.
• Auto dragging. The default mouse action that starts drag mode.

Source and Target Windows


These objects can be source windows:
• Data field
• Multiline field
• List box
• Combo box
• Picture
• Table window
Any SQLWindows object can be a target window. However, target windows that do not have actions (such as
Frames) do not receive SAM_Drag* messages.

427
Drag Mode Events
SQLWindows informs an application about drag mode events by sending messages to both the source and
target windows.

Auto Dragging
SQLWindows starts drag mode automatically when the application returns TRUE from the
SAM_DragCanAutoStart message. This is the minimum that the application does to let a user drag from a
window. However, you must write additional code to do something when the user drops in a window.
Auto dragging begins when the user holds down the left mouse button over a window and does not move
the mouse for a short period of time. When this happens, SQLWindows changes the cursor to indicate drag
mode. This user interface for auto dragging does not interfere with other mouse operations for the window.
For example, the user can still edit Data Fields and can still select from List Boxes as long as the user moves
the mouse or releases the mouse button before SQLWindows starts drag mode.

Application-Initiated Dragging
You can start drag mode at other mouse-down events using the SalDragDropStart function. For example, you
can start drag mode on a SAM_Click message for a picture window. This way the user does not have to hold
the mouse down for some
interval-drag mode starts immediately when the user presses the left button. You can call SalDragDropStart to
start drag mode at any time a mouse button (right, middle, or left) is down.

Enabling and Disabling Dropping


While in drag mode, the user can only drop when the mouse cursor is over a SQLWindows window. You can
disable dropping in a window using the SalDragDropDisableDrop function. For example, you can prevent the
user from dropping except when the mouse is in a picture window.

Application-Defined Cursors
SQLWindows displays default cursors to indicate drag mode to the user. When drag mode starts, SQLWindows
displays a special cursor to indicate this to the user. When drop is disabled, SQLWindows displays a different
cursor.
You can override the default cursors that SQLWindows provides. You can associate up to three types of
application-defined cursors with a window.
Window Cursor. SQLWindows displays this cursor when a window is not in drag mode.
Drag Cursor. SQLWindows displays this cursor when a window is in drag mode and dropping is enabled.
428
Disabled Drop Cursor. SQLWindows displays this cursor when a window is in drag mode and dropping is
disabled.

Functions
SalDragDropDisableDrop
This function disables dropping while in drag mode:
bOk = SalDragDropDisableDrop( )

SalDragDropEnableDrop
This function enables dropping while in drag mode:
bOk = SalDragDropEnableDrop( )

SalDragDropGetSource
This function returns the handle of the source window and the location of the mouse in the source window
when drag mode started:
bOk = SalDragDropGetSource( hWndSource, nX, nY )

SalDragDropGetTarget
This function returns the handle of the target window and the location of the mouse in the target window:
bOk = SalDragDropGetTarget( hWndTarget, nX, nY )

SalDragDropStart
This function starts drag mode:
bOk = SalDragDropStart( hWndSource )
One of the mouse buttons (left, right, or middle) must be down.

SalDragDropStop
This function ends drag mode:
bOk = SalDragDropStop( )

SalCursorSetFile
This function sets a cursor for the window:
bOk = SalCursorSetFile( hWnd, strFile, nType )
The strFile parameter is the name of a cursor or icon file specified in the Resources section of the outline. The
nType parameter is one of these constants:
• CURSOR_Window. Displayed when not in drag mode when the mouse is over the window.
• CURSOR_DisableDrop. Displayed in drag mode when drop is disabled.
• CURSOR_DragDrop. Displayed in drag mode when drop is enabled.

429
Source Window Messages
SAM_DragCanAutoStart
SQLWindows sends this message to ask the window whether it wants auto dragging. Return TRUE to enable
auto dragging. If you do not process this message or you return FALSE, then auto dragging is not enabled.

wParam X coordinate in the window


lParam Y coordinate in the window

SAM_DragStart
SQLWindows sends this message when drag mode starts.
wParam X coordinate in the window
lParam Y coordinate in the window

SAM_DragEnd
SQLWindows sends this message when drag mode ends.
wParam Not used
lParam Not used

SAM_DragNotify
SQLWindows sends this message when a mouse action happens in drag mode.
wParam Handle of a target window
lParam One of these values:
SAM_DragEnter – The user moved the mouse into a target window
SAM_DragDrop – The user dropped the mouse in a target window
SAM_DragExit – The user moved the mouse out of a target window
SAM_DragMove – The user moved the mouse within a target window

Target Window Messages


SAM_DragEnter
SQLWindows sends this message when the user moves the mouse into this target window while in drag
mode.
wParam Handle of a source window
lParam Not used

SAM_DragDrop
SQLWindows sends this message when the user drops the mouse on this target window.
wParam Handle of a source window
lParam Not used
430
SAM_DragExit
SQLWindows sends this message when the user moves the mouse out of this target window while in drag
mode.

wParam Handle of a source window


lParam Not used

SAM_DragMove
SQLWindows sends this message when the user moves the mouse within this target window while in drag
mode.

wParam Handle of a source window


lParam Not used

Auto-Dragging Example
This example uses auto-dragging to show how to drag a selection in a list box to a data field:
Q) The lb1 list box is the source window. When the user holds down the mouse button for an
interval, SQLWindows sends the list box the SAM_DragCanAutoStart message. The message
actions for the list box pro- cess SAM_DragCanAutoStart by returning TRUE if the user has
selected an entry.
C9 SQLWindows sends the list box the SAM_DragStart message when drag mode starts. The
SAM_DragStart message actions get the list box selection and store it as the list box's window
text.
• The df1 data field is the target window. SQLWindows sends the data field the SAM_DragDrop
message when the user drops on the data field. The SAM_DragDrop message actions for the
data field:
– Get the handle of the source window from the wParam
– Make sure the source window is not the data field itself and the parent of the source
window is the same as the parent of the data field
– Get the window text of the source window and use it to set the data field window text

431
List Box: lb1
...
List Initialization
Text: Value 1
...
Message Actions
Q) On SAM_DragCanAutoStart
If SalListQuerySelection( hWndItem ) != LB_Err
Return TRUE
Else
Return FALSE
C9 On SAM_DragStart
! Store the current selection as window text so we can use it on the drop
Call SalListQueryText( hWndItem, SalListQuerySelection( hWndItem ),
sList )
Call SalSetWindowText( hWndItem, sList )
Data Field: df1
...
Data
...
Data Type: String
Editable? Yes
...
Message Actions
• On SAM_DragDrop
Set hWndSrc = SalNumberToWindowHandle( wParam )
If hWndSrc != hWndItem
AND SalParentWindow( hWndSrc ) = hWndForm
Call SalGetWindowText( hWndSrc, sSource, 1000 )
Call SalSetWindowText( hWndItem, sSource )

Application-Initiated Dragging Example


This example uses application-initiated dragging to show how to drag the contents of one picture object to
another picture object:
Q) Application-initiated dragging relies on mouse-down events. This application declares a constant
for the Windows message WM_LBUTTONDOWN. Windows sends this message when the user
presses the left mouse button. You can find the values of Windows message constants in
WINDOWS.H.
C9 C9 The pic1 picture is the source window. If the user presses the left mouse button in this
window, Windows sends WM_LBUTTONDOWN to the picture. The picture processes
WM_LBUTTONDOWN by calling SalDragDropStart, which begins drag mode.
• The pic2 picture is the target window. SQLWindows sends the SAM_DragDrop message to the
picture when the user drops on the picture. The SAM_DragDrop message actions for the picture:
– Get the handle of the source window from the wParam.
– Make sure the source window is not pic2 itself and the source window is a picture object.
– Call SalPicGetString to copy the contents of the source window to a string.
– Call SalPicSetString to copy the String to the target window.

432
Global Declarations
...
Constants
System
Q) Number: WM_LBUTTONDOWN = 0x201
...
Picture: pic1
...
Message Actions
C9 On WM_LBUTTONDOWN
Call SalDragDropStart( hWndItem )
Picture: pic2
...
Message Actions
• On SAM_DragDrop
Set hWndSrc = SalNumberToWindowHandle( wParam )
If hWndSrc != hWndItem
AND SalGetType( hWndSrc ) = TYPE_Picture
Set nLength = SalPicGetString( hWndSrc, PIC_FormatBitmap, strPic )
If nLength > 0
If NOT SalPicSetString( hWndItem, PIC_FormatBitmap, strPic )
Call SalMessageBox('Could not drag picture.',
'Drag-and-Drop Error', MB_Ok | MB_IconStop )

Dropping from Explorer


You can write applications where the user drops files from Explorer on an application window.

To drop a file from Explorer, the user selects one or more files, holds down the mouse button, and
moves the mouse. When the mouse is over a window that supports file dropping, the mouse pointer
changes to the symbol at the left. When the user releases the mouse button, the file or files drop on
the window.

When the mouse is over a window that does not support file dropping, the mouse pointer changes to
the international “no” symbol at the left.

Any window type with message actions can be the destination of a file drop.
Except for editable picture objects, the application must call SalDropFilesAcceptFiles to enable file dropping
on a window (see File Dropping Functions on page 433).
Editable picture objects support file dropping by default.
By default, file dropping is enabled for editable picture objects. To prevent this default processing, execute a
Return statement in the SAM_DropFiles message processing for a picture object and do not perform any
other processing. For example, when a user drops on a picture, call SalDropFilesQueryFiles or
SalDropFilesQueryPoint in the SAM_DropFiles message processing and decide whether to process what the
user is dropping or to ignore it by executing a Return statement with no other processing. To completely
disable file dropping for an editable picture, call SalDropFilesAcceptFiles.

File Dropping Functions


This function sets whether a window can accept a file from Explorer:

433
bOk = SalDropFilesAcceptFiles( hWnd, bAccept )
The default for editable picture objects is TRUE. The default for all other window types is FALSE.
When an object receives a SAM_DropFiles message, call this function to find the location of the mouse where
the user dropped the file or files:
bOk = SalDropFilesQueryPoint( hWnd, nX, nY )
When an object receives the SAM_DropFiles message, call this function to get the names of the files that the
user dropped:
bFiles = SalDropFilesQueryFiles( hWndSource, sFileArray[*] )
This function returns the number of files that the user dropped. This function returns zero if it fails. This
function fails unless you call it in SAM_DropFiles message processing.

SAM_DropFiles Message
SQLWindows sends this message to a window when the user drops a file or files from Explorer on the
window. SQLWindows only sends this message to windows that have enabled file dropping.
Call SalDropFilesQueryFiles to get the names of the files dropped on the object. Call SalDropFilesQueryPoint
to get the location of the mouse in the window where the user dropped the file or files.
This message does not use wParam or lParam.

434
Chapter 18 – Libraries
This chapter shows how to write and use Include libraries and Dynalibs.

Include Libraries
Include libraries let you:
• Share application components in more than one application
• Share application components with other developers
An include library is a collection of SQLWindows objects such as form windows, dialog boxes, or class
definitions that are shared by more than one application. You edit libraries in the same way as an application.
You maintain components for an include library in a single source file. This means that you only need to
change one source file to change a component used in many applications.

An include library only contains components that you use in other applications. An include library contains a
set of related outline items. An item is anything that you can copy to the Clipboard.
These are examples of what an include library can contain:
• Top-level windows (form windows, table windows, and dialog boxes)
• MDI windows
• Internal functions
• External function definitions
• Class definitions

435
• A group of global variables and constants

Creating an include library


To create an include library, place a group of related items in an outline:
By convention, you save an include library file with an *.APL extension. The *.APL extension is not required,
but is the default.
You can create any number of include libraries.

Nested includes
You can nest included items. An include library can contain items from other libraries.

Using an include library


To use a library, specify the include library name in the File Include section of the outline under Libraries
(between Design-time Settings and Global Declarations):
...
Design-time Settings
...
Libraries
File Include: <Library Name>
Global Declarations
...
Important: SQLWindows includes all the items in an include library.
When you use an item from an include library in an application, SQLWindows incorporates the item in the
appropriate part of the application's outline.
In an application, you can include items from any number of libraries.
SQLWindows displays included items in the color that you specify in Tools, Preferences. On monochrome
computers, SQLWindows displays included items in italics.
Important: When you use an include library in an application, statements in the application actions section of
the library are not included. If you need application actions in a library (such as for SAM_SqlError processing),
put the code in an internal function and call the function in the application actions.

Editing an include library


You cannot directly edit included items in an application. You can only edit included items in their include
library.
To edit an include library, follow these steps:
1. Select an item that is in an include library.
2. Select Component, Go To Item or press F5. This starts a second instance of SQLWindows that opens the
include library.
3. Make changes to the include library.
4. Save the changes and exit the second instance of SQLWindows. You automatically return to the
application.
5. If Refresh When Changed is checked in Tools, Preferences (the default), the changes you made to the
include library are automatically reflected in the application. If Refresh When Changed is not checked,
select Component, Refresh to reinclude the include library.

436
You can also change an include library by opening it with another instance of SQLWindows, editing it, and
then saving it.

Component menu
The sections below explain the menu items in the Component menu.

Go To Item (F5)
Starts a new instance of SQLWindows and opens the include library that contains the selected included item.
You can then edit the included item. When you save and close this instance of SQLWindows, the first instance
of SQLWindows resumes.
Unless you uncheck Refresh When Changed in Tools > Preferences (see page 94), SQLWindows detects that
one of the included items has changed and automatically reincludes the changed include library.
When you edit an included item in an include library, the target item is selected in the include library.
Show Item Information (Shift+F5)
Displays a window that contains the name of the include library that contains the selected item. This menu
item is only enabled when you have selected an included item in the outline.
Refresh
Reincludes all libraries. Choose Refresh to include a recently-changed include library without closing the
current application (such as when another person changes an include library on a file server).
Merge
Permanently merges all libraries with the open application. Once merged, the items are a fixed part of the
application. Merging removes the information that relates the included items to their original libraries.
SQLWindows displays a warning dialog before completing the merge.

Tools, Preferences
General tab: refresh when changed
By default, SQLWindows automatically detects changes in libraries and reincludes them if they have changed.
Turn off this feature by unchecking the check box. This is useful when libraries are in a remote location or
when the reinclude is time-consuming.

437
Outline tab: text enhancements
The Includes property lets you select the color or style for included items in the outline. The default color is
blue. Instead of displaying included items in color, you can display them with bold, italic, or underline styles,
or with no special property. On monochrome computers, SQLWindows always displays included items in
italics.

Directories tab: searching group


This groups specifies a list of paths where SQLWindows looks for libraries. Separate each path in the list with a
semicolon as in a DOS PATH environment variable. For example:
C:\INCLUDES;C:\PROJECT1

Dynamically Linked Libraries (Dynalibs)


A dynalib is a compiled SQLWindows module with functions and objects that other applications can
dynamically load at runtime.

A dynalib is different from an include library:


• With an include library, you share source code at design time. All items in the include library are available
in the including application.
• With an dynalib, you share compiled code at runtime. Only the interface to objects and functions are
available to an application that uses a dynalib.
A dynalib shares its objects and functions with other applications. This is called exporting. Other applications
use the items. This is called importing. The process of creating and using dynalibs can be summarized as
follows:
1. Create a dynalib source file (*.APL) with the items you want to export.
2. Compile the dynalib *>APL source file to create the *.APD runtime library.
3. Import the items in other applications.
4. To deploy, install compiled dynalibs (*.APD) with other runtime files.
The advantages of using a dynalib are:
• Modular Design. You can split an application into separate modules (dynalibs), with each module
dedicated to a single purpose. You can also create nested dynalibs.

438
• Reduced Footprint. You need less disk space to deploy a group of applications when they share code in
common libraries.
• Modular Upgrades. You can recompile a library after an application is in production without recompiling
the application.
• Source Code Security. You can distribute libraries developed in SAL without revealing the source.
• Faster Compiles. You do not need to compile dynalibs every time you compile the application. Unlike an
include library, the code in a dynalib is not recompiled when you compile the application. This means that
using dynalibs can reduce the time required to compile an application.

How to Write Dynalibs


To create a dynalib, place a group of related global functions, global variables, top- level windows, and MDI
windows in an application. The default file extension for dynalib source files is *.APL, the same as for
include library source files.

What you can export


You can export these items from a dynalib:
• Global functions
• Global variables (only the standard, built-in data types such as Number and String, not UDVs)
• Top-level windows and their window functions
• MDI windows, their contents, and their window functions

What you cannot export


You cannot export these items from a dynalib:
• Constants
• External function declarations
• Classes (an importing application cannot derive a class from a class defined in a dynalib, nor can it create
an instance of a class defined in a dynalib; the dynalib can only create an instance of a class and then
export that instance)
• Inherited window functions
• Window variables such as hWnd.LibForm.Var
• Inherited instance variables
• Content items (child windows)
• Items from included files
The items above are not visible to an importing application. However, there are design techniques you can use
to share these items in dynalibs (see Using Non-Exportable Items in Dynalibs on page 441).

How to export
For each item you want to export, you must explicitly mark it with an “exported” pragma in a trailing
comment in the item's declaration. Put two underscores at the start of the pragma. In the following example,
the declarations mean that the dynalib exports numGInLib1 and strGInLib1:

439
Number: numGInLib1 ! Exported
String: strGInLib1 ! Pragmas such as " exported" are
insensitive to case, position, and quoting
For multiline items, put the pragma as a comment on the first line (usually the line where you name the
item):
Form Window: frmExporter ! exported
...
Dialog Box: dlgExporter ! exported
...

System variables
System variables like hWndForm are available to the dynalib and are shared by all dynalibs and an application.

Nesting dynalibs
A dynalib can use objects or call functions in another dynalib.
This feature makes it possible for an application to indirectly use the same dynalib more than once. If this
happens, SQLWindows loads only one instance of the dynalib and its global variables. For example, an
application uses dynalib1 and dynalib2.
Dynalib2 also uses dynalib1. The first time the application or dynalib2 refers to dynalib1, SQLWindows loads
one instance of it.

Semi-qualified references
You cannot make semi-qualified references to variables (such as hWnd.var) in dynalibs. This type of late-
bound reference requires “var” to be a consistently defined data type and object type throughout the
application and all its dynalibs. The compiler cannot enforce this consistency in any other way except to reject
the reference because the compiler does not have global knowledge of the application and its dynalibs.

Recompiling dynalibs
You can replace existing dynalibs with newly-compiled ones without recompiling the importing applications if
the dynalib's interface does not change. Examples of changes to the interface are:
• Changing the name of an exported item
• Changing the return data type of a dynalib's functions
• Changing the names or data types of a function's parameters
• Changing the names or data types of a window's parameters
• Adding or changing the instance variables of a UDV that is passed as a parameter
However, you can change the behavior of an existing function or add new items.

Passing long strings to a dynalib


Passing a Long String that contains a large amount of data from an application to a dynalib and then
processing the Long String in the dynalib is just as efficient as processing the Long String in the application.

Literal strings and string constants


Before passing them to a dynalib, GUPTA SQLWindows copies literal strings (such as in the statement Set
df1='MyString') and strings defined in the constants section.

440
Version compatibility
When a new version of GUPTA is announced as “binary incompatible” with previous versions in the release
notes, this means that dynalibs and importing applications must be recompiled to use the new runtime
environment.

Using include files with dynalibs


A dynalib has its own outline that affects how global variables defined in include files are handled; for
example:
• Application A includes APL B and imports functionality from APD C
• APL B defines variable strVar
• APD C also includes APL B
• Application A has an instance of strVar; APD C has its own separate instance of strVar

Using Non-Exportable Items in Dynalibs


These are the design techniques you can use to share non-exportable items in dynalibs:
• Constants. Place constant definitions in an include file that is included by both the dynalib and the
application.
• External Functions. Place external function declarations in an include file that is included by both the
dynalib and the application.
• Classes. Place class declarations in an include file that is included by both the dynalib and the application.
• UDVs. You can pass UDVs between dynalibs or between an application and a dynalib. Place class
declarations in an include file that is included by both the dynalib and the application.
• Inherited Functions. Only window functions explicitly defined by a window are exported from a dynalib.
Inherited window functions are not automatically exported. To make an inherited function available to
clients of the dynalib, define a window function that does nothing but call the inherited function. This is
what the function declaration looks like in the *.APL source file:
CEmpFormClass: LibForm
...
Functions
Function: GetEmployeeData
Description: A call to an inherited function.
Returns
Boolean
Parameters
Number: numEmployeeID
Actions
Return CEmpFormClass.GetEmployeeData( numEmployeeID )

Compiling a Dynalib
Select Project > Build Settings in the main menu to specify that you want the compiler to create a dynalib the
next time you build. In the Build Target tab, click Dynalib under Select build target.
The *.APL file must be compilable. SQLWindows gives the name of the compiled dynalib file an *.APD
extension by default.

441
You can also compile a dynalib from the command line by using the “-y” option that tells SQLWindows to
create an *.APD file (dynalib) and then exit:
cbi* -y dynlib.apl [target.apd]
If you do not give a target file name, SQLWindows uses the base name of the source file and an *.APD
extension.

Compiling importing applications


If you compile an importing application, it does not force a recompile of the exporting dynalib.

Using Imported Items


You use a dynalib by naming it in the outline item called Dynalib in the Libraries section:
Libraries
File Include: myLib1.apl
Dynalib: ObjLib1.apd
Imported items are displayed in the same color as include library items.
Only the interfaces to imported items are displayed in the application, not the entire item with all its child
items. For example, SAL code is not displayed. Examples of imported items in an application are shown in
later section of this chapter.
You refer to imported items the same way as other items. For example, you can call SalCreateWindow in the
application to create an instance of a form window defined by a dynalib and pass parameters to the
window the same as if you had defined the form window in the application:
Set hWnd = SalCreateWindow( FormEmployee, hWndNULL, numEmployee )
You can then send messages to the form window or call its window functions:
Call FormEmployee.GetEmployeeData( numEmp )
Use function calls instead of messages because message numbers are hard to coordinate across
multiple dynalibs and because functions can take as many parameters as you need instead of only
wParam and lParam.
If you create more than one instance of the form window, you need to use a window- handle qualified call
as you normally do:
Call hWnd.FormEmployee.GetEmployeeData( numEmp )

Imported global functions


The sections for static variables, local variables, and actions are not displayed for imported functions
because they are not part of the interface to a function:

442
Internal Functions
Dynalink Function: MyFun ! exported
Description:
Returns
Boolean
Parameters
String: strParm1
Receive Number: numParm2

Imported global variables


This example shows what an imported global variable looks like in the outline.
Dynalink String: strExported ! exported Dynalink Number: nExported ! exported

Imported top-level windows and window functions


This example shows what an imported form window looks like in the outline. Child windows are not visible.
Other imported top-level objects and dialog boxes have similar child items:
Global Declarations
Dynalink Form Window: MyForm ! exported
Description:
Functions
Function: MyWinFun
Description:
Returns
Boolean
Parameters
String: strParm1
Window Parameters
String: strWinParm1
Dynalink Table Window: MyTable ! __exported
Dynalink Dialog Box: MyDialog ! exported

Imported MDI windows, children, and window functions


This example shows what an imported MDI window with children and window functions looks like in the
outline. Note that the MDI child windows are also dynalib items.

443
Global Declarations
Dynalink MDI Window: MyMDI ! exported
Description:
Contents
Dynalink Form Window: MyForm ! exported
Description:
Functions
Function: MyFormFun
Description:
Returns
Boolean
Parameters
String: strParm1
Window Parameters
String: strWinParm1
Dynalink Table Window: MyTable! exported
Functions
Function: MyMDIFun
Description:
Returns
Boolean
Parameters
String: strParm1
Window Parameters
String: strWinParm1

444
Chapter 19 – Handling XML
This chapter shows how to read, write, and manipulate XML documents.

XML Overview
To add XML handling capability to your SQLWindows application, you must include the library file xmllib.apl in
the application.
XML support in SQLWindows is provided by a group of functional class definitions. When you need to perform
XML tasks, you create instances of the classes and call functions in those instance objects.
Class XMLNode is the parent of nearly all other classes, except for XMLNodeList and XMLNamedNodeMap,
which contain collections of XMLNode objects.
A large number of constants are contained in xmllib.apl to support specific methods within these classes.

Basic Techniques
The first step in using XML is to map an XMLDocument object to the Document Object Model (DOM). Do this
with a call to the create or createNewDoc functions in that class. XMLDocument is the only class that provides
input and output methods for XML data. It also contains functions that create other objects such as elements
and attributes.
All of the internal objects created through calls to a document’s functions will persist in memory until the
application exits, unless you call the release function from the document, which will free up the document
itself and all its owned objects. It is
imperative to call the release function when you are finished with a document, or your application may
encounter “memory leak” issues.
Reading data in through the loadFromSQL, loadFromString, or loadFromURI methods in XMLDocument will
populate the document and all of its child objects. Other objects can be instantiated by calls to
XMLDocument methods such as createElement and createAttribute. It is important to note that simply
creating such an object does not make it part of the document for purposes of parsing. For example, you can
create an element using a call to function createElement, but it does not become part of the document tree
until you reference the element in a call to XMLNode.appendChild or XMLNode.insertBefore or
XMLNode.replaceChild.
You can change some of the behaviors in a document by using the setFeature function. It is important to note
that many features do not take effect immediately in a document. The features are related to the loading and
writing of documents, and thus they are dependent on when you perform those operations. For best results,
you should call setFeature after calling create or createNewDoc, and before calling loadFromSQL,
loadFromString, or loadFromURI.
Often you will want to examine the child objects contained in a document, or under a particular node of a
document. The XMLNodeList and XMLNamedNodeMap classes are designed to handle collections of such
objects, and they have links to the methods that are used to create such collections.

445
Avoiding Problems when Using XML Objects
You need an understanding of the possible states of XML objects to avoid unexpected problems in your
applications. The objects created from XML classes are mapped to internal objects in the Document Object
Model (DOM) itself at runtime. Because of this mapping technique, XML objects can exist in various states.
Consider the following example:
Function: myFunc
Description:
Returns
Parameters
Static Variables
Local variables
XMLDocument: myDocument
XMLElement: myElement
XMLElement: rootElement
Actions
! at this point, myDocument and myElement exist, but they are not mapped
to internal DOM objects
Call myDocument.create( )
! now myDocument is mapped: a legal, but empty, XML document
Call myDocument.loadFromURI( 'file//usr/local/myFile.xml' )
! now myDocument actually contains XML data
Call myDocument.createElement( myElement, 'myElementName' )
! myElement is now mapped, but it is not yet part of the document tree
of myDocument.
Call myDocument.getDocumentElement( rootElement )
Call rootElement.appendChild( myElement )
! Now myElement is actually part of the document tree, the last child
of the root element.
If we follow the UDV object myDocument in this example, we can see that it has three states. First, it exists
simply because it is in scope when the function is called. Second, it is mapped to an internal DOM object by
the call to create(), so it is now a proper XML document (although empty). Third, it is loaded with data
through a call to one of the load functions.
Similarly, variable myElement, an XML element, has three states. First, it exists because it is in scope when the
function is called. Second, it is mapped to an internal DOM object through the call to createElement. At this
point, it is a proper XML object (many function calls made against this object will succeed), but it is not yet
part of the tree structure of the document—it is an “orphan”. In its third state, it becomes part of the
document tree through the call to appendChild.

An object’s state affects its usefulness


When these objects are in their first state, not yet mapped to an internal DOM object, they are useless for
any practical XML purposes. All of the objects’ class functions will fail when called.
When objects are in their second state, mapped to an internal DOM object, most of their class functions will
succeed. However, you still may not get much practical use from the object. In the example above, we used a
createElement() call to associate object myElement with an internal DOM object. At this point we could add
attributes to myElement, for example, and those function calls would succeed. But myElement is not part of
the document tree yet, and if you write the document to a file, the contents of myElement and its attributes
would not be included in the output.
So it is often necessary that XML objects reach their third state before they are of practical value in the
application. For myElement, that means becoming part of the document tree through the call to
appendChild(), or a call to similar functions insertBefore() or replaceChild().

446
Beware of memory leaks
The example above illustrates a potential danger for applications that use XML objects. These objects are
mapped to internal DOM objects. But what happens when function myFunc ends? The XML objects are
declared as local variables, so they go out of scope and their mapping to internal DOM objects is lost. Yet the
internal DOM objects persist in memory. Obviously, if function myFunc is called multiple times, the
accumulation of unmapped internal DOM objects is a potential danger. Therefore, it is imperative that you
call the release function in a document when you are finished using it, and certainly before its objects go out
of scope. It is easy to locate a document from any of the other objects—nearly every object inherits from
class XMLNode, and XMLNode has a function ownerDocument that will provide a link to the document.

Using Casting
Many of the XML classes contain functions with the word "cast". As an example consider
XMLElement.castToElement.
The reason such functions exist is because many XML operations involve populating a collection of objects,
but those objects are always of type XMLNode. When you make a collection of elements using
XMLDocument.getElementsByTagName, the collection is stored in the first parameter of that function, which
is datatype XMLNodeList. In fact, every function that collects more than one object uses either XMLNodeLIst
or its subclass XMLNamedNodeMap to hold that collection. And the objects inside that collection are always
instances of class XMLNode.
Now suppose you want to perform some work on the collection, and that work is related to elements. You
can’t simply retrieve one of the XMLNode objects and call XMLElement.getAttribute() on it. That object is not
an instance of XMLElement. Therefore, you create a UDV that is an instance of XMLElement and then initialize
that UDV with the information contained in the XMLNode object, as in the following:
XMLElement: myWorkElement
XMLNodeList: theList
XMLNode: myRetrievedNode

bOk = myDocument.getElementsByTagName(theList, "customer")


bOk = theList.first(myRetrievedNode)
bOk = myWorkElement.castToElement(myRetrievedNode)
You can then make XMLElement calls from myWorkElement, and they will succeed.
Casting is not a magic bullet. It won’t transform one kind of node into another. In the example above, the
object in myRetrievedNode was originally an XMLElement, and we are simply casting it back to its original type
to perform work upon it.

447
Chapter 20 – Introduction to COM and
Writing COM Client Applications
This chapter introduces COM and explains how to write COM client applications, including:
• Creating an ActiveX component with the Controls palette and ActiveX Explorer
• Class outline structure and support classes
• ActiveX controls
• ActiveX container controls
• Automation
• Handling events
• Properties
• Handling exceptions
• Include libraries
For information on writing COM server applications, see Chapter 21 – Writing COM Servers.

COM Concepts

Component Software
The basis of object-oriented analysis and design is breaking down a project into its logical components. This is
also the basis for component software, which is software composed of building blocks. A component is a
reusable, self-contained piece of software in binary form that is independent of any application. A component
can be plugged into any application with relatively little effort.
Components provide a standard model for packaging services and exposing them to consumers. Components
are “black boxes”—their data and implementation details are hidden.
A component is not a complete application. A component performs a limited set of tasks within an
application domain. A component can be fine grained (for example, a window that only displays JPEG
images), medium grained (such as a tabbed dialog control), or coarse grained (such as a multi-dimensional
database analysis application). Components can be used in unpredictable combinations and in ways not
anticipated by the original developer.

COM
Microsoft’s COM (Component Object Model) provides a standard way for components to interoperate.
Components interoperate using client-server interaction models. COM defines a standardized means for
creating components and for controlling the communication between these components and their clients.
Unlike traditional objects, components can interoperate across tools and networks.

448
Standardizing the communication means that an application can look for a COM object at runtime, discover
its interface, and know how to interact with it.

Interfaces
A COM component exposes one or more interfaces. In its simplest definition, an interface is the way in which
an object exposes its functionality to the outside world. An interface is strongly typed contract between a
software component and a client that provides a relatively small but useful set of semantically related
operations.
Each interface provides a set of functions or events through which a client accesses the component:
• Incoming interfaces are collections of functions that a client can call to request that the component
perform an action.
• Outgoing, or source, interfaces are collections of event definitions. They describe calls the component
can make and are implemented in the client, if the client chooses to respond to the event. In COM
terminology, components fire events, and clients handle them.
The way that an object’s methods, events, and properties are related is called the object model. Learning a
component’s object model is essential to using it successfully.
COM specifies the binary layout of incoming interfaces as a table of function pointers, based on the C++
vtable structure. For certain components, this means they can be called directly through this table, called a
custom interface, from development tools that support the binary level calling style, while others support a
more generic, 4GL-style of access, called OLE automation, or automation access, through the IDispatch
interface. Automation access is the only access supported by SQLWindows.
A server is a COM component that provides an interface (or interfaces) and a client is an application that uses
an interface by calling one or more of its functions.

GUIDs
Each COM component is identified by a globally unique identifier (GUID). COM servers use these types of
identifiers:
• Each COM class is uniquely identified by a class ID (CLSID)
• Each interface is uniquely identified by an interface ID (IID)
• Each method is identified by a dispatch ID (dispID)
• Each event is identified by a dispatch ID
Through the use of GUIDs, each object is referenced at runtime by COM. The association between the
GUID information and the host server is stored in the registry. Every server that hosts COM objects must be
registered in order for those objects to be available to client components.

Type Information
Type information is standard descriptions of properties, methods, and events that an object supports as well
as return types, parameter names, and parameter types. Type information is stored in a type library. Clients
read a type library to get information about server objects’ properties and methods.

449
Proxies and Stubs
From a client’s perspective, a method call is invoked through interface pointer running in-process. When a
client makes a remote call, the call is actually handled by client-side stub code called a proxy. The proxy packs
the call parameters into a message and delivers the message to the server stub, which subsequently unpacks
the message and calls the method on the server-side object. This technique of packing and unpacking
function call parameters is called marshalling.

Distributed COM (DCOM) extends COM across machine boundaries, providing remote invocation of COM
component in a location-transparent manner. Location transparency enables a client application to function
consistently, regardless of whether the components it uses are located on the client machine or on a
separate machine.
Whether the client and server are on the same computer or on different computer, the communications
between the two takes place through RPC (Remote Procedure Call). Lower-level protocols ride underneath
RPC. RPC masks the differences between heterogeneous computers.

SQLWindows COM Client Applications


When building a client application, you can use ActiveX objects directly in the SQLWindows development
environment. Visual components appear on the Controls palette for direct use in the user interface design.
The methods and properties of both visual and non-visual components are available in Coding Assistant and
you can use them directly in the SAL language. You can process events unique to these components just like
other events.
A SQLWindows application can be a client to both visual and nonvisual COM servers. In the outline, visual and
nonvisual servers are similar. Their class hierarchies are a little different and you process events for each in
slightly different ways.
There are three ways that SQLWindows applications may incorporate visual COM servers:
• As a control, which has properties, functions, and events.
• As an insertable object, which can support both functions and events.
• As a contained object, hosted within the container control. When hosted in this way an object does not
have a “type” within SQLWindows and it does not directly support functions.
Microsoft provides many different server types within its software offerings. Within Microsoft Office all three
types are available, along with visual and non-visual components. Microsoft Calendar Control is an example
of an ActiveX Control that supports events and automation access. Microsoft Word provides examples of both
visual and non-visual components. The Microsoft Word application is a non-visual component that supports
automation access (through functions and events). The Document component can be incorporated into a
SQLWindows application as an insertable object, complete with type information, or hosted within the
container control.
When acting as a COM component client, SQLWindows applications must access components through auto-
generated SAL classes called proxy classes, which can be functional classes for access to COM interfaces, COM

450
Proxy Classes for COM CoClasses, and ActiveX classes that extend their COM Proxy CoClasses as child window
types. All automation access is made through the functional class that acts as a proxy to the COM interface
(see COM Client Class Outline Structure on page 459).
SQLWindows clients fully support ActiveX semantics such as automation (page 469), events (page 472),
embedding (page 467), menu merging (page 474), and toolbar negotiation.

SQLWindows COM Server Applications


You can also write COM server applications with SQLWindows. A COM server that you write can have
methods and fire events. It can be an in-process server (DLL), an out-of-process server (executable), or an
MTS component. It can contain collections and enumerations.
When you use SQLWindows to write a COM server, you combine CoClass classes and Interfaces classes. The
CoClasses correspond to the COM concept of the same name, with one exception: In SAL, CoClasses define
the set of events that can be fired (sent to the client) when the server is running. SAL interfaces correspond to
their COM counterparts, and these contain the functions that clients access through automation. In the code
of the Interfaces in your server, you “fire” the events declared in the CoClasses. Chapter 21 – Writing COM
Servers explains how to write COM servers.

COM Entities and the Outline


In the COM model, CoClasses are said to implement Interfaces; in SAL, CoClasses have their Interfaces as their
base classes, which is where the behavior of the component is implemented.
The table below maps the COM entities to the outline types:

COM Entity COM Server Outline Type COM Client Outline Type
CoClass CoClass class COM Proxy class or ActiveX class (if visual)
Interface Interface class Functional class, derived from Object class
Event interface COM server Events section Message Actions child items in COM Proxy or ActiveX
classes, or ActiveX class child windows

Getting Started with COM Client Applications


It is recommended that you do the following:
• Read the next topic about creating an ActiveX component.
• Read COM Client Class Outline Structure on page 459 to become familiar with the include file that the
Controls palette and ActiveX Explorer generate.
• If you want to use Microsoft Office components, read Using Microsoft Office Components on page 461. If
you are using another vendor’s component, read that vendor’s documentation.
• Read Automation on page 469, Handling Events on page 472, and Properties on page 473 to learn the
basics of manipulating a component in a SQLWindows application.
• Read other sections of this chapter as needed depending on the features of COM you are using.

451
Creating a COM Component
There are two ways to create an object at design time in SQLWindows:
• With the Controls palette
• With ActiveX Explorer
The Controls palette is the most convenient way. Using it, you have direct access to the ActiveX objects
installed on your computer. With ActiveX Explorer, you must know the name of the type library that contains
the object you want. A type library can contain many objects, so you may have to hunt for the object once the
type library is open.
The Controls Palette only contains visible objects. For non-visible objects, you must use ActiveX Explorer.
Both the Controls palette and ActiveX Explorer generate an include file with a class hierarchy for the object. In
turn, the include file includes automation.apl that defines the standard classes Object, Variant, SafeArray, and
OleErrorInfo. The file "OLE automation.apl" can also be included. It is an auto-generated file whose contents
depend on what is installed on your computer.
The Controls palette always generates the include file with the Generate Full option (see SAL code generation
options on page 457).

Using the Controls Palette


When you click the ActiveX button on the Controls palette, the list in the lower part populates with the
registered ActiveX components on the system. You can click the name of an object and drag it just to the right
of the ActiveX button to add it to the palette. You can then use the button to add the object to the application
in the same way as SQLWindows's built-in objects. You can add more buttons by dragging to the right of
existing ActiveX component buttons. To remove a button, drag it off the palette.

When you click the right mouse button while over a list of ActiveX components in the Controls palette, you
can:
• Add a button for the selected component to the Controls palette
• Choose to display only controls or insertable objects

452
To create an ActiveX component at design time using a button on the Controls palette, follow these steps:
1. Click the ActiveX button in the Controls palette.
2. Select an ActiveX component in the list and drag it just to the right of the ActiveX button
OR
Select an ActiveX component in the list, click the right mouse button and select Add to Palette.
3. To create the object, click its button and then draw it on the top-level window as you would any other
object.
To create an ActiveX insertable object at design time using the Insert Object dialog:
4. Click the ActiveX button in the Controls palette.
5. Draw the object on the top-level window as you would any other object. The Insert Object dialog
appears.
6. Select an insertable object in the dialog and click OK.
To create an ActiveX insertable object at design time using the Paste Special dialog:
7. Click the ActiveX button in the Controls palette.
8. Draw the component on the top-level window as you would any other object. The Insert Object dialog
appears.
9. Click Cancel.
10. Later, select the insertable object, right-click the mouse, and select Paste Special. The Paste Special
dialog appears.
11. In the Paste Special dialog, set the options and click OK.
To create an ActiveX insertable object at runtime (an empty ActiveX container) using the SAL ActiveX API:
12. Click the ActiveX button in the Controls palette, but do not choose any specific control from the
dropdown list.
13. Draw the component on the top-level window as you would any other object. The Insert Object dialog
appears.
14. Click Cancel.
15. In your application logic, call a SAL ActiveX API function to create the object.

453
Using ActiveX Explorer
An ActiveX object appears as a functional class in the outline. The functional class is derived from the Object
base class. You use ActiveX Explorer to generate the functional class. When you import an interface, its
functional class has the same name as the ActiveX interface in the type library. If this causes a name clash,
you can rename the functional class.
ActiveX Explorer lists all the type libraries available on the computer. You can select any set of interfaces.
You use ActiveX Explorer to display the contents of an ActiveX server type library (*.OLB, *.TLB, *.DLL, *.OCX,
*.EXE). ActiveX Explorer parses a type library showing:
• CoClasses, interfaces (dispatches or dispinterfaces), enums, and events
• Members of the above: other interfaces, methods, and properties
• Method parameters and returns as both SAL and COM types
After viewing a type library, you can use ActiveX Explorer to generate SAL code for interfaces that you select.
ActiveX Explorer creates an APL with a class hierarchy that invokes the methods of the server. ActiveX
Explorer includes this APL in the current application.
ActiveX Explorer can also check an AXLibs *.APL and open its corresponding type library.
ActiveX Explorer can also open context-sensitive help for a type library if help for the type library exists.

Starting ActiveX Explorer


You start ActiveX Explorer by:
1. Selecting Tools > ActiveX Explorer.
2. Clicking the ActiveX Explorer button in the ActiveX toolbar.
3. Selecting Explore ActiveX Library from a context menu when positioned on an item that is included from
an AXLibs *.APL or a File Include statement that refers to an AXLibs *.APL. In this case, ActiveX Explorer
opens the type library automatically.

Toolbar

From left to right, this is the function of each of the buttons:


• Displays ActiveX Explorer open type library dialog
• Displays the help file for the open type library
• Generates an *.APL for the open type library
• Sets the options for generating an *.APL
• Regenerates the *.APL for the open type library
• Includes the *.APL for the open type library in the outline
• Shows or hides CoClasses in the open type library
• Shows or hides interfaces in the open type library

454
• Shows or hides events in the open type library
• Shows or hides enums in the open type library
• Shows or hides functions in the open type library
• Shows or hides get properties in the open type library
• Shows or hides set properties in the open type library
• Displays data types as SAL data types or as automation data types There is also an ActiveX Explorer menu
to the right of the Tools menu when you display ActiveX Explorer. The items in this menu correspond to
the toolbar buttons.

Selecting a type library


When you start ActiveX Explorer, you are prompted with a dialog to select a type library or an AXLibs *.APL
file.
The path name in the lower part of the dialog is scrollable for long names.

By default, when you select GUPTA APLs, ActiveX Explorer displays the names of APLs in the AXLibs directory,
but you can click the Browse button to navigate to a different directory.
When you select an *.APL and click OK, ActiveX Explorer checks the APL to find the name of the type library,
and then opens and reads that type library.
455
Note: If, while trying to generate an APL from a 3rd-party product, you get an "IDS_Unexpected Error," you
might have a registry issue caused by multiple conflicting versions or a faulty installation of the
ActiveX object. Often this issue is easily remedied by reinstalling the ActiveX object.
After ActiveX Explorer opens a type library, it displays a dialog with three sections:
• ClassView, a list in the upper left-hand part
• MembersView, a list in the upper right hand part
• InfoView in the bottom part
Each of these sections has its own context menu.
You can resize the ClassView, MembersView, and InfoView sections using the splitter cursor.

ClassView
The ClassView shows CoClasses, interfaces, event sets, and enumerations in the type library.

By default, the ClassView section lists its items alphabetically, but you can check Group Members in the
context menu to sort the list by type. You can also view only certain types by checking items in the context
menu.
When you select Generate, SQLWindows creates an AXLibs *.APL and includes it in the current application.
What SQLWindows puts in the *.APL depends on the options you set in Generate Options and on the items
you check in the ClassView. You can individually check certain items in the ClassView or select Check All
Shown in the context menu to check all items.
These are examples of the icons in the ClassView:

456
SAL code generation options
In the ActiveX Explorer Code Generation dialog, you specify how you want ActiveX Explorer to generate SAL
Proxy classes for the items selected in the ClassView:

Stub. Generates the selected classes without any functions. Use this option when you need some classes to
appear in the outline that, although your code does not use them directly, are referred to in the Functions of
the classes you do use. Stub generation of a CoClass will cause stub generation of its interfaces, even if they
are not selected in the list.
Full. Generates the selected classes with implementations for all of the classes' functions. In addition, this
option generates stub classes for any classes that are directly referred to by the ones that are being
completely generated, so that the APL code can compile.
Deep. Generates the selected classes with implementations for all of the classes' functions. In addition, this
option generates all classes that are directly or indirectly referred to with implementations for all of their
functions.
The option selected here is the default Generate option in ClassView context menu, The ActiveX Explorer
toolbar, and the ActiveX Explorer menu.

Note: A side effect of the general 64-character limitation for symbol names is that ActiveX Explorer will
abandon its naming convention if it generates a symbol name larger than 64 characters. For example,
when working with COM objects from Microsoft Word, constants are usually named in the format
<ENUM_NAME>_<VALUE_NAME>. But that can lead to an excessively long name like
Word_wdPhoneticGuideAlignmentType_wdPhoneticGuideAlignmentZeroOneZero. In such a case, the
ENUM portion of the name is dropped, and only the VALUE is used:
wdPhoneticGuideAlignmentZeroOneZero.

Invoke Options
Invoke by Function Name. Invoking by function name is particularly desirable for generating client code for
development of custom COM servers and ActiveX objects. The dispatch IDs for these objects may change
during development. They can also change from version to version. An incorrect dispatch ID can result in a
wide range of problems, from runtime errors to undefined program behavior. The worst case would be the
intended method having the same parameter list as the actual called method, but different functionality.
Invoking by name avoids such problems, although it is slower.

457
Invoke by Dispatch ID. Invoking a COM object by using its dispatch ID is signficantly faster than using a
function name. This is especially true when invoking the object a large number of times, as in filling a
spreadsheet from a database.
You can generate an interface from the ClassView list by selecting it for generation, or by selecting a CoClass
that implements that interface.
If you generate enumerations, SQLWindows adds each member as a constant in the outline.

Storing your preferences


The generate options that you choose are stored in the registry and are used as the default the next time you
run the Generate action in ActiveX Explorer.

MembersView
The MembersView displays the items in a CoClass, interface, event set, or enumeration.

• When a CoClass is selected in ClassView, the MembersView displays interfaces for that CoClass
• When an interface is selected in ClassView, the MembersView displays methods in that interface
• When an enumeration is selected in ClassView, the MembersView displays its enumerations
• When an event set is selected in ClassView, the MembersView displays its events
As with the ClassView, you can list the item alphabetically (default) or by type and you can choose to show
only certain types of items.
These are examples of the icons used in the MembersView:

458
InfoView
The InfoView section displays details about the selected item in the ClassView or MembersView.

The context menu enables you to:


• Switch between displaying a function or event in its SAL form, using SAL data types, or in its COM form,
using automation data types.
• Open the help file for the type library. If the InfoView is displaying information for an item, ActiveX
Explorer sets the help display to that topic when possible.

COM Client Class Outline Structure


When you generate COM proxy classes, either through ActiveX Explorer, or automatically when an ActiveX
control or object is created through the Controls palette, SQLWindows creates an APL with proxy classes that
access the COM component. The top three levels of this class hierarchy are the same for visual and non-visual
objects.

To learn more about these classes read Object Class on page 477 and COM Proxy Class on page 478.

459
When SQLWindows generates a COM Proxy class, it also generates a functional class for each interface that
the CoClass implements. The classes are added to the base classes of the COM Proxy class. These functional
classes provide the means to access the functionality provided by the COM component.
If the class is visual, SQLWindows generates a further class:

This is an example of how a nonvisual class hierarchy appears in the outline:


Functional Class: Word Application ! Interface
...
Derived From
Class: Object
...
Functions
Function: PropSetVisible
Function: HelpTool
Function: Quit
...
COM Proxy Class: Word_Application
...
Derived From:
Class: Word Application
...
Functions
Function: CreateEx
Function: Create
Function: GetInterface
Function: Release
At runtime, a nonvisual COM object does not exist until you call its Create method:
Call MyCOMProxy.Create
Here is an example of how a visual class hierarchy appears in the outline:

460
Functional Class: Word Document
...
Derived From
Class: Object
...
Functions
...
COM Class: Word_Document
...
Derived From
Class: Word Document
...
Functions
Function: GetInterface
...
ActiveX Class: AX_Word_Document
...
Derived From
Class: Word_Document
...

Using Microsoft Office Components


Microsoft Office applications are controlled through the automation interface. Visual Basic for Applications
(VBA) provides a programming environment and a language for you to extend Office’s capabilities, integrate
Office with other software applications, and incorporate Office into a set of business processes.

Learning the Object Hierarchy


In Office, almost all the functionality and all the viewable content is represented by an equivalent object in
VBA. Because these objects are programmable, you can develop a SQLWindows application that manipulates
the properties that an object exposes.
The collections of Office objects are categorized by Word, Excel, PowerPoint, Access, Outlook, or Office itself,
and they allow you to navigate down to a detailed level in a document.
Each Office application uses an object hierarchy where most objects are described in relation to another
object. The object model for each application defines which components are available under program
control. All Office applications have the same general hierarchy model of objects, with the Application object
residing at the
top. Each object represents an element of an application, such as a cell in a worksheet or a word in a
document. To effectively use an Office application through SQLWindows and ActiveX, you must learn the
application’s object hierarchy.
VBA has two types of documentation: MSDN and online help.

MSDN Documentation
If you have MSDN (Microsoft Developer Network), you can find the Visual Basic Programmer’s Guide and
Visual Basic Language Reference for Office 97 VBA in:
• Office Developer Documentation/Office 97 Documentation

461
You can find the Developer Object Model Guide, Visual Basic Programmer’s Guide and Visual Basic Language
Reference for Office 2000 VBA in:
• Office Developer Documentation/Office 2000 Documentation

Installing Online Help


The VBA online help for Microsoft Office applications is not installed by default. You must explicitly ask that it
be installed. Each Office application has its own VBA help file.

Office 97
To install the help for Office 97 VBA, follow these steps:
1. Start the install program. For a new installation, complete each dialog until you get to the one where it
asks you the type of installation you want. Select Custom.

462
If you already have Office 97 installed, select Add/Remove.

2. Select the application (such as Excel) for which you want to install VBA help. Click Change Option.

3. Select the help component. The wording varies according to the application.

463
Application Wording
Access Help Topics
Excel Help and Sample Files
PowerPoint Help
Word Help

4. Select Change Option. As with the previous dialog, the wording varies according to the application, but
you want to check Help for Visual Basic, Online Help for Visual Basic, or Programming Help.

5. Click OK and complete the remaining installation steps.


Important: You must repeat the steps above for each application for which you want to install VBA help.
Installing Outlook 97 VBA help. The Office 97 installation program cannot install the VBA help for Outlook.
You must manually copy the files. The VBA help file for Outlook is in the ValuPack directory on the Office 97
CD.
To install the help file, follow these steps:
1. Quit Help.
2. Insert the Office CD.
464
3. In the ValuPack directory, double-click the MoreHelp subdirectory.
4. Select the vbaoutl.hlp and vbaoutl.cnt files.
5. Copy these two files to your Office 97 installation directory (usually C:\Program Files\Microsoft
Office\Office).
6. If asked whether you want to replace the existing versions of these files, click Yes.
7. To update the table of contents and the index so that they include the topics in the files you just copied,
select Start > Find and then click Files or Folders.
8. In the Named field, type *.gid.
9. In the Look in field, type C:\Program Files\Microsoft Office\Office (or your installation directory) and
then click Find Now.
10. When the file names appear at the bottom of the dialog box, select all of them and select File > Delete.

Office 2000
1. Start the install program and proceed to the “Selecting Features” step.
2. Expand the Office Tools branch.
3. Select Visual Basic Help and click.

4. Select Run all from My Computer.


Warning: Selecting Run from My Computer does not install the files.
5. Proceed with the installation.

Help file names

Application Office 97 Name Office 2000 Name


Access acvba80.hlp acmain9.chm
Excel vbaxl8.hlp vbaxl9.chm
Office vbaoff8.hlp vbaoff9.chm
Outlook vbaoutl.hlp vbaoutl9.chm
PowerPoint vbappt8.hlp vbappt9.chm

465
Word vbawrd8.hlp vbawrd9.chm

Viewing the object hierarchy in help


To get an overview of the class hierarchy for Word 97, open vbawrd8.hlp, double- click “Getting Started
with Visual Basic”, and then double-click “Microsoft Word Objects”.

For Word 2000, this topic is displayed automatically when you open vbawrd9.chm.
To get an overview of the class hierarchy for Excel 97, open vbaxl8.hlp, double-click “Getting Started with
Visual Basic”, and then double-click “Microsoft Excel Objects”.

466
Controls
For Excel 2000, this topic is displayed automatically when you open vbaxl9.chm.
A control is a lightweight, in-process object. A control typically implements IDispatch (automation) and type
information, and can have events. A control has an *.OCX extension.

Container Controls (Insertable Objects)


The container control is a runtime placeholder for insertable objects such as a Microsoft Excel worksheet or a
Microsoft Word document. An insertable object follows the guidelines for the OLE documents interface and
supports embedding. An insertable object can be automated (implementing IDispatch). An insertable object
usually runs as a local/remote server. An insertable object may also support in-place activation.
At runtime you can create the object that is displayed in the container control or change an object you placed
in the container control at design time. You can also use the container control to create an object based on a
file.
The main advantage to using the ActiveX container control to embed automation objects is that users can
insert any one of a variety of object types into an application at runtime and subsequently manipulate the
object programmatically via the SalActiveX* API.
To create an ActiveX container control, follow these steps:
1. Click the ActiveX button on the Controls palette.
2. Draw the control on a form or dialog.
3. Click Cancel because you do not want to do any further development to the control at design time.

Embedded Objects
Data associated with an embedded object is contained in an ActiveX container control and can be saved
with your application.
Note: To place an object in an ActiveX container control, the object must be in your system registry. When
you install an application that supplies the objects you want to use in your application, that
application should register its object library on your system so that application's objects appear in the
Insert Object dialog and in the Controls palette.
When you use an ActiveX container control to create an embedded object, all the data associated with the
object is copied to and contained in the ActiveX container control. When you save the contents of the control
to a file, the file contains the name of the application that produced the object, the object's data, and a
metafile image of the object. For this reason, embedded objects can greatly increase the size of an
application.

Creating Embedded Objects


When you create an embedded object, you can either embed data from a file or create a new empty object
that can be filled with data later. When you embed data from a file, a copy of the specified file's data is
displayed in the ActiveX container control. When you create a new object, the application that created the
object is invoked and you can enter data in the object.
467
You usually create embedded objects that display existing data at design time. This lets you view the object's
data as it appears to the user of the application.
To display existing data in an embedded object, create the object using an existing file as a template. The
ActiveX container control then contains an image of the data in the file. An application that displays data
using an embedded object will be larger than an application that displays the same data using a linked object
because the application with the embedded object actually contains the source file's data.
To create an embedded object, follow these steps:
1. Click the ActiveX button on the Controls palette.
2. Draw the control on a form or dialog.
3. Click Create from File.
4. Click Browse. SQLWindows displays the Browse dialog.
5. Navigate to the file you want to embed and select it.
6. Click Open. The Insert Object dialog reopens.
7. Click OK to create the embedded object.

SalActiveX Functions
For details about these functions, read the online help. These functions provide support for all ActiveX
objects.

Name Description
SalActiveXAutoErrorMode Turn off automatic error handling (on by default) by calling this function and
specifying FALSE. Later, you can turn automatic error handling on by calling
this function and specifying TRUE.
SalActiveXGetActiveObject Gets an instance of an ActiveX object when the server application is already
up and running.

You can programmatically manipulate a container control and its contents at runtime using these functions.

Name Description
SalActiveXClose Closes an object and ends the connection to the application that provided
the object.
SalActiveXCreate Creates an object given its class descriptor (progID).
SalActiveXCreateFromData Recreates an object from binary storage data, in the form of a string.
SalActiveXCreateFromFile Creates an instance of an ActiveX object.
SalActiveXDelete Deletes an instance of an ActiveX object.
SalActiveXDoVerb Opens an object for an operation such as editing. Each object can support its
own set of verbs.
SalActiveXGetData Gets the storage (state and data) associated with the object as a raw blob of
bytes. This provides an alternate runtime persistence mechanism for
embedded objects.

468
Name Description
SalActiveXGetFileName Gets the file name of an ActiveX object that was inserted into a window
using the SalActiveXInsertObjectDialog function and the “Create from File”
option.
SalActiveXGetObject Gives access to the automation dispatch interface of the object in the
specified container.
SalActiveXGetProgID Gets the ProgID of an ActiveX object that was inserted into a window using
the SalActiveXInsertObjectDialog function and the “Create from File” option.
SalActiveXInsertObjectDlg Displays the standard Insert Object dialog.
SalActiveXOLEType Returns the status of the object in an ActiveX container control.

Automation
Automation is an industry standard used by applications to provide objects in a consistent way to other
applications, development tools, and macro languages. To use automation, the object must support the
IDispatch interface.
There are two type of automation: static and dynamic.

Static Automation
With static automation, type information is available at compile time (early bound) and all calls are type
checked for validity.
With static automation, you use ActiveX Explorer or the Controls palette to generate a functional class
derived from the Object class. This derived class contains a function for each of the object's methods. Each
function pushes any parameters onto the stack, invokes the method, and pops a return.
For example, ActiveX Explorer generated this code to invoke a tree control's GetNode method:
Function: GetNodes
Description:
Returns
Boolean:
Parameters
ComctlLib_INodes: returnValue
Static Variables
Local variables
Boolean: tmpret
Actions
Set tmpret = Invoke("Nodes", INVOKE_GET)
Call PopObject(-1, returnValue)
Call FlushArgs()
Return tmpret
In code you write, you call the method:

469
ComctlLib_INodes: theNodes
ActiveX: ax1
...
Call ax1.GetNodes( theNodes )
Important: If a method returns a value that you want to check, code an additional parameter for it.

Code generation for international servers


SQLWindows tries to use language-independent method names (with no translation) by calling methods via
Invoke. If language-independent method names are not available, SQLWindows calls methods by number
with InvokeID.

Dynamic Automation
With dynamic automation, you use the methods of the Object class directly to make calls to the server. You
do not use ActiveX Explorer to generate method invocations. No type information is used and invalid
invocations can cause runtime errors.
Push any parameters onto the stack and then invoke the method:
xlapp.PushStringByRef( "hello" )
xlapp.Invoke( "SetActiveCell", INVOKE_FUNCTION )
To invoke a method, do the following:
1. Push parameters onto the stack, either by value or by reference.
2. Execute the method by calling Invoke or InvokeID.
3. Pop the parameters off the stack.
4. Flush the parameters from the stack by calling FlushArgs.
The easiest way to write this code is to let ActiveX Explorer generate it automatically and then use that as a
starting point. The examples below show the code that is generated by ActiveX Explorer.

Pushing parameters by value


This example shows the generated code for the SetObserverWindow method in the GUPTA Replication
Synch Agent component. This is how the method is defined in IDL (Interface Definition Language):
[id(0x00000017), helpstring("Set a window handle to receive Phase
notifications.")]
VARIANT_BOOL SetObserverWindow(OLE_HANDLE hWndObserver);
This is the code that ActiveX Explorer generates:

470
Function: SetObserverWindow
Description:
Returns
Boolean:
Parameters
Number: hWndObserver
Receive Boolean: returnValue
Static Variables
Local variables
Boolean: tmpret
Actions
Call PushNumber(hWndObserver, VT_R8)
Set tmpret = Invoke("SetObserverWindow", INVOKE_FUNCTION)
Call PopBoolean(-1, returnValue)
Call FlushArgs()
Return tmpret

Pushing parameters by reference


This example shows the generated code for the Add method for the Collection object in Visual Basic for
Applications. This is how the code is defined in IDL:
[id(0x00000001), helpcontext(0x000f7901)]
HRESULT _stdcall Add(
[in] VARIANT* Item,
[in, optional] VARIANT* Key,
[in, optional] VARIANT* Before,
[in, optional] VARIANT* After);
This is the code that ActiveX Explorer generates:
Function: Add
Description:
Returns
Boolean:
Parameters
Variant: Item
Variant: Key
Variant: Before
Variant: After
Static Variables
Local variables
Boolean: tmpret
Actions
Call PushVariantByRef(Item)
Call PushVariantByRef(Key)
Call PushVariantByRef(Before)
Call PushVariantByRef(After)
Set tmpret = Invoke("Add", INVOKE_FUNCTION)
Call PopVariant(0, Item)
Call PopVariant(1, Key)
Call PopVariant(2, Before)
Call PopVariant(3, After)
Call FlushArgs()
Return tmpret

Creating Objects at Runtime


This is a specialized form of dynamic automation where you create a generic instance of the Object class that
is untyped at design time. You wait until runtime to set it to a specific object.
471
Create an instance of the Object class:
Object: xlapp
At runtime, you call the Object’s CreateObject method to create a specific object.
xlapp.CreateObject( ’Excel.Sheet.8’ )
You can then call methods in the object.

Handling Events
An event interface is part of a CoClass signature. A COM server interface fires events. A SQLWindows client
application can process events from both visual and non-visual servers. An event belongs to CoClass, not to a
window, and there is no correspondence between events and Windows messages.
If an ActiveX control has defined events, SQLWindows represents the event in the Message Actions section of
the outline. Event handlers have a fixed signature (as defined by the control), but you define the
implementation in the Message Actions block.

The following diagram shows where you process events.

472
To process events with non-visual servers, you derive a new COM Proxy Class from the generated COM Proxy
Class. The events for the COM Proxy Class appear in Coding Assistant and in the context menu when you are
positioned in the Message Actions in derived classes.
COM Proxy Class: WordApp
Description:
Derived From:
Class: Word_Application
...
Message Actions
On DocumentChange
Parameters
Actions
...
On Quit
Parameters
Actions
...
To process events with visual servers, add code in the message actions of instances of the ActiveX Class. The
events for the ActiveX Class appear in Coding Assistant and in the context menu when you are positioned in
the Message Actions of an instance of an ActiveX class.
If an event has parameters, SQLWindows adds definitions of them to the Parameters section. This example
shows an instance of a visual ActiveX object:
AX_MSACAL_Calendar: CalendarCtrl
Message Actions
On KeyDown
Parameters
Receive Number: KeyCode
Number: Shift
Actions
...
SQLWindows assumes that any numeric event parameter is the same subtype as defined by the server. You
may also add subtypes to the definition of numeric event parameters, which may change the numeric value
that the server passed. For example, if the server defines an event parameter as subtype VT_R8 and passes
the value 3902.58, your client application will receive that value. But if you manually add a subtype of VT_I4
to the parameter definition in your client application, it will then receive a value of 3903.
GUPTA recommends that you explicitly add the appropriate subtype to each numeric event parameter
defined by your client application.

Properties
When an ActiveX object is selected, the Attribute Inspector displays the properties of the control and you can
edit them.

Ambient Properties
ActiveX objects usually ask their container for the current values of certain stock entities such as font and
background color. This provides a consistent look-and-feel coordination between controls in a window.

473
In-Place Activation
When an ActiveX object supports in-place activation, a user can double-click the object to interact with the
application supplying the object without switching to a different application or window. The menus and
toolbars of the server application merge with those of the application that contains the object.
By convention, only embedded objects support in-place activation.

Toolbar and Menu Merging


For objects that support in-place activation, SQLWindows merges the toolbars of an object server
application in these ways:
• At design time, SQLWindows negotiates border space with the main SQLWindows window
• At runtime, SQLWindows negotiates border space with the parent window of the container control
SQLWindows follows similar rules for menu merging:
• At design time, SQLWindows merges the object server's menus with the menu in with the main
SQLWindows window
• At runtime, SQLWindows merges the object server's menus with the menu in the parent window of the
container control

Menu Groups
In ActiveX, menus in clients and servers are assigned to menu groups. ActiveX clients have these three
groups:
• File
• Container
• Window
ActiveX servers have these three groups:
• Edit
• Object
• Help
The actual menus that go into each group depend on the nature of the application. However, when an
ActiveX client merges its menus with a server's, it follows this strict order:
File Edit Container Object Window Help
group group group group group group
(client) (server) (client) (server) (client) (server)

474
Collections
A collection is a group of related objects that can be indexed numerically like an array. A collection lets you
work with a set of similar things as a single group instead of as independent entities.
SQLWindows supports ActiveX collections with these methods in the Object class:
• IsCollection
• Next
• Reset
• Skip
The Object class methods let you manipulate a collection in a type-independent manner. A collection is a
dispatch interface that has a property name "_NewEnum" or "NewEnum". The DISPID of this property is
always DISPID_NEWENUM. The IsCollection method in the Object class looks for this property to determine if
the object is a collection. The Next, Reset, and Skip methods are implemented through a COM interface
named IEnumVARIANT.
The methods implemented in a collection’s actual interface let you manipulate a collection in a type-
dependent manner. A collection’s interface must implement these methods:
• Count
• Item
These methods are optional for a collection:
• Add
• Remove

Handling Exceptions
SQLWindows has two types of ActiveX error handling:
• Default error handling where SQLWindows detects ActiveX error and displays a standard error dialog
• Custom error handling where you detect and handle errors
Automatic error handling is turned on by default. SalActiveXAutoErrorMod

Custom Error Handling


To handle errors yourself, Call SalActiveXAutoErrorMode and specify FALSE for its parameter.
For custom error handling, you create an instance of the OleErrorInfo class. When the Object's Invoke or
InvokeID method returns FALSE, call GetLastError to fill in the instance variables in OleErrorInfo. Here is the
declaration for GetLastError:
bOK = GetLastError( olexException )
Gets a detail about an error when an Invoke fails. The textual description of the error is obtained from the
description field of OleErrorInfo structure. Source of the error is obtained from the source field. The helpFile

475
field contains the fully qualified drive, path, and file name of a Help file with more information about the
error. The Help context ID of the topic within the Help file can be obtained from the helpContext.
The scode field will contain a value describing the error. Either this field or wcode (but not both) will be filled
in.
If you turn off automatic error handling, you may need to include extra logic in your application to properly
decode some errors. For example, if you are using the Microsoft Rich Text control, and your application
supplies an invalid file name as a property to that control, the error returned in the scode field is –
2146828213. In Visual Basic, the same error would return 75. To get the 75 value in SAL, convert the large
negative value to hexadecimal, extract the rightmost four hex digits (004B), and then convert that value to
decimal (75).
Parameters
olexExceptionOleErrorInfo. An instance of the ActiveX exception class.
Return value
bOK is TRUE if the function succeeds and FALSE if it fails.
You can then check the instance variables or use them in a custom error dialog. Here’s an example:
ActiveX ax1
OleErrorInfo oError

If ax1.GetLastError( oError )
Set mlDesc= oError.description || oError.source
Set dfScode= oError.scode
Set dfWcode=oError.wcode
Set dfHelpContext = oError.helpContext
Set dfHelpFile = oError.helpFile
The variables in OleErrorInfo are the following:

Variable Name Description


scode Return value
wcode Error code
source Version-independent progID
description Explanation of error
helpFile Fully qualified help file path and file name
helpContext Help context ID of relevant help topic

Either wcode or scode is filled in; the other is zero.

Include Libraries
When you add an ActiveX component to an application, SQLWindows generates wrapper classes in an include
library that is included by your application. GUPTA creates one include library per type library and as you add
components to your applications, GUPTA adds to the include library. SQLWindows uses the root name of the
type library and adds an *.APL extension.
SQLWindows uses this mechanism so that it does not have to regenerate the wrapper classes each time you
reuse a component.
476
You can set the directory where SQLWindows stores the ActiveX include libraries, by selecting Tools >
Preferences, clicking the Directories tab, and specifying a directory in the ActiveX Libraries field (see
Preferences on page 94).

Regenerating Include Libraries


ActiveX include libraries can become obsolete when a component with a changed interface is re-installed on
a computer. In this case, you must regenerate the include file with the Controls palette or ActiveX Explorer.
ActiveX Explorer remembers the options that you specified in the last Generate action, regardless of which
component you were generating, and uses those options as the default in the current Generate. You must be
careful to confirm that the options, especially for Invoke, are appropriate for the include file you are
regenerating.

Licensing
Some controls ship with a license file that limits the control’s use to where they are installed. When you add
such a control to an application, SQLWindows stores the license in the outline. When SQLWindows creates
the control for deployment, it uses the license to validate creation of the control.

Object Class
The Object class represents an ActiveX dispatch interface. The Object class contains methods to manage
automation. You use it to call functions and get and set properties on an ActiveX object:

Name Description
Attach Attaches this Object to the dispatch of another Object
Count Counts the number of items in a collection.
CreateObject Creates an automation object locally.
CreateObjectEx Creates an automation object on a remote server.
Detach Disassociates an object from its server to force release early. This frees resources when an
application no longer needs an object.
FlushArgs Call this function after popping parameters off the stack to reset the stack
GetLastError Gets details about an error when an Invoke fails
Invoke Invokes a method by name.
InvokeID Invokes a method by its dispatch ID.
IsCollection Determines whether an ActiveX object is a collection.
IsDispatchVaild Determines whether an ActiveX object has a been attached as an automation object.
Next Gets the next item in an ActiveX collection.
Pop* Pops a parameter value off the stack after invoking a method.
Push* Pushes a parameter value onto the stack before invoking a method.

477
Name Description
Push*ByRef Pushes a parameter value by reference onto the stack before invoking a method. Use this
function when the function you are invoking can change the value you are passing.
Reset Resets the ActiveX collection back to the first item.
Skip Moves the internal pointer in an ActiveX collection forward by a number of elements.

COM Proxy Class


The methods in the COM Proxy Class are for COM management:

Function Description
Create Creates an instance of the CoClass.
CreateEx Creates an instance of the CoClass on a remote host.
GetInterface Attaches a proxy functional class variable to the named interface ID with an empty string
corresponding to the default interface.
Release Releases the association between the COM class variable and the SQLWindows data
structures.

Variant Class
The Variant class represents the ActiveX VARIANT runtime data type. A Variant can contain any kind of data.
You can use the Variant class in place of any data type (including built-in data types and the Object data type)
to work with data in a more flexible way.
SQLWindows uses the Variant type to pass parameters for dispatch interfaces (IDispatch) used in automation.
Warning: The Variant class is intended only for supporting interfaces to ActiveX and is not recommended as a
general purpose class for SAL programming. This class is not appropriate for most general purpose SAL
programming. Instead use the native SAL types for non-ActiveX programming.
Warning: When storing data in a Variant object, the data is copied. This includes storing Strings and
SafeArrays. This is necessary for transporting data to and from ActiveX components, but causes significant
performance problems if used for general purpose SAL programming. Instead, you should use SQLWindows's
native arrays and Strings as much as possible and only convert to a SafeArray when required for ActiveX.

Methods
For details about the following methods, see the online help.

Name Description
ActiveXType Returns the type of value stored in the Variant.
AsActiveX Changes the Variant to the VT_* type you specify.
Get* Gets a value stored in the Variant.

478
Name Description
MakeOptional Call this when using a Variant as an optional parameter.
SalType Returns the SAL data type.
Set* Assigns the specified value to the Variant.

Data Type Mappings


SAL data types map to ActiveX VARIANT types as follows:

Automation Type Description SAL Type Constants SAL Data Type


Constants
Not applicable Not applicable SAL_ARRAY SafeArray
VT_BOOL TRUE=-1, FALSE=0 SAL_BOOLEAN Boolean
VT_BSTR OLE automation string SAL_STRING String
VT_CY currency SAL_NUMBER Number
VT_DATE date SAL_DATE Date/Time
VT_DISPATCH IDispatch SAL_OBJECT Object
VT_ERROR SCODE SAL_NUMBER Number
VT_EMPTY Variant created, but not Not applicable Not applicable
assigned a value
VT_I1 1-byte signed int SAL_NUMBER Number
VT_I2 2-byte signed int SAL_NUMBER Number
VT_I4 4-byte signed int SAL_NUMBER Number
VT_R4 4-byte real SAL_NUMBER Number
VT_R8 8-byte real SAL_NUMBER Number
VT_UI1 1-byte unsigned int SAL_NUMBER Number
VT_UI2 2-byte unsigned int SAL_NUMBER Number
VT_UI4 4-byte unsigned int SAL_NUMBER Number
VT_UNKOWN IUnknown interface Not applicable Not applicable
VT_VARIANT VARIANT SAL_VARIANT Variant
VT_VOID C-style void SAL_NUMBER Number
Not applicable Not applicable SAL_NOTYPE Unknown; possibly
corrupt

479
SafeArray Class
You use SafeArrays to pass arrays along with information about the array's dimensions and bounds. The
reason they are “safe” is because the array itself is a data structure that contains boundary information as
well as actual reference to the data.
Warning: When storing data in a Variant object, the data is copied. This includes storing Strings and
SafeArrays. This is necessary for transporting data to and from ActiveX components (marshalling), but causes
significant performance problems if used for general purpose SAL programming. Instead, you should use
SQLWindows's native arrays and Strings as much as possible and only convert to a SafeArray when required
for ActiveX.
You can create three types of SafeArrays:
• One dimensional
• Two dimensional
• Multi-dimensional
There is a separate type for two dimensional arrays because they are common. The multi-dimensional array is
generic.
This class has the methods in the table below. For details about these methods, read the online help.

Name Description
Create Creates a single-dimensional SafeArray.
Create2D Creates a two-dimensional SafeArray.
CreateMD Creates a multi-dimensional SafeArray.
GetLowerBound Returns the lower bound in a single-dimensional SafeArray.
GetLowerBound2D Returns the lower bound in a two-dimensional SafeArray.
GetLowerBoundMD Returns the lower bound in a multi-dimensional SafeArray.
Get* Gets a Date, Number, Object String, or Variant from an array element in a single-
dimensional SafeArray.
Get*2D Gets a Date, Number, Object String, or Variant from an array element in a two-
dimensional SafeArray.
Get*MD Gets a Date, Number, Object String, or Variant from an array element in a multi-
dimensional SafeArray.
GetUpperBound Returns the upper bound in a single-dimensional SafeArray.
GetUpperBound2D Returns the upper bound in a two-dimensional SafeArray.
GetUpperBoundMD Returns the upper bound in a multi-dimensional SafeArray.
Put* Puts a Date, Number, Object String, or Variant into an array element in a single-
dimensional SafeArray.
Put*2D Puts a Date, Number, Object String, or Variant into an array element in a two-
dimensional SafeArray.
Put*MD Puts a Date, Number, Object String, or Variant into an array element in a multi-
dimensional SafeArray.

480
COM Client Font and Picture Classes
SQLWindows generates font and picture classes for ActiveX controls that import standard OLE types from
StdOLE2.tlb:
• stdole_Font and stdole_StdFont
• stdole_Picture and stdole_StdPicture
These classes contain methods that get and set properties. For details about parameter and return types, start
ActiveX Explorer, and select “Standard OLE Types”.

481
Chapter 21 – Writing COM Servers
This chapter explains how to write COM servers including:
• COM Class Wizard
• Outline structure
• Events
• Collections
• Enumerations
• Object instantiation and assignment
• Interface inheritance
• Debugging
• Type information
• Registering servers
• Threading support
• MTS support
Important: Before reading this chapter, see COM Concepts on page 448.

Overview
You can write COM automation servers with SQLWindows and create non-visual business objects. You use the
Interface and the CoClass outline types to write COM servers. Through COM automation, clients can call
methods that you write in the Interface. You can also define events in the CoClass and fire them in the
Interface code. Clients can process these events.
SQLWindows generates GUID identifiers automatically for a server class and its interfaces, methods, and
events. SQLWindows automatically generates type library information about the server.
You can install automation servers that you write with SQLWindows as MTS packages (see MTS (Microsoft
Transaction Server) Support on page 506).
SQLWindows’s COM server support is intended for non-visual automation servers, not visual editing servers.
To write COM automation servers, you use these two types of classes: Interfaces and CoClasses. You derive a
CoClass from one or more Interfaces.

Interface implementation

482
You can derive an Interface from a functional class, or from another Interface. You can derive the CoClass
from multiple Interfaces where each Interface represents a different model of programmatic access.
Like a CoClass, an interface can use multiple inheritances. However, an Interface can only inherit from a
maximum of one other Interface, which means that any additional parent classes must be functional classes.
To generate this class hierarchy, use the COM Class Wizard.

COM Class Wizard


The COM Class Wizard lets you quickly automatically generate an initial COM server, MTS server, or just an
interface class. You then complete the class by editing in the outline.
You can derive a server from existing interfaces or from new interfaces. For MTS servers, you can request the
that the server support IObjectControl.
Important: You cannot use the wizard to edit existing CoClasses or interface classes. You can only edit the
elements of a new (just being created) entity. For example, if you derive a new CoClass from an existing
Interface, you cannot edit the Interface although the wizard will display the methods and properties of the
Interface.
You create servers and interfaces with the COM Class Wizard by specifying information in a series
dialogs as shown in the diagram below.

Select what to
generate

CoClass

Name the server, Same as for COM


set its attributes, server on the left,
name/select its with additional Name the
interfaces settings for MTS interface

Optional step
Choose collection
element type
Add argument Add function

Specify/view
Add property functions,
properties, and
Add argument events
Add event

Set attributes
483
Summary
MTS CoClass
Interface

Pick existing
interface

Set attributes

To start the COM Class Wizard, select Components > Wizards or press Ctrl+W. In the Wizards dialog, start the
COM Class Wizard by double-clicking its icon or by selecting its icon and clicking Start.

In the first dialog you specify what you want to create (CoClass, MTS CoClass, or Interface).

If you select COM server in the first dialog, SQLWindows displays this dialog where you name the server, set
its attributes, and name or select the interfaces.

484
Important: You cannot derive from more than one new interface; you can derive from multiple existing
interfaces.
Click Top level object to make this creatable by clients outside the server.
Click the Attributes button to set the description, helpstring, and help context number for the server.

To derive the server from a new interface, click New Interface. In a later dialog you specify the functions and
properties of the interface.
To make a new interface a collection, click Collection. When you click Next, SQLWindows displays a dialog
where you specify whether this is a collection of an existing class or a collection of an intrinsic data type.
To derive the server from an existing interface, click Existing Interface and Pick Interface. SQLWindows
displays a dialog where you can select existing interfaces.

485
In this dialog you select one or more existing interface classes from which you want the server class to derive.
Use the arrow buttons to move class names from the left-hand list to the right-hand list. Use the Up and
Down buttons to change the order of the derived from list.
If you specify that a server is a collection, SQLWindows displays this dialog where you specify whether the
server is a collection of an existing class or a collection of an intrinsic data type (but only those compatible
with the standard automation data types). When you click Next, SQLWindows automatically generates Item,
Add, and Remove functions, and a Count property for the collection.

For collections of Number data types, you select the corresponding automation type from the list (see Setting
the Automation Type for Numbers on page 493).

486
After you specify the information about the interfaces, SQLWindows displays the following dialog.

In this dialog you define or view the functions and properties of each interface. You can also define the
server’s events in this dialog.
Note: If the selected interface already exists, you can only view the functions, properties, and events.
To set the description, help string, and help context number for a new interface, click the Attributes button
next to the interface name.
For functions and properties, begin by selecting an interface name in the drop-down list at the top. If this is a
new interface, click Add to add a new function or property. If this is an existing interface, the functions are
listed but you cannot edit them.

Note: SQLWindows only generates function stubs for functions and properties. Later you must add code
using the outline editor.
In the Add Function dialog you specify the name of a function, its parameters, and its return type.
For returns that are Number data types, you select the corresponding automation type from the list (see
Setting the Automation Type for Numbers on page 493).

487
To add a parameter click the plus button to display the Add Argument dialog. Use the arrow buttons to
change the order of the parameters.

In the Add Argument dialog, you specify the parameter name, its data type, whether it is an array, and
whether it is passed by value or passed by reference (receive parameter). For Number parameters, you select
a corresponding automation type that same way you do for returns.
If you click the Properties tab, you can add accessor functions that read and write named attributes.

Enter the name of the property and select its data type. For Number data types, you select a corresponding
automation type that same way you do for returns and parameters.
Also select whether this is a Set or Get property only or both a Set and Get property (the default is Set only).
SQLWindows generates functions with names with this format:
• PropGetname
488
• PropSetname
To set the description, help string, and help context number of a function or property, select the function or
property and click the Attributes button below the list.
Warning: After you generate a COM server, you can edit the outline and assign unique help strings and help
contexts to the PropGetname and PropSetname functions of a given property. However, when you compile
and SQLWindows generates the type information, the PropGetname help string and context is assigned to the
PropSetname function as well. This is not a defect in SQLWindows, but is a COM feature: a property only has
one help string and context even if it has both a get and set function.
To add or view events, click the Events radio button at the top of the dialog.

To set the description, help string, and help context number of the events, click the Attributes next to the
Events radio button.
If this is a new server class, click Add to add a new event. If this is an existing class, the events are listed but
you cannot edit them.

In this dialog you specify the name of an event and its arguments. Click the plus button to add a new
argument (this displays the same dialog as for the Add Function dialog). For events that are Number data
types, you select a corresponding automation type in the Add Argument dialog in the same way that you do
for returns, parameters, and properties. Use the arrow buttons to change the order of the arguments.
SQLWindows adds the event you define to the Events section of the CoClass.

489
If you select MTS CoClass in the first COM Class Wizard dialog, the second dialog has additional items for
MTS.

If you check Support IObjectControl, SQLWindows generates an IObjectControl class (with the name specified
in the field on the right) with these functions: Activate, CanBePooled, and Deactivate.
If you check Can be pooled, SQLWindows generates a “Return TRUE” statement in the CanBePooled function.

If you select interface in the first COM Class Wizard dialog, the following dialog appears:

490
In this dialog you specify the name of the interface and whether it is a COM collection. You may also
designate an existing interface, from which the new interface inherits, by choosing an existing interface
name in the Derives From combo box.
At the end of the process, SQLWindows displays the following summary of what you generated:

Outline
This is the generated outline structure for a COM server:
Interface: ILineItem
Description: Attributes

GUID: {90B8E4A0-0010-11D4-BF61-005004707BD0}

Help String: Help Context:


0

Derived From

...

491
Class Variables Instance
Variables Functions

Function: Show
Description: Attributes

Dispatch Number: 0 Help


String:

Help Context: 0

...

...

CoClass: LineItem Description:


Attributes

GUID: {46C6976-6572-0013-0007-1900000000064}

Help String: Help Context:


0 Creatable: Yes

Derived From Class: ILineItem

Events Attributes

GUID: {90B8E4A2-0010-11D4-BF61-005004707BD0}

Help String: Help Context:


0

Event: ItemEvent Attributes

Dispatch Number: 0 Help


String:

Help Context: 0 Parameters

Receive Number: nItemID Use: VT_I4

There is no procedural code in the server class; that is in the interface classes.
“Creatable” means that the object is not creatable by the client, but can be passed to the client as a return
value or through a parameter. Some objects cannot reasonably live outside an owning object.
The Microsoft Word Document CoClass is an example. It cannot be created from outside, but can be created
by adding one to the Documents object and retrieved from the Documents object (which itself cannot be
created from outside, but must be retrieved from the application).
See Passing Objects Outside the Server on page 493.

Local Servers, In-Process Servers, and MTS Servers


In the Build Settings, you specify whether SQLWindows should generate a local server or an in-process
server. SQLWindows generates *.EXEs generated for local servers and *.DLLs for in-process servers. Also, you
can specify that SQLWindows build a *.DLL that can be installed in MTS (see Build Target tab on page 79).

492
Passing Objects Outside the Server
You can create an instance of a COM object as a global variable, a class variable, or an array element. You can
pass an instance of a COM object as a function parameter or return and as an event parameter.
All automation-compatible types are supported, which means that CoClass, Interface, COM Proxy and
functional classes that are COM Interface proxies are supported, as is the SAL Variant class type.
These types are not supported: Window Handle, SQL Handle, Session Handle, File Handle and general
Functional Classes. These types are either not meaningful or not “safe” outside the application that created
them; Window handles are not “safe” because they should only be directly accessed by their owning module,
and the others are not meaningful because they are handles to process-, module-, or thread-specific data.

Automation Types
SQLWindows exposes all SAL data types as standard automation types:

SAL Data Type Automation Type


String VT_BSTR
Number VT_I2, VT_I4, VT_UI1, VT_R4, VT_R8, VT_CY
See Setting the Automation Type for Numbers on page 493.
Boolean VT_BOOL
Date/Time VT_DATE
Object VT_DISPATCH
SafeArray VT_ARRAY

Setting the Automation Type for Numbers


When you specify that a parameter, return, event, or property is a Number, you select its corresponding
automation type. You can choose how much precision you need by selecting one of the following automation
types in the COM Class Wizard:

Automation Type C Type


VT_I2 short
VT_I4 long
VT_UI1 byte
VT_R4 float
VT_R8 double
VT_CY No C equivalent

The SAL Number data type has greater precision than any of the automation types. In most cases you can use
VT_R4 or VT_R8 to pass non-integer values.
Note: You can also set the automation type to the name of an Enum (see Setting the Automation Type to an
Enum Name on page 497).
493
You can also select the automation type after generating the class. Items with a Number data type have a
“Use” child item that specifies the corresponding automation type.

You can set the type in these ways:


• By typing it directly
• By cycling through the types with the arrow keys on the numeric keypad
• By selecting it in Coding Assistant

Defining and Firing Events


You define events in the Events section of a CoClass. An event definition is an identifier and signature only:
• An Interface class fires an event
• Clients catch and process events
An event can have parameters. You can pass objects as event parameters (see Passing Objects Outside the
Server on page 493).
An event can have Receive parameters. Events are synchronous; when a server fires an event, control does
not return to it until the client has completed processing the event. If a client changes the value of a Receive
parameter, that value is visible to the server when control returns to it.
An Interface of a CoClass fires an event. Clients of the CoClass receive and can process events.
An Interface fires an event with:
Call serverCoClassname.eventName([parameters])
In this case, eventName is declared as an event of serverCoClassname. The parameters must match the type
of the declaration of eventName.

Collections
A collection is a group of related objects that can be indexed numerically like an array. A collection lets you
work with a set of similar things as a single group instead of as independent entities.
If your server holds a number of items of the same type, you should implement a collection to enable clients
to work with them in a consistent way.
To create a collection, define an Interface class with two required methods: Count and Item.

Syntax Description
nCount = Count() Returns the number of items in the collection.

494
oDisp = Item( nItem ) Returns the item identified by the parameter.
or You must provide at least an implementation that uses a
oDisp = Item( vItem ) numeric parameter. Use a Variant parameter for iteration
schemes not based on integers.

When SQLWindows finds an interface class with methods with these names and signatures, it knows it is a
collection class.
Optionally, you can implement Add and Remove methods if they are relevant for the collection.
You can automatically generate collection interfaces using the COM Class Wizard (page 483).

Example
This is what a collection looks like in the outline:
Interface Class: INumberCollection
Description:
Attributes
GUID: {2B7FFF84-42C5-11D3-9FEB-00104B260106}
Help String:
Help Context: 0
...
Functions
Function: Item
Description:
Attributes
Dispatch Number: 0
Help String:
Help Context: 0
Returns
Number:
Parameters
Number: nIndex
...
Actions
...
Function: Count
Description:
Attributes
Dispatch Number: 1
Help String:
Help Context: 0
Returns
Number:
...
Actions
...

Enumerations
An enumeration is a named collection of numeric constants. You use enumerations with COM servers. You
code enumerations in the Enumerations section under Constants:

495
Constants
...
Enumerations
Enum: EnumName
Attributes
GUID: {0F2907E0-39FE-11D3-BF61-005004707BD0}
Help String: ‘String’
Help Context: 0001
Item: Itemname_n [=integer_value_n]
...
SQLWindows automatically assigns the GUID.
By default, the first enumerator has a value of 0, and each successive enumerator is one larger than the value
of the previous one, unless you explicitly specify a value for a specific enumerator. An Enum can contain
duplicate constant values.
To refer to an enumerator, specify the Enum name and item name together separated by a period:
enumname.name_n
The example above returns the constant value associate with the nth item in the list. You refer to an Enum
wherever you can refer to a Number.
Note: You cannot use an Enum name as a data type name.

Example
In this example, the values start at 1 and increment by 1 with Saturday being 7. If no value had been supplied
for Sunday, it would have defaulted to 0.
Enum: Day
Attributes
GUID: {731C2721-49A6-11D3-BF61-005004707BD0}
Help String: Day of the week
Help Context: 0
Item: Sunday = 1
Item: Monday
Item: Tuesday
Item: Wednesday
Item: Thursday
Item: Friday
Item: Saturday
In the following example, the values of Diamonds, Hearts, Clubs, and Spades are 5, 6, 4, and 5, respectively.
No value was specified for Hearts and Spades, so they were assigned default values (incrementing the
previous value by 1). Note that 5 is used more than once.

496
Enum: Suits
Attributes
GUID: {5741C9AA-49D4-11D3-BF61-005004707BD0}
Help String: Suits in a deck of cards
Help Context: 0
Item: Diamonds = 5
Item: Hearts
Item: Clubs = 4
Item: Spades

Setting the Automation Type to an Enum Name


You can set the automation type to the name of an Enum declared in the application. SQLWindows then
writes the Enum name in the type information; for example:
Enum: OpenStyle
...
Item: OpenNormal
Item: OpenMaximized
Item: OpenMinimized
...
Function: OpenFile
...
Parameters
Number: nOpenStyle
Use: OpenStyle
...

Dynamic Instantiation
When you declare a CoClass variable, SQLWindows creates it at runtime and you can refer to it. However, you
can re-initialize it at any time using the new keyword:
Set serverCoClassVar = new serverCoClassName
The new keyword takes as an argument the type of object being created and returns a reference to an
object of that type. serverCoClassVar must be a variable of type serverCoClassName.

Assigning COM CoClass Variables


You can assign one CoClass variable to another using the standard syntax:
Set CoClassVar2 = CoClassVar1
CoClassVar2 and CoClassVar1 must be the same type, or CoClassVar2 is of a type from which the type of
CoClassVar1 derives.
Important: CoClass variables are references, not actual values. After you perform an assignment, both
variables refer to the same object and changes made through one variable changes the object itself and that
change is visible in any other variable that refers to that object.

497
Setting CoClass Variables to Null
Use the OBJ_Null constant to make a CoClass variable null:
Set CoClassVar1 = OBJ_Null
To force release of an object safely, assign OBJ_Null to an object variable. This causes the same sequence as
going out of scope and causes the referenced object to be freed if there are no other references to it in your
application (or from outside, in the case of COM server objects). See Reference Counting on page 498.

Checking for Null Objects


You can call SalObjIsNull to test an object to see if it is null:
If SalObjIsNull( functionalClassVar1 )
...
The code above is equivalent to:
If functionalClassVar1 = OBJ_Null
...

Reference Counting
SQLWindows manages object lifetimes through reference counts. When an object variable goes out of scope,
the runtime drops the reference count of the referenced object, and if the object is no longer referenced, it is
released.
Warning: You can create “islands” in memory where a set of objects that refer to each other are lost, with no
application object referring to any one of them, but each with a non-zero reference count. This storage is not
released because SQLWindows does not perform garbage collection.
If you want to force release of an object safely, assign OBJ_Null to an object variable. This causes the same
sequence as going out of scope and causes the referenced object to be freed if there are no other references
to it in your application (or from outside, in the case of COM server objects). See Setting CoClass Variables to
Null on page 498.

Setting Error Information


If an error occurs during the executtion of a COM interface function, you can call SalSetErrorInfo to set
standard error information:
bOK = SalSetErrorInfo( nCode, sDesc, sHelpfileName, nHelpContext )
SQLWindows takes the information you supply in this function, fills in a COM EXCEPINFO structure, and
passes a pointer to it to the client after the Invoke. An EXCEPINFO structure describes an exception that the
server raised.
SalSetErrorInfo does not halt processing. It should be the last statement that the COM interface function
executes.

Parameter Description

498
nCode A number identifying the error. This number should be less than -1000 and negative; if
this number is zero or positive, SQLWindows converts the value to E_FAIL, the generic
error code.
The actual error code returned from the Invoke call is DISP_E_EXCEPTION, meaning
that the server raised an exception.
sDesc A textual, human-readable description of the error intended for the end user.
sHelpfileName The fully qualified drive, path, and file name of a help file with more information about
the error.
nHelpContext The help context identifier of a topic in the help file. This field is ignored when
sHelpfileName is empty.

The COM EXCEPINFO structure has more than these four fields; SQLWindows fills in the remaining fields.

Interface Inheritance
Many widely available COM servers use interface inheritance. For example, the Microsoft XML parser,
MSXML, has a large number of interfaces that inherit from the IXMLDOMNode interface. To get the most
effective use out of COM servers like these, the SQLWindows ActiveX Explorer must create APL files with class
hierarchies that reflect the inheritance hierarchy of the server. In Team Developer 3.0, ActiveX Explorer was
enhanced to recognize and preserve interface inheritance in COM servers. For this reason, as well as others,
Gupta recommends that you regenerate any existing ActiveX APLs that were created prior to version 3.0.
You can create similar inheritance relationships in the COM servers that you write in SQLWindows. The COM
Class Wizard prompts you for an inherited interface name in the Derived From dropdown whenever you
define a new interface. You can also access the Derived From property from the Coding Asssitant, or from the
right-click context menu for interfaces in the outline.
With interface inheritance, you have access to any of the methods of any of the parent interfaces. As an
example, if you are working with an instance of the MSXML interface IXMLDOMElement, you can also call any
of the IXMLDOMNode methods from that instance because IXMLDOMELement inherits from IXMLDOMNode.

Interface Inheritance Use in Visual Basic


If you are using interface inheritance in a COM server that will be accessed by Visual Basic version 6 or Visual
Basic .NET, make sure that the VB applications use late binding when declaring objects from that COM server.
Otherwise VB will produce errors at runtime. Force late binding in VB by doing two things:
• Declare the variable that will contain an object from the COM server as type Object, not the specific type
from the server.
• Declare the variable first, as a new Object; then assign the COM server reference to it later in your code.

499
Dim objIslandSales as New Object Set objIslandSales = _
CreateObject("IslandSALESInfoSVR.ISOSalesServer")

Debugging COM Servers


With SQLWindows, you can debug a COM server, whether a DLL or an EXE, in the same way you debug
desktop applications. You select Debug, Go and then connect to the server with a client application.
Using the SQLWindows record/playback feature, you can also test a server by connecting to it with client
applications and recording server execution in a file. You then play back the execution of the server in the
SQLWindows debugging environment. This lets you learn about the flow of the server when it is running
under COM.
Note: The trace records only statement execution and can display neither application state nor object state.
To debug a COM server, follow these steps:
1. Open the server application.
2. Select Project > Build Settings.
Check Enable Playback and click OK.
If you enable playback mode, you can change Statement Cache Size in the Build Settings to control how
often SQLWindows writes statements to disk during recording. A low value could significantly affect
performance because of the disk access overhead. If the server exits unexpectedly, any statements in the
cache not yet written to disk will not appear in the playback. For this reason, use a low cache size (usually
1) if you need to record the final statement executed before an unexpected exit.
3. Select Debug > Go.
4. Connect to the server from a client application and test.
While you test, SQLWindows writes to a log file named with the root name of the application and a *.rec
extension.
5. When you exit debug mode, the Playback menu item is enabled on the Debug menu. Select it to play
back the application. You are prompted for the name of the *.rec file to open.
6. To start the playback, select Debug > Go.
During playback you can use animation, breakpoints, step over, step into, and the call stack window.
You cannot use the Variables, Expressions, or Messages windows in playback mode.
7. To rewind the playback to the beginning of execution, select Debug > Playback Rewind.
You can manually rename a *.rec file. This lets you store different versions of *.rec files.
Warning: Playback files are stamped with an identifying GUID so that they can be correlated with the
application file that generated the EXE or DLL. This GUID is regenerated each time you build the COM server,
even if the outline has not changed. For this reason, SQLWindows warns you when you open a playback file
from an earlier build. If the outline has not actually changed, you can ignore this warning. However, if the
outline has changed, you proceed at your own risk. Executing a playback file against an outline that does not
match can cause unexpected behavior, including crashing SQLWindows.
Warning: When running a server in debug mode, SQLWindows registers itself as the server instead of the
application. When you exit debug mode, SQLWindows re-registers the application as the server. If you exit the

500
application abnormally, SQLWindows cannot re-register the application and you must do so manually by
selecting Project > Register Server.

Type Information
SQLWindows automatically generates type information for COM servers. For both local servers and in-process
servers, SQLWindows embeds the type information in the *.EXE or *.DLL. As well, SQLWindows also
generates an external *.TLB file.
You specify the GUID of the type library in the Build Settings (see COM Server Tab and Thread dialog on page
83).

Registering Servers
Registering a COM server places information about the server in the system registry. Once the server has
been registered, applications and development environments can search the registry to determine the
servers that are installed.
When you build a server *.EXE, SQLWindows adds code internally that interprets standard command-line
registration flags:
• RegServer. The server does whatever COM registration is necessary and exits.
• UnRegServer. The server removes registry information and exits.
• Embedding. COM launches servers with this argument. If the server starts and this flag is not present, it
means that an end user has run the *.EXE as a standalone application. If the server is not intended to run
as a standalone application and this flag is not present, display an error dialog and then terminate the
*.EXE.
When you build a server *.DLL, SQLWindows makes it self-registering and implements COM registration entry
points (DllRegisterServer and DllUnregisterServer) that regsvr32.exe calls.

Registering and Unregistering during Development


The Project menu contains two commands for COM servers:
• Register Server
• Un-Register Server
You can use these menu items so that you do not have to open a DOS prompt during development.

Regenerating GUIDs
Select Project > Regenerate GUIDs to generate new GUID values for the COM server.

501
You want to regenerate GUIDs when:
• You are starting a new server, but are using existing code
• You have completed development and you want to assign a fresh set of GUIDs

Internal Implementation
SQLWindows’s automation incoming interfaces (methods) and outgoing interfaces (events) are dispatch
interfaces (dispinterfaces) and are implementations of IDispatch. These interfaces use standard automation
types (VT_*) for parameters and returns used with IDispatch::Invoke. SQLWindows automation servers do not
support dual interfaces.
The SQLWindows runtime environment implements a generic class factory for object instantiation.
CoCreateInstance looks for a class factory that knows how to take a progID/GUID, create an instance, and
return an IUnknown.
At runtime, events are implemented as COM connection points.
COM server collections are implemented with IEnumVARIANT.

Threading Support
SQLWindows’ COM servers (both DLLs and EXEs) can use one of two threading models:
• “None,” which is a single apartment with a single thread.
• STA (single-threaded apartment), which is multiple single-threaded apartments.

Introduction to Threads
A thread is a path of execution through a section of code in a program and is the smallest unit of execution
that Win32 schedules. Threads subdivide the tasks running within a program. A thread consists of a stack, the
state of the CPU registers, and an entry in the execution list of the system scheduler.
A program executes when the system scheduler gives one of its threads execution control. The scheduler
determines which threads should run and when they should run. On a single processor computer, the
scheduler can alternate execution among several threads, giving the appearance of concurrent execution. On
a multiprocessor computer, the scheduler can move individual threads to different processors to “balance”
the CPU load, executing the threads in parallel. If one thread must wait for an input/output operation to
complete, the system gives processor time to another thread.
502
The threads of a process share the virtual address space, global variables, and operating system resources of
the process. Each thread in a process operates independently. Threads execute individually and are unaware
of the other threads in a process.
Thread local storage (TLS) is a Win32 mechanism that allows multiple threads of a process to store data that is
unique for each thread. For example, a database server can create a new instance of the same thread each
time a user connects. Two instances of the same class created on different threads cannot access each other’s
data.
Writing code that can be safely used by multiple threads has become critical because thread overhead is
lower than process overhead. Also, threading has only relatively recently become available in Windows for
developers to take advantage of to build more efficient applications.

Apartment Model Threading


The term apartment describes a thread-related execution context. In the apartment model, objects have an
affinity for the thread on which they were created. Every call made to the object will execute in the same
thread in which the object was created. Objects in one apartment cannot directly refer to objects created on
another thread although they can be “marshalled” between threads. Objects in the same apartment share
thread global variables. In a single-threaded apartment, only one object can be executing at any given time.
SQLWindows serializes (queues) calls to other objects that share the apartment and only executes them when
no other call into that apartment is in progress.
An apartment can contain one or more objects. An object resides in exactly one apartment in its lifetime.

“None” or Main Single Threaded Apartment (STA)


In this model, the process is the apartment and there is only one main application thread. COM serializes
method calls until the thread finishes the method it is currently executing.

Process Legend
STA
Thread Apartment Object

Multiple STA
In this model, a process can have multiple apartments, each with its own thread.
Legend
Thread Apartment Object
STA STA
STA

SAL does not support marshalling between threads within an application. SQLWindows does not
support MTA (multi-threaded apartment).

COM Client and Server Apartments


COM supports threading in such a manner that neither the client nor the server needs to know what
threading model the other is using:

503
• The client application tells COM the model that it intends to follow for using threads.
• The object’s server tells COM the model that it intends to follow for using threads.
• When a client creates an object, COM compares the threading models that each party has said that it
uses. If the parties use the same model, then COM sets up a direct connection between the two. If they
use different models, then COM sets up marshalling between the two parties so that each sees only the
threading model that it has said it knows how to handle. The latter case has some performance costs but
allows parties following dissimilar threading models to work together.

Example: Multiple STA client/”none” server DLL


The diagram below shows a client process with two apartments accessing a server using the “None”
threading model. In this case, COM sets up marshalling code similar to that used for marshalling calls
between processes. If a multiple STA client connects to a single-threaded DLL server, COM instantiates the
object in a distinct apartment and returns a proxy to the client. COM marshalling synchronizes access from
different clients and serializes calls so that a call from one thread is never interrupted by a call from another
thread.

Multiple STA client application

STA 1 STA n

Proxy

(COM

“None” server DLL

COM-

created
thread

Legend
Thread Apartment
Object

Example: STA client/STA server DLL


The diagram below shows a client process with two apartments accessing a server using the multiple STA
model. When a multiple STA client connects to an STA DLL
COM server, COM instantiates the object directly in the apartment of the client that provides the most efficient
access.
Multiple STA client application

504
STA 1 STA n

Multiple STA DLL

Legend
Thread Apartment
Object

Using multiple STAs has these advantages:


• Multi-threaded clients are not blocked by serialization
• You can ensure that different objects run on different threads (thread affinity)
• Clients have direct references to objects in DLLs
• MTS is most efficient with the STA model

SQLWindows Support for Threads


SQLWindows supports threading in both DLL and EXE COM servers. CTD manages all threading issues
including thread creation (for *.EXE servers), synchronization, thread local storage, and deadlock.
For an EXE server, SQLWindows creates threads. For a DLL server, the client creates threads.

Build Settings
You control threading through the Build Settings where you can select the threading model (None or Single
Threaded Apartment). In the Build Settings, you can also associate a CoClasses to a specific thread (see COM
Server Tab and Thread Dialog on page 83).

Outlines, Apartments, and the Runtime Environment


All the apartments in an application or DLL share a single copy of the outline and the runtime environment.
Global variables and class variables are per-apartment.
Runtime state (interpreter state) is per-apartment.

Example: STA client–STA server DLL


The following diagram shows how SQLWindows manages the runtime environment of an multiple STA COM
*.DLL server. A single instance of the DLL runs with the client creating an apartment for each instance of the
CoClass. Each instance has its own thread-specific and apartment-specific data. The instances share the
runtime environment and the outline.

505
Client STA 1 Client STA n

CoClass CoClass
SAL COM

DLL server

Thread/ outline Thread/

specific Shared specific


data data
CTD

Example: STA SAL EXE COM server


The diagram below shows how SQLWindows manages the runtime environment of an STA COM *.EXE server.
Each time a client connects, the *.EXE creates an apartment for it. Each apartment has its own thread-specific
and apartment-specific data. The apartments share the runtime environment and the outline.

“None” client SAL COM EXE

STA n

STA client

STA 1
marshallin

Shared
COM

STA 2 outline

CTD

MTS (Microsoft Transaction Server) Support


You can write in-process servers that are managed by MTS. The SQLWindows runtime environment provides
support for MTS.

What is MTS?
MTS is a distributed runtime environment for COM objects that provides an infrastructure for running objects
across a network. MTS is a combined object request broker (ORB), resource manager, and transaction
monitor.
MTS provides automatic transaction management, database connection pooling, process isolation, automatic
thread-pooling, automatic object instance management, resource sharing, role-based security, transaction
monitoring within distributed applications, and more.

506
These services are necessary for scaling server-side components and supporting a substantial number of
concurrent client requests. MTS performs all of these services automatically, and without the need for
application developers to write special code. A developer can therefore develop server-side components that
behave as if only a single client is connected at a time.

MTS Architecture
MTS is a DLL surrogate process. DLL server components are loaded into the MTS surrogate (mtx.exe) process
along with the MTS Executive (mtxex.dll) as shown below.

mtx.exe

DLL

MTS object

DLL

MTS object
Proxy
DLL

MTS object

You can use SQLWindows to build an MTS object as a DLL. MTS creates proxies for the client.
To manage every single instance of a component installed under its control, MTS creates a sibling object
called a context object whose interface is exposed by IObjectContext. You use IObjectContext to commit or
abort a component’s transaction, to enable or disable transactions, and to check the security of a
component’s caller.
This context contains information about the object's execution environment, such as the identity of the
object's creator and, optionally, the transaction encompassing the work of the object.
IObjectContext Transaction ID
Object-Creator ID
IOrder

An MTS object and its associated context object have corresponding lifetimes. MTS creates the context before
it creates the MTS object. MTS destroys the context after it destroys the MTS object.
MTS coordinates the communication between components and databases over a set of pre-established
connections (connection pooling).
MTS clients use COM to create MTS components and MTS manages execution of the components. Clients can
receive MTS events and get complete/rollback status.
An activity is a collection of MTS objects that has a single distributed thread of logical execution. Each MTS
object belongs to a single activity.
COM+ (the combination of COM with a new version of MTS in Windows 2000) will support these features:
• Deferred activation, where MTS defers physically creating an object until the client actually calls one of its
methods.

507
• Early deactivation, where MTS deactivates an object (after a period of inactivity) even while the client still
holds a reference to the object. Later, when the client calls a method, MTS creates the object again.
Important: Microsoft refers to deferred activation and early activation collectively as just-in-time activation.

Issues in Writing MTS Components


The databases you use must support MTS to participate in transactions. Depending on the database, you may
have to take steps to enlist database connections with a transaction.
For an MTS component to be used by many clients concurrently, it must be scalable. To make an object
scalable, make it stateless. A stateless object does not hold any intermediate state while waiting for the next
call from a client. Each method call is independent and the object retains no memory of previous calls.
Stateless components cannot rely on events.
You should implement IObjectControl so that you can initialize and clean up state when MTS’ just-in-time
activation creates and destroys a component. Also, you can return TRUE in the CanBePooled method to take
advantage of object pooling in the future.
An MTS server looks like a standard COM object to the client. However, when you install the COM object in
MTS on the server, MTS makes itself the in-process server of the COM object in the registry. That way, when a
client wants to create an instance of the COM object, MTS will know it.

IObjectContext
The primary interface that MTS provides for components is the object context via IObjectContext. The object
context is implicit and only one is in scope at a time. SQLWindows exposes the IObjectContext through
SalMTS* functions.

Function Description
SalMTSSetComplete Indicates that the object has successfully completed its work for the transaction.
The object is deactivated upon return from the method that first entered the
context (stateless object).
SalMTSSetAbort Indicates that the object’s work can never be committed. The object is
deactivated upon return from the method that first entered the context
(stateless object).
SalMTSEnableCommit Indicates that the object’s work is not necessarily done, but that its
transactional updates can be committed in their current form (stateful object).
SalMTSDisableCommit Indicates that the object’s transactional updates cannot be committed in their
current form (stateful object).
SalMTSCreateInstance Creates a new component as part of the current transaction or in a new,
independent transaction.
SalMTSIsInTransaction Returns TRUE if the component is in a transaction; returns FALSE otherwise.
SalMTSIsSecurityEnabled Returns TRUE if declarative security is enabled for the component; returns
FALSE otherwise.
SalMTSIsCallerInRole Returns TRUE if the component’s caller is a member of the specified role. A role
is a symbolic name that defines a class of users for a set of components.
SalMTSGetObjectContext Gets the explicit object context (IUnknown).

508
IObjectControl
You implement the IObjectControl interface when you want to define context-specific initialization and
cleanup procedures for your COM objects and specify whether the objects can be recycled. Implementing the
IObjectControl interface is optional.
You can implement IObjectControl in two ways:
• Use the COM Class Wizard to automatically generate the class with empty methods to which you add
code.
• Hand code an Interface with this GUID: {51372aec-cae7-11cf-be81- 00aa00a2fa25}. You can give it any
name.
If you implement the IObjectControl interface in your component, the COM run-time environment
automatically calls the IObjectControl methods on your objects at the appropriate times. Only the COM run-
time environment can invoke the IObjectControl methods and they are not accessible to an object's clients or
to the object itself.
When an object supports the IObjectControl interface, COM calls its Activate method once for each time the
object is activated. The Activate method is called before any of the object's other methods are called. You can
use this method to perform any context-specific initialization an object may require.
COM calls the object's Deactivate method each time the object is deactivated. This can be the result of the
object returning from a method in which it calls SetComplete or SetAbort, or due to the root of the object's
transaction, causing the transaction to complete. You call the Deactivate method to clean up state that you
initialized in the Activate method.
By implementing the Activate and Deactivate methods, you can create stateless applications.
After calling the Deactivate method, the COM run-time environment calls the CanBePooled method to
determine whether the deactivated object is placed in an object pool for reuse or if the object is released in
the usual way.
Note: Although COM currently calls this method, it does not support object pooling. This forward-
compatibility encourages developers to use CanBePooled in their applications now in order to benefit
from a future release without having to modify their applications later.
Important: If you plan on taking advantage of object pooling when it is available, you must write stateless
code and not rely on volatile state because the same object may be used by a different client later.

Methods

Method Description
Activate Allows an object to perform context-specific initialization whenever it's activated. This
method is called by COM before any other methods are called on the object.
CanBePooled Allows an object to notify COM of whether it can be pooled for reuse. Return TRUE if
you want the object to be pooled for reuse or FALSE if not.
Deactivate Allows an object to perform whatever cleanup is necessary before it's recycled or
destroyed. This method is called by COM whenever an object is deactivated.

509
Shared Properties Classes
A shared property is a variable that is available to all objects in the same server process. The value of the
property can be any type that can be represented by a variant. The Shared Property Manager provides
synchronized access to application-defined, process-wide properties.

Class Description
ISharedPropertyGroupManager You access and create shared property groups through this class.
ISharedPropertyGroup Establishes a namespace for a set of shared properties.
ISharedProperty The property values

To generate the shared property classes, open “Shared Property Manager Type Library” in ActiveX Explorer
and generate the APL as you would for any ActiveX server. The class names have an “MTxSpm” prefix. You can
then use the APL as a reference for the functions, parameters, and returns.

Sample Applications
SQLWindows comes with a sample MTS client application and two MTS server applications. The diagram
below shows the multi-tiered architecture of these applications.
MTSOledbClient.exe MTSOledbServerClient.dll MTSOledbServer.dll

MTSOledbClient.exe creates an instance of MTSOledbServerClient.dll, which creates an instance of


MTSOledbServer.dll. The two DLLs are MTS servers.

Setting up the samples


To set up and run the samples, you must install SQLWindows on a computer running Windows NT 4.0 or
Windows 2000. For Windows NT 4.0, MTS must be installed (MTS comes the Windows NT Option Pack).
First, set up MTSOledbServer.dll:
1. Open MTSOledbServer.apt.
2. Select Project > Build.
3. Select Project > Register Server.
Next, set up MTSOledbServerClient.dll. If you haven’t used ActiveX Explorer, read Using ActiveX Explorer on
page 454.
4. Open MTSOledbServerClient.apt.
You get a message saying that SQLWindows cannot open “MTSOledbServer 1.0 Type Library.apl” because
the COM server does not has a type library APL yet.
5. Click OK.
6. Select Tools > ActiveX Explorer.
7. Select the type library MTSOledbServer 1.0 Type Library and click OK.
8. In the ClassView area of ActiveX Explorer, right-click and select Check All Shown, and then right-click
again and select Generate Full. SQLWindows creates an APL and includes it in the application. Close
ActiveX Explorer.
9. Select File > Save.

510
10. Select Project > Build.
11. Select Project > Register Server.
Finally, set up MTSOledbClient.exe:
12. Open MTSOledbClient.apt.
You get a message saying that SQLWindows cannot open “MTSOledbServerClient 1.0 Type Library.apl”
because the COM server does not has a type library APL yet.
13. Click OK.
14. Select Tools > ActiveX Explorer.
15. Select the type library MTSOledbServerClient 1.0 Type Library and click OK.
16. In the ClassView area of ActiveX Explorer, right-click and select Check All Shown, and then right-click
again and select Generate Full. SQLWindows creates an APL and includes it in the application. Close
ActiveX Explorer.
17. Select File > Save.
18. Select Project > Build.

Setting up MTS
You need to register the two server components with MTS.
Note: Each time you change an MTS-enabled COM server, delete the old MTS package and then reinstall the
revised COM server in a new MTS package.
For Windows NT 4.0, follow these steps:
1. Select Start > Programs > Windows NT 4.0 Option Pack > Microsoft Transaction Server > Transaction
Server Explorer.
2. Expand the Microsoft Transaction Server tree.
3. Expand the Computers tree and expand your computer’s tree.
4. Select Packages Installed, and right-click and select New > Package.
5. In the dialog, click Create an empty package, and then give the package a name. Click Next.
6. In the Set Package Identity dialog, select Interactive user - the current logged on user. Click Finish.
7. Expand the Packages Installed tree and expand the tree of the package you just created.
8. Select Components.

511
9. Right-click and select New > Component. In the dialog, click Import component(s) that are already
registered.

10. Select MTSOledbServer.CFuncionario and MTSOledbServerClient.CONegCFuncionario. Click Finish.


11. Expand the Components tree.
12. Right-click MTSOledbServer.CFuncionario and select Properties.
13. Click the Transaction tab and select Supports transactions. Click OK.

512
14. Right-click MTSOledbServerClient.CONegCFuncionario and select Properties.
15. Click the Transaction tab and select Requires a new transaction. Click OK.

To set up MTS on Windows 2000, follow these steps:


1. In the Start menu, select Settings > Control Panel > Administrative Tools > Component Services.
2. Expand the Component Services tree.
3. Expand the Computers tree and expand your computer’s tree.
4. Expand COM+ Applications.

513
5. Right-click COM+ Applications and select New > Application.
6. In the first wizard dialog click Next.
7. Click Create an empty application.
8. Enter the name of the application, select Server Application, and click Next.
9. Select Interactive User, click Next, and then click Finish.
10. Expand the tree of the newly created application.
11. Select Components.
12. Right-click and select New > Component.
13. Click Next.
14. Select Import component(s) that are already registered.

15. Select MTSOledbServer.CFuncionario and MTSOledbServerClient.CONegCFuncionario. Click Next and


then click Finish.
16. Expand the Components tree.

514
17. Right-click MTSOledbServer.CFuncionario and select Properties.
18. Click the Transactions tab and select Supported. Click OK.

19. Right-click MTSOledbServerClient.CONegCFuncionario and select Properties.


20. Click the Transactions tab and click Requires New. Click OK.

Logic flow of the applications


MTSOledbClient.exe creates an instance of MTSOledbServerClient_CONeg_Funcionario and then calls its
AddFunction function.

515
Local variables
MTSOledbServerClient_CONeg_Funcionario: oObject
Class:
Boolean: Retval
Actions
If oObject.Create()
Call oObject.AddFunction("Rock", "Star", "Sr", "Mynumber",
"Meet here", Retval)
In AddFunction, MTSOledbServerClient.dll calls SalMTSIsInTransaction and displays a dialog letting you know
whether it is in a transaction or not. Because you specified that MTSOledbServerClient.dll requires a new
transaction in MTS, it is always in a transaction.
Set bTransac = FALSE
Set bComplete = SalMTSIsInTransaction(bTransac)
If (bComplete AND bTransac)
Call SalMessageBox('in transaction -', 'MTSOledbServerClient', MB_Ok)
Else
Call SalMessageBox('out of transaction', 'MTSOledbServerClient', MB_Ok)
MTSOledbServerClient.dll then calls SalMTSCreateInstance to create an instance of
MTSOledbServer_cFuncionario and calls SalMTSEnableCommit to tell MTS that the object’s work is not
necessarily finished, but that its transaction updates are consistent and could be committed in their present
form. The object maintains its state across calls from the client until it calls SalMTSSetComplete,
SalMTSSetAbort, or the transaction ends.
MTSOledbServer_cFuncionario: oFunction
...
If SalMTSCreateInstance( oFunction )
Call SalMTSEnableCommit( )
Next, MTSOledbServerClient.dll calls the server’s Insert function. If the call succeeds,
MTSOledbServerClient.dll calls SalMTSSetComplete. Otherwise, it calls SalMTSSetAbort. Before and after
calling SalMTSSetComplete or SalMTSSetAbort, MTSOledbServerClient.dll displays dialogs so that you can
follow the progress.
Call oFunction.Insert(pFirstName, pLastName, pMiddleName, pTelephone,
pEMail, bReturn)
If bReturn
Call SalMessageBox( "SetComplete().", "COM Error", MB_Ok )
Set bComplete = SalMTSSetComplete( )
If bComplete
Call SalMessageBox("SetComplete().Passed", "COM Error", MB_Ok )
Else
Call SalMessageBox("SetComplete().Failed" "COM Error", MB_Ok )
Return 1
Else
Call SalMessageBox("SetAbort().", "COM Error", MB_Ok )
Call SalMTSSetAbort( )
Return 0
Else
Call SalMessageBox("SalMTSCreateInstance has failed.", "COM Error" , MB_Ok )
Return -1
Return -2
In its Insert function, MTSOledbServer.dll starts by calling SalMTSIsInTransaction and displaying a dialog
indicating whether it is in a transaction. Because you set up MTSOledbServer.dll to support transactions in
MTS, it runs in a transaction if its creator is running in one; otherwise it does not run in a transaction. In this
case, its creator (MTSOledbServerClient.dll) is running in a transaction, so MTSOledbServer.dll runs in that
transaction.

516
Set bTransac = FALSE
Set bTest = SalMTSIsInTransaction(bTransac)
If (bTransac AND bTest)
Call SalMessageBox('in transaction - in server comp', 'MTSOledbServer', MB_Ok)
Else
Call SalMessageBox('out of transaction', 'MTSOledbServer', MB_Ok)
MTSOledbServer.dll then sets up system variables for connecting to an OLE DB provider.
Important: This example is for connecting to Microsoft SQL Server. If you are running Microsoft SQL Server,
you must change the application to connect to a valid database and user account on your server. If you are
not running Microsoft SQL Server, then you must change the application to connect to a different MTS-
compliant database as well.
Set sSession = "Provider=sqloledb; OLE DB Services=2;"
Set SqlDatabase = "oraclent"
Set SqlUser = "qatest"
Set SqlPassword = "tester"
MTSOledbServer.dll creates an OLE DB session and statement and then calls SalMTSDisableCommit. By calling
SalMTSDisableCommit, MTSOledbServer.dll tells MTS that the object’s work is not finished, and that its
transaction updates are inconsistent and cannot be committed in their present form. the object maintains its
internal state across calls from the client until it calls SalMTSSetComplete, SalMTSSetAbort, or until the
transaction ends.
If SqlCreateSession( hSession , sSession )
Call SalMessageBox('created session - in server comp',
'MTSOledbServer', MB_Ok)
If SqlCreateStatement( hSession , hSQL )
Call SalMessageBox(' created stmt - in server comp',
'MTSOledbServer', MB_Ok)
Call SalMTSDisableCommit( )
Next, MTSOledbServer.dll prepares and executes a CREATE TABLE SQL statement.
Note: If you run this example more than once, the second and subsequent execution of this step can fail
because the table already exists.
If NOT SqlPrepareAndExecute ( hSQL, " CREATE table
myfunction ( first_name char (50) , last_name (50) ,
midlle_name char (50) , telephone char (50), e_mail char (50)" )
Return FALSE
MTSOledbServer.dll prepares and executes an INSERT statement that uses the function parameters passed to
it as values for the new row.
If NOT SqlPrepareAndExecute ( hSQL , " INSERT INTO
myfunction ( first_name , last_name , middle_name , telephone
, e_mail VALUES ( '" || Robert || "' , '" || John || "' , '" ||
Jr || "' , '" || Phone_number || "' , '" || EMAIL || "' ) "
)
Return FALSE

Finally, MTSOledbServer.dll calls SalMTSSetComplete:

517
Set bTest = SalMTSSetComplete()
If bTest
Call SalMessageBox('Set Complete passed', 'MTSOledbServer', MB_Ok)
Else
Call SalMessageBox('Set Complete failed', 'MTSOledbServer', MB_Ok)
Return TRUE
Else
Return FALSE
Else
Return FALSE

Testing the client application


Once you’ve set up the servers in MTS, you can test the client application. With MTSOledbClient.apt open,
select Project > Execute. Click the push button in the application. The applications display dialogs showing
you the progress as indicated in the code above.

518
Chapter 22 – Calling External Functions in
Dynamic Link Libraries
This chapter explains how to:
• Declare external functions in the outline.
• Choose external data types for function parameters and returns.
• Call external functions in a Dynamic Link Library (DLL) from a SQLWindows application.
• Write a DLL
• Use CDLLI*.DLL that comes with SQLWindows.
A DLL is a library file that contains external functions that SQLWindows applications and other DLLs can call to
perform tasks.
A DLL usually contains executable code for common functions. A DLL gives an application access to functions
that are not part of its executable code. Although a DLL contains executable code, you cannot run it as a
program. Instead, an application loads a DLL and executes the functions in the DLL by linking to it dynamically.
Some DLLs (such as USER32.DLL and GDI32.DLL) come with Microsoft Windows. You can also write your own
DLLs or buy them from third-party vendors.
The name of a DLL file does not have to have a *.DLL extension (such as USER32.DLL and GDI32.DLL).
From TD5.1 onward, strict type-checking is enforced while calling external functions. For example, to use
VisMenuInsertPicture on a popup menu created by calling the external function CreatePopupMenu, make
sure to declare the return type as DWORD for CreatePopupMenu. Declaring WORD will result in an error.

When to Use DLLs


Normally, you do not need to use DLLs for SQLWindows applications. However, DLLs are useful for:
• Calling functions in KNRL32.DLL, GDI32.DLL, USER32.DLL, and other Windows libraries
• Third-party libraries
• Special functions, such as custom screen controls (objects) or device drivers for special hardware
• Allowing multiple SQLWindows applications to share a common set of functions
• Passing data between applications
• Isolating function libraries so that you can change them without relinking the calling applications

Dynamic Linking
DLLs are similar to C libraries. The main difference is that DLLs are linked with the application at runtime,
not when you create the application:
• Linking a library with an application at runtime is called dynamic linking; the library is called a dynamic
library
519
• Linking a library with an application using a linker is called static linking; the library is called a static library
With static libraries, you combine the code for called functions with the application code when you create the
application, but with a DLL you do not combine the code.

Advantages of dynamic linking


You can change a DLL’s functions without changing the calling application.
A DLL saves memory when two or more applications that use a common set of functions are running at the
same time. Once a DLL is loaded, the system shares the
DLL with any other program that needs it. Only one copy of the library is loaded at a time.

Disadvantages of static linking


After you link a program to a static library, if you change a function in the static library, you must relink the
application.
Static libraries can be inefficient in a multitasking environment. If two applications are running at the same
time and they use the same static-library function, there are two copies of that function in the system.

Example Application and DLL


DEMODLLA.APP shows how a SQLWindows application uses a DLL.

The following are the files for DEMODLLA.APP. The examples in this chapter come from these files.

File Name Description


DEMODLLA.APP SQLWindows application that calls functions in DEMODLL.DLL
DEMODLL.C C source
DEMODLL.DEF Module definition file
DEMODLL.DLL Compiled and linked DLL; linked with CDLL.LIB (import library for CDLLI*.DLL)
DEMODLL.MAK Make file

Note: This chapter uses an asterisk (*) in the name of CDLLI*.DLL. The asterisk represents the first two digits
of the version of software you are using.

520
External Function Outline Sections
To declare a function in a DLL in a SQLWindows application, you need to know:
• The name of the function or its ordinal number
• The function's parameters and their data types
• The function's return data type
You declare external functions under Global Declarations:
Global Declarations
External Functions
...
Library name: DEMODLL.DLL
ThreadSafe: Yes
...
Function: ReturnLPFLOAT
Description:
Export Ordinal: 27
Returns
Boolean: BOOL
Parameters
Receive Number: LPFLOAT
Number: FLOAT
Number: FLOAT
For the Library Name, specify the name of the DLL.
Set ThreadSafe to Yes if the runtime environment can make calls to the DLL from multiple threads. Set
ThreadSafe to No if the runtime environment must pause until the current thread completes.
For each function in the DLL that the application calls, specify these items:
• The name of the function (see Identifying a Function on page 521).
• A description of what the function does (optional).
• The export ordinal that is a number that identifies a function (see Identifying a Function on page 521).
• The internal data type and the external data type of the return value. Sections further in this chapter
explain external data types. If the function does not return anything, you can leave this item blank.
• The SQLWindows internal data type and the external data type of each parameter that the SQLWindows
application passes to the function or that the function returns to the application. Sections further in this
chapter explain external data types.

Identifying a Function
You have a choice of how you identify the function in the DLL you want to call.
• By function name. You spell the function name in the outline exactly as it is declared in the DLL and you
specify 0 (the default value) for the export ordinal.
• By export ordinal. You specify the ordinal number for the function and give the function any name that
you want.
Export ordinals

521
Each function has an ordinal number declared in the library's *.DEF file. You can determine a function's
export ordinal by running a utility such as QuickView.

Parameter and Return Data Types


When you declare an external function in the outline, you specify a data type for the return value and
parameters. The data type for parameters and returns has two parts:
• An internal data type
• An external data type
The two parts are separated by a colon:
Number: LONG
The internal data type is a standard SQLWindows data type. Each internal data type corresponds to one or
more external data types. The external data type tells SQLWindows the format to use when passing data to
the external function and the format to expect when receiving data from the function.
The external data types are:
• Standard C and Windows scalar data types such as LONG, INT, DWORD, and HWND
• External SAL data types such as HSTRING and HARRAY
• Structures with one or more of the above data types such as NUMBER and DATETIME
The names of external data types are UPPERCASE.

Setting the External Data Type


When you declare an external function, you can choose the external data type in one of two ways after
moving the cursor to the external data type:
• Use the up and down arrow keys to cycle through the choices.
• Choose the external data type in Coding Assistant as follows:

522
Pass By Value and Pass By Reference
You can pass parameters by reference or by value. If the DLL changes the value of a parameter, specify the
Receive keyword for the internal data type so that SQLWindows passes the value by reference.
Chapter 7, SAL (SQLWindows Application Language), explains receive data types:
• Receive data types are passed to functions by reference (pass by reference), which means that the called
function has access to the original value; the called function can change the original value.
• Data types with names that do not start with “Receive” are passed to functions by value (pass by value),
which means that the called function only has access to a copy of the value; the called function can only
change the copy of the value. The names of the external data types for the Receive data types start with
“LP” which means “Long Pointer”.

External DLLs with HSTRINGs and UDVs


Programmers are able to create and manipulate entries in the internal string and class tables of Team
Developer using the C API. This ability comes with some cautions that need to be followed.
In Team Developer, entries in these tables are managed via reference counts; once the variable has been
passed back to Team Developer the interpreter takes over the reference count manipulation. This is done via
variable assignment in the Team Developer runtime, for example when a second variable is set equal to a first
the data is not copied they simply refer to the same entry in the table and the reference count is incremented
by one. When a variable is set to a new handle or that variable goes out of scope the reference count is
decremented. Finally when a reference count of an entry in one of these tables goes to zero the memory is
freed and the handle that referred to it is put back in a pool to be reused.

523
Programmer Cautions
The C programmer must be acutely aware of reference counts in Team Developer to properly use this
functionality. Team Developer is allowing access to the internals of its runtime at risk of causing memory leaks
or runtime errors, and even data corruption.
Memory leaks are caused by a reference count being incremented too many times (one is enough) or a
handle that is not assigned to a variable in Team Developer when returning from the C code. If you are
creating a handle to a string or a class, you must make sure its reference count is one and that it is assigned to
a Team Developer variable when returning from the call into the DLL. If that handle is a return value (as
opposed to a parameter), it cannot be ignored when the function is called in the Sal code. To assure that Sal
programmers do not circumvent your reference count logic, it is recommended that HSTRINGs and UDVs are
always parameters and not return values in your DLLs.
Runtime errors are caused when a Handle’s reference count is decremented to zero and an attempt is made
to use that handle. Because the data for that handle has been destroyed, runtime error occurs and aborts
execution.
Data corruption is caused by use of a stale handle, similar to the runtime error scenario. A handle will have
been decremented to zero so that the data is deleted, but that handle was reallocated somewhere else
before referencing. This can only happen if you cache handles in your C code, which is why you must avoid
doing so.

Using SAL External Data Types


SQLWindows uses the external data type to allocate bytes on the stack when an application calls the function
in the DLL. You must choose an external data type with the number of bytes that the function expects.
The external data types for Number and Date/Time are easier to understand because they are fixed-length.
The external data types for Strings are more complex because they are variable length.
To understand how to use external data types, you need to know some things about the formats that
SQLWindows uses for internal data types.
The next sections explain:
• The external data types you can use with each SQLWindows internal data type
• The relationship between the SQLWindows internal data types and the external data types

External Data Type Quick Reference


Internal Data Type Guidelines for choosing an external data type
Number Use an external data type that matches DLL’s scalar data type.
If you write the DLL, consider using NUMBER or LPNUMBER and calling CDLLI*.DLL
functions.
Date/Time Only use if you write the DLL and call CDLLI*.DLL functions.
String For null-terminated values, use LPSTR.
For binary values, use LPVOID.
If you write the DLL and need to change the buffer length in the DLL, use HSTRING or
LPHSTRING.

524
Internal Data Type Guidelines for choosing an external data type
Array Only use if you write the DLL and call CDLLI*.DLL functions.
For C structures, use structPointer

SAL Number Internal Data Type


Passing Numbers by value
Specify one of these external data types when you pass a Number by value:

External Data Type Corresponding C Scalar Data Type


BYTE unsigned char (WINDOWS.H typedef)
CHAR char
DOUBLE double
DWORD unsigned long (WINDOWS.H typedef)
FLOAT float
HARRAY None: Read HARRAY external data type on page 22-19
INT int
LONG signed long (WINDOWS.H typedef)
NUMBER None: Read NUMBER external data type on page 22-9
WORD unsigned short (WINDOWS.H typedef)

Warning: The WINDOWS.H typedefs shown in the table above are for the current version of Windows. The
actual underlying definition can be different depending on the version of Windows and the platform. Do not
write code that depends on the underlying definitions of these typedefs.

NUMBER external data type


The NUMBER data type is a C language struct that uses an internal SQLWindows format. This is the same
format that SQLBase uses for numbers.
Usually, you do not use the NUMBER (or LPNUMBER) data type (see Passing Numbers by reference on page
526) when calling an external function. However, you can use them in a DLL that you write and call
SalNumber* functions in CDLLI*.DLL (see Using CDLLI*.DLL on page 543). Also, you can these CDLLI*.DLL
functions in a DLL that you write to convert C data types to and from the SQLWindows NUMBER data type:

525
BOOL SWinCvtDoubleToNumber(double, LPNUMBER);
BOOL SWinCvtIntToNumber( INT, LPNUMBER )
BOOL SWinCvtLongToNumber( LONG, LPNUMBER )
BOOL SWinCvtULongToNumber( ULONG, LPNUMBER )
BOOL SWinCvtWordToNumber( WORD, LPNUMBER )
BOOL SWinCvtNumberToDouble(LPNUMBER, double FAR *);
BOOL SWinCvtNumberToInt( LPNUMBER, LPINT )
BOOL SWinCvtNumberToLong( LPNUMBER, LPLONG )
BOOL SWinCvtNumberToULong( LPNUMBER, LPULONG )
BOOL SWinCvtNumberToWord( LPNUMBER, LPWORD )

Passing Numbers by reference


Specify one of these external data types when you pass a Number by reference:

External Data Type Corresponding C Scalar Data Type


LPBYTE BYTE FAR* (WINDOWS.H typedef)
LPCHAR CHAR FAR * (CBTYPE.H typedef)
LPDOUBLE double FAR * (CBTYPE.H typedef)
LPDWORD DWORD FAR* (WINDOWS.H typedef)
LPFLOAT float FAR * (CBTYPE.H typedef)
LPINT int FAR* (WINDOWS.H typedef)
LPLONG long FAR* (WINDOWS.H typedef)
LPNUMBER None: long pointer to NUMBER struct
LPWORD WORD FAR* (WINDOWS.H typedef)

Warning: The WINDOWS.H and CBTYPE.H typedefs shown in the table above are for the current version of
Windows. The actual underlying definition can be different depending on the version of Windows and the
platform. Do not write code that depends on the underlying definitions of these typedefs.

Example
In the following example, the SQLWindows application declares an external function called ReturnDWORD
with a Number parameter that has a DWORD external data type. The external function returns the parameter
to the SQLWindows application as a DWORD. After calling the external function, the SQLWindows application
compares the returned value to the original value to find if it is the same.
External Functions
Library name: DEMODLL.DLL
Function: ReturnDWORD
...
Returns
Number: DWORD
Parameters
Number: DWORD
...
Set dfNum1 = 4123456789
Set dfNum3 = ReturnDWORD( dfNum1 )
If dfNum1 != dfNum3
Call SalMessageBox( 'dfNum1 != dfNum3', 'FAIL', MB_Ok )
Else
Set dfStr2 = 'test ReturnDWORD( ) - OK'
This is the C code for the external function:
526
#define EXPORTAPI _far _pascal _export _loadds
DWORD EXPORTAPI ReturnDWORD( DWORD varDWORD )
{
return varDWORD;
}

SAL Date/Time Internal Data Type


You can pass a Date/Time data type by value as a DATETIME or an HARRAY (a section later in this chapter
explains HARRAYs). Like the NUMBER data type, the DATETIME data type is a C language struct that uses an
internal SQLWindows format. You can pass a Date/Time data type by reference as an LPDATETIME (long
pointer to a DATETIME structure).
Usually, you do not use the DATETIME or LPDATETIME data type when calling an external function. However,
you can use them in a DLL that you write and call SalDate* functions in CDLLI*.DLL (see Using CDLLI*.DLL on
page 543).

SAL String Internal Data Type


Strings are buffers that can contain text or binary data. Text is null terminated. You can pass Strings as these
external data types:
• LPSTR (for null-terminated data)
• LPVOID (for binary data)
• HSTRING and LPHSTRING (when the DLL needs to set the length of the buffer)
• HARRAY (a section later in this chapter explains HARRAYs) LPSTR and LPVOID are WINDOWS.H typedefs:
typedef void FAR* LPVOID; typedef char FAR* LPSTR;
The most important thing about the String data type is that you must be aware of its length.

Memory management
Strings are fully dynamic and no memory management is required by a SQLWindows developer. Internally,
SQLWindows uses buffers in a proprietary format to store and manage String values. The details of these
buffers are not important to a SQLWindows developer, but you need to be aware of these things when you
call external functions that manipulate Strings:
• SQLWindows does not keep multiple copies of the same String value in memory. Instead, SQLWindows
stores one copy and keeps a reference count for the value (see Reference count example on page 528).
• SQLWindows creates a buffer for a String value the first time that you refer to it, not when the application
starts (see Common problem on page 529).
• SQLWindows frees the memory for a String buffer when its reference count drops to zero.
• The buffer for a String value always has a length, either zero or its length after its last assignment.
• The length of a buffer for a String value is determined by its most recent assignment. The length of a
buffer grows or shrinks as needed.
• Strings can be any length up to the actual memory available.
• Depending on the size of a String value's buffer, SQLWindows manages it in a heap through subsegment
allocation (see Subsegment allocation on page 528) or in the global heap.

527
Reference count example
In this example, you declare two String variables:
String: str1
String: str2
SQLWindows does not allocate memory for a String's value until you actually refer to it:
Set str1 = 'select * from' || strTable
After the statement above executes, the reference count for the String value
'select * from' || strTable
is one. If you then assign str1's value to another variable, SQLWindows increments the reference count for
the String value to two:
Set str2 = str1
If you then assign another value to str1:
Set str1 = 'select Name from' || strTable
SQLWindows decrements the reference count for the original String value (now only referred to by Str2) and
creates a new String value (referred to by str1) and sets its reference count to one.

Subsegment allocation
The current version of Windows has a system-wide limit of 8,192 selectors. Windows uses a selector to refer
indirectly to a memory segment. Each call to GlobalAlloc (a Microsoft Windows function that allocates
memory from the global heap) uses one selector, which makes GlobalAlloc inappropriate for allocating many
small blocks of memory. In fact, the number of available selectors is less than 8,192 because all Windows
applications and libraries share the same pool of selectors.
Instead of allocating a new segment with GlobalAlloc for each memory request, SQLWindows tries to satisfy
as many requests as possible using a single segment. SQLWindows tries to be more efficient than GlobalAlloc
by allocating memory in chunks, filling several memory requests using only one selector. SQLWindows
expands the segment as needed and returns pointers to areas of memory within the segment. This process of
managing memory within a segment is called subsegment allocation.

LPSTR
You use an LPSTR for a null-terminated string.

Passing LPSTRs by reference


An LPSTR points to a predefined fixed-length buffer. In this context, “buffer” means the actual memory that
holds the String's value. The external function cannot change the length of this buffer (even though the
external function can change the length of the value in the buffer). If the DLL needs to change the length of a
buffer, use the HSTRING data type.
If you pass an LPSTR by reference, SQLWindows resets the length of the buffer to the length of the actual
value when the function returns to the SQLWindows application. This optimization technique reclaims
memory when it is not actually being used.
Every time you call the external function, set the length of the buffer explicitly with SalStrSetBufferLength
first; for example, you can declare a parameter as:
Receive String: LPSTR
Follow these steps:
528
1. In the SQLWindows application, set the length of the string's buffer before calling the external function:
Call SalStrSetBufferLength( strExtFuncParam, 100 )
2. Call the external function in the DLL.
3. The external function writes a 5-byte value to the string.
4. When the function returns, SQLWindows looks for the null terminator to find the end of the value and
resets the length of the buffer to five bytes. Five bytes is the length of the buffer the next time you call
the external function, unless you explicitly reset the length with SalStrSetBufferLength or assign a new
value to the String.

Example
In the following example, the SQLWindows application declares an external function called ShowString with
a String parameter that has an LPSTR external data type. The external function displays the String in a
message box.
External Functions
Library name: DEMODLL.DLL
Function: ShowString
...
Parameters
String: LPSTR
...
Call ShowString( 'String in DEMODLLA.APP' )
This is the C code for the external function:
#define EXPORTAPI _far _pascal _export _loadds
void EXPORTAPI ShowString( LPSTR lpszString )
{
MessageBox( GetActiveWindow( ), lpszString,
"ShowString", MB_OK | MB_ICONASTERISK );
}

Common problem
SQLWindows creates a String the first time that you refer to it, not when the application starts. For example,
if a SQLWindows application contains the following code, the call to getname in the DLL causes a runtime
error because it writes to an invalid buffer (str1 has not been referenced):
External Functions
Library name: TEST.DLL
Function: getname
...
Parameters
Receive String: LPSTR
...
Internal Functions
Function: MyGetName
...
Local variables
String: str1
Actions
Call getname( str1 )
The solution is to first set str1 to a given length in the SQLWindows application, either by assigning it a value
or by calling SalStrSetBufferLength.

529
LPVOID
An LPVOID data type is like an LPSTR, but SQLWindows ignores null terminators in the value. You use
LPVOID for binary data with embedded nulls. For Receive Strings, SQLWindows does not reset the length
of an LPVOID when the function returns and does not reclaim unused space.

HSTRING and LPHSTRING


You use an HSTRING data type when:
• You write the DLL
• You need to set the length of the String buffer in the DLL
For example, if you are writing a DLL that needs to make the size of buffer larger than what the application
passes to it, you need to use an HSTRING.
The HSTRING and LPHSTRING data types are totally implemented in SQLWindows and do not rely on features
of Windows or C.
SQLWindows ignores null characters in HSTRINGs and LPHSTRINGs.
“HSTRING” means Handle to a String. A handle is a number that indirectly refers to a string. String handles are
like file handles or window handles. The actual value of the handle is not important to an application, but
SQLWindows knows how to use it to refer to the string.
HSTRINGs let you set the length of the buffer, but you must follow a specific protocol in the DLL to use them
because SQLWindows dynamically manages them for you. This is why you can only use HSTRING and
LPHSTRING with DLLs that you write. In the steps in the protocol, you must call these functions in CDLLI*.DLL:
LPSTR SWinHStringLock( HSTRING, LPLONG )
BOOL SWinInitLPHSTRINGParam( LPHSTRING, LONG )
VOID SWinHStringUnRef( HSTRING )
The next sections explain how you use these functions. Also see Using CDLLI*.DLL on page 543.

Finding the length of an HSTRING


Call SalStrGetBufferLength (in CDLLI*.DLL) to get the current length of the buffer for an HSTRING (including
the null byte):
lLength = SalStrGetBufferLength( hString )

Reading an HSTRING
A buffer that SQLWindows allocates for a String value does not stay fixed at a specific memory location. The
system can move it to make more contiguous memory available.
An HSTRING is a handle, not a pointer. The handle is an indirect reference to the String's buffer. To access an
HSTRING, you lock its handle. This temporarily fixes the buffer for the String's value and returns a pointer to it
(this is called dereferencing). While locked, the system cannot move the buffer. You unlock the memory
handle after you finish using the buffer.
In the DLL, declare a variable that holds the handle:
HSTRING hString;
Call SWinHStringLock to get a pointer to the HSTRING:

530
lpStr = SWinHStringLock( hString, &lLength )
SWinHStringLock also returns the length.
Read the HSTRING:
wsprintf( cBuff, "Testing ... %ld: %.50s\n\rContinue?", lCurrent, lpStrItem );
nRet = MessageBox( NULL, cBuff, "Show Value", MB_YESNO | MB_ICONQUESTION );
After you are through using the String, call SWinHStringUnlock:
SWinHStringUnlock( hString );

Writing an LPHSTRING
To change a String that a SQLWindows application passes to a function in a DLL, you must allocate a new
HSTRING.
In the SQLWindows application, you must declare the parameter as:
Receive String: LPHSTRING
In the DLL, declare a variable that holds the handle:
HSTRING hString;
Call SWinInitLPHSTRINGParam to associate the variable with an actual HSTRING value:
SWinInitLPHSTRINGParam( &hString, 128L );
After you create the HSTRING, lock it with SWinHStringLock:
lpStrItem = SWinHStringLock( hString, &lLength );
Once locked, you can write to it:
lstrcpy( lpStrItem, "This is a test" );
When you are through, unlock it with SWinHStringUnRef:
SWinHStringUnRef( hString );

Returning an HSTRING
In the SQLWindows application, you must declare the return as:
Returns
String: HSTRING
The steps you follow in the DLL are almost the same as for writing to a LPHSTRING, with one important
addition.
In the DLL, declare a variable that holds the handle:
HSTRING hString;
Important: Before calling SWinInitLPHSTRINGParam, you must set the HSTRING variable to zero:
hString = 0;
Call SWinInitLPHSTRINGParam to associate the variable with an actual HSTRING value:
SWinInitLPHSTRINGParam( &hString, 128L );
After you create the HSTRING, lock it with SWinHStringLock:
lpStrItem = SWinHStringLock( hString, &lLength );
Once locked, you can write to it:

531
lstrcpy( lpStrItem, "This is a test" );
When you are through, unlock it with SWinHStringUnRef:
SWinHStringUnRef( hString );
Return the HSTRING to the application:
return hString;

Example
In the following example, the SQLWindows application declares an external function called CombineStrings
with two String parameters that have HSTRING external data types and a Receive String parameter that has
an LPHSTRING external data type.
The external function concatenates the two Strings and returns the combined String.
External Functions
Library name: DEMODLL.DLL Function: CombineStrings
...
Returns Boolean: BOOL
Parameters String: HSTRING String: HSTRING
Receive String: LPHSTRING
...
Call CombineStrings( 'Hello, ', 'There!', dfStr1 )
This is the C code for the external function:
#define EXPORTAPI _far _pascal _export _loadds
BOOL EXPORTAPI CombineStrings( HSTRING hString1, HSTRING hString2,
LPHSTRING lphDestination )
{
LONG lLength;
char huge *lpString1;
char huge *lpString2;
char huge *lpDestination;
LONG lDummy;

/* Get length of both source strings (without zero delimiter) */


Q) lLength = SalStrGetBufferLength( hString1 ) - 1;
lLength += SalStrGetBufferLength( hString2 ) - 1;
C9 if ( !SWinInitLPHSTRINGParam( lphDestination, lLength + 1 ) )
return FALSE;
• lpDestination = SWinHStringLock( *lphDestination, &lDummy );
¢l: lpString1 = SWinHStringLock( hString1, &lDummy );
while( *lpDestination++ = *lpString1++ )
;
� SWinHStringUnRef( hString1 );
<: lpDestination--;
cP lpString2 = SWinHStringLock( hString2, &lDummy );
while( *lpDestination++ = *lpString2++ )
;
-\ SWinHStringUnRef( hString2 );
rl SWinHStringUnRef( *lphDestination ); return TRUE;
}
This is what the code does:
Q) Finds the length of the two HSTRINGs that the SQLWindows application passed by calling
SalStrGetBufferLength in CDLLI*.DLL. This is an example of calling a Sal* function in a DLL.
C9 Calls SWinInitLPHSTRINGParam to allocate a new HSTRING that is long enough to hold both of the

532
passed HSTRINGs.
• Locks the new HSTRING.
¢l: Locks the first HSTRING that the application passed and copies it to the new HSTRING.
� Unlocks the first HSTRING that the application passed.
<: Backs up the pointer to the new HSTRING so that the next byte is written at the position of null
terminator.
cP Locks the second HSTRING that the application passed and appends it to the new HSTRING.
-\ Unlocks the second HSTRING that the application passed.
rl Unlocks the new HSTRING.

HARRAY External Data Type


You use the HARRAY external data type to pass SQLWindows arrays to DLLs.
“HARRAY” means Handle to an Array. Like HSTRINGs, HARRAYs are totally implemented in SQLWindows and
do not rely on features of C or Windows.
SQLWindows always passes HARRAYs by reference, so you can always change the value of array elements in a
DLL.
Call these functions to process arrays in a DLL that you write:
BYTE SWinMDArrayDataType(HARRAY );
BOOL SWinMDArrayGetBoolean(HARRAY, LPBOOL,LONG, ... );
BOOL SWinMDArrayGetDateTime(HARRAY, LPDATETIME,LONG, ... );
BOOL SWinMDArrayGetHandle(HARRAY, LPHANDLE,LONG, ... );
BOOL SWinMDArrayGetHString(HARRAY, LPHSTRING,LONG, ... );
BOOL SWinMDArrayGetNumber(HARRAY, LPNUMBER,LONG, ... );
BOOL SWinMDArrayPutBoolean(HARRAY, BOOL,LONG, ... );
BOOL SWinMDArrayPutDateTime(HARRAY, LPDATETIME,LONG, ... );
BOOL SWinMDArrayPutHandle(HARRAY, HANDLE,LONG, ... );
BOOL SWinMDArrayPutHString(HARRAY, HSTRING,LONG, ... );
BOOL SWinMDArrayPutNumber(HARRAY, LPNUMBER,LONG, ... );
Call SWinMDArrayDataType to find the data type of the elements in an array. SWinMDArrayDataType returns
a pointer to one of these constants:
• DT_Boolean
• DT_DateTime
• DT_Number
• DT_String
• DT_LongString
From left to right, these are the arguments for the SWinMDArray* functions:
• The array handle
• The value to get or put
• An index into the array (repeated as many times as necessary for a multi-dimensional array)
To convert between standard C data types and SQLWindows Number data types in an array, call the SWinCvt*
functions in CDLLI*.DLL. For a list of the SWinCvt* functions, see NUMBER external data type on page 525.

533
You can also call SalArray* functions in CDLLI*.DLL (such as SalArrayGetLowerBound ) to manipulate HARRAYs
in a DLL that you write (see Using CDLLI*.DLL on page 543).
Because an HARRAY does not contain actual array values, you cannot use a debugger to examine the values.
In the DLL, you can write debugging code that calls SWinArrayGet* functions to retrieve the values.

Example
In the following example, the SQLWindows application declares an external function called ShowArray with
a String parameter that has an HARRAY external data type. The SQLWindows application fills an array with
values and then calls the ShowArray external function. After calling the external function, the application
displays the first element in the array.
External Functions
Library name: DEMODLL.DLL
Function: ShowArray
...
Parameters
String: HARRAY
...
Set strGlobalStrArray[0] = 'This is the first string'
Set strGlobalStrArray[1] = 'This is the second string'
Set strGlobalStrArray[2] = 'This is the third string'
Set strGlobalStrArray[3] = 'This is the fourth string'
Set strGlobalStrArray[4] = 'This is the fifth string'
Call ShowArray( strGlobalStrArray )
Call SalMessageBox( 'strGlobalStrArray[0]: ' || strGlobalStrArray[0],
'ShowArray', MB_Ok )
This is the C code for the external function:

534
#define EXPORTAPI _far _pascal _export _loadds
void EXPORTAPI ShowArray( HARRAY hArray )
{
LONG lLowerLimit;
LONG lUpperLimit;
LONG lCurrent;
LONG lLength;
LPSTR lpStrItem;
char cBuff[128];
BOOL bStopped;
HSTRING hString;
int nRet;

/* Get the current array bounds */

Q) SalQueryArrayBounds( hArray, &lLowerLimit, &lUpperLimit );

/* Display the array bounds */

wsprintf( cBuff, "This array boundaries are: %ld - %ld", lLowerLimit,


lUpperLimit );
C9 SalMessageBox( cBuff, "ShowArray", MB_Ok );

bStopped = FALSE;
lCurrent = lLowerLimit;

while ( !bStopped )
{

/*
Now loop through each of the elements, and display until the
user says stop or we are at the end of the array.
*/

if ( lCurrent > lUpperLimit )


break;

/* Retrieve the element of the array */

C) SWinArrayGetHString( hArray, lCurrent, &hString );// Note 3

/* Now that we have the hString, we need to get a pointer to it. */

¢l: lpStrItem = SWinHStringLock( hString, &lLength );// Note 4

/* Now display it. */

� wsprintf( cBuff, "String Array element %ld: %.50s\n\rContinue?",


lCurrent, lpStrItem );
nRet = MessageBox( NULL, cBuff, "ShowArray", MB_YESNO | MB_ICONQUESTION );

if ( nRet == IDNO )
bStopped = TRUE;

/* Now unlock the string pointer */

<: SWinHStringUnlock( hString );


hString = 0;
cP SWinInitLPHSTRINGParam( &hString, 128L );

535
/* Now hString contains a new string that I can write into. */

-\ lpStrItem = SWinHStringLock( hString, &lLength );


rl lstrcpy( lpStrItem, "String replaced in ShowArray" );
� SWinHStringUnlock( hString );

/* Now we need to put this hString into the array. */

SWinArrayPutHString( hArray, lCurrent, hString );

/* Look at the next element */

lCurrent++;
}
}
This is what the code does:
Q) Finds the starting bound and ending bound of the array by calling SalQueryArrayBounds in
CDLLI*.DLL. This is an example of calling a Sal* function in a DLL.
C9 Displays the bounds of the array by calling SalMessageBox. This is another example of calling a
Sal* function in a DLL.
C) Gets an array element into an HSTRING.
¢l: Locks the HSTRING.
� Displays the current value of the array element.
<: Unlocks the HSTRING.
cP Allocates a new HSTRING.
-\ Locks the new HSTRING.
rl Copies a value to the new HSTRING.
� Unlocks the new HSTRING with SWinHStringUnlock and copies it into an array element with
SWinArrayPutHString.

Other External Data Types


The table below lists the external data types you can use with the other internal data types:

Internal Data Type External Data Type


Boolean BOOL
Receive Boolean LPBOOL
File Handle HFILE
Receive File Handle LPHFILE
Sql Handle HSQLHANDLE HARRAY
Receive Sql Handle LPHSQLHANDLE
Window Handle HWND HARRAY
Receive Window Handle LPHWND

536
Using C Structures (structPointer External Data Type)
You use the structPointer external data type to identify the elements in a C struct when you call external
functions.
Note: You can use the structPointer data type for most C structure operations. However, if you find that you
cannot perform something any other way, you can call functions in strci*.dll to manipulate structures
(see Using strci*.dll on page 547).
When you declare an external function parameter with the structPointer data type, SQLWindows bundles the
items under it in a C struct and passes a pointer to it to the external function.
For example, the Windows function GetClientRect takes two parameters:
• HWND – Window handle
• LPRECT – Pointer to a structure that contains four integers
The structure above is defined in C as:
typedef struct tagRECT {
int left;
int top;
int right;
int bottom;
} RECT;
This is how you declare the external function in a SQLWindows application:
External Functions
Library name: USER32.DLL
Function: GetClientRect
Description: This function returns the width and height of a window.
Export Ordinal: 33
Returns
Parameters
Window Handle: HWND
structPointer
Receive Number: INT
Receive Number: INT
Receive Number: INT
Receive Number: INT
The four Receive Number data types under structPointer correspond to the four elements of the RECT
structure.
You can declare the items under a structPointer as receive or non-receive. The code below calls
GetClientRect:

537
Form Window: frmMain
!
! The 4 data fields are defined as Number data types.
!
Data Field: dfTop
...
Data Field: dfLeft
...
Data Field: dfRight
...
Data Field: dfBottom
...
Pushbutton: pb1
Message Actions
On SAM_Click
!
! GetClientRect returns zero in the left and top parameters
! and the width and height of the window in the right and
! bottom parameters.
!
Call GetClientRect(frmMain, dfLeft, dfTop, dfRight, dfBottom )

Fixed-length Strings and pointers to Strings


Often, C structs have embedded fixed-length strings. The following example defines a structure with two
fixed-length strings:
structPointer
Number: INT
Receive String: char[10]
Number: LONG
String: char[20]
Note: If you use Coding Assistant to create a fixed-length string, you must explicitly specify the length.
The following example defines a structure with pointers to strings:
structPointer
Number: INT
Receive String: LPSTR
Number: LONG
String: LPSTR

Using byte and char external data types


Use the byte external data type to pass a fixed-length byte array in a structure to an external function. This
example passes two 4-byte arrays in a structure to an external function:
External Functions
Library Name: x.dll
Function: test
...
Parameters
structPointer
String: byte[4]
Receive String: byte[4]
When you use byte, SQLWindows does not null-terminate the value passed to the external function. For
example, this code passes "1234ABCD" to the external function:

538
Set s1 = "ABCD"
Call test( "1234", s1 )
SQLWindows truncates a value if it is longer than the length you declare for the structPointer element in the
SQLWindows application. This code also passes “1234ABCD”:
Set s1 = "ABCDxxxxx"
Call test( "1234xxxxx", s1 )
When you use byte, SQLWindows does not add a null terminator to the byte array. For example, if the
external function changes “ABCD” to “WXYZ”, s1 contains “WXYZ”. Internally, the null terminator follows the
“Z”, but the SQLWindows application does not see it.
The byte external data type is like the char external data type, but it handles null terminators differently. Use
char to pass a fixed-length string in a structure to an external function. This example passes two 4-byte strings
in a structure to an external function:
External Functions
Library Name: x.dll
Function: test
...
Parameters
structPointer
String: char[4]
Receive String: char[4]
When you use char, SQLWindows null terminates the value passed to the external function. For example, this
code passes “123-ABC-” to the external function (- represents a null terminator):
Set s1 = "ABCD"
Call test( "1234", s1 )
SQLWindows truncates a value if it is longer than the length you declare for the structPointer element in the
SQLWindows application. This code also passes “123- ABC-”:
Set s1 = "ABCDxxxxx"
Call test( "1234xxxxx", s1 )
When you use char, SQLWindows null terminates the string. For example, if the external function changes
“ABCD” to “WXYZ”, s1 contains “WXY-”.

Nested structs
You can nest structs. The following example contains two rectangles:

539
structPointer
struct
Number: INT
Number: INT
Number: INT
Number: INT
struct
Number: INT
Number: INT
Number: INT
Number: INT

Calling External Functions


You call an external function the same way as a system function or internal function: by executing a Set or Call
statement or by embedding it in an expression. The following example calls ReturnLPFLOAT in an expression:
Set dfNum1 = 123.4
Set dfNum2 = 3456.6999512
Set dfNum3 = 123.4
If NOT ReturnLPFLOAT( dfNum1, dfNum2, dfNum3 )
Call SalMessageBox( 'ReturnLPFLOAT', 'FALSE', MB_Ok )
If dfNum1 != dfNum2
Call SalMessageBox( 'dfNum1 != dfNum2', 'FAIL', MB_Ok )
Else
Set dfStr2 = 'test ReturnLPFLOAT() - OK'

Writing a DLL
This section uses DEMODLL.DLL to show the basics of writing a DLL. You can use the files for DEMODLL.DLL as
templates for DLLs that you write.

Requirements for writing a DLL


To write a DLL, you must:
• Be competent in writing C or assembler programs.
• Know how to program with Windows.
• Understand memory management, code segments, data segments, and stacks.
This section discusses these topics and shows examples, but does not try to teach you how to write a DLL.
Use the documentation that comes with your development software or third-party books.
To write a DLL, you need the following or its equivalent: Microsoft Visual C++.
To create a DLL with functions that you can call from a SQLWindows application, you need these files:
• A C source file (DEMODLL.C)
• A module definition file (DEMODLL.DEF)
• A make file (DEMODLL.MAK) You can also use include (*.H) files.

540
C source file (*.C)
The code fragments below show part of DEMODLL.C:
#include "cbtype.h"
#include "centura.h"
/* Other includes ... */
Q)#define EXPORTAPI _far _pascal _export _loadds
/* Function Prototypes */
...
BOOL EXPORTAPI ReturnLPFLOAT( LPFLOAT, float, float );
...
C9int EXPORTAPI LibMain( HANDLE hModule, WORD wDataSeg,
WORD cbHeapSize,
LPSTR lpszCmdLine )
{
hModule;
wDataSeg;
cbHeapSize;
lpszCmdLine;
return 1;
}
...
BOOL EXPORTAPI ReturnLPFLOAT( LPFLOAT varLPFLOAT,
float varFLOAT,
float varFLOATTEST)
{
BOOL bResult;
bResult = *varLPFLOAT == varFLOATTEST;
*varLPFLOAT = varFLOAT;
return bResult;
}
/* Other function definitions ... */
This is what the code does:
Q) The EXPORTAPI macro says to define the function as FAR PASCAL, to export the function so that
other applications can call it, and to load the data segment when the function is called.
Functions in a DLL that other applications call must use the FAR PASCAL calling convention:
– Use FAR because the functions are called from a different code segment.
– PASCAL creates slightly smaller and faster code.
C9 The system calls LIBENTRY at startup to initialize the DLL. In turn, LIBENTRY calls the C function
LibMain in your DLL when the DLL is loaded.
The LibMain function can perform additional initialization for the DLL. LibMain returns 1 if the
initialization is successful.

Module Definition File (*.DEF)


The *.DEF (module definition) file tells the linker about attributes of the DLL:

541
LIBRARY DEMODLL
EXETYPE WINDOWS
DESCRIPTION 'Test DLL library'
STUB 'WINSTUB.EXE'
CODE MOVEABLE DISCARDABLE
DATA SINGLE MOVEABLE PRELOAD
HEAPSIZE 1024
EXPORTS
...
ReturnLPFLOAT @27
...
Here is what the statements do:
• The LIBRARY keyword says that this is a DLL.
• The EXPORTS keyword defines the functions called by applications or other DLLs. Give each function in
the DLL a unique ordinal entry value (the number after the “@” symbol).

Make File (*.MAK)


This is the make file for the example DLL:
all: demodll.dll
FLAGS= -c -Asnw -Gy2csD -Ox -Zlpe -W3
demodll.obj: demodll.c cbtype.h centura.h
cl $(FLAGS) $*.c
demodll.dll: demodll.obj demodll.def
link /NOE demodll,demodll.dll/align:16,demodll/m/nod,swin+sdllcew+libw,
demodll.def
rc demodll.dll
In the CL command:
• The “c” in -Gy2csD tells the compiler to use the PASCAL calling sequence for functions.
• The “w” in -Asnw tells the compiler that the stack is not part of the DLL’s data segment (SS != DS). The
compiler produces an error message when it detects the DLL is trying to pass a stack variable to a
function that expects a near pointer. In other words, the “w” causes a warning message when the DLL
tries to create a near pointer to an automatic variable (an automatic variable is one allocated in the stack
when the function is called).
The LINK command has five arguments that are separated by commas:
• The names of the object file to link: DEMODLL.OBJ
• The name of the final DLL: DEMODLL.DLL
• The name of the MAP file: DEMODLL.MAP
• The names of the import libraries and static libraries that, for this example, are:
CBDLL.LIB. Import library for CDLLI*.DLL (this is an example of how you link a DLL to CDLLI*.DLL)
SDLLCEW.LIB. C runtime static library for Windows DLLs
LIBW.LIB. Import library for Windows functions in KNRL32.DLL, USER32.DLL, GDI32.DLL, and other
Windows libraries
• The name of the module definition file

542
Using CDLLI*.DLL
CDLLI*.DLL comes with SQLWindows and has two types of functions:
• DLL helper functions
• Sal* functions
These DLL helper functions are explained in other places in this chapter:
• SWinCvt* functions for NUMBER data types
• SWinHStringLock, SWinHStringUnlock, and SWinInitLPHSTRINGParam for HSTRINGs and LPHSTRINGs
• SWinArray* functions for HARRAY data types
You can call any Sal* function that you can call in a SQLWindows application, such as:
• SalNumber* functions for NUMBER data types
• SalDate* functions for DATETIME data types
• Sal* array functions for HARRAY data types
• Other Sal* functions as appropriate
These files are for CDLLI*.DLL:

File Name Description


CBTYPE.H Typedefs for SQLWindows data types
CENTURA.H Prototypes for SQLWindows functions and SQLWindows constants
CDLLI*.DLL Compiled and linked DLL
CBDLL.LIB Import library that you link with your DLL

To call functions in CDLLI*.DLL:


• Include CENTURA.H and CBTYPE.H
• Link CBDLL.LIB (import library for CDLLI*.DLL) with your DLL (see Creating an Import Library on page 543)

Creating an Import Library


One DLL can call functions in another DLL. To do this, you create an import library for the called DLL and then
link the calling DLL to the import library. An import library contains information that helps the system find
code in a DLL. An import library does not contain code. Instead, it contains information necessary to set up
relocation tables.
If you write a DLL that calls function in another DLL, you need to create an import library for the called DLL.
You then link your DLL with the import library of the called DLL.
At runtime, the system uses the information in an import library to resolve references to external functions.
The Microsoft C command IMPLIB creates an import library. For example, the command below creates an
import library called IMPORT.LIB for IMPORT.DLL:
IMPLIB IMPORT.DLL
You then link IMPORT.LIB to other *.OBJ files, C libraries, and Windows libraries:

543
LINK TEST.OBJ + <other *.OBJs and *.LIBs>, TEST.EXE,, IMPORT.LIB, DYNAMIC.DEF
The command above creates a file named TEST.EXE.

DLLs and the Stack Segment


A DLL does not have its own stack. Instead, it shares the stack of the application that called the DLL. This can
create problems if the calling application assumes the DS register and the SS register hold the same address.

Data segment of
calling application Data segment of DLL

Local heap Local heap

Stack

Uninitialized static data Uninitialized static data

Initialized static data


Initialized static data

DS and SS are names of registers:


• The DS (Data Segment) register points to a segment that contains static data.
• The SS (Stack Segment) register points to the stack. A stack is an area of memory reserved for storing
temporary data.
When you use a near pointer in a C program, the pointer can refer to a variable either in static memory or on
the stack. The compiler has no way to know whether the near pointer is an offset to DS or SS. This is why C
programs normally use the same segment for data and the stack. In other words, DS == SS.
However, in a DLL the data segment is the library's own, but the stack segment is the stack of the caller. That
is, DS != SS.

Using Visual Studio with DLLs


To write a DLL and use Visual Studio to diagnose problems at design time, follow these steps:
1. Load the symbols for the DLL.
2. Set a breakpoint on a function in the DLL.
3. Load the SQLWindows application. You get a message saying that SQLWindows does not have code
symbols.
4. Test the SQLWindows application.
5. Load the DLL source files.
6. Check the Visual Studio locals window.
Neither SQLWindows nor a SQLWindows application have code symbols.

544
Passing UDVs to External Functions
You can pass UDVs (which are instances of functional classes) to external functions. In SQLWindows, declare
the function parameter with an internal data type of Functional Class Object and an external data type of
HUDV (UDV handle).The instance variables in UDVs are accessed indirectly through handles.
The include file centura.h declares three functions for UDVs: SalUdvGetCurrentHandle, SWinUdvLock, and
SalGetUDVData. In all cases you must call SalUdvGetCurrentHandle and SWinUdvLock. If you use nested
UDVs, you also must call SalGetUDVData (see Nested UDVs on page 547).
First, you must call SalUdvGetCurrentHandle:
HUDV SalUdvGetCurrentHandle( void );
This function gets the handle of the currently executing object that called the external function in the DLL. If
the currently executing object is not a UDV, this function causes a runtime abort.
You then pass the handle returned by SalUdvGetCurrentHandle to SWinUdvLock:
LPSTR SWinUdvLock( HUDV );
SWinUdvLock returns the address of the first instance variable defined or inherited by the UDV class. Define a
C struct whose first element is a HANDLE and the remainder of which corresponds to the instance variable
mapping in the UDV.
The pointer returned by SwinUdvLock refers the original SQLWindows data, not to a copy. Changing the data
through this pointer changes the data as seen by the SQLWindows application; for example:
typedef struct
{
HANDLE foohandle;
HSTRING strFoo;
NUMBER numFoo;
} UDVFOO,
FAR * LPUDVFOO;
Cast the LPSTR returned by SWinUdvLock to this struct pointer.
Note: For a UDV whose class is derived from another class, the instance variables inherited by the UDV's
class appear in the C struct before those defined by the class.
Here is an example from demodll.c:

545
typedef struct
{
HANDLE derivehandle;
HSTRING strBase;
NUMBER numBase;
HANDLE MyFoo;
HARRAY haFoo;
NUMBER numProduct;
} UDVDERIVED,
FAR * LPUDVDERIVED;

HUDV hUdv;

hUdv = SalUdvGetCurrentHandle();
return UdvCalculate(hUdv);

BOOL EXPORTAPI UdvCalculate(HUDV hUdvDerived)


{
LPUDVDERIVED lpUdvDerived;

double dSum
...
lpUdvDerived = (LPUDVDERIVED) SWinUdvLock(hUdvDerived);
...
SWinCvtDoubleToNumber(dSum, &lpUdvDerived->numProduct);
...
}

Data types
Use the following data types for instance variables of a UDV:

SQLWindows Data Type C Data Type


Boolean NUMBER
Date/Time DATETIME
File Handle HFILE or HANDLE
Long String HSTRING
Number NUMBER
String STRING
Sql Handle SQLHANDLE or HANDLE
Window Handle HWND or HANDLE
Arrays HARRAY
Examples:
Number: numArray[10]
Employee: staff[*]
UDVs C struct
Example:
Employee: Manager

Use the HANDLE data type for arrays of file handles, Sql Handles, or window handles. Access elements of an
array of handles with the following functions:

546
BOOL SwinArrayGetHandle( HARRAY, LONG, LPHANDLE );
BOOL SwinArrayPutHandle( HARRAY, LONG, HANDLE );

Nested UDVs
When you have a UDV that contains another UDV as a member, the pointer returned by SWinUdvLock can
only point to the nested UDV’s handle, and not to its instance variables. In this case, you must dereference
the handle by calling SalGetUDVData.
For example, assume you have a UDV that corresponds to this struct:
typedef struct
{
HANDLE derivehandle;
HSTRING strBase;
NUMBER numBase;
HANDLE MyFoo;
HARRAY haFoo;
NUMBER numProduct;
} UDVDERIVED,
FAR * LPUDVDERIVED;
In the example above (from demodll.c), MyFoo is a nested UDV. To deference MyFoo, define a struct that
corresponds to its instance variables:
typedef struct
{
HANDLE foohandle;
HSTRING strFoo;
NUMBER numFoo;
} UDVFOO,
FAR * LPUDVFOO;
Create the new struct and then fill it by calling SalGetUDVData. You can then refer to instance variables in
the UDV:
UDVFOO *newudvfoo;
newudvfoo = (UDVFOO*)SalGetUDVData((HANDLE)(lpUdvDerived->MyFoo));
SWinCvtNumberToDouble(&newudvfoo->numFoo,&dCurValue);

UDV Arrays
For an array of UDVs, this function returns a reference to a UDV handle:
BOOL FAR CDECL SWinMDArrayGetUdv( HARRAY, LPHUDV, LONG, ... );
The first argument is a handle to the array, the second is the returned reference to the UDV handle, and the
third and subsequent parameters are index values for each dimension of the array.
After calling this function, pass the handle to SwinUdvLock to get the address of the UDV's instance
variables and then directly access them in the DLL.

Using strci*.dll
SQLWindows applications can pass data to and receive data from DLL functions that use C structures by
calling functions in strci*.dll. You use strci*.dll when you need more flexibility to manipulate structures than
the structPointer external data type provides (see Using C Structures (structPointer External Data Type) on
page 537).

547
The functions that use C structures are grouped into the following categories:
• Get functions that extract elements from a SQLWindows string buffer
• Put functions that insert elements into a SQLWindows string buffer
• Memory functions that allocate, free, and access global memory
These functions use a string buffer to provide access to C structures. The string buffer is accessed directly by
these functions and cannot be used as a normal string within SQLWindows.
Warning: To ensure that the SQLWindows string is large enough to hold the entire structure, call
SalStrSetBufferLength to initialize the length of the string. The CStructPut* functions do not detect attempts to
write beyond the length of the destination string. Writing beyond the length of the string can cause
unpredictable results.

Example Files
The following are the example files for strci*.dll:

Name Description
cstructl.apl Include library that declares external functions in strci*.dll.
cstruct.app Sample application that uses strci*.dll.

Extracting Elements from a C Structure


The tables below show the functions that extract C structure elements from a string. Except for
CStructGetString, all functions have these parameters:
String: LPVOID
Number: LONG
The first parameter is the SQLWindows buffer for a C structure. The second parameter is the offset, in bytes,
of the value to extract. The extracted value is returned.
The following example gets a WORD that begins at the eighth byte:
nResult = CStructGetWord( strBuffer, 7 )
CStructGetString has these parameters:
String: LPVOID
Number: LONG
Number: LONG
Receive String: LPSTR
The first and second parameters are as described above. The third and fourth parameters contain the number
of bytes to extract and the string where the value is stored. The length of the string that has been extracted is
returned, including the null terminator.
The following example extracts a string that begins at the eighth byte into a string that can hold up to 20
bytes:
nLength = CStructGetString( strBuffer, 7, 20, strExtract )
Important: To extract int data types, call CStructGetWord.

548
Get Functions
Syntax nResult = CStructGetByte( strBuffer, nOffset )
Description Extracts a byte from a buffer
Parameters String: LPVOID C structure buffer
Number: LONG offset in bytes to extract
Returns Number: BYTE extracted value

Syntax nResult = CStructGetWord( strBuffer, nOffset )


Description Extracts an unsigned integer from a buffer
Parameters String: LPVOID C structure buffer
Number: LONG offset in bytes to extract

Returns Number: WORD extracted value

Syntax nResult = CStructGetLong( strBuffer, nOffset )


Description Extracts a long from a buffer
Parameters String: LPVOID C structure buffer
Number: LONG offset in bytes to extract
Returns Number: LONG extracted value

Syntax nResult = CStructGetFloat( strBuffer, nOffset )


Description Extracts a float from a buffer
Parameters String: LPVOID C structure buffer
Number: LONG offset in bytes to extract
Returns Number: FLOAT extracted value

Syntax nResult = CStructGetDouble( strBuffer, nOffset


Description Extracts a double from a buffer
Parameters String: LPVOID C structure buffer
Number: LONG offset in bytes to extract
Returns Number: DOUBLE extracted value

Syntax nLength = CStructGetString( strBuffer, nOffset, nMaxWidth, strExtract )


Description Extracts a string from a buffer

549
Parameters String: LPVOID C structure buffer
Number: LONG offset in bytes to extract
Number: LONG number of bytes to extract
Receive String: LPSTR where to put extracted string

Returns Number: LONG length extracted (including null)

Syntax nFarPointer = CStructGetFarPointer( strBuffer, nOffset )


Description Extracts a far pointer from a buffer
Parameters String: LPVOID C structure buffer
Number: LONG offset in bytes to extract
Returns Number: LONG extracted value

Inserting Elements into a C Structure


The tables below show the functions that insert C structure elements into a string. Except for
CStructPutString, all functions have these parameters:
Receive String: LPVOID
Number: LONG
Number: BYTE, INT, WORD, LONG, FLOAT, or DOUBLE
The first parameter is a buffer for a C structure. The second parameter is the offset in bytes that indicates
where to insert the value. The third parameter is the value to insert. This external data type depends on the
function.
The following example inserts a WORD beginning at the eighth byte:
CStructPutWord( strBuffer, 7, nValue )
CStructPutString has these parameters:
Receive String: LPVOID
Number: LONG
Number: LONG
String: LPSTR
The first and second parameters are as described above. The third parameter is the maximum number of
bytes to insert. The fourth parameter is the null-terminated string to insert. If the maximum number of bytes
is less than the length of the string to insert, then the inserted string does not include a null terminator.
The following example inserts a string starting at the eighth byte, where up to 20 bytes are allowed:
CStructPutString( strBuffer, 7, 20, strInsert )
Important: To insert int data types, call CStructPutWord.

Put Functions
Syntax bOk = CStructPutByte( strBuffer, nOffset, nInsert )
Description Inserts a byte into a buffer

550
Parameters Receive String: LPVOID C structure buffer
Number: LONG where to insert (offset in bytes)
Number: BYTE value to insert
Returns Boolean: BOOL

Syntax bOk = CStructPutWord( strBuffer, nOffset, nInsert )


Description Inserts a word into a buffer
Parameters Receive String: LPVOID C structure buffer
Number: LONG where to insert (offset in bytes)
Number: WORD value to insert
Returns Boolean: BOOL

Syntax bOk = CStructPutLong( strBuffer, nOffset, nInsert )


Description Inserts a long into a buffer
Parameters Receive String: LPVOID C structure buffer
Number: LONG where to insert (offset in bytes)
Number: LONG value to insert
Returns Boolean: BOOL

Syntax bOk = CStructPutFloat( strBuffer, nOffset, nInsert )


Description Inserts a float into a buffer
Parameters Receive String: LPVOID C structure buffer
Number: LONG where to insert (offset in bytes)
Number: FLOAT value to insert
Returns Boolean: BOOL

Syntax bOk = CStructPutDouble( strBuffer, nOffset, nInsert )


Description Inserts a double into a buffer
Parameters Receive String: LPVOID C structure buffer
Number: LONG where to insert (offset in bytes)
Number: DOUBLE value to insert
Returns Boolean: BOOL

Syntax bOk = CStructPutString( strBuffer, nOffset, nMaxWidth, strInsert )


Description Inserts a string into a buffer

551
Parameters Receive String: LPVOID C structure buffer
Number: LONG where to insert (offset in bytes)
Number: LONG null-terminated string to insert
String: LPSTR maximum number of bytes to insert
Returns Boolean: BOOL

Syntax bOk = CStructPutFarPointer( strBuffer, nOffset, nFarPointer )


Description Inserts a far pointer into a buffer
Parameters Receive String: LPVOID C structure buffer
Number: LONG where to insert (offset in bytes)
Number: LONG value to insert
Returns Boolean: BOOL

Using Global Memory


strci*.dll has functions that allocate, free, and access global memory so that structures with pointers to global
memory are accessible by SQLWindows. The tables below show these functions.
The following example shows how to use the memory functions to insert a pointer to a string into a structure:
1. Allocate memory to hold the string:
nPointer = CStructAllocFarMem( 80 )
2. Store the string in the allocated memory:
Call CStructCopyToFarMem( nPointer, strToPass, 80 )
3. Store the pointer to the string in a structure starting at the tenth byte:
Call CStructPutFarPointer( strBuffer, 10, nPointer )
... do something with allocated memory
4. When done using the allocated memory, free it:
Call CStructFreeFarMem( nPointer )

Global Memory Functions


Syntax nFarPointer = CStructAllocFarMem( nBytes )
Description Allocates global memory
Parameters Number: LONG number of bytes to allocate
Returns Boolean: LONG address of the global memory

Syntax bOk = CStructFreeFarMem( nFarPointer )


Description Frees memory allocated by CStructAllocFarMem
Parameters Number: LONG address of the global memory to free
Returns Boolean: BOOL

552
Syntax bOk = CStructCopyToFarMem( nFarPointer, strData, nDataLen )
Description Copies a string to far memory
Parameters Number: LONG address of global memory
String: LPVOID data to copy
Number: LONG maximum number of bytes to copy
Returns Boolean: BOOL

Syntax bOk = CStructCopyFromFarMem( nFarPointer, strData, nDataLen )


Description Copies data from far memory to a string
Parameters Number: LONG address of global memory
Receive String: LPVOID string to copy
Number: LONG number of bytes to copy
Returns Boolean: BOOL

Copying Buffers
Use the CStructCopyBuffer function to copy data from one buffer to another. The data in the buffers can
contain null characters.
Syntax bOk = CStructCopyBuffer(strDest, nDestOffset, strSrc, nSrcOffset, nCopyLen )
Description Copies data from far memory to a string
Parameters String: LPVOID copy to this string (destination)
Number: LONG where to copy to in destination string
String: LPVOID copy from this string (source)
Number: LONG where to copy from in source string
Number: LONG number of bytes to copy
Returns Boolean: BOOL

553
Chapter 23 – Team Developer Win32 API
Migration
This chapter explains how to migrate legacy Team Developer applications with Win32 API function calls to
Team Developer 5.1 SP2 and above. More than 50% of the legacy applications that use Win32 APIs should
migrate naturally. There is, however, a chance that some of the Win32 APIs need to be reviewed and modified
manually.
Functionally speaking, TD 5.1 is a superset of the previous version of Team Developer. It introduces new
features such as Unicode and the latest GUI features based on Microsoft’s Standard. It is inevitable that some
of the Win32 APIs might not be compatible with the new features in TD 5.1. This document identifies
problems you might experience during the migration, and provides a solution for most of the problems.

Migration Process
If any problem arises when a legacy application is compiled and run with Team Developer 5.1, it probably falls
into the following categories:
• Menu
• Usage of hWndForm
• ASCII version of Win32 API
• Incorrect Win32 API function prototype declaration
• Using a string as a Buffer for binary data
• Getting the parent window handle using win32 api
• Custom control referencing an old dll version (for example, “Not enough system resources to create
window” error)

Working with Menus


In Team Developer 5.1, menus are displayed by a Control Bar, which were implemented with the SAL
functions SalGetMenu and SalMenuUpdate.
When trying to manipulate menus with the Windows API, you can no longer use the GetMenu function to
retrieve the menu handle. You must now use the new SalGetMenu function to obtain this information. This
will return the correct menu handle that can be used with other Windows API function calls to
add/change/delete menu information. Then once you made all your changes to this menu, you must use the
new function SalMenuUpdate for your changes to take effect.
If you use the WinAPI calls to create a new menu the new function SalMenuUpdate will also work to attach
that newly created menu.
If you are just manipulating the enabled or checked settings of a menu item using the WinAPI, you can
continue to use the SalDrawMenuBar function to update a top level menu. “Enabled when” or “Checked
when” code in the Sal Outline will take precedence over hMenu settings if and only if Sal code exists for those
items.
554
The Control Bars do not support owner draw object, which means if you have an owner draw menu that was
created and attached to a form (or MDI), the messages WM_MEASUREITEM and WM_DRAWITEM do not get
called.
Owner Draw popup menus created for the child windows will continue to work.
Download the Team Developer samples and look at the contents of ../SQLWindows/ WinAPI for some
examples.

Window Handle of Accessory Frame Window


Some Win32 APIs didn't work due to a new window created in TD5.1. In TD4.2, hWndForm is the window
handle to form window, which is the top-level window. However, TD5.1 creates an “accessory frame” window
in addition to the form window, and the new “accessory frame” window is the parent of the form window
(this is true even when the “Accessories Enabled” attribute of the form windows is set to “No”).
That's why SetWindowLong/SetLayeredWindowAttribute stopped working. In prior versions of TD, they
would have been called with hWndForm, which is not a layered window any more - it becomes a child
window of the “accessory frame” window. We have to call them with the top-level window. So, how do we
get the window handle of the “accessory frame” window?
There are two ways:
• Call Win32 API function GetParent()
Use this with caution, our internal structure has changed and the frame window may not be the parent.
• TD5.1 provides a new system variable (Recommended).
hWndFrame: This is a convenient method to obtain the “accessory frame” window handle.
There is no generic rule here to decide when hWndFrame should be used, and when hWndFrom should be
used. The user has to understand what the code does and make the decision accordingly. But generally
speaking, when you use the Win32 API to paint the form window, you should still use hWndForm; otherwise,
you should consider hWndFrame. For instance, when you resize the window, change the style or attribute of
the form window, or do non-client area painting on the form.
In the sample ClockWindow.app, the following changes must be made:
• frmCLOCK::OnWM_Paint(…) – replace hWndForm with hWndFrame on SetWindowPos() and
SetLayeredWindowAttributes. You will notice we still use hWndForm for other functions.
• FrmCLOCK::OnSAM_Create() – Replace the hWndForm with hWndFrame on
GetWindowLongA(),SetWindowLongA(), and VisWinSetStyle.
Another area that deserves attention is the theme. Some of the themes don't work well with Win32 API.
Especially when you change a visual window style such as WS_CAPTION, WS_BORDER, WS_DLGFRAME (…).
So ALWAYS start with native Windows XP theme, make it work, and try other themes.
Download the Team Developer samples and look at the contents of ../SQLWindows/ WinAPI for some
examples.

Use Unicode Version of Win32 API function


Many Win32 API functions have both ASCII and Unicode versions. If you use the ASCII version, you could leave
as it is if the function doesn't use any string parameter (LPSTR or LPCSTR). Otherwise you have to replace
ASCII function calls with its Unicode version counterpart.

555
For instance, if you dynamically create a window with CreateWindowExA, you have to use
CreateWindowsExW, otherwise the function call will fail.

Fix Win32 API Function Declaration


If a function parameter is defined as an array, it should be defined as LPVOID in TD5.1 and above.

Using a String as a Buffer for Binary Data


You now have two new functions to set and get buffer length information, in a string variable. In previous
version of Team Developer you could just simply use the SalStrGetBufferLength or SalStrSetBufferLength
functions. This is because all character data (being ANSI) was 1 byte in length. But with TD5.1, all string data is
UNICODE, or 2 bytes in length. So, if you are currently using a string variable to store non-text data (or binary
data) in TD5.1, you can now use the new functions SalSetBufferLength & SalGetBufferLength to correctly
manipulate the size of a string variable.

Getting Parent Window Handle Using the Win32 API


To get the handle of an MDI frame window, call GetParent(hWndForm).
To get the handle of the top level window, call GetAncestor(hWndForm,GA_ROOT)

Custom Control “Current DLL” Property


If you run into this error: "Not enough system resources to create window," a custom control is probably
referencing an older Team Developer installation dll. Custom controls must use the correct dll versions for the
Team Developer installation that you want to use.

556
Chapter 24 – Custom Controls
This chapter explains how to use Microsoft Windows custom controls in SQLWindows applications.
A custom control extends the user interface in a SQLWindows application. You can add a custom control as a
child window to a form window, dialog box, or toolbar. You can buy custom control DLLs from software
vendors or you can develop your own. One or more Windows applications can use the same custom control.
Custom controls are stored in DLLs (Dynamic Link Libraries). A DLL can contain more than 1 custom control.
Each custom control in a DLL is uniquely identified by its window class name. Some custom control DLLs call
functions in separate support DLLs.
Most custom controls have a message interface. The application outline for a custom control has a message
actions section. A custom control's DLL can have functions that you can call from a SQLWindows application.
The way you use messages or functions with a custom control is defined by its developer.
You add a custom control to an application the same way as other objects. SQLWindows displays custom
controls at design time and runtime. You use the name of a custom control to refer to it in SAL statements.
A custom control does not have a data type and you cannot refer to it in a SAL expression.
Control means the same thing as object.

Adding a Custom Control to a Window


You can add a custom control to a form window, dialog box, or toolbar. If the application has custom control
classes, the Controls toolbar and Coding Assistant list the class names. To create an instance of a class, choose
the class name before adding the custom control.
1. Use Coding Assistant or the Controls palette to place a custom control on a parent window and display
the Open Control Library dialog. In the lower left of the dialog, make a selection in List Files of Type.

All custom control files are DLLs, but they do not have to have a *.DLL extension.
2. Select the directory where the custom control is stored in the right list.
3. Select a DLL in the left list.

557
4. Specify the class name. The author of the custom control supplies the window class name. If you buy a
custom control, the documentation tells you the class name.
Important: Some DLLs register window classes for their own use. Make sure to select the class name in
the list that you want.
5. Click OK and the custom control appears.

Message Actions
SQLWindows sends the following messages to a custom control:
• SAM_Create
• SAM_CustControlCmd
• SAM_Destroy
• SAM_Timer

SAM_CustControlCmd
Custom controls send a WM_COMMAND message to the parent window to tell it that an event happened.
For example, when a user clicks a standard push button, BN_CLICK is the notification sent to the parent
window.
To encapsulate message handling within custom controls, SQLWindows translates WM_COMMAND messages
that the parent receives into SAM_CustControlCmd and sends them to the custom control with the
notification code in the wParam. For example, the WM_COMMAND message above causes a
SAM_CustControlCmd with wParam containing BN_CLICK.
SQLWindows ignores any value you Return when you process SAM_CustControlCmd.

Other Messages
Custom control objects can send and receive other messages that you can use in SQLWindows applications to
operate the control.

Using Classes and Libraries


You can use SQLWindows libraries and classes to encapsulate custom controls, making them easy to reuse in
applications.
You can define a custom control class and create objects that are instances of the class. This lets you define
behavior once, and then share it. In a custom control class definition, you can define:
• Message actions to process messages.
• Wrapper functions that operate the control, but hide and simplify its interface. These functions can send
messages to the control or call external functions in the control's DLL.

558
You derive other classes that have different styles from a base custom control class, such as deriving a vertical
spin control class or a horizontal spin control class from a spin control base class that does not specify
orientation.
Put all source elements related to the custom control in a library:
• Custom control class definitions
• Support class definitions
• Constants
• External function declarations
The two main examples in this chapter use a class, wrapper functions, and a library with a custom control.

Creating Custom Control Classes


When you create a custom control class, the Open Control Library dialog appears with a Class Default push
button. If you click this push button, you do not have to specify a DLL name or window class name. This lets
you:
• Specify the DLL name and window class name when you create an instance of the class
• Inherit the DLL name and window class name from a base class

Attributes
The table below describes the attributes for a custom control. Some properties are not relevant for a given
custom control. For example, some custom controls do not display a title or use scroll bars.
You can change the DLL name and window class name in the Attribute Inspector.

Property Description
Object Name The name you use to refer to the custom control in statements.
Object Title The name that appears as the custom control's title. Some controls use the title to encode
settings. In this case, you can enter the settings in the Attribute Inspector.
Current DLL The name of the DLL that defines the window class.
MS Windows Class The name of the custom control's window class.
Name
Visible If Yes (default), the custom control is visible at runtime. If No, the custom control is not
visible at runtime.
At runtime, you can change the setting of this property with SalHideWindow and
SalShowWindow.
Location and Size Displays a cascading menu with the custom control's position (top and left) and size
(width and height).
Properties This is only enabled for custom controls that have an editor interface (explained later in
this chapter).
Border If Yes, the custom control has a border. The default is No.

559
Property Description
Etched Border If Yes, the custom control has an etched border that makes it appear 3-dimensional. If the
display style of the parent form or dialog box is etched, then the border of the custom
control is etched. SQLWindows draws an etched border using two shades of gray. The
default is No.
Vertical Scroll If Yes, the custom control is created with the WS_VSCROLL window style defined in
WINDOWS.H. The default is No.
Horizontal Scroll If Yes, the custom control is created with the WS_HSCROLL window style defined in
WINDOWS.H. The default is No.
Hollow Window If Yes, the custom control behaves like a group box: you can put other child objects in the
custom control and SQLWindows does not clip or obscure them. The default is No.
Tab Stop None – The user cannot set the focus on the custom control using the Tab key (default).
Group – The first or last item in the group gets the focus when the user tabs. The user can
then set the focus to an object within the group using the arrow keys.
SQLWindows maps this setting to the WS_GROUP windows style defined in WINDOWS.H.
Tab – The user can set the focus on the custom control with the Tab key.
SQLWindows maps this setting to the WS_TABSTOP windows style defined in
WINDOWS.H.
Tile to Parent If Yes, the custom control fills the background of the parent object. SQLWindows
automatically resizes the custom control when its parent is resized.
MS Windows Style A window style specific to the custom control. Read the documentation for the custom
control.
MS Windows An extended window style specific to the custom control. Read the documentation for the
Extended Style custom control.
Background Color The background color of the custom control.
Text Color The color of text in the custom control.
Font Name The font of text in the custom control.
Font Size The font size of text in the custom control.
Font Enhancement The font enhancement (such as italic or bold) of text in the custom control.

Example
To find the interface for a custom control, read the documentation or the source code. This section illustrates
an interface by showing the source code for a slider custom control and the code in a SQLWindows
application that uses the slider.

Include File
The SQLWindows application can send four messages to the slider custom control. You need to specify the
values for the message numbers in the SQLWindows application. They are defined in the include file as:

560
#define SLDM_SETPOS WM_USER+101 // wParam = wPos
// lParam = Not used
// Returns = TRUE
#define SLDM_GETPOS WM_USER+102 // wParam = Not used
// lParam = Not used
// Returns = (WORD)wPos
#define SLDM_SETRANGE WM_USER+103 // wParam = Not used
// lParam = MAKELONG(wMin, wMax);
// Returns = TRUE
#define SLDM_GETRANGE WM_USER+104 // wParam = Not used
// lParam = Not used
// Returns = MAKELONG(wMin, wMax);
The DLL sends a WM_COMMAND message with a notification code when the user moves the slider. You need
to define this number in the SQLWindows application.
This statement in the include file defines the number:
#define SLDN_POSCHANGE 1
The slider custom control has two styles that you can set. The numbers for these styles are defined in the
include file as:
#define SLDS_VERTICAL0x0001L
#define SLDS_HORIZONTAL 0x0002L
You need to specify the window class name in the Attribute Inspector. The DLL defines this string in an include
file:
#define SLIDERCLASS "SWSlider"
The DLL sets the class name in LibMain:
wc.lpszClassName = SLIDERCLASS;

Window Procedure
The window procedure shows how the DLL processes messages. The code fragment below shows the
message processing for WM_LBUTTONUP and SLDM_SETPOS:

561
long FAR PASCAL SliderWndProc( HWND hWnd, unsigned message,
WORD wParam, LONG lParam )
{
...
switch ( message )
{
...
case WM_LBUTTONUP:
...
// Code that paints slider in new position
...
// Notify parent of thumb position change
SendMessage( GetParent( hWnd ), WM_COMMAND,
GetWindowWord( hWnd, GWW_ID ), MAKELONG( hWnd, SLDN_POSCHANGE ) );
break;
case SLDM_SETPOS:
if ( ( wParam < THUMBMIN ) || ( wParam > THUMBMAX ) ) return( 0L );
...
// Code that paints slider in new position
...
return( 1L );
case SLDM_GETPOS:
...
case SLDM_SETRANGE:
...
case SLDM_GETRANGE:
...
The code fragments show message processing in two directions: the DLL receiving messages and sending
messages. When the user moves the slider and releases the mouse button, the DLL gets WM_LBUTTONUP
that it processes by repainting the slider and sending the parent WM_COMMAND with the notification code
SLDN_POSCHANGE. SQLWindows then sends WM_COMMAND to the custom control itself as
SAM_CustControlCmd with the notification code in the wParam. The SQLWindows application message
processing is shown later in this chapter.
The SQLWindows application can send the DLL SLDM_SETPOS to change the position of the slider. The DLL
processes SLDM_SETPOS by repainting the slider and returning one to indicate that the message processing
was successful. Note that the DLL returns zero if the range is not valid.

SQLWindows Application
This example uses classes and libraries. First, the library declares constants for the messages that the custom
control sends or receives:
Global Declarations
...
Constants
System
Number: WM_USER = 0x0400
Number: SLDM_SETPOS = WM_USER + 101
Number: SLDM_GETPOS = WM_USER + 102
Number: SLDM_SETRANGE = WM_USER + 103
Number: SLDM_GETRANGE = WM_USER + 104
Number: SLDN_POSCHANGE = 1
The library defines a custom control class:

562
Custom Control Class: clsSlider
...
Functions
Function: SetPos
...
Parameters
Window Handle: hWnd
Number: nPos
...
Actions
If NOT SalSendMsg( hWnd, SLDM_SETPOS, nPos, 0 )
Call SalMessageBox( 'The slider range is not valid',
'Slider Error', MB_Ok )
Function: GetPos
...
Function: GetRange
...
Function: SetRange
...
Message Actions
On SAM_CustControlCmd
If wParam = SLDN_POSCHANGE
! Simulate SAM_ScrollBar when the user moves the slider
Call SalSendMsg( hWndItem, SAM_ScrollBar, SB_ThumbPosition,
GetPos( hWndItem ) )
The class defines functions that an application calls to operate the slider. In turn, the functions send messages
to the slider. This is an example of using wrapper functions to hide the message processing for a custom
control.
Note the SAM_CustControlCmd message processing. The message actions check for the SLDN_POSCHANGE
notification code and send the control a SAM_ScrollBar message with the SB_ThumbPosition code in the
wParam and the position of the slider in the lParam. This is an example of using a class to hide and simplify a
custom control's interface; to a developer who creates an instance of the slider, it operates like a standard
SQLWindows scroll bar.
The application creates an instance of the custom control:

563
Form Window: frmSlider
...
Contents
Data Field: dfMin
...
Data Field: dfMax
...
Data Field: dfPos
...
clsSlider: cc1
...
Message Actions
On SAM_ScrollBar
Set dfPos = lParam
Pushbutton: pb1
...
Message Actions
On SAM_Click
Call cc1.GetRange( cc1, dfMin, dfMax )
Pushbutton: pb4
...
Message Actions
On SAM_Click
Call cc1.SetRange( cc1, dfMin, dfMax )
Pushbutton: pb2
...
Message Actions
On SAM_Click
Set dfPos = cc1.GetPos( cc1 )
Pushbutton: pb3
...
Message Actions
On SAM_Click
Call cc1.SetPos( cc1, dfPos )
The SAM_ScrollBar message actions set dfPos with the value of the lParam. The push buttons call class
functions that operate the custom control.
Packing and unpacking numbers in lParam. Many custom controls pass and receive two numbers in the
lParam. For example, the SLDM_GETRANGE message returns both the minimum and maximum value in
lParam. You can unpack the numbers using SalNumberHigh and SalNumberLow:
Actions
Set nRange = SalSendMsg( hWnd, SLDM_GETRANGE, 0, 0 )
Set nMin = SalNumberLow( nRange )
Set nMax = SalNumberHigh( nRange )
Do the following to pack two numbers in the lParam:

564
Function: SetRange
...
Actions
Set nRange = nMin + nMax * 0x10000
Call SalSendMsg( hWnd, SLDM_SETRANGE, 0, nRange )

Writing a SQLWindows-Aware Custom Control


This section describes the key features in a custom control that is tailored for use in SQLWindows
applications.

Registering a Window Class


A custom control library registers one or more window classes when the DLL loads. A SQLWindows developer
specifies the DLL name and window class to use the custom control.
SQLWindows superclasses the window class registered by the DLL. SQLWindows adds some additional
window words and class words. A custom control can be written in a way that is incompatible with
superclassing. If you write a DLL, be aware that the superclass will have the new window words.
SQLWindows sets the CS_DBLCLKS style in the new window class so that the window receives
WM_LBUTTONDBLCLK.

Window Styles
MS windows style. The window style is a double-word value that SQLWindows passes to a window when it is
created. The meaning of the bits in this double-word is defined by Windows. These attribute settings control
these bits:
• WS_BORDER
• WS_GROUP
• WS_TABSTOP
• WS_HSCROLL
• WS_VSCROLL
For example, setting the Border attribute to Yes sets the WS_BORDER bit. The constant values for the WS_*
styles are defined in WINDOWS.H.
Some controls use the low-order word of the window style for class-specific styles. For example, the BUTTON
class in USER32.EXE uses the BS_* styles in the low- order word to distinguish between a push button, radio
button, and check box. You can get the style bits when you process a CREATE message.
MS extended windows style. SQLWindows creates custom controls by calling CreateWindowEx with another
double-word value that SQLWindows passes to a window when it is created. You also get the extended style
bits when you process a CREATE message.

565
Colors
When a custom control receives a WM_PAINT message, it can send a WM_CTLCOLOR message to get the
color that the developer sets:
case WM_PAINT
hBrush = ( BRUSH )SendMessage(GetParent( hWnd ),
WM_CTLCOLOR, hDC,
MAKELONG( hWnd, 0 ) )
The hBrush is the background color. Use GetTextColor( hDC ) instead of GetParent( hWnd ) to get the text
color.
When a control sends WM_CTLCOLOR, SQLWindows returns the background color that the developer sets
and calls SetTextColor with the text color that the developer sets.

Fonts
Custom controls that display text must process WM_GETFONT and WM_SETFONT.
SQLWindows sends WM_GETFONT to a control to find the font name. Process WM_GETFONT by returning
the font handle.
When a developer sets a font, SQLWindows sends the control WM_SETFONT. Process WM_SETFONT by
storing the font handle and using it when the custom control paints text.

Interface
Through the interface, a custom control talks to the SQLWindows application and the application talks to the
custom control. You can implement the interface through messages or functions or a combination.
Message interface. A custom control DLL can have a message interface that operates the control. A control
can both send and receive messages, depending on its nature.
For example, if a custom control can display different shapes, it could have a SM_SETSHAPE message that the
SQLWindows application can send to it with a number in the wParam that identifies the type of shape.
Notification messages. When an event happens that is relevant to the control such as a click, double-click, or
selection from list, send a WM_COMMAND message to notify the parent. Use WM_COMMAND as follows:
• wParam – Window ID of the custom control
• HIWORD( lParam ) – Window handle of the custom control
• LOWORD( lParam ) – Notification code
For example, standard buttons send BN_CLICK with WM_COMMAND to tell the application that the user
clicked a button.
SQLWindows translates WM_COMMAND messages into SAM_CustControlCmd and sends them to the custom
control with the notification code in the wParam.
Function interface. You can write functions in the DLL that a SQLWindows application calls to operate the
custom control. These functions take the custom control window handle as a parameter. Compared to
messages, functions have the benefit of parameter type-checking. Also, functions can send messages to a
custom control.

566
Design Time Behavior
Some custom control objects need to behave differently at runtime and design time. Because SQLWindows
only sends SAM_Create at runtime, the application can use it to detect that it is in runtime. For example, an
animation control does not need to be animated at runtime. When the control receives SAM_Create, send it
a message:
On SAM_Create
SendMessage( hWnd, CCM_STARTRUNMODE, 0, 0L )
If you write a property editor function, you can retrieve the mode from SQLWindows.

Calling SAL functions


DLLs that use SWIN*.DLL, SWIN.H, and SWIN.LIB can call Sal* functions. For example, you can call Sal*
functions to control sibling windows. For example, a spin control can call SalFmtStrToField to set the contents
of a data field after incrementing the field's value (see Using CDLLI*.DLL on page 543).

Validation
You can call SalValidateSet in the DLL (see Calling SalValidateSet in a DLL on page 571).
The SalValidateSet function is in SWIN*.DLL. For more information about SWIN*.DLL, see Chapter 22 – Calling
External Functions in Dynamic Link Libraries.

Custom control editor interface


A custom control DLL can optionally provide a function that SQLWindows calls at design time to display a
dialog where a developer can specify window styles or other settings specific to the custom control. For
example, settings for a spin control can include a start range, a stop range, and an increment; settings for a
progress bar can include vertical or horizontal orientation.
This is an example of a modal editor dialog for a slider custom control:

SQLWindows calls the function when a SQLWindows developer selects the Properties attribute. The function
passes a variable-length data block that contains the settings and a window style back to SQLWindows.
SQLWindows stores these in the outline and passes them to the function when a developer chooses the
Properties attribute. You can define the format of the settings data block as you need for the custom control.
The include file SWCC.H contains the structures and macros you need to write the function.
This is the function prototype:

567
WORD FAR PASCAL _export _loadds SWCustControlEditor(
HWND const hWndDialogParent,
LPSTR const lpszClass,
HWND const hWndCustom,
LPSWCCSETTINGS lpSettings,
LPDWORD lpdwStyle;
Important: You must specify this function name in the EXPORTS statement in the DLLs. *.DEF file.
SQLWindows disables the Properties attribute if it cannot find a function named SWCustControlEditor in the
DLL. Also, SQLWindows disables the Properties item if the custom control does not have a window.
SQLWindows passes these parameters as input values for the function:
• hWndDialogParent – The handle of the parent window of the modal dialog this function creates.
• lpszClass – The name of the custom control class.
• hWndCustom – The handle of the custom control instance.
• lpSettings – The current custom control settings. The definition of the LPSWCCSETTINGS struct is:
typedef struct tagSWCCSETTINGS
{
DWORD dwLength; HGLOBAL hMem;
} SWCCSETTINGS;
typedef SWCCSETTINGS FAR * LPSWCCSETTINGS;
The dwLength member is the length in bytes of the current settings. This is zero if settings have not been
defined.
The hMem member is a handle to global memory that contains the current settings. This is null if
dwLength is zero. This memory block always contains as many bytes as indicated by dwLength. Define the
format of the data that hMem points to as needed for the control.
• lpdwStyle – The current window style bits that are passed to CreateWindow.
SQLWindows passes a pointer to the structure below in the lParam of the WM_CREATE and WM_NCCREATE
messages. Use the macros below to get the members in this structure.
typedef struct tagSWCCCREATESTRUCT
{
Int nReserved;
UINT fUserMode: 1; // User mode or design mode
UINT fUnused: 15; // Unused bits
LPSWCCSETTINGS lpSettings; // Custom control settings
} SWCCCREATESTRUCT;
typedef SWCCCREATESTRUCT FAR* LPSWCCCREATESTRUCT;
In the function, use the macro below to extract the custom control settings from the lParam. The return value
is a pointer to the LPSWCCSETTINGS structure. This pointer and the contents of LPSWCCSETTINGS are only
valid while processing the CREATE message:
#define SWCCGETCREATESETTINGS( lparam ) \
(((LPSWCCCREATESTRUCT)((LPCREATESTRUCT)lparam)->lpCreateParams)->lp Settings)
Use the following macro to get the mode of the control. The return value is a Boolean: TRUE means the
control is in user mode and FALSE means it is in design mode.
#define SWCCGETCREATEMODE( lparam ) ( BOOL ) \
(((LPSWCCCREATESTRUCT)((LPCREATESTRUCT)lparam)->lpCreateParams)->fUserMode)
Important: You can only call these macros while processing the WM_CREATE and WM_NCCREATE messages.

568
You write the code for the function. Display a modal dialog where the user can change the custom control's
window style or other settings.
After it completes its processing, the function returns these values:
• lpSettings – The new settings. The DLL can reallocate this memory block if necessary to increase its size.
SQLWindows stores the data in this memory block in the outline when the function returns
SWCC_NEWSETTINGS. Set dwLength to zero if the settings were not defined.
• lpdwStyle – The new window style bits. SQLWindows replaces the current window style with this value
when the function returns SWCC_NEWSTYLE. Do not include these style bits in dwStyle because
SQLWindows controls them:
WS_CHILD WS_VSCROLL WS_HSCROLL WS_TABSTOP WS_GROUP WS_BORDER WS_VISIBLE
The return value of this function is one or more of the flags below combined with the '|' operator. The flags
tell SQLWindows whether the DLL changed the settings or the style and how to update the custom control
window:
#define SWCC_NEWSTYLE 0x0001 // The style changed
#define SWCC_NEWSETTINGS 0x0002 // The settings changed
#define SWCC_NOCHANGE 0x0000 // Neither style nor settings changed
#define SWCC_PAINTWINDOW 0x0004 // SQLWindows needs to repaint the
// custom control window
#define SWCC_RECREATEWINDOW 0x0008 // SQLWindows needs to recreate the
// custom control window
#define SWCC_ERROR 0xffff // An error prevented the function
// from succeeding (such as out of memory)

Validation
You can enable SAM_Validate processing for a custom control. Call SalValidateSet to use validation with
custom controls:
bOk = SalValidateSet( hWndCC, bValState, lParam )
In SQLWindows, changes in focus trigger validation. SalValidateSet tells SQLWindows that the focus is
changing to a custom control so that SQLWindows can perform validation as needed.
Important: You must set the Tab stop attribute to Tab or Group so that the custom control can receive the
focus.
You call SalValidateSet when the user tries to move the focus to the custom control. The parameters are:
• hWndCC – Window handle of the custom control
• bValState – Whether to validate this custom control when it loses the focus:
 If TRUE, SQLWindows sends SAM_Validate when the custom control loses the focus
 If FALSE, SQLWindows does not send SAM_Validate when the custom control loses the focus
• lParam – SQLWindows passes the value you specify in the lParam of SAM_Validate
Specify TRUE in bValState for controls that behave like editable objects. When bValState is TRUE,
SQLWindows sends SAM_Validate to the object losing the focus:
• If validation succeeds, SalValidateSet returns TRUE and SQLWindows moves the focus to the custom
control. Later, when the user moves the focus off the custom control, SQLWindows sends it SAM_Validate
if its field edit flag is set to TRUE.
569
• If validation fails, SalValidateSet returns FALSE and SQLWindows sets the focus to the invalid object.

Editable Custom Controls


For an editable custom control, you want SQLWindows to send SAM_Validate if the user changes the value.
Call SalSetFieldEdit( hWndItem, TRUE ) when the user changes the value so that SQLWindows sends
SAM_Validate if the user tries to change the focus to another object.
The code example below shows the message actions for an editable custom control. The message actions call
SalValidateSet if the user tries to move the focus to the custom control. Also, if the user changes the value of
the custom control (which causes Windows to send EN_CHANGE notification messages), the actions call
SalSetFieldEdit.
Important: The message actions in the following example expect WM_SETFOCUS when the user sets the
focus on the custom control and EN_CHANGE when the user changes the value of the custom control. The
messages for these events can be different, so check the documentation (or the source code, if available) for
the custom control that you are using.
Number: WM_SETFOCUS = 0x0007
Number: EN_CHANGE = 0x0300
...
On SAM_Create
Call SalSetFieldEdit( hWndItem, TRUE )
On WM_SETFOCUS ! Sent after a window gets the input focus
! Send SAM_Validate to the object losing the focus
If NOT SalValidateSet( hWndItem, TRUE, 0 )
! If validation fails, return 0 so that Windows does not process
! WM_SETFOCUS further (moving the focus)
Return 0
On SAM_CustControlCmd
! When the user changes the value, Windows updates the display
! and sends EN_CHANGE; let SQLWindows know that the value has changed
If wParam = EN_CHANGE
Call SalSetFieldEdit( hWndItem, TRUE )
On SAM_Validate
Call SalGetWindowText( hWndItem, sText, 1000 )
If sText = ''
Call SalMessageBox( 'You must enter data in this field',
'Validation Error', MB_Ok )
Return VALIDATE_Cancel
Else
Return VALIDATE_Ok

Non-editable Custom Controls


Specify FALSE in bValState for controls that are not editable but that cause events (such as buttons) and for
controls that accept input but do not have a field edit flag (such as list boxes):
• If validation succeeds, SalValidateSet returns TRUE and SQLWindows moves the focus to the custom
control
• If validation fails, SalValidateSet returns FALSE and SQLWindows sets the focus to the invalid object
The following example shows the message actions for a non-editable custom control:

570
On WM_SETFOCUS ! Sent after a window gets the input focus
! Send SAM_Validate to the object losing the focus
If NOT SalValidateSet( hWndItem, FALSE, 0 )
! If validation fails, return 0 so that Windows does not process
! WM_SETFOCUS further (which moves the focus)
Return 0

Calling SalValidateSet in a DLL


If you write a custom control, you can call SalValidateSet in the DLL. The SalValidateSet function is in
SWIN*.DLL. For more about SWIN*.DLL, read Chapter 22–Calling External Functions in DLLs.
The asterisk in the name of SWIN*.DLL represents the first two digits of the version of the software you are
using. For example, if you are using version 5.0, SWIN*.DLL means SWIN50.DLL.

571
Chapter 25 – Symbol Scoping and Qualified
References
This chapter explains how SQLWindows resolves symbol names and how you qualify symbol names in
references.

Symbol Scoping
This section explains SQLWindows' symbol name resolution rules.
A symbol is a name that identifies an object, variable, constant, function, or class. The application elements
where you can define symbols are:
• Global declarations
• Form windows
• Table windows
• Dialog boxes
• MDI windows
• Functions
• Classes
The part of an application where you can refer to a symbol using only its name is called its scope. In
SQLWindows, the scope of a symbol is the application element
that defines the symbol. The scope of a symbol includes all application elements in the defining element,
nested to any level.
For example, the scope of a form's window variable (such as num1) is the form itself and the form's child
windows. Columns in the child table are also in num1's scope because the columns are in the defining form,
nested 2 levels down.

External References
To refer to a symbol outside of its scope, you must make an external reference. An external reference refers
to either:
• A variable, object, or function defined in a top-level window (at any level) from outside that top-level
window
• A variable, object, or function defined in an MDI window from outside that MDI window
To make an external reference, you must qualify it by prefixing other names to the symbol name. Sections
later in this chapter explain how to qualify references.

572
Examples of External References
The following diagram shows three external references. An arrow points from the referencing statement to
the symbol.

External References
Application Form1

Global Function: F

Global Variables Number: num1


Actions
Number: num ChildTable1

Window Handle: hWnd3 Function: FT


Window Handle: hWnd33

Column1

Actions
Form2 Call FT( )
Call F( )

Set num = 0

hWnd3.Form3 hWnd33.Form3

Function: F3

Number: num3 Number: num3

Actions Actions

If hWndForm = hWnd3 If hWndForm = hWnd3

Set hWnd33.Form3.num3 = 33 Set hWnd33.Form3.num3 = 33


Else Else

In the diagram on the previous page, all external references are qualified references, but not all qualified
references are external references. For example, this statement in Form1 is qualified, but is not external
because it refers to a symbol nested in the current top- level window:
Set ChildTable1.numT = 9
This means that there are two times when you must use qualified references:
• To make an external reference
• To refer to a child in its parent

Symbol Resolution Steps


Symbol resolution means how SQLWindows finds a symbol when you refer to it. SQLWindows follows these
steps to resolve a reference to a symbol:
1. Look for the symbol in the current context such as a form window or table window.

573
2. If the symbol is not in the current context (where you make the reference), look for the symbol in the
containing context such as a parent form window.
3. If the symbol is not in the containing context, continue to look in each application element's containing
context (grandparent, great grandparent, and so on).
4. Finally, look in the global context (application).
If the current context is a class, then its containing context is its direct base class.
This minimizes the times that you must qualify references. For example, you do not need to qualify a
reference to a form window variable that you make from a child table column defined in the form window.

Program Element Nesting


The outline below shows how application elements are nested for purposes of symbol resolution. The
numbers represent levels of nesting. Template means a form window, a table window (top level), or a dialog
box.

1. Application
2. Internal Function
1. Template
2. Window Function
2. Child Table
3. Window Function
1. MDI window
2. Window Function
2. Template
3. Window Function
3. Child Table
4.Window Function

1. Base Class
2. Class Function
2. Derived Class
3. Class Function

The scope of a derived class is logically contained in its base class for purposes of symbol resolution.
Therefore, you do not need to qualify references in a derived class to access variables or functions defined in
its base classes.
The diagram below shows graphically how you can nest application elements:

Internal Function

Window Function

574
Child Table
Window Function

MDI Window

Window Function

Template

Window Function

Child Table
Window Function
Base Class

Class Function

Derived Class
Class Function

Scope of Global Symbols


The scope of an item that you declare in the global declarations is the entire SQLWindows application. You
can access a global symbol from anywhere in an application without qualifying its name.

Names of Templates and MDI Windows


Template names and MDI window names are global. This means that the names of all form windows, table
windows (top-level), dialog boxes, and MDI windows must be unique throughout an application.

Early-Bound and Late-Bound References


Binding means associating a symbol with an object. There are two types of binding in references:
• An early-bound reference refers to a symbol whose containing object can be determined when you
compile
• A late-bound reference refers to a symbol whose containing object cannot be determined until runtime
Early-bound references are always more efficient than late-bound references.

Unqualified References
In an unqualified (or simple) reference, you only specify the name of the symbol.

575
Examples

Example Type Comments


strTemp variable
MyPrint( ) function The parentheses used to call a function are not part of the reference
dfStatus object
strArray[2] array element The square brackets used to access array elements are not part of the
reference
MSG_1 constant References to constants are always unqualified because constants are
always global (you can only define constants in the global declarations
section)

Late-Bound Unqualified References


An unqualified reference is early bound unless you specify two periods before a function name:
Call ..function( )

Qualified References
You use a qualified reference for a variable, object, or function in a top-level window (or MDI window) other
than the current top-level window (or MDI window).
In a qualified reference, you add a prefix that contains one or two other names to a symbol. You separate the
names with periods:
hWnd1.frm1.df1
The names that you can use in the prefix are:
• Object names (template, MDI window, user-defined window, or UDV)
• Window handles
• Class names
You combine these names in different ways to make these types of references:
• Object-qualified
• Fully object-qualified
• Handle-qualified
• Class-qualified
• Fully class-qualified
Sections later in this chapter explain each of these.
You need to qualify a reference when:
• The reference is not in the scope of the symbol
• A parent window refers to a symbol defined in one of its children

576
• It is an external reference (to a different top-level object or MDI window or to a different instance)
An external reference is always a qualified reference, but that a qualified reference is not always an external
reference.

Object-Qualified Reference
In an object-qualified reference, you qualify a symbol with an object name.

Syntax
object.symbol
where object is the name of the object that defines the symbol. If object is an instance of a class, then the
object's class can define or inherit the symbol.
The prefix object can be a:
• Object-qualified reference
• Fully object-qualified reference

Binding
An object-qualified reference is always early bound.

Examples
frmMain.strTemp
frmCustomer.dfName
frmMain.strArray[2]
childtable1.colSalary
frmMain.Print( )
frmMain.tbl1.col
hWnd.frm1.tbl1.col
Referring to duplicate symbols
In the following example, two form windows (frm1 and frm2) contain a data field named dfName:
Form Window: frm1
...
Contents
Data Field: dfName
...
Form Window: frm2
...
Contents
Data Field: dfName
When a dialog box (dlg1) refers to dfName, it is ambiguous:
Dialog Box: dlg1
...
Window Variables
String: strName
Message Actions
On SAM_Create
Set strName = dfName
To eliminate the ambiguity, qualify the variable name:

577
Dialog Box: dlg1
...
Window Variables
String: strName
Message Actions
On SAM_Create
Set strName = frm1.dfName
Referring to child symbols from a parent
You declare a child variable in a child object of a parent window. When you refer to a child variable from the
parent window, you must qualify the name with the name of the child object in which it is declared.
For example, if you refer to a variable from a form window and the variable is declared in one of the form's
child table windows, you must qualify the variable name with the child table name:
ChildWindowName.VariableName
You must qualify the reference because it is in the form window and is not in the scope of the child variable.
In the following example, a form window makes a reference to a window variable defined in its child table
window:
Form Window: frm1
...
Contents
Data Field: df1
Child Table: tblChild
...
Window Variables
String: strInfo
Window Variables
Message Actions
On SAM_Create
Set df1 = tblChild.strInfo
Use an object-qualified reference in MDI windows to refer to:
• An MDI window's child form window if there is only one instance of the child form
• A child table window of an MDI window's child form window

Fully Object-Qualified Reference


In a fully object-qualified reference, you qualify a symbol with a window handle and an object name.

Syntax
handle.object.symbol

• handle – A window handle or an expression that evaluates to a window handle.


• object – The name of the object that defines the symbol. If object is an instance of a class, the object's
class can define or inherit the symbol.
This can be an object-qualified reference.

Errors
You get an error at runtime if handle does not refer to an instance of object.

578
Binding
A fully object-qualified reference is always early bound.

Examples
hWnd.form.var
(hWndArray[1]).form.var
hWndChildTbl.(ParentForm.ChildTable).var
Referring to multiple instances of a window
In the following example, frm1 contains a data field named dfName:
Form Window: frm1
...
Contents
Data Field: dfName
These statements create two instances of frm1:
hWnd1 = SalCreateWindow( frm1, hWndOwner )
hWnd2 = SalCreateWindow( frm1, hWndOwner )
Two windows exist with identical names (frm1) and identically-named variables (dfName). SQLWindows
cannot determine the copy of dfName to which the dialog box dlg1 refers:
Dialog Box: dlg1
...
Window Variables
String: strName
Message Actions
On SAM_Create
Set strName = frm1.dfName
To eliminate the ambiguity, specify:
• The window handle with which the variable is associated (hWnd1 or hWnd2)
• The template name with which the variable is associated (frm1) For example:
Message Actions
On SAM_Create
Set strName = hWnd1.frm1.dfName

Handle-Qualified Reference
Important: This type of reference is provided for compatibility with existing applications. Using it is
discouraged because it can make application code unstructured and difficult to maintain. Instead, use late-
bound function calls.
In a handle-qualified reference, you qualify a symbol with a window handle.
The compiler accepts handle-qualified references even when the design-time setting “Require Qualified
External References” is set to No.

Syntax
handle.symbol

• handle – A window handle or an expression that evaluates to a window handle.


• symbol – This must be a child object or variable name. This cannot be a window parameter.

579
Errors
You get an error when you compile unless all symbols with the same name in all templates (top-level
windows), MDI windows, and child tables are the same type and the same underlying data type.
You get an error at runtime if the object to which handle refers does not contain the symbol.

Binding
A handle-qualified reference is always late bound.

Examples
hWnd.dfEmployee
(hWndArray[1]).dfEmp

Using generic functions


You can use handle-qualified references with generic functions that perform a service for more than one type
of window. You pass a handle to the function and the function accesses objects in the window. The function
must know the names of the objects that it accesses but does not need to know the window name.
Referring to multiple Instances of a window
In the following example, frm1 contains a data field named dfName:
Form Window: frm1
...
Contents
Data Field: dfName
These statements create two instances of frm1:
hWnd1 = SalCreateWindow( frm1, hWndOwner )
hWnd2 = SalCreateWindow( frm1, hWndOwner )
Two windows exist with identical names (frm1) and identically-named variables (dfName). SQLWindows
cannot determine the copy of dfName to which the dialog box dlg1 refers:
Dialog Box: dlg1
...
Window Variables
String: strName
Message Actions
On SAM_Create
Set strName = dfName
To eliminate the ambiguity, specify the window handle with which the variable is associated (hWnd1 or
hWnd2).
Message Actions
On SAM_Create
Set strName = hWnd2.dfName

Class-Qualified Reference
In a class-qualified reference, you qualify a symbol with a class name.
You can only make this type of reference in a class that inherits or defines the symbol.
Chapter 21 – Object-Oriented Programming, shows how to use class-qualified references.

580
Syntax
class.symbol
where class is the name of a class that defines or inherits the symbol.

Binding
A class-qualified reference is early bound unless you specify two periods before a function name:
cls1..func1( )

Examples
clsDbField.bIsKeyField
clsDbForm.print( )
clsDbForm..print( )

Fully Class-Qualified Reference


In a fully class-qualified reference, you qualify a symbol with a window handle and a class name.
You can only make this type of reference in a class that inherits or defines the symbol.
Chapter 21 – Object-Oriented Programming, shows how to use fully class-qualified references.

Syntax
handle.class.symbol

• handle – A window handle or an expression that evaluates to a window handle.


• class – The name of a class that defines or inherits the symbol. The window handle that you specify must
refer to an object that is an instance of class.

Binding
A fully class-qualified reference is early bound unless you specify two periods before a function name:
obj1.cls1..func1( )

Examples
hWnd.clsDbField.bIsKey
(hWnd[1]).clsDbF.bKey
hWnd.clsDbF..Insert( )

Design Time Settings


Three items in the Runtime tab of the Properties dialog (page 76) are related to external references:
• Fully Qualified External References
• Reject Multiple Window Instances
• Enable Runtime Checks of External References
All of these are explained below.

581
Fully Qualified External References
When on, the compiler forces you to qualify all external references.
When off, when the compiler cannot find a symbol in an unqualified reference using the symbol resolution
rules, the compiler silently uses any variable, object, or function with a matching name in any object
throughout the application.
This means that you must be sure that:
• You do not misspell a name.
• The application only creates one instance of the containing top-level form.
If both of these conditions are not true, then you get errors at runtime or the application misbehaves. These
problems are difficult to diagnose.
This setting sometimes determines how SQLWindows interprets parent object names, as the table below
explains:

Reference Explanation
hWnd.Variable The compiler always accepts no matter what the setting
Object.Variable The compiler accepts if you make the reference in the object's scope no matter what the
setting.
If you make the reference outside the object's scope, the compiler only accepts it if both
of the following are true:
– Fully Qualified External References is off.
– The object’s name is unique.

Reject Multiple Window Instances


When on, you get an error at runtime when the application tries to create a second instance of a form
window, table window, dialog box, or MDI window.
If the application never creates more than one instance of a window, you do not need to use window handles
in references; an object-qualified reference is always enough. However, the design of some applications
requires multiple instances of a window.

Enable Runtime Checks of External References


You can turn on this option to generate extra code to ensure that a window handle refers to a window whose
type or class is consistent with the SAL statement.
For example, when you turn on Enable Runtime Checks Of External References, SQLWindows performs these
checks for these expressions:
• hWnd.frm1.var – hWnd refers to a window whose type is frm1.
• hWnd.frm1.fun( ) – hWnd refers to a window whose type is frm1.
• hWnd.cls1.var – hWnd refers to a window that is an instance of the class named cls1.
• hWnd.cls1.fun( ) – hWnd refers to a window that is an instance of the class named cls1.
• hWnd.cls1..fun( ) – hWnd refers to a window that is an instance of the class named cls1 or is an instance
of a class derived from cls1.

582
It is recommended that you turn on this option during application development and testing to help find
programming errors. This option generates extra code that slightly impacts the performance and size of an
application, so turn off runtime checks for production applications (before making an *.EXE).
You can enable runtime checks to help diagnose incorrect behavior in production applications. Usually you
make an *.EXE with runtime checks enabled only if an application misbehaves. Such an *.EXE causes an error
message if there is a programming error that assigns an incorrect value to a window handle.

Advanced References
You can make references with more than one qualifying object name.

Nested Objects
To make a global reference (from an unrelated scope) to something nested more than one level inside
another object, you must specify all its parents’ names; for example:
mdi1.mdiform1.df1 frmMain.tbl1.col1
mdi1.mdiform1.tbl1.num1

Child Window Handles


If you use a window handle to qualify a reference and the handle refers to an object whose name is not next
to the window handle in the reference, then you must use parentheses to tell the compiler which object is
associated with the window handle. (This is called a “casting” operation.)
The compiler requires that any qualifier to the left of an opening parentheses, if any, be a window handle
expression. The following example does not require parentheses because hWndFrmMain refers to the object
to which it is adjacent, frmMain:
hWndFrmMain.frmMain.tbl1.col1
This example does require parentheses to associate hWndTbl1 with tbl1:
hWndTbl1.(frmMain.tbl1).col1
A simpler reference such as the following is only accepted when the reference is in the scope of tbl1 (for
example, when tbl1 is “visible” from the location of the reference):
hWndTbl1.tbl1.col1
You can group more than two object names with casting parentheses:
hWndCol1.(frmMain.tbl1.col1).num1
The example above, if accepted by the compiler, implies that col1 must be a class object that inherits the
instance variable num1. We know this because column objects cannot themselves define variables.
The compiler does not accept this example because the element to the left of the parentheses must be a
window handle expression and mdi1 is not:
(mdi1.(mdiform1.tbl1)).num1 Illegal!
This looks like a valid reference, but the compiler rejects it because it cannot tell which instance of the child
form window the code refers to because it only specifies the MDI window’s handle and there can be more
than one instance of the same child form window:

583
hWndMdi1.mdi1.mdiChildForm1.df1 Illegal!
Make the reference valid by specifying a handle to the specific child form window:
hWndMdiChildForm1.(mdi1.mdiChildForm1).df1

Non-Simple Window Handle Qualifiers


The window handle component of a qualified reference does not have to be a simple name.
This example is an array reference to a window handle:
hWndForms[2].frm1.df1
This example shows a common use of an array reference where the array contains handles to all the active
instances of an MDI child form window template:
hWndChildForms[2].(mdi1.mdiChildForm1).df1
This example uses a function that returns a window handle:
GetMyChildHandle().frm1.df1

584
Chapter 26 – Constructors and Destructors
in Team Developer 6.3
Constructors are class methods/functions that run automatically when an instance of that class is created.
Constructors may optionally have parameters, like a function, and so a class may contain more than one
constructor if the signatures (list of parameters) vary.

Adding a Constructor
In supported classes there is a new node, above the Functions node, called Constructor/Destructor.

There are two ways to add a subnode (a constructor node or destructor node) to this new node:
• Right-click the node. The context menu for the node shows two choices for inserting under the node:

• Press the Insert button. The context menu offers the same two options:

The name of the constructor is automatically filled in to match the name of the class, which is standard in
most programming languages. The actual name specified does not matter.

585
Selecting a Constructor inserts a new Constructor node under the Constructor/Destructor node.
A constructor is a kind of method, so you see many of the similar subnodes to a function:

The following are missing compared to functions:


• No return value because the constructor is never called like a function.
• No “static” variables, which would not make sense in a constructor environment.

Classes that Support Constructors


Both Functional classes and Windows classes can have constructors. The following cannot:
• Background Text Classes
• Frame Classes
• GroupBox Classes
• Line Classes
• Separator Classes
• CoClass Classes
• Web Service Classes
• WPF Custom Classes

Default vs. Parameterized Constructors


If a constructor has no arguments defined, it is considered the “default” constructor. This is the constructor
that will be run if you instantiate an object without passing any argument into the “new” statement:
Set obj1 = New MyClass()

When Constructors Run


The constructor of a class runs immediately when each instance of that class is created. For example, consider
the line:
586
Set obj1 = New MyClass()
This one line of code causes three actions internally:
• Creates a new instance of the class “MyClass”.
• Runs the constructor of MyClass on the newly created object.
• Assigns a reference to the new object to the “obj1” variable.
Unlike many languages, SAL automatically instantiates UDV variables when they come “into scope”; for
example:
MyClass: obj1
Because of this, if you add a default constructor to an existing class, it will run each time a variable is
declared. You can prevent this by adding “= OBJ_Null” to the variable declaration node; for example:
MyClass: obj1 = OBJ_Null
In this case, the “obj1” variable will have a null value and will have to have an object reference assigned to it
later using the “new” keyword.

Default Constructors and Inheritance


Default constructors can be inherited from one or more parent classes. Team Developer’s constructors always
call any inherited default constructors, from all inherited class parents. The call is automatic and occurs
before any code within the current constructor runs; for example:

If you create an instance of ClassB, the inherited constructor of ClassA runs first, and then the constructor of
ClassB; for example:

587
In this scenario, if you create an instance of ClassB, the inherited constructor of ClassA runs and that is all.
Team Develop does not offer any way to call inherited constructors “on purpose”, by which is meant using
some specific language command to control the timing of the call.
For Team Developer win32 applications, the order in which inherited constructors are called is based on the
order in which the inherited classes are listed in the outline. Therefore, if ClassA inherited ClassB, ClassC, and
ClassD (listed in that order in the outline), the constructors (if they exist) are also run in that order.
For Team Developer .NET applications, the order of running inherited constructors is harder to predict. To the
end-user, it can appear random. This is because .NET does not natively support multiple inheritance.
Therefore, Team Developer .NET mimics multiple inheritance using “delegation” logic.

The inherited default constructor that comes from the “true” inherited parent always runs first. Code is
generated inside ClassC’s constructor to invoke the constructor of the other class(s) inherited through
delegation.
Our .NET compiler decides which parent class gets “true” inheritance using multiple criteria:
• The “complexity” of the inherited parent
• For windows classes, whether the parent is of the same windows type
It can be hard to determine at design time the order in which the inherited constructors will run. For the end-
user, it is the best design, for win32 or .NET, to not design your constructors with any expectation that they
will run in a particular order.

Parameterized Constructors
Team Developer 6.3 offers a new format for “New" expressions to support parameterized constructors. To
pass values into the parameters of a parameterized constructor, the New keyword supports an argument list
similar to a function call:
Set obj1 = new MyClass(“foo”, 4)
The existing New keyword will continue to be supported with no parentheses for backward compatibility.
Arguments passed to a New expression must match the data type and order of those specified in the
parameters node of the constructor.

588
Overloading Constructors
Because you can have multiple constructors with different “signatures” (parameter lists), Team Developer 6.3
introduces the beginnings of “overloading” into SAL. At compile time, the compiler matches the signature
used in any New expression with the exact matching version of the necessary constructor.
One complex overloading situation can arise. SAL supports using field control references in a polymorphic
way. For example, “df1” can be used to refer to the window handle of the data field “df1”, and it can also be
used to refer to the current value contained in that data field; for example:
Set sVar = df1
This brings up potential confusion with constructor overloads. Consider the situation where a class has two
constructors, one that takes a single window handle as an argument and one that takes a single string as an
argument. Now, that class is instantiated with “df1” as the sole argument. Which constructor should the
compiler choose? The one that will treat “df1” as a window handle, or the one that will treat “df1” as a
string?
To help resolve this, Team Developer always gives preference to treating field control references as a
reference to the value contained in the control. Therefore, in the previous example, the constructor that takes
a single string would be called. If a user wants to pass the control reference into a constructor as a window
handle, they can assign df1 to a temporary window handle variable and then pass that variable into the
constructor.

Parameterized Constructors and Inheritance


You can only use a parameterized constructor directly on a class that offers one, and not on a class that
inherits one.

In this case, ClassB could not be instantiated using its inherited parameterized constructor, just the default
constructor.
Parameterized constructors will not call inherited parameterized constructors.
• They will call any inherited default constructors.
589
• Nothing will call an inherited parameterized constructor, either from a default or parameterized
constructor.

Windows Classes and Constructors


The constructors of windows classes run before the object is visible, fully created, or added to its parent
form/dialog/mdi object. For this reason, certain kinds of activities that attempt to affect the visual state of
the object are discouraged:
• Accessing or setting MyValue
• Using hWndItem to pass into any Sal window functions to manipulate the window object

Destructors
Destructors are class methods, or functions, that run automatically whenever an instance of the class is
destroyed in memory. Unlike constructors, there can be only one destructor per class. No parameters are
allowed because they are not invoked by the user directly.

When a Destructor is Called


When a destructor is called varies according to platform:
• Win32: Called when the object goes “out of scope” in the code, or when there are no more references to
the object.
• .NET: When the object has no more references to it, or goes out of scope, it is placed on the garbage
collection queue and it is up to .NET to decide when to actually destroy the object. There are native .NET
methods that can be used to manage the garbage collection, but the process is always going to be more
random than in win32.

Legacy: ObjectDestructor
In the past, there was a “partial” attempt at supporting destructors. If you placed a function in your class and
named it ObjectDestructor, Team Developer would call that function upon destroying each object. Stability
and support were spotty at best. This was never implemented in TD .NET, and was never widely used in the
TD community.
Team Developer 6.3 has migration logic to locate these instances and move them to a true Destructor node:
• Automatically add a destructor to the class in question.
• The auto-added destructor can call the existing ObjectDestructor function.

Cautions
Avoid the following cautions in assigning tasks to a destructor:
• Don’t do database interactions.
• Don’t throw exceptions.

590
• Don’t do expensive and time-consuming cleanup jobs, especially in win32.
• Don’t have logic that creates other objects.

591
Chapter 27 – Threading in Team Developer
7.1
Threading allows developers to execute long running tasks that would otherwise block the user interface in a
background thread. This keeps the UI responsive while expensive tasks run. There are three main
components to the threading capability in Team Developer:
1. Background Worker Class – A new class type, which is where you define the SAL code that will run in
the background.
2. Background Threads - Outline section on form/dialog windows. This is where you define an instance
of your worker class, and respond to events it raises.
3. SAL Threading API – Functions for interacting with threads at runtime.

Adding a Background Worker Class


The background worker class is where you would write your SAL code to perform an expensive operation that
would otherwise block the user interface. Background worker classes can be added to your project just like a
Functional Class, and have many other similaraties such as: Functions, Instance Variables, inheritenance.
They key difference in the Thread Start node, this is the SAL code which will be executed when the thread is
started.

Code executing in Thread Start (or any code you might call from Thread Start), is not allowed to access any UI
components. If you need to provide updates to the user interface, it must be done by passing information
using the SalBackgroundWorkerReportProgress function. This function allows you to periodically send
updates that can then be reported in the UI, for instance update a progress bar. If you want to allow the user
to cancel the worker, periodically check the return value of SalBackgroundWorkerIsCanceled, and if true
return out of Thread Start after cleaning up any resources.

Adding a Worker Instance to a Window


To make use of your new Background Worker class, you need to define an instance of it on a window. You can
add instances under the new “Backround Threads” outline node. Once added, specify an instance name. You
can add events to this instance under Thread Events. These events all will run on the GUI thread, and allow
you to give user feedback to events occurring in the background thread which cannot access the UI directly.

592
Thread Events
• Thread Before Start – Raised after SalBackgroundWorkerStart is called, but before thread is started.
Use this to initialize instance variables on the worker class.
• Thread Report Progress – Raised when the worker class calls SalBackgroundWorkerReportProgress.
• Thread Finished – Raised when the worker code finishes execution.
• Thread Report Error – Raised if an unhandled error occurs in the thread.

SAL Threading API


Several API functions support interacting with worker instances. Please refer to the Team Developer
embedded help for a detailed API reference.
• SalBackgroundWorkerStart – Used to start a worker thread instance.
• SalBackgroundWorkerCancel – Set a cancel flag on the worker instance.
• SalBackgroundWorkerIsCanceled – Check status of cancel flag.
• SalBackgroundWorkerAnyRunning – Check if a window or the entire application has any running
threads.
• SalBackgroundWorkerIsBusy – Check if a specific thread is running.
• SalBackgroundWorkerReportProgress – Send progress message to window running the thread.

593
Glossary
accelerator: A keyboard shortcut for choosing a menu item or pressing a push button. An accelerator causes
an action. Alt+<char>, Ctrl+<char>, and Shift+<char> are examples. Contrast with mnemonic.
accessor method: A method that sets or retrieves the value of a property. Most properties have a pair of
accessor methods. Properties that are read-only may have only one accessor method.
ActiveX: Microsoft's brand name for a set of Windows technologies and services that enable interoperability
using COM.
ActiveX control: A lightweight, in-process object with support for properties, property pages, methods, type
information, and events. An ActiveX control typically implements IDispatch and type information, and can
have events. An ActiveX control has an *.OCX extension.
ambient properties: Exposed properties that define a container's surroundings, including default colors,
fonts, and alignment.
animate: A menu command that highlights each item in the outline as it executes.
apartment model: A threading model that can be used only on the thread that created it.
API (Application Programming Interface): A set of functions that a program uses to access a service.
applet: A Java program that runs in the context of a Java-capable browser. Java applets extend the content of
Web pages beyond just graphics and text.
application: A SQLWindows program written for a user that applies to the user's work.
Application Actions: A section in the outline that contains procedural code that executes when the
application receives messages.
argument: See parameter.
array: A set of elements of the same data type. You refer to an element in an array using a subscript (index).
automation: An ActiveX mechanism for applications, development tools, and macro languages to control
objects by setting and reading their properties, by invoking their methods, and by detecting their events.
backend: See database server.
base class: The class from which a given class is derived. A derived class inherits its base class' data structure
and behavior. Also called superclass, ancestor, and parent class. Contrast with derived class. See also class,
inheritance and OOP.
behavior: The set of operations that an object can perform on its data.
bind variable: A variable that associates data to a SQL statement. You can use bind variables in the VALUES
clause of an INSERT statement, in a WHERE clause, or in the SET clause of an UPDATE statement. Bind
variables associate data in an application to the database.
binding: Associating a symbol with an object. See also early binding and late binding.
bitmap: A series of bits where one or more bits correspond to each display pixel. For a monochrome bitmap,
1 bit corresponds to 1 pixel. In a gray-scale or color bitmap, multiple bits correspond to each pixel to
represent shades of gray or color.
bitwise: A bit-by-bit comparison of identically positioned bits in two numeric expressions.

594
Boolean operator: An operator (AND, OR, NOT) that combines logical values to produce a result of TRUE or
FALSE. Also called logical operator.
breakpoint: A statement in an application where execution suspends so you can set and examine variables.
browse: A mode where a user queries a database without necessarily making additions or changes. In a
browsing application, a user needs to examine data before deciding what to do with it. A browsing application
lets the user scroll forward and backward through data.
browser: An application that knows how to interpret and display documents that it finds on the World-Wide
Web.
buffer: A memory area that holds data during input/output operations.
cache: An area of memory that holds table window row data.
call by reference: A parameter-passing technique where a function has the original value of a parameter, not
a local copy. Contrast with call by value.
call by value: A parameter-passing technique where a function has a copy of a parameter's value, but not the
original value. The called function cannot change the original value; it can only change the temporary copy.
Contrast with call by reference.
case sensitive: A condition in which data must be entered in a specific lowercase, uppercase, or mixed-case
format.
cast: An action that converts an object from one type or class to another.
cell: The intersection of a row and a column in a table window.
CGI (Common Gateway Interface): A standard that specifies how Web servers communicate with other
programs running on the server. With CGI, the Web server can start a program and pass it user-specific data
(such as what host the user is connecting from or input the user has supplied using HTML form syntax). The
program then processes that data and the server passes the program’s response back to the Web browser.
character: A letter, digit, or special character (such as punctuation mark) that represents data.
class: A template that specifies the data and behavior of an object. Objects are created at run time and are
instances of a class, while classes are a static description of a set of objects. You create classes in hierarchies,
and inheritance lets you pass the data and behavior in one class down the hierarchy. See also base class,
derived class, inheritance, object, and OOP.
class function: A function that you write in a class definition. A class function is the implementation of an
object's behavior. An object's functions are shared by all objects in the same class. Also called method or
member function.
class variable: Stores data that is shared by all objects in a class. Contrast with instance variable.
client: A computer that accesses shared resources on other computers running as servers on the network.
Also called front-end or requester. See also: server and database server. The term client is also used to refer
to applications in DDE and Report Builder.
Clipboard: The holding place for what was last cut or copied. Data on the Clipboard can be inserted (pasted)
into other Windows applications.
code page: An internal table that the operating system uses to map symbols (letters, numbers, and
punctuation characters) to a character number. Different code pages provide support for the character sets
used in different countries. For example: “Unicode”.
Coding Assistant: Displays the items that you can add at the current location in the outline.
collapse: Hiding lower outline levels.
595
collection: In COM, a group of related objects that can be indexed, either numerically like an array or by
name. A collection lets you work with a set of similar things as a single group instead of as independent
entities.
column: In a table window, a complete vertical line of cells. See also table window and row.
In a database, a data value that describes one characteristic of an entity. A column is the smallest unit of data
that can be referred to in a row. A column contains one unit of data in a row of a table. A column has a name
and a data type. Sometimes called field or attribute. See also database and row.
column identifier: A column’s position in the outline or its order of creation. It is a permanent, non-
changeable number associated with a table window column. You specify one for the first column, two for the
second column, and so on. A column’s identifier does not change if you or the user changes the order of
columns in a table window. Contrast with column position.
column position: The visual position of a column. It is a relative, changeable number associated with a table
window column. The first (left-most) column in a table window is one, the column to its immediate right is
two, and so on. If you or the user changes the order of the columns in a table window, their column positions
change to reflect the visual order. Contrast with column identifier.
COM (Component Object Model): A specification that defines the binary-level compatibility and
interoperability of components.
comment: A non-executing line in an application that has an exclamation mark at the beginning of the line.
Comments document what the application is doing.
component: A distinct unit of code that delivers a well-specified set of services. An ActiveX component is a
runtime instance of code, memory, resources, and executing state, either as a process or a DLL, that uses or
provides ActiveX interfaces.
constant: An unchanging, named value. Contrast with variable.
contents: The objects in form windows, table windows, dialog boxes, MDI windows, and toolbars.
context: State that is implicitly associated with a given MTS object. Context contains information about the
object's execution environment, such as the identity of the object's creator and, optionally, the transaction
encompassing the work of the object. The MTS run-time environment manages a context for each object.
context row: The row whose column values are referenced when used as variables. This is usually the row
with the focus.
control: An object that has its own set of recognized properties and events. Controls can receive user input,
display output, and trigger event procedures. You can manipulate most controls using methods. Some
controls are interactive (responsive to user actions), while others are static (accessible only through code).
cookies: A means by which, under the HTTP protocol, a server or a script can maintain state or status
information on the client computer. A cookie can include information such as the way a Web page is
customized or how a visitor shopped on a Web site, or it can be used to track repeat visits.
creator: In MTS, a client that creates an object provided by a component (using CreateObject,
CoCreateInstance, or CreateInstance). When a client creates an object, it is given an object reference that can
be used to call the methods of that object.
CSS (Cascading Style Sheets): Formatting descriptions that provide control over presentation and layout of
HTML and XML elements.
cursor: A work space in memory that is used for processing a SQL command. This work space contains the
return code, number of rows, error position, number of select list items, number of program variables,
rollback flag, and the command result. A cursor is part of a Sql Handle. Cursor is also a name for a mouse
pointer.
596
data binding: Associating an object in an application to a data source.
data type: A characteristic of a variable or constant that determines the type of data it holds and how you
manipulate it.
database: A collection of interrelated or independent pieces of information stored together without
unnecessary redundancy. Client applications can read and write a database.
database server: A DBMS that a user interacts with through a client application on the same or a different
computer. Also called backend or engine.
DBMS (database management system): A software system that manages the creation, organization, and
modification of a database and access to data stored within it. A DBMS provides centralized control, data
independence, and complex physical structures for efficient access, integrity, recovery, concurrency, and
security.
DCOM (Distributed COM): DCOM is an object protocol that enables ActiveX components to communicate
directly with each other across a network. DCOM is language neutral, so any language that produces ActiveX
components can also produce DCOM applications.
derived class: A class defined from an existing class (its base class). A derived class inherits its base class' data
structure and behavior and it can change (override) the inherited data structure and behavior. It can also add
its own data structure and behavior. All of the derived class' data structure and behavior-changed, new, and
inherited-is inherited by its own derived classes. Also called descendant, subclass, and child class. Contrast
with base class. See also inheritance and OOP.
design window: A form window, table window, or dialog box at design time. You use the Window Editor to
add child objects to a design window.
design time: An environment in which you can create and change an application. Contrast with runtime.
DHTML (Dynamic HTML): A technology that enables interactive HTML documents that do not rely on server-
side programs or complicated sets of HTML pages to achieve special effects. DHTML achieves these effects by
reformatting and redisplaying the changes on the user's computer, instead of reloading a document or
loading a new document. This frees the user from having to wait for text and data to make a round-trip to
and from the server. DHTML is made up of HTML 4.0, data binding, the Document Object Model (DOM), and
Cascading Style Sheets (CSS).
dialog box: A single-function window that displays data and messages and accepts input. See also modal
dialog box, modeless dialog box, and system modal dialog box.
diamond: The symbol that represents the beginning of an item in the outline.
DIB (Device-Independent Bitmap): Windows SDK functions that define and manipulate color bitmaps so that
they can be displayed appropriately on a device with a given resolution, regardless of the method used by the
device to represent color in memory.
disabled: A menu item or menu that cannot be chosen; the menu item or menu title appears dimmed or gray.
DLL (Dynamic Link Library): A program library written in C or assembler that contains related functions of
compiled code. The functions in a DLL are not read until runtime (dynamic linking).
DNA (Distributed interNet Applications): A Microsoft framework for building three-tier, component-based
applications that can be delivered over a network.
DOM (Document Object Model): The standard maintained by the W3C (World Wide Web Consortium) that
specifies how the content, structure, and appearance of Web documents can be updated programmatically
with scripts or other programs. The object model for XML matches the Document Object Model for HTML so
that script writers can easily learn XML programming. The XML DOM provides a simple means of reading and
writing data to and from an XML tree structure.
597
domain: In Windows NT, a group of computers and servers that share a common Security Accounts Manager
(SAM) database and allow a user to log on to any resource in the domain with a single user ID and password.
Contrast with workgroup.
early binding: Associating a symbol with an object at compile-time. Also called static binding. Contrast with
late binding. See also bind
elevator box: See scroll box.
embedding: To insert an object completely within an ActiveX client application. An embedded object contains
a presentation format (bitmap or MetaFile), a data structure that identifies the server, and the native data
provided by the server. A user can edit an embedded object directly in the client application. Editing an
embedded object starts the server and sends the native data back to that server. Gupta SQLWindows stores
an embedded object as a blob of raw bytes in the application outline.
encapsulation: Has two related meanings:
• Combining data and procedures together in a class or object
• Making the behavior of a class or object visible while hiding the details of its implementation
Encapsulation lets a class or object provide a service in any way, without requiring cooperation or knowledge
by other program elements. This object- oriented programming characteristic makes applications easier to
maintain and extend. Also called data hiding or information hiding. See also class and OOP.
engine: See database server.
event: An asynchronous notification from an object that something has happened.
event-driven program: A program that responds to user input by repeatedly checking for events. An event-
driven program does nothing until it detects an event such as a mouse click. Program actions are based on
events caused by the user, rather than a fixed script.
exception: An error condition that prevents the normal flow of instructions.
expand: Displaying lower outline levels.
expression: An item or a combination of items and operators that yield a single value. An example is an
arithmetic expression with operators such as + or - that yields the result of performing the operation.
external function: A function in a DLL that you call from a SQLWindows application.
external reference: A reference to a variable, an object, or a function in an application window (top-level
window or MDI window) other than the current application window.
extranet: A Web server that handles confidential intranet content and communications that are available on
the public Internet to, for example, business partners and customers.
fetch: To retrieve one or more rows of data from a database.
File Handle: A data type that identifies an open file.
firewall: A system that prevents unauthorized access to or from a private network. Firewalls can be
implemented in both hardware and software, or a combination of both. All messages entering or leaving the
network pass through the firewall, which examines each message and blocks those that do not meet
specified security criteria.
flag: A variable whose value indicates a condition.
focus: See input focus.
focus frame: A movable, dark border that highlights a row where the insertion bar is positioned.
form window: A top-level window used for data entry and display.
598
format: The appearance of data. Currency, percentage, decimal, date, time, invisible, numbers, and
unformatted are examples.
frontend: See client.
FTP (File Transfer Protocol): You use FTP to connect to a computer on the Internet using an FTP program on
your local computer, browse through files available on that computer, and then download or upload files.
function: A routine that performs a task that needs to be done several times but at different places in an
application. SQLWindows has 5 types of functions: built-in system functions, internal functions, window
functions, external functions, and class functions.
GDI (Graphics Device Interface): Windows SDK functions that perform device- independent graphics
operations such as creating lines, text, and bitmaps on different output devices.
GIF (Graphics Interchange Format): A Compuserve graphics format used to transfer graphics between
different applications and different types of computers. GIF stores images in a bitmap (raster) format.
global: A variable, function, or object known in all parts of an application. Constants are always global. See
also local and scope.
global declarations: A section in the outline that contains elements that are recognized in all parts of the
application.
grid: A pattern used to align objects in a design window.
group separator: Separates two contiguous sets of radio buttons.
GUI (Graphical User Interface): A graphics-based user interface with windows, icons, pull-down menus, a
pointer, and a mouse. Microsoft Windows is an example of graphical user interfaces.
GUID (Globally Unique IDentifier): A 128-bit number that is generated automatically and used to refer to a
resource, component, directory entry, or other type of entity. Guaranteed to be unique. Pronounced either
“guid” (rhymes with squid) or “goo-id”.
handle: A number that identifies a window, a database connection, or an open file. An application gets a
handle by calling a Sal* or Sql* function. The application then uses the handle in other functions to refer to
the window, database connection, or file. An application does not know the actual value of the handle.
hierarchy: The relationship between classes. See also base class, derived class, inheritance, and OOP.
HTML (Hypertext Markup Language): A system of marking up, or tagging, a document so it can be published
on the World-Wide Web. Using a generic markup language allows a single text file to be displayed on multiple
computer platforms by many types of display software, or browsers. You incorporate HTML in a document to
define the function (as distinct from the appearance) of different text elements. The appearance of these text
elements is not defined at the authoring stage; a browser decides how to display the text elements. An HTML
document can contain hypermedia such as pictures, graphics, sounds, and animation.
HTTP (Hypertext Transport Protocol): A set of messages and replies a client and server use to communicate
during a hypertext link.
hWndForm: A variable that contains the handle of the parent.
hWndItem: A variable that contains the handle of a child object.
hypertext: Text containing links that, when clicked by a user, jumps to a different place, either in the same
document or in another.
icon: An image that represents an application or window.
in-place activation: Activating an object provided by an ActiveX server. By double- clicking the object, a user
can interact with the application supplying the object without switching to a different application or window.
599
The menus and toolbars of the server application merge with those of the application that contains the
object. Also called visual editing.
in-process server: An ActiveX server that runs in a client application's process space, usually as a DLL.
inheritance: Arranging classes in a hierarchy so that classes can share the data and behavior of other classes
without duplicating the code. A derived class automatically includes the data and behavior of one or more
base classes. Derived classes can add their own data and behavior and can redefine inherited data and
behavior. A derived class can inherit from one base class (single inheritance) or more than one base class
(multiple inheritance). See also base class, class, derived class, and OOP.
input focus: The area in a window that receives keystrokes or mouse actions. Also called focus.
insertable object: An ActiveX object created by its server through the OLE Documents interface. Insertable
objects are marked in the registry and appear in the Insert Object dialog.
insertion point: Where the next characters that the user types appear.
instance variable: A variable that contains data that is private to a specific object in a class. Also called field,
member, and slot. Contrast with class variable.
instantiation: See object.
interface: The external view of an object that hides the code that implements its behavior. In COM, group of
semantically related functions that provide access to a COM object.
internal function: A global function that you write.
Internet: When capitalized, the world-wide system for linking smaller computer networks together. Networks
connected through the Internet use a set of communications standards called TCP/IP to communicate. The
Internet provides file transfer, remote login electronic mail, news, World-Wide Web, and other services.
When not capitalized, any collection of distinct networks working as one.
intranet: A private network that uses TCP/IP-based networking for host access, workgroup collaboration,
desktop and network resource management, and custom applications to maximize the enterprise's
productivity.
ISP (Internet Service Provider): A commercial service with an Internet gateway that provides access to the
Internet for organizations and individuals.
Java: An object-oriented language that can be used to create machine-independent applications and applets.
JavaScript: A scripting language that was jointly created by NetScape and Sun. JavaScript programs are not
compiled like Java applets. JavaScript programs are embedded in the HTML markup of a page. After the page
is loaded, the browser interprets the JavaScript program and runs it.
just-in-time activation: The ability for an MTS object to be activated only as needed for executing requests
from its client. Objects can be deactivated even while clients hold references to them, allowing otherwise idle
server resources to be used more productively. Also refers to MTS’ ability to deactivate an object after a
period of inactivity.
late binding: Associating a symbol with an object at runtime. Also called dynamic binding. Contrast with early
binding. See also binding.
library: A collection of SQLWindows objects such as form windows, dialog boxes, or class definitions that are
shared by more than one application.
link: In programming, to connect programs compiled or assembled at separate times so they can be executed
together.

600
local: A variable, function, or object that is known only in a single part of an application. See also global and
scope.
locale: A text string such as “English (United States)” that identifies a language and locality to allow programs
to use language-specific formatting and processes. Can also be identified by a number called the localeID.
logical operator: See boolean operator.
LONG VARCHAR: In SQL, a column data type where the value can be longer than 254 bytes. Also called LONG.
loop: Code that is executed repeatedly until a limit or condition is met.
lParam: A parameter used with messages. The “l” stands for long, which is its length (32 bits or two words).
marshalling: Packing and sending method parameters across thread or process boundaries.
MDI (Multiple Document Interface): A user interface model created by Microsoft.
menu: A list of choices from which you can select an action. A menu appears when you click the menu title in
the menu bar.
menu item: A choice in a menu or menu bar.
message: The way that objects interact with each other. An object (the sender) sends a message to another
object (the receiver) to make a request or notify it of something. The receiver can ignore it or take some
action. Messages make it easy to reuse code. The internals of an object can change while the messages
remain the same. Code changes are then highly localized.
message actions: A section in the outline where you code actions that are responses to messages.
MetaFile: Windows GDI commands that create text or images. MetaFiles are a convenient way to store
graphics commands.
method: A request to an object to perform an action.
mnemonic: A keyboard sequence that moves the input focus to an object, menu, or menu item. Contrast
with accelerator.
modal dialog box: A dialog box that suspends the application until the user closes the dialog box.
modeless dialog box: A dialog box that does not stop processing within other windows.
mouse pointer: A graphic symbol that shows the location of the mouse on the screen. The mouse pointer is
usually an arrow, but can change to other shapes during some tasks. Also called cursor.
MTS (Microsoft Transaction Server): A windows NT service that acts as both an object broker for components
and as a distributed transaction manager.
MTS object, MTX server: A COM object that executes in the MTS run-time environment and follows the MTS
programming and deployment model.
multiuser: The ability of a database server to provide its services to more than one user at a time.
null: A value that means the absence of data. Null is not considered equivalent to zero or to blank. The value
of null is not considered to be greater than, less than, or equivalent to another value, including a null value.
object: A window object is a visual element on the screen such as a table window, push button, or menu. An
OOP object is a representation of a software entity such as a user-defined window or a user-defined variable
(UDV). An object has the data structure and behavior specified by its class (which is its blueprint). Also called
instance, occurrence, or instantiation. See also class, encapsulation, and OOP.
object-oriented programming (OOP): Programming that uses objects that combine data and behavior.
Objects use the data structure and behavior of their class. See also class, encapsulation, inheritance, object,
and polymorphism.
601
ODBC (Open DataBase Connectivity): An open standard originally developed by Microsoft to allow
transparent data access to all kinds of data stored such as relational databases. Third parties create drivers to
suit their own data store.
OLE DB: A standard data access programming interface from Microsoft designed to replace ODBC, and
provide wider coverage of different types of data stores.
OLE Documents: The part of ActiveX that deals with embedding, linking, and editing objects.
operator: A symbol or word that represents an operation to be performed on the values on either side of it.
Examples of operators are: arithmetic (+, -, *, /), relation (=.!=, >, <, >=, <=), and logical (AND, OR, NOT).
outline: The statements that define the objects and procedural logic in an application.
outline items: Each line of text in an outline.
parameter: A value for a function that defines the data or controls how the function executes. Also called
argument or operand.
polymorphism: The ability for different objects to respond to the same request in different ways. For
example, both a push button and a scroll bar can respond to a paint message, but the actions they take are
different. The sender does not need to know the type of object that is responding to the message. Also called
overloading. See also OOP.
pooling: A performance optimization based on using collection of pre-allocated resources, such as objects or
database connections. Pooling results in more efficient resource allocation.
populate: To fill a table window with data from a source such as a database, array, or file.
popup menu: See menu.
precedence: The default order in which operations are performed in an expression.
profile: A set of format specifications.
property: Data that defines the state of a component.
proxy: An interface that provides parameter marshalling and communication for a client to call an object
running in a different execution environment, such as on a different thread or in another process. The proxy is
located with the client and communicates with a corresponding stub that is located with the object that is
being called.
Also, an internet server that runs on a firewall computer that controls client computers’ access to the
Internet. Using a proxy server, a company can stop employees from accessing certain Web addresses,
improve performance by storing Web pages locally, and hide the internal network’s identity so that it is
difficult for external users to monitor.
query: A request for information from a database, optionally based on specific conditions. For example, a
request to list all customers whose balance is greater than $1000. You give queries with the SQL SELECT
command.
receive data types: A data type that passes data to a function by reference so the function can change it.
Report Builder: An application that lets you design, display, and print reports.
result set: A set of rows retrieved from one or more tables or views during a query.
row: In a table window, a complete horizontal line of cells in a table window. In a database, a set of related
columns that describe a specific entity. For example, a row could contain a name, address, telephone number.
Sometimes called record or tuple. See also table and column.
RPC (Remote Procedure Call): A standard that allows one process to make calls to functions that are executed
in another process. The process can be on the same computer or on a different computer in the network.
602
RTF (Rich Text Format): A Microsoft format that uses ASCII characters to encode layout and format settings.
For example, \ul1 is the code for underline. You use RTF to transfer a file from one application to another. You
can specify RTF output when you call the SalReportPrintToFile function.
run mode: A design time mode in SQLWindows when you run and test an application. Also called user mode.
runtime: The time during which a user executes a program.
safe reference: A reference to the current object that is safe to pass outside the current object's context.
SAL (SQLWindows Application Language): A procedural language for writing actions that execute at runtime.
SAM (SQLWindows Application Messages): A message that SQLWindows sends to an application or its
objects when an event occurs.
scope: The part of an outline where the name of a variable, function, or object is known. See also local and
global.
section: In an application outline, a group of contiguous statements; a parent item and all its children.
serialization: In apartment-model threading, the process of queuing a property or method request until the
threads that own the apartment of the current object finishes the method it is executing.
server: A computer on a network that provides services to client applications. See also: client and database
server. The term server is also used to refer to applications in DDE and Report Builder. In ActiveX,
local/remote server runs in a separate process space from a client application, as an *.EXE.
SGML (Standard Generalized Markup Language): An international standard for defining descriptions of
structure and content of electronic documents. XML is a subset of SGML designed to deliver SGML-type
information over the Web.
shared property: A variable that is available to all objects in the same server process via the Shared Property
Manager. The value of the property can be any type that can be represented by a variant.
siblings: Child items with the same parent.
single-user: A database server that can only provide its services to one user at a time.
sizing pointer: A pointer you use to change the size of an object.
SQL (Structured Query Language): A standard set of commands used to manage information stored in a
database. These commands let users retrieve, add, update, or delete data. There are four types of SQL
commands: Data Definition Language (DDL), Data Manipulation Language (DML), Data Query Language (DQL),
and Data Control Language (DCL). Pronounced ess-que-ell or sequel.
Sql Handle: A data type that identifies a connection to a database. See also cursor.
SQL/API: Gupta Technologies LLC's API that lets a programmer develop a database application in the C
programming language. The SQL/API has functions that a programmer calls to access a database using SQL
commands.
SQLBase: A relational DBMS that lets users access, create, update, and delete data.
SQLWindows: A graphical SQL application development system for Microsoft Windows and Motif.
stateless object: An MTS object can maintain internal state across multiple interactions with a client. Such an
object is said to be stateful. An MTS object can also be stateless, which means the object does not hold any
intermediate state while waiting for the next call from a client.
statement: A unit in the application outline that specifies an action for the computer to perform.
static variable: A variable defined in a function that retains its value in between calls to the function.
string: A sequence of characters treated as a unit.
603
stub: An interface that provides parameter marshalling and communication for an object to receive calls from
a client that is running in a different execution environment, such as on a different thread or in another
process. The stub is located with the object and communicates with a corresponding proxy that is located
with the client that calls it.
system function: A built-in SQLWindows function that performs an often-needed task.
system modal dialog box: A dialog box that suspends all Window applications until the user closes the dialog
box.
table: The basic data storage structure in a relational database. A table is a two- dimensional arrangement of
columns and rows. Each row contains a like set of data items (columns). Also called relation.
table window: An object that displays data in a tabular format (columns and rows). A table window can be a
top-level or child window.
TCP/IP (Transmission Control Protocol/Internet Protocol): Two main standards in the Internet suite of
protocols. This protocol suite provides the standards, specifies the details of how computers communicate,
and provides a set of conventions for interconnecting networks and for routing traffic over the Internet.
thread: A path of execution through a program and the smallest unit of execution that Win32 schedules and
allocates CPU time. A thread consists of a stack, the state of the CPU registers, and an entry in the execution
list of the system scheduler. Each thread shares all of the process’s resources.
thread local storage (TLS): A Win32 mechanism that allows multiple threads of a process to store data that is
unique for each thread.
thumb: See scroll box.
TIFF (Tag Image File Format): A graphics format (developed by Aldus and Microsoft) used to transfer graphics
between different applications and different types of computers. TIFF stores images in a bitmap (raster)
format.
top-level window: A form window, table window (that is not a child), or dialog box.
type information: Standard descriptions of properties, methods, and events that an object supports as well
as return types, parameter names, and parameter types.
URL (Uniform Resource Locator): The address of a document on the World Wide Web. A URL has three parts:
the protocol, the host name, and the path name to the documents.
value: Data assigned to a constant or a variable.
variable: A named item that can be any of a given set of values. Contrast with constant.
visual editing: See in-place activation.
W3C (World Wide Web Consortium): The international consortium founded in 1994 to develop standards for
the Web.
window: A rectangular area on the screen where an application receives input from the mouse or keyboard
and displays output. A user can open, close, an move windows and can resize most windows. Several
windows can be open at the same time.
Window Editor: SQLWindows' drawing functions. You use the Window Editor to add child objects to a design
window.
window function: A function that you write in a top-level window (form window, dialog box, or table
window) or in a MDI window. The scope of a window function is in actions in the window.
Window Grabber: A mouse pointer that selects and moves an object.
Window Handle: A data type that identifies a single instance of a particular window.
604
workgroup: In Windows, an informal group of computers that share resources with each other. User
authentication occurs on each computer in the workgroup. Other computers in the workgroup trust that each
computer has performed this authentication. Contrast with domain.
World-Wide Web (WWW): A group of Internet servers that share a set of protocols such as HTTP and
conventions such as HTML. Using Web browsing software, you can activate hyperlinks in Web documents and
jump from one location to another in any order you choose. You can also open documents on Web servers
that contain many types of information--not just text but sound, animation, and video.
wParam: A parameter used with messages. The “w” stands for word (16 bits), which is its length.
XML (Extensible Markup Language): A subset of SGML that provides a uniform method for describing and
exchanging structured data in an open, text-based format, and delivers this data using the standard HTTP
protocol.

605

You might also like