PowerBasic
Introduction
PowerBasic is the ultimate Basic compiler for Windows! It was originally
Bob Zale's project TurboBasic 1.0 over at Borland in 1985. After Borland discontinued
the project following release 1.1
because it feared it could not compete with Microsoft's QuickBasic, Borland transferred the rights to the code
to Bob, who left and built a company to market it. PowerBasic 2.0 was published
in 1989 by Spectra Publishing. In addition to the regular release, PB 2.1 was
released as shareware in 1996 as FirstBasic. Bob started his own company, PowerBasic
Inc, to publish PowerBasic 3.0 in 1993.
In addition to command-line-based programs (PB/CC, PB/DOS, etc.), PowerBasic
Inc offers PowerBasic for Windows (ex-PB/DLL) which is a compiler to build either DLLs or EXEs for Windows.
Scroll down to see what the standard "Hello, world!" program looks
like in PB/DLL. Being a small shop, PowerBasic doesn't have the means to promote
PB/DLL much, so it has to be one of the most under-marketed gems out there.
Must haves
- A good editor from which you can build and run your PB application:
I recommend either UltraEdit (see below on how to compile your .BAS file
directly from UE), the JellyFish
Editor (Didn't find features
about JF that UltraEdit doesn't have, though) by Paul Squires which integrates with the Lynx Project Explorer
to display a hierarchical map of the files in a project (although it's neat,
just like the CodeSmart add-in for the VB IDE, I don't like Lynx because
it isn't displayed inside
UltraEdit, but rather, alongside, and also because it requires building
a project file instead of just showing up in UltraEdit as you open a PB
file), or PBCEd,
the PowerBasic Code Editor by Heber Jorge da Silva, both built on the CodeMax
OCX.
Yet other alternatives are PowerIDE from KGP
Software (I don't like it because of its lack of the instant
one-block indenting, but it does have a killer feature, though:
A tiny dialog lists all the subs/functions in the open source file, and
you can jump to any them by just selecting it in that dialog. Very nice,
and a basic alternative to Lynx), RAD
Developer, or Jose Roca's SciEditor
(a.k.a. SED) based on a rewrite in PB of the open-source Scintilla edit
widget
- A GUI builder to avoid having to draw the UI by hand: I recommend that
you build the GUI with the DDT extensions offered by PB/DLL 6 with the help
of a dialog editor (eg. Microsoft Developer Studio and James Fuller's RC2DTT.EXE), use the EZGUI Dialog Designer (freeware), or consider
buying EZGUI 2.0 . See section below. Seems
like PowerBasic
gave up on PBGen, and replaced it with with PBForms
to generate DDT instructions
- A database engine such as Advantage
Systems' Tsunami (really a hashing
system; ttds, a client-server
version of the Tsunami Record Manager is available here), Borland's InterBase/BDE,
Planet Squires' Cheetah or CodeBase
for PowerBasic.
More options here.
- A grid objet: There's quite a lot of such objects available commercially
(eg. VSFlexGrid, SIGrid,
Farpoints Spread, etc.), but you can also use Erik Christensen's free source,
Roberto Valoi's Editable Listview,
VBAccelerator's SGrid,
Edwin's Visual Designer which
has a small grid included, Elias' e-grid32,
or wxGrid).
Ideally, it can print nice tables so you don't waste time reformating data
for output. Also check how to interact with a SQL server (ideally, you can
just perform SELECTs and INPUTs)
- The Librarian by Bare Point Systems:
Source code library designed with EZ_GUI and Vista
Software's Artemis 5 database engine.
- A preview/print object: Don Dickinson's ddoc
Print and Preview, DLLPrint
- A DLL bundler to ship a single EXE : EXE
Bundle, PEBundle (list
here)
- A recorder to build a demo (PB
Recorder)
- Unfortunately, neither PowerBasic nor a third-party has written a book
on PB/DLL, so you'll have to rely on books written for Visual Basic or VC++
users to learn how to work with PB/DLL, and make the necessary adjustements.
A pity for such a great tool. Recommended books include...
- And remember to check out the excellent source code vault over at PowerBasic
here,
and over at (RIP) BASICally
speaking. If you read German, there's a PowerBasic
Quick-Referenz (commercial)
PowerBasic Pros and Cons
Pros
- Can compile small, fast, stand-alone EXE
- Small development environment
- Doesn't hide the logic under tons of auto-generated code ā la MFC or
.Net
Cons
- Not an OO language, and no support for .Net as of May 2003, so knowledge of Win32 API required.
Get your copy of Petzold's
(or the older
edition if you want to play with the widgets introduced since Win95),
and download its examples
rewritten in PB
- WYSIWYG GUI designers still evolving (multiple tools). No native tool
as good as Visual Basic for GUI design
- No book available besides the PBDLL.PDF (or its printed equivalent),
forcing users to buy books on Visual Basic or C, and make the necessary conversion
to learn PowerBasic
- 16-bit compiler, although it PB/DLL 5 and 6 build 32-bit programs. Don't
know if that could be an issue
Hello, world!
The easiest way
- #COMPILE EXE
-
- Function PbMain() AS LONG
- MsgBox "Hello, World!"
- End Function
The easier way
Here, we'll use the DDT extensions introduced with PB/DLL 6 to create a dialog
box:
- #Compile Exe
- #REGISTER NONE
- #DIM ALL
- #include "win32api.inc"
-
- %IDLABEL = 1000
-
- CallBack Function IDD_DIALOG1_CB As Long
-
- Select Case CbMsg
-
- Case
%WM_COMMAND
- Select
Case CbCtl
- Case
%IDOK
- DIALOG
END CBHNDL
- End Select
-
- End Select
-
- End Function
-
- Function PbMain() As Long
- Local hDlg As Long
- Local lRetVal As Long
-
- Dialog New %NULL, "Your base are belong to us",
0, 0, 186, 95, _
- %DS_MODALFRAME
Or %DS_CENTER Or %WS_POPUP Or %WS_CAPTION Or %WS_SYSMENU, _
- %WS_EX_TOOLWINDOW,
TO hDlg
-
- Control Add Label, hDlg, %IDLABEL, "Hello, world!",
71,39,70,8
- Control Add Button, hDlg, %IDOK, "OK", 65,74,50,14
-
- Dialog Show Modal hDlg, Call IDD_DIALOG1_CB TO lRetVal
-
- End Function
The hard way
Here, we'll build a full-fledged window ā la Petzold (a trip down memory
lane):
- $COMPILE EXE
- $INCLUDE "WIN32API.INC"
-
- FUNCTION WinMain (BYVAL hInstance AS LONG, BYVAL hPrevInstance
AS LONG, lpCmdLine AS ASCIIZ PTR, BYVAL iCmdShow AS LONG) AS
LONG
-
- LOCAL Msg AS
tagMsg
- LOCAL wndclass AS
WndClassEx
- LOCAL hWnd AS
LONG
- LOCAL szAppName AS
ASCIIZ * 80
-
- szAppName =
"HelloWin"
-
- wndclass.lpfnWndProc
= CODEPTR( WndProc )
- wndclass.cbSize =
SIZEOF(WndClass)
- wndclass.style =
%CS_HREDRAW OR %CS_VREDRAW
- wndclass.cbClsExtra
= 0
- wndclass.cbWndExtra
= 0
- wndclass.hInstance =
hInstance
- wndclass.hIcon =
LoadIcon( hInstance, "HELLOWIN" )
- wndclass.hCursor =
LoadCursor( %NULL, BYVAL %IDC_ARROW )
- wndclass.hbrBackground
= GetStockObject( %WHITE_BRUSH )
- wndclass.lpszMenuName
= %NULL
- wndclass.lpszClassName
= VARPTR( szAppName )
- wndclass.hIconSm =
LoadIcon( hInstance, BYVAL %IDI_APPLICATION )
-
- RegisterClassEx wndclass
-
- hWnd = CreateWindow(szAppName,
_ '
window class name
- "The
Hello Program", _ ' window caption
- %WS_OVERLAPPEDWINDOW,
_ ' window style
- %CW_USEDEFAULT,
_ ' initial x position
- %CW_USEDEFAULT,
_ ' initial y position
- %CW_USEDEFAULT,
_ ' initial x size
- %CW_USEDEFAULT,
_ ' initial y size
- %NULL,
_ '
parent window handle
- %NULL,
_ '
window menu handle
- hInstance,
_ '
program instance handle
- BYVAL
%NULL) '
creation parameters
-
- ShowWindow hWnd, iCmdShow
- UpdateWindow hWnd
-
- WHILE GetMessage(Msg,
%NULL, 0, 0)
- TranslateMessage
Msg
- DispatchMessage
Msg
- WEND
-
- FUNCTION = msg.wParam
-
- END FUNCTION ' WinMain
-
- FUNCTION WndProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, BYVAL wParam
AS LONG, BYVAL lParam AS LONG) EXPORT AS LONG
-
- LOCAL hDC AS
LONG
- LOCAL LpPaint AS
PaintStruct
- LOCAL tRect AS
Rect
-
- SELECT CASE wMsg
-
- CASE
%WM_CREATE
-
- CASE
%WM_PAINT
- hDC
= BeginPaint(hWnd, LpPaint)
- GetClientRect
hWnd, tRect
- DrawText
hDC, "Hello, Windows 95!", -1, tRect, %DT_SINGLELINE OR %DT_CENTER
OR %DT_VCENTER
- EndPaint
hWnd, LpPaint
- FUNCTION
= 0
- EXIT
FUNCTION
-
- CASE
%WM_DESTROY
- PostQuitMessage
0
- FUNCTION
= 0
- EXIT
FUNCTION
-
- END SELECT
-
- END FUNCTION
Why use dialogs instead of windows?
A dialog doesn't require registering a window class, and it can be easily
designed using WYSIWYG tools such as those presented below.
From Chris Boss: Dialogs benefit from the extra processing of messages
by the DefDialogProc function, (rather than DefWindowProc). A number of common
messages are processed differently by this function. This extra processing basically
benefits a Dialog with standard controls in areas such as the keyboard (ie.
Tabbing).
The disadvantage to Dialogs is that you don't have access to the Dialogs
Window procedure, but only a Dialog procedure (they are different). For example,
a Dialog procedure will not get a WM_CREATE message, but will get the WM_INITDIALOG
message. A Window (non dialog) will get the WM_CREATE message, but not the WM_INITDIALOG.
Such things as MDI are not well suited to use with Dialogs. [...] On the other
hand Dialogs are easier and will handle more than 90% of your needs.
From Chris Boss, again : DDT is dependant upon the Windows Dialog
engine which doesn't give you access to the Dialog Class Window procedure, but
just a Dialog procedure called by the Class Window procedure. While you could
subclass a DDT Dialog, it is just easier to use SDK created Dialogs if you want
more control.
DDT (and any Windows Dialog engine created windows) use the DefDialogProc
API function internally, where as SDK windows normally use the DefWindowProc
API function. There is a significant difference between the two functions !
Since, DDT uses the Windows Dialog engine, one advantage it has is the a number
of common tasks are already handled by the Windows dialog engine (ie. WM_NEXTDLGCTL
message). When using SDK style windows you need to write your own code to process
some messages, that the Windows Dialog engine handles already.
If your Dialogs are more oriented to standard type Dialogs using standard
controls, then DDT may be better suited. If your Dialogs need to do some custom
stuff (ie. MDI, non-rectangular dialog using regions) then SDK windows are better
suited.
Most Dialogs can be created with DDT and development is faster and easier.
There are instances where SDK style Dialogs are a must though and a programmer
should learn how to do both.
Also the Windows Dialog engine (which includes DDT) uses a portion of
the available 40 bytes (30 bytes are used) for the extra window bytes , which
means you have less of these bytes available for custom storage for the windows
extra bytes. Windows 95/98 limits you to 40 bytes (I tested this and it is so
and it applies to 32 bit windows and not just 16 bit). If you need more bytes
for the extra window bytes, then you will have to do extra work with DDT, since
you will have to create your own Global UDTs to store data. There are situations
where the extra data space available for SDK windows is very useful.
Lastly, the Windows Dialog engine adds an extra amount of overhead when
processing messages, since it has both a Window Procedure (the Dialog Class
handles this) and a Dialog Procedure. Unless you subclass the Dialog, DDT is
doing extra processing (albeit very little, but something) than an SDK Window
class. If your Dialog requires the optimum speed (we are talking about extremely
fast), then SDK style windows will save a few CPU cycles because it has less
overhead.
To be practical though, the extra overhead when using the Windows Dialog
engine (or DDT) is negligable. It is there, but it is so small that in most
instances it is insignificant !
The main point here is :
- There is a difference between DDT and SDK style Dialogs. DDT should
handle more than 90% (or more) of the situations we may face. Yet, there
are some instances that SDK style coding is better.
- The beauty of PB, is that you have the option to use either method
if you choose. Use DDT first and in the rare instance that DDT doesn't give
you the control and power you need, then use SDK style code.
Chris Boss :-) : Here are a few more minor differences between
DDT and SDK : DDT uses Dialog Units, while SDK uses Pixels. Dialog Units has
the advantage of autoscaling your Dialog based on the end users Font setting
(Small Fonts/Large Fonts), while SDK does not (You have to write your own autoscaling
code).
On the other hand, Dialog Units (DDT) prevent you from having exact positioning
of controls to an exact pixel. For example, try a column of ten buttons evenly
spaced. The odds are you will have a tough time getting them to have the exact
same number of pixels between them.
The reason for this, is that DDT defines the default font to MS Sans Serif
8 while the Windows Dialog engine uses the System font instead (if no font is
defined). The system font divides more evenly into exact pixels (a Dialog Unit
is 2 x 2 pixels when using small fonts - character size is 8 x 16 pixels), while
DDT's MS Sans Serif font doesn't divide well (character size is 6 x 13 pixels).
In most cases this doesn't cause a problem, but when the dialog requires
some very exact and simetrical positioning of controls, DDT will be a hair off.
This is nothing new though, since C programmers who create Dialogs as resources
and who use CreateDialog (API) have suffered with this problem long before PB
added DDT.
This doesn't mean DDT is bad or at fault, it is just a reality of dealing
with the Windows Dialog engine and using Dialog Units. As I said, DDT works
for 90% (or more) of the needs for a Windows programmer.
You might find it interesting, that when I had to make a choice of whether
to use the Windows Dialog engine or CreateWindowEX in my third party tools to
create the Dialogs, I chose the Windows Dialog engine ! The advantages of DefDialogProc
(which is called by the Windows Dialog engine) far outwayed the benefits of
SDK created windows (CreateWindow). This advantage also exists in DDT !
My recommendation is that a programmer learn both ways of writing Windows
apps. For beginners, DDT is much easier so they should start there. At some
point it is good to learn how to write apps using the SDK style and to experiment
and see the differences. If at some point a programmer finds that SDK style
code doesn't offer them any significant advantages, then just stick with DDT.
If you find that SDK style code offers some advantages crucial to your needs,
then by all means use it !
From Eric Pearson : To clarify... > DDT uses Dialog Units, while
SDK uses Pixels.
That's not true if you use SDK techniques to create dialogs. In fact that's
the way most of my own programs are written. I create a dialog in a resource
file and link it to my program. The program then uses SDK-style techniques to
display and control the dialogs. And as a result, almost everything is done
in dialog units, not pixels.
I do find myself writing more and more new programs using DDT code, however.
For most of my applications (95%?) it is more than sufficient.
My personal summary of "DDT vs. SDK"...
SDK means "using the native API", and that implies that everything
is possible if you are willing to write enough code, and to wrestle with the
complexities of the API.
DDT is much easier to use. It requires much less coding and knowledge
of the Windows APIs, and it can do nearly everything.
FireFly SDK Design (ex-VisualPB, ex-PowerGUI)
- Commercial app from PlanetSquires
about $100
- From the same company that makes the JellyFish editor and the Cheetah
database system
PwrDev
- Brought to you by PBSoft's Edwin Knoppert
- Formerly known as "VD - Visual Designer for PowerBASIC"
- Commercial app available here
EZGUI
- http://ezgui.com/
- EZGUI Lite (was EZGUI 1.0; $69; 122KB DLL; Not available as trialware)
- EZGUI 2.0 Visual Designer and GUI engine ($169; 122KB DLL; Not available
as trialware). EZGUI 3.0 will support MDI
- EZGUI Freeware Dialog Designer (Freeware DDT Visual Designer; Comes
in a Light and full version: The former only offers the standard widgets,
while the latter also offers the so-called Common Controls (Tab Control,
Progress Bar, UpDown.) It generates a Basic template code that you just
copy/paste into your source file)
PowerBasic Forms
Son of PowerGen, commercial product from PB. Dialog
interface
builder similar to VB, but adds DDT instructions to BAS file. As long as you
don't mess up the instructions added by PBForm, you can edit the code back and
forth between the PB IDE and PBForms.
Personally, the sharing of a BAS file
between PB and PBForms and the fact that PBForms is a very recent tool... make
me prefer other tools like EZGUI or even VD. I'm just don't trust such a recent
tool to parse code correctly without messing up the code I added manually in
the PB IDE.
PowerGen
PowerGen Visual
Designer 16-bit commercial product from
PowerBasic. Use a dialog editor such as Microsoft's Dialog Editor or Borland's
Resource Workshop to generate a resource file, and PowerGen will turn it into
a .BAS template, not unlike working with VC++ and MFCs. Create the dialog with
any editor (Microsoft Developer Studio, etc.), save the file as an ASCII-based
.RC file, run Microsoft's RC.EXE applet to turn into a binary .RES file, use
PowerBasic's PBRES.EXE applet to convert the .RES file into a .PBR file, and
add this reference into your source code (#RESOURCE "MYRES.PBR").
As an alternative, use James Fuller's RSRC.EXE to embed an .RES file into the
.EXE .
- Launch the Microsoft Dialog Editor
- Create a dialog, and save it: This creates two files, MYDLG.DLG (ASCII)
and MYDLG.RES (Binary). DE actually works off the .RES file, so any change
that you made manually in the .DLG are lost the next time you launch DE
and make changes there
- Make a copy of those two files, rename the .DLG file with a .RC extension,
and edit it as follows:
- Remove the following lines from the resource script:
DLGINCLUDE
RCDATA FIXED IMPURE
BEGIN
"MYDLG.H\0"
END
- Add #include "MYDLG.H"
- Add #include "RESOURCE.H"
- Create a file to include the resource equates, eg. MYDLG.H
(equates are constants that you use to refer to widgets through names
instead of ID numbers; equates are case sensitive)
- Run this .RC file through the RC.EXE resource compiler. This generates
an .RES file... which is incompatible with the original .RES that you created
above (hence the backup)!
- Convert this .RES file into a .PBR with the utility PBRES
- Edit your .BAS source file, add a $RESOURCE meta-statement so the PB/DLL
compiler includes this resource into the .EXE
Dynamic Dialog Tool (DDT)
Those new commands introduced in PB/DLL 6 let you build a dialog box in your
source code instead of using a third-party application. Since it's a pain to
build dialogs in code, you'll probably want to draw them in eg. MS Dialog Editor,
and fetch coordinates of each widget. James C. Fuller's RC2DDT
generates a .BAS template with DDT extensions, ready to copy/paste into
your source file
Visual Forms Editor
Cool VB IDE rip-off designer. Proof of concept by Jules
Marchildon. Only available as a demo, which won't let you save the dialogs you created.
Jules Marchildon. Available
on PowerBasic's web site.
Dialog Editor Controls
Shareware. The demo version won't save
files. Current release is 2.10.
Written by Simon Whiteside. More recent editor than MS Dialog Editor, and supports
common controls.
PWinADP
JC Fuller's PBWinADP interface
builder Another free (16-bit) interface builder. Create the UI in a
RC file with a third-party editor. A PBWin ADP project is a collection of dialogs
created in an external Dialog Editor; One dialog is set as the starting dialog;
All dialogs should be named DLG_xxx, where xxx is a number (a description for
each dialog in the project list.)
Visual MetaFourGL
MetaFourGL, a
nice (and free!) interface builder for PowerBasic. No grid to adjust widgets;
no support for common controls or cool-bar; can't get properties of a widget
by double-clicking on it; when generating .BAS file, says that it generated
.BAS and .PBR, but only see .BAS and .RC; Neither Compile nor Run works (if
try to run generated . BAS with PBDLL.EXE, err with "Required INITCOMMONCONTROLS";
Generated source code a bit complicated.
A project (eg. MYPROJ.GGP) includes all the forms (dialogs, eg. MYFRM1.GGF)
that your application needs. VMGL uses. Add your code in each form. VMGL generates
a .BAS file by combining the templates UNTITLED.GGC (code pattern used for each
program), UNTITLE2.GGC (code pattern used for all forms other than the main
form), and your project-specific files (MYPROJ.GGP and MYFRM1.GGF, here). You
should not modify the templates UNTITLED.GGC and UNTITLE2.GGC, as upgrading
to the next version of VMGL will replace those files with the latest version.
CodeMax OCX
(RIP?) Free. Available from WinMain.
Web applications
Here's how to build an EXE that you can call with eg. http://localhost/list.exe?dir=temp,
and displays a list of OCXs in the directory you specify, each with its filename
+ date (dd/mm/yyyy) + time (hh:mm:ss) + version number (1.0.0.0):
DDT
Should write an introduction to what is DDT (as opposed to alternatives),
how to build dialogs (manually; with PBForms, etc.), and how to interact with
controls
Getting the text selected in a listbox
Like most cases, you need to send a message to the listbox to get the string
and item # that is currently selected:
- Dim lIndex as Long
- Control Send CbHndl, %IDC_LISTBOX1, %LB_GETCURSEL, 0, 0 to lIndex
- LISTBOX GET TEXT CBHNDL, %IDC_LISTBOX1 TO sListItem
- MsgBox sListItem, %MB_TASKMODAL,"You selected item#" &
str$(lIndex)
Setting the text of a label
In PBMain()
- CONTROL SET TEXT hDlg, %IDC_LABEL1, "Original text"
In the dialog's event handler:
- CONTROL SET TEXT CBHNDL, %IDC_LABEL1, "New text
List of DDT instructions
- ACCEL ATTACH Attach a table of keyboard accelerators to a
DDT dialog
- CALLBACK FUNCTION Define a Dialog/Control Callback
Function block
- CBCTL Return the numeric ID of the control sending a
callback message
- CBCTLMSG Return the numeric notification message
parameter
- CBHNDL Return the window handle of the parent dialog
receiving the message
- CBLPARAM Return the numeric value of the lParam&
parameter of the message
- CBMSG Return the numeric value of the message sent by the
caller
- CBWPARAM Return the numeric value of the wParam&
parameter of the message
- COMBOBOX ADD Add a string value to a combo box
control
- COMBOBOX DELETE Remove a string from a combo box
control
- COMBOBOX GET TEXT Retrieve the default text from a
combo box
- COMBOBOX RESET Remove all strings from a combo box
- COMBOBOX SELECT Select a string in a combo box and make it
the default selection
- CONTROL ADD Add a custom control to a DDT dialog
- CONTROL ADD BUTTON Add a command button to a
dialog
- CONTROL ADD CHECK3STATE Add an auto 3-state checkbox to a
dialog
- CONTROL ADD CHECKBOX Add an checkbox to a dialog
- CONTROL ADD COMBOBOX Add a combo box to a dialog
- CONTROL ADD FRAME Add a frame control to a
dialog
- CONTROL ADD IMAGE Add a non-resizing image control to
a dialog
- CONTROL ADD IMAGEX Add an image control to a
dialog
- CONTROL ADD IMGBUTTON Add a non-resizing image button to a
dialog
- CONTROL ADD IMGBUTTONX Add an image button to a
dialog
- CONTROL ADD LABEL Add a text label to a dialog
- CONTROL ADD LINE Add a line control to a dialog
- CONTROL ADD LISTBOX Add a list box control to a
dialog
- CONTROL ADD OPTION Add an option button to a
dialog
- CONTROL ADD SCROLLBAR Add a scroll bar control to a
dialog
- CONTROL ADD TEXTBOX Add a text box control to a
dialog
- CONTROL DISABLE Disable a control so that it no longer
accepts user interaction
- CONTROL ENABLE Enable a control so that it can receive user
interaction
- CONTROL GET CHECK Get the Check State of a 3-state,
checkbox, or option button
- CONTROL GET CLIENT Get the client area dimensions of a
control
- CONTROL GET LOC Get the location of the specified control in
a dialog
- CONTROL GET SIZE Get the size of a control in the
specified dialog
- CONTROL GET TEXT Get the text from a control
- CONTROL GET USER Retrieve a value from the user data
area of a DDT control
- CONTROL HANDLE Return a window handle for a given control
ID
- CONTROL KILL Remove a control from a dialog
- CONTROL POST Place a message into the message queue of a
control (non-blocking)
- CONTROL REDRAW Schedule a control to be redrawn
- CONTROL SEND Send a message to a control and wait for it
to be processed
- CONTROL SET CHECK Set the Check State for a 3-state or
checkbox control
- CONTROL SET COLOR Set the foreground and background
color of a control
- CONTROL SET FOCUS Set the keyboard focus to the
specified control
- CONTROL SET IMAGE Change the icon or bitmap displayed
in an IMAGE control
- CONTROL SET IMAGEX Change the icon or bitmap displayed
in an IMAGEX control
- CONTROL SET IMGBUTTON Change the icon or bitmap displayed
in an IMGBUTTON control
- CONTROL SET IMGBUTTONX Change the icon or bitmap displayed
in an IMGBUTTONX control
- CONTROL SET LOC Move the control to a new location in the
dialog
- CONTROL SET OPTION Set the Check State for an option
(radio) control
- CONTROL SET SIZE Change the size of a control
- CONTROL SET TEXT Change the text in a control
- CONTROL SET USER Set a value in the user data area of
a DDT control
- CONTROL SHOW STATE Change the visible state of a
control
- DIALOG DISABLE Disable a dialog so that it no longer
responds to user interaction
- DIALOG DOEVENTS Process pending window or dialog messages
for modeless dialogs
- DIALOG ENABLE Enable a dialog so that it responds to user
interaction
- DIALOG END Close and destroy the specified dialog
- DIALOG FONT Specify the default DDT font and point
size
- DIALOG GET CLIENT Return the client size of the
specified dialog
- DIALOG GET LOC Return the location of the specified
dialog
- DIALOG GET SIZE Return the size of the specified
dialog
- DIALOG GET TEXT Retrieve the text in a dialog or window
caption
- DIALOG GET USER Retrieve a value from the user data area of
a DDT dialog
- DIALOG NEW Create a new dialog in memory, ready for
display
- DIALOG PIXELS Convert pixels (device units) into dialog
units
- DIALOG POST Place a message in the dialog message queue
(non-blocking)
- DIALOG REDRAW Force a dialog and all child controls to be
redrawn immediately
- DIALOG SEND Send a message to a dialog and wait for it
to be processed
- DIALOG SET COLOR Set the background color of a dialog
to a specific RGB color
- DIALOG SET ICON Change both the dialog icon in the caption,
and the icon shown in the ALT+TAB task list
- DIALOG SET LOC Change the position of a dialog
- DIALOG SET SIZE Change the size of a dialog
- DIALOG SET TEXT Set the text in a dialog or window
caption
- DIALOG SET USER Set a value in the user data area of a DDT
dialog
- DIALOG SHOW MODAL Display and activate a modal
dialog
- DIALOG SHOW MODELESS Display and activate a modeless
dialog
- DIALOG SHOW STATE Change the visible state of a
dialog
- DIALOG UNITS Convert dialog units into pixels
- INPUTBOX$ INPUTBOX$ displays a dialog box containing a
prompt
- LISTBOX ADD Add a string value to a list box
control
- LISTBOX DELETE Remove a string from a list box
control
- LISTBOX GET TEXT Retrieve the default text from a
list box control
- LISTBOX RESET Remove all strings from a list box
- LISTBOX SELECT Select a string in a list box and make it
the default selection
- MENU ADD POPUP Add a popup child menu to an existing
menu
- MENU ADD STRING Add a string or separator to an existing
menu
- MENU ATTACH Attach a menu to a given dialog
- MENU DELETE Delete a menu item from an existing
menu
- MENU DRAW BAR Redraw the menu bar for a given dialog
- MENU GET STATE Return the state of a specified menu
item
- MENU GET TEXT Return the text associated with a given menu
item
- MENU NEW BAR Create a new menu bar
- MENU NEW POPUP Create a new popup menu
- MENU SET STATE Set the state of a specified menu item
- MENU SET TEXT Set the text of a given menu item
- MOUSEPTR Change the mouse pointer (cursor) to a new
shape
- MSGBOX Display a message box and get the users Ok/Cancel
selection
- MSGBOX Display an informational message box (discard the
users selection)
Excerpt from the HLP file
You can convert between Dialog Units and Pixels with the built in DIALOG
PIXELS and DIALOG UNITS statements.
All of the control and dialog message equates are located in the DDT.INC
file. This file is simply a subset of the much larger WIN32API.INC file and is
provided only for convenience. Therefore, the use of these two files is
mutually exclusive.
If your code processes one of these event messages, it should return
non-zero to Windows, by setting FUNCTION = 1 within the Control Callback. This
tells Windows that it should not need to process that message any further. If
you return zero, Windows will pass this message on to your Dialog Callback. If
the message is still unhandled by your Dialog Callback, the DDT dialog engine
itself will handle the message on your behalf. This can add unnecessary
overhead to the performance of your application.
CONTROL ADD BUTTON, hDlg, %IDOK, "OK", 34, 32, 40, 14, %BS_DEFAULT OR
%WS_TABSTOP CALL OkButton
In the generally case, a dialog Callback Function should return TRUE
(non-zero) for all %WM_COMMAND messages it processes. However, this rule cannot
be equally applied to other types of messages, since the return value will be
message-specific.
In some cases, especially when dealing with Common Controls and custom
controls, it can become necessary to return an additional result value to the
dialog engine through a special data area referred to by the name
DWL_MSGRESULT.
The default style comprises the combination of %WS_POPUP, %WS_CAPTION,
%DS_SETFONT, %DS_NOFAILCREATE, %DS_MODALFRAME, and %DS_3DLOOK. These equates
are equivalent to a style of &H080C00D4. The extended style default is
zero.
If you explicitly specify %WS_CAPTION in your DIALOG NEW statement, then
DDT will interpret the width and height values as client dimensions, rather then
as overall dialog dimensions. This can be very useful for the times when you
need to build a dialog with particular client dimensions.
Purpose Add a custom control to a DDT dialog.
Syntax CONTROL ADD classname$, hDlg&, id&, txt$, x,
y, xx, yy [, [style&] [, [exstyle&]]] [[,] CALL
callback]
When the Callback Function receives a %WM_COMMAND message, the identity of
the control sending the message can be found with the CBCTL function. Use the
CBCTLMSG function to retrieve the notification message value in your callback.
However, many Windows common controls send %WM_NOTIFY messages rather than the
more conventional %WM_COMMAND messages. In such cases, the meaning of the
message parameters CBWPARAM and CBLPARAM will vary according to the type of
notification message being processed.
Pointers and calling DLLs
More infos here on the solutions available to make calls to DLLs written
in C.
- LONG, POINTER
- CODEPTR(FunctionName)
- STRPTR
- VARPTR
- ASCIIZ
- PTR
- AS ANY
- BYREF, BYVAL
Managing data
More infos here.
MySQL
SQLite
Code by Nathan Evans. When
performing heavy changes such as creating thousands of records, remember to
send the "BEGIN;" and "COMMIT;" SQL instructions before
and after making changes, respectively; Otherwise, you will get pathetic performances
SQLTools
From PerfectSync. Eases use of ODBC
from PowerBasic to connect to SQL servers.
PowerTree
DvBTree
Cheetah
VB/ISAM
Tsunami Record Manager
This is a free one-DLL database application for Windows by Timm Motl (Advantage
Systems, Timm Motl). To use Tsunami,
simply copy its header file trm.inc and its engine trm.dll in the same directory
as your PB/DLL application, and add #include "trm.inc" in the source
file. That .DLL is the only file that is required to work with a Tsunami data
file. Tsunami is a page-structured file. Depending on the average size of the
records that Tsunami will have to handle, you'll have to decide on the size
of the page size in your Tsunami file, ranging from 1K to 8K.
- LOCAL PageSize AS LONG
- LOCAL Compression AS LONG
- LOCAL KeySegments AS LONG
- LOCAL FileDef AS STRING
- LOCAL KeyNo AS LONG
- LOCAL KeyFlags AS LONG
- LOCAL OverWrite AS LONG
- LOCAL lResult as LONG
- LOCAL InputString AS STRING
- LOCAL Count AS QUAD
- LOCAL FileSize AS QUAD
- LOCAL Record AS STRING
- LOCAL sResult as String
-
- PageSize = 1
- Compression = %TRUE
- KeySegments = 1
- KeyNo = 1
- KeyFlags = %NO_COMPRESSION
-
- FileDef = MKBYT$(PageSize) + MKBYT$(Compression) + MKBYT$(KeySegments) +
"Account Number "
+ MKBYT$(KeyNo) + MKWRD$(1) + MKBYT$(6) + MKBYT$(KeyFlags)
- OverWrite = %TRUE
- lResult = trm_Create("MYFILE.DAT", FileDef, OverWrite)
-
- hFile = trm_Open(Path + "TRMDEMO.DAT", %FALSE)
-
- InputString = " 3934DOWNIN DANA
4850
FREDRICK ST CORAL
SPRINGS FL33071"
- lResult = trm_Insert(hFile, InputString)
-
- Count = trm_Count(hFile)
- FileSize = trm_FileSize(hFile)
-
- Record = trm_GetFirst(hFile, CurrKeyPath)
- lResult = trm_Result(hFile)
- sResult = sResult + TRIM$(MID$(Record, 1, 6)) ' Acct No
- sResult = sResult + TRIM$(MID$(Record, 7, 24)) ' Last Name
- sResult = sResult + TRIM$(MID$(Record, 31, 18)) ' First Name
- sResult = sResult + TRIM$(MID$(Record, 49, 1)) ' Middle Initial
- sResult = sResult + TRIM$(MID$(Record, 50, 30)) ' Street
- sResult = sResult + TRIM$(MID$(Record, 80, 16)) ' City
- sResult = sResult + TRIM$(MID$(Record, 96, 2)) ' State
- sResult = sResult + TRIM$(MID$(Record, 98, 5)) ' Zip Code
-
- Record = trm_GetNext(hFile)
-
- Record = trm_GetEqual(hFile, CurrKeyPath," 3934")
-
- lResult = trm_CloseAll
Common Controls
Those are additional widgets introduced since Windows 95. When using DDT,
you will have to rely on the CONTROL ADD
classname instruction.
RichText
- LOCAL hRichEd AS LONG
- LOCAL CC1 AS INIT_COMMON_CONTROLSEX
- hRichEd = LoadLibrary("RICHED32.DLL")
- CC1.dwSize=SIZEOF(CC1)
- CC1.dwICC=%ICC_WIN95_CLASSES
- INITCOMMONCONTROLSEX CC1
Tips and Tricks
Zipping
A PowerBasic interface to zLib.dll is here.
Checking if a file exists
- FUNCTION Exist(File$) AS LONG
- LOCAL Dummy&
- Dummy& = GETATTR(File$)
- FUNCTION = (ERRCLEAR = 0)
- END Function
Note: Some routines given in the PowerBasic forum such as FileExists()
don't work when used in a DIR$ loop.
Writing CGI programs
Creating Dynamic
Web Pages with PB/CC
Regex
To extract the section of a string
- Dim sFull as String, sMask as String, lPosVar as Long, lLenVar as Long
- sFull = "I can be reached at john@acme.com"
- sMask = "[a-z_.-]+@[a-z_.-]+"
- REGEXPR sMask IN sFull TO lPosVar, lLenVar
- Msgbox MID$(sFull, lPosVar, lLenVar)
To extract a tag
A tag is defined as a sub-pattern of a mask. In this example, we'd like to
extract just the actual content of the Description metatag of a web page, ie.
ignore the rest of the mask (let's pretend the web page was read into sFull).
As of June 2004, it appears that the REGEXPR or REGREPL functions can't do this,
so we'll use other functions:
- sInput = "blablabla<meta name=""description""
content="some cool doco">blablabla"
- 'REMAIN() = return stuff after this pattern
- 'EXTRACT() = return stuff until this pattern
- MsgBox EXTRACT$(REMAIN$(sInput,"description"" content="""),""">")
Replacing a section in a string
- sFull = ""
- sMask = ""
- sReplaceMask = ""
- REGREPL sMask IN sFull WITH sReplaceMask TO iPosvar, sNewFull
- MsgBox sNewFull
Compiling from UltraEdit
Advanced | Tool Configurations:
- Command line = D:\PBWin70\Bin\PBWin.exe %F /I.\;D:\PBWIN70\WINAPI (The
/I switch is used to tell UltraEdit where to locate the include files; Note
that ".\" is required to tell UE to start search in the current
work directory. Also, if you installed PB using long filenames for directories,
remember that PB/DLL is a 16-bit compiler... So, you should use the 8.3
notation such as d:\progra~1\pbdll60\bin\Pbdll.exe %F)
- Working directory = %P
- Menu Item Name = PB/DLL
Click on Insert, and OK
PowerBasic add-on for UltraEdit
To tell UltraEdit how to handle PowerBasic files, just edit WORDFILE.TXT
located in UltraEdit's directory, and add this section (Note: Make sure no L11
section already exists):
- /L11"PowerBasic" Line Comment Num = 2' Line
Comment = ' Block Comment On Alt = #PBFORMS File Extensions = BAS INC
- /Delimiters = ~!@^*()+=|\{}[]:;"' ,.<>
- /Function String = "%*^{Sub^}^{Function^}*("
- /C1="STATEMENTS"
- ABS ACCEL ACCEPT ACCESS ACODE$ ADD ADDR ALIAS ALL AND ANY APPEND ARRAY
ARRAYATTR AS ASC ASCEND ASCIIZ ASCIZ ASM AT ATN ATTACH ATTRIB
- BAR BASE BAUD BDECL BEEP BIN$ BINARY BIT BITS% BITS& BITS? BITS??
BITS??? BREAK BUTTON BYCMD BYCOPY BYREF BYTE BYVAL
- CALC CALL CALLBACK CALLSTK CALLSTK$ CALLSTKCOUNT CASE CATCH CBCTL CBCTLMSG
CBHNDL CBLPARAM CBMSG CBWPARAM CBYT CCUR CCUX CD CDBL
- CDECL CDWD CEIL CEXT CHDIR CHDRIVE CHECK CHECK3STATE CHECKBOX CHOOSE
CHOOSE$ CHOOSE% CHOOSE& CHR$ CINT CLIENT CLNG CLOSE CLSID$
- CODEPTR COLLATE COLOR COMBOBOX COMM COMMAND$ CON CONNECT CONST CONST$
CONTROL COS CQUD CREATE CSET CSET$ CSNG CTSFLOW CUR CURDIR$
- CURRENCY CURRENCYX CUX CVBYT CVCUR CVCUX CVD CVDWD CVE CVI CVL CVQ CVS
CVWRD CWRD
- DATA DATACOUNT DATE$ DECLARE DECR DEFAULT DEFBYT DEFCUR DEFCUX DEFDBL
DEFDWD DEFEXT DEFINT DEFLNG DEFQUD DEFSNG DEFSTR DEFWRD DELETE
- DESCEND DIALOG DIM DIR$ DISABLE DISKFREE DISKSIZE DISPATCH DLL DLLMAIN
DLLMAIN& DO DOEVENTS DOUBLE DRAW DSRFLOW DSRSENS DTRFLOW
- DTRLINE DWORD
- ELSE ELSEIF EMPTY ENABLE END ENVIRON$ EOF EQV ERASE ERR ERRAPI ERRCLEAR
ERROR ERROR$ EXE EXIT EXP EXP10 EXP2 EXPLICIT EXPORT EXT
- EXTENDED EXTRACT$
- FILEATTR FILECOPY FILENAME$ FILESCAN FILL FINALLY FIX FLOW FLUSH FOCUS
FONT FOR FORMAT$ FRAC FRAME FREEFILE FROM FUNCNAME$ FUNCTION
- GET GET$ GETATTR GLOBAL GOSUB GOTO GUID GUID$ GUIDTXT$
- HANDLE HEX$ HIBYT HIINT HIWRD HOST
- ICASE ICON IDN IF IFACE IIF IIF$ IIF% IIF& IMAGE IMAGEX IMGBUTTON
IMGBUTTONX IMP IN INCR INOUT INP INPUT INPUT# INPUT$ INPUTBOX$
- INSERT INSTR INT INTEGER INTERFACE INV ISFALSE ISNOTHING ISOBJECT ISTRUE
ITERATE
- JOIN$
- KILL
- LABEL LBOUND LCASE$ LEFT LEFT$ LEN LET LIB LIBMAIN LIBMAIN& LINE
LISTBOX LOBYT LOC LOCAL LOCK LOF LOG LOG10 LOG2 LOINT LONG LOOP
- LOWRD LSET LSET$ LTRIM$
- MACRO MACROTEMP MAIN MAIN& MAKDWD MAKINT MAKLNG MAKPTR MAKWRD MAT
MAX MAX$ MAX% MAX& MCASE$ MEMBER MENU MID$ MIN MIN$ MIN% MIN&
- MKBYT$ MKCUR$ MKCUX$ MKD$ MKDIR MKDWD$ MKE$ MKI$ MKL$ MKQ$ MKS$ MKWRD$
MOD MODAL MODELESS MOUSEPTR MSGBOX
- NAME NEW NEXT NONE NOT NOTHING NOTIFY NULL
- OBJACTIVE OBJECT OBJPTR OBJRESULT OCT$ OF OFF ON OPEN OPT OPTION OPTIONAL
OR OUT OUTPUT
- PARITY PARITYCHAR PARITYREPL PARITYTYPE PARSE PARSE$ PARSECOUNT PBLIBMAIN
PBLIBMAIN& PBMAIN PBMAIN& PEEK PEEK$ PIXELS POINTER POKE
- POKE$ POPUP PORT POST PRESERVE PRINT PRINT# PRIVATE PROFILE PROGID$
PTR PUT PUT$
- QUAD QWORD
- RANDOM RANDOMIZE READ READ$ RECORDS RECV REDIM REDRAW REGEXPR REGISTER
REGREPL REM REMAIN$ REMOVE$ REPEAT$ REPLACE RESET RESUME
- RETAIN$ RETURN RGB RIGHT RIGHT$ RING RLSD RMDIR RND ROTATE ROUND RSET
RSET$ RTRIM$ RTSFLOW RXBUFFER RXQUE
- SCAN SCROLLBAR SDECL SEEK SELECT SEND SERVER SET SETATTR SETEOF SGN
SHARED SHELL SHIFT SHOW SIGNED SIN SINGLE SIZE SIZEOF SLEEP SORT
- SPACE$ SPC SQR STATE STATIC STATUS STDCALL STEP STOP STR$ STRDELETE$
STRING STRING$ STRINSERT$ STRPTR STRREVERSE$ SUB SUSPEND SWAP
- SWITCH SWITCH$ SWITCH% SWITCH&
- TAB TAB$ TAGARRAY TALLY TAN TCP TEXT TEXTBOX THEN THREAD THREADCOUNT
THREADID TIME$ TIMEOUT TIMER TO TOGGLE TRACE TRIM$ TRN TRY
- TXBUFFER TXQUE TYPE
- UBOUND UCASE UCASE$ UCODE$ UDP UNION UNITS UNLOCK UNTIL USER USING USING$
- VAL VARIANT VARIANT# VARIANT$ VARIANTVT VARPTR VERIFY VERSION3 VERSION4
VERSION5
- WEND WHILE WIDTH WIDTH# WINMAIN WINMAIN& WITH WORD WRITE WRITE#
- XINPFLOW XOR XOUTFLOW
- ZER
- /C2"PRECOMPILER"
- !
- #BLOAT #COMPILE #DEBUG #DIM #ELSE #ELSEIF #ENDIF #IF #INCLUDE #OPTION
#PBFORMS #Register #Resource #Stack #Tools $Bel
- $BLOAT $COMPILE $DEBUG $DIM $ELSE $ELSEIF $ENDIF $IF $INCLUDE $OPTION
$REGISTER $RESOURCE $STACK $TOOLS
- /C2"DEFINITIONS"
- $CR $CRLF $BS $DQ $EOF $ESC $FF $LF $NUL $SPC $TAB $VT
- %BLACK %BLUE %CYAN %GRAY %GREEN %LTGRAY %MAGENTA %RED
- %DEF
- %ERR_BADFILEMODE %ERR_BADFILENAME %ERR_BADFILENAMEORNUMBER %ERR_BADRECORDNUMBER
%ERR_COMMERROR %ERR_DEVICEIOERROR %ERR_DEVICETIMEOUT
- %ERR_DEVICEUNAVAILABLE %ERR_DISKFULL %ERR_DISKMEDIAERROR %ERR_DISKNOTREADY
%ERR_FARHEAPCORRUPT %ERR_FILEALREADYEXISTS
- %ERR_FILEISOPEN %ERR_FILENOTFOUND %ERR_ILLEGALFUNCTIONCALL %ERR_INPUTPASTEND
%ERR_INTERNALERROR %ERR_NOERROR %ERR_OUTOFMEMORY
- %ERR_PATHFILEACCESSERROR %ERR_PATHNOTFOUND %ERR_PERMISSIONDENIED %ERR_RENAMEACROSSDISKS
%ERR_STRINGSPACECORRUPT
- %ERR_SUBSCRIPTPOINTEROUTOFRANGE %ERR_TOOMANYFILES
- %PB_CC32 %PB_DLL16 %PB_DLL32 %PB_EXE %PB_REVISION %PB_REVLETTER %PB_WIN32
- %VARCLASS_ASC %VARCLASS_BYT %VARCLASS_CUR %VARCLASS_CUX %VARCLASS_DBL
%VARCLASS_DWD %VARCLASS_EXT %VARCLASS_FIX %VARCLASS_GUID
- %VARCLASS_IFAC %VARCLASS_INT %VARCLASS_LNG %VARCLASS_QUD %VARCLASS_SNG
%VARCLASS_STR %VARCLASS_TYPE %VARCLASS_VRNT %VARCLASS_WRD
- %VT_ARRAY %VT_BLOB %VT_BLOB_OBJECT %VT_BOOL %VT_BSTR %VT_BYREF %VT_CARRAY
%VT_CF %VT_CLSID %VT_CY %VT_DATE %VT_DISPATCH %VT_EMPTY
- %VT_ERROR %VT_FILETIME %VT_HRESULT %VT_I1 %VT_I2 %VT_I4 %VT_I8 %VT_INT
%VT_LPSTR %VT_LPWSTR %VT_NULL %VT_PTR %VT_R4 %VT_R8
- %VT_SAFEARRAY %VT_STORAGE %VT_STORED_OBJECT %VT_STREAM %VT_STREAMED_OBJECT
%VT_UI1 %VT_UI2 %VT_UI4 %VT_UI8 %VT_UINT %VT_UNKNOWN
- %VT_USERDEFINED %VT_VARIANT %VT_VECTOR %VT_VOID
- %WHITE
- %YELLOW
Timing a task
- LOCAL Start AS DWORD
- LOCAL Finish AS DWORD
- LOCAL TotalTime AS DWORD
- Start = GetTickCount
- Finish = GetTickCount
- TotalTime = TotalTime + (Finish - Start)
Coordinates
Check where a user double-clicked in a dialog box
- SELECT CASE CBMSG
- Case %WM_LBUTTONDBLCLK
- LOCAL sEvent AS ASCIIZ
* 32, iX AS INTEGER, iY AS INTEGER
-
- iX = LOWRD(CBLPARAM)
- iY = HIWRD(CBLPARAM)
-
- sEvent = "x="
+ Str$(iX) + ", y=" + str$(iY)
-
- Call SetWindowText (CBHNDL,sEvent)
Icons
Setting the title bar icon
- DIALOG SEND hDlg, %WM_SETICON, %ICON_SMALL, LoadIcon(BYVAL %NULL, BYVAL
%IDI_WINLOGO)
Adding an icon in the resource file, and loading it
- In the .RC file, add references to icon files: MYICON ICON
DISCARDABLE "cool.ico"
- Use RC.EXE to convert this .RC file into a .RES file
- Use PBRES.EXE to turn the .RES file into a .PBR
- In your program, add a reference: #RESOURCE "MYRES.PBR"
- Load the icon: Call SendMessage (hDlg, %WM_SETICON, %ICON_SMALL,
LoadIcon(GetModuleHandle("MYPRG.EXE"), "MYICON"))
Displaying an icon
- hDC = GetDC (CBHNDL)
- Call DrawIcon (hDC, 33, 180, hIcon)
- Call ReleaseDC (CBHNDL, hDC)
Static
Selecting a different font
- LOCAL hOldFont AS LONG
- LOCAL hNewFont AS LONG
-
- hNewFont = CreateFont(0,0,0,0, %FW_HEAVY ,%TRUE,%FALSE,%ANSI_CHARSET,%OUT_TT_PRECIS,0,
_
- %PROOF_QUALITY,%DEFAULT_PITCH,%FF_DONTCARE,"Arial")
-
- CONTROL Send CBHNDL, %IDC_LABEL,%WM_GETFONT,0,0 to hOldFont
- CONTROL Send CBHNDL, %IDC_LABEL, %WM_SETFONT, hNewFont,0
- CONTROL Set TEXT hDlg, %IDC_LABEL, "PowerBasic Rules!"
- CONTROL Send CBHNDL, %IDC_LABEL,hOldFont,0,0
Changing the font
- LOCAL hOldFont AS LONG
-
- CONTROL Send CBHNDL, %IDC_LABEL,%WM_GETFONT,0,0 to hOldFont
- CONTROL Send CBHNDL, %IDC_LABEL, %WM_SETFONT, GetStockObject( %SYSTEM_FIXED_FONT
),0
- CONTROL Set TEXT hDlg, %IDC_LABEL, "PowerBasic Rules!"
- CONTROL Send CBHNDL, %IDC_LABEL,hOldFont,0,0
RichEdit widget
Change color and font
- Type charformat2a
- cbSize As Long
- dwMask As Dword
- dwEffects As Dword
- yHeight As Long
- yOffset As Long
- crTextColor As Dword
- bCharSet As Byte
- bPitchAndFamily As Byte
- szFaceName As Asciiz * %LF_FACESIZE
- wpad2 As Integer
- wWeight As Word
- sSpacing As Integer
- crBackColor As Dword
- lcid As Long
- dwReserved As Dword
- sStyle As Integer
- wKerning As Word
- bUnderlineType As Byte
- bAnimation As Byte
- bRevAuthor As Byte
- bReserved1 As Byte
- End Type
-
- LOCAL MyFormat AS charformat2a
- LOCAL sFaceName AS ASCIIZ * 64
- sFaceName = "Verdana"
-
- MyFormat.cbSize = SizeOf(MyFormat)
- MyFormat.dwMask = %CFM_FACE OR %CFM_COLOR
- MyFormat.szFaceName = sFaceName
- MyFormat.crTextColor = RGB (0,0,255)
-
- CONTROL Send CBHNDL, %IDC_RICHEDIT1, %EM_SETCHARFORMAT, 0,VARPTR(MyFormat)
Threads
- #COMPILE EXE
- #DIM ALL
- #REGISTER NONE
- #INCLUDE "WIN32API.INC"
-
- GLOBAL hDlg AS
LONG
-
- FUNCTION ThreadInst(BYVAL lVal AS LONG) AS LONG
- LOCAL lRet AS LONG
-
- 'Need WHILE, or will execute once and go
- While %TRUE
- Call
SetWindowText (hDlg, TIME$)
- SLEEP
1000
- Wend
- End FUNCTION
-
- CALLBACK FUNCTION IDD_DIALOG1_CB AS LONG
- 'Nichts
- END FUNCTION
-
- FUNCTION PBMain () AS LONG
- LOCAL hThread AS LONG, lRetVal AS LONG
-
- THREAD CREATE ThreadInst(0)
TO hThread
-
- DIALOG NEW 0, "About to be erased...",
0, 0, 279, 169, _
- %DS_MODALFRAME
OR %DS_CENTER OR %WS_POPUP OR %WS_CAPTION OR %WS_SYSMENU, _
- %WS_EX_TOOLWINDOW,
TO hDlg
-
- DIALOG SHOW MODAL hDlg,CALL IDD_DIALOG1_CB TO
lRetVal
-
- THREAD CLOSE hThread TO retVal
-
- END FUNCTION
Timer
- #COMPILE EXE
- #DIM ALL
- #REGISTER NONE
- #INCLUDE "WIN32API.INC"
-
- GLOBAL hDlg AS
LONG
-
- CALLBACK FUNCTION IDD_DIALOG1_CB AS LONG
-
- SELECT CASE CBMSG
- Case
%WM_TIMER
- Call
SetWindowText (hDlg, TIME$)
- END SELECT
- END FUNCTION
-
- FUNCTION PBMain () AS LONG
- LOCAL hThread AS LONG, lRetVal AS LONG
- DIALOG NEW 0, "About to be erased...",
0, 0, 279, 169, _
- %DS_MODALFRAME
OR %DS_CENTER OR %WS_POPUP OR %WS_CAPTION OR %WS_SYSMENU, _
- %WS_EX_TOOLWINDOW,
TO hDlg
-
- Call SetTimer(hDlg, BYVAL
&H0000FEED, 1000, BYVAL %NULL)
-
- DIALOG SHOW MODAL hDlg,CALL IDD_DIALOG1_CB TO
lRetVal
-
- KillTimer hDlg, &H0000FEED
- END FUNCTION
TreeView
- Add a control in your dialog box
CONTROL ADD "SYSTREEVIEW32",
hDlg, %IDC_TREE1, "Tree1", 7, 7, 202, 72, _
%WS_CHILD
or %WS_VISIBLE or %TVS_HASBUTTONS or %TVS_HASLINES or _
%TVS_LINESATROOT
or %TVS_SHOWSELALWAYS, %WS_EX_CLIENTEDGE, _ , 'CALL IDC_TREE1_CB
- In the dialog callback function, add items to the tree:
GLOBAL
CurrentItem AS STRING
GLOBAL hDlgTree As Long
FUNCTION
TVInsertItem(byval hTree as long, byval hParent as long, sTxt as string)
as long
local tv_insert as TV_INSERTSTRUCT
local
tv_item as TV_ITEM
if hParent then
tv_item.mask
= %TVIF_CHILDREN OR %TVIF_HANDLE
tv_item.hItem
= hParent
tv_item.cchildren
= 1
TreeView_SetItem
hTree, tv_item
end if
tv_insert.hParent
=
hParent
tv_insert.Item.Item.mask =
%TVIF_TEXT
tv_insert.Item.Item.pszText =
strptr(sTxt)
tv_insert.Item.Item.cchTextMax =
len(sTxt)
function = TreeView_InsertItem(hTree,
tv_insert)
end function
CALLBACK FUNCTION IDD_DIALOG1_CB
AS LONG
LOCAL hTree AS LONG, hRoot AS LONG, hParent AS LONG
LOCAL
lpNmh As NMHDR Ptr
LOCAL lpTV As NM_TREEVIEW PTR
LOCAL szTxt As AsciiZ
* 61
STATIC tItem As TV_ITEM
hDlgTree
= GetDlgItem(CbHndl,%IDC_TREE1)
SELECT CASE CBMSG
CASE
%WM_INITDIALOG
CONTROL
HANDLE CBHNDL, %IDC_TREE1 to hTree
hRoot
= TVInsertItem(hTree, 0, "Inbox")
hParent
= TVInsertItem(hTree, hRoot, "From GROUCHO: ")
hParent
= TVInsertItem(hTree, hRoot, "From ZEPPO: ")
hRoot
= TVInsertItem(hTree, 0, "Outbox")
hParent
= TVInsertItem(hTree, hRoot, "From HARPO: ")
hParent
= TVInsertItem(hTree, hRoot, "From CHICO: ")
case %WM_NOTIFY
lpNmh
= CblParam
Select Case @lpNmh.Code
Case %TVN_SELCHANGED
lpTV
= CblParam
- tItem.hitem = @lpTV.ItemNew.hItem
- tItem.mask = %TVIF_TEXT
- tItem.pszText = VarPtr(szTxt)
- tItem.cchTextMax = 61&
- Call TreeView_GetItem(hDlgTree,
tItem)
- CurrentItem = szTxt
- Case %NM_DBLCLK
CONTROL
SET TEXT CBHNDL, %IDC_RICHEDIT1, CurrentItem
- Case %NM_RCLICK
Call
TreeView_DeleteItem (hDlgTree, tItem.hitem)
End
Select
Listbox
- 'Get list of items in listbox
- CONTROL SEND CBHNDL, %IDC_LIST1, %LB_GETCOUNT, 0, 0 TO lResult
-
- 'Get currently select item (doesn't work for multiple-selection listboxes)
- CONTROL SEND CBHNDL , %IDC_LIST1, %LB_GETCURSEL, 0,0 TO lResult
- 'Other way
- LISTBOX GET TEXT CBHNDL, %IDC_LIST1 TO sTemp
-
- 'Get select items in multiple-selection listbox
- lResult=SendMessage(GetDlgItem(CBHNDL,%IDC_LIST1), %LB_GETCOUNT,0,0)
' get count of items
- IF lResult>0 THEN
- lResult=lResult-1
- FOR iIndex=0 to lResult ' zero indexed
- IF (SendMessage(GetDlgItem(CBHNDL,%IDC_LIST1),
%LB_GETSEL, iIndex, 0)) THEN
- sTemp = SPACE$(SendMessage(GetDlgItem(CBHNDL,%IDC_LIST1),
%LB_GETTEXTLEN, iIndex, 0) + 1)
- iTemp=SendMessage(GetDlgItem(CBHNDL,%IDC_LIST1),
%LB_GETTEXT, iIndex, STRPTR(sTemp))
- MsgBox sTemp
- END IF
- NEXT iIndex
- END If
-
- 'Another way, by iterating through array of pointers to selected items
- lResult = SendMessage(hList, %LB_GETSELCOUNT, 0, 0)
- IF lResult <> %LB_ERR THEN
- REDIM lArray(lResult - 1) AS LONG
- ReDim sTemp(lResult - 1) AS String
- lResult = SendMessage(hList, %LB_GETSELITEMS,
lResult, VARPTR(lArray(0)))
- END IF
-
- FOR iIndex= 0 TO UBOUND(lArray)
- lResult = SendMessage(hList, %LB_GETTEXT, lArray(iIndex),
STRPTR(sTemp(iIndex)))
- MsgBox sTemp(iIndex)
- Next iIndex
-
- 'Empty listbox
- Call SendMessage(hList, %LB_RESETCONTENT, 0, 0)
-
- 'Check if string exists
- Control Send hDlg,%HDList,%LB_FINDSTRINGEXACT, -1,ByVal StrPtr(Msg$)
To Li&
- 'Add string
- Call SendMessage(hList, %LB_ADDSTRING, 0, BYVAL STRPTR(txt))
- 'Alternative
- ListBox Add hDlg, %ID_LIST1, Txt
Checking the number of items
- iIndex = SendMessage (hControl, %LB_GETCOUNT, 0, 0)
Avoid STRING variables
From Chris Boss
If you attempt to use string variables in PB DLL, your program will be
using the Windows OLE string engine. An awful lot of processing goes on in the
background, when you use string variables. The C code is using the CHAR type,
which if my memory serves me, would be comparable to a Byte array in PB and
not a string variable. Because the OLE string engine (which even VB uses) is
significantly slower than working with a byte array, the PB DLL code should
be significantly slower than the C code.
Displaying a Unicode string
MsgBox only accepts ANSI/ASCII strings. To display a Unicode string, either
convert it with the Win32 API WideCharToMultiByte(), or use this:
- DECLARE FUNCTION SetWindowTextW LIB "USER32.DLL" ALIAS "SetWindowTextW"
(BYVAL hwnd AS LONG, BYVAL lString AS LONG) AS LONG
-
- LOCAL hDlg AS LONG
- LOCAL sMyString AS ASCIIZ * 64
- LOCAL lResult AS LONG
-
- lResult = SetWindowTextW (hDlg, BYVAL VARPTR(sMyString))
Note that the SetWindowText defined in PB/DLL's WIN32API.INC is the ANSI
version (SetWindowTextA).
An alternative: Declare FUNCTION MessageBoxW LIB "USER32.DLL" ALIAS
"MessageBoxW" (BYVAL hwnd AS DWORD, lpText AS ASCIIZ, lpCaption AS
ASCIIZ, BYVAL wType AS LONG) AS LONG
Computing the length of an ASCIIZ
Len(sMyString) doesn't work until you used sMyString = SPACE$(128) to fill
it up with spaces. The reason is that, after an ASCIIZ variable is created,
it is initialized by PowerBasic with a 0... which leads Len() to consider that
the size of the string is equal to 0. Use SizeOf(sMyString) instead.
TPC/IP - Connecting to a web server to download headers
- ERRCLEAR
-
- LOCAL sBuffer as String
- LOCAL nTCP as INTEGER
- LOCAL n AS INTEGER
- LOCAL sBigBuffer as String
- LOCAL sServer as String
-
- nTCP = FREEFILE
-
- sServer = INPUTBOX$("WWW server?")
-
- TCP Open PORT 80 AT sServer AS nTCP
- If ERR THEN MSGBOX "Server could not be reached!"
-
- TCP PRINT nTCP, "HEAD / HTTP/1.0"
- TCP PRINT nTCP, ""
- TCP PRINT nTCP, ""
-
- Do
- TCP LINE nTCP, sBuffer
- sBigBuffer = sBigBuffer + chr$(13) + sBuffer
- Loop While (Len(sBuffer) <> 0)
-
- TCP CLOSE nTCP
-
- MsgBox sBigBuffer
Note: Under 98/98SE, at least with PB/Win 7.04, you may trigger an error
when setting the port using aliases such as "http" instead of setting
its numeric value, eg. "PORT 80". The following always triggered error
57 under 98SE:
- ERRCLEAR
-
- 'Replace with PORT 80
- TCP OPEN "http" AT "www.acme.com" AS #1 TIMEOUT
5000
- If ISFALSE ERR Then
- MsgBox "Online"
- TCP Close #1
- Else
- MsgBox "Offline",,"Err = "
& str$(ERR)
- END IF
Drawing text in the main window
- CASE %WM_PAINT
- hDC = BeginPaint(hWnd, LpPaint)
- GetClientRect hWnd, tRect
-
- For iIndex = 1 TO 10
- sBufferA = "Test"
+ str$(iIndex)
- lResult = TextOut(hDc,
100, iIndex * 50, sBufferA, Len(sBufferA))
- Next iIndex
-
- For iIndex = 1 TO 10
- tRect.nLeft = 100
- tRect.nTop = 100 (iIndex/2)
- tRect.nRight = 200
- tRect.nBottom = 600
- DrawText hDC, "Line
" + str$(iIndex), -1, tRect, %DT_SINGLELINE OR %DT_CENTER 'OR %DT_VCENTER
- Next iIndex
-
- EndPaint hWnd, LpPaint
-
Creating child windows, and sending messages to them
- GLOBAL hButton AS LONG
- GLOBAL hList AS LONG
-
- %Button = 100
- %List = 101
-
- hButton = CreateWindow("BUTTON", "Click me", %WS_VISIBLE
OR %WS_CHILD OR %BS_DEFPUSHBUTTON, _
- 10,
10, 100, 100,hWnd, %Button, hInstance, %NULL)
-
- hList = CreateWindow("LISTBOX", "", %WS_VISIBLE
OR %WS_CHILD OR %LBS_EXTENDEDSEL OR %LBS_HASSTRINGS OR %LBS_STANDARD,
_
- 110,
10, 150, 150, hWnd, %List, hInstance, %NULL)
-
Converting from ANSI to Unicode, and sending a pop-up message
- LOCAL sToHostA as ASCIIZ * %STR_MAX_SIZE
- LOCAL sToHostW as ASCIIZ * (%STR_MAX_SIZE * 2)
-
- LOCAL sBufferA AS ASCIIZ * %STR_MAX_SIZE
- LOCAL sBufferW AS ASCIIZ * (%STR_MAX_SIZE * 2)
-
- sBufferA = "All your base are belong to us"
-
- SELECT CASE wMsg
- Case %WM_CREATE
- GetUserName sToHostA,
%STR_MAX_SIZE
-
- lResult = MultiByteToWideChar
(%CP_ACP, 0&, sToHostA, -1, sToHostW, Len(sToHostA) * 2)
- lResult = MultiByteToWideChar
(%CP_ACP, 0&, sBufferA, -1, sBufferW, Len(sBufferA) * 2)
-
- lResult = NetMessageBufferSend
("", sToHostW, "", sBufferW, %STR_MAX_SIZE * 2)
Reading from a sequential file
- LOCAL strHosts() AS STRING
-
- ERRCLEAR
- hFile = FREEFILE
- OPEN "HOSTS.DAT" FOR INPUT AS hFile
- IF ERR = 53 THEN
- MSGBOX "Error: No HOSTS.DAT in local directory.
Exiting."
- EXIT FUNCTION
- END IF
-
- iIndex = 0
- WHILE NOT EOF(hFile)
- REDIM PRESERVE strHosts(iIndex + 1) AS STRING
- LINE INPUT #hFile, strHosts(iIndex)
- iIndex = iIndex + 1
- WEND
-
- CLOSE hFile
Writing to a sequential file
- OPEN "OPEN.DTA" FOR OUTPUT AS #1
- PRINT# 1, sBufferA
- CLOSE 1
DDT - Obtaining selected items in listbox
- CALLBACK FUNCTION DlgProc()
-
- LOCAL lReturn AS LONG
-
- SELECT CASE CBMSG
-
- CASE
%WM_COMMAND
-
- SELECT
CASE CBCTL
-
- CASE
%IDLIST
- IF
(CBCTLMSG = %CBN_SELCHANGE) THEN
- CONTROL
SEND CBHNDL , CBCTL, %LB_GETCURSEL, 0,0 TO lReturn
- CONTROL
SEND CBHNDL, CBCTL, %LB_GETTEXT, lReturn, VARPTR(sToHostA)
- END
IF
-
- FUNCTION=0
- EXIT
FUNCTION
-
- END
SELECT
-
- END SELECT
-
- END FUNCTION
Displaying the host's workgroup/domain
- FUNCTION StrToAnsi(BYVAL u AS LONG) AS STRING
-
- DIM Buffer AS STRING
- DIM x AS STRING
- DIM l AS LONG
-
- l = lstrlenW(BYVAL u)
- x = PEEK$(u, l * 2)
-
- Buffer = SPACE$(LEN(x) \ 2)
-
- WideCharToMultiByte %CP_ACP, _ '
code page
- %NULL,
_ '
performance and mapping flags
- BYVAL
STRPTR(x), _ ' Unicode string to convert
- LEN(x),
_ '
len of Unicode string
- BYVAL
STRPTR(Buffer), _ ' buffer for ANSI string
- LEN(Buffer),
_ ' len of ANSI
buffer
- BYVAL
%NULL, _ ' default
for unmappable chars
- BYVAL
%NULL '
default flag
-
- IF LEN(Buffer) = 0 THEN
- Buffer = "[none]"
- END IF
-
- FUNCTION = RTRIM$(Buffer)
-
- END FUNCTION
-
- LOCAL MyWKSTA_INFO_100 AS WKSTA_INFO_100 PTR
-
- lResult = NetWkstaGetInfo(BYVAL %NULL, 100, MyWKSTA_INFO_100)
- MsgBox "System name: \\" & StrToAnsi(@MyWKSTA_INFO_100.wki100_langroup)
Networking
Enumerating the list of shared drives on the LAN
To achieve this, the EnumAll() function below is called recursively so as
to list all the shared drives for each host, and exit until all the entries
have been parsed:
- Function EnumAll (nr AS NETRESOURCE) as String
- LOCAL hEnum AS LONG
- LOCAL Entries AS LONG
- LOCAL nSize AS LONG
- LOCAL ec AS LONG
- LOCAL x AS
LONG
-
- 'Static because this string but live through
each recurrent call
- Static sStuff as String
-
- DIM n(1 to 256) AS NETRESOURCE
-
- Entries = 256
- nSize = SIZEOF(nr) * Entries
-
- ec = WNetOpenEnum(%RESOURCE_GLOBALNET, %RESOURCETYPE_DISK,
%NULL, nr, hEnum)
-
- ec = WNetEnumResource(hEnum, Entries, n(1),
nSize)
-
- FOR x = 1 TO Entries
- IF (n(x).dwUsage AND
%RESOURCEUSAGE_CONTAINER) THEN
- EnumAll
n(x)
- Else
- sStuff
= sStuff & LTRIM$(n(x).@lpRemoteName) & $CRLF
- END IF
- NEXT
-
- 'We're done parsing through, so return the list
- Function = sStuff
- END Function
-
- Function PBMain
- MsgBox EnumAll BYVAL
%NULL
- End Function
Working with Win32 APIs
C
|
PB/DLL
|
hWnd
|
BYVAL hWnd AS WORD
|
lpStr
|
lpStr AS ASCIIZ PTR
|
UINT Style
|
BYVAL Style AS WORD
|
CHAR
|
BYTE
|
|
|
|
|
|
|
|
|
|
|
VARPTR = address where a variable is stored in memory
STRPTR = pointer to a string
CODEPTR = address of a routine
AS STRING
AS STRING * 10
AS ASCIIZ * 10 'Same as above, but last
character is ASCII 0, ie. up to 9 characters available
AS ... PTR 'Pointer, eg. AS STRING PTR = char *
DIM MYSTR AS STRING
DIM
MYSTRPTR AS STRING PTR
MYSTRPTR = STRPTR(MYSTR)
@MYSTRPTR = "Test"
'Same as MYSTR = "Test"
INCR MYSTRPTR 'Opposit is DECR MYSTRPTR
DIM MYSTRUCTPTR(1 to 10) AS MYSTRUCT PTR
FOR I = 1 TO 10
@MYSTRUCTPTR(I).FIELD1
= "Item " + STR$(I)
NEXT I
@MYARRAY[I].FIELD1 'For arrays
created by other languages
Equates different from numeric constants? Equates have global scope
This is not allowed: VARPTR(lMyLong) =
Instead:
DIM lMyLong AS LONG
DIM pMyLongPtr AS LONG PTR
pMyLongPtr = VARPTR(lMyLong)
@pMyLongPtr = 1 'same as lMyLong = 1
ASCIIZ = address of a string
An ASCIIZ string is very different from a STRING. It's actually the same
thing as a string in C: The variable contains an address (pointer) to the memory
cell where the first character is located.
- LOCAL sMyString AS ASCIIZ * 128
- LOCAL pMyString as ASCIIZ PTR
- pMyString = VARPTR(sMyString)
-
- MoveMemory @pMyString, BYVAL se100.sv100_name, 1
- 'This also works
- MoveMemory BYVAL pMyString, BYVAL se100.sv100_name, 1
- 'This also works
- MoveMemory BYVAL VARPTR(sMyString), BYVAL se100.sv100_name, 1
Round trip
- LOCAL sStart AS ASCIIZ * 64
- LOCAL sFinish AS ASCIIZ * 64
- LOCAL MyWKSTA_INFO_100 AS WKSTA_INFO_100
-
- sStart = "Hi there"
- 'wki100_langroup is a LONG, ie. contains the address of a variable
- MyWKSTA_INFO_100.wki100_langroup = VARPTR(sStart)
- MoveMemory sFinish, BYVAL MyWKSTA_INFO_100.wki100_langroup, SIZEOF(sFinish)
- MsgBox sFinish
Questions
How to set a pushbutton clickable through ENTER in DDT and PB 7.03?
This code generated by PBForms won't let me just hit ENTER as an alternative
to a mouse click:
- 'Originally tried without the long list of parameters as last parameter,
to no avail
- CONTROL ADD BUTTON, hDlg, %IDC_CANCEL, "Cancel", 140, 35,
55, 20, _
- %WS_CHILD Or %WS_VISIBLE
Or %WS_TABSTOP Or %BS_TEXT Or _
- %BS_DEFPUSHBUTTON Or
%BS_PUSHBUTTON Or %BS_CENTER Or %BS_VCENTER, _
- %WS_EX_LEFT Or %WS_EX_LTRREADING
-
- Dialog Send hDlg, %DM_SETDEFID,
%IDC_CANCEL, 0
What's the difference between DIM and LOCAL?
Saw both in samples. DIM is required when declaring arrays (LOCAL triggers
an error), eg. Dim rEntry(1) As RASENTRYNAME .
While using DDT, widgets coordinates are wrong
The problem is that Win32 APIs such as GetClientRect() or MoveWindow() use
pixels (which are device-dependent) while DDT instructions "dialog units"
(which are pretty much device-independent.) Either use only DDT instructions
such as CONTROL SET SIZE and the like, or use DIALOG PIXELS ... UNITS and DIALOG
UNITS ... TO PIXELS to convert coordinates between Win32 and DDT.
Here's a sample:
- 'Instead of using GetClientRect and converting from pixels to DUs
- DIALOG GET CLIENT CBHNDL TO R.nRight, R.nBottom
- CONTROL ADD LISTBOX, CBHNDL, 500,, 0, 0, 85, R.nBottom, etc.
FYI, PBForms and
Edwin Knoppert's (PBSoft) VisualDesigner
show widget coordinates in dialog units.
When I start PBForms with a maximized dialog
... the PBForms application is covered with my dialog and can't be accessed.
Right-click on the PBForms icon in the taskbar, Minimize, then Restore.
Where can I find more infos on using the Win32 API?
A version is here,
but there may be more recent versions on MS' site.
How to emulate OOP in PB?
- Keep all the code pertaining to an "object" in its .BAS file
and #include it in the main .BAS file
- use STATIC local variable (their value is kept even after leaving the
routine)
- Prefix all routines (subs & functions) with the name of the object,
eg. Grid_Init(), Grid_Add(), etc.
- Good practise : Use #DIM ALL, add a prefix to global variables (eg.
Glb_X)
How does PB compare to other Basic languages like IBasic, PureBasic and RealBasic?
IBasic
PureBasic
RealBasic
Rapid-Q
I need a good graphics library
FastGraph
I need to write a COM server
(From Lance Edmonds, sept 2002) PowerBASIC does not natively support the
creation of COM components (yet?!), but you might be able to do it using some
of the tools available from http://www.jazzagesoft.com
Are there any wrappers to make it easier to work with widgets?
Especially when using common controls which can be troublesome.
Sometimes, the PB/DLL compiler gets stuck
Remember, PB/DLL is a 16-bit compiler, and Windows' 16-bit engine can go
haywire. In NT, open Task Manager, and kill WOWEXEC.EXE.
When declaring APIs, why is the ALIAS part required?
Is PbMain() the equivalent to C's main()...
... and, if yes, do I use it when my Windows application only uses a dialog
box instead of a full-fledged window with? IOW, can I get rid of WinMain() and
WinProc() ?
What is DDT?
DDT: Dynamic Dialog Tools(tm)... With DDT, you'll build complete
GUI applications easier than ever. Don't struggle with form designers.
Don't fight with resource scripts. Don't get lost in a sea of API calls!
With PB/DLL's DDT, a few simple Basic Statements will build a complete
Graphical User Interface!
* DIALOG NEW creates an empty dialog box. CONTROL ADD places buttons,
icons, frames, bitmaps, combo boxes, labels, list boxes, text/edit boxes, even
custom controls and more. Add menus. Then display it with DIALOG
SHOW. It really is just that easy! Perhaps best of all, DDT is dynamic.
Change dialogs and controls "on-the-fly"! Alter the size,
position, and style at will. With DDT, we put the Power in your hands.
That's precisely where it belongs!
I get Error 480: Parameter mismatch, may need ByCopy when calling a SUB
You defined a SUB, but called it with parentheses:
- Sub MyFunc (sMyString AS STRING)
- 'nichts
- End Sub
-
- FUNCTION PBMAIN () AS LONG
- DIM sMyString AS STRING
-
- MyFunc (sMyString)
-
- END FUNCTION
Use "MyFunc sMyString", or "Call MyFunc(sMyString)" instead.
Error 420 when calling an API function
Functions return a value. Add an lResult = .
How to maximize a dialog box at creation time?
Tried using 0,0 as width,height and ORing %WS_MAXIMIZE, to no avail.
How to add an icon in the title bar of a dialog bar?
Tried a bunch of switches in PBForm, but none worked.
Temp
Watch out : contrary to what it says in the online help of 7.02, search _is_ case sensitive by default (didn't find </title> because it was </TITLE> !:!!!!!!
1. REGEXPR statement
"While it is possible for more than one match to be found in a particular target string, REGEXPR first selects one or more matches which start at the leftmost possible position, then returns the longest of those. Use the \s special escape operator to force a match on the shortest match."
=>
'Doesn't work
sMask = "\s[0-9]+"
2. "Tags/sub-patterns:
(parentheses) Parentheses are used to match a Tag, or sub-pattern, within the full search pattern, and remember the match. The
matched sub-pattern _can be retrieved later in the mask_ (or in a replace operation with REGREPL), with \01 through \99, based upon the left-to-right position of the opening parentheses."
=> "Retrieved later", ie. possible to extract subtag with REGEXPR instead of REGREPL?
3. "Parentheses may also be used to force precedence of evaluation with the alternation operator. For example, "(Begin)|(End)File" would match either "BeginFile" or "EndFile" [...]".
=> Shouldn't the pattern be "(Begin|End)" instead?
4. "Note: Parentheses may not be used with ? + * as any match repetition could cause the tag value to be ambiguous. To match repeated expressions, use parentheses followed by \01*."
=> Er... that is, sMask = "<content=""()\01*"">"?
5. REGREPL only works if the mask matches the entire original string:
'Doesn't work...
'sFull = "blablabla<content=" + $DQ + "mycontent" + $DQ + ">blablabla"
sFull = "<content=" + $DQ + "mycontent" + $DQ + ">"
sMask = "<content=\q(.+)\q>"
sReplaceMask = "\01"
REGREPL sMask IN sFull WITH sReplaceMask TO lPosvar, sNewFull
Resources