Last updated March 1st,
1999
Copyright © 1998-1999 Thomas Althammer.
All rights reserved.
No part of this document should be reproduced, distributed or altered without
my permission.
All Windows SDK definitions appearing
on this page can be optained from 16/32-bit include files in the
"Downloads" section.
Fast Facts - If you are experiencing crashes or other obscure errors when using Centura Team Developer, take a look at the CTD Development Environment section. - If there are problems with your database connection, make sure you have walked throught the basic steps explained in the paragraph Configuring database connections. - Too many timeouts? Check here. |
Date/Time
Number
String
Miscellaneous
External functions
Check Boxes
Combo Boxes
Data Fields
Form Windows
List Boxes
MDI
Multiline Field
Pushbuttons
QuickGraphs
QuickTabs
Radio Boxes
Table Windows
Miscellaneous
Miscellaneous
General
Database Access
ActiveX
Team Object Manager
General
Database Access
General
BKG - Background Images and Hotspots
CPT - Custom Painted Table Windows
TLB - Toolbars
TTP - ToolTips
UDV - User-defined variables
Where can I find information about Centura's
development products and the Year 2000 problem?
The newest releases are all Year 2000 compliant. Check
www.centurasoft.com/support/tech_info/bulletins/cli2000.htm
for further information.
Even though SQLBase is Y2K compliant, your client-side applications that access
SQLBase may not be. Use a utility available for download at
ftp.centurasoft.com/products/utilities/y2ksqlb.zip to analyze
your SQLBase databases to help with your Y2K efforts. Please read the
ReadMe.txt and License.txt files after extracting them from the .ZIP file.
Should I build one huge application or split it
up into a number of interlinked applications?
There are many applications deployed around the world that are fairly large in
size. A typical "large" Centura application would contain hundreds of
top level windows (form windows, dialog boxes etc.) and in excess of 100,000
lines of SAL code. Either of the two approaches (i.e., build everything into
one application, versus split them into multiple applications) has been adopted
into such applications. The governing factors for the choice are: Does the
system being built contain independent modules that can run independent of each
other? If so, then building separate apps for each module makes sense.
There really is only one reason, stated above, to warrant a system to be built
as a set of applications that would be deployed as multiple EXEs at runtime.
Other than that, Centura Team Developer has several built-in features that
greatly aid building large applications:
- Team Object Manager takes care of version control, as well as concurrent
check-in/check-outs using its visual diff/merge features.
- Dynalibs, the pre-compiled chunks of SAL code that lend themselves to faster
compile times.
- Centura Team Developer, being a 32-bit product, shatters all limits imposed
by the 16-bit architecture that manifested in SQLWindows like the maximum size
of a section of an outline and the global symbol-table space. These were the
limits that prevented SQLWindows apps from growing beyond a certain limit.
Once you built your system as a single application, you would reap the
following benefits:
- You wouldn't have to worry much about protocols like DDE for enabling
communication between different windows in the system. Simple windows messaging
and function call interfaces will take care of that.
- Creating and launching another window within the system would be faster as
compared to starting another app via SalLoadApp() function call.
- Windows resources consumed in creating a new window within the same app are
much less than having to start another application. This point is rather moot
in Windows 95 and Windows NT systems. However, if you are planning on deploying
your Centura-built applications onto a Win16 platform, then the issue of free
windows resources becomes critical.
How can I deliver help files along with my
self-written applications?
Several third-party tools enable you to generate HLP and nowadays HTML files.
The Microsoft Help Compiler will turn a RTF (richt text format) document with
certain formatting and tags into a HLP file. More convenient is using products
like DocToHelp, RoboHelp, or Help Magician that take care of necessary
formatting and enable the user to generate online help and the application
documentation from one source in different formats.
Which naming conventions should I use when
developing with SQLWindows or SQLWindows/32?
The following table is just a recommendation and should only be used
as a guideline.
Object type | Prefix | Example | Alternatives |
---|---|---|---|
Boolean | b | bDebug | |
Date | d | dBegin | |
Time | t | tStart | |
Date/Time | dt | dtEnd | |
Number | n | nCount | |
String | s | sName | str |
Long String | ls | lsName | |
Window Handle | hWnd | hWndFom | |
SQL Handle | hSql | hSqlDQL | |
Functional Class | cf | cfUser | rec ("record"); obj/o ("object"); udv ("user-defined variable") |
Internal Class Variable | m_ [+ datatype] | m_bConstructed | i_ |
Class Variable | c_ [+ datatype] | c_bShowError | |
Global Variable | g_ [+ datatype] | g_bMayEdit | |
Parameter | p_ [+ datatype] | p_nCustomerID | |
Form Window | frm | frmName | fw |
Table Window | tw | tblName | tbl |
Dialog Box | dlg | dlgName | |
MDI Window | mdi | mdiName | |
Child table | tbl | tblCustomers | |
Data Field | df + Datatype | dfnNumber, dfsName, dfdStart | w/o datatype |
Multiline Field | ml | mlErrorText | |
Pushbutton | pb | pbStart | |
Radio Button | rb | rbSelection | |
Check Box | cb | cbShowColors | |
Option Button | ob | obName | |
List Box | lb | lbUsers | |
Combo Box | cmb | cmbTitle | |
Picture | pic | picImage | |
Horizontal Scroll Bar | hsb | hsbRight | |
Vertical Scroll Bar | vsb | vsbHeight | |
Custom Control | cc | ccSpin | |
Column | col [+ datatype] | colnNumber, colsName, coldStart | w/o datatype; c |
When I attempt to run the SETUP.EXE of a
Centura product I get 'Installation Aborted", "Internal Error".
How can I avoid this?
The Wise installer makes extensive use of the TEMP directory during any
installation. Make sure that:
- The directory pointed to by the TEMP (or TMP) environment variable
exists.
- Make sure that this directory is writable by the current user.
Sadly, there's no way to code around this in the installer, since the error
occurs before the first line of code is executed.
How do I change the standard file
type settings in the open/save dialogs of the SQLWindows/Team Developer?
The default application file extension can be changed in the
Preferences window. This is set to "APP" as Centura's standard source
file type and can be replaced by any extension, for example "AP?" to
display all files having an extension starting with "AP". However, as
a drawback, you have to manually type the file extension of your file when
saving.
I get the error "This application
has exceeded the space available for string constants". What should I
do?
What you need to do in your app is consolidate your string literals
into constants. For example, you may have many calls to SalMessageBox( ) in
your app and the title parameter passed to each call might be a hard coded
string like the name of the application:
Call SalMessageBox( sText, 'Super App', MB_Ok )
Instead, you should define one string constant and use this string
constant.
Other strategies you can use include storing lengthy messages in a text file or
database table and load the messages at application startup. The Visual
Toolchest string table functions can be great for this approach. Also, you
could place code in internal functions and compile them with the object
compiler.
Are constant names retained when
making an executable?
In SQLWindows, when you make an EXE, named constants are replaced with their
actual values. This means you can't use named constants with
SalCompileAndEvaluate, including SAL system defined constants.
The workaround is to assign NUMBER_Null to a variable that you can later
reference, for example:
On SAM_AppStartup
Set gnNull=NUMBER_Null
and then you can call SalCompileAndEvaluate with
"Set nNumberVariable=' || 'gnNulll'".
In Centura Team Developer the runtime was changed so that the symbol is
preserved in the EXE file and named constants can be used in
SalCompileAndEvaluate.
Are there any problems I might face
when working with Windows 98?
Centura Software Corporation is in the process of certifying its 32-bit
products on Windows 98. Visit
http://www.centurasoft.com/support/tech_info/bulletins/win98warn.html
to obtain further information.
I keep getting messages about missing
bitmaps in my source code that are not referenced anymore. How do I avoid
this?
SQLWindows doesn't remove such references correctly, although the
source will compile and run fine. To avoid it, just save as text, exit, and
reload the file.
Whenever a new version of Centura's
development environments comes out, do I have to recompile my source code or
can I just replace the runtime DLLs?
You will need to recompile existing applications to deploy them with a new
version's runtime files. In general this is true of every major release
of SQLWindows and SQLWindows/32. In 32-bits for example, all executables built
with a given version of SQLWindows/32 are implicitly linked to cdlliXX.dll
where XX is the major/minor release number, so your existing executables link
to cdlli11.dll (which in turns links to many other xxxi11 DLLs), and all
executables built with 1.5 link to cbi15.dll.
However, this does mean that you can deploy applications built with 1.5
alongside earlier ones built with 1.1.x.
Whenever an instance of a program
developed with SQLWindows or SQLWindows/32 gets started, do new instances of
deployment files get loaded or are these DLLs shared?
I Win16, DLLs detect if they are already loaded and will use the existing
instace. Since each 32-bit application runs in it's own process, it loads its
own copies of any DLLs required.
How do I initialise class
variables?
For setting values for class variables, you don't need an existing instance of
the class. So, you can just use the following code to initialise the default
color of screen element:
On SAM_AppStartup
Set cfScreenElement.c_mDefaultColor=COLOR_Grey
I am not able to compile my
application because of an error stating that my outline is full. What should I
do now?
You might first try to save everything as text, exit SQLWindows(/32) and reopen
the files. If that does not help, try one or more of the following
suggestions.
- partition your application in several smaller programs,
- compile parts of the outline into DLLs (Object Compiler),
- use dynalibs,
- examine your code for re-use possibilities, for example,
- develop functions,
- develop classes,
- create screens with parameters if you have similar
screens.
A comment in my code makes it look
odd. How do I hide my comments?
Comments for Window Parameters and Window Variables can be easily hidden. Write
the comment meant for the variable or parameter prefixing with "!".
Select the comment line and press Alt + Right Arrow. The comment is now hidden.
Now double click the variable to see the hidden comment associated with it.
Likewise comments can be hidden anywhere in SAL outline code. And don't forget
to mention some where "Double Click for Hidden Comments" in your code
so that your colleagues find these hints.
How can I decipher a bitmask return
code in Centura's development environments?
If the error is only one bit:
If ( nErrorCode & ERROR_CODE )
If the error is more than one bit:
If ( nErrorCode & ERROR_CODE )=ERROR_CODE
How do I round up durations to a certain
granularity?
The following is a simple expression that will get you the nearest half hour,
given a duration expressed in decimal hours.
This expression takes a value such as 2.36 hours from nHourDuration, doubles it
to 4.72 half-hours and adds 0.99999 to make this round up to 5.71999.
SalNumberTruncate( ) reduces this down to five half-hours, and the division by
2 yields 2.5 hours.
SalNumberTruncate( 2 * nHourDuration + 0.99999, 10, 0 ) / 2
You can go from minutes to hours at half-hour granularity by using
SalNumberTruncate(nMinuteDuration / 30 + 0.99999, 10, 0 ) / 2
This can be easily modified to any time period you want to use.
What is the forumla for calculating a week
number?
The number of a week can be determined by
Set nWeekNumber=( SalDateWeekBegin( dtDate ) - SalDateWeekBegin(
SalDateConstruct( SalDateYear( SalDateWeekBegin( dtDate ) + 3 ), 1, 4, 0, 0, 0
) ) ) / 7 + 1
Where can I get information about
calendars?
Check the Calendar FAQ at
www.pip.dknet.dk/~pip10160/calendar.html. It contains an
extensive overview of the Christian, Hebrew, and Islamic calendar and even
covers some historical background.
Given that I have two date/time
values, how do I calculate the elapsed time between them?
If you subtract two date/time values from each other to get the elapsed time,
the resulting value is given in number of days. When you are dealing with a
matter of minutes or even a smaller time interval, the results of the
subtraction aren't very useful. In order to convert this value to a more
meaningful one, calculate how many of the given time units occur in one day.
Then, multiply the difference you calculated by the number of units in a day to
get the number of units in your elapsed time.For example, there are 24 * 60 *
60 seconds in a day, or 86400 seconds. If subtracting two date/time values
results in a value of 0.0416666666666667, then multiply 0.0416666666666667 *
86400=3600 seconds. (This corresponds to one hour.)
How do I combine low and high values into
one number?
Use the following code fragment:
Set nCombinedValue=nHighValue * 65536 | nLowValue
Instead, one can use VisNumberMakeLong( ), a function part of the Visual
Toolchest (VT.APL/VTMISC.APL).
How do I accomplish hexadecimal
conversions with Centura's development products?
Function: NumberToHex
Description:
Returns
String:
Parameters
Number: p_nValue
Static Variables
Local variables
Number: nRemainder
String: sHex
Actions
Set p_nValue=SalNumberAbs( p_nValue )
If p_nValue > 15
Set sHex=NumberToHex( SalNumberTruncate( p_nValue/16, 18, 0 )
)
Set nRemainder=SalNumberMod( p_nValue, 16 )
If nRemainder > 9
Set nRemainder=nRemainder + 7
Set sHex=sHex || SalNumberToChar( nRemainder + 48 )
Return sHex
Function: HexToNumber
Description:
Returns
Number:
Parameters
String: p_sHex
Static Variables
Local variables
Number: nDec
Number: nLen
Number: nLower
Actions
Set p_sHex=SalStrUpperX( SalStrTrimX( p_sHex ) )
If SalStrLeftX( p_sHex, 2 )='0X'
Set p_sHex=SalStrRightX( p_sHex, SalStrLength( p_sHex ) - 2 )
Set nDec=SalStrLop( p_sHex )
Set nLen=SalStrLength( p_nHex )
If (nDec > 47) and (nDec < 58)
Set nDec=nDec - 48
Else If (nDec > 64) and (nDec < 71)
Set nDec=nDec - 55
Else
Set nDec=NUMBER_Null
If (nLen > 0) and (nDec !=NUMBER_Null)
Set nLower=HexToNumber( p_sHex )
If nLower !=NUMBER_Null
Set nDec=nDec * SalNumberPower( 16, nLen ) + nLower
Else
Set nDec=NUMBER_Null
Return nDec
How do I concatenate strings in Centura's
development products?
String can be combined with two vertical lines like sString1 || sString2
.
Where can I get the documentation of the
CStruct library available with SQLWindows and Team Developer?
The CStruct functions are rarely documented, however, there is a .WRI
file available that was originally written for SQLWindows. The functions are
almost the same, thus the information provided counts for CTD as well. Download
SWCStruc.ZIP.
In which order does SalLoadApp( ) search for
the correct path to be used if I didn't specify one?
SQLWindows' SalLoadApp() uses WinExec() directly. The rules for finding
executables with WinExec() are as follows:
1. The directory from which the application loaded.
2. The current directory.
3. The Windows system directory. The GetSystemDirectory() function retrieves
the path of this directory.
4. The Windows directory. The GetWindowsDirectory() function retrieves the path
of this directory.
5. The directories listed in the PATH environment variable.
When running on NT or Win95 then WinExec actually uses CreateProcess()
internally (and CTD uses CreateProcess directly instead of WinExec) The
rules for finding exectuables on Win95 and NT are as follows:
1. The directory from which the application loaded.
2. The current directory for the parent process.
3. Windows 95: The Windows system directory. Use the GetSystemDirectory()
function to get the path of this directory.
Windows NT: The 32-bit Windows system directory. Use the
GetSystemDirectory() function to get the path of this directory.
The name of this directory is SYSTEM32.
4. Windows NT: The 16-bit Windows system directory. There is no Win32 function
that obtains the path of this directory, but it is searched. The name of this
directory is SYSTEM.
5. The Windows directory. Use the GetWindowsDirectory() function to get the
path of this directory.
6. The directories that are listed in the PATH environment variable.
Note that on NT there is a 'system' path that is prepended to any user supplied
path. This is settable in Control Panel->System->Environment.
How do I use the function
SalCompileAndEvaluate to evaluate an IF-ELSE statement?
1) Put your If-Else statement into a internal function and call this function
with SalCompileAndEvaluate( ). This is of course only possible if your If-Else
statement is known at design-time.
2) Transform your If-Else statement to an expression. For example:
If <condition>
<statement1>
else
<statement2>
...can also be written as...
(<condition> AND <statement1>) & 0 OR (Not <condition>
AND <statement2>)
This works because Centura only evaluates as much of the AND-OR expressions as
is needed to decide the final outcome. Hence if <condition> is true, then
<statement1> must be evaluated to decided whether the first AND is True
or FALSE. If <condition> is false, then <statement1> does not need
to be evalueded and therefore is never executed. The same (but reverse)
is true for the second AND statement. The "&0 OR" part in the
middle is there to force Centura to evaluate both AND statements.
Additionally, you might consider constructing an expression that contains
VisStrChoose( ) or VisNumberChoose( ) to be evaluated by SalCompileAndEvaluate(
).
How can I open/print a file/document with
its default application?
This can easily be done with the Windows SDK function
"ShellExecuteA" (leave out the "A" in 16-bit SQLWindows).
Example:
Call ShellExecuteA( hWndForm, "open", "C:\example.doc",
STRING_Null, STRING_Null, SW_SHOWNORMAL )
Call ShellExecuteA( hWndForm, "print", "C:\example.doc",
STRING_Null, STRING_Null, 0 )
To avoid the appearance of a new window, specify "SW_HIDE" as
the last parameter. Other SW_* parameters are defined in the SDK libraries.
It is possible to send eMails with the above function call. Just pass
"open" and "mailto:Centura_FAQ@gmx.net" in
the call to ShellExecute(A).
How can I close an external application from
within SQLWindows or SQLWindows/32 (for example the local database
engine)?
Just use the following function:
Call SalPostMsg( SalAppFind( sAppliationName, FALSE ), SAM_Close, 0,
0 )
sApplicationName could be set to "DBNT1SV.EXE".
How do I use SalAppFind on NT, it works on
all other platforms?
You have to run a specific OS installation routine which is located in your
Deploy directory. See
http://www.centurasoft.com/support/tech_info/knowledge_base/ctdinfo/wintdist.html
for further information
How do I open a file with long file/path
name and SalLoadApp( )?
You have to submit additional quotes like
Call SalLoadApp( '"C:\\Program Files\\Microsoft
Office\\Winword.exe"'
How do I specify multiple file extensions in
one file type selection row of SalDlgOpenFile( )?
Just use the following code as an example:
Set saFilters[0]='Images Files'
Set saFilters[1]='*.bmp; *.gif; *.jpg; *.tif; *.wmf; *.ico'
Set nNumFilters=2
Call SalDlgOpenFile( hWndOwner, sTitle, saFilters, nNumFilters, nIndex, sFile,
sPathedFile )
What is SOUNDEX and how can I
use it?
SOUNDEX is an algorithm that converts strings to a 4-byte code. It can be used
to encrypt a surname and do searching only on the code. This will eliminate
most variations of different spelling. Example: Meyer=M600, Meier=M600, Mayer=M600,
Smith=S530, SMYTHE=S530.
The function listed below generates the soundex code for a string that is
passed to the function.
Function: Soundex
Description:
Returns
String:
Parameters
String: p_sOrgString
Static Variables
Local variables
String: s
String: result
String: PrevChar
String: Ch
Number: i
Actions
Set s=SalStrUpperX( SalStrTrimX( p_sOrgString ) )
If s !=STRING_Null
Set PrevChar=STRING_Null
Set result=SalStrLeftX( s, 1 )
Set i=1
While i < SalStrLength( s )
If SalStrLength( result )=4
Break
Set Ch=SalStrMidX( s, i, 1 )
If Ch !=PrevChar
If SalStrScan( 'BPFV', Ch ) >=0
Set result=result || '1'
Else If SalStrScan( 'CSKGJQXZ', Ch ) >=0
Set result=result || '2'
Else If SalStrScan( 'DT', Ch ) >=0
Set result=result || '3'
Else If Ch='L'
Set result=result || '4'
Else If SalStrScan( 'MN', Ch ) >=0
Set result=result || '5'
Else If Ch='R'
Set result=result || '6'
Set PrevChar=Ch
Set i=i + 1
While SalStrLength( result ) < 4
Set result=result || '0'
Return result
Is it possible to use a timer that has
longer intervals than those provided by SalSetTimer( )?
A: I would suggest to set some date/time-variable to the current time, then
call SalSetTimer() with a value 1 minute (you should specify less, if you need
more accurate timing, common rule is you get a maximum error of +/-
time_specified/2). Then in the message actions of SAM_Timer you have to check
your date/time-variable against the current-time and see if the needed amount
of time has elapsed (remember you get values in days if you compute the
difference between dates, that means 0.000001157407.. or 1/86400 are one
second.
Alternatively, you could use the SDK function SetTimer( ).
How do I search an array of UDV?
You can use the standard VisArrayFindNumber(), VisArrayFindString(), and
VisArrayFindDateTime(). The search is performed on the first member of the UDV.
When the UDV is derived from another UDV, the first member is also the one from
the base class.
Functional Class: cTestClass
Instance Variables:
String: m_sName
Number: m_nAge
...
cTestClass: ObjArray[*]
...
Set ObjArray[0].m_sName="Tom"
Set ObjArray[1].m_sName="Sam"
Set ObjArray[2].m_sName="Pam"
...
Set nIndex=VisArrayFindString( ObjArray, "Pam"
) ! nIndex will be set to "2"
VisArray* functions defined in VT.APL (SW) and VTARRAY.APL (CTD).
How do I set up an UDV as a receive parameter in
Centura's development environment?
User-defined variables are always passed by reference (as a receive parameter).
That is why SQLWindows and SQLWindows/32 do not differentiate between normal
and receive paramters with functional classes.
How do I define an external function?
External functions usually reside in dynamically linked libraries (DLLs). A
function has to be identified by SQLWindows or Team Developer. If an export
ordinal is supplied, Centura will use it to identify the function uniquely.
Otherwise, the development environment uses the function name.
It is possible to set up one function several times with different function
names. In this case, you have to enter the correct export ordinal each time. If
the function name is spelled correctly, set the export ordinal to
"0".
It is recommended to use the correctly spelled function name in 32-bit, because
there are some differences between Windows 95 and Windows NT in the export
tables of DLLs.
What is an export ordinal?
An export ordinal uniquely defines a function within a dynamically linked
library (DLL). Upon building the DLL, the export ordinal is defined in the
project's definition file (*.DEF). Some DLLs specify a certain base ordinal
that has to be added to each definition.
How do I determine the export ordinal of a
function?
There are a couple of utilities that allow you do view the structure of a DLL.
If you are using a 16-bit development environment, you can determine a
function's export ordinal by running MAPDLL.EXE (supplied with SQLWindows) or
EXEHDR.EXE (comes with Visual C++). Team Developer does not ship with
such a tool. Windows 95 and Windows NT 4 include a utility named
"QuikView" which is added to the explorer's context menu. Just
right-click on a DLL and scroll down until you see the list with exported
functions ("Export table"). Mind that the "base" (in the
header of the "Export table") has to be added to each value.
Is there a limit to the number of
parameters that can be passed to an external function?
Yes, there is a limit to the number of parameters that can be passed to an
external function. It is not actually a fixed number, but a limit that is
reached when the compiler cannot compile the function call because of it's
complexity. It was found that this usually occurs at 15 or more parameters. The
solution is to pass an array or UDV handle to the external DLL. If it is one
you have written, if not, you may have to consider writing another DLL using
arrays or UDVs which then calls the DLL you want.
Can I use non-indexed DLLs (those
that have no export ordinal numbers)?
SQLWindows 5.0 as well as Team Developer can handle DLL's that export functions
without ordinal numbers. SQLWindows 4.1 requires ordinals.
How do I deal with CTD string handles
in Borland's Delphi?
Centura Team Developer has its own string handling mechanisms. Strings are
managed internally and only string handles can be seen from the outside. The
APIs used to accomplish this task reside in CDLLI1x.DLL and are included as
external functions. Furthermore, there are three wrapper functions that make
life somewhat easier:
- SWinCreateHString (create a new Centura string)
- SWinSetHString (replace the content of a Centura string)
- SWinGetHString (retrieve the content of a Centura string)
Find the necessary Delphi unit below:
unit HStrings;
interface
uses
Windows;
type
HSTRING=integer;
// creates a new string handle and copies s
function SWinCreateHString (s:PChar) : HSTRING;
// replaces the contents associated with the string handle with s
procedure SWinSetHString (hs:HSTRING; s:PChar);
// converts a string handle to a pascal string
function SWinGetHString (StringHandle:HSTRING) : String;
implementation
uses
SysUtils;
const
DLLName='CDLLI11';
function SWinStringGetBuffer (StringHandle:HSTRING; var Len:integer)
:
PChar;
stdcall; external DLLName;
function SWinInitLPHSTRINGParam (var StringHandle:HSTRING;
Len:integer)
: BOOL;
stdcall; external DLLName;
function SWinCreateHString (s:PChar) : HSTRING;
var
hs : HSTRING;
Len : integer;
begin
hs :=0; // handle=0 tells CTD to create a new string
Len :=strlen (s) + 1; // length of the string plus zero-byte
if SWinInitLPHSTRINGParam (hs, Len) then
StrCopy (SWinStringGetBuffer (hs, Len), s); // set the
content
result :=hs; // return the newly created handle
end;
procedure SWinSetHString (hs:HSTRING; s:PChar);
var
Len : integer;
begin
// handle is not zero, which tells CTD to replace the string
Len :=strlen (s) + 1; // length of the string plus zero-byte
if SWinInitLPHSTRINGParam (hs, Len) then
StrCopy (SWinStringGetBuffer (hs, Len), s); // set the
content
end;
function SWinGetHString (StringHandle:HSTRING) : String;
var
Len : integer;
begin
result :=StrPas (SWinStringGetBuffer (StringHandle, Len));
end;
end.
How can I execute a batch-file from
within Centura's development environemnts?
This can easily be done with the Windows SDK function "ShellExecuteA"
(leave out the "A" in 16-bit SQLWindows). Example:
Call ShellExecuteA( hWndForm, "open", "C:\example.bat",
STRING_Null, STRING_Null, SW_ShowNormal)
To avoid the appearance of a new window, specify "SW_HIDE" as
the last parameter.
My application crashes when I compile it
with a self-written DLL using MFC. How can I fix that?
SQLWindows(/32) loads/unloads the DLL to check the correctness of external
references during compilation. Experiments have shown that the function call
Sleep( 50 );
placed inside 'InitInstance' and 'ExitInstance' will fix the observed
error.
What is the difference between the
external data types LPSTR and LPCSTR?
It's mostly the same to CTD. The benefit is for you is that it is somewhat
documenting. For a string you can map it to an LPSTR or an LPCSTR, but for a
receive string you can only map it to an LPSTR. Similarly, a Number can be
mapped to a DWORD or a HANDLE. The HANDLE is more documenting about how the
parameter is used.
Where can I find documentation about
the various functions which exist in Windows DLLs like USER.EXE/USER32.DLL,
etc.?
These functions are documented in the Windows SDK, available with development
products like VC++, C++ Builder, VB, or the Microsoft Developer Network. The
information is also available online at
www.microsoft.com/msdn/.
How can I get the address of a
string-variable?
Use the following code:
nAddress=SWinStringGetBuffer( sString, lLength )
Library name: CDLLI11.DLL
Function: SWinStringGetBuffer
Description:
Export Ordinal: 0
Returns
Number:
DWORD
Parameters
String:
HSTRING
Receive
Number: LPLONG
How do I pass parameters that are part
of a pointed array of structures?
There are two ways to go about it. The simple way requires that you always pass
an array of the same size. If this works for you, than your declaration would
look something like this:
Function: DPtoLP
Returns
Boolean: BOOL
Parameters
Number: HANDLE
structPointer
Receive Number: LONG
Receive Number: LONG
Receive Number: LONG
Receive Number: LONG
Receive Number: LONG
Receive Number: LONG
Number: INT
This declarations presumes that you're always going to pass three POINTs.
You'd have to call it something like this:
Call DPtoLP( hDC, x1, y1, x2, y2, x3, y3, 3 )
If that doesn't work for you and you need dynamic arrays, then you could
declare the function like this:
Function: DPtoLP
Returns
Boolean: BOOL
Parameters
Number: HANDLE
String: LPVOID
Number: INT
With this declaration, you'd "stuff" the POINTs into a string
variable first using CStructPutLong from the CSTRUCTL.APL library. The call
would look something like:
! assume na[ ] is a 2D array of point data.
Set nPointSize=8 ! 2 longs
Set nNumPoints=5 ! just for this example
Call SalStrSetBufferLength( sBuffer, nPointSize * nNumPoints )
Set n=0
While n < nNumPoints
Call CStructPutLong( sBuffer, n * nPointSize, na[n, 0] ) ! first
long
Call CStructPutLong( sBuffer, n * nPointSize + 4, na[n, 1] ) ! second
long
Set n=n + 1
Call DPtoLP( hDC, sBuffer, nNumPoints )
How can I avoid the empty areas when I
resize a toplevel window?
This can be accomplished by trapping the windows message WM_SIZE and
aligning the child windows properly on the form window. Table windows and list
boxes should extend their size, pushbuttons will have to be placed accordingly,
radio and check boxes moved to the right or bottom. A sample on how this can be
accomplished is available for download:
RESIZE.ZIP
Is it possible to determine the window
handle of a status bar in order to place controls in it?
The identifier of a status bar is hard-coded into SQLWindow/Team
Developer and equals the hex value 0x7FF1. By calling the SDK function
GetDlgItem( hWnd, 0x7FF1 ), the window handle of the status bar is returned.
hWnd must be the parent of a form window, so from within the message actions
section of normal toplevel window you would have to use the following code:
On SAM_Create
Set hWndStatus=GetDlgItem( GetParent( hWndForm ), 0x7FF1
)
Controls can be easily placed there with a call to SetParent( ).
Alternatively, you could create a small form window and place all the controls
on it, that you want to appear on the status bar. Keep in mind, that height and
width of the status bar is limited.
Call SalCreateWindowEx( frmDummy, hWndStatus, 0.0, 0, nFormWidth,
nFormHeight, CREATE_AsChild )
In which order are child controls created at
runtime?
Except for lines, frames, and pictures, all child items of a container
window are created in the order they appear in your outline. This behaviour
will ensure the "z order", meaning that background texts will not
appear to be on top of data field, for example.
How can I set the tab-order dynamically at
runtime?
This can be accomplished with the SDK funktion SetWindowPos( ). Alternatively,
VisWinSetTabOrder( ) as defined in VT.APL/VTWIN.APL will work also.
I'm searching for items in the toolbar and
SalGetFirstChild() and SalGetNextChild() don't seem to work?
First, you have to look for the window handle of the toolbar (which is not the
same as your form, respectively hWndForm). Afterwards, you can get acquire the
window handles of the controls with SalGetFirst/NextChild( ).
Set hWndToolbar=SalGetFirstChild( GetParent( hWndForm ), TYPE_FormToolBar
)
Set hWndToolbarChild=SalGetFirstChild( hWndToolbar, TYPE_Any )
How do I get the handle of a window I only
know the name of?
Find the handle using SalFindWindow( hWndParent, sWindowName ) for
SQLWindows/32 or SWinFindWindow( hWndParent, sWindowName ) for SQLWindows.
Errors have been reported with these functions when there are instances of the
cOutlineComboBox placed on a form. In such a case, you might want to try the
interal function below:
Function: __FindWindow
Returns
Window Handle:
Parameters
Window Handle: hWndContainer
String: sTemplate
Local variables
Window Handle: hWnd
Window Handle: hWndChild
Number: nTypeMask
String: sName
Actions
Set hWnd= SWinFindWindow( hWndContainer, sTemplate
)
If hWnd=hWndNULL
Set nTypeMask=TYPE_Any
Set hWndChild=
SalGetFirstChild ( hWndContainer, nTypeMask )
Loop
If
SalGetItemName ( hWndChild, sName )
If sName=sTemplate
Return hWndChild
Set
hWndChild=SalGetNextChild ( hWndChild, nTypeMask )
If
hWndChild=hWndNULL
Break
Return hWnd
How can I detect/prevent that the user shuts
down Windows?
When the user tries to shut down Windows, WM_QUERYENDSESSION is sent to all
applications. If you want to allow the termination return TRUE. If you return
FALSE, Windows will not be closed.
How do I get window handle of a Background
Text?
Window handle of a Background Text can be captured by setting SQLWindows
bStaticsAsWindows parameter.
Before creating a Form Window which contains the Background Text, use statement
"Set bStaticsAsWindows=TRUE". Use SalGetFirstChild and
SalGetNextChild functions to extract the window handles of the Background
Text's you are interested in.
When trying to place a cCalendarDropDown in a
Toolbar, I get GPFs. How can I fix that?
When placed on a Tool Bar, the object GPFs when setting m_lpControl in the
VTM_ControlCreate message. It appears that the window objects aren't
"there" yet, so if you post the same message to itself, the
control works beautifully.
Original Message Actions
On VTM_ControlCreate
Set m_lpControl=lParam
Workaround Message Actions
On VTM_ControlCreate
If wParam
Set m_lpControl=lParam
Else
Call
SalPostMsg(hWndItem,VTM_ControlCreate, TRUE, lParam)
How can I hide a group box?
You can find the handle of a groupbox on a form by using SalGetFirstChild()
with TYPE_GroupBox. The following example shows or hides a groupbox identified
by it's title:
Function: Switch
Description:
Returns
Boolean: bSucceeded
Parameters
String: p_sGroupboxTitle
Boolean: p_bMakeVisible
Static Variables
Local variables
Window Handle: hWnd
String: sText
Actions
Set hWnd=SalGetFirstChild( hWndForm, TYPE_GroupBox )
While hWnd !=hWndNULL
Call SalGetWindowText( hWnd, sText, 256 )
If sText=p_sGroupboxTitle
If p_bMakeVisible
Call SalShowWindow( hWnd )
Else
Call SalHideWindow( hWnd )
Return TRUE
Set hWnd=SalGetNextChild( hWnd, TYPE_GroupBox )
Return FALSE
Is it possible to have the text
(label) of a check box appear on the left?
To have the label of a check box switch sides, the button style
"BS_LEFTTEXT", defined in the Windows SDK, has to be assigned which
can be done with the following code (remove the "A" in the
*WindowLong functions when using SQLWindows):
On SAM_Create
Call SetWindowLongA( cbCheck, GWL_STYLE, GetWindowLongA( cbCheck,
GWL_STYLE ) | BS_LEFTTEXT )
To assign this style using the Visual Toolchest enhancements (defined in
VT.APL/VTWIN.APL), call
On SAM_Create
Call VisWinSetStyle( cbCheck, BS_LEFTTEXT, TRUE )
How do I determine the window handle of
the data field part of a combo box?
By making use of the Windows SDK, the handle of the editing part of a combo box
can be returned with
GetWindow( cmb1, GW_CHILD)
When I disable a combo box, the
combo box text is hard to read. How can I make it appear in the original black
font?
The trick is to disable the combo box, but enable the contained data
field. This can be done by adding a global function to your class library:
Function: BlackDisabledCombo
Description: Disables a combo box, but leaves text black,
rather than hard-to-read "disabled gray" color.
Returns
Boolean:
Parameters
Window Handle: p_hWndCombo
Static Variables
Local variables
Boolean: bOk
Window Handle: hWndEditPortion
Actions
Set bOk=TRUE
Set bOk=bOk AND SalGetType(
p_hWndCombo )=TYPE_ComboBox
Set bOk=bOk AND SalDisableWindow(
p_hWndCombo )
If bOk
Set
hWndEditPortion=GetWindow( p_hWndCombo, GW_CHILD )
Set bOk=bOk AND hWndEditPortion !=hWndNULL
Set bOk=bOk AND
SalEnableWindow(hWndEditPortion)
Set bOk=bOk AND SalSendMsg(
hWndEditPortion, EM_SETREADONLY, TRUE, 0 )
Return bOk
However, the above function does only work for combo boxes having the
"editable" style set. If you still need to prevent the user from
altering the text contained in the combo box, use the following (in the
SAM_CreateComplete message of its parent, for example):
Call SalEnableWindow( hWndCombo )
Call SalSendMsg( GetWindow( hWndCombo ), GW_CHILD), EM_SETREADONLY, TRUE, 0 )
Check the August 1998 issue of
Centura Pro for
further information.
Is there a way to avoid disabled
datafields appear grayed out on Win32s platforms?
This can be accomplished with setting the attribute "Editable" to
"No" in the object's customizer. Then, when the field gets disabled
at runtime using SalDisableWindow( ), add the call SalSetColor( dfDatField,
COLOR_IndexWindow, COLOR_White - 1 ). There is a limitation in Windows causing
disabled fields to refuse appearing in COLOR_White.
Alternatively, you could just make the control read only instead of disabling
it. This can be done with sending the message EM_SETREADONLY to the control,
passing TRUE in wParam.
How do I create a window without the
system menu?
Just add the following code to the windows message actions section:
On WM_NCCREATE
Call SetWindowLongA( hWndForm, GWL_STYLE, GetWindowLongA(
hWndForm, GWL_STYLE ) - WS_SYSMENU )
In 16-bit SQLWindows, remove the "A" from the function
definitions.
How do I trap that a window gets
minimized?
The WM_SIZE message gets send when the user clicks the
"minimize" button in the title bar or chooses this function from the
system menu. The type of sizing is passed in the wParam variable as shown
below:
On WM_Size
If wParam=SIZE_MINIMIZED
How do I prevent scroll bars to appear
when resizing?
Set the form page width and height to 0.01" at design time.
I add a dynamically built menu to my
MDI Window. Why does it get lost when switching to another MDI child?
Menus are built depending on the current MDI child. Whenever the user
switches to another child, the menu set up for that form becomes the current
menu of the MDI parent. If you want to build a dynamic menu in a MDI Window,
you have to rebuild your dynamic menu every time the current MDI child changes.
In order to do this, trap the WM_MDIACTIVATE on the MDI Child (the Form Window,
not the MDI Parent Window), and recreate the menu if wParam is TRUE. This
parameter indicates that the window get activated, not de-activating.
Alternatively, you can return FALSE when receiving WM_MDIACTIVATE to avoid
updating the menu.
How do I append text to a multiline
field?
The easiest solution is using
Set mlField=mlField || sNewString
This is not a useful technique when the new text portion should be
scrolled into view as in console windows or progress notificators. The
following technique is recommended by Microsoft and can be easily wrapped up in
a global function, FieldAppendText( ), for example:
Call SalSendMsg( mlField, EM_SETSEL, -1, -1 )
Call SendMessageA( mlField, EM_REPLACESEL, 0, CRLF || sStringToAdd )
In 16-bit SQLWindows, use SendMessage( ) instead of SendMessageA( ).
How do I position the cursor in a
multiline field?
This can be achieved by using the EM_SETSEL message as defined in the SDK
libraries available for download.
The following example shows how to move the cursor to the 25th character:
Call SalSendMsg( mlField, EM_SETSEL, 25, 25 )
Additionally, if the following ten characters should be selected, use the
following function call:
Call SalSendMsg( mlField, EM_SETSEL, 25, 35 )
I try to display text with some page
breaks in my multiline field, but all breaks are displayed as double
concatenate-chars ("||"), why does that happen?
When retrieving text from external sources sometimes you get the paragraph
breaks as CR/LF (DOS/Windows) and sometimes as CR (mostly on Unix). Centura
(like other Windows-programs, e.g. Notepad) expects that there is the
CR/LF-combination, therefore if there is only CR it doesn't display
page-breaks. You must convert the single CRs in your text to CR/LF.
CR is ASCII-code 0x0a
LF is ASCII-code 0x0d
How do I spool a Quick Graph to the
printer?
QG.ZIP is a simple sample that show how to use the Quick Graph with SAL. That
is, that graph is not linked directly to a datasource. You control the graph
programmatically. QG.ZIP also include two options for printing the graph, one
using a .WMF file, and another showing how to print the QG by linking it to
detail lines in a .QRP report. The sample is using the BUDGET table from the
sample database. QG.ZIP include QG.SQL, SW_QG.APT, CTD_QG.APT and two .QRP's.
QG.ZIP sample work with both SQLWindows and CTD higher than 1.0.0. Click
here to jump to the downloads
section.
How do I set up a control to have no
association to any of the tab pages at all?
Enter the "Associate with tab" dialog from the context menu.
When you click on the last row, just hold done the shift-key or use the space
bar to deselect the last row.
SalHideWindow doesn't work with QuickTabs. How
do I keep controls hidden?
Whenever you activate a tab, it goes through its business of making visible the
associated child objects. To keep a child object hidden at that moment of time,
you'll need to tap into the functionality provided by the QuickTab class
library. Here's what you need to do:
In the parent form window, code the following window function:
Function: TabActivateStart
Description: Indicates that a tab has been activated.
This function is called before the child windows have been shown
Returns
Parameters
Window Handle: hWnd
Number: nTab
Static Variables
Local variables
Actions
If nTab=2 !
2 is the # of tab in which df1 exists
Call
picTabs.HideWindow( df1 )
df1 is the data field that you need to hide. What's really happening is that
TabActivateStart is a late-bound function call in the class library. It allows
you to hook into the process of a tab being activated when the user clicks on
it. At that point in time, calling this special flavor of
"HideWindow" function does the trick.
To hide an object on the default tab, you'll need to plug in another late-bound
function call, TabCreate(), as a window function of the form window. This is
because the default tab won't need to call the TabActivateStart() function
until the time the user tabs away to another tab and revisits subsequently.
Function: TabCreate
Description: Indicates that a tab has been created.
This function is called when the tab control receives SAM_Create.
Returns
Parameters
Window Handle: hWnd
Static Variables
Local variables
Actions
Call picTabs.HideWindow( df1 )
And you can use picTabs.ShowWindow ( hWnd ) to make the object visible.
When I edit the base class which includes
cQuickTabsDialog or cQuickTabsForm I lose all the information in the derived
Windows! Can I avoid this?
Some information is stored in picTabs, which is replaced if something changes
and therefore this gets lost. You can work around this problem if you remember
all the tabs in the QuickTabs editor and recreate them with the equal names
after changing your classes. The child windows will be on the same tabs as
before, because they reference the page on which they are to be shown by named
properties.
How do I hide individual tab pages of a
cQuickTab?
Hiding is not directly supported in the cQuickTab interface. However, you can
delete a tab and recreate it later using the same tab name (and label if you
want). All associated child windows will still appear as configured at design
time on the correct page. Keep in mind that the index will change when deleting
pages at the beginning, i. e. the second tab page will become the first one if
the with Index=0 gets erased.
I am trying to figure out how to associate
a child window on a tab. How can I do this?
If you look at properties from the "Outline" tab of SQLWindows/32,
you will not find "Associate with tab" over there. But if you switch
to "Layout" mode and look at control properties the "Associate
with tab" will appear (if the form/dialog is derived from cQuickForm or
cQuickDialog class).
I've derived a new class from the Tab
QuickObject. Now, I cannot access the tab properties anymore. How can this be
fixed?
You need to configure the editor settings for the new class. Select your new
class in the outline and do the following:
1) Click on cQuickTabsParentForm(/Dialog) or cQuickTabs and go to the
"Component" menu, select QuickObject editor.
2) Write all of the entries down for that class, especially application and
dialog name.
3) Pick your derived class from the outline.
4) Enter the entries taken from the tab class in the QuickObject editor for
your self-written class.
Is it possible to have the text
(label) of a radio button appear on the left?
To have the label of a radio button switch sides, the button style
"BS_LEFTTEXT", defined in the Windows SDK, has to be assigned which
can be done with the following code (remove the "A" in the
*WindowLong functions when using SQLWindows):
On SAM_Create
Call SetWindowLongA( rbRadio, GWL_STYLE, GetWindowLongA( rbRadio,
GWL_STYLE ) | BS_LEFTTEXT )
To assign this style using the Visual Toolchest enhancements (defined in
VT.APL/VTWIN.APL), call
On SAM_Create
Call VisWinSetStyle( rbRadio, BS_LEFTTEXT, TRUE )
How do I change the background color
for individual cells of a table window?
Unfortunately, this is not directly supported as it is possible to
change the text color with SalTblSetCellTextColor( ). However, it can
be accomplished by manually painting table windows or by placing controls on
top of it. These techniques got explorered by Gianluca Pivato in Centura Pro's
July 1997 issue, "Super-flexible Table Windows", and the December
1997 copy, namely "Custom Painted TableWindows". The functions
covered in the latter article are available as a 3rd-party product at
www.pivato.com wrapped into a
DLL .
Additionally, a similar table window enhancement called "TableGDI" is
available at www.primeardour.co.nz/primeardour.
How can I reset the style of a column to
normal (a function like SalTblDefineNormalColumn)?
Such a function doesn't exist in CTD. However, it can be easily
implemented by including the following global function in your code:
Function: SalTblDefineStandardColumn
Description:
Returns
Boolean:
Parameters
Window Handle: p_hWndColumn
Static Variables
Local variables
Boolean: bRetVal
Window Handle: hWndParentTable
Number: nColID
Actions
Set bRetVal=FALSE
If SalGetType( p_hWndColumn
)=TYPE_TableColumn
Set
hWndParentTable=SalParentWindow( p_hWndColumn )
Set
bRetVal=SalSendMsg( hWndParentTable, WM_USER + 122, SalTblQueryColumnID(
p_hWndColumn ) - 1, 0 )
Return bRetVal
Is it possible to implement sorting in
ascending/descending order by clicking on the column header of a table
window?
The table window must be set up to capture for a click on a column header (gray
area at top of each column). This is accomplished by setting a table flag on
(TRUE); usually this is done at the time the child table window is created, but
it could be done at any time you specify. At the Message Action section of the
table window:
On SAM_CreateComplete
Call SalTblSetTableFlags(hWndForm, TBL_Flag_SelectableCols, TRUE)
Now that the table is able to capture for a click on a column header, you may
use another message at the table window's Message Action section. When the
customer clicks on a column header, it will be directed to this block of code
that contains a call to a function named ColumnSort(), for example. This
function is expecting a number as a parameter, and conveniently enough, wParam
in this case contains the column's window handle in the form of a number.
(Window Handle is a unique address given to each window object such as a push
button, data field, column and so on when they are createdWindows takes
care of assigning this for you):
On SAM_ColumnSelectClick
Call ColumnSort(wParam)
This should be defined as a local function within the table window:
Function: ColumnSort
Description:
Returns
Parameters
Number: nColHandle
Static Variables
Boolean: bSortOrder
Number: nPreviousColumn
Local variables
Window Handle: hWndClickedCol
Number: nIdClickedCol
Actions
Set
hWndClickedCol =SalNumberToWindowHandle( nColHandle )
Set
nIdClickedCol=SalTblQueryColumnID( hWndClickedCol )
! the sort order is a numeric value
of either 0 or 1. The constants are
! TBL_SortIncreasing (1) and
TBL_SortDecreasing (0).
If nIdClickedCol=nPreviousColumn
Set
bSortOrder=NOT bSortOrder
! Don't use
FALSE - the code would not toggle between Ascending and Descending.
Else
Set
bSortOrder=TRUE
Call SalTblSortRows( hWndForm,
nIdClickedCol, bSortOrder )
Set nPreviousColumn=nIdClickedCol
This code is well suited to migration into a class library. This will allow all
your table windows to have this type of functionality and you don't ever have
to think about this code again.
How do I get around the problem of check
box columns displaying incorrect values?
There is a mysterious error in check box columns. To get around this anomaly,
just insert an invisible column (preferably as the first one) with the check
box style. It does not need to contain any data - just the existance solved all
problems with this column style.
After populating a table window with
TBL_FillNormal, blank rows appear if one tries to scroll up or down. How can
avoid this anomaly?
Try one of the following:
- The table needs to have its property "Discardable" changed from the
default of YES to NO.
- Make sure that the "Max Rows in Memory" value in the table's
properties is large enough.
- Ensure that the SQL handle used with SalTblPopulate( ) is not disconnected
before the table window gets destroyed.
You may want to review the table window chapter in the docs to understand how
the table window manages rows.
If a table window's Discardable attribute is set to yes, then the table window
expects that it can discard unmodified rows freely. Usually you use
this setting if the data is in a persistent result set that you can go back to
for refetching the rows. With this setting, the table window's Max Rows in
Memory attribute governs how many rows it will cache in memory at a time. If
you have a Discardable table window with 200 Max Rows in Memory, then it will
only cache 200 rows at a time. As you scroll the table window, it will discard
previously fetched rows once the cache is full to accomodate new rows. With
Discardable set to yes, a SAM_CacheFull message means all the rows being cached
have been modified so there's no space left to refetch rows. Use discardable
table windows when you want the table window to be a "window" into a
larger result set. You need to use
discardable table windows if you're working with a result set that is greater
than than the maximum Max Rows in Memory, which in SQLWindows is 32767
rows.
If a table window's Discardable attribute is set to no, then the table window
retains all refetched rows and doesn't discard any rows. Usually you use this
setting if you need the table window to contain the whole result of a query
because you're not using a database result set (possibly not even using a SQL
database). With this setting, Max Rows in Memory still governs how many rows
will be managed by the table window. If you have a non-Discardable table window
with 200 Max Rows in Memory, then you'll only be able to fetch the first 200
rows of a database query result, you'll get a SAM_CacheFull message if you try
fetch past this point.
So you have to decide what works for your particular application. If your using
result sets enabled, then you could leave your table window as discardable, and
set Max Rows in Memory to a suitably high setting. If you're not using result
sets, you could still have a high Max Rows in Memory setting. In fact,
developers usually use a table window class as the basis of
their table windows that defines Max Rows in Memory as 32750. This is
acceptable because row memory is dynamically allocated as needed.
How do I avoid SQLBase error 203 appearing
occasionally when filling a table with SalTblPopulate( )?
This error usually appears when the SQL handle specified for populating a table
window is used at other locations during the existance of the table window, for
example to insert or update data. The table's result set built internally with
Prepare/Execute gets destroyed and the table window is unable to fetch rows not
contained in the table window cache anymore. Read the online help for further
information on that topic.
I have a table window column and some code
under SAM_Validate where I try to clear the "Field Edit" flag with
SalTblSetRowFlags( tblTest, nRow, ROW_Edited, FALSE), and it just doesn't work.
How can I get it to work?
When leaving SAM_Validate with VALIDATE_Ok, then the Edit-Flag is set, so in
addition to unsetting it with SalTblSetRowFlags(), return also
VALIDATE_OkClearFlag out of SAM_Validate as shown in the following example
On SAM_Validate
If <Clear EditFlag but otherwise ok>
Call SalTblSetRowFlags( tblTest,
SalTblQueryContext( tblTest), ROW_Edited, FALSE)
Return VALIDATE_OkClearFlag
Else
Return VALIDATE_Ok
I have created the column with
SalTblCreateColumn( ). How can I refer to it as a bind or into
variable?
You can use # character as a separator between the table window
name and the column number to refer to automatically created columns.
tblMain#1 - first column of tblMain
frm1.tbl1#3 - third column of tbl1, a child table of frm1
How do I return the number of columns in a
table window?
In lieu of a SalTblQueryColumnCount function, here's a way to do it in SAL:
Function: QueryColumnCount
Returns
Number:
Parameters
Window Handle: p_hWndTbl
Static Variables
Local Variables
Number: nColCount
Number: nWindowType
Window Handle: hWndCol
Actions
Set nWindowType=SalGetType(
p_hWndTbl )
If nWindowType=TYPE_TableWindow OR
nWindowType=TYPE_ChildTable
Set
nColCount=0
Set
hWndCol=SalGetFirstChild( p_hWndTbl, TYPE_TableColumn )
While
hWndCol !=hWndNULL
Set nColCount=nColCount + 1
Set hWndCol=SalGetNextChild( hWndCol, TYPE_TableColumn )
Else
Set
nColCount=-1
Return nColCount
How can I hide a table window
row?
You can use the function SalTblSetRowFlags( ) with the ROW_Hidden constant. See
the help file for further information.
How do I get the handle of the listbox
element in columns with the "drop down" style set?
Put the following code in your column class:
On SAM_DropDown
! Find out the drop down handle
Set hWndDropDown=SalNumberToWindowHandle( SalSendMsg( hWndForm,
0x0400+119, SalTblQueryColumnID( hWndItem )-1, 0 ) )
You could for example use LB_SETHORIZONTALEXTENT to show an horizontal
scroll bar in the list box.
How many rows can be kept in the cache of a
table window?
In SQLWindows/16 this used to be 32753 rows. In CTD the table window cache
can theoretically address 2,147,423,632 rows, providing the operating system
can supply the required resources.
How do I make the Visual Toolchest
splitter bar display in 3D?
The cSplitterWindow has a flat style and doesn't fit nicely with other
controls displayed etched or in 3D. This appearance can be changed when the
following code is added to a splitter bar's message actions section.
On WM_NCCREATE
Call VisWinSetStyle( hWndItem, WS_DLGFRAME, TRUE )
On WM_NCHITTEST
Return HTCAPTION
On WM_MOVE
Call ResizeObjects( )
VisWin* is defined in VT.APL (SW) and VTWIN.APL (CTD).
Is it possible to replace the text
displayed in the Visual Toolchest cMeter control?
Yes, just set the Windows style to 0x00000010 and then call SalSetWindowText( )
to set the text of the meter. You can pass an empty string if there shouldn't
be any notification displayed at all.
When using the cOutline* classes, the
function GetItemHandle() does not seem to work sometimes. Is this
correct?
GetItemHandle() works only after ShowOutline() function is called. If any
item is not 'visible' in the outline, then GetItemHandle() returns a NULL or
0. But if all the items are 'visible' in the outline, then
GetItemHandle() returns a proper value.
I encounter crashes when using the
function Expand( ) with the cOutline* classes. How can this be
avoided?
This does happen if the Expand( ) function is called on a leaf node. Just check
if the specified item can get expanded, as soon shown in the following
code:
If GetItemFlags( hItem ) & ITEM_CanExpand
Call Expand( hItem )
This has been confirmed by Centura and will get fixed in upcoming releases.
What is the difference between SalSendMsg( )
and SalPostMsg( ) and when should which one be used?
SalPostMsg( ) will cause a message to be placed in the addressed window's
message queue. This message queue is queried once a thread enters idle state,
that is, when nothing else has to be executed. SalSendMsg( ) works just like a
normal function. The code in the receiver's message actions of the specified
message is immediately executed. You can return a numeric value when calling
SalSendMsg( ).
Mostly, SalSendMsg( ) is used. However, there are situations where posting a
message is necessary, for example when re-setting focus upon receiving
SAM_KillFocus.
How do I implement Query By Example in the
QuickObjects architecture?
One of the good things about QuickObjects is that it's an extensible framework.
For example, when the data source (the child table window) goes about its
business of formulating the SQL statement for retrieving data, it gives you an
opportunity to plug in your own WHERE clause or your own ORDER BY clause. In
the QuickObjects class code (in QCKDVC.APL), if you look at the function
cQuickTable.GetSqlSelect, you will notice a late-bound function called
"GetSelectWhere ()". All you need to do is define a function of the
same name in the instance of cQuickTable in your form window, and take care of
supplying the QBE-driven WHERE clause. Here's the pseudo-code you would use:
Loop through all the objects of the form window
(SalGetFirst/NextChild)
If the object participates in
the QBE
If the
object is not null (sContents)
- Check the database item name of this object
- SalWindowGetProperty (hWndItem, 'ITEM', sItem)
- Append to WHERE clause
- sItem || "LIKE " || sContents || "%"
See 'What does "QBE"
stand for?' for further information.
How can I get around the error 163
("Result sets are not active")?
Centura provides native connectivity routers (and ODBC access) to all popular
RDBMS brands like Oracle, Sybase, SQLServer, Informix, DB/2, etc. One of the
features provided by those routers is "front end result sets" (FERS).
Every time data is read from the backend, a copy of the data is written to the
PC's disk. This enables backward scrolling capability, a feature that is
normally missing in the backend. SQLBase, by the way, supports this as a native
feature (by formulating a scrollable result set on the backend). FERS enables
the following function calls to be made from the app:
- SqlFetchNext
- SqlFetchRow
- SqlGetResultSetCount
The FERS files are written to the TEMP directory on the PC. These files are
named as FRSn, where n is an integer. The router takes care of purging these
files as soon as they are not required anymore. There are certain instances,
however, when these files may linger "orphaned" -- typically under
abnormal termination conditions (affectionately known as "GPF" in
Windows parlance). Consequently, there may come a time when the TEMP directly
could have hundreds of these FERS files. Under some circumstances, the router
could have trouble creating a new file in the same directory -- even DOS has a
limit to the number of files that can be created in a directory. Or the disk
itself may run out of space. This is when you start noticing error 163 -- the
router is informing you that it could not create a result set file for you.
The solution is simple: every time you boot your PC, clean up your TEMP
directory. Better still, put the cleanup into your AUTOEXEC.BAT (echo Y | del
C:\Windows\Temp). On a more strategic note though, most of your application
could do without using FERS altogether! You see, when you populate a listbox,
you don't need this feature. And a table window can contain up to 32K rows
anyway, which should be more than sufficient in most cases. So, the trick is to
use FERS with DISCRETION. This feature can be turned off globally by the
following code:
On SAM_AppStartup
Set SqlResultSet=FALSE
FERS can also be set on a per cursor basis:
If SqlConnect ( hSql)
Call SqlSetResultSet ( hSql, FALSE )
For complete information on these functions, check your on-line help.
How can I quickly count the number of rows
in a table?
The easist solution can be wrapped in a function:
Function: SqlRowCount
Description:
Returns
Number:
Parameters
Sql Handle: p_hSql
String: p_sTableName
Static Variables
Local variables
Number: nRowCount
Actions
If p_hSql !=hWndNULL
If
SqlPrepareAndExecute( p_hSql, 'ROWCOUNT ' || sTableName )
If SqlGetModifiedRows( p_hSql, nRowCount )
Return nRowCount
Return -1
Alternatively, you could call the function SQLGNR from the SQLBase C/API.
It is defined for SQLWindows (16-bit) in library SQLAPIW.DLL and for Team
Developer (32-bit) in library SQLWNTM.DLL.
Function: sqlgnr
Description: Determines the rows in a database table
Export Ordinal: 0
Returns
Number: SHORT
Parameters
Number: USHORT
String: LPSTR
Number: USHORT
Number: ULONG
Call sqlgnr( SqlGetCursor( hSql ), sTable, SalStrLength( sTable ),
nRowCountTable )
Keep in mind that this function only works with SqlBase and therefore
break portability to another database platform. However, there might be similar
functions that return the same information.
Is it possible to change the user name
appearing on the SQLBase-Server screen programmatically?
It can be done with the following function call:
Call SqlSetParameterAll( hSQl, SQLPCLN, 0, 'NewUserName', FALSE )
This is useful when only one SQL.INI is used for a group of workstations
in the network or one seat is shared by several users. The definition of
SQLPCLN can be looked up in SQL.H, found in the Centura installation
directory.
I receive the message "SQL Error: No
SQL Cursors remaining. Halt application?". What can I do to avoid
this?
This appears if 100 cursors are opened simultaneously. Check your application
to disconnect all SQL handles not needed anymore and don't connect an already
connected handle a second time. You should also check to disconnect all
previously connected handles if in case of errors you exit with an error
code.
Is it possible to stop stop the execution of
a command sent to the database with SqlPrepare(), SqlExecute(), or
SqlImmediate()?
From within SQLWindows and SQLWindows/32 it is currently not possible
to kill or stop the execution of a SQL statement. SqlPrepare/SqlExecute will
return control to the application when the specified SQL processing is
finished. To stop SqlPrepare/SqlExecute( ) before control is returned to the
application, you would need external software that watches the duration of SQL
processing inside your application (DLL) or a development environment being
capable to manage multiple threads.
What you can do is controlling fetching data. For SalTblPopulate( ) this can be
done with returning TBL_NoMoreRows on SAM_FetchRow. Normal fetching can be
interrupted after each SqlFetch* call. The corresponding code would look
like this:
Function: Populate
! ... Disable form here (except pbCancel)
Set bOk=bOk AND SalYieldStartMessage( pbCancel )
While bOk AND NOT bCancel AND SqlFetchNext( hSql, nFetch
)
! ...
! ... (for example SalTblInsertRow(
)
! ...
Set bOk=bOk AND SalYieldStopMessage( pbCancel )
Pushbutton: pbCancel
On SAM_Click
Set bCancel=TRUE
I experience problems while trying to
connect to the database. What am I doing wrong?
There are some steps you should check thoroughly:
1. Are you using one and only one SQL.INI? Try to have only one SQL.INI in the
Windows-PATH and directories that could be referenced by your application,
better in the whole system to make sure that your application is using the
correct one. Having several versions might produce unexpected errors.
2. Some DLLs from Centura get installed in various places. Check if you have
the correct versions of them (right click in Windows-Explorer and then
Properties...), because Centura applications can behave unpredictable wrong if
there are mixed versions being used. You should especially look after
SQLWNTM.DLL and SQLNGCI.DLL which are installed into the Windows system folder,
and the communication DLLs from the SQLBase or development directory. Some of
the important ones (depending on your setup) are SQLAPIPE.DLL, SQLAPIW.DLL,
SQLWSOCK.DLL, SQLWS32.DLL, SQLWSSPX.DLL, SQLORA.DLL, SQLORA32.DLL, SQLODBC.DLL,
SQLODB32.DLL.
3. Go step by step when trying to get things like connections to foreign
database systems working! That means, set the foreign client up first and use
the client tools
(ISQL/W, SqlPlus, MSQuery for ODBC-Connections, ...) to see if the pure foreign
database connection works! Then you can configure your SQL.INI and use SQLTalk
first to see if this works. Look in "Help-About" to see if the
correct file versions were loaded (the PTF level is displayed there as well).
Once you are able to establish a connection through SQLTalk, there should not
be a problem with the database connection from your application.
Check the Database Products FAQ for
further information about installing and configuring database server and
clients.
After a call to SqlVarSetup( ) the flow of
execution suddenly jumps somwhere else and reports mysterious errors. What is
going on?
This behaviour can sometimes be observed when SqlVarSetup( ) is placed before
SqlPrepare( ). Just move it done until you actually execute the prepared
statement, thus, right before SqlExecute( ).
How can I export a binary object (e.g. a
BMP) from a SQL-Database to a file?
You'll need to SELECT you BMP INTO a long string-variable in SQLWindows/Centura
Builder, then use SalFileWrite() to write the file to disk. If the BMP had been
compressed at INSERT time, you'll need to uncompress before the write.
I'd like to periodically check whether the
cancel button has been pressed during long operations. How can I accomplish
this?
Take a look at the SalYield* functions. If the form window/dialog box gets
disabled before the beginning of the transaction, please don't forget to enable
the Cancel button.
I would like to know how to use the SQLBase
C/API. I am interested in doing UNLOAD, LOAD and REORGANIZE. How do I get
going?
Starting from the release of SQLBase 6.00 and the new functions sqlunl() and
sqlldp() this can be done from within a SQLWindows/16 and SQLWindows/32 (CTD)
program. In fact you do not need to to use the C/API all the way as
SqlPrepareAndExecute() now support UNLOADING and LOADING. Download
SBCAPI.ZIP for further information
and sample code.
My application eats up the available memory
and eventually crashes when running long database processes. How do I avoid
this?
First thing you can do is to eliminate all calls of SqlImmediate(), because
this function eats memory with every call. Second step is to close sql handles
which are kept after SqlFetchNext()-calls with the SqlClose()-function
regardless if ResultSetMode is on or off for this handle. This will free memory
allocated for this resultset and prevents your application from consuming more
and more memory. With these two things in mind people have succesfully
implemented very long
running transaction (36 hours on Oracle) with many selects, inserts and
updates.
How do I reduce the number of timeouts in
my application?
- The default mode for SQLWindows when it connects to SQLBase is RR - Read
Repeatability. When you connect your cursors, you should change the the
isolation level to RL - Release Locks. This alone may reduce your
Timeouts dramatically - if you are not doing this now.
- Make sure that all Transactions ( update/insert/delete ) are handled quickly
and a commit ( or rollback ) is done at the end of the Transaction before ANY
user display or interaction is allowed. After all, modification
statements will put an Exclusive Lock on the data, and will increase the
likelyhood of Timeouts until commited or rolledback.
- Alter the Timeout period after you connect the cursors. The timeout
period should be set to at lease 30 - 40 seconds - something reasonable.
- You may wish to implement RO - Read Only isolation mode for cursors that are
just going to be used for reading the database. Please read about
ReadOnly and see if you would like to use it. There may be a performance
hit when using RO.
- Do NOT use SqlImmediate( ... ) or SqlExists( ... ) in your SQLWindows code!
These commands will lead to unnecessary timeouts! You can easily write your own
SqlImmediate command by defining your own cursor, etc. And you will have
MUCH more control as to what is happening in your code. I can NOT be too
emphatic about not using these two commands.
- It is possible to increase the PCTFREE parameter in a table definition. For
more information about this issue, consult the online books. This will probably
increase your database size quite significantly, though.
I am having problems printing from
ReportWindows on a HP Laserjet 5 printer. How can I get around this
problem?
There are several problems with HP printer drivers in conjunction with
Centura products. Usually, the LaserJet 4 driver supplied with Windows 95 works
correctly. Instead of using the drivers supplied with the DeskJet 6xx and 8xx
series, use a standard DJ 500 or 550 printer driver.
A landscape report saved as a RTF file loses
its orientation in Word, how can I fix that?
When printing landscape report to RTF-file with
SalReportPrintToFile( ) function, paper size is generated properly but the
"\landscape" RTF command is not generated as it should be. This leads
to the problem that Word interprets report in landscape size but orientation is
portrait. Printing such a document causes incorrect result.
"\landscape" defines that the whole document is in landscape
orientation. This means that you have to do function which opens RTF-file after
print, add "\landscape" control word to where other paper properties
are set (\paperhN\paperwN and so on). So the correct control word series could
be like:
\landcape\paperw16833\paperh11908
(A4 landscape, width and height are in twips).
Pictures are not displayed correctly in RTF
files generated with ReportWindows. How do I have them display
correctly?
When printing to RTF-file with SalReportPrintToFile-function,
bitmaps are formatted as windows metafiles. For example original picture size
is 5.2" x 1.2" and it is scaled to 1.56" x 0.36" in report
template. The SalReportPrintToFile( ) function generates the following command
series in RTF files:
\pict\wmetafile8\picw1814\pich439\picwgoal7488\pichgoal1728
\picscalex30\picscaley30
So, if the picture should show correctly in Word 6, 7, and 8, the RTF commands
"\picw" and "\pich" should have following values:
\picw13210\pich3050 or \picw0\pich0
both of these result the same. This means that you have to do function which
opens RTF-file after print, search all the "\picw" and
"\pich" commands and set the correct values for them. Please note
that calculated values may differ a bit in the RTF-file.
RTF command | Meaning |
---|---|
\pict | This control word defines the picture beginning |
\wmetafileN | This control word sets
the picture type to a Windows metafile. N specifies the metafile type. This parameter must be 8 (MM_ANISOTROPIC) |
\picwN | This control word
contain an optional suggested picture size in MM_HIMETRIC units. This is the
control word that causes picture to be shrinked in width. It is not known why
SalReportPrintToFile-function generates this value as it does, but anyhow it
shows correctly on Word 6 and 7 but not in Word 8. This value should be
original picture size in MM_HIMETRIC units (one logical unit is mapped to
0.01millimeters) or just zero. For example, original picture height is 5.2" which is about 13,21 cm -> 132,1mm -> 13210 in MM_HIMETRIC units. |
\pichN | This command contain
an optional suggested picture size in MM_HIMETRIC units. This is the control
word that causes picture to be shrinked in height. It is not known why
SalReportPrintToFile-function generates this value as it does, but anyhow it
shows correctly on Word 6 and 7 but not in Word 8. This value should be
original picture size in MM_HIMETRIC units (one logical unit is mapped to 0.01
millimeters) or just zero. For example, original picture height is 1.2" which is about 3,05 cm -> 30,5mm -> 3050 in MM_HIMETRIC units. |
\picwgoalN | This specifies the
picture height set in ReportWindows. N specifies the desired height, in twips
(1\1440 part of inch) For example, width 5.2 inches=5.2*1440 twips=7488 twips |
\pichgoalN | This specifies the
picture height set in ReportWindows. N specifies the desired height, in twips
(1\1440 part of inch). For example, height 1.2 inches=1.2*1440 twips=1728 twips |
\picscalexN | Horizontal scaling
value. For example N=30, 5.2" x 0.30=1.56" |
\picscaleyN | Vertical scaling
value. For example N=30, 1.2" x 0.30=0.36" |
For more information on RTF, visit
www.microsoft.com to view
the RTF specifications online.
How do I develop a report that is able to
print multiple detail tables?
While handling multiple sets of data with RW you need to retrieve all
information for the detail tables as you skip through your master table. There
are several techniques for doing this. The
sample code shows two methods: One
fetching detail records into the .QRP one by one, another one is using a
technique reading the data into tabbed strings.
How do I avoid corrupted reports when exiting
ReportWindows (CTD 1.5)?
There is a bug that got introduce in version 1.5 of Centura's development
environment. Check the downloads
section for a small utility that recovers corrupted QRP files.
Is SQLWindow certified for Windows
95/NT?
SQLWindows 5.0.2 is the first certified version which you can use with Windows
95, beginning with 5.0.3 PTF4, SQLWindows has the NT compliant certificate.
Is it possible to run SQLWindows 5.x
without using all the components that are in the deploy catalog?
Yes this is possible, however note that you are on your own risk while doing
that. The tips you need are all documented in a paper called "SQLWindows
5.x minimized deploy catalog". Click
here to go to the downloads section.
The file is named SWDEPLOY.ZIP.
How do I determine the version of the
operating system?
This can be done with a call to GetVersion( ), however, the information
returned will only be different between Windows 95 and any other Windows
platform (return value "3.1"). To get the "real" version,
check out the file WIN16VER.APT which uses file version functions with
KRNL386.EXE. Look up returned values in the table given below. "WOW"
stands for "Windows on Win32".
Platform |
GetVersion( ) | "FileVersion" | "WOW Version" |
---|---|---|---|
Windows 3.10 | 3.1 | 3.1 | N/A |
Windows 3.11 | 3.1 | 3.11 | N/A |
Windows 95 | 3.95 | 4.0095 or 4.00.1111 (OSR2) | N/A |
Windows 98 | 3.98 (?) | 4.?? (?) | N/A |
Windows NT 3.1 | 3.1 | 3.1 | 3.1 |
Windows NT 3.5 | 3.1 | 3.1 | 3.5 |
Windows NT 3.51 | 3.1 | 3.1 | 3.51 |
Windows NT 4.0 | 3.1 | 3.1 | 4.0 |
I would like to integrate ToolTip support in
my applications. How do I do this?
ToolTips are part of the XSal extensions, written by
Gianluca Pivato.
How can I avoid the "OLE - Invalid class"
error message?
In SQLWindows, when one tries to add a QuestWindow in the form window, the
following error message is displayed. The application does not stop, but tables
in the database are not listed and one just can not use QuestWindow at this
point. You get an error saying "OLE - Invalid Class".
While loading Quest, during the various activity initialization, one may get
following messages in a sequence related to corrupted OLE registration
database: "Cannot Update Application Registration Database",
"Sorry, Unable to register the Activity Library"
After receiving these messages, Table and Query activities are disabled and can
not be used.
Windows 3.1:
Windows maintains the OLE registration database called REG.DAT. One can edit it
using the registration database editor called REGEDIT.EXE. These files usually
reside in the directory where MS Windows is installed, most typically in
C:\WINDOWS directory. Sometimes, the database might get corrupted due to number
of reasons such as bad sectors on hard disk, etc. There are 2 solutions to this
problem.
- Load REGEDIT.EXE. It lists all registered file types. Select Quest related
file types from the list. Choose "Delete File Type" option from Edit
menu and delete these entries. Exit the editor. Load Quest and it should be
running OK.
- Quit Windows and delete REG.DAT (might want to back up the file too), and
restart Windows. Run Registration Information Editor and select Merge
Registration File option from File menu. Select SETUP.REG (resides in the
Windows SYSTEM directory) from the file name list in the dialog box.
Windows NT:
When one logs on to newly-installed Windows NT computer first time, the system
migrates REG.DAT and portions of WIN.INI from the previous version of Windows
to the Registry in Windows NT. This Registry file is called REGISTRY.INF. The
status of each step in the migration is logged in the Application Log, which
can be viewed with Event Viewer.
The Registry is structured as a set of four subtrees of keys that contain
per-computer and per-user databases. One of the subtree is called
HKEY_CLASSES_ROOT which contains Object Linking and Embedding and file-class
association data. Each individual key can contain data items called value
entries and can also contain subtrees. Following are the steps to resolve this
problem on Windows NT:
Run Registry editor called REGEDT32.EXE. Under Windows menu, select
HKEY_CLASSES_ROOT. It will list keys called QuestQueryServer, QuestTableServer,
etc. among other keys. Select Delete option from Edit menu and delete these
Quest related keys. Run Quest. It should work OK now. One may have to exit
Windows NT and reload it if Quest does not work properly at this point.
Why do I face problems when trying to use OCX
controls whose methods have variant datatypes (SQLWindows/pre CTD
1.5)?
All versions of SQLWindows and SQLWindows/32 before Centura Team Developer 1.5
do not contain support for variant datatypes. That is the reason why the OLE
Class Wizard refuses to generate such classes.
What is the difference between
"SQLWindows/32" and Centura Team Developer?
The latest release of Centura's 32-bit application development tool is Centura
Team Developer. One of the components of Centura Team Development is the
development environment. In previous versions of Centura Team Developer, this
component was known as Centura Builder. In homage to their groundbreaking
16-bit development tool, they decided that in the Centura Team Developer 1.5,
they would rename the development environment to SQLWindow/32.
To state is another way: The product is still Centura Team Developer. Within
the product, the development environment is now called SQLWindows/32.
Is it possible to have both 1.5 and 1.1.x
installed simultaneously on the same machine?
It should be easy to set up your machine to use both 1.5 and 1.1.x. You
should even be able to use them at the same time.
The only problem with having two versions of CTD-SQLWindows/32 on the same
machine stems from the practice of not incorporating version numbers into the
names of APL files. If we did, you would have to fix up every APP you
wrote with the new name when you migrated to a new release, something I'm sure
you would rather not have to do. The steps used to attempt to locate APLs are
as follows:
- Look in the directories listed in the Application Path (SQLWin/32 1.5
only)
- Look in the directories listed in the Global Path
- Look in the directories listed in the PATH environment variable
Most people encounter problems because they rely on the environment PATH for
all of the built-in APLs shipped with CTD, although we do include the
directories which hold those files in the initial Global Path on
installation.
However, there was a problem with the 1.5 installer: it prepends the registry
setting of an earlier version of CTD - if there is on on the machine - to the
path constructed for the 1.5 version. Using the Directories tab of the
Prefeences dialog you should remove any 1.1.2 directories from the Global Path
for 1.5, as the first step to making the two versions coexist.
The next step is to make sure that the Global Path includes every directory
from the appropriate installation which that version should use to locate
Centura APLs (and also any third party APLs which link to Centura DLLs).
If that is done, then SQLWindows/32 will never resort to looking at the
environment PATH to locate APLs.
This means that you can leave directories of both installations in the
environment PATH so that DLLs can be located at compile- and run-time. Since
the DLLs (Centura's, in any case) do have version numbers, there will be no
conflict.
Important: Please keep in mind that the Object Compiler is version
dependent. You cannot use DLLs generated with version 1.1.x in conjunction with
CTD 1.5!
I do often get "Application
errors" when trying to open APP files. What should I do?
Try to save this file as "Text" or "Indented Text", close
CTD, and reopen this file.
Centura Team Developer crashes upon
opening a source code file. How can I recover the APP?
If CTD doesn't even let you open the file, use a CDK utility which can
be downloaded at
ftp.centurasoft.com/products/utilities/cvt2apt.zip or a
program called CBFIX.EXE which is available for download at
www.metex.com/Products/cbfix.
I've created an APP with CTD 1.5
(Eiger) and would like to open this file with a previous version. I've saved as
text, but apparently, it doesn't work. What should I do?
If you need go backwards, and open a CTD 1.5 app into CTD 1.1.2, the
following will work:
1) Save the app as text
2) use a text editor to change the outline version to 4.0.26
3) Delete lines pertaining to ActiveX features, including the ActiveX line in
Default Classes.
Then you shouldn't have any problems opening the app in CTD 1.1.2.
How can I easily check out the values
of named properties at design time?
Next to the browse capabilities of some 3rd-party applications and directly
looking at source code saved as text, Team Developer lets you print the named
properties set up for a specific item. Just go to the Page Settings window and
check the option "Include Named Properties".
I've converted my app from SqlWindows
to CTD 1.1. The application compiles, but during execution I get an application
error. How can I avoid this problem?
Make sure you step through the application. Often, 16-bit Windows API functions
got not converted correctly. Check your function definitions and replace them
according to the Win32 SDKdefintions, for example WORD to DWORD.
How do I avoid a general protection
fault "Unhandled exception 0x000c5"?
There can be many causes for such untimely exits of CBI11.EXE; sometimes it is
because your code has 'tripped' over a bug in the CTD runtime system which
causes an unhandled exception, and sometimes it is because the parameters
passed to an external function (a Sal function, or a Visual Toolchest method
which has a C++ implementation, for example) are incorrect, and attempts to
interpret them are not 'safe'.
The first, and often fastest, thing you can do to track down this problem is to
run your application with "Fast Animate" turned on, with the windows
layed out on the screen so that you can see what Sal code is being executed
when the program terminates. You can then re-run with a breakpoint set
at that line, and examine the parameters to see if they have correct and
legitimate values.
Check to see where it occurs and contact Centura support if it seems to be a
bug in the development environment. Often, this error appears due to incorrect
set up of external function calls.
Using version 1.0 of Centura Team
Developer, I experience a lot of crashes, especially on Windows NT machines.
What's wrong?
Version 1.0 is known to be very unstable. Consider switching to the next
version, i. e. 1.1 or 1.5.
When there are two applications
referencing the same Dynalib, are they loaded once or twice into
memory?
Each program loads its own copy of the dynalib.
According to the documentation,
CenturyDefaultMode behaviour should be in CTD 1.1.0. However, I get wrong
results. Can this be fixed?
CenturyDefaultMode behavior was targeted for CTD 1.1.0, but introduced until
CTD 1.1.0 PTF 1.
CTD 1.0.0 and vanilla CTD 1.1.0 do not have CenturyDefaultMode behavior. All
releases of CTD from CTD 1.1.0 PTF 1 onwards should exhibit CenturyDefaultMode
behavior.
When I load my application into
SQLWindows/32, I get error messages about "Invalid class size at line
xxx". Can I avoid this error?
This is a small, not critical error in Centura Team Developer. This might
appear when you change the initial object sizes of certain classes. Save the
file, exit and reopen it. The errors should go away.
Is Centura Team Developer certified
with NT 4.0?
Yes. With CTD 1.1.0 and higher.
I have heard about SqlContext*( )
functions but can't find them in the documentation. What are they used
for?
This is quoted from the SQLWindows 5 online help:
bOk=SqlContextClear ( hSql )
Clears the context set by SqlContextSet. SQLWindows evaluates the bind
and INTO variables associated with the specified Sql Handle in the local
context. For new applications, call SqlVarSetup instead of this function.
Parameters
hSql Sql Handle. A handle that identifies a
database connection.
Return Value
bOk is TRUE if the function succeeds and FALSE if it fails.
bOk=SqlContextSet ( hSql )
Sets the context for future processing (for
example, calls to SqlPrepare, SqlFetchNext, SqlFetchPrevious, and SqlFetchRow).
Sql* functions you call after SqlContextSet behave as if they are in the window
identified by hWndForm. Call this function in a class to perform SQL processing
for the current window without fully qualifying bind and INTO variables. This
function is also useful for global functions. Important: After you call
SqlContextSet, the context for bind variables and INTO variables is always
hWndForm. If you call a Sql* function in an internal function, window function,
or class function after calling SqlContextSet, SQLWindows does not recognize
local variables or Parameters that you use as bind variables and INTO
variables. For new applications, call SqlVarSetup instead of this function.
Parameters
hSql Sql Handle. A handle that identifies a
database connection.
Return Value
bOk is TRUE if the function succeeds and FALSE if it fails.
bOk=SqlContextSetToForm ( hSql, hWndMyForm)
This function is like SqlContextSet, except for
an additional parameter: SqlContextSet sets the context of the Sql Handle to
the window identified by hWndForm; SqlContextSetToForm sets the context of the
Sql Handle to the window you specify in the second parameter. Call this
function from a child table window when you want to set the context to the
parent form window; in this situation hWndForm refers to the child table
window, not to the parent form window. For new applications, call SqlVarSetup
instead of this function.
How can I use MTS-published COM objects in
CTD 1.5?
Install the MTS development SDK on your machine. You'll notice a few
MTS-related type libraries appear in the ActiveX Wizard. Use the Wizard
to generate classes for them, and use those to access MTS context interfaces,
etc... Apart from that, it's just a case of talking to the COM objects via
Automation as usual -- CTD 1.5 should be able to take advantage of this
interface like any ActiveX interface.
How do I acquire the file information (such
as version number, vendor, description) stored in Win32 files?
Certain version information can be stored in Win32 file images (not
available in 16-bit Windows file images). Things like version number, vendor
name, and copyright notice can be accessed with functions part of the file
installation library defined in VERSION.DLL. To access such resources, read the
Win32 SDK and use the code snippet below in conjuction with the definitions
provided in the WinSDK32.APT.
Set dwLen=GetFileVersionInfoSizeA( dfsFile, dwLen )
Set bOk=bOk AND dwLen > 0
Set lpData=GlobalAlloc( GMEM_FIXED, dwLen )
Set bOk=lpData !=0
Set bOk=bOk AND GetFileVersionInfoA( sFile, 0, dwLen, lpData )
Set bOk=bOk AND VerQueryValueA( lpData,
'\\StringFileInfo\\040904b0\\FileDescription', lplpBuffer, puLen )
Set bOk=bOk AND SalStrSetBufferLength( sDesc, puLen )
Set bOk=bOk AND CStructCopyFromFarMem( lplpBuffer, sDesc, puLen )
Set bOk=bOk AND ( 0=GlobalFree( lpData ) )
Please don't forget to include CSTRUCTL.APL. The above function calls will
return the description (English [U.S.]) of a Win32 file image (passed through
"sFile") in "sDesc".
I would like to integrate ToolTip support in my
applications. How do I do this?
There is a library called QCKTTIP.APL in the samples directory of CTD which
provides an easy to use interface. If the QuickObject framework is not needed,
the underlying TTMNGR.APL file can be used directly.
Also, ToolTips are part of the XSal extensions, written by
Gianluca Pivato.
How can I implement context sensitive help with a
question mark button in the title bar of a window?
In the Win32, the extended window style WS_EX_CONTEXTHELP got added for dialogs
which causes the help button to get displayed. To apply this style to a dialog
box add the following code in the message actions section:
On WM_NCCREATE
Call SetWindowLongA( hWndForm, GWL_EXSTYLE,
WS_EX_CONTEXTHELP | GetWindowLongA( hWndForm, GWL_EXSTYLE ) )
This is partially true.
It is only possible to assign the style WS_EX_CONTEXTHELP to form windows that
are not maximizable and not minimizable. On normal form windows, this does not
work because there is no such style. In Microsoft Word and similar
applications, this is usually accomplished by placing a button in the
windows toolbar. Add the following code to the buttons message
actions:
On SAM_Click
Call SalSendMsg( GetParent( hWndForm ), WM_SYSCOMMAND,
SC_CONTEXTHELP, 0 )
A call to GetParent( ) is necessary when the button resides in a window's
toolbar.
Each child that should react to the context help function needs the following
code in its message actions section:
On WM_HELP
Call WinHelpA( hWndForm, "Helpfile.hlp",
HELP_CONTEXTPOPUP, nContextID )
Can a script to create a database be generated
from a TOM Data Model?
Unfortunately, the TOM data modeler does not support generating schemas, only
reading them in from existing databases.
The screen shot with such an option in the manual slipped through in earlier
releases of the documentation. For the curious, the original developers of TOM,
Jarrah/OEC Australia/Borland Australia/Inprise Australia, did plan to support
Entera generation in TOM, but the feature was withdrawn before the 1.0
release.
When trying to import a new project with the
Wizard, the "Finish" button is disabled for no obvious reason. How
can I fix that?
This is a known bug in Centura Team Developer 1.1.1 that has been fixed in
subsequent releases. If you're determined to stick with 1.1.1, there is a hack
that'll get you going. The hack is to use a tool like Spy++ to get the window
handle of the disabled Finish button. Once you've got it you can send it a
SAM_Click message from another app. Just start up Builder and code something
like:
On SAM_AppStartup
Call SalSendMsg( SalNumberToWindowHandle( 0xXXXX ),
SAM_Click, 0, 0 )
and execute it.
How do I determine the library file
an item is included from?
There is an undocumented function that will do the job:
HITEM SalOutlineGetIncludingItem( HOUTLINE hOutline, HITEM hItem )
.
Is it possible to compile sources externally, for
example with a "mass compiler"?
External compilation is one feature available with the command line
options of SQLWindows and SQLWindows/32. With passing either "-b" or
"-B", Centura compiles and save the application as an executable
file. "-x" and "-X" will cause the
development to exit immediately after the compilation is done.
Where can I obtain a copy of the CDK for SQLWindows
5?
Unlike the CDK for Centura Team Developer, which is freely downloadable, the
SQLWindows CDK was an add-on product which was not free and delivered on
traditional media.
Unfortunately, the SQLWindows CDK has been discontinued. You may be able to
purchase a "previously owned" copy by posting on the news groups.
I have recently upgraded my version of CTD and my
CDK is causing problems. How can I avoid this?
The CDK interacting with CTD is very version specific. The need to be exactly
the same version. Make sure that you are using the latest version.
For migration issues, check the
following sites:
http://www.centurasoft.com/support/tech_info/migrate_wizard.html
http://www.centurasoft.com/products/development/white/ctdguide.html
What are the SalIdle*
functions used for?
The SalIdle* functions are general purpose. Some examples for
situations in which they might be useful:
- refresh the UI such as enabling/disabling toolbar buttons,
- periodic commits when using SQLBase to release log files when no transaction
has occured,
- populate the rest of a table window that has not been filled completely.
With 16-bit SQLWindows I used
SWCSTRUC.DLL. Now we moved to 32-bit and I can't seem to find the equavilent
library?
It is now named STRCI11.DLL, the name of the include APL received the suffix
"L". The general functionality did not get changed.
I would like to call C/API functions
directly but it does not seem to work. What happened to
SQLAPIW.DLL?
SQLAPIW.DLL is the 16-bit SQLBase API, the 32-bit version is SQLWNTM.DLL which
has to be used with Centura Team Developer.
Why do I get GPFs during compile/run
time with the 32-bit version after the migration?
Be careful of the definition of external functions.
- Almost all ordinal numbers are different in external DLLs, like USER.EXE vs.
USER32.DLL. Check all external functions you use and try to remove ordinal
numbers whereever possible.
- Parameters may be different. For instance, some parameters which are WORD in
16-bit version may have to be changed to DWORD, depending on the function
used.
I switched to 32-bit and get the error
'Cannot find function within external library' when compiling. How can I fix
that?
This can occurs with external functions that have string parameters. In Win32,
there are two different functions for the same purpose, one for ASCII, the
other one for Unicode. These functions are typically marked with an
"A" and a "W". For example, the 32-bit equivalents for
GetWindowText are GetWindowTextA( ), 8 bit characters (ASCII) and
GetWindowTextW( ), 16 bit characters (Unicode). Centura Team Developer does
only work with ASCII functions, thus you'll have to modify your external
declarations, and add the 'A' to some of the function names.
When converting from SQLWindows to Team
Developer 1.5, do I have to migrate via 1.1 or can I directly use the newest
version?
You should be able to go straight to 1.5. It is recommended that you open your
APL files first in CTD 1.5 and save them, then open your APP files and save
them.
The "Select From"
with library files does not seem to work anymore, am I doing something
wrong?
This feature is not implemented in SQLWindows/32 (the CTD package).
The function
SqlConnectTransaction( ) doesn't seem to work. Is this a bug?
This function was used in SQLWindows 5.x to connect named
transactions. This concept is not supported in Centura Team Developer, thus,
the functions won't work anymore. You have to rewrite your code.
I can't find the SqlContext* functions
in the documentation. Can they still be used?
Centura Software Corp. has confirmed that they continue to offer SqlContext*
functions and preserve compatibility with existing code. It is recommended for
new applications to use SqlVarSetup where necessary.
The SalDDEPost( ) function
doesn't seem to work anymore. What is going on?
The function definition has changed.
Call SalDDEPost( hWndDDE, UMSG_DDESearch, frmMain, SalNumberLow(vnNr),
SalNumberHigh(vnNr) )
doesn't function any more (lParam is 0). Therefore you should use
Call SalPostMsg( hWndDDE, UMSG_DDESearch, 0, vnNr).
The XSal package is available at www.pivato.com.
I get the runtime violation message when
I use the runtime version of my XSal extension on NT, why?
The first builds of the XSal extensions were testing the file name for the
".EXE" suffix. NT keeps the file name the way it's written, therefore
instead of ".EXE", the suffix is ".exe" and the runtime
extension fails to initialize. The solution is to contact
support@pivato.com to
receive a later build or to change the executable name to uppercase.
Can I use the BKG in the
toolbar?
Yes, you have to create a dialog box with the BKG as a child of the toolbar
using SalCreateWindowEx():
Set hWndToolbar=SalGetFirstChild( hWndMDI, TYPE_FormToolBar )
Call SalGetWindowSize( hWndToolbar, nToolbarWidth, nToolbarHeight )
Set hWndToolbarBkg=SalCreateWindowEx( dlgToolbarBkg, hWndToolbar, 0, 0,
nToolbarWidth, nToolbarHeight, CREATE_AsChild )
Then, in case you want to make the dialog box always fit the toolbar, use
WM_SIZE (0x0005) to resize the dialog:
On WM_SIZE
Call SalSetWindowSize( hWndToolbarBkg, SalPixelsToFormUnits(
hWndForm,SalNumberLow( lParam ), FALSE ), nToolbarHeight )
Can I show custom controls in a TableWindow
cell?
Yes, you can do it putting your custom control/s or any other type of child
window in a dialog box and the create the dialog box as a child of the table
windows hooking the handle to the TableWindow cell using the CPT function
XSalTblSetCellCustom(). Then you can make sure the form (or forms, since you
can do that for as many cells as you like) is shown inside the cell using the
SAM_DrawCell message:
Set nCustom=SalWindowHandleToNumber( SalCreateWindowEx( dlgTest, hWndTable,
0,0,0,0,CREATE_AsChild ) )
Call XSalTblSetCellCustom( hWndColumn, nCustom )
Add the following code to the table window's message actions section:
On SAM_DrawCell
If XSalTblGetCustomInfo( lParam, hdc, nCol, nRow, nValue,
nLeft, nTop, nRight, nBottom )
Set
hWndChild=SalNumberToWindowHandle( nValue )
Call SalSetWindowLoc( hWndChild,
SalPixelsToFormUnits( hWndForm, nLeft, FALSE ), SalPixelsToFormUnits( hWndForm,
nTop, TRUE ) )
Call SalSetWindowSize( hWndChild,
SalPixelsToFormUnits( hWndForm, nRight-nLeft, FALSE ), SalPixelsToFormUnits(
hWndForm, nBottom-nTop, TRUE) )
Can I show bitmaps in a TableWindow
cell from a database?
Yes, if the image in the database column is a bitmap save with the
same format of a bitmap file or from a picture control using SalPicGetString().
You have to get the image handle using XSalImageFromString() (part of the IMG
extensions) and set the image handle in the cell using XSalTblSetCellImage()
(CPT). Remember to free the image using XSalImageClose() to release the
resources.
Can I have pushbuttons with the bitmap on the
side?
Yes, use the TLB function XSalToolboxMakeFlat( pbButton,
TLBS_LEFTIMAGE or TLBS_RIGHTIMAGE ).
Can I have pushbuttons only with a thin frame
without making them flat?
Yes, in XSalToolboxMakeFlat(), just use the TLBS_THINFRAME flag.
Sometimes my flat buttons get "stuck".
What can I do?
It happens when you execute a function that release the mouse capture and
notifies the "wrong" window. In those cases you can release the
"stuck" flat button sending the WM_CANCELMODE (0x001F) message to the
button.
When a flat toolbar button gets clicked,
SAM_Validate is not sent to the control loosing the focus. How can this be
fixed?
When you press buttons that have been modified using XSalToolboxMakeFlat( ),
they behave like menu items. The focus doesn't really change and thus,
SAM_Validate does not get sent. You can either program the focus change with
SalSetFocus( ) or, more elegantly, make a call to SalSendValidateMsg( ) from
within the SAM_Click message portion of toolbox buttons. Once implemented in a
class, you don't have to further worry about it.
How do I show tooltips for TableWindows'
columns/rows/cells?
Detect the mouse movement using WM_MOUSEMOVE (0x0200) and save the
column/row/cell using
SalTblObjectsFromPoint( hWndItem, SalNumberLow(lParam),
SalNumberHigh(lParam), nRow, hWndColumn, nFlags ).
When the column/row/cell is different from the previous one, use
XSalTooltipShow( hWndItem, sTooltipText ).
Can I receive a notification when a tooltip is
shown or hidden?
You can use SAM_TooltipSetText to know when the tooltip gets shown.
For SAM_TooltipClose you have to wait the next version: TTP2.0.
I've noticed that tooltips are shown even when
the window is inactive, can I decide to show the tooltips only when the window
is active?
You can use the following function instead of XSalTooltipSetText():
Function: XSalTooltipSetTextActive
Parameters
Number: p_nLParam
String: p_sText
Actions
If GetActiveWindow( )=hWndForm OR GetParent( hWndForm
)=GetActiveWindow( )
Return XSalTooltipSetText(
p_nLParam, p_sText )
Next version (TTP2.0) will have a setting for this plus another setting
for showing tooltip on disabled windows.
The tooltips don't seem to work although I
included the library and added SAM_TooltipSetText to some controls. Is this a
bug?
No, it is not a bug. You have to call any tooltip function to make SQLWindows32
load the DLL. SQLWindows loads DLLs at startup, SQLWindows32 doesn't. That's
why the DLL doesn't get initialized. Just call XSalTooltipSetColors() and the
tooltip system will get enabled.
Can I pass an object (UDV or functional
class) by sending a a message?
Yes, but only by value, not by reference. You can convert the object in a
string using XSalUdvToString() (UDV) and send the string in a message using
SalHStringToNumber(). The received of the message can duplicate the object
locally using XSalUdvFromString() and SalNumberToHString().