Developing With SQLWindows32
Developing With SQLWindows32
SQLWindows/32
20-6201-0001
Trademarks
Centura, Centura Ranger, the Centura logo, Gupta, the Gupta logo, Gupta Centura, ,
the Centura logo, Centura net.db, Gupta, the Gupta logo, Gupta Powered, the Gupta
Powered logo, Fast Facts, Object Nationalizer, Quest, QuickObjects, SQL/API,
SQLBase, SQLBase Exchange, SQLConsole, SQLGateway, SQLHost, SQLNetwork,
SQLRouter, SQLTalk, and Team Object Manager are trademarks of Centura Software
Corporation and may be registered in the United States of America and/or other
countries. SQLWindows is a registered trademark and TeamWindows,
ReportWindows and EditWindows are trademarks exclusively used and licensed by
Centura Software Corporation.
Microsoft, Win32, Windows, Windows NT and Visual Basic are either registered
trademarks or trademarks of Microsoft Corporation in the United States of America
and/or other countries.
Java is a trademark of Sun Microsystems Inc.
All other product or service names mentioned herein are trademarks or registered
trademarks of their respective owners.
Copyright
Copyright 1998 by Centura Software Corporation. All rights reserved.
SQLWindows/32 1.5
Developing with SQLWindows/32
20-6201-0001
May 1998
Author: Bruce Ring
Contents
Title: Developing with SQLWindows/32
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv
Purpose and audience of this manual. . . . . . . . . . . . . xvi
Scope of this manual. . . . . . . . . . . . . . . . . . . . . . . . . . xvi
What you need to know. . . . . . . . . . . . . . . . . . . . . . . . xvi
Summary of chapters . . . . . . . . . . . . . . . . . . . . . . . . . xvi
Notation conventions. . . . . . . . . . . . . . . . . . . . . . . . . xviii
2 SQLWindows/32 Desktop . . . . . . . . . . . . . 2 - 1
SQLWindows/32 user interface. . . . . . . . . . . . . . . . . 2 - 2
Toolbars . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 4
Docking and customizing toolbars and palettes . . . . 2 - 5
Tab views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 6
Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 11
Right mouse button features . . . . . . . . . . . . . . . . . . 2 - 11
Editing object attributes . . . . . . . . . . . . . . . . . . . . . . 2 - 14
Attribute Inspector . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 16
Customizer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 18
Coding Assistant . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 19
Controls palette . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 21
Centura SQLWindows/32 menus . . . . . . . . . . . . . . 2 - 23
Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 24
Keyboard shortcuts . . . . . . . . . . . . . . . . . . . . . . . . . 2 - 25
SQLWindows/32 command line arguments . . . . . . 2 - 30
6 Application Menus . . . . . . . . . . . . . . . . . . . . . 6 - 1
About menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 2
Popup menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 2
Menu items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 3
Menu separator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 5
Cascading menus . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 6
Menu row . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 6
Menu column. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 7
Named menus. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 7
Menu status text . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 9
Windows menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 10
Menu Editor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 10
9 Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - 1
About messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - 2
Types of messages . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - 2
Message names and numbers . . . . . . . . . . . . . . . . . 9 - 2
About SAM_* messages . . . . . . . . . . . . . . . . . . . . . . 9 - 2
Application-defined messages . . . . . . . . . . . . . . . . . 9 - 3
Microsoft Windows messages. . . . . . . . . . . . . . . . . . 9 - 4
Processing messages . . . . . . . . . . . . . . . . . . . . . . . . 9 - 4
System variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - 5
SAM reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - 6
SAM_* summary . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 - 45
10 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 1
Run mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 2
Animation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 2
Breakpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 2
Debug toolbar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 4
Debugging DLLs . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 9
Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 - 9
Writing your own debugging code. . . . . . . . . . . . . . 10 - 9
12 SQL Programming . . . . . . . . . . . . . . . . . . . 12 - 1
Using SQL in a SQLWindows/32 application . . . . . 12 - 2
What you need to know. . . . . . . . . . . . . . . . . . . . . . 12 - 2
Database access cycle . . . . . . . . . . . . . . . . . . . . . . 12 - 3
Multistep interface . . . . . . . . . . . . . . . . . . . . . . . . . . 12 - 3
Single-step interface . . . . . . . . . . . . . . . . . . . . . . . 12 - 15
Long Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 - 17
SQL error handling . . . . . . . . . . . . . . . . . . . . . . . . 12 - 18
Using both SQL error handling methods. . . . . . . . 12 - 19
13 Report Programming . . . . . . . . . . . . . . . . . 13 - 1
What you need to know. . . . . . . . . . . . . . . . . . . . . . 13 - 2
About Report Builder. . . . . . . . . . . . . . . . . . . . . . . . 13 - 2
Designtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 3
Runtime. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 5
SalReportPrint. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 7
SalReportPrintToFile. . . . . . . . . . . . . . . . . . . . . . . 13 - 12
SalReportView . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 12
SalReportReset. . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 15
SalReportClose . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 17
SalReportCreate (creating a report template) . . . . 13 - 17
Input variables. . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 - 17
SAM_ReportNotify . . . . . . . . . . . . . . . . . . . . . . . . 13 - 18
Creating reports from table windows. . . . . . . . . . . 13 - 20
14 Table Windows . . . . . . . . . . . . . . . . . . . . . . . 14 - 1
About table windows . . . . . . . . . . . . . . . . . . . . . . . . 14 - 2
Types of table windows. . . . . . . . . . . . . . . . . . . . . . 14 - 2
Top-level table windows . . . . . . . . . . . . . . . . . . . . . 14 - 3
Child table windows . . . . . . . . . . . . . . . . . . . . . . . . 14 - 4
Table window columns . . . . . . . . . . . . . . . . . . . . . . 14 - 6
User interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 9
Programming techniques . . . . . . . . . . . . . . . . . . . 14 - 12
Context row . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 24
Populating a table window . . . . . . . . . . . . . . . . . . 14 - 25
Table range . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 31
Table window flags . . . . . . . . . . . . . . . . . . . . . . . . 14 - 35
Row flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 36
Column flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 37
TBL_Error constant . . . . . . . . . . . . . . . . . . . . . . . . 14 - 38
TBL_* constants . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 38
Table window messages. . . . . . . . . . . . . . . . . . . . 14 - 38
Setting the focus row. . . . . . . . . . . . . . . . . . . . . . . 14 - 41
Focus cell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 42
Deselecting all rows . . . . . . . . . . . . . . . . . . . . . . . 14 - 42
Finding the visible range . . . . . . . . . . . . . . . . . . . . 14 - 42
Scroll position . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 42
Table window title . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 42
Table window font . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 43
Table window color . . . . . . . . . . . . . . . . . . . . . . . . 14 - 43
Column title . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 43
Column width . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 43
Column identifier and column position . . . . . . . . . 14 - 43
Locking columns . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 45
Row header. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 45
Split windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 - 47
Using the Clipboard with table windows . . . . . . . . 14 - 48
Using database result sets with table windows. . . 14 - 49
Dynamic table windows. . . . . . . . . . . . . . . . . . . . . 14 - 49
Sum, average, and sort functions . . . . . . . . . . . . . 14 - 51
Checking and setting a cell's field edit flag . . . . . . 14 - 51
Processing WM_* cell editing messages . . . . . . . 14 - 52
16 MDI Windows . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 1
About MDI windows . . . . . . . . . . . . . . . . . . . . . . . . 16 - 2
Outline items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 4
MDI Window Handles . . . . . . . . . . . . . . . . . . . . . . . 16 - 4
Multiple MDI windows . . . . . . . . . . . . . . . . . . . . . . . 16 - 4
Creating an MDI window at runtime . . . . . . . . . . . . 16 - 5
Creating MDI child objects at runtime . . . . . . . . . . . 16 - 5
SAM_Destroy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 5
Functions for MDI windows . . . . . . . . . . . . . . . . . . . 16 - 5
Windows menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 - 6
17 Pictures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 - 1
About pictures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 - 2
Picture attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 - 2
Paste From . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 - 5
Sources of pictures at designtime . . . . . . . . . . . . . . 17 - 6
Using 256-color bitmaps . . . . . . . . . . . . . . . . . . . . . 17 - 7
Picture messages . . . . . . . . . . . . . . . . . . . . . . . . . . 17 - 7
Picture functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 - 8
Sources and destinations for pictures at runtime . 17 - 11
Storing pictures in a database. . . . . . . . . . . . . . . . 17 - 12
Other SAL picture functions . . . . . . . . . . . . . . . . . 17 - 13
18 Drag-and-Drop. . . . . . . . . . . . . . . . . . . . . . . . 18 - 1
About drag-and-drop . . . . . . . . . . . . . . . . . . . . . . . . 18 - 2
Source and target windows. . . . . . . . . . . . . . . . . . . 18 - 2
Drag-mode events. . . . . . . . . . . . . . . . . . . . . . . . . . 18 - 3
Auto dragging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 - 3
Application-initiated dragging . . . . . . . . . . . . . . . . . 18 - 3
Enabling and disabling dropping . . . . . . . . . . . . . . . 18 - 3
Application-defined cursors. . . . . . . . . . . . . . . . . . . 18 - 4
Functions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 - 4
Source window messages . . . . . . . . . . . . . . . . . . . 18 - 5
Target window messages . . . . . . . . . . . . . . . . . . . . 18 - 6
Auto-dragging example . . . . . . . . . . . . . . . . . . . . . . 18 - 7
Application-initiated dragging example . . . . . . . . . . 18 - 8
Dropping from Explorer or File Manager. . . . . . . . . 18 - 9
19 Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 - 1
Include libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 - 2
Dynamically linked libraries (dynalibs) . . . . . . . . . . 19 - 6
20 ActiveX programming . . . . . . . . . . . . . . . . 20 - 1
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 2
Creating an ActiveX component . . . . . . . . . . . . . . . 20 - 3
ActiveX controls . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 5
ActiveX container controls. . . . . . . . . . . . . . . . . . . . 20 - 6
ActiveX container control SAL API functions . . . . . 20 - 8
In-place activation . . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 9
ActiveX automation . . . . . . . . . . . . . . . . . . . . . . . . 20 - 10
ActiveX Wizard . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 11
ActiveX include libraries . . . . . . . . . . . . . . . . . . . . 20 - 14
ActiveX exception handling . . . . . . . . . . . . . . . . . . 20 - 14
Object class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 15
Variant class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 18
SafeArray class . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 - 19
23 Custom Controls . . . . . . . . . . . . . . . . . . . . . . 23 - 1
About custom controls. . . . . . . . . . . . . . . . . . . . . . . 23 - 2
Adding a custom control to a window . . . . . . . . . . . 23 - 2
Message actions . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 - 3
Using classes and libraries . . . . . . . . . . . . . . . . . . . 23 - 4
Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 - 5
Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 - 6
Writing a SQLWindows/32-aware custom control. 23 - 11
Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 - 18
Preface
This Preface explains:
• Purpose and audience of this manual
• What the reader of this manual needs to know
• Organization of this manual
• Conventions used in this manual
• Other helpful resources
• How to send us your comments
Summary of chapters
This manual is organized in the chapters in the table below.
1 About SQLWindows/32 Designtime environment and runtime environment; objects, messages,
and events
2 SQLWindows/32 Main window, Controls palette, Attribute Inspector, Coding Assistant,
Desktop application outline
3 Deploying and Migrating Installing production applications, SQLWindows/32 runtime, migrating
Applications to 32-bit
4 SQLWindows/32 Menus Menu items in the main window
5 SQLWindows/32 Objects Objects that you can add to an application and their Customizer
properties
6 Application Menus Popup menus, menu items, named menus, creating menus dynamically,
menu status text
7 SAL (Scalable Data types, variables, arrays, constants, operators, expressions,
Application Language) statements, functions
Notation conventions
The table below show the notation conventions that this manual uses.
Notation Explanation
bold type Menu items, push buttons, and field names. Things that you select.
Keyboard keys that you press.
REPBI*.EXE Program names where the asterisk respresents the version number. For
example, the program name for Report Builder 1.5 is REPBI15.EXE.
Precaution Warning:
Vital
information Important:
Supplemental
information Note:
Alt+1 A plus sign between key names means to press and hold down the first
key while you press the second key
Chapter 1
About SQLWindows/32
This chapter introduces SQLWindows/32, including:
• Designtime environment
• Runtime environment
• Objects, messages, and events
What is Centura
Centura is a set of products for building and deploying robust, scalable, Internet-
enabled client/server applications. Centura lets you:
Scale up. Create scalable applications without sacrificing ease or team productivity.
Reach out. Move beyond the limits of traditional corporate networks to embrace
the Internet.
Connect it all. Unite disparate databases and integrate mobile users in your
decentralized enterprise.
SQLWindows/32 is a part of Centura.
What is SQLWindows/32?
SQLWindows/32 is an application development system that developers
(programmers) use to applications which run on Microsoft Windows.
An application that you create in SQLWindows/32 has scroll bars, menus, and dialog
boxes, and other objects associated with a graphical user interface (GUI).
To write a SQLWindows/32 application, you draw screen objects in a design window.
As you draw, SQLWindows/32 generates predefined code definitions. You define
behaviors in the outline with SAL (SQLWindows Application Language) and SAM
(SQLWindows Application Messages).
SQLWindows/32 environments
SQLWindows/32 has two environments:
• Designtime
• Runtime
Designtime environment
At designtime, you first create the user interface. SQLWindows/32 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/32 Runtime product on the users’ computer.
Chapter 2
SQLWindows/32 Desktop
This chapter explains the SQLWindows/32 user interface, including:
• Outline
• Coding Assistant
• Right mouse button menus
• Toolbars
• Controls palette
• Attribute Inspector
• Debugger
Tree view
Tab view
Status bar
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
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 Centura SQLWindows/32 application, you can add screen objects in a
Layout tab or in a preview window. Centura SQLWindows/32 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
Centura SQLWindows/32’s 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 views
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, read
Tab views on page 2-6.
Status bar
SQLWindows/32 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/32 has toolbars that let you quickly select often-used menu commands.
You control which toolbars are displayed by selecting Tools, Toolbars. For more,
read Toolbars on page 4-31. Also, you can right-click a blank area of a toolbar and
select a toolbar from the context menu.
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 toolbar
You can add buttons that launch programs to the toolbar named Tools. An item also
appears in the Tools menu for each button you add. You can pass command line
arguments to the programs that you launch. For more, read Tools on page 4-29.
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 tabs that are provided for each
view are listed below:
Actions
Base classes
Class variables
Components
Constants
Description
Layout
Libraries
Outline
Parameters
Returns
Static variables
Variables
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.
Actions tab
The Actions tab displays all statements in a function or message actions section. You
can code any SAL statements in this section.
Outline tab
Centura SQLWindows/32 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 which 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. For more, read Component
menu on page 4-15.
Collapsed Item Expanded Item
Application Description. This is the top-most item in the outline where you enter
a description of the application.
Libraries. You specify include libraries in this section. For more, read Chapter 19,
Libraries.
Name Description
Window The default font, color, display style, font, text color, and background color
Defaults 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. For more, read Chapter 11,
Formatting and Validating.
External DLLs (Dynamic Link Libraries) that contain functions that the application
Functions calls. For more, read Chapter 22, Calling External Functions in DLLs.
Constants Global system constants (such as WM_* Messages) and global user
constants. For more, read Chapter 7, SAL (SQLWindows/32 Application
Language).
Resources The names of bitmap, cursor, and icon resource files that you use in the
application. For more, read Chapter 7, SAL (SQLWindows/32 Application
Language).
Internal Global functions that you write. For more, read Chapter 7, SAL
Functions (SQLWindows/32 Application Language).
Named Popup menus that windows in the application share. For more, read
Menus Chapter 6, Application Menus.
Application Statements to perform when the application receives messages. For more,
Actions read Chapter 9, Messages.
Layout tab
When you select the Layout tab, Centura SQLWindows/32 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. For more, read Preview Window on page 4-17.
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
Constants tab
The Constants tab displays constants declarations in the Global Declarations block of
the outline.
Libraries tab
The Libraries tab displays files and dynalibs which are in the outline. An include
library is a collection of Centura SQLWindows/32 objects such as form windows,
dialog boxes, or class definitions that are shared by more than one application. A
dynalib is a compiled Centura SQLWindows/32 module with functions and objects
that other applications can dynamically load at runtime.
For more, read Chapter 19, Libraries.
Variables tab
The Variables tab displays the Variables block of the application or the selected top-
level window, class, class function, or internal function.
Parameters tab
The Parameters tab displays the outline for a Parameters block which belongs to
several item types in the application such as functions, top-level windows, and some
message actions sections.
Description tab
In a Description tab you can enter text that describes the purpose of the selected item.
Returns tab
The Returns tab displays the return value for functions.
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.
Note: 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 that 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.
Other examples of when you can use New are shown in this table:
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. For more, read
Edit, Properties.
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.
Outline tab (no item selected) Undo, Cut, Copy, Paste, Select All
Objects in Layout and Preview windows Align Left, Align Top, Align to Grid
You can also create custom templates so that each new application you create
conforms to the default colors and fonts you choose. For more, read New … on page
4-2.
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 these 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
Note: 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.
Note: The Attribute Inspector can only display attributes for one object at a time.
The Attribute Inspector is a dockable palette. For more, read Docking and undocking
toolbars and palettes on page 2-5.
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
Setting properties
To set properties for an object:
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. Note that you can undo your changes as long as you have not switched to
another selection.
Customizer
You use the Customizer to set the properties for an object, such as how the object
looks, where it appears, and other characteristics.
Important: You cannot use the Customizer to edit the properties of an ActiveX component;
you must use the Attribute Inspector.
When you are using the Customizer to edit attributes, the Attribute Inspector toolbar
button is disabled.
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
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 which
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.
If another palette overlaps this palette, you must click in an editable area to bring it to
the top.
The Coding Assistant is a dockable palette. For more, read Docking and undocking
toolbars and palettes on page 2-5.
You can configure the Coding Assistant by selecting Tools, Preferences. For more,
read Preferences on page 4-31.
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.
Standard child-
window toolbar
Custom controls
toolbar
ActiveX toolbar
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.
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, Centura SQLWindows/32 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 is a dockable palette. For more, read Docking and undocking
toolbars and palettes on page 2-5.
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. Centura SQLWindows/32 needs to associate
a file name with the button.
If you have 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, Centura
SQLWindows/32 automatically includes the application file that defines the class. Be
aware of this when adding and using such classes. Centura Software recommends that
you define such classes in small APLs which contain a related set of classes and the
definitions they require.
Debugger
Chapter 10, Debugging describes SQLWindows/32’s debugger. In summary, you use
the debugger 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 designtime, it is called
design mode. When you run the application at designtime, it is call run mode.
Keyboard shortcuts
Displaying Centura SQLWindows/32 palettes
Window Shortcut
Save as F12
Editing
Action Shortcut
Cut Ctrl+X
Copy Ctrl+C
Paste Ctrl+V
Clear Del
Expand all below selected section Select lines and press the keypad “*”
Collapse entire outline Ctrl+- (Control key and keypad minus key)
Editable/right portion of line Select line and press the Tab key
Find Alt+F3
Find Again F3
Libraries
Action Shortcut
Edit library F5
Compile F8
Action Shortcut
Next error F4
Execute F7
Debugging
Action Shortcut
Toggle breakpoint F9
Other
Action Shortcut
Properties Alt+Enter
Chapter 3
Deploying an application
To run a SQLWindows/32 application in a production environment, you must install
these components on users' computers:
• An executable version of the SQLWindows/32 application
• Deployment files that come with SQLWindows/32
• Other components that connect the application to a data source
DEPLOY*.EXE adds files to the current directory and to the Windows /system
directory.
To see the files that DEPLOY*.EXE installs, run it with the /x option:
DEPLOY*.EXE /x
DEPLOY*.EXE then lists the file names and you can shoose individual files to
install:
Simple migration
If you wrote your SQLWindows applications using only SAL code and did not
include external DLLs or direct calls to the SDK directly, your migration is fairly
easy. In such cases, all you need to do is open the SQLWindows application in
SQLWindows/32 and save it.
Important: The size of a 32-bit executable is about 30 percent more than the size of the
corresponding 16-bit executable.
Advanced migration
If your applications include any of the items listed below, then migrating requires
more than opening and saving the applications in SQLWindows/32:
• Called SDK functions directly
• Used SDK messages directly
• Used DLLs you wrote
• Used third-party DLLs
• Used previous support for OLE1, OLE2, and VBXs
This next sections describe how to migrate applications that use the features above
(and others).
Windows SDK
The following sections describe how to migrate your SQLWindows applications to
SQLWindows/32 when you have directly called the SDK.
16-bit 32-bit
USER.EXE USER32.DLL
GDI.EXE GDI32.DLL
KERNEL.EXE KERNEL32.DLL
KRNL386.EXE
If you are calling functions in these libraries using ordinals, change all ordinals to
zero because the SQLWindows/32 compiler can look for the external function
automatically, without a specified ordinal. Use the exact external function name.
SDK functions
When directly calling SDK functions, the function parameters may be different under
Win32 than they were under Win16. Some data types have expanded under Win32
and so you may need to change your external function definitions. The key
consideration is getting the same data type width defined in both the external and
internal declarations.
Note: In general, look at Visual Toolchest for any needed functions before calling the Windows
SDK directly.
A small number of functions in the Windows API are not available under 32-bit. You
receive a message if you call an unavailable function. A list of API functions removed
by Microsoft is on the Microsoft Developer Network CD.
SDK function names and Unicode. The support for Unicode in Windows NT
complicates the use of function names. For instance you cannot directly access the
function GetWindowText in the Win32 SDK because there are actually two names for
this one function. GetWindowTextA is the ANSI version, and GetWindowTextW (W
for wide) is the Unicode version.
If you try to call GetWindowText by itself, the compiler notifies you that it cannot
find the function, therefore you must specify either the A or W function.
SQLODBW.DLL SQLODB32.DLL
SQLORAW.DLL SQLORA32.DLL
SQLSYBW.DLL SQLSYB32.DLL
SQLAPIW.DLL SQLWNTM.DLL
SQLIRTW.DLL SQLIRT32.DLL
SYBSAL.DLL SYBSAL32.DLL
ODBSAL.DLL ODBSAL32.DLL
menuOLEEdit
Because the named menu, menuOLEEdit, calls some of the now unsupported OLE1
functions, SQLWindows/32 does not support it. Many applications may have this
menu defined by default as it was defined in the SQLWindows file, NEWAPP.APP.
Remove this menu from your applications.
VBXs
Replace VBXs with equivalent ActiveX controls.
QuickOLE
You can continue to use QuickOLE, but Centura Software does not plan to enhance it.
For new applications, use ActiveX instead.
CDK
A 32-bit version of the CDK is available for SQLWindows/32. You need to recompile
your 16-bit CDK applications using the 32-bit CDK and save them.
QuickEmail
The 32-bit library of QuickEMail does not have cMailMeter, nor does it have dialog
boxes dlgMailAddrsMsg or dlgMailSelectSys. These dialogs were used only by
QuickEMail itself and are no longer necessary because the QuickEMail in
SQLWindows/32 supports the MAPI (Microsoft) mail interface. If you used these in
your SQLWindows code, remove them before converting.
Lotus Corporation VIM and Novell MHS are not supported.
Quest
Use Database Explorer to browse and update the database directly from SQLWindows/32.
Report Builder is integrated into Database Explorer, so you can define queries and generate
reports. You can also use Report Builder as a stand-alone application to define queries and
generate reports.
QuestWindows
Replace QuestWindows with table windows, adding program code to execute a
query, populate the table, apply and discard changes, and so on.
Test tools
Contact your test tool vendor about availability and requirements for their 16-bit tools
working in 32-bit.
Obsolete Functions
The following SQLWindows functions were provided for Windows features that are
now obsolete, such as OLE1 or VBXs, and are therefore not in SQLWindows/32. If
you use any of these functions in applications, you need to remove them.
OLE1 Support
SalEditCanInsertObject SalEditCanPasteSpecial
SalEditPasteSpecial SalEditPasteLink
SalEditInsertObject SalOLEAnyActive
SalOLEAnyLinked SalOLEDoVerb
OLE1 Support
SalOLEFileInsert SalOLEGetServers
SalOLEGetVerbs SalOLELinkProperties
SalOLEServerInsert SalOLEUpdateActive
SalEditCanPasteLink
VBX Support
SalVBXAddItem SalVBXCloseChannel
SalVBXGetError SalVBXGetNumParam
SalVBXGetProp SalVBXGetStringParam
SalVBXOpenChannel SalVBXRefresh
SalVBXRemoveItem SalVBXSetPicture
SalVBXSetProp
SqlSharedAcquire SqlSharedSet
SqlSharedRelease SqlSSTGetID
SqlSSTStatus
QuestWindow Functions
SalQuestTblApplyEdits SalQuestTblReset
Chapter 4
SQLWindows/32 Menus
This chapter explains these menus in SQLWindows/32:
• File
• Edit
• Project
• Component
• Layout
• Debug
• Database
• Tools
• Window
• Help
File menu
New …
Creates a new unnamed Centura SQLWindows/32 application. You name the
application the first time you save it.
Displays the Templates dialog where you choose an application template for a
Centura SQLWindows/32 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 checkbox in the application
icon. To accept the default template as the new application, click OK. This creates a
new unnamed Centura SQLWindows/32 application.
You can also select a template other than the default and Click OK to choose it.
Centura SQLWindows/32 then opens the new application using the template that you
selected.
If you click Close, Centura SQLWindows/32 does not create a new application.
Note: 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.
Note: If you enter an application name without a path, the file must reside in the Templates
subdirectory where you installed Centura SQLWindows/32 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 that you want as the default template and click Set As
Default.
Note: The Templates dialog displays the default template with a checkbox in the application
icon. The Set As Default button is disabled when the default template is selected.
Open
Displays a dialog that lets you select a different application to work on.
The File Open dialog can display different file types and you can use the Files of type
combo box to chose 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 Centura SQLWindows/32, 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, Centura SQLWindows/32 displays the Save As
dialog where you name the application and specify its path.
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, Centura SQLWindows/32 asks
you if you want to replace the existing application.
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 designtime. This is also called the binary format
• Compiled saves the compiled code.
• Text saves the application in a form that you can open with a text editor.
• Indented Text is like Text, but it saves the application with tabs for the
indent levels.
• Libraries saves the application as an include library. For more, read Include
Libraries.
Page Settings
Displays a dialog where you set printing options.
Centura SQLWindows/32 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).
Selection
Choose whether to print entire outline or only the part that is selected.
Text Style
Set the font and font size.
Titles
Set titles for the header and footer at the left, center, and right. You can enter literals
and these keywords:
%A Name of application
%P Page number
%D Date
%T Time
Options
Set the number of Copies to print.
When you check Include Display Attributes, the window attributes print in the outline
in the same place as when you save an application as text.
If you check Include Named Properties, the named properties of QuickObjects print.
Code Only means to only print lines that have actual SAL statements. This does not
include formats, external functions, constants, and variables. The Application
Description always prints.
You can print with or without Line Numbers.
Margins
Set the left, right, top, and bottom margins in inches.
Print
Displays a standard Windows Print dialog. When you print, Centura SQLWindows/32
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).
Exit
Closes Centura SQLWindows/32. If you changed the open application after the last
time you saved it, Centura SQLWindows/32 displays the "Save current changes?"
dialog.
Edit menu
The Edit menu displays these menu options to work with the code outline. Click a
menu option to display details.
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.
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.
Collapse
Hides all child items of the selected parent item.
You can also collapse an outline item by double-clicking its diamond.
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.
Move Up
Moves the selected item above the previous item.
Move Down
Moves the selected item below the next item.
Find
Displays a dialog where you specify what to search for in the outline.
Each time Centura SQLWindows/32 finds the string, it highlights the string and
enables Find Next. Click Find Next to search for the next occurrence of the search
string.
Note: Find only works in an Outline tab. If you are in a different tab and you execute a Find,
Centura SQLWindows/32 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 Centura SQLWindows/32 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.
Match Case
Check this if you want the search to depend on the capitalization of the search string
in Find What.
Find Next
Searches for the string you previously specified in the Find dialog.
Replace
Displays a dialog where you specify what to search for in the outline and what to
replace it with.
After you enter a search string and a replace string, the push buttons on the bottom of
the dialog are enabled.
Note: Replace only works in an Outline tab. If you are in a different tab and you execute a
Replace, Centura SQLWindows/32 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 Centura SQLWindows/32 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.
Centura SQLWindows/32 updates the property when you close the field by clicking
elsewhere in the outline or by pressing Esc or Enter.
Match Case
Check this if you want the search to depend on the capitalization of the strings in Find
What and Change To.
Find Next
Searches for the next occurrence of the search string.
Change
Replaces the current selection but waits for you to click Find Next before searching
for the next occurrence.
Change All
Replaces all occurrences of the search string without prompting.
Properties
If an object is selected in the tree view or a layout window, displays the Customizer
for the object if you have selected the Customizer in the Presentation tab of Tools,
Preferences.
If the top-most item is selected in the tree view, displays a tabbed dialog where you
can view statisitics and specify runtime settings for the application.
Statistics tab
This tab contains information about resource use and application components.
Runtime tab
Reject Multiple Window Instances. When you turn on this option, 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 this option, Centura SQLWindows/32 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 which is an instance of
the class named cls1
hWnd.cls1.fun( ) hWnd refers to a window which is an instance of
the class named cls1
Project menu
Displays these options to work with the application project application. Click an
option to display details.
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, Centura SQLWindows/32 displays a
dialog. Click Cancel to stop the compile.
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.
Go
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.
Build Settings
Displays a tabbed dialog where you set specify information about what to build.
Build Target. Specify the name and path of what you are building. Click the ellipsis
push button to navigate to the file.
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.
You must have installed the Object Compiler to see this tab.
Use Object Compiler. Check this to make actions in the application into external
functions in a DLL.
Target DLL name. Specify the path and name of the output DLL. Click the ellipsis
push button to navigate to the file.
Generated Source File. The path and name of the output application that contains
external function definitions for each function in the DLL. This field is not editable.
Build
Creates an executable, dynalib, or include library as specified in the Build Settings
dialog. Click Settings to go to the Build Settings dialog.
Component menu
Displays options for the various Centura SQLWindows/32 components.
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 an object or class using Centura SQLWindows/32’s wizards which
guide you through dialogs.
ActiveX Wizard
Displays the ActiveX automation wizard. For more, read Chapter 20, ActiveX
programming.
QuickObject Editor
Lets you associate a dialog with a class. The dialog is invoked at designtime on
objects of the class, usually to set properties that are used at runtime.
Menu Editor
You build menus graphically with this dialog. For more, read Menu Editor on page 6-
10.
Go To Item
Starts a new instance of Centura SQLWindows/32 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 Centura SQLWindows/32, the first instance of Centura
SQLWindows/32 resumes.
Refresh
Re-includes 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).
For more, read Include libraries on page 19-2.
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. Centura SQLWindows/32 displays a
warning dialog before completing the merge.
For more, read Include libraries on page 19-2.
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
Sets the type of view in the Components tab to a list.
Details
Sets the type of view in the Components tab to show details.
Layout menu
Displays these menu options to work with the code outline layout. Click an option to
display details.
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 Centura
SQLWindows/32's 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.
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. Note: 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.
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.
Space Evenly
Evenly spaces selected objects using these menu options.
• Across
• Down
You must select at least two objects before this menu item is enabled.
Across
Evenly spaces objects horizontally.
Down
Evenly spaces objects vertically.
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.
The tab sequence value is from 1 to the number of objects in the window which 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 at the left) 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.
Click Reset to set the objects' tab sequences to their original values.
To save changes and close the Tab Order dialog, click Close.
Show
Show Design
Design Scroll
Scroll Bars
Bars
uncheck this,
If you uncheck this, Centura
Centura SQLWindows/32
SQLWindows/32 does
does not
not display
display scroll bars on form
and table
windows and table windows
windows atat designtime.
designtime. Uncheck
Uncheck this
this item
item when
when you
you are
designing a window that does not have scroll bars at runtime.
designing
Show
Show Hidden
Hidden Windows
Windows
check this,
If you check this, Centura
Centura SQLWindows/32
SQLWindows/32 displays
displays windows
windows atat designtime
designtime even
even if
if
you set
you set their
their visible
visible property
property to
to No
No in
in the
the Attribute
Attribute Inspector
Inspector or
or the
the Customizer.
Customizer.
Debug
Debug menu
menu
Displays these
Displays menumenu
options to debug
options the application.
to debug For more,
the application. Clickread Chapter
an option 10,
to display
Debugging.
details.
• Go
Go
• Stop Debugging
Starts execution or resumes execution at a breakpoint.
• Break
• Step Into
• Step Over
• Breakpoints
• No Animate
• Slow Animate
• Fast Animate
Go
Starts execution or resumes execution at a breakpoint.
Stop Debugging
Stop execution of the application and returns you to Centura SQLWindows/32.
Break
Suspends execution.
Step Into
Executes the next statement and returns control to Centura SQLWindows/32. If the
application calls a function, Centura SQLWindows/32 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, Centura SQLWindows/32 takes
you to the first line but does not execute it. If the item is a call to an external function,
Centura SQLWindows/32 behaves the same way as Debug, Step Over.
Step Over
Executes the next statement and returns control to Centura SQLWindows/32. If the
application calls a function, Centura SQLWindows/32 executes all the function's
statements in one step and stops at the statement after the function call.
Breakpoints
Displays these options to work with the breakpoints.
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,
Centura SQLWindows/32 stops at each breakpoint and displays the Debug toolbar.
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.
Database menu
Displays these database menu options. Click an option to display details.
New
This menu item lets you select these subitems:
Table Displays the table Definition tab.
Index Displays the New Index dialog.
Stored Procedure Displays the New Stored Procedure dialog
Stored Procedure Package Displays the Create Stored Procedure Package
dialog
Database Displays the New Database dialog
Table
This menu item lets you select these subitems:
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 This command is activated 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.
Refresh Refreshes the table by retrieving the new result set. If you have
been away from your computer, select this command to see if any
one 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
This menu item lets you select these subitems:
Stored Procedure Class Wizard The Stored Procedure Class Wizard allows 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.
SQL Script
Use this menu item to select the following subitems:
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 These options are available:
Execute Displays the Script Execution Settings dialog.
Connection Displays the Connections Settings dialog.
Session Displays the Session Settings dialog.
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
Query
Use this menu item to select the following subitems:
Define Query
Use this menu option to access the property pages to the query you are currently
defining. These property pages allow 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
Use this menu option to create a new query using the Query property pages. If you
select this, you lose the current query.
Open Query
Opens a query that 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.
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
This menu item lets you select the following items to format:
Report Displays the Format Report dialog box to
determine how to print the report.
Input This menu item lets you select the following
subitems:
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.
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
Display the results of the query as a report.
Show as Table
Display 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
Disconnect from the database you have selected in the Explorer (left) pane. You can
also select any of the nested nodes underneath that database, then select the
Disconnect menu item.
Tools menu
Displays these options for displaying the tools available in Centura.
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.
Tools
The current items in the Tools toolbar.
Command
The program name.
Browse
Click this to select the program using the standard File Open dialog.
Parameters
Command line arguments to pass to the program each time it starts.
Working Directory
The name of the directory that contains files that 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
Displays a dialog where you select the toolbars that you want to display.
Preferences
Displays a tabbed dialog with items that you use to customize Centura SQLWindows/
32’s environment.
To see the effect of changing a setting without closing the dialog, click Apply.
Slow Animate Interval (In Seconds). The speed of Slow Animate in seconds.
Split Horizontally. Turn this on to display Coding Assistant's Add Same Level and
Add Next Level lists stacked one on top of the other.
Split Vertically.
Turn this on to display Coding Assistant's Add Same Level and Add Next Level lists
side by side.
Use Attribute Inspector. Turn this on to use the Attribute Inspector to view and
edit properties.
Use Customizer. Turn this on to use the Customizer to view and edit properties.
Visible. Check this to display a grid pattern in layout windows. When not checked,
Centura SQLWindows/32 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.
C:\INCLUDES;C:\PROJECT1
Use Global Search Path. If checked, Centura SQLWindows/32 looks for files
first in the specified Application Path and then in the specified Global Path. If not
checked, Centura SQLWindows/32 looks only in the Application Path.
Centura SQLWindows/32 stores both the Application Path and the Global Path in the
application.
Output
Displays the compiler error message list.
When compiling, Centura SQLWindows/32 detects as many errors as possible before
stopping. As Centura SQLWindows/32 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
Centura SQLWindows/32 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. For more, read Docking and customizing toolbars and
palettes on page 2-5.
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 (Next Error on page 4-12) and Project, Previous Error (Previous Error on
page 4-12).
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. For more, read Coding Assistant on page 2-19.
Attribute Inspector
Displays the Attribute Inspector. For more, read Attribute Inspector on page 2-16.
Controls
Displays the Controls palette. For more, read Controls palette on page 2-21.
Variables
Displays the names and values of variables at a breakpoint. Centura SQLWindows/32
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. Centura
SQLWindows/32 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, Centura
SQLWindows/32 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. Centura SQLWindows/
32 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 which 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.
Click SAM messages only to display only Centura SQLWindows/32 messages
(SAM_*). The values displayed under the Message heading are Centura
SQLWindows/32 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 Centura
SQLWindows/32. 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 these:
SalDateCurrent( )
2+2
Report Builder
Starts Report Builder.
Diff/Merge
Starts the diff/merge tool.
SQLTalk
Starts SQLTalk.
SQLConsole
Starts SQLConsole.
Window menu
You can have these Windows options to resize the Centura application window.
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
Help menu
Help Topics
Displays the main topic list. Double-click a topic to select it.
Functions
Displays help for system functions.
Messages
Displays help for messages.
QuickObjects
Displays help for QuickObjects.
Visual Toolchest
Displays help for Visual Toolchest.
Books Online
Opens the Centura Books Online collection. The Centura Books Online collection
was created using Acrobat 3.x and lets you perform full-text searches across the
entire document suite, navigate the table of contents using the expandable/collapsible
browser, or print any chapter.
About Centura
Displays the version number of Centura.
Chapter 5
SQLWindows/32 Objects
This chapter:
• Describes most of the objects that you can add to an application
• Explains the attributes for each object
Adding objects
You add objects with the Controls palette (page 2-21), the New menu (page 2-11),
and the Coding Assistant (page 2-19).
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 then 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
Background Text
Group Box
Frame
Line
Data Field
Multiline Field
Push Button
Radio Button
Check box
Option button
List Box
Combo Box
Picture
Custom Control
ActiveX Control
Attributes
You use the Attribute Inspector or the Customizer to set properties of an object. For
more, read Editing object attributes on page 2-14.
Types of objects
There are two types of objects:
• Top-level
• 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.
MDI windows
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.
Form window
Form windows are used to enter and display data. You can place child objects such as
data fields, push buttons, and background text on a form window.
A form window with a toolbar, menus, data fields, and background text
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 If Yes, the form window has a toolbar and a status bar and the Accessories item is enabled
Enabled where you can turn off the toolbar or status bar. The default is no.
Accessories If Accessories Enabled is Yes, then you can use this cascading menu to turn off the
toolbar or status bar and to set the size and position of the toolbar.
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 If Yes (default), the window is created and displayed at application startup. If No, you
Create must call SalCreateWindow to create the window.
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.
Location and Size Displays a cascading menu with the form window's position (top and left) and size (width
and height).
Property Description
Dialog box
You can use dialog boxes to let the user enter data, or to display warning or error
messages. You can place child objects such as data fields, push buttons, and
background text in a dialog box.
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.
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/32 Function Reference or the online help.
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.
Property Description
Accessories If Yes, the dialog box has a toolbar and a status bar and the Accessories item is enabled
Enabled where you can turn off the toolbar or status bar. The default is no.
Accessories If Accessories Enabled is Yes, then you can use this cascading menu to turn off the
toolbar or status bar and to set the size and position of the toolbar.
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
Type of Dialog The type of dialog box: Modal (default), Modeless, or System modal.
Location and Size Displays a cascading menu with the dialog box's position (top and left) and size (width
and height).
If you check Absolute Screen Location, the position of the dialog box is relative to the
upper left corner of the screen. If you do not check Absolute Screen Location, the position
of the dialog box is relative to the owner of the dialog box (you specify the owner in
SalModalDialog or SalCreateWindow). If not checked and the dialog box does not have
an owner, the position of the dialog box is absolute (as it is if checked).
Table window
Chapter 14 describes table windows.
MDI window
Chapter 16 describes MDI windows.
Child objects
You place child objects 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.
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 or
the Customizer. 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.
Background text
You use background text for titles, labels, and instructions.
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.
Property Description
Visible If Yes (default), the background text is visible at runtime. If No, the background text is not
visible at runtime.
Location and Displays a cascading menu with the background text's position (top and left) and size
Size (width and height).
Group box
You use a group box to label a set of related objects such as radio buttons.
At designtime, you can edit the title of a group box by pressing the Shift key and
clicking the right mouse button.
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 and Displays a cascading menu with the group box's position (top and left) and size (width and
Size height).
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.
Frame attributes
The table below describes the attributes for a frame.
Property Description
Visible If Yes (default), the frame is visible at runtime. If No, the frame is not visible at runtime.
Location and Displays a cascading menu with the frame's position (top and left) and size (width and
Size 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.
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.
Line attributes
The table below describes the attributes for a line.
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.
Data field
A data field displays output or accepts input.
Property Description
Object Name The name you use to refer to the data field in statements.
Property Description
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).
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/32 allocates for the object’s value.
At runtime, SQLWindows/32 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/32 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. For more, read Chapter
11, Formatting and Validating.
Input Mask Input validation criteria for the data field. For more, read Chapter 11, Formatting and
Validating.
Country The country profile for the data field. For more, read Chapter 11, Formatting and
Validating.
Property Description
Multiline field
A multiline field accepts and displays multiple lines of data.
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 Displays a cascading menu with the multiline field's position (top and left) and size (width
Size and height).
Property Description
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/32 allocates for the object’s value.
At runtime, SQLWindows/32 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/32 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.
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.
Push button
When the user clicks a push button, the application performs an action.
At designtime 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.
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 Displays a cascading menu with the push button's position (top and left) and size (width and
Size height).
Picture Displays a cascading menu where you enter a description, specify the name of the file that
Contents contains an image, and set the image style (single or multiple).
Picture Displays a palette where you select a color in the image that you want to replace with the
Transparent background color of the option button. This makes parts of the image transparent. This
Color 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 The accelerator that activates the push button. None is the default. The table below lists the
Accelerator keyboard accelerators.
Background Displays a palette where you can set the color of the background (the area of the push
Color button not covered by an image).
Font Size The font size of text for the push button.
Accelerators
Function keys Other keys
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12 Enter, Esc
file associated with the push button to contain multiple images. A setting of Multiple
does not affect the behavior of *.ICO files.
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/32 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.
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.
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 Displays a cascading menu with the radio button's position (top and left) and size (width
Size and height).
Font Size The font size of text for the radio button.
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.
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 Displays a cascading menu with the check box's position (top and left) and size (width and
Size height).
Option button
Chapter 15 describes option buttons.
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.
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
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 Displays a cascading menu with the list box's position (top and left) and size (width and
Size height).
Property Description
Multiple If Yes, user can select more than one item at a time in the list box. The default is no.
Selection
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.
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.
Property Description
Object Name The name you use to refer to the combo box in statements.
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).
Property Description
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 that you specify in Max Data Length is the maximum capacity of
the object, not the number of bytes that SQLWindows/32 allocates for the object’s value.
At runtime, SQLWindows/32 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/32 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. For more, read 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 If Yes, the list box part of the combo box is always displayed. If No (default), the list box
List 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.
Picture
Chapter 17 describes picture objects.
Scroll bars
You can add vertical and horizontal scroll bars to an application.
Up arrow
Scroll box (also
called thumb,
elevator box, or
slider box)
Down arrow
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 Displays a cascading menu with the scroll bar's position (top and left) and size (width and
Size height).
Custom control
Chapter 23 describes custom controls.
ActiveX control
Chapter 20 describes ActiveX controls.
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.
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
objects.
Toolbar attributes
The table below describes the attributes for a toolbar.
Property Description
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:
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#:
...
Functions
You can hide or show a toolbar by calling SalTBarSetVisible.
Call SalGetFirstChild to get the handle of the toolbar window. The statement:
Set hWndToolBar = SalGetFirstChild( hWndForm,
TYPE_FormToolBar )
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.
SalParentWindow
Where called Return
parameter
Toolbar child in top-level object hWndItem Handle of containing top-level object
(hWndForm)
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)
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.
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 designtime. Instead, you call the SalMessageBox
function. The SQLWindows/32 Function Reference describes SalMessageBox.
Standard dialogs
You can call these functions to display standard Windows dialog boxes:
• SalDlgChooseColor
• SalDlgChooseFont
• SalDlgOpenFile
• SalDlgSaveFile
The SQLWindows/32 Function Reference describes these functions.
Object colors
When you add an object, you set its color in the Attribute Inspector or Customizer.
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/32 uses the
closest color. On monochrome computers, SQLWindows/32 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/32 Function Reference describes these functions.
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
Property Description
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.
Form units
SQLWindows/32 uses form units as the unit of measure for objects. Form units are
independent of the screen resolution which 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.
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/32 has a specific data type for window handles. For more, read
Window Handle on page 7-8.
Before sending SAM_Create to the window being created, SQLWindows/32 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.
Important: 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.
Chapter 6
Application Menus
This chapter explains the elements of menus that 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
• Graphical Menu Editor
About 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 or the
Customizer to create them. Instead, you use Coding Assistant or the graphical Menu
Editor 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.
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. For more, read Menu status text on page 6-9.
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.
Property Description
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.
Accelerators
Shift + function key
Ctrl + character key combinations Function keys Other
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.
Menu separator
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.
Cascading
menu
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.
Menu
row
Menu column
A menu column groups menu items in vertical columns.
Menu
column
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
which 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.
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.
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
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 )
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.
For more, read Chapter 16, MDI Windows.
Menu Editor
You build menus graphically using this dialog.
you selected in the menu definition. If the new popup menu does not appear where
you want it, drag it up or down, or to the left or right.
Note: You can also double-click Popup Menu in the list below the toolbar to add a popup menu
below the selected item in the menu definition area.
3. In the middle of the dialog, enter a menu title and status text. In the title, put an
asterisk before the character that you want to be the mnemonic.
4. You can call a function that determines when the popup menu is enabled. For
more, read Function Call Editor dialog on page 6-13.
Note: You can also double-click Menu Item in the list below the toolbar to add a menu item
below the selected item in the menu definition area. You can also add a menu item to the menu
bar.
4. In the middle of the dialog, enter a menu title and status text. In the title, put an
asterisk before the character that you want to be the mnemonic.
5. Specify information about the menu accelerator in the middle of the dialog.
6. You can call a function that determines:
• When the menu item is enabled
• When the menu item is checked
• The statement that executes when a user chooses the menu item
For more, read Function Call Editor dialog on page 6-13.
Note: You can also double-click the component name in the list below the toolbar to add the
component below the selected item in the menu definition area.
Building statements
To build statements, use the Function Call Editor dialog. After you add a popup menu
or menu item, click Enabled When, Checked When, or Call Function to display
this dialog.
For menu items, click Create Window to display a dialog where you select a window
that SQLWindows/32 uses to automatically build a SalCreateWindow or
SalModalDialog statement.
Create Window dialog. The list in the lower left of the dialog shows the names of
all windows in the application. You can scroll the list by typing the first few
characters of the window name in the data field above the list.
Make a selection in the combo box to list only a certain type of window. The choices
are:
• All
• Form window
• Dialog
• Table window
• MDI window
• MDI children
You can also select a window type to list by clicking a button in the toolbar below the
combo box. The buttons correspond to the choices in the combo box.
Choose the window to create by selecting and double-clicking or clicking Select
Window. After you choose a window, its name appears in the data field in the upper
left of the dialog.
After you choose a window, click OK to save your changes and close this dialog or
click Cancel to close the dialog without saving your changes.
Clearing functions
If you have associated functions with menu components, you can delete them by
selecting the function in the lower middle section of the Menu Editor dialog and
clicking Clear Function.
After you perform an operation, click OK to save your changes and close the
Function Editor dialog or click Cancel to close the dialog without saving your
changes.
Selecting a function
When you first display this dialog, the top left contains (none). The middle left of the
dialog lists functions.
Type in the data field above the list to scroll to a function that begins with what you
type. Uncheck Global Functions in the lower left to list only functions local to the
window.
After you select a function name, double-click or click Select Function. The upper
left of the dialog displays the function with its parameters listed below it.
Note: For enabled when and checked when functions, you can only select a function that returns
a Boolean value.
Selecting parameters
After you select a function, the list in the lower left of the dialog changes and shows
symbols defined in the application. Type in the data field above the list to scroll to a
symbol that begins with what you type. Use Symbols in the middle left of the dialog
to limit what the list displays. Uncheck Global Symbols in the lower left to list only
symbols local to the window.
After you select a symbol name, double-click or click Change Parameter. The
symbol you chose replaces the parameter in the upper left of the dialog.
Chapter 7
SAL (SQLWindows/32
Application Language)
This chapter explains the elements of SAL:
• Data types
• Variables
• Constants
• Arrays
• Operators
• Expressions
• Statements
• Functions
• Command line arguments
Case sensitivity
SQLWindows/32 is case sensitive. Uppercase and lowercase characters are seen as
different.
Data types
You specify a data type for variables and constants.
Variables can be one of these data types:
• Boolean
• Date/Time
• File Handle
• Long String
• Number
• Sql Handle
• String
• Window Handle
Constants can be one of these data types:
• Boolean
• Date/Time
• Number
• String
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 as shown
above. Note the following:
• The year must be four digits
• The month, day, hour, minute, and seconds must be 2 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
• 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/32 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/32 supplies the default
of 0, which converts to December 30, 1899 (date part) 12:00:00 AM (time part).
For example, if you define this variable:
Date/Time: dtExample
and execute this Set statement that does not specify a time:
Set dtExample = 1983-10-02
then the value in dtExample is:
1983-10-02-00.00.00
Note: When the microseconds part is zero, SQLWindows/32 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
Note that 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. In these
examples, these variables are used:
Date/Time: dtExample1
Date/Time: dtExample2
Number: nResult
Number
Use this data type for numbers with up to 22 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( ) )
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.
For more, read 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/32 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.
Use this data type to read and write SQL database columns longer than 254 bytes.
Example
Variables
Long String: sLong
...
Set sLong = 'Long String'
Internally, SQLWindows/32 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. For more, read Window handles on page 5-38.
Example
Variables
Window Handle: hWndItem
...
Form Window: frmMain
...
Contents
Data Field: dfClock
...
Message Actions
On SAM_Create
Call SalTimerSet( hWndItem, 1, 1000)
Variables
A variable can hold any value of its data type.
Syntax
Use this syntax to declare a variable:
Data Type: VariableName
Examples
These are examples of variable declarations:
Boolean: bReturn
Date/Time: dtBirthday
Long String: strLong
Number: nCount
Sql Handle: hSql
String: strName
Window Handle: hWndHelp
You must qualify the reference because it is in the form and is not in the scope of the
child variable. In the example below, 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
System variables
The table below lists SQLWindows/32's system variables.
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).
SQLWindows/32 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/32 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.
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.
Note: 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).
Important: You can make only the first dimension of a multi-dimensional array dynamic.
Important: When you refer to a multi-dimensional array, you must explicitly specify an index
for every dimension.
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/32 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:
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/32 has many system constants that are explained in the online help.
Naming conventions
Variables
Use prefixes in the names of variables to make the outline self-documenting. The
table below lists the name prefixes.
Constants
Use an uppercase prefix with an underscore followed by a mixed-case or uppercase
name. For example:
TYPE_ConstantName
TYPE_CONSTANTNAME
Operators
An operator is a symbol or word that represents an operation to perform on one or
more values. The table below shows the operators:
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/32 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
Examples
nSalary[grade] + .1*nSal[3]
bQueryOn
MAXNO
1 + 1
SalDateCurrent( )
SAL statements
You use SAL statements 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
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.
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')
Syntax
If expression1
statement1
Else If expression2
statement2
Else
statement3
SQLWindows/32 evaluates expression1. If expression1 is TRUE, SQLWindows/32
executes statement1. If expression1 is FALSE, SQLWindows/32 evaluates
expression2. If expression2 is TRUE, SQLWindows/32 executes statement2. If
expression2 is FALSE, SQLWindows/32 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:
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:
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/32 evaluates expression. If expression matches constant1, then
SQLWindows/32 executes statement1; if expression matches constant2, then
SQLWindows/32 executes statement2. If no Case constant matches expression, then
SQLWindows/32 executes the statements under Default.
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/32 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. For more, read SQL error handling
on page 12-18.
While
The While statement repeats until the expression being evaluated becomes FALSE.
Syntax
While expression
statement
SQLWindows/32 evaluates expression. If expression is TRUE, SQLWindows/32
executes statement and re-evaluates expression. When expression becomes FALSE,
SQLWindows/32 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/32 displays comments in gray by default. You can change this to a
different color or style. For more, read Preferences on page 4-31.
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:
1. Add a comment line that is the one-line summary and press Enter.
2. Display Coding Assistant. There is an exclamation point in the Add Next Level
list.
3. Double-click the exclamation point to add a line at the next level. Enter the
comment text and press Enter.
4. 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.
Here is an example of a collapsible comment with nested levels (shown without the
diamonds):
! Short pithy description
! Some details ...
! More details ...
! More details ...
! Even more details ...
! Even more details ...
! Even more details ...
! More details ...
! More details ...
Functions
A function performs a specific task. There are five types of functions:
• System functions
• 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/32 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/32 Function Reference explains the system functions. Chapter 12,
SQL Programming, also explains the Sql* functions.
External functions
In a SQLWindows/32 application, you can call external functions in a DLL (Dynamic
Link Library). For more, read Chapter 22, Calling External Functions in DLLs.
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.
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/32 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/32 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/32
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.
Important: 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.
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 )
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:
Clipboard functions
You use the SQLWindows/32 functions in the table below to cut and paste with the
Clipboard.
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 designtime, SQLWindows/32 must be able to find the
resources in external files. When you make an *.EXE version of the application,
SQLWindows/32 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/32
has two types of yielding that you can control:
• Intra-application: between objects in the same SQLWindows/32 application
• Interapplication: between a SQLWindows/32 application and other Windows
applications
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.
Chapter 8
Object-Oriented
Programming
This chapter shows how to use SQLWindows/32 object-oriented programming
features and covers these topics:
• Classes, inheritance, and objects
• Defining classes
• Creating objects
• Message actions
• Instance variables
• Class variables
• Class functions
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.
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/32 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.
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:
Base
class
Derived
class
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:
Derived class of B;
C derived class of A
Multiple inheritance
With multiple inheritance, a class has more than one direct base class. In the diagram
below, class D inherits behavior from two direct base classes, B and C:
B C
Types of classes
SQLWindows/32 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
• Define behavior that is shared by more than one window class
Functional Functional
class class
Functional Window
class 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
Functional Window
class class
Must be the
same window
type
Window Window
class class
Types of objects
SQLWindows/32 has three types of objects:
• Standard window objects
• User-defined window objects
• User-defined variables
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 user-defined variable (UDV)
Objects
User-defined windows
You create a user-defined window as an instance of a window class:
Window
class
User-defined
window
User-defined variables
You create a user-defined variable as an instance of a functional class:
Functional
class
User-defined
variable
Defining classes
You define classes in the class definitions section near the bottom of the global
declarations in the outline.
The example below shows six collapsed classes: cls1, clsMDIFrame1,
clsDataEntryForm, clsDlgStandard, and clsDatabaseField.
Global Declarations
...
Class Definitions
Functional class: cls1
MDI Window Class: clsMDIFrame1
Form Window Class: clsDataEntryForm
Dialog Box Class: clsDlgStandard
Data Field Class: clsDatabaseField
Later sections explain details about functional classes and window classes.
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 shared by all objects of this class.
Variables
Instance Variables replicated and private to each object of this class.
Variables
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, so functional classes do not
have a message actions section.
Attributes
Attirbutes that you set are inherited by:
• Derived classes
• Objects of the class
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/32 uses the first
non-default setting it finds and ignores other non-default settings.
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
Item Description
Class Type and The class type is to the left of the colon (for example, Data Field Class). The class name is
Name to the right of the colon (for example, clsDataField1)
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 functional classes or
window classes of the same window type as the current class. You can select classes in
Coding Assistant.
Class Variables shared by all objects of this class.
Variables
Instance Variables replicated and private to each object of this class.
Variables
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.
Window class
Form,
top-level table, Dialog box Child
or MDI
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.
Outline items
The outline items for child window classes are:
<class type>: <class name>
Description: <text>
Derived From
Class Variables
Instance Variables
Functions
Message Actions
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 table below describes the outline items that are unique to these types of window
classes:
Item Description
Menu Default menu definition for window objects which are instances of the class
Toolbar Default toolbar definition for windows which 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.
With multiple inheritance, if a derived class inherits a menu from more than one
direct base class, SQLWindows/32 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 the Attribute Inspector or the Customizer 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 or the Customizer to clarify the ambiguity in the derived class.
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.
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/32 object or an instance of a class.
You can use the Attribute Inspector or the Customizer 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/32 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/32
updates all windows that are instances of the class.
You can define the tab order of class children by selecting Layout, Tab Order.
SQLWindows/32 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/32 uses the same rules for default names for class children as for other
objects.
Example
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/32 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
...
SQLWindows/32 does not propagate child object name changes to existing derived
classes or instances. For example if you already have this hierarchy:
frm1 Instance
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.
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.
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.
Passed by reference
SQLWindows/32 always passes user-defined variables by reference. A called
function or top-level window can both read and write the user-defined variable’s
instance variables.
...
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
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.
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
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.
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).
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.
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' 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.
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).
Class
Object
cls_df1: df1
...
Message Actions
...
Class
Object
cls_df1: df1
... An action here for a
Message Actions given message over-
On SAM_Validate rides one inherited
...
from the base class
Class
Object
cls_df1: df1
... Invokes specified
Message Actions message action
On SAM_SetFocus in the direct
Call SalSendClassMessage( SAM_SetFocus,...) base class
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 diagram below 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.
Class
Object
cls_df1: df1 cls_df1: df2 cls_df1: df3
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.
Inheritance
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.
Internal references
In an object that operates on itself, you can access an instance variable with an
unqualified reference.
Object
cls_fw2: frm1
...
Window Functions
Function: frm_func3
...
Set str1 = 'test3'
Set str2 = 'test4'
...
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, then 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'
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 the these places and 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).
At runtime, SQLWindows/32 searches for the instance variable in these places and in
this order:
1. The object identified by hWnd
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/32 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 diagram below 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.
Class Variables
String: str1
Class
Object
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.
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.
Object
cls_fw2: frm1
...
Window Functions
Function: frm_func3
...
Set str1 = 'test3'
Set str2 = 'test4'
...
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.
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.
Internal references
In an object that operates on itself, you can use:
• An unqualified reference
• A class-qualified reference
Unqualified
Form Window Class: cls_fw2
... references
Derived From
Class: cls_fw1
Functions
Function: cls_func3
...
Call cls_func1(...)
...
Class
Object
cls_fw2: frm1
...
Window Functions
Function: frm_func4
...
Call cls_fw1.cls_func1(...) Class-qualified
Call cls_fw2.cls_func3(...) references
...
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.
• 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 )
Important: You can only make a late-bound unqualified reference in a class that defines or
inherits the named function.
Warning: Late binding adds flexibility, but it is significantly slower, so only use it when
necessary.
Class
Object
cls_fw2: frm1
...
In the example below, 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():
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.
...
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
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 and 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).
Most
efficient
Early-bound object-qualified
Early-bound fully class-qualified
Late-bound fully class qualified
Least
efficient
SqlVarSetup
Before Centura performs a SQL execute or fetch operation, it compiles the bind and
into variables which 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,
Centura 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, Centura 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.
Chapter 9
Messages
This chapter explains:
• Types of messages
• How you process messages
• Each SAM_* message
About messages
SQLWindows/32 sends a message to an object when an event happens. An
application processes a message by taking an action.
Messages drive a SQLWindows/32 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/32 Application Messages (SAM_*)
• Windows Messages (WM_*)
• Application-defined messages
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/32 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:
Global Declarations
System
...
User
Number: PAM_Ok = SAM_User + 2
Number: PAM_Cancel = SAM_User + 4
Important: Do not define constants for Windows DDE messages. The WM_DDE_* message
constants are defined internally in SQLWindows/32.
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 example below 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, read On on page 7-23
For some SAM_* messages, SQLWindows/32 expects you to Return a value to
control processing. After executing a Return statement, message processing ends. In
other words, SQLWindows/32 ignores any statements after a Return statement.
System variables
You use these system variables to process messages:
• 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.
You can use this variable to pass a window handle to a function.
hWndItem
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.
SAM reference
The sections on the following pages describe each SAM_* message.
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
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
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/32 sends SAM_AppExit.
This is the last message SQLWindows/32 sends to an application.
Processing Perform cleanup tasks such as disconnecting from the database.
Important: SQLWindows/32 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
wParam Not used
lParam Not used
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/32 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
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:
• 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
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
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
List Box
SQLWindows/32 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
Combo Box
SQLWindows/32 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/32 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/32 sends SAM_Click to a currently-unselected radio button when a
user clicks it. If the radio button is already selected, SQLWindows/32 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
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/32 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/32 implicitly calls
SalEndDialog( hWnd, 0 ).
Message Variables
hWndForm Handle of current window
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_CornerClick
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
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
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/32 follow these steps to create a form window that has
data fields:
1. Create the form window
2. Create each of its data fields
After SQLWindows/32 creates all the windows, but before making them visible,
SQLWindows/32 sends SAM_Create to the objects in this order:
1. The form window
2. Each of the form's data fields
After SQLWindows/32 sends the SAM_Create messages, SQLWindows/32 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
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/32 ignores any value that you Return when you process this message.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of custom control.
wParam Notification message number
lParam Not used
Example None
SAM_DDE_ClientExecute
Sent to All objects in a DDE server application
Event A DDE client sent a command string.
Processing A server listens for command requests from clients by processing
SAM_DDE_ClientExecute. The server gets the command string that the client sent
by calling SalDDEGetExecuteString. The parameter for SalDDEGetExecuteString is
the lParam of the SAM_DDE_ClientExecute message, which points to the command
string. After calling SalDDEGetExecuteString, the server can parse the command
string to determine the action to perform.
The server can send data or some other response to the client by calling
SalDDESendToClient. The wParam for the SAM_DDE_ClientExecute message
contains the window handle of the client. The server uses wParam in the third
parameter of SalDDESendToClient to send the data or response back to the same
client.
Message Variables
hWndForm Handle of top-level window
hWndItem Object handle
wParam Window handle of sender
lParam Command string
Example
On SAM_DDE_ClientExecute
Set strCommand = SalDDEGetExecuteString (lParam)
! ... parse string, perform required action
If NOT SalDDESendToClient( frmMain, dfServerData, wParam, 100 )
Call SalMessageBox( 'SalDDESendToClient failed',
'DDE Error', MB_Ok | MB_IconHand )
SAM_DDE_ClientRequest
Sent to All objects in a DDE server application
Event A DDE client requested data.
Processing A server listens for requests from clients by processing the
SAM_DDE_ClientRequest message. A server sends data to a client by calling
SalDDESendToClient. The wParam for the SAM_DDE_ClientRequest message
contains the window handle of the client. The server uses wParam in a
SalDDESendToClient parameter to send the data back to the same client.
Message Variables
hWndForm Handle of top-level window
hWndItem Object handle
wParam Window handle of sender
lParam Not used
Example
On SAM_DDE_ClientRequest
If NOT SalDDESendToClient( frmMain, dfServerData, wParam, 100 )
Call SalMessageBox( 'SalDDESendToClient failed',
'DDE Error', MB_Ok | MB_IconHand )
SAM_DDE_DataChange
Sent to All objects in a DDE client application
Event A DDE server has data to the client.
Processing When a DDE server sends an item to the client, the data appears automatically in the
window that the client specified in SalDDEStartSession. The client application does
not need to perform any action to receive the data. However, if the client application
wants to know when the server sends an item, it can process the
SAM_DDE_DataChange message.
Note: SQLWindows/32 sends SAM_DDE_DataChange after the server sends the data to the
client.
Message Variables
hWndForm Handle of top-level window
hWndItem Object handle
wParam Not used
lParam Not used
SAM_Destroy
Sent to Top-level window and its children; MDI window
Event Just before the windows are destroyed.
SQLWindows/32 sends SAM_Destroy messages after sending SAM_Close to the
top-level window. For example, if a form window has data fields, SQLWindows/32
sends the messages to the objects in this order:
1. SAM_Close to the form window
2. SAM_Destroy to the form window
3. SAM_Destroy to each of the form window's child windows
After sending the SAM_Destroy messages, SQLWindows/32 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
SAM_DoubleClick
Sent to List box, combo box, table window, column, and picture
SQLWindows/32 only sends SAM_DoubleClick to a combo box when you set its
Always Show List Customizer property to Yes.
Event The user double-clicks the object.
When the user double-clicks a row in a table window or list box, SQLWindows/32
sends the messages in this order:
1. Two SAM_Click messages
2. SAM_DoubleClick to the table window column or list box
3. 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 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/32 sends this message to ask a window whether it wants auto dragging.
Processing Return TRUE to enable auto dragging. If you do not process this message or you
return FALSE, then SQLWindows/32 does not enable auto dragging.
SQLWindows/32 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
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
SAM_DragEnd
Sent to Top-level window, data field, multiline field, list box, combo box, and picture
Event Drag mode has ended.
Message Variables
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
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
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/32 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/32 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.
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/32 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/32 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
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/32 sends SAM_FetchRow for every row in the table window
that needs to be displayed. When the user scrolls the table window, SQLWindows/32
sends more SAM_FetchRow messages to the table window for rows not in the cache
that need to be displayed.
Processing You usually call SqlFetchRow to fetch the row into the table window based on the
row number in lParam.
Note: Setting a breakpoint on a statement that executes while processing SAM_FetchRow can
cause incomplete painting of a table window.
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
SAM_FetchRowDone
Sent to Table window
Event After SQLWindows/32 has populated a row.
Example None
SAM_FieldEdit
Important: Use SAM_Validate instead of SAM_FieldEdit. SAM_FieldEdit is provided for
compatibility with earlier SQLWindows/32 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/32 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
Example None
SAM_Help
Sent to Top-level window and MDI window
Event The user pressed the F1 key.
Processing Call SalWinHelp to start an application help system that you created with the
Microsoft Windows Software Development Kit. 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/32 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/32 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
SAM_Print
Sent to Form window, data field, multiline field, combo box, and push button
Event SQLWindows/32 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/32 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 A top-level window or MDI window that started a report
Event When Report SQLWindows/32 is ready to format the first page of a report. Report
SQLWindows/32 sends SAM_ReportFetchInit after sending SAM_ReportStart.
SAM_ReportFetchInit means that Report SQLWindows/32 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
SAM_ReportFetchNext
Sent to A top-level window or MDI window that started a report
Event When Report SQLWindows/32 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
SAM_ReportFinish
Sent to A 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
lParam Not used
SAM_ReportNotify
Sent to A 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. For
more, read RPT_Err* constants on page 13-9.
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 A 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
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
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/32 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_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/32 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/32 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)
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.
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.
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
...
Message Actions
On SAM_ScrollBar
! Show scroll bar position in data
! field 'dfScrollBarPos'
If wParam = SB_ThumbTrack
Set dfScrollBarPos = lParam
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/32 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 which take place when the user enters an object.
Important: 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
SAM_SqlError
Sent to Application Actions section of the outline
Event A SQL function fails.
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.
You can also use When SqlError in any actions section of the outline to process an
error at a local level. For more, read SQL error handling on page 12-18.
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
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:
➀ 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/32 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
!
➀ 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/32 **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.
Important: Timers are a limited resource in Windows, so use as few of them as possible.
Message Variables
hWndForm Handle of top-level window
hWndItem Handle of object receiving message
wParam Timer identifier
lParam Not used
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/32 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/32 does not send SAM_Validate when the user selects a menu item (a
menu selection does not change the focus). You can force SQLWindows/32 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.
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).
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_Ok- Lets the attempted action take place and sets the field edited flag to FALSE.
ClearFlag
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 actions)
lParam Table window context row (first row is zero, second row is one, and so on)
SAM_* summary
In the table below:
• “Y” means that SQLWindows/32 sends the message to the object
• A blank entry means that SQLWindows/32 does not send the message to the
object
Application Actions
Custom control
Option button
Table window
Form window
Multiline field
Radio button
Push button
MDI window
Combo box
Dialog box
Check box
Scroll bar
Data field
List box
Column
Picture
Message
Activate Y Y Y Y
AnyEdit Y Y Y Y
AppExit Y
AppStartup Y
CacheFull Y
Caption Y Y
DoubleClick
Click Y Y Y Y Y Y Y Y Y
Close Y Y Y Y
Column Y Y
SelectClick
CornerClick Y
Corner Y
DoubleClick
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
Application Actions
Custom control
Option button
Table window
Form window
Multiline field
Radio button
Push button
MDI window
Combo box
Dialog box
Check box
Scroll bar
Data field
List box
Column
Picture
Message
DDE_Client Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
Execute
DDE_Client Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
Request
DDE_Data Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
Change
Destroy Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
DoubleClick Y Y Y Y Y
DragCan Y Y Y Y Y Y Y Y Y
AutoStart
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
DropDown Y
DropFiles Y Y Y Y Y Y Y
EndCellTab Y
FetchDone Y
FetchRow Y
FetchRowDone Y
FieldEdit Y Y Y Y Y
Application Actions
Custom control
Option button
Table window
Form window
Multiline field
Radio button
Push button
MDI window
Combo box
Dialog box
Check box
Scroll bar
Data field
List box
Column
Picture
Message
Help Y Y Y Y
KillFocus Y Y Y Y
Print Y Y Y
ReportFetch Y Y Y Y
Init
ReportFetch Y Y Y Y Y Y Y Y
Next
Report Y Y Y
Finish
ReportNotify Y Y Y Y
ReportStart Y Y Y Y
RowHeader Y Y Y Y
Click
RowHeader Y Y Y Y
DoubleClick
Row Y Y Y Y
Validate
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
Chapter 10
Debugging
Debugging is an important part of developing an application. SQLWindows/32 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
Run mode
SQLWindows/32 lets you run an application at designtime 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.
Select Project, Execute or press F7 to enter run mode. To exit run mode, select
Debug, Stop Debugging or press Shift+F7.
Animation
Animation displays an application's code as it executes. As SQLWindows/32
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:
Breakpoints
A breakpoint is a statement in an application where SQLWindows/32 suspends
execution and displays the Debug toolbar where you can:
• Examine the values of variables and expressions
• Track messages
• Check the call stack
• Execute the next SAL statement
• Resume normal application execution
The Debug menu's cascading Breakpoints menu has items you use to manage
breakpoints.
Setting breakpoints
You can set breakpoints in design mode or run mode.
To set a breakpoint:
1. 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.
2. 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 set breakpoints on SAL statements. If the line of code highlighted when
you select Toggle is not a SAL statement, SQLWindows/32 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. For more,
read Preferences on page 4-31.
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 temporarily turn off all breakpoints in the
application. Later, select Breakpoints, Enable All to turn on all breakpoints in the
application.
Immediate breakpoints
You can cause an immediate breakpoint while an application is running by selecting
Debug, Break.
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
Go Expressions
Break 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:
• Run an application with 1 or more breakpoints. SQLWindows/32 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/32 displays the word “(Break)” in its title bar. When
the application is running, SQLWindows/32 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.
Step Into
Executes the next statement and returns control to the Debug toolbar. If the
application calls a function, SQLWindows/32 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/32 executes all the function's statements in
one step and returns to the statement after the function call.
Break
Causes an immediate break.
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. For more, read Docking and undocking toolbars and palettes
on page 2-5.
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.
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/32.
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.
Variables window
Displays the names and values of variables. SQLWindows/32 updates the variable
values at each breakpoint.
Debugging DLLs
To debug DLLs that you write, read Using CodeView with DLLs on page 22-34.
Tips
Test SQL statements
Run SQL statements that you plan to use in a SQLWindows/32 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.
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/32.
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/32 reports compile and evaluation
errors by displaying a message box. If you set bInhibitErrors to TRUE,
SQLWindows/32 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 ( )
Chapter 11
About 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 later in this chapter.
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 or Customizer to display the formats
available for the object. The default format for all objects is unformatted.
Number Date/Time
data type data type
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.
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
# Zero suppression. SQLWindows/32 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.
0 Zero fill. SQLWindows/32 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/32 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/32 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/32 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/32 displays the value in scientific format and adds an E or e. The number of
e+ digits (#'s or 0's) sets the exponent's number of digits. E- or e- places a minus sign by negative
exponents. E+ or e+ places a plus sign by positive exponents
E-
You must start this format with '0' and a period, followed by '0' and/or '#' characters. Place a '+',
e- '-', '#', 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/32 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/32 adds a “-” to the value.
Character Description
_ 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.
Profile-driven formats
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. For more, read Country profiles on
page 11-6.
The data type of the field determines its possible formats. For example, you can
format a number field as currency, decimal, percentage, or unformatted. The table
below lists data types that you can use with each profile-driven format:
Country profiles
Since countries use different ways to express formatted data (such as the currency
symbol), SQLWindows/32 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/32 has internally-defined profiles for certain countries.
When you set Country, SQLWindows/32 uses the format characteristics from the
associated profile.
For example, when you select USA as the country for a formatted currency field,
SQLWindows/32 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.
About 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/32 applications:
• Default validation (for Number and Date/Time data types)
• Input masks
• Custom validation that you write
Default validation
SQLWindows/32 performs default validation for number and date/time data types.
SQLWindows/32 performs default validation as soon as the focus leaves the object. If
an entry is invalid, SQLWindows/32 does not let the user move the focus away from
the object until the entry is correct or the entry is blank.
1. SQLWindows/32 looks in the Regional Settings control panel for the sShortDate
setting. If the entered data matches sShortDate, the data is valid.
2. If the data does not match sShortDate, SQLWindows/32 checks if the data
matches the sLongDate setting. If the entered data matches sLongDate, the data is
valid.
3. If the data does not match sLongDate, SQLWindows/32 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.
4. If the data does not match any of the formats above and the object has a date/time
picture format, SQLWindows/32 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/32 displays an “invalid data” message.
Custom validation
You can replace the SQLWindows/32 default validation with custom validation.
For custom validation, you process the SAM_Validate message for an object.
Whenever the user changes an object, SQLWindows/32 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/32 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',
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/32 beeps.
• Uppercase or lowercase characters. SQLWindows/32 automatically
converts the character if the user enters it in the wrong case.
• Constants. SQLWindows/32 inserts a constant (such as a hyphen) in a
position automatically without the user typing it.
Mask
Matches
character
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/32 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
• When the user moves the focus off a masked number field, SQLWindows/32
formats the field contents according to its output display format
• When the user moves the focus back to a number field, SQLWindows/32
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).
Warning: Because of this behavior, Centura Software Corporation recommends that you not
use input masks with Date/Time fields.
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).
SalFmtGetInputMask
This function returns the input mask of field hWnd in strMask:
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/32 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/32 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/32 removes input mask characters when
you copy a value. If bKeep is TRUE, SQLWindows/32 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.
Chapter 12
SQL Programming
This chapter shows how to access a SQL database from a SQLWindows/32
application and covers these topics:
• Database access cycles
• Error handling
• Database parameters
• Multiuser techniques
• Database browser
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.
Connect
Prepare (compile)
Database
operations Execute
Disconnect
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.
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 need to:
• Specify the database you want to connect to
• Specify the user name and password to use in the connection
• Call the SqlConnect function which returns a Sql Handle
Database name, user name, and password. SQLWindows/32 has three
system variables that identify the database, user name, and password:
• SqlDatabase
• SqlUser
• SqlPassword
You can set these in the Application Actions section. For example:
On SAM_AppStartup
Set SqlDatabase = 'SPA'
Set SqlUser = 'username'
Set SqlPassword = 'userpswd'
The table below shows the default values for these system variables:
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
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.
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/32 checks the INTO clause (for a SELECT statement) and verifies
bind variables. Then, SQLWindows/32 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.
SqlPrepare
SqlPrepareAndExecute
SqlExecute
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 (for more, read
Transaction scope on page 12-25)
SELECTs (queries)
You follow these steps to perform a SELECT:
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
You 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.
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.
Result set
You can set a row position and
start fetching from that row with
SqlFetchNext
Result set
Example
This 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.
In this example, you can replace these two lines:
Set bOk = SqlPrepare( hSqlFetch, strSelect )
Set bOk = SqlExecute( hSqlFetch )
with:
Set bOk = SqlPrepareAndExecute( hSqlFetch, strSelect )
➅ Call SqlFetchNext to get the first row.
➆ After calling SqlFetchNext, check the fetch indicator. The table below lists
the fetch indicators:
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
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 examples below 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 )
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 (Database 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.
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. For more,
read Transaction scope on page 12-25.
Example
This 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 data-
base, but each connection is associated with a different Sql Handle.
➄ Compile and execute the SELECT statement with SqlPrepare and SqlExe-
cute. 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 SqlExe-
cute. The UPDATE statement is associated with the second Sql Handle.
➇ Before exiting the application, disconnect both Sql Handles.
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
Function Description
SqlClearImmediate Disconnects the Sql Handle created with SqlImmediate
SqlConnect
SqlPrepare
SqlImmediate
SqlExecute
SqlFetchNext (for a SELECT)
The first time you call SqlImmediate, SQLWindows/32 performs all of these
functions. On later calls, SQLWindows/32 does not perform the SqlConnect if the Sql
Handle is still connected.
For the SqlConnect, SQLWindows/32 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/32 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/32 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 example below 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 the table below shows:
Internally, SQLWindows/32 uses the SQL/API functions sqlrlo and sqlwlo to read and
write these column data types.
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.
The flowchart below summarizes how you can use When SqlError, SAM_SqlError,
and default error handling.
When
SqlError
?
Perform When
SqlError state-
ments
Application Actions sec-
tion only
Return No
statement
?
Yes SAM_ No
Return value SqlError If a user clicks Halt,
becomes Sql* ? the application ends;
function’s return if a user clicks Con-
Yes
tinue, the Sql* func-
Perform When tion returns FALSE
SAM_SqlError and the application
statements continues.
Return No
statement
?
Default error
Yes
handling
Return value
becomes Sql*
function’s return
End
The flowchart shows the steps that SQLWindows/32 follows when a Sql* function
fails:
1. SQLWindows/32 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/32 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
• If When SqlError does not have a Return statement, SQLWindows/32 looks
for the On SAM_SqlError statement in the Application Actions section
If there is not a When SqlError in the local section, SQLWindows/32 looks for On
SAM_SqlError in the Application Actions section.
2. SQLWindows/32 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/32 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/32
performs its default error handling
If there is not an On SAM_SqlError in the application actions, SQLWindows/32
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.
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.
Function Description
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.
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/32 **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/32
! 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 )
ERROR.SQL
All error messages are stored in a common error message file called ERROR.SQL.
ERROR.SQL contains all error codes that the Sql* functions can cause.
ERROR.SQL must be on the client computer. SQLBase servers also use
ERROR.SQL.
As the diagram below shows, for each error message there is:
• Error message text
• Error reason
• Error remedy
00353EXE NSY Not a synonym
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.
Mnemonic
Search path
SQLWindows/32 looks for ERROR.SQL in these places in this order:
1. Current directory
2. \SQLBASE directory
3. The root directory
4. 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.
Table windows
Use the functions below to display and change database data in table windows.
Chapter 12, Table Windows, explains these 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.
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 explains the parameters you can set to control data operations:
• Functions you call to get and set parameters
• The DBP_* parameters
• System variables
• Input message buffer
• Output message buffer
• Isolation levels
• SQL.INI
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
SqlSetParameterAll (see explanation below).
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.
Important: 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 these parameters with SqlGetParameter and SqlSetParameter:
DBP_BRAND (get)
This parameter shows the brand of the database:
Constant Database
DBV_BRAND_ALLBASE Hewlett-Packard ALLBASE
DBV_BRAND_AS400 IBM AS/400
Constant Database
DBV_BRAND_CINCOM-SUPRA Cincom Supra
DBV_BRAND_DB2 IBM DB2
DBV_ BRAND_INFORMIX Informix
DBV_BRAND_INFORMIX- Informix Online
ONLINE
DBV_BRAND_ORACLE Oracle
DBV_BRAND_ORACLE7 Oracle v. 7
DBV_BRAND_OS2EE IBM OS/2 EE
DBV_BRAND_SQL SQLBase
DBV_BRAND_SYBASE SQL Server
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)
DBP_VERSION (get)
This is the version number of the connectivity software.
System variables
These 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. For more, read Calling
SqlConnect on page 12-4.
SqlInMessage
This system variable contains the size of the input message buffer. For more, read
Input message buffer on page 12-34.
SqlIsolationLevel
This system variable contains the isolation level. For more, read Isolation levels on
page 12-36.
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/32 resets these parameters to their default
settings:
• 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. For more, read
Output message buffer on page 12-35.
SqlPassword
This system variable sets the password to use connect to databases. For more, read
Calling SqlConnect on page 12-4.
SqlResultSet
This system variable turns result set mode on and off for the next connection to a
database. For more, read Result set mode on page 12-9.
SqlUser
This system variable sets the user name to use to connect to databases. For more, read
Calling SqlConnect on page 12-4.
Application 2
hSql1 Input Message Buffer
Input Message Buffer
hSql2 Input Message Buffer
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 2,000 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.
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)
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.
Read the explanation of isolation levels in the SQLBase SQL Reference (SET
ISOLATION) for more.
SQL.INI
SQLWindows/32 reads SQL.INI to determine the database servers that the application
can access. SQLWindows/32 looks for SQL.INI in this order:
1. Current directory
2. \SQLBASE (in current drive)
3. Root directory (in current drive)
4. As specified by the PATH environment variable
For more about SQL.INI, see the SQLBase Database Administrator's Guide.
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 flowchart on the next page 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.
ROWID Validation
Start
Prepare and
Include the ROWID in
execute a
the SELECT list
SELECT
Fetch rows
User changes
a row
No
Successful
?
Yes No
ROWID
valid
COMMIT ?
Yes Error
processing
“Changed-row”
processing
When SqlError
or
SAM_SqlError
End
Example
In the example on the next page, if the SQL error is an invalid ROWID, the When
SqlError statements:
➀ Turn on DBP_FETCHTHROUGH to tell SQLWindows/32 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
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
!
Stored commands
Call these 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.
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.
SqlVarSetup
Call SqlVarSetup to change the default behavior:
bOk = SqlVarSetup( hSql )
SqlVarSetup saves the current execution context. When you execute or fetch later,
SQLWindows/32 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
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.
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 that you specify in SqlOpen you also use 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. For more, read ROWID validation on page 12-37.
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. For more, read the online help.
SQL troubleshooting
This section explains common SQL problems and their solutions.
Chapter 13
Report Programming
This chapter explains how a SQLWindows/32 application can print and display
reports based on report templates created with Report Builder, including:
• SalReport* functions
• SAM_Report* messages
• RPT_* constants
The diagram below shows the designtime and runtime environments of Report
Builder:
Displayed or
printed reports
As used in this chapter, the term Report Builder means the collection of files that
make up the designtime and runtime environments.
Designtime
At designtime, 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/32
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/32 application. Read Reporting with Centura Team Developer 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 which 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.
• A report footer at the end (such as grand totals).
Input items
A SQLWindows/32 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 designtime, 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 designtime, you specify input variables through the Format menu.
Runtime
At runtime, Report Builder requests and receives data from a SQLWindows/32
application, formats it, performs calculations, and displays or prints the report.
A SQLWindows/32 application communicates with Report Builder by calling
SalReport* functions; Report Builder communicates with SQLWindows/32
applications through SAM_Report* messages. The SQLWindows/32 application is
called the server because it supplies data; Report Builder is the client because it
request data.
At runtime, a SQLWindows/32 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
Sections in this chapter show examples for each of these
The report template and the SQLWindows/32 application are independent of each
other. The SQLWindows/32 application calls a SalReport* function that specifies the
name of the report template. Then, Report Builder sends messages to the
SQLWindows/32 application to ask for data. The data that the application sends must
correspond to the input items defined in the report template.
The diagram below shows the basic steps you follow to display or print a report:
➀ SalReportView Report
or template
SalReportPrint
➁ SAM_ReportStart
➂ SAM_ReportFetchInit
➃ SAM_ReportFetchNext
Fetch
data
➄ SAM_ReportFinish
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/32. For all SAM_Report* messages, the wParam contains the handle
of this window.
When this function executes, SQLWindows/32 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
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 designtime, SQLWindows/32 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/32 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:
The strCaption, strLine1, and strLine2 parameters are strings that SQLWindows/32
displays in the dialog. The strDocName parameter is the string that Windows print
manager displays.
Example
This example shows a menu item that calls SalReportPrint:
➀ Set nOptions to RPT_PrintAll to print all pages in the report. Set nCopies to
1 to print 1 copy of the report.
➁ Call SalReportPrint.
➂ The SAM_ReportStart processing:
• Calls SalReportDlgOptions to create a custom dialog that is displayed
while printing
• Connects to a database
➃ The SAM_ReportFetchInit processing calls SqlPrepare and SqlExecute for
the SELECT statement.
➄ The SAM_ReportFetchNext processing calls SqlFetchNext. After the last
row has been 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.
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
...
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 designtime
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).
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
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:
➀ Call SalReportView. The second parameter tells Report Builder the name of
a form window defined in the application to use to display the report.
➁ The frmView form window that displays the report has top-level menu items
that call SalReportCmd.
Form Window: frmMain
...
Menu Item: &Display Report
...
Menu Actions
Set nError = 1
➀ Set hWndReport = SalReportView( frmMain, frmView,
RPT_Template, RPT_Variables,
RPT_Inputs, nError )
...
Form Window: frmView
...
➁ Menu Item: First!
...
Menu Actions
Call SalReportCmd( hWndReport, RPT_CmdFirstPage )
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.
SalReportReset causes SAM_ReportFetchInit and SAM_ReportFetchNext messages.
Example
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:
➀ Set the b300 Boolean to TRUE.
➁ Call SalReportReset.
➂ The SAM_ReportFetchInit processing checks the b300 Boolean. If it is set,
the code prepares and executes the SELECT statement. The SELECT state-
ment 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
➀ Set b300 = TRUE
➁ If NOT SalReportReset( hWndReport )
Call SalMessageBox( 'Report Error', 'SalReportReset',
MB_Ok | MB_IconHand )
Set b300 = FALSE
...
Form Window: frmMain
...
Message Actions
➂ 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.
With SalReportView, SalReportClose is the same as the user double-clicking the
system menu of the report view window and the application calling
SalDestroyWindow.
Example
The example below 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.
Function Description
SalReportSetDateTimeVar Sets a Date/Time input variable
SalReportSetNumberVar Sets a Number input variable
SalReportSetObjectVar Sets an object input variable
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
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 tables below.
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:
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 )
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.
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:
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 )
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.
Example
This example shows three menu items that call:
➀ SalReportTableCreate
➁ SalReportTableView
➂ SalReportTablePrint
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
...
➀ 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 )
➁ 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 )
➂ 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
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
Chapter 14
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
A complete
horizontal
line of cells
is a row
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 If Yes, the table window has a toolbar and a status bar and the Accessories item is
Enabled enabled where you can turn off the toolbar or status bar. The default is no.
Accessories If the Accessories Enabled item is yes, then you can use this cascading menu to turn off
the toolbar or status bar and to set the size and position of the toolbar.
Automatically If Yes (default), the window is created and displayed at application startup. If No, you
Create 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.
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.
Property Description
Discardable If Yes (default), rows in the table window cache are discardable. SQLWindows/32 makes
space for new rows by discarding unused rows. If No, SQLWindows/32 does not
automatically discard rows and keeps all data in the cache.
Max Rows in The number of table window rows that can be stored in the cache. The default is 100 and
Memory the maximum is 2,147,423,632 rows. Please see the section Table Window Cache
Beginning on page 14-33 for more details.
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 Displays a cascading menu with the table window's position (top and left) and size (width
Size and height).
Location and Displays a cascading menu with the table window's position (top and left) and size (width
Size 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 If Yes, users can drag and resize rows at runtime. You can also change this setting
sizing dynamically at runtime by calling SalTblDefineRowHeader and specifying
TBL_RowHdr_RowsSizable.
Discardable If Yes (default), rows in the table window cache are discardable. SQLWindows/32 makes
space for new rows by discarding unused rows. If No, SQLWindows/32 does not
automatically discard rows and keeps all data in the cache.
Max Rows in The number of table window rows that can be stored in the cache. The default is 100 and the
Memory theoretical maximum is 2,147, 423,632 rows. Please see the section Table Window Cache
beginning on page 14-33 for more details.
Adding columns
You can add columns like other child objects by:
• Clicking the column push button in the Controls toolbar
OR
• Selecting Column in Coding Assistant
OR
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.
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”.
Note: A user can also move and resize columns using these mouse pointers at runtime.
Column attributes
The table below describes the attributes for a table window column.
To display the Attribute Inspector for a column, position the mouse pointer on the
column heading and click. To display the Customizer for a column, position the
mouse pointer on the column heading and double-click.
Property Description
Object The title in the column heading. Create a mnemonic by adding an ampersand (&) before the letter
Title that is the mnemonic.
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 The width of the column in inches. The default is 1.2 inches.
Width
Max Data The maximum number of characters that the user can enter in the column. The default is 100. The
Length 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 that you specify in Max Data Length is the maximum capacity of the
object, not the number of bytes that SQLWindows/32 allocates for the object’s value. At runtime,
SQLWindows/32 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/32 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.
Property Description
Drop When you set the Cell Type to Drop Down List, you can set this to:
Down List
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 User can type new text as well as choosing an item from the list
Note: You can call any SalList* function for a column that you set as a drop down list, except for:
• SalListFiles
• SalListGetMultiSelect
• SalListQueryFile
• SalListQueryMultiCount
• SalListSetMultiSelect
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.
Format The output format of the column. The default is unformatted. For more, read Chapter 11,
Formatting and Validating.
Input Mask Input validation criteria for the column. For more, read Chapter 11, Formatting and Validating.
Country The country profile for the column. For more, read Chapter 11, Formatting and Validating.
Property Description
Word When the lines per row is two or more, you can set this property to Yes so that text in the cell
Wrap wraps automatically.
User interface
This section explains basic table window functions from the point of view of a user.
Note: A user can also move and resize columns using the mouse pointers explained in the
section called Moving and Sizing Columns earlier in this chapter.
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.
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.
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.
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 Moves the focus frame down. Selects or deselects the focus row just as the previous row.
Arrow
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.
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.
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.
Ins Selects the focus row. Puts the table window in cell mode.
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.
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
• Advanced technique
You can mix and match the two techniques.
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.
Code examples
Note the following about the 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.
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.
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 steps which follow 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:
1. 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 )
2. 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 ) ' )
3. 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 transaction. It is better to wait until you have successfully inserted all rows
are before clearing the ROW_New flag.
4. COMMIT or ROLLBACK the INSERT.
5. Set the table window row number to TBL_MinRow:
Set nRow = TBL_MinRow
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:
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 which
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:
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/32 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/32 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/32
sends one SAM_FetchRow message for each row that is visible on screen. As the
user scrolls, SQLWindows/32 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 delete operation described below, 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:
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/32 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 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.
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).
The user can now enter data in the cells of the new table window row.
For the second part, the steps below in the Menu Actions section for the Apply
Changes menu item INSERT into the database one or more new rows that the user
entered:
1. 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 that the user entered:
Call SalTblKillEdit( twCompanyInfo )
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 data source until the user selects the Apply
Changes menu item. The steps below in the Menu Actions section 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 (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/32 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.
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/32 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 this statement:
Set varName = :twCompanyInfo.colName
: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.
SQLWindows/32 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.
Note: Please see the section Table Window Cache beginning on page 14-33 for more details.
Constant Description
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 example below 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 )
SAM_FetchRow message
SQLWindows/32 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/32 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/32 sends
a SAM_FetchRow message for each row that is visible on screen
• As the user scrolls, SQLWindows/32 sends a SAM_FetchRow message for
each row
SQLWindows/32 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/32 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
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.
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.
SAM_CountRows message
SQLWindows/32 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/32 sends SAM_FetchRow messages until the
application returns TBL_NoMoreRows. However, the application performs better if
it processes SAM_CountRows.
SAM_CountRows does not use lParam.
The example below calls SalTblSetRange and specifies TBL_MaxRow in the third
parameter (dynamic table range). When the user moves the slider box to the bottom
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.
SAM_CacheFull message
SQLWindows/32 sends this message to a table window when a row is to be fetched,
but the table window cache is full and SQLWindows/32 cannot discard any rows.
SQLWindows/32 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. However, see the Table Window Cache section on page 14-33 for
more details.
The lParam for SAM_CacheFull is the row number the table window tried to fetch.
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_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_SingleSelection FALSE When TRUE, users can only select one row at a time in the
table window.
TBL_Flag_SuppressLast- FALSE When TRUE, SQLWindows/32 does not display the last
ColLine vertical column separation line.
TBL_Flag_SuppressRow- FALSE When TRUE, SQLWindows/32 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_HideMarks Do not use the symbols in the default row header. For more, read Row header on
page 14-45.
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 example below uses SalTblFindNextRow to search for rows with the
ROW_New flag set to TRUE. Once SQLWindows/32 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
Constant Description
COL_IndicateOverflow Fill the column cell with '#' when the text does not fit (except when the cell has
the focus).
TBL_Error constant
SQLWindows/32 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
SAM_CaptionDoubleClick
SQLWindows/32 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/32 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/32 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/32 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
SAM_AnyEdit
SQLWindows/32 sends this message to a table window and column when the user
edits a cell.
SAM_Click
SQLWindows/32 sends this message to the table window and the non-editable
column when the user clicks in a non-editable column.
SAM_DoubleClick
SQLWindows/32 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/32 sends the table
window and the non-editable column:
• SAM_Click
• SAM_DoubleClick
SAM_FieldEdit
SQLWindows/32 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/32 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.
SAM_Close
SQLWindows/32 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/32 does not send a SAM_Close message to a child table window since
a child table window does not have a system menu and cannot be closed.
Focus cell
Use SalTblKillEdit to end editing and force SQLWindows/32 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/32 to validate the data.
After calling SalSendValidateMsg, the table window is in cell mode.
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
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.
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
These functions return a column identifier:
• SalTblCreateColumn
• SalTblQueryColumnID
You can also use column identifiers in references (see below).
To get the window handle of a column, call SalTblGetColumnWindow and specify
either the column identifier or the column position.
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:
Call SalTblDefineRowHeader(hWndTbl, strTitle, nWidth,
TBL_RowHdr_Visible | TBL_RowHdr_ShareColor, colRowHeader )
SAM_RowHeaderClick
SQLWindows/32 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/32 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/32 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/32 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.
Constant Description
Constant Description
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.
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.
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
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.
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.
Function Description
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.
Constant Description
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.
For more, read Updating rows on page 14-23.
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/32 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/32 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 designtime.
SalTblCreateColumn
This function creates a table window column automatically at runtime:
bColID = SalTblCreateColumn( hWndTbl, nColumnPos,
nDispWidth, nMaxChars, strTitle )
The columns that this function creates are not available at designtime.
Note: SQLWindows/32 assumes that the data type of a column you create with
SalTblCreateColumn is String.
If you set Discardable attribute to Yes, SQLWindows/32 discards rows when you call
SalTblCreateColumn. If you set Discardable to No, SQLWindows/32 expands rows
when you call SalTblCreateColumn.
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.
Messages
SQLWindows/32 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/32 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/32 ignores any value you return when you process this message.
Note: 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.
The specific cell that SQLWindows/32 checks or set is at the intersection of the
context row and the column you specify.
Chapter 15
Option Buttons
This chapter shows how to add option buttons to SQLWindows/32 applications.
Option buttons are rectangular buttons that display an image and text on a window,
toolbar, or palette.
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 Displays a cascading menu with the option button's position (top and left) and size (width
Size and height).
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).
Picture Displays a palette where you select a color in the image that you want to replace with the
Transparent background color of the option button. This makes parts of the image transparent. This
Color 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 The background color of the option button.
Color
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 The font enhancement of text in the option button.
Enhancement
State
Style Corners Focus frame Behavior
changes
Radio Round Yes Radio Up
Check Box Round Yes Check Box Up
Palette Square No Radio Down
Single-image style
For the single-image style, SQLWindows/32 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/32 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/32 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.
Chapter 16
MDI Windows
This chapter shows how to create and use MDI windows in SQLWindows/32
applications.
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.
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, the MDI window has a toolbar and a status bar and the Accessories item is enabled
Enabled where you can turn off the toolbar or status bar. The default is no.
Accessories If Accessories Enabled is Yes, then you can use this cascading menu to turn off the
toolbar or status bar and to set the size and position of the toolbar.
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.
Location and Size Displays a cascading menu with the MDI window's position (top and left) and size (width
and height).
Outline items
An MDI window outline has these items:
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.
SAM_Destroy
SQLWindows/32 sends SAM_Destroy to an MDI window and its children in this
order:
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
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 Return
parameter
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.
An example of a windows menu is shown below:
The developer specified the first four items in the menu in the same way as regular
popup menu items. SQLWindows/32 added the last three items and the menu
separator automatically.
The default title of the popup menu is “Windows”, but you can change it.
Chapter 17
Pictures
This chapter shows how to create and use picture objects in SQLWindows/32
applications. This chapter explains:
• Picture properties
• Messages and functions you can use with pictures
About 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
• 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 table below describes the attributes for a picture.
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 Displays a cascading menu with the form window's position (top and left) and size (width
Size 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.
Picture Displays a cascading menu that has editing commands. For more, read Picture Contents
Contents cascading menu on page 17-4.
Property Description
Picture Displays a palette where you select a color in the image that you want to replace with the
Transparent background color of the option button. This makes parts of the image transparent. This
Color 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, pass
COLOR_None to SalColorSet.
Picture Fit How to fit the image in 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 If Yes, the picture fills the background of the parent object.
Parent
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 The border thickness. The default is 1.
Thickness
Background Displays a palette where you can set the color of the background (the area of the picture not
Color covered by an image).
Border Color Displays a palette where you can set the color of the picture border.
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/32 copies the image
file into the application. If you set the File Storage item to External, SQLWindows/32
finds and displays the image file at runtime and designtime.
File Storage
The method that SQLWindows/32 uses to store the image:
External. SQLWindows/32 reads the image from a disk file at both runtime and
designtime. You must distribute the external file with production versions of an
application.
Internal. SQLWindows/32 stores the picture image in the application at runtime.
SQLWindows/32 must be able to find the image in an external file at designtime.
When you make an *.EXE version of an application, SQLWindows/32 copies the
image from the file into the application. You do not need to distribute the external file
with production versions of an application.
Paste From
This menu item displays a dialog so you can select a file to paste into the picture with
the focus.
Choose the file's name and directory from the File Name and Folders lists or type the
full path name in File Name.
You can change the type of files displayed and the drive with the combo boxes at the
bottom of the dialog. You can retrieve these image file types:
SQLWindows/32 converts the image from one of these formats to display a bitmap.
You can select any type of file. If you select a file type that is not in the table above,
SQLWindows/32 pastes it in the picture with the generic document icon shown on
the left.
The contents of the file are available to SQLWindows/32 through the SalPicGetString
function. For example, you can use SalPicGetString to copy the file to a string. Then,
you can write it to a database or file.
Clipboard
File
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.
Message
Description
variable
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.
SalEditCopyTo
This function displays a dialog so a user can copy the image with the focus to a file:
bOk = SalEditCopyTo( )
SalEditPasteFrom
This function displays a dialog (the same as the one displayed by Picture Contents,
Paste From in the Customizer—read Paste From on page 17-5) so a user can select a
file to paste into the picture with the focus:
bOk = SalEditPasteFrom( )
A user can retrieve the image file types listed in the table for SalEditCopyTo above.
SQLWindows/32 converts the image from one of these formats to display a bitmap.
A user can select any type of file. If the file type a user selects is not in the table
above, SQLWindows/32 pastes it in the picture using the generic document icon
shown on the left.
The contents of the file are available to SQLWindows/32 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, read Storing pictures in a database on page 17-12.
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, read Storing pictures in a database on page 17-12.
Clipboard
File or
database
Inserting pictures
To insert an picture in a database:
➀ 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.
➁ Prepare, execute, and commit the INSERT command.
➀ Call SalPicGetString( picObject, PIC_FormatObject, lsImage )
➁ 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:
➀ Prepare and execute the SELECT command.
➁ 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.
➀ 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 )
➁ Call SalPicSetString( picObject, PIC_FormatObject, lsImage )
Updating pictures
To update a picture in a database:
➀ 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.
➁ Prepare, execute, and commit the UPDATE command.
➀ Call SalPicGetString( picObject, PIC_FormatObject, lsImage )
➁ Call SqlPrepare(hSql, 'update SWOBJECT
set descr = :mlDescr, image = :lsImage, fit = :cbFit
where ROWID = :strRowIDs[nCurrentRow]')
If SqlExecute(hSql)
Call SqlCommit( hSql )
SalPicSet
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 )
Chapter 18
Drag-and-Drop
This chapter explains the functions and messages that you use to write a drag-and-
drop interface in a SQLWindows/32 application.
About drag-and-drop
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 or File Manager window
to an application window.
Terms
Drag mode. While in drag mode, SQLWindows/32 suspends the mouse's normal
operation until the user releases the mouse button. Also, SQLWindows/32 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.
Drag-mode events
SQLWindows/32 informs an application about drag mode events by sending
messages to both the source and target windows.
Auto dragging
SQLWindows/32 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/32 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/32
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.
Application-defined cursors
SQLWindows/32 displays default cursors to indicate drag mode to the user. When
drag mode starts, SQLWindows/32 displays a special cursor to indicate this to the
user. When drop is disabled, SQLWindows/32 displays a different cursor.
You can override the default cursors that SQLWindows/32 provides. You can
associate up to three types of application-defined cursors with a window.
Window Cursor. SQLWindows/32 displays this cursor when a window is not in
drag mode.
Drag Cursor. SQLWindows/32 displays this cursor when a window is in drag mode
and dropping is enabled.
Disabled Drop Cursor. SQLWindows/32 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:
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.
SAM_DragStart
SQLWindows/32 sends this message when drag mode starts.
wParam X coordinate in the window
lParam Y coordinate in the window
SAM_DragEnd
SQLWindows/32 sends this message when drag mode ends.
wParam Not used
lParam Not used
SAM_DragNotify
SQLWindows/32 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
SAM_DragDrop
SQLWindows/32 sends this message when the user drops the mouse on this target
window.
wParam Handle of a source window
lParam Not used
SAM_DragExit
SQLWindows/32 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/32 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:
➀ The lb1 list box is the source window. When the user holds down the mouse
button for an interval, SQLWindows/32 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.
➁ SQLWindows/32 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/32 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
List Box: lb1
...
List Initialization
Text: Value 1
...
Message Actions
➀ On SAM_DragCanAutoStart
If SalListQuerySelection( hWndItem ) != LB_Err
Return TRUE
Else
Return FALSE
➁ On SAM_DragStart
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 (read File dropping functions on page 18-10) to enable file
dropping on a window. 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.
SAM_DropFiles message
SQLWindows/32 sends this message to a window when the user drops a file or files
from Explorer or File Manager on the window. SQLWindows/32 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.
Chapter 19
Libraries
This chapter shows how to write and use:
• Include libraries
• 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/32 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.
Include
library Application 1
(*.APL) (*.APP)
Application 2
(*.APP)
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.
Nested includes
You can nest included items. An include library can contain items from other
libraries.
SQLWindows/32 displays included items in the color that you specify in Tools,
Preferences. On monochrome computers, SQLWindows/32 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.
Component menu
The sections below explain the menu items in the Component menu.
Go To Item (F5)
Starts a new instance of SQLWindows/32 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/32, the first instance of SQLWindows/32
resumes.
Unless you uncheck Refresh When Changed in Tools, Preferences (page 4-31),
SQLWindows/32 detects that one of the included items has changed and
automatically re-includes the changed include library.
When you edit an included item in an include library, the target item is selected in the
include library.
Refresh
Re-includes 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/32 displays a warning dialog
before completing the merge.
Tools, Preferences
General tab: Refresh When Changed.
By default, SQLWindows/32 automatically detects changes in libraries and re-
includes 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 re-include is time-consuming.
can display them with bold, italic, or underline styles, or with no special property. On
monochrome computers, SQLWindows/32 always displays included items in italics.
Running
applications
A
Compiled
Dynalib
Objects
and B
functions
A dynalib shares its objects and functions with other applications. This is called
exporting. Other applications use the items. This is called importing. The diagram
shows an overview of the process of creating and using dynalibs:
C re a te a d yn a lib s o u rc e
file (*.A P L ) w ith th e
ite m s yo u w a n t to
e x p o rt
C o m p ile th e d y n a lib
*.A P L s o u rc e file to
c re a te th e *.A P D
ru n tim e lib ra ry
Im p o rt th e
ite m s in o th e r
a p p lic a tio n s
T o d e p lo y , in s ta ll
c o m p ile d d yn a lib s
(*.A P D ) w ith o th e r
ru n tim e file s
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 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 this example, the declarations mean the dynalib exports
numGInLib1 and strGInLib1:
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/32 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/32 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
Version compatibility
When a new version of Centura 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.
UDVs. You can pass UDVs (user-defined variables) 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 )
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 )
Chapter 20
ActiveX programming
This chapter explains how to write ActiveX client applications, including:
• ActiveX controls
• ActiveX container controls
• ActiveX container control SAL API
• In-place activation
• ActiveX automation
• ActiveX Wizard
• Creating an ActiveX component
• Exception handling
Overview
ActiveX (formerly called OLE) is the most popular component development
architecture on Windows platforms. A component is a discrete unit of code that
delivers a well-specified set of services. An ActiveX component is a runtime instance
of code, memory, resources, and execution state, either a process or a DLL, that uses
or provides ActiveX interfaces. Centura SQLWindows/32 provides optimum support
for using ActiveX components in several ways.
When building an application, you can use ActiveX objects directly in the Centura
SQLWindows/32 development environment. Visual components appear on the
Controls palette for direct use in the user interface design. The functions (methods)
and variables (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. You can use
ActiveX components developed in other products in the Centura SQLWindows/32
development environment.
You can use two kinds of ActiveX components—controls and insertable objects—in
several ways:
• ActiveX controls are in-process components that can support events and
automation. You use ActiveX controls the same way that you use Centura
SQLWindows/32's built-in child objects.
• You place insertable objects in Centura SQLWindows/32's ActiveX
container control. Insertable objects use the OLE documents interface and
support embedding and automation. A runtime container control is also
provded and can be primed with an object either at designtime or at runtime
using one of the SalActiveX* API functions.
You can use ActiveX automation to programmatically manipulate ActiveX
components. A server is a COM object that provides an interface (or interfaces) that
someone else might want to use, and a client is a COM object which uses an interface
by calling one or more of its methods. ActiveX automation allows clients to control
components from ActiveX servers using Centura SQLWindows/32 code. You can
code to directly manipulate ActiveX automation components, using all the
component's properties and methods in an application.
ActiveX objects are imported into the outline as (global) functional classes. They all
share the common base class Object. The Object class represents an ActiveX dispatch
interface. It lets you call methods and set/get properties on an ActiveX object. The
Variant class represents the ActiveX VARIANT runtime data type.
ActiveX components support properties, methods, and events. A component's data
(settings or attributes) are called properties, while the procedures that can operate on
the component are called methods. An event is an action recognized by a component,
such as clicking a mouse or pressing a key, and you can write code to respond to that
event.
Centura SQLWindows/32 fully supports ActiveX semantics such as embedding,
automation, menu merging, toolbar negotiation, and events.
Getting started
Start by reading the topics ActiveX controls (page 20-5) and ActiveX container
controls (page 20-6) to become familiar with the types of ActiveX components. If you
are using a container control, also read the topic ActiveX container control SAL API
(page 20-8). You should also read the topic In-place activation (page 20-9).
For most applications, you will use the ActiveX Wizard to automatically generate a
functional class that invokes the methods of the ActiveX component. Read the topics
ActiveX automation (page 20-10), ActiveX Wizard (page 20-11), and Creating an
ActiveX component (page 20-3).
For advanced applications, you can write code that invokes a component's methods
directly. For that, you need to read the topics Object class (page 20-15) and Variant
class (page 20-18).
the right of existing ActiveX component buttons. To remove a button, drag it off the
palette.
ActiveX button
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
OR
Select an ActiveX component in the list, click the right mouse button and select
Add to Palette.
3. When you want 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 designtime using the Insert Object dialog:
1. Click the ActiveX button in the Controls palette.
2. Draw the object on the top-level window as you would any other object. The Insert
Object dialog appears.
3. Select an insertable object in the dialog and click OK.
To create an ActiveX insertable object at designtime using the Paste Special dialog:
1. Click the ActiveX button in the Controls palette.
2. Draw the component on the top-level window as you would any other object. The
Insert Object dialog appears.
3. Click Cancel.
4. Later, select the insertable object and right click the mouse and select Paste
Special. The Paste Special dialog appears.
5. In the Paste Special dialog, set the options and click OK.
To create an ActiveX insertable object at runtime using the SAL ActiveX API:
1. Click the ActiveX button in the Controls palette.
2. Draw the component on the top-level window as you would any other object. The
Insert Object dialog appears.
3. Click Cancel.
4. In your application logic, call a SAL ActiveX API function to create the object.
ActiveX controls
An ActiveX control is a lightweight, in-process object. An ActiveX control typically
implements IDispatch (automation) and type information, and can have events. An
ActiveX control has an *.OCX extension.
Events
If an ActiveX control has defined events, Centura SQLWindows/32 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.
Attribute Inspector
When an ActiveX control is selected, the Attribute Inspector displays the properties
of the control and you can edit them.
Ambient properties
ActiveX controls 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.
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.
Name Description
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.
In-place activation
With an ActiveX object that 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.
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 Windows Help
group group group group group group
(client) (server) (client) (server) (client) (server)
You identify which menus belong to the client's File, Container, and Window groups
in the menu editor (select Component, Menu Editor). In the Menu Editor, there is
an ActiveX Menu Group combo box where you associate a menu with one of the
client groups. For more, read Menu Editor on page 6-10.
ActiveX automation
ActiveX 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 ActiveX object must support the IDispatch interface.
There are two type of automation: dynamic and static.
Dynamic automation
With dynamic automation, you use the methods of the Object class directly to make
calls to the server. No type information is used and invalid invocations can cause
runtime errors.
Static automation
With static automation, type information is available at compile time (early bound)
and all calls are typechecked for validity. You use the ActiveX Wizard is used to
generate statically bound automation classes.
...
xlapp.Create( ’Excel.Sheet.8’ )
Push any parameters onto the stack and then invoke the method:
xlapp.PushStringByRef( "hello" )
xlapp.Invoke( "SetActiveCell", INVOKE_FUNCTION )
ActiveX Wizard
An ActiveX object appears as a functional class in the outline. The functional class is
derived from the Object base class. You use the ActiveX Wizard 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.
The ActiveX Wizard lists all the type libraries available on the computer. You can
select any set of interfaces.
To use the ActiveX Wizard:
1. Select Component, ActiveX Wizard.
2. Select the type library you want to use or click Browse to find and register an
unregistered type library.
3. Click Next. Select the interfaces and coclasses that you want to use by checking
them.
6. Click Finish.
description Explanation
helpFile Help file path
helpContext Help context ID
Object class
The Object class represents an ActiveX dispatch interface. You use it to call functions
and get and set properties on an ActiveX object.
Functions
This class has the functions in the table below. For details about these functions, read
the online help.
Name Description
FlushArgs Call this function after popping parameters off the stack to reset the stack
Push* Pushes a parameter value onto the stack before invoking a method.
Push*ByRef Pushes a parameter value by reference onto the stack before invoking a
method. Use this function to push values onto the stack for ActiveX in-
process servers.
Name Description
Invoking methods
To invoke a method, you must:
1. Push parameters onto the stack, either by value or by reference
2. Execute the method by calling Invoke
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 the ActiveX Wizard generate it
automatically and then use that as a starting point. The examples below show the
code that is generated by the ActiveX Wizard.
ActiveX collections
A collection object contains a set of related objects. You can work with the objects in
a collection as a single group rather than separate entities. Servers use a collection to
hold a number of items of the same type. SQLWindows/32 supports ActiveX
collections with these methods in the Object class:
• IsCollection
• Next
• Reset
• Skip
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.
Centura SQLWindows/32 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/32's native arrays and Strings as much as
possible and only convert to a SafeArray when required for ActiveX.
Functions
This class has the functions in the table below. For details about these functions, read
the online help.
Name Description
Automation type
constants Description SalType constants SAL data type
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, but causes significant performance problems if used for general purpose SAL
programming. Instead, you should use SQLWindows/32's native arrays and Strings as much as
possible and only convert to a SafeArray when required for ActiveX.
Functions
This class has the functions in the table below. For details about these functions, read
the online help.
Name Description
Chapter 21
About DDE
DDE (Dynamic Data Exchange) is a Microsoft Windows message protocol that
applications can use to exchange data. Through DDE, applications can send data to
and receive data from other applications on the same computer. In other words, DDE
lets cooperating applications share data.
Examples of DDE applications are:
• Compound documents that combine data from word processing applications,
graphics applications, spreadsheet applications, or database applications
• Real-time data acquisition for stock market and commodity prices, scientific
instruments, and process control instruments
The DDE messages are built into Microsoft Windows.
Important: If you write a SQLWindows/32 application that talks to another DDE application,
be sure to determine how the other application supports DDE. The other application must
support the CF_TEXT format.
Simple interface
This interface is easier to use than the advanced interface. The simple interface uses a
few function calls and messages.
The simple interface is flexible enough for most DDE applications. Use the simple
interface the first time you write a DDE application.
Advanced interface
The advanced interface is more complex than the simple interface and has more
function calls and messages. The trade-off for the additional complexity is that you
have maximum flexibility and can perform any DDE operation.
DDE concepts
Conversations and messages
Two applications exchange data through DDE in a conversation. The applications
carry on a DDE conversation by sending messages to each other.
The simple DDE interface has 3 messages. The advanced DDE interface has 9
messages.
Conversation
Service
Topic Topic
Items Items
Window Handles
A DDE conversation takes place between two windows, one for each of the
participating applications. The window can be the “main” window of the application,
a hidden (invisible) window, or any other window that can receive messages.
An application can carry on several DDE conversations at the same time. For
example:
• A client can receive data from multiple servers
• A server can send data to multiple clients
• An application can act as the client in some conversations and as the server in
other conversations
A DDE application must provide a different window for each of its conversations
with another DDE application. A DDE conversation is identified by a pair of window
handles, so there should be no window engaged in more than one conversation with
another window.
You can ensure that a pair of client and server windows is never involved in more than
one conversation by creating a hidden window for each conversation. The sole
purpose of these hidden windows is to process DDE messages.
Because the client and server window handles together identify a DDE conversation,
you cannot change the service name and the topic name during a conversation.
Called
Function Description
by
SalDDEStartServer Server Server is ready to start conversations with clients
SalDDEStopServer Server Server no longer wants to start conversations with clients
SalDDEStartSession Client Starts a conversation with a server
SalDDEStopSession Client Ends a conversation with a server
SalDDESendToClient Server Sends data to clients
SalDDERequest Client Asks a server to send data
Called
Function Description
by
SalDDESendExecute Client Sends a command string to a server
SalDDEGetExecuteString Server Gets a command string that a client sent
Message Description
SAM_DDE_DataChange Tells a client that the server has sent data
SAM_DDE_ClientRequest Tells a server that a client has requested data
SAM_DDE_ClientExecute Tells a server that a client has sent a command string
The table below shows how each of these messages use the lParam and wParam
parameters:
Hot link
In a hot link DDE conversation, the server sends data to the client automatically.
The next sections use code fragments from a SQLWindows/32 DDE client
application and a SQLWindows/32 DDE server application to show how a hot link
works.
The diagram below shows the basic steps that a DDE client and server perform during
a hot link.
Client Server
Application Application
SalDDEStartServer
SalDDEStartSession
SalDDEStopSession
SalDDEStopServer
The DDE service, topic, and item represent the data that clients request.
Set dfService = 'SWServer'
Set dfServerTopic ='frmMain'
Set dfServerItem ='dfServerData'
...
Call SalWaitCursor( TRUE )
If NOT SalDDEStartServer( frmMain,
dfService,
dfServerTopic,
dfServerItem )
Call SalWaitCursor( FALSE )
Call SalMessageBox( 'SalDDEStartServer failed',
'DDE Error',
MB_Ok | MB_IconHand )
Else
Set dfServerStatus = 'DDE server started'
Call SalWaitCursor( FALSE )
A given window handle (first parameter) can only be associated with one service,
topic, and item. This means that for each given service, topic, and item that a DDE
server supplies, you must:
• Use a different window handle. You can use hidden windows for this purpose
• Call SalDDEStartServer
More than one DDE client can connect to the same service, topic, and item at the
same time.
Cold link
In a cold link DDE conversation, the client and server can interact in one of two
ways:
• The client can request data from a server by calling SalDDERequest. Unlike
a hot link, the server sends data only when the client requests it.
• The client can send commands to a server by calling SalDDESendExecute.
The nature of the commands (including whether the server returns data or any
other response to the client) is defined by the applications.
During a hot link, a client application can call SalDDERequest and
SalDDESendExecute just as during a cold link.
The next two sections show how data requests and command requests work.
Data requests
The next sections use code fragments from a SQLWindows/32 DDE client application
and a SQLWindows/32 DDE server application to show how data requests work.
The diagram below shows the basic steps that a DDE client and server perform to
process data requests.
Client Server
Application Application
SalDDEStartServer
SAM_DDE_ClientRequest
SalDDERequest
SAM_DDE_DataChange
SalDDESendToClient
SalDDEStopServer
The server application must still call SalDDEStartServer as with a hot link. However,
the client does not need to call SalDDEStartSession and SalDDEStopSession.
The server calls SalDDEStartServer and SalDDEStopServer in the same way as
shown before.
Command requests
The next sections use code fragments from a SQLWindows/32 DDE client
application and a SQLWindows/32 DDE server application to show how command
requests work.
The diagram below shows the basic steps that a DDE client and server perform to
process command requests.
Client Server
Application Application
SalDDEStartServer
SAM_DDE_ClientExecute
SalDDESendExecute
SalDDEGetExecuteString
SalDDEStopServer
Message Description
WM_DDE_Initiate Starts a conversation
WM_DDE_Terminate Ends a conversation
WM_DDE_Ack Positively or negatively acknowledges receipt of a message
WM_DDE_Request Asks the server to send a data item
WM_DDE_Data Sends a data item
WM_DDE_Advise Asks the server to send a data item or a notification whenever the data item
changes
WM_DDE_Unadvise Asks the server to stop sending a data item or a notification whenever the data
item changes
WM_DDE_Poke A client application uses this message to send an unsolicited data item
to a server.
WM_DDE_Execute Sends a command string
The numeric values for these constants are defined internally in SQLWindows/32.
You do not need to define values in the outline for these constants.
DDE functions
SQLWindows/32 has three functions that you use to send DDE messages:
You use these SQLWindows/32 functions to share service names, topic names, and
item names with other DDE applications
Function Description
SalDDEAddAtom Adds a string to the atom table
SalDDEDeleteAtom Deletes a string from the atom table
SalDDEFindAtom Returns the atom associated with a string
SalDDEGetAtomName Returns the string associated with an atom
Function Description
SalDDEAlloc Allocates a memory handle
SalDDEFree Frees a memory handle
In a DDE application, you use SalDDEAlloc and SalDDEFree to allocate and free
memory handles for:
• Data for a WM_DDE_Data or WM_DDE_Poke message
• Command string for a WM_DDE_Execute message
• Options for a WM_DDE_Advise message
For the WM_DDE_Data, WM_DDE_Poke, and WM_DDE_Execute messages, the
data that the handle is associated with must be CF_TEXT format. The end of data is
signaled by a null character.
Important: Do not embed a null character in the data. SQLWindows/32 disregards all bytes
after the first null character.
Use the SQLWindows/32 bitwise AND (&) and bitwise OR (|) operators to set and
read these flags.
WM_DDE_Initiate
Client WM_DDE_Ack Server
Application Application
Any server application that supports the requested topic responds by sending a
WM_DDE_Ack message to the client application.
After a client application successfully starts a conversation with a server application,
the applications can use any of the conversation styles that are explained in the next
section.
Either application can terminate the conversation at any time by sending a
WM_DDE_Terminate message.
WM_DDE_Terminate
Client WM_DDE_Terminate Server
Application Application
WM_DDE_Request
If the server can, it sends the data item to the client in a WM_DDE_Data message.
Optionally, the server can set the fAck flag in the WM_DDE_Data message to tell the
client to send a WM_DDE_Ack message. The client sets a flag called fAck in the
WM_DDE_Ack message (meaning “accepted”) before sending it. A WM_DDE_Ack
message with the fAck flag set is called a “positive WM_DDE_Ack”.
If the server cannot send the data item, it sends a WM_DDE_Ack message with the
fAck flag not set (meaning “not accepted”). A WM_DDE_Ack message with the
fAck flag not set is called a “negative WM_DDE_Ack”.
WM_DDE_Request
Client Server
Application WM_DDE_Ack Application
WM_DDE_Advise
Client Server
WM_DDE_Ack
Application Application
WM_DDE_Data
Client Server
Application WM_DDE_Ack Application
The server can set the fAck flag in the WM_DDE_Data message to tell the client to
send a WM_DDE_Ack message. If the client accepts the WM_DDE_Data message,
it sends a positive WM_DDE_Ack message. If the client does not accept the
WM_DDE_Data message, it sends a negative WM_DDE_Ack message.
The client sends a WM_DDE_Unadvise message to the server when it wants the
server to stop sending data. The server responds with a WM_DDE_Ack message.
WM_DDE_Unadvise
Client WM_DDE_Ack Server
Application Application
WM_DDE_Advise
Client Server
WM_DDE_Ack
Application Application
WM_DDE_Data
Client Server
Application WM_DDE_Ack Application
The server can set the fAck flag in the WM_DDE_Data message to tell the client to
send a WM_DDE_Ack message. If the client accepts the WM_DDE_Data message, it
sends a positive WM_DDE_Ack message. If the client does not accept the
WM_DDE_Data message, it sends a negative WM_DDE_Ack message.
When the client does need the data item, it sends the server a WM_DDE_Request
message.
WM_DDE_Request
The server can set the fAck flag in the WM_DDE_Data message to tell the client to
send a WM_DDE_Ack message. If the client accepts the WM_DDE_Data message, it
sends a positive WM_DDE_Ack message. If the client does not accept the
WM_DDE_Data message, it sends a negative WM_DDE_Ack message.
The client sends a WM_DDE_Unadvise message to the server when it wants the
server to stop sending notifications. The server responds with a WM_DDE_Ack
message.
WM_DDE_Unadvise
Client WM_DDE_Ack Server
Application Application
WM_DDE_Poke
Client Server
WM_DDE_Ack
Application Application
WM_DDE_Execute
Client Server
Application WM_DDE_Ack Application
WM_DDE_Initiate
An application sends this message to one or more other applications to start a
conversation.
nLowlParm An atom that specifies the service name of the receiving application.
If this is null, any application can respond to the initiate request.
The service name cannot contain slashes (/) or backslashes (\).
nHighlParm An atom that specifies the name of the topic.
If this is null, any topic is valid.
Sender actions
Add the atoms for nLowlParm and nHighlParm with SalDDEAddAtom.
• When the call to SalDDESendAll returns, delete the atoms with
SalDDEDeleteAtom.
Receiver actions
If the receiver supports the topic name in nHighlParm, it responds with a
WM_DDE_Ack message.
• If nHighlParm is null, respond with one WM_DDE_Ack message for
each topic that the receiver supports.
• When replying with a WM_DDE_Ack message, create new nLowlParm
and nHighlParm atoms with SalDDEAddAtom. Do not reuse the atoms
sent with the WM_DDE_Initiate message.
WM_DDE_Terminate
Either application in a conversation sends this message to end the conversation.
An application must terminate all its conversations before shutting down.
nLowlParm Reserved.
nHighlParm Reserved.
Sender actions
Once you send a WM_DDE_Terminate message and are waiting for a matching
WM_DDE_Terminate message, do not positively or negatively acknowledge any
subsequent messages sent by the receiver. If you get a message other than
WM_DDE_Terminate from the receiver, delete any atoms or objects that accompany
the message.
Receiver actions
Acknowledge this message by sending a WM_DDE_Terminate message.
WM_DDE_Ack
An application sends this message to acknowledge the receipt and processing of these
messages:
• WM_DDE_Initiate
• WM_DDE_Execute
• WM_DDE_Data
• WM_DDE_Advise
• WM_DDE_Unadvise
• WM_DDE_Poke
• WM_DDE_Request
The use of nLowlParm and nHighlParm depends on the message that the application
is acknowledging.
nLowlParm In a reply to a WM_DDE_Initiate message, this is an atom that specifies the service
name of the replying application.
For replies to all other messages, this is the status as shown in the diagram below. In
the Microsoft Windows developer's documentation, this is called wStatus.
Bit: 15 14 13 8 7 0
... ...
Reserved Application-
fBusy defined
1 = busy
0 = not busy
fAck
1 = accepted
0 = not accepted
nHighlParm For a reply to a WM_DDE_Initiate message, this is an atom that specifies the topic.
For a reply to a WM_DDE_Execute message, this is a memory handle for a
command string.
For replies to all other messages, this is an atom that specifies the name of the item.
Sender actions
Respond to a WM_DDE_Initiate message by sending a WM_DDE_Ack message
with SalDDESend. Respond to all other messages by sending a WM_DDE_Ack
message with SalDDEPost.
• When replying to a WM_DDE_Initiate message, create new nLowlParm
and nHighlParm atoms with SalDDEAddAtom. Do not reuse the atoms
sent with the WM_DDE_Initiate message.
• If responding to a WM_DDE_Data, WM_DDE_Request,
WM_DDE_Poke, WM_DDE_Advise, or WM_DDE_Unadvise
message, reuse the atom or atoms that came with the original message or
else delete them and create new ones.
Receiver actions
Delete all atoms that come in a WM_DDE_Ack message with SalDDEDeleteAtom.
• If receiving a WM_DDE_Ack in response to WM_DDE_Advise, delete
the nLowlParm memory handle with SalDDEFree.
• If receiving a WM_DDE_Ack in response to WM_DDE_Execute, delete
the nHighlParm memory handle with SalDDEFree.
• If receiving a WM_DDE_Ack in response to WM_DDE_Data, delete the
nLowlParm memory handle with SalDDEFree if fRelease in the original
message is zero or if fAck or fBusy is one.
• If receiving a WM_DDE_Ack in response to WM_DDE_Poke, delete
the nLowlParm memory handle with SalDDEFree if fAck or fBusy is
one.
WM_DDE_Request
A client sends this message to ask the server to return a data item.
nLowlParm The requested clipboard format.
SQLWindows/32 only supports the CF_TEXT clipboard format. However, you can
still use other clipboard formats by using external functions in a DLL to pack and
unpack data in the required format.
nHighlParm An atom that specifies the name of the requested item.
Sender actions
Add the nHighlParm atom with SalDDEAddAtom.
• If the call to SalDDEPost fails, delete the nHighlParm atom with
SalDDEDeleteAtom.
Receiver actions
If the receiver can, it sends the requested data with a WM_DDE_Data.
• If the receiver cannot send the data, it sends a negative WM_DDE_Ack
message.
• Whether responding with WM_DDE_Data or a negative
WM_DDE_Ack, reuse the nHighlParm atom that came with the original
WM_DDE_Request message or delete it and create a new one.
WM_DDE_Data
A server sends this message to tell the client that a data item is available.
nLowlParm A memory handle for the data. The data is formatted as shown in the diagram below.
This is called hData in the Microsoft Windows developer's documentation.
Sender actions
Add the nHighlParm atom with SalDDEAddAtom.
Receiver actions
If fAck is zero, delete the nHighlParm atom with SalDDEDeleteAtom.
• If fAck is one, reply with WM_DDE_Ack. Reuse the nHighlParm atom
or delete it and create a new one.
• Get the value of nLowlParm with SalDDEExtractDataText.
• If fRelease is one and the processing associated with the
WM_DDE_Data message is successful, delete the nLowlParm memory
handle with SalDDEFree.
• If fRelease is zero, do not delete the nLowlParm memory handle.
• If both fAck and fRelease are one and the processing associated with the
WM_DDE_Data message is not successful, do not delete the nLowlParm
memory handle.
• If the nLowlParm memory handle is null, the receiver can request the
data by sending WM_DDE_Request.
WM_DDE_Advise
A client sends this message to tell the server to send a data item (or a notification)
whenever it changes.
nLowlParm A memory handle for the options. The format of the options is as shown in the
diagram below. This is called hOptions in the Microsoft Windows developer's
documentation.
word 1 word 2
Bit: 15 14 13 0 15 0
... ...
fAck
1 = Server should set fAck bit when sending
WM_DDE_Data messages (for flow control)
0 = Server should not send fAck bit when
sending WM_DDE_Data messages
Sender actions
Set the value of nLowlParm with SalDDESetOptions.
• Allocate the nLowlParm memory handle with SalDDEAlloc.
• Add the nHighlParm atom with SalDDEAddAtom.
• If the call to SalDDEPost fails, delete the nHighlParm atom with
SalDDEDeleteAtom.
• If the call to SalDDEPost fails, delete the nLowlParm memory handle
with SalDDEFree.
• If the receiver replies with a negative or busy WM_DDE_Ack message,
delete the nLowlParm memory handle with SalDDEFree.
Receiver actions
Get the value of nLowlParm with SalDDEExtractOptions.
• Reply with a WM_DDE_Ack message. Reuse the nHighlParm atom or
delete it and create a new one.
• If the WM_DDE_Advise message is accepted, delete the nLowlParm
memory handle with SalDDEFree.
• If the WM_DDE_Advise message is not accepted, do not delete the
nLowlParm memory handle.
WM_DDE_Unadvise
A client sends this message to tell the server to stop sending a data item (or a
notification) whenever the item changes.
nLowlParm Clipboard format. This tells the server to stop sending updates or notifications for this
clipboard format.
If this is null, it means to stop sending updates for the item specified in nHighlParm
for all formats.
nHighlParm An atom that specifies the name of the item.
If this is null, it means to stop sending updates for all data items.
Sender actions
Add the nHighlParm atom with SalDDEAddAtom.
• If the call to SalDDEPost fails, delete the nHighlParm atom with
SalDDEDeleteAtom.
Receiver actions
Reply with a WM_DDE_Ack message. Reuse the nHighlParm atom or delete it and
create a new one.
WM_DDE_Poke
A client application uses this message to send an unsolicited data item to a server.
nLowlParm A memory handle for the data. The format of the data is as shown in the diagram
below. This is called hData in the Microsoft Windows developer's documentation.
Reserved
Sender actions
Add the nHighlParm atom with SalDDEAddAtom.
• If the call to SalDDEPost fails, delete the nHighlParm atom with
SalDDEDeleteAtom.
• Allocate the nLowlParm memory handle with SalDDEAlloc.
• Set the value of nLowlParm with SalDDESetDataText.
• If the call to SalDDEPost fails, delete the nLowlParm memory handle
with SalDDEFree.
• If you set fRelease to zero and the receiver replies with a positive
WM_DDE_Ack message, delete the nLowlParm memory handle with
SalDDEFree.
• If you set fRelease to one and the receiver replies with a negative or busy
WM_DDE_Ack message, delete the nLowlParm memory handle with
SalDDEFree.
Receiver actions
Reply with a WM_DDE_Ack message.
• Get the value of nLowlParm with SalDDEExtractDataText.
• If fRelease is zero, do not delete the nLowlParm memory handle.
• If fRelease is one and the processing associated with the
WM_DDE_Poke message is successful, delete the nLowlParm memory
handle with SalDDEFree.
• If fRelease is one and the processing associated with the
WM_DDE_Poke message is not successful, do not delete the
nLowlParm memory handle.
WM_DDE_Execute
An application sends this message to transmit a string that the other application is to
process as a series of commands.
nLowlParm Reserved.
nHighlParm A memory handle for the command string. Follow the rules below to format the
command string.
Sender actions
Set the value of nHighlParm with SalDDESetCmd.
• Allocate the nHighlParm memory handle with SalDDEAlloc.
• If the call to SalDDEPost fails, delete the nHighlParm memory handle
with SalDDEFree.
• When the receiver replies with a WM_DDE_Ack, delete the
nHighlParm memory handle with SalDDEFree.
Receiver actions
Get the data for nHighlParm with SalDDEExtractCmd.
• Reply with a WM_DDE_Ack message. Reuse the nHighlParm memory
handle.
Chapter 22
Calling External
Functions in DLLs
This chapter explains:
• How to declare external functions in the outline
• How to choose external data types for function parameters and returns
• How to call external functions in a DLL from a SQLWindows/32 application
• How to write a DLL
• How to use CDLLI*.DLL which comes with SQLWindows/32
Note: The name of a DLL file does not have to have a *.DLL extension (such as USER32.DLL
and GDI32.DLL).
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
• 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.
The table below lists the files for DEMODLLA.APP. The examples in this chapter
come from these files.
Notation convention
This chapter uses an asterisk (“*”) in the name of CDLLI*.DLL. The asterisk
represents the first two digits of the version of the software that you are using.
Global Declarations
External Functions
...
Library name: DEMODLL.DLL
...
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.
For each function in the DLL that the application calls, specify these items:
• The name of the function. For more, read Identifying a function on page 22-5.
• A description of what the function does (optional).
• The export ordinal which is a number that identifies a function. For more,
read Identifying a function on page 22-5.
• The internal data type and the external data type of the return value. Sections
later in this chapter explain external data types. If the function does not return
anything, you can leave this item blank.
• The SQLWindows/32 internal data type and the external data type of each
parameter that the SQLWindows/32 application passes to the function or that
the function returns to the application. Sections later in this chapter explain
external data types.
Identifying a function
You have a choice of how you identify the function in the DLL that 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 (read Export ordinals on page
22-5) for the function and give the function any name that you want.
Export ordinals
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.
External
Corresponding C scalar data type
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-20
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.
External data
Corresponding C scalar data type
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 example below, the SQLWindows/32 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/32 application
as a DWORD. After calling the external function, the SQLWindows/32 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:
#define EXPORTAPI _far _pascal _export _loadds
DWORD EXPORTAPI ReturnDWORD( DWORD varDWORD )
{
return varDWORD;
}
Memory management
Strings are fully dynamic and no memory management is required by a
SQLWindows/32 developer. Internally, SQLWindows/32 uses buffers in a
proprietary format to store and manage String values. The details of these buffers are
not important to a SQLWindows/32 developer, but you need to be aware of these
things when you call external functions that manipulate Strings:
• SQLWindows/32 does not keep multiple copies of the same String value in
memory. Instead, SQLWindows/32 stores one copy and keeps a reference
count for the value (read Reference count example on page 22-12).
• SQLWindows/32 creates a buffer for a String value the first time that you
refer to it, not when the application starts. For more, read Common problem
on page 22-14.
• SQLWindows/32 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/32 manages
it in a heap through subsegment allocation (read Subsegment allocation on
page 22-13) or in the global heap.
SQLWindows/32 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 systemwide 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/32 tries to satisfy as many requests as possible using a single segment.
SQLWindows/32 tries to be more efficient than GlobalAlloc by allocating memory in
chunks, filling several memory requests using only one selector. SQLWindows/32
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.
Example
In the example below, the SQLWindows/32 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/32 creates a String the first time that you refer to it, not when the
application starts. For example, if a SQLWindows/32 application contains this code:
External Functions
Library name: TEST.DLL
Function: getname
...
Parameters
Receive String: LPSTR
...
Internal Functions
Function: MyGetName
...
Local variables
String: str1
Actions
Call getname( str1 )
then the call to getname in the DLL causes a runtime error because it writes to an
invalid buffer (str1 has not been referenced). The solution is to first set str1 to a given
length in the SQLWindows/32 application, either by assigning it a value or by calling
SalStrSetBufferLength.
LPVOID
An LPVOID data type is like an LPSTR, but SQLWindows/32 ignores null
terminators in the value. You use LPVOID for binary data with embedded nulls. For
Receive Strings, SQLWindows/32 does not reset the length of an LPVOID when the
function returns and does not reclaim unused space.
Reading an HSTRING
A buffer that SQLWindows/32 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:
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/32 application passes to a function in a DLL,
you must allocate a new HSTRING.
In the SQLWindows/32 application, you must declare the parameter as:
Receive String: LPHSTRING
In the DLL, declare a variable that holds the handle:
HSTRING hString;
Returning an HSTRING
In the SQLWindows/32 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:
lstrcpy( lpStrItem, "This is a test" );
When you are through, unlock it with SWinHStringUnlock:
SWinHStringUnlock( hString );
Return the HSTRING to the application:
return hString;
Example
In the example below, the SQLWindows/32 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 )
ý Locks the second HSTRING that the application passed and appends it to
the new HSTRING.
« Unlocks the second HSTRING that the application passed.
» Unlocks the new HSTRING.
To convert between standard C data types and SQLWindows/32 Number data types
in an array, call the SWinCvt* functions in CDLLI*.DLL. For a list of the SWinCvt*
functions, read the NUMBER external data type on page 22-9.
You can also call SalArray* functions in CDLLI*.DLL (such as
SalArrayGetLowerBound ) to manipulate HARRAYs in a DLL that you write. For
more, read Using CDLLI*.DLL on page 22-32.
Since 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 example below, the SQLWindows/32 application declares an external function
called ShowArray with a String parameter that has an HARRAY external data type.
The SQLWindows/32 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:
#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;
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 ( nRet == IDNO )
bStopped = TRUE;
Ý SWinHStringUnlock( hString );
hString = 0;
lCurrent++;
}
}
This is what the code does:
¿ Finds the starting bound and ending bound of the array by calling SalQuer-
yArrayBounds in CDLLI*.DLL. This is an example of calling a Sal* func-
tion in a DLL.
¡ Displays the bounds of the array by calling SalMessageBox. This is another
example of calling a Sal* function in a DLL.
¬ Gets an array element into an HSTRING.
Ð Locks the HSTRING.
ƒ Displays the current value of the array element.
Ý Unlocks the HSTRING.
ý Allocates a new HSTRING.
« Locks the new HSTRING
» Copies a value to the new HSTRING.
… Unlocks the new HSTRING with SWinHStringUnlock and copies it into an
array element with SWinArrayPutHString.
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
SWCSTRUC.DLL to manipulate structures. A separate document available on Centura’s
CompuServe forum describes how to use SWCSTRUC.DLL.
When you declare an external function parameter with the structPointer data type,
SQLWindows/32 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:
HWNDWindow handle
LPRECTPointer 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;
Note: If you use Coding Assistant to create a fixed-length string, you must explicitly specify
the length.
Nested structs
You can nest structs. The example below contains 2 rectangles:
structPointer
struct
Number: INT
Number: INT
Number: INT
Number: INT
struct
Number: INT
Number: INT
Number: INT
Number: INT
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.
Software tools
To write a DLL, you need the following or its equivalent: Microsoft Visual C++.
Files
To create a DLL with functions that you can call from a SQLWindows/32
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.
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
all: 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 which 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
Using CDLLI*.DLL
CDLLI*.DLL comes with SQLWindows/32 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/32 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:
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:
LINK TEST.OBJ + <other *.OBJs and *.LIBs>, TEST.EXE,, IMPORT.LIB, DYNAMIC.DEF
The command above creates a file named TEST.EXE.
Data segment of
calling application Data segment of DLL
Local heap Local heap
Stack
Boolean NUMBER
Date/Time DATETIME
Number NUMBER
String STRING
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 these functions:
BOOL FAR PASCAL SwinArrayGetHandle( HARRAY, LONG, LPHANDLE );
BOOL FAR PASCAL SwinArrayPutHandle( HARRAY, LONG, HANDLE );
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.
You cannot pass a UDV whose class uses multiple inheritance to an external function.
A class uses multiple inheritance if:
• The class has more than one direct base class, meaning it has more than one
class in its Derived From section.
• Any of the class' direct or indirect base classes (parent, grandparent, and so
on) use multiple inheritance.
• Any of the instance variables of the class use multiple inheritance.
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.
Chapter 23
Custom Controls
This chapter shows how to use Microsoft Windows custom controls in SQLWindows/
32 applications.
1. Place a custom control to display the Open Control Library dialog. In the lower
left of the dialog, make a selection in List Files of Type.
Note: 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.
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. Be sure to select the class
name in the list that you want.
Message actions
SQLWindows/32 sends these 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/32 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/32 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/32 applications to operate the control.
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 or
the Customizer.
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 or the
Customizer.
Current DLL The name of the DLL that defines the window class.
MS The name of the custom control's window class.
Windows 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.
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/32 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.
Property Description
Horizontal Scroll If Yes, the custom control is created with the WS_HSCROLL window style defined in
WINDOWS.H. The default is No.
Hollow If Yes, the custom control behaves like a group box: you can put other child objects in the
Window custom control and SQLWindows/32 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/32 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/32 maps this setting to the WS_TABSTOP windows style
defined in WINDOWS.H.
Tile to If Yes, the custom control fills the background of the parent object. SQLWindows/32
Parent automatically resizes the custom control when its parent is resized.
MS A window style specific to the custom control. Read the documentation for the custom
Windows Style control.
MS An extended window style specific to the custom control. Read the documentation for the
Windows custom control.
Extended Style
Background The background color of the custom control.
Color
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 The font enhancement (such as italic or bold) of text in the custom control.
Enhancement
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 then the code in a SQLWindows/32 application that uses the slider.
Include file
There are four messages that the SQLWindows/32 application can send to the slider
custom control. You need to specify the values for the message numbers in the
SQLWindows/32 application. They are defined in the include file as:
#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/32 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_VERTICAL 0x0001L
#define SLDS_HORIZONTAL 0x0002L
You need to specify the window class name in the Attribute Inspector or the
Customizer. 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:
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 above 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/32 then sends WM_COMMAND to the
custom control itself as SAM_CustControlCmd with the notification code in the
wParam. The SQLWindows/32 application message processing is shown later in this
chapter.
The SQLWindows/32 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/32 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:
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/32 scroll bar.
The application creates an instance of the custom control:
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:
Function: SetRange
...
Actions
Set nRange = nMin + nMax * 0x10000
Call SalSendMsg( hWnd, SLDM_SETRANGE, 0, nRange )
Window styles
MS windows style. The window style is a double-word value that SQLWindows/
32 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/32 creates custom controls by
calling CreateWindowEx with another double-word value that SQLWindows/32
passes to a window when it is created. You also get the extended style bits when you
process a CREATE message.
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/32 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:
Interface
Through the interface, a custom control talks to the SQLWindows/32 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/32 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:
wParamWindow 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/32 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/32
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.
Designtime behavior
Some custom control objects need to behave differently at runtime and designtime.
Since SQLWindows/32 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/32.
Validation
You can call SalValidateSet in the DLL. For more, read Calling SalValidateSet in a
DLL on page 23-20. The SalValidateSet function is in SWIN*.DLL. For more about
SWIN*.DLL, read Chapter 22, Calling External Functions in DLLs.
The include file SWCC.H contains the structures and macros you need to write the
function.
This is the function prototype:
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 DLL’s
*.DEF file. SQLWindows/32 disables the Properties attribute if it cannot find a function named
SWCustControlEditor in the DLL. Also, SQLWindows/32 disables the Properties item if the
custom control does not have a window.
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 macro below 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.
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:
lpSettingsThe new settings. The DLL can reallocate this memory block if necessary
to increase its size. SQLWindows/32 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.
lpdwStyleThe new window style bits. SQLWindows/32 replaces the current window
style with this value when the function returns SWCC_NEWSTYLE.
Do not include these style bits in dwStyle because SQLWindows/32
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/32 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/32 needs to repaint the
// custom control window
#define SWCC_RECREATEWINDOW 0x0008 // SQLWindows/32 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/32, changes in focus trigger validation. SalValidateSet tells
SQLWindows/32 that the focus is changing to a custom control so that SQLWindows/
32 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:
hWndCCWindow handle of the custom control
bValStateWhether to validate this custom control when it loses the focus:
• If TRUE, SQLWindows/32 sends SAM_Validate when the custom
control loses the focus
• If FALSE, SQLWindows/32 does not send SAM_Validate when the
custom control loses the focus
lParamSQLWindows/32 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/32 sends SAM_Validate to the object losing the
focus:
• If validation succeeds, SalValidateSet returns TRUE and SQLWindows/32
moves the focus to the custom control. Later, when the user moves the focus
off the custom control, SQLWindows/32 sends it SAM_Validate if its field
edit flag is set to TRUE.
• If validation fails, SalValidateSet returns FALSE and SQLWindows/32 sets
the focus to the invalid object.
Important: The message actions in the example below 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.
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
Chapter 24
Symbol scoping
This section explains SQLWindows/32's 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/32, 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.
External References
Application Form1
Actions
Call FT( )
Call F( )
Form2 Set num = 0
Set num1 = 0
Number: num2 Set Form2.num2 = 0
hWnd3.Form3 hWnd33.Form3
Function: F3 Function: F3
Actions Actions
If hWndForm = hWnd3 If hWndForm = hWnd3
Set hWnd33.Form3.num3 = 33 Set hWnd33.Form3.num3 = 33
Else Else
Call hWnd3.Form3.F3( 33 ) Call hWnd3.Form3.F3( 33 )
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:
Set ChildTable1.numT = 9
is qualified, but is not external because it refers to a symbol nested in the current top-
level window.
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
Note: 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.
0. Application
1. 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:
Application
Internal Function
Template
Window Function
Child Table
Window Function
MDI Window
Window Function
Template
Window Function
Child Table
Window Function
Base Class
Class Function
Derived Class
Class Function
Unqualified references
In an unqualified (or simple) reference, you only specify the name of the symbol.
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 The square brackets used to access array elements are not part of the reference
element
MSG_1 constant References to constants are always unqualified because constants are always
global (you can only define constants in the global declarations section)
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 user-defined
variable)
• 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.
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
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
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.
Errors
You get an error at runtime if handle does not refer to an instance of object.
Binding
A fully object-qualified reference is always early bound.
Examples
hWnd.form.var
(hWndArray[1]).form.var
hWndChildTbl.(ParentForm.ChildTable).var
Handle-qualified reference
Important: This type of reference is provided for compatibility with existing applications.
Centura Software Corporation discourages its use because it can make application code
unstructured and difficult to maintain. Instead, use late-bound function calls.
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.
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
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.
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( )
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
There are three items in the Runtime tab of the Properties dialog (page 4-9) that are
related to external references:
• Fully Qualified External References
• Reject Multiple Window Instances
• Enable Runtime Checks of External References
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
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
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.
ActiveX: Microsoft's brand name for a set of Windows technologies and services that
enable interoperatability 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.
argument: See parameter.
API (Application Programming Interface): A set of functions that a program uses
to access a service.
application: A SQLWindows/32 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.
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.
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).
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.
Centura SQLWindows/32 stores an embedded object as a blob of raw bytes in
the application outline.
encapsulation: This term 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.
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.
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.
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. 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.
Index
Symbols normal 4 - 23
! (comments) 4 - 6, 7 - 26 slow 4 - 23
# (formatting character) 11 - 5 speed 4 - 32
$ (formatting character) 11 - 5 API (Application Programming Interface)
% (formatting character) 11 - 5 defined G - 1
* (formatting character) 11 - 5 application
, (formatting character) 11 - 5 defined G - 1
. (formatting character) 11 - 5 Application Actions
; (formatting character) 11 - 5 defined G - 1
_ (formatting character) 11 - 6 Application Actions (outline item) 2 - 8
Application Description (outline item) 2 - 7
Numerics applications
0 (formatting character) 11 - 5 command line arguments 7 - 14, 7 - 32
compiling 4 - 4, 4 - 12
A executable 3 - 2
About Centura (Help menu) 4 - 40 indented text 4 - 4
absolute screen location (dialog boxes) 5 - 10 normal storage format 4 - 4
accelerators 5 - 12 production 3 - 2
defined G - 1 testing 4 - 12
menu items 6 - 3 text 4 - 4
push buttons 5 - 20, 5 - 21 argument
ActiveX defined G - 1
see Chapter 20 arrays 7 - 14
ambient properties 20 - 6 defined G - 1
container control API 20 - 8 dynamic 7 - 15, 7 - 16
controls 20 - 5 multi-dimensional 7 - 15
Controls palette button 20 - 3 one-dimensional 7 - 14
creating components 20 - 3 static 7 - 14, 7 - 16
defined G - 1 Attribute Inspector (Tools menu) 4 - 37
embedded objects 20 - 7 attributes 5 - 4
events 20 - 5 automation
in-place activation 20 - 8 defined G - 1
menu groups 20 - 9
menu merging 20 - 9 B
toolbar merging 20 - 9 backend
ActiveX control defined G - 2
defined G - 1 background text 5 - 12–5 - 13
ActiveX Wizard (Component menu) 4 - 15 Customizer properties 5 - 12
Add to List (Database menu) 4 - 28 mnemonics 5 - 12
adding objects 5 - 2 base class
Coding Assistant 5 - 2 defined G - 2
Controls palette 5 - 2 behavior
Align Edges (Layout menu) 4 - 18 defined G - 2
Align to Grid (Layout menu) 4 - 18 bind variables 12 - 6
ambient properties defined G - 2
defined G - 1 binding
animate 10 - 2 defined G - 2
defined G - 1 bitmap
defined G - 2 defined G - 3
bitwise G - 2 CENTURA.H 22 - 32
Books Online (Help menu) 4 - 40 CHAR (external data type) 22 - 9
BOOL (external data type) 22 - 24 character
Boolean data type 7 - 3 defined G - 3
Boolean operator check boxes 5 - 24–5 - 25
defined G - 2 Customizer properties 5 - 25
Both (Layout menu) 4 - 19 hiding and showing 5 - 25
Bottom (Layout menu) 4 - 18 SalHideWindow 5 - 25
Break (Debug menu) 4 - 22 SalShowWindow 5 - 25
Break statement 7 - 21 Check In (Project menu) 4 - 12
breakpoints 4 - 22, 10 - 2, 10 - 3 Check Out (Project menu) 4 - 12
defined G - 2 child objects 5 - 6, 5 - 8, 5 - 11, 5 - 31
display properties 4 - 33 class
Breakpoints (Debug menu) 4 - 22 defined G - 3
Bring To Front (Layout menu) 4 - 17 Class Definitions (outline item) 2 - 8, 7 - 28
browse class function
defined G - 2 defined G - 3
browser class functions 7 - 28
defined G - 2 writing 7 - 28
buffer class variable
defined G - 2 defined G - 3
Build (Project menu) 4 - 15 classes 8 -2
Build Settings (Project menu) 4 - 12 client
BYTE (external data type) 22 - 9 defined G - 3
Clipboard 7 - 33
C copying in main window 4 - 6
C structures 22 - 24 cutting in main window 4 - 6
cache defined G - 3
defined G - 2 functions 7 - 33
call by reference pasting in main window 4 - 6
defined G - 2 Close All (Window menu) 4 - 39
call by value Close Database Explorer (Database menu) 4 - 29
defined G - 3 CodeView 22 - 34
Call Stack (Tools menu) 4 - 37 Coding Assistant 1 - 4, 5 - 2
Call Stack window 10 - 8 adding class children 8 -16
Call statement 7 - 21 adding columns 14 - 6
calling functions 7 - 21 adding comments 7 - 27
Cascade (Window menu) 4 - 39 adding menus 6 - 2
cascading menus 6 - 6 adding objects 5 - 2
Case (Select Case statement) 7 - 24 adding resources 7 - 33
case sensitive adding user-defined variables 8 -20
defined G - 3 adding user-defined windows 8 -22
case sensitivity (SAL) 7 - 2 defined G - 3
CBTYPE.H 22 - 32 Microsoft Windows Messages 9 - 4
CDLL.LIB 22 - 31, 22 - 32 program-defined messages 9 - 3
CDLLI*.DLL 22 - 32 selecting base classes 8 -10, 8 -12
cell specifying accelerators 5 - 12, 6 - 3
expressions 7 - 20 % 11 - 5
defined G - 7 * 11 - 5
Expressions (Tools menu) 4 - 38 , 11 - 5
Expressions window 10 - 6 . 11 - 5
external data type 22 - 6, 22 - 8 ; 11 - 5
external functions 7 - 28 _ 11 - 6
see Chapter 22 0 11 - 5
calling 22 - 28 scientific notation 11 - 5
defined G - 7 columns 14 - 8
External Functions (outline item) 2 - 8, 22 - 4 data fields 5 - 17
external reference defined G - 7
defined G - 7 Formats (outline item) 2 - 8
frames 5 - 14–5 - 15
F Customizer properties 5 - 15
Fast Animate (Debug menu) 4 - 23 frontend
fetch defined G - 7
defined G - 7 FTP
File Handle defined G - 7
defined G - 7 functions 7 - 27
File Handle data type 7 - 7 actions 7 - 30
File menu calling 7 - 21
Exit 4 - 5 class 7 - 28
New 4 - 2 defined G - 7
Open 4 - 3 external 7 - 28
Page Settings 4 - 4 internal 7 - 28
Print 4 - 5 local variables 7 - 29
Save 4 - 3 parameters 7 - 29
Find (Edit menu) 4 - 7 returns 7 - 29
Find Next (Edit menu) 4 - 8 static variables 7 - 29
flag system 7 - 28
defined G - 7 window 5 - 6, 7 - 28
focus Functions (Help menu) 4 - 39
defined G - 7
focus frame G
defined G - 7 GDI (Graphics Device Interface)
fonts for objects 5 - 36 defined G - 7
form pages 5 - 7 GIF (Graphics Interchange Format)
form units 5 - 37 defined G - 7
form windows 5 - 5, 5 - 6–5 - 8 global
automatically creating 5 - 7 defined G - 7
Customizer properties 5 - 7 global declarations
defined G - 7 defined G - 8
form pages 5 - 7 Global Declarations (outline item) 2 - 8
icon 5 - 7 Go (Debug menu) 4 - 21
formats Go To Item (Component menu) 4 - 15, 19 - 4, 19 - 11
characters grid
# 11 - 5 activating 4 - 35
$ 11 - 5 aligning 4 - 18
N selection handles 4 - 18
named menus 6 - 7 sizing evenly 4 - 19
Named Menus (outline item) 2 - 8 spacing evenly 4 - 19
naming conventions tab order 4 - 20
constants 7 - 19 top-level 5 - 5, 5 - 11
objects 5 - 4 variables 5 - 39
variables 7 - 19 Window Variables 5 - 6
nArgCount 7 - 14, 7 - 32 OLE
New (Component menu) 4 - 15 see Chapter 20
New (File menu) 4 - 2 OLE Class Editor (Component menu) 4 - 15
NEWAPP.APP 6 - 8 OLE Documents
Next Error (Project menu) 4 - 12 defined G - 11
No Animate (Debug menu) 4 - 23 On statement 7 - 23
normal storage format (applications) 4 - 4 Open (File menu) 4 - 3
notation conventions xviii Open Database Explorer (Database menu) 4 - 23
null operators 7 - 19
defined G - 11 defined G - 11
NUMBER (external data type) 22 - 9 option buttons
Number data type 7 - 6 see Chapter 15
internal format 7 - 6 Customizer properties 15 - 2
NUMBER_Null 7 - 6 hiding and showing 15 - 2
images 15 - 4
O SalHideWindow 15 - 2
Object Compiler 4 - 14 SalShowWindow 15 - 2
Object Nationalizer 4 - 13 styles 15 - 3
object-oriented programming outline 2 - 6
see Chapter 8 Application Actions 2 - 8
defined G - 11 Application Description 2 - 7
objects 1 - 3, 1 - 5 Class Definitions 2 - 8, 7 - 28
see Chapter 5 collapsing 4 - 7
accelerators 5 - 12 Constants 2 - 8
adding 5 - 2 Contents 5 - 6, 5 - 11
Coding Assistant 5 - 2 defined G - 11
Controls palette 5 - 2 Design-time Settings 2 - 7
aligning 4 - 18 expanding 4 - 7
attributes 5 - 4 External Functions 2 - 8, 22 - 4
child 5 - 6, 5 - 8, 5 - 11, 5 - 31 Formats 2 - 8
color 5 - 36 Functions 5 - 6
Contents 5 - 6, 5 - 11 Global Declarations 2 - 8
defined G - 11 Internal Functions 2 - 8, 7 - 28
fonts 5 - 36 Libraries 2 - 7
Functions 5 - 6 Menu Actions 6 - 4
Message Actions 5 - 6 Message Actions 5 - 6
mnemonics 5 - 11 Named Menus 2 - 8, 6 - 7
mouse pointers 5 - 3 Resources 2 - 8
naming conventions 5 - 4 Variables 2 - 8
properties 5 - 4 Window Defaults 2 - 8
SAM_* messages 5 - 6 Window Parameters 5 - 39
defined G - 12 SalDDEExtractOptions 21 - 23
result sets 12 - 9 SalDDEFindAtom 21 - 22
Return statement 7 - 24 SalDDEFree 21 - 22
Right (Layout menu) 4 - 18 SalDDEGetAtomName 21 - 22
row SalDDEGetExecuteString 21 - 6, 21 - 18
defined G - 12 SalDDEPost 21 - 20
ROWIDs 12 - 37 SalDDERequest 21 - 5, 21 - 12, 21 - 14, 21 - 16
RTF (Rich Text Format) SalDDESend 21 - 20
defined G - 12 SalDDESendAll 21 - 20
run mode SalDDESendExecute 21 - 6, 21 - 12, 21 - 17, 21 - 19
defined G - 12 SalDDESendToClient 21 - 5, 21 - 10, 21 - 15, 21 - 18
runtime 1 - 4 SalDDESetCmd 21 - 23
defined G - 12 SalDDESetDataText 21 - 23
SalDDESetOptions 21 - 23
S SalDDEStartServer 21 - 5, 21 - 7, 21 - 8, 21 - 13
SAL (SQLWindows Application Language) 1 - 3 SalDDEStartSession 21 - 5, 21 - 9, 21 - 11, 21 - 13
see Chapter 7 SalDDEStopServer 21 - 5, 21 - 12, 21 - 13
defined G - 12 SalDDEStopSession 21 - 5, 21 - 11
SalActiveXAutoErrorMode 20 - 8 SalDestroyWindow
SalActiveXClose 20 - 8 dialog boxes 5 - 9
SalActiveXCreate 20 - 8 SalDisableWindow
SalActiveXCreateFromData 20 - 8 columns 14 - 8
SalActiveXCreateFromFile 20 - 8 combo boxes
SalActiveXDelete 20 - 8 SalDisableWindow 5 - 29
SalActiveXDoVerb 20 - 8 data fields 5 - 17
SalActiveXGetActiveObject 20 - 8 multiline fields 5 - 19
SalActiveXGetData 20 - 8 pictures 17 - 2
SalActiveXGetObject 20 - 8 SalDlgChooseColor 5 - 35
SalActiveXInsertObjectDlg 20 - 8 SalDlgChooseFont 5 - 35
SalActiveXOLEType 20 - 8 SalDlgOpenFile 5 - 35
SalColorGet 14 - 43 SalDlgSaveFile 5 - 35
SalColorSet 14 - 43 SalDragDropDisableDrop 18 - 3, 18 - 4
SalCompileAndEvaluate 10 - 9 SalDragDropEnableDrop 18 - 4
SalContextBreak 10 - 10 SalDragDropGetSource 18 - 4
SalContextCurrent 10 - 10 SalDragDropGetTarget 18 - 4
SalCreateWindow 5 - 38 SalDragDropStart 18 - 3, 18 - 5
dialog boxes 5 - 8, 5 - 9 SalDragDropStop 18 - 5
form windows 5 - 7 SalDrawMenuBar 6 - 2, 6 - 4
MDI windows 16 - 3 SalDropFilesAcceptFiles 18 - 10
table windows 14 - 3 SalDropFilesQueryFiles 18 - 10
window parameters 5 - 39 SalDropFilesQueryPoint 18 - 10
SalCursorSetFile 18 - 5 SalEditCanCopyTo 17 - 8
SalDDEAddAtom 21 - 22 SalEditCanCut 14 - 48, 17 - 8
SalDDEAlloc 21 - 22 SalEditCanPaste 7 - 33, 14 - 48, 17 - 8
SalDDEDeleteAtom 21 - 22 SalEditCanUndo 17 - 8
SalDDEExtract 21 - 22 SalEditClear 17 - 8
SalDDEExtractCmd 21 - 23 SalEditCopy 7 - 33, 14 - 48, 17 - 8
SalDDEExtractDataText 21 - 23 SalEditCopyString 7 - 33
SalStatusGetText 5 - 34 SalTblSetColumnText 14 - 44
SalStatusSetText 5 - 34 SalTblSetColumnTitle 14 - 43
SalStatusSetVisible 5 - 34 SalTblSetColumnWidth 14 - 43
SalStrGetBufferLength 22 - 16 SalTblSetContext 14 - 20, 14 - 22, 14 - 24, 14 - 25
SalTBarSetVisible 5 - 33 SalTblSetFlagsAnyRows 14 - 16, 14 - 17, 14 - 37
SalTblAnyRows 14 - 13, 14 - 15, 14 - 16 SalTblSetFocusCell 14 - 14, 14 - 21, 14 - 41
SalTblClearSelection 14 - 42 SalTblSetFocusRow 14 - 41
SalTblColumnAverage 14 - 44, 14 - 51 SalTblSetLockedColumns 14 - 45
SalTblColumnSum 14 - 44, 14 - 51 SalTblSetRange 14 - 19, 14 - 25, 14 - 28, 14 - 31
SalTblCopyRows 7 - 33, 14 - 49 SalTblSetRow 14 - 41
SalTblCreateColumn 14 - 44, 14 - 50 SalTblSetRowFlags 14 - 16, 14 - 17, 14 - 22, 14 - 24,
SalTblDefineRowHeader 14 - 45, 14 - 46 14 - 37
SalTblDefineSplitWindow 14 - 47 SalTblSetTableFlags 14 - 35
SalTblDeleteRow 14 - 20 SalTblSortRows 14 - 44, 14 - 51
SalTblDeleteSelected 14 - 13 SalTrackPopupMenu 6 - 8
SalTblDestroyColumns 14 - 50 menu status text 5 - 34, 6 - 10
SalTblDoDeletes 14 - 14 SalValidateSet 23 - 18, 23 - 20
SalTblDoInserts 14 - 15 SAM (SQLWindows Application Messages) 1 - 3
SalTblDoUpdates 14 - 17 see Chapter 9
SalTblFetchRow 14 - 25 defined G - 12
SalTblFindNextRow 14 - 16, 14 - 17, 14 - 22, 14 - 23, SAM_AnyEdit 9 - 6, 14 - 40
14 - 37, 14 - 38 SAM_AppExit 9 - 7
SalTblFindPrevRow 14 - 38 SAM_AppStartup 9 - 8
SalTblGetColumnText 14 - 44 SAM_CacheFull 9 - 8, 14 - 34, 14 - 35
SalTblGetColumnTitle 14 - 43 SAM_CaptionDoubleClick 9 - 9, 14 - 39
SalTblGetColumnWindow 14 - 44 SAM_Click 9 - 10, 14 - 40, 17 - 7
SalTblInsertRow 14 - 14, 14 - 21 SAM_Close 9 - 12, 14 - 41
SalTblKillEdit 14 - 15, 14 - 16, 14 - 21, 14 - 23, 14 - SAM_ColumnSelectClick 9 - 13, 14 - 39
42 SAM_CornerClick 9 - 13, 14 - 46
SalTblKillFocus 14 - 41 SAM_CornerDoubleClick 9 - 14, 14 - 46
SalTblPasteRows 7 - 33, 14 - 48 SAM_CountRows 9 - 15, 14 - 32
SalTblPopulate 14 - 13, 14 - 25, 14 - 26, 14 - 30 SAM_Create 9 - 16
SalTblQueryColumnFlags 14 - 37 custom controls 23 - 3
SalTblQueryColumnID 14 - 44 SAM_CustControlCmd 9 - 17, 23 - 3
SalTblQueryColumnPos 14 - 44 SAM_DDE_ClientExecute 9 - 17, 21 - 6, 21 - 18
SalTblQueryColumnWidth 14 - 43 SAM_DDE_ClientRequest 9 - 18, 21 - 6, 21 - 15
SalTblQueryContext 14 - 20 SAM_DDE_CreateComplete 9 - 16
SalTblQueryLockedColumns 14 - 45 SAM_DDE_DataChange 9 - 18, 21 - 6, 21 - 11, 21 -
SalTblQueryRowHeader 14 - 46 16, 21 - 19
SalTblQueryScroll 14 - 42 SAM_Destroy 9 - 19, 16 - 5
SalTblQuerySplitWindow 14 - 47 custom controls 23 - 3
SalTblQueryTableFlags 14 - 35 SAM_DoubleClick 9 - 20, 14 - 40, 17 - 7
SalTblQueryVisibleRange 14 - 42 SAM_DragCanAutoStart 9 - 21, 18 - 5
SalTblReset 14 - 18 SAM_DragDrop 9 - 22, 18 - 6
SalTblScroll 14 - 42 SAM_DragEnd 9 - 22, 18 - 6
SalTblSetCellTextColor 14 - 43 SAM_DragEnter 9 - 23, 18 - 6
SalTblSetColumnFlags 14 - 37 SAM_DragExit 9 - 23, 18 - 6
SalTblSetColumnPos 14 - 44 SAM_DragMove 9 - 24, 18 - 7
SqlFetchPrevious 12 - 9 On 7 - 23
SqlFetchRow 12 - 9 Return 7 - 24
SqlGetErrorPosition 12 - 22 Select Case 7 - 24
SqlGetErrorText 12 - 22 Set 7 - 25
SqlGetErrorTextX 12 - 22 When SqlError 7 - 26, 12 - 18
SqlGetParameter 12 - 28 While 7 - 26
SqlGetParameterAll 12 - 28 static linking 22 - 3
SqlGetResultSetCount 12 - 9 static variables 7 - 29
SqlGetRollbackFlag 12 - 22 defined G - 13
SqlImmediate 12 - 15 statistics 4 - 9
SqlInMessage 12 - 32 status bar 2 - 3
SqlIsolationLevel 12 - 32, 12 - 36 status bars 5 - 34
SqlNoRecovery 12 - 33 menu status text 5 - 34, 6 - 2, 6 - 3, 6 - 9
SqlOpen 12 - 45 SalStatusGetText 5 - 34
SqlOutMessage 12 - 33 SalStatusSetText 5 - 34
SqlPassword 12 - 4, 12 - 33 SalStatusSetVisible 5 - 34
SqlPrepare 12 - 8 step into 10 - 5
SqlPrepareAndExecute 12 - 8 Step Into (Debug menu) 4 - 22
SqlResultSet 12 - 33 step over 10 - 5
SqlRetrieve 12 - 41 Step Over (Debug menu) 4 - 22
SqlSetInMessage 12 - 28 Stop Debugging (Debug menu) 4 - 22
SqlSetIsolationLevel 12 - 28, 12 - 36 Stored Procedure (Database menu) 4 - 24
SqlSetLockTimeout 12 - 28 strArgArray 7 - 14, 7 - 32
SqlSetOutMessage 12 - 28 string
SqlSetParameter 12 - 28 defined G - 13
SqlSetParameterAll 12 - 28 String data type 7 - 7
SqlSetResultSet 12 - 9 maximum length 7 - 7
SqlStore 12 - 41 structPointer (external data type) 22 - 24
SQLTalk (Tools menu) 4 - 38 subsegment allocation 22 - 13
SqlUser 12 - 4, 12 - 34 SWCustControlEditor 23 - 15
SQLWindows Application Language SWinCvtIntToNumber 22 - 9
see SAL SWinCvtLongToNumber 22 - 9
SQLWindows Application Messages SWinCvtNumberToInt 22 - 9
see SAM SWinCvtNumberToLong 22 - 9
SQLWindows/32 SWinCvtNumberToULong 22 - 10
defined G - 13 SWinCvtNumberToWord 22 - 10
description 1 - 3 SWinCvtULongToNumber 22 - 9
user interface 2 - 2 SWinCvtWordToNumber 22 - 9
stack segment 22 - 33 SWinHStringLock 22 - 15
standard dialogs 5 - 35 SWinHStringUnlock 22 - 15
statements 7 - 20 SWinInitLPHSTRINGParam 22 - 15
Break 7 - 21 symbol 24 - 2
Call 7 - 21 system constants 7 - 18
defined G - 13 system functions 7 - 28
Else 7 - 22 defined G - 13
Else If 7 - 22 system modal dialog boxes 5 - 9
If 7 - 22 defined G - 13
Loop 7 - 23 system variables 7 - 13
W
When SqlError statement 7 - 26, 12 - 18
While statement 7 - 26
Width (Layout menu) 4 - 19
window
defined G - 14
Window Defaults (outline item) 2 - 8
Window Editor
defined G - 14
window functions 7 - 28
calling 7 - 30
defined G - 14
writing 7 - 28
Window Grabber
defined G - 14
Window Handle
defined G - 14
getting 5 - 38
storing in arrays 7 - 17
Window Handle data type 5 - 38, 7 - 8
Window menu
Cascade 4 - 39
Close All 4 - 39
Tile Horizontally 4 - 39
Tile Vertically 4 - 39
window parameters 5 - 39
Window Variables 5 - 6
WINDOWS.H 9 - 4
Wizards (Component menu) 4 - 15
WM_COMMAND 23 - 4
WM_DDE_Ack 21 - 23, 21 - 29