DVX_GUI/docs/dvx_basic_reference.html
2026-10-20 17:24:15 -05:00

8122 lines
702 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DVX BASIC IDE Guide</title>
<style>
body { font-family: sans-serif; margin: 0; padding: 0; display: flex; }
nav { width: 250px; min-width: 250px; background: #f0f0f0; padding: 16px;
border-right: 1px solid #ccc; height: 100vh; overflow-y: auto;
position: sticky; top: 0; box-sizing: border-box; }
nav ul { list-style: none; padding-left: 16px; margin: 4px 0; }
nav > ul { padding-left: 0; }
nav a { text-decoration: none; color: #0066cc; }
nav a:hover { text-decoration: underline; }
main { flex: 1; padding: 24px 32px; max-width: 800px; }
h1 { border-bottom: 2px solid #333; padding-bottom: 4px; }
h2 { border-bottom: 1px solid #999; padding-bottom: 2px; margin-top: 32px; }
h3 { margin-top: 24px; }
pre { background: #f8f8f8; border: 1px solid #ddd; padding: 8px;
overflow-x: auto; font-size: 14px; }
blockquote { background: #fffde7; border-left: 4px solid #ffc107;
padding: 8px 12px; margin: 12px 0; }
hr { border: none; border-top: 1px solid #ccc; margin: 24px 0; }
img { max-width: 100%; }
.topic { margin-bottom: 48px; }
</style>
</head>
<body>
<nav>
<h3>Contents</h3>
<ul>
<li><a href="#ide.overview">Overview</a>
<ul>
<li><a href="#ide.menu.file">Menu Reference</a>
<ul>
<li><a href="#ide.menu.file">File Menu</a></li>
<li><a href="#ide.menu.edit">Edit Menu</a></li>
<li><a href="#ide.menu.run">Run Menu</a></li>
<li><a href="#ide.menu.view">View Menu</a></li>
<li><a href="#ide.menu.window">Window Menu</a></li>
<li><a href="#ide.menu.tools">Tools Menu</a></li>
<li><a href="#ide.menu.help">Help Menu</a></li>
</ul>
</li>
<li><a href="#ide.toolbar">Toolbar</a></li>
<li><a href="#ide.editor">Code Editor</a></li>
<li><a href="#ide.designer">Form Designer</a></li>
<li><a href="#ide.project">Project System</a></li>
<li><a href="#ide.package">Making a Package</a></li>
<li><a href="#ide.usercontrols">UserControls in the IDE</a></li>
<li><a href="#ide.properties">Properties Panel</a></li>
<li><a href="#ide.toolbox">Toolbox</a></li>
<li><a href="#ide.debugger">Debugger</a></li>
<li><a href="#ide.debug.locals">Debug Windows</a>
<ul>
<li><a href="#ide.debug.locals">Locals Window</a></li>
<li><a href="#ide.debug.callstack">Call Stack Window</a></li>
<li><a href="#ide.debug.watch">Watch Window</a></li>
<li><a href="#ide.debug.breakpoints">Breakpoints Window</a></li>
</ul>
</li>
<li><a href="#ide.immediate">Immediate Window</a></li>
<li><a href="#ide.output">Output Window</a></li>
<li><a href="#ide.findreplace">Find / Replace</a></li>
<li><a href="#ide.preferences">Preferences</a></li>
<li><a href="#ide.shortcuts">Keyboard Shortcuts</a></li>
</ul>
</li>
<li><a href="#ide.changes">Changes in This Release</a></li>
<li><a href="#lang.datatypes">Data Types</a>
<ul>
<li><a href="#lang.variants">Variants</a></li>
<li><a href="#lang.operators">Operators</a></li>
<li><a href="#lang.statements">Statements</a>
<ul>
<li><a href="#lang.declarations">Declarations</a></li>
<li><a href="#lang.conditionals">Conditionals</a></li>
<li><a href="#lang.loops">Loops</a></li>
<li><a href="#lang.procedures">Procedures</a></li>
<li><a href="#lang.flow">Flow Control</a></li>
<li><a href="#lang.io">Input/Output</a></li>
<li><a href="#lang.misc">Miscellaneous Statements</a></li>
<li><a href="#lang.sound">Sound, Joysticks, and Frames</a></li>
<li><a href="#lang.screen">Console and Graphics</a></li>
</ul>
</li>
<li><a href="#lang.fileio">File I/O</a></li>
<li><a href="#lang.filesystem">File System Statements</a></li>
<li><a href="#lang.func.string">Built-in Functions</a>
<ul>
<li><a href="#lang.func.string">String Functions</a></li>
<li><a href="#lang.func.math">Math Functions</a></li>
<li><a href="#lang.func.conversion">Conversion Functions</a></li>
<li><a href="#lang.func.date">Date and Time Functions</a></li>
<li><a href="#lang.func.fileio">File I/O Functions</a></li>
<li><a href="#lang.func.misc">Miscellaneous Functions</a></li>
</ul>
</li>
<li><a href="#lang.forms">Form and Control Statements</a></li>
<li><a href="#lang.classes">Objects and Class Modules</a>
<ul>
<li><a href="#lang.events">Events</a></li>
<li><a href="#lang.interfaces">Interfaces (Implements)</a></li>
<li><a href="#lang.collection">Collection Object</a></li>
</ul>
</li>
<li><a href="#lang.sql">SQL Functions</a></li>
<li><a href="#lang.app">App Object</a></li>
<li><a href="#lang.clipboard">Clipboard Object</a></li>
<li><a href="#lang.printerobj">Printer Object</a></li>
<li><a href="#lang.screenobj">Screen Object</a></li>
<li><a href="#lang.ini">INI Functions</a></li>
<li><a href="#lang.constants">Predefined Constants</a></li>
<li><a href="#lang.runtime">Include Libraries</a></li>
</ul>
</li>
<li><a href="#ctrl.common.props">Common Properties, Events, and Methods</a>
<ul>
<li><a href="#ctrl.drawing">Drawing on Forms and PictureBoxes</a></li>
<li><a href="#ctrl.databinding">Data Binding</a></li>
<li><a href="#ctrl.menus">Menu System</a></li>
<li><a href="#ctrl.arrays">Control Arrays</a></li>
<li><a href="#ctrl.frm">FRM File Format</a></li>
<li><a href="#ctrl.form">Form</a></li>
<li><a href="#lang.usercontrol">UserControls: Your Own Controls</a></li>
<li><a href="#ctrl.terminal">Special Controls</a></li>
<li><a href="#ctrl.terminal">Terminal</a></li>
<li><a href="#ctrl.frame">Frame</a></li>
<li><a href="#ctrl.hbox">HBox</a></li>
<li><a href="#ctrl.vbox">VBox</a></li>
<li><a href="#ctrl.button">CommandButton</a></li>
<li><a href="#ctrl.picturebox">PictureBox</a></li>
<li><a href="#ctrl.checkbox">CheckBox</a></li>
<li><a href="#ctrl.combobox">ComboBox</a></li>
<li><a href="#ctrl.data">Data Controls</a></li>
<li><a href="#ctrl.data">Data</a></li>
<li><a href="#ctrl.dbgrid">DBGrid</a></li>
<li><a href="#ctrl.dropdown">DropDown</a></li>
<li><a href="#ctrl.helppane">Data Display Controls</a></li>
<li><a href="#ctrl.helppane">HelpPane</a></li>
<li><a href="#ctrl.imagebutton">ImageButton</a></li>
<li><a href="#ctrl.image">Image</a></li>
<li><a href="#ctrl.label">Label</a></li>
<li><a href="#ctrl.listbox">ListBox</a></li>
<li><a href="#ctrl.listview">Data Display Controls</a></li>
<li><a href="#ctrl.listview">ListView</a></li>
<li><a href="#ctrl.progressbar">ProgressBar</a></li>
<li><a href="#ctrl.optionbutton">OptionButton</a></li>
<li><a href="#ctrl.richedit">RichEdit</a></li>
<li><a href="#ctrl.richlabel">RichLabel</a></li>
<li><a href="#ctrl.scrollpane">ScrollPane</a></li>
<li><a href="#ctrl.line">Decorative Controls</a></li>
<li><a href="#ctrl.line">Line</a></li>
<li><a href="#ctrl.hscrollbar">HScrollBar</a></li>
<li><a href="#ctrl.spacer">Spacer</a></li>
<li><a href="#ctrl.spinbutton">SpinButton</a></li>
<li><a href="#ctrl.splitter">Splitter</a></li>
<li><a href="#ctrl.statusbar">StatusBar</a></li>
<li><a href="#ctrl.tabstrip">Tabbed and Split Controls</a></li>
<li><a href="#ctrl.tabstrip">TabStrip</a></li>
<li><a href="#ctrl.textbox">TextBox</a></li>
<li><a href="#ctrl.textarea">TextArea</a></li>
<li><a href="#ctrl.timer">Timer</a></li>
<li><a href="#ctrl.toolbar">Bar Controls</a></li>
<li><a href="#ctrl.toolbar">Toolbar</a></li>
<li><a href="#ctrl.treeview">TreeView</a></li>
<li><a href="#ctrl.wrapbox">WrapBox</a></li>
</ul>
</li>
</ul>
<h3>Index</h3>
<ul>
<li><a href="#ide.project">.cls Files</a></li>
<li><a href="#lang.classes">.cls Files</a></li>
<li><a href="#lang.usercontrol">.ctl</a></li>
<li><a href="#ide.usercontrols">.ctl Files</a></li>
<li><a href="#ide.project">.dbp Files</a></li>
<li><a href="#ctrl.frm">.frm</a></li>
<li><a href="#ide.menu.help">About</a></li>
<li><a href="#lang.func.math">ABS</a></li>
<li><a href="#ide.shortcuts">Accelerators</a></li>
<li><a href="#ctrl.drawing">AccelKey</a></li>
<li><a href="#ctrl.form">ActiveControl</a></li>
<li><a href="#lang.collection">Add</a></li>
<li><a href="#ide.menu.file">Add File</a></li>
<li><a href="#lang.runtime">Add-on packages</a></li>
<li><a href="#ctrl.treeview">AddChildItem</a></li>
<li><a href="#ctrl.listbox">AddItem</a></li>
<li><a href="#ctrl.treeview">AddItem</a></li>
<li><a href="#ctrl.richlabel">AddLineBreak</a></li>
<li><a href="#ctrl.menus">AddMenuItem</a></li>
<li><a href="#ctrl.menus">AddMenuSeparator</a></li>
<li><a href="#ctrl.data">AddNew</a></li>
<li><a href="#ctrl.richlabel">AddParagraph</a></li>
<li><a href="#ctrl.menus">AddSubMenu</a></li>
<li><a href="#ctrl.richlabel">AddText</a></li>
<li><a href="#ctrl.hbox">Alignment</a></li>
<li><a href="#ctrl.label">Alignment</a></li>
<li><a href="#ctrl.statusbar">Alignment</a></li>
<li><a href="#ctrl.toolbar">Alignment</a></li>
<li><a href="#lang.operators">AND</a></li>
<li><a href="#ctrl.terminal">ANSI Terminal</a></li>
<li><a href="#lang.app">App</a></li>
<li><a href="#lang.app">App.Data</a></li>
<li><a href="#lang.app">App.Path</a></li>
<li><a href="#lang.app">App.User</a></li>
<li><a href="#lang.screenobj">Arrange</a></li>
<li><a href="#lang.variants">ARRAY</a></li>
<li><a href="#lang.func.string">ASC</a></li>
<li><a href="#lang.func.string">ASCW</a></li>
<li><a href="#lang.func.math">ATN</a></li>
<li><a href="#lang.classes">Attribute</a></li>
<li><a href="#ide.editor">Auto-indent</a></li>
<li><a href="#ctrl.textarea">AutoIndent</a></li>
<li><a href="#ctrl.drawing">AutoRedraw</a></li>
<li><a href="#ctrl.form">AutoSize</a></li>
<li><a href="#lang.sound">BEEP</a></li>
<li><a href="#lang.declarations">BINARY STRING</a></li>
<li><a href="#ctrl.image">BMP</a></li>
<li><a href="#lang.datatypes">Boolean</a></li>
<li><a href="#ctrl.picturebox">BorderStyle</a></li>
<li><a href="#ide.debugger">Breakpoints</a></li>
<li><a href="#ide.debug.breakpoints">Breakpoints Window</a></li>
<li><a href="#ctrl.button">Button</a></li>
<li><a href="#lang.datatypes">Byte</a></li>
<li><a href="#lang.procedures">BYVAL</a></li>
<li><a href="#lang.flow">CALL</a></li>
<li><a href="#ide.debug.callstack">Call Stack</a></li>
<li><a href="#lang.classes">CallByName</a></li>
<li><a href="#lang.classes">CALLBYNAME</a></li>
<li><a href="#ctrl.button">Cancel</a></li>
<li><a href="#ctrl.picturebox">Canvas</a></li>
<li><a href="#ctrl.form">Caption</a></li>
<li><a href="#ctrl.label">Caption</a></li>
<li><a href="#lang.conditionals">CASE</a></li>
<li><a href="#lang.conditionals">CASE ELSE</a></li>
<li><a href="#lang.func.conversion">CBOOL</a></li>
<li><a href="#lang.func.conversion">CBYTE</a></li>
<li><a href="#lang.func.conversion">CCUR</a></li>
<li><a href="#lang.func.conversion">CDATE</a></li>
<li><a href="#lang.func.conversion">CDBL</a></li>
<li><a href="#ide.changes">Changes</a></li>
<li><a href="#lang.filesystem">CHDIR</a></li>
<li><a href="#lang.filesystem">CHDRIVE</a></li>
<li><a href="#ctrl.checkbox">CheckBox</a></li>
<li><a href="#lang.func.misc">CHOOSE</a></li>
<li><a href="#lang.func.string">CHR$</a></li>
<li><a href="#lang.func.string">CHRW$</a></li>
<li><a href="#lang.func.conversion">CINT</a></li>
<li><a href="#lang.screen">CIRCLE</a></li>
<li><a href="#ctrl.drawing">Circle method</a></li>
<li><a href="#lang.classes">Class Module</a></li>
<li><a href="#lang.classes">Class Modules</a></li>
<li><a href="#ide.project">Class Modules in the IDE</a></li>
<li><a href="#lang.datatypes">Class Types</a></li>
<li><a href="#lang.classes">Class_Initialize</a></li>
<li><a href="#lang.classes">Class_Terminate</a></li>
<li><a href="#ide.project">Classes Section</a></li>
<li><a href="#ide.menu.run">Clear Output</a></li>
<li><a href="#ctrl.button">Click</a></li>
<li><a href="#lang.clipboard">Clipboard</a></li>
<li><a href="#lang.clipboard">Clipboard.Clear</a></li>
<li><a href="#lang.clipboard">Clipboard.GetFormat</a></li>
<li><a href="#lang.clipboard">Clipboard.GetText</a></li>
<li><a href="#lang.clipboard">Clipboard.SetText</a></li>
<li><a href="#lang.func.conversion">CLNG</a></li>
<li><a href="#lang.fileio">CLOSE</a></li>
<li><a href="#ide.menu.file">Close Project</a></li>
<li><a href="#lang.screen">CLS</a></li>
<li><a href="#ctrl.drawing">Cls</a></li>
<li><a href="#lang.classes">CLS Files</a></li>
<li><a href="#ide.editor">Code Editor</a></li>
<li><a href="#ctrl.textarea">Code editor</a></li>
<li><a href="#lang.runtime">Code editors</a></li>
<li><a href="#ide.menu.view">Code View</a></li>
<li><a href="#lang.collection">Collection</a></li>
<li><a href="#lang.collection">COLLECTION</a></li>
<li><a href="#lang.collection">Collection Keys</a></li>
<li><a href="#lang.screen">COLOR</a></li>
<li><a href="#lang.runtime">Color Dialog</a></li>
<li><a href="#ctrl.textbox">Colorize</a></li>
<li><a href="#ctrl.listview">ColumnClick</a></li>
<li><a href="#ctrl.combobox">ComboBox</a></li>
<li><a href="#lang.runtime">comm.bas</a></li>
<li><a href="#lang.func.misc">Command Line</a></li>
<li><a href="#lang.func.misc">COMMAND$</a></li>
<li><a href="#ctrl.form">COMMAND$ (new arguments)</a></li>
<li><a href="#ctrl.button">CommandButton</a></li>
<li><a href="#lang.runtime">commdlg.bas</a></li>
<li><a href="#lang.statements">Comments</a></li>
<li><a href="#lang.runtime">CommHandshake</a></li>
<li><a href="#lang.runtime">CommHandshakeStep</a></li>
<li><a href="#lang.runtime">CommLastError</a></li>
<li><a href="#ctrl.common.props">Common Events</a></li>
<li><a href="#ctrl.common.props">Common Methods</a></li>
<li><a href="#ctrl.common.props">Common Properties</a></li>
<li><a href="#lang.runtime">CommOpenTcp</a></li>
<li><a href="#lang.runtime">CommRecvEncrypted</a></li>
<li><a href="#lang.runtime">CommSetPlain</a></li>
<li><a href="#lang.runtime">CompBuildApp</a></li>
<li><a href="#lang.runtime">CompClassEvents$</a></li>
<li><a href="#lang.runtime">CompCompile</a></li>
<li><a href="#lang.runtime">CompDesignControls</a></li>
<li><a href="#lang.runtime">CompDesignRelease</a></li>
<li><a href="#lang.runtime">CompError$</a></li>
<li><a href="#lang.runtime">CompHelpTopic$</a></li>
<li><a href="#ide.output">Compile Errors</a></li>
<li><a href="#lang.runtime">compiler.bas</a></li>
<li><a href="#lang.runtime">Compiling programs</a></li>
<li><a href="#lang.runtime">CompInCode</a></li>
<li><a href="#lang.runtime">CompKeywordClass</a></li>
<li><a href="#lang.runtime">CompProcList$</a></li>
<li><a href="#lang.runtime">CompRenameInCode$</a></li>
<li><a href="#lang.runtime">CompSourceCreate</a></li>
<li><a href="#lang.runtime">CompSourceFromProject</a></li>
<li><a href="#lang.runtime">CompTokens$</a></li>
<li><a href="#lang.runtime">CompWithEvents$</a></li>
<li><a href="#lang.runtime">conn.bas</a></li>
<li><a href="#lang.runtime">ConnAttach</a></li>
<li><a href="#lang.runtime">ConnCreate</a></li>
<li><a href="#lang.runtime">Connections</a></li>
<li><a href="#lang.runtime">ConnOpen</a></li>
<li><a href="#lang.runtime">ConnPoll</a></li>
<li><a href="#lang.runtime">ConnReceiveFiles</a></li>
<li><a href="#lang.runtime">ConnSendFiles</a></li>
<li><a href="#lang.screen">Console</a></li>
<li><a href="#lang.declarations">CONST</a></li>
<li><a href="#ctrl.common.props">Container</a></li>
<li><a href="#ctrl.frame">Container</a></li>
<li><a href="#lang.forms">Control Arrays</a></li>
<li><a href="#ctrl.arrays">Control Arrays</a></li>
<li><a href="#lang.runtime">Control Panel settings</a></li>
<li><a href="#ide.designer">Control Placement</a></li>
<li><a href="#ide.usercontrols">Control Projects</a></li>
<li><a href="#ide.properties">Control Properties</a></li>
<li><a href="#ide.properties">Control Tree</a></li>
<li><a href="#lang.datatypes">Control Type</a></li>
<li><a href="#ide.toolbox">Controls</a></li>
<li><a href="#ctrl.form">Controls (form)</a></li>
<li><a href="#lang.usercontrol">Controls (project section)</a></li>
<li><a href="#ide.project">Controls Section</a></li>
<li><a href="#ide.menu.edit">Copy</a></li>
<li><a href="#lang.func.math">COS</a></li>
<li><a href="#lang.collection">Count</a></li>
<li><a href="#lang.forms">CreateControl</a></li>
<li><a href="#lang.forms">CreateForm</a></li>
<li><a href="#ctrl.menus">CreateMenu</a></li>
<li><a href="#lang.func.conversion">CSNG</a></li>
<li><a href="#lang.screen">CSRLIN</a></li>
<li><a href="#lang.func.conversion">CSTR</a></li>
<li><a href="#lang.runtime">CtlEventList$</a></li>
<li><a href="#lang.runtime">CtlEventParams$</a></li>
<li><a href="#lang.runtime">CtlPropCount</a></li>
<li><a href="#lang.runtime">CtlPropName$</a></li>
<li><a href="#lang.runtime">CtlPropType</a></li>
<li><a href="#lang.runtime">CtlTypeCount</a></li>
<li><a href="#lang.runtime">CtlTypeEventParams$</a></li>
<li><a href="#lang.runtime">CtlTypeFlags</a></li>
<li><a href="#lang.runtime">CtlTypeName$</a></li>
<li><a href="#lang.datatypes">Currency</a></li>
<li><a href="#ctrl.drawing">CurrentX</a></li>
<li><a href="#ctrl.drawing">CurrentY</a></li>
<li><a href="#ctrl.textarea">CursorCol</a></li>
<li><a href="#ctrl.textarea">CursorLine</a></li>
<li><a href="#ide.menu.edit">Cut</a></li>
<li><a href="#lang.variants">CVAR</a></li>
<li><a href="#lang.func.conversion">CVAR</a></li>
<li><a href="#lang.io">DATA</a></li>
<li><a href="#ctrl.data">Data</a></li>
<li><a href="#ctrl.databinding">Data Binding</a></li>
<li><a href="#lang.datatypes">Data Types</a></li>
<li><a href="#ctrl.dbgrid">Data-Bound Grid</a></li>
<li><a href="#ctrl.data">Database</a></li>
<li><a href="#ctrl.data">DatabaseName</a></li>
<li><a href="#ctrl.databinding">DataField</a></li>
<li><a href="#ctrl.textbox">DataField</a></li>
<li><a href="#ctrl.databinding">DataSource</a></li>
<li><a href="#ctrl.textbox">DataSource</a></li>
<li><a href="#lang.datatypes">Date</a></li>
<li><a href="#lang.func.date">DATE</a></li>
<li><a href="#lang.datatypes">Date Literals</a></li>
<li><a href="#lang.func.misc">DATE$</a></li>
<li><a href="#lang.func.date">DATEADD</a></li>
<li><a href="#lang.func.date">DATEDIFF</a></li>
<li><a href="#lang.func.date">DATEPART</a></li>
<li><a href="#lang.func.date">DATESERIAL</a></li>
<li><a href="#lang.func.date">DATEVALUE</a></li>
<li><a href="#lang.func.date">DAY</a></li>
<li><a href="#lang.runtime">DbgEval$</a></li>
<li><a href="#lang.runtime">DbgExec$</a></li>
<li><a href="#lang.runtime">DbgLocals$</a></li>
<li><a href="#ctrl.dbgrid">DBGrid</a></li>
<li><a href="#lang.runtime">DbgSetBreakpoints</a></li>
<li><a href="#lang.runtime">DbgSetVar</a></li>
<li><a href="#lang.runtime">DbgStepOver</a></li>
<li><a href="#ide.menu.run">Debug</a></li>
<li><a href="#ide.menu.tools">Debug Layout</a></li>
<li><a href="#ide.debugger">Debug Mode</a></li>
<li><a href="#lang.runtime">debug.bas</a></li>
<li><a href="#ide.debugger">Debugger</a></li>
<li><a href="#lang.runtime">Debugging programs</a></li>
<li><a href="#ctrl.spinbutton">Decimals</a></li>
<li><a href="#lang.declarations">DECLARE</a></li>
<li><a href="#lang.declarations">DECLARE LIBRARY</a></li>
<li><a href="#lang.runtime">DECLARE LIBRARY</a></li>
<li><a href="#lang.procedures">DEF FN</a></li>
<li><a href="#ctrl.button">Default</a></li>
<li><a href="#lang.classes">Default Member</a></li>
<li><a href="#ctrl.common.props">Default Properties</a></li>
<li><a href="#ctrl.common.props">Default Property</a></li>
<li><a href="#lang.declarations">DEFBYTE</a></li>
<li><a href="#lang.declarations">DEFCUR</a></li>
<li><a href="#lang.declarations">DEFDBL</a></li>
<li><a href="#lang.declarations">DEFINT</a></li>
<li><a href="#lang.declarations">DEFLNG</a></li>
<li><a href="#lang.declarations">DEFSNG</a></li>
<li><a href="#lang.declarations">DEFSTR</a></li>
<li><a href="#ide.menu.edit">Delete</a></li>
<li><a href="#ide.designer">Design Surface</a></li>
<li><a href="#ctrl.form">Design surface</a></li>
<li><a href="#ide.menu.view">Design View</a></li>
<li><a href="#lang.runtime">designer.bas</a></li>
<li><a href="#ctrl.form">DesignKey</a></li>
<li><a href="#ctrl.form">DesignMode</a></li>
<li><a href="#ctrl.form">DesignMouse</a></li>
<li><a href="#ctrl.form">DesignPropertyChanged</a></li>
<li><a href="#ctrl.form">DesignSelection</a></li>
<li><a href="#ctrl.menus">DestroyMenu</a></li>
<li><a href="#ide.overview">Development Environment</a></li>
<li><a href="#lang.declarations">DIM</a></li>
<li><a href="#lang.runtime">DLG_FONT_FIXED</a></li>
<li><a href="#lang.runtime">DlgButtons</a></li>
<li><a href="#lang.runtime">DlgColor</a></li>
<li><a href="#lang.runtime">DlgFileOpenIn$</a></li>
<li><a href="#lang.runtime">DlgFileSaveIn$</a></li>
<li><a href="#lang.runtime">DlgFolder$</a></li>
<li><a href="#lang.runtime">DlgFont</a></li>
<li><a href="#lang.runtime">DlgFontName$</a></li>
<li><a href="#lang.runtime">DlgFontSize</a></li>
<li><a href="#lang.runtime">DlgFontStyle</a></li>
<li><a href="#lang.runtime">DlgInputCancelled</a></li>
<li><a href="#lang.runtime">DlgIntInput</a></li>
<li><a href="#lang.runtime">DlgIntInputStep</a></li>
<li><a href="#lang.loops">DO</a></li>
<li><a href="#lang.forms">DoEvents</a></li>
<li><a href="#lang.forms">DOEVENTS</a></li>
<li><a href="#lang.datatypes">Double</a></li>
<li><a href="#ide.package">DPK files</a></li>
<li><a href="#ctrl.common.props">Drag</a></li>
<li><a href="#ctrl.common.props">Drag and Drop</a></li>
<li><a href="#ctrl.common.props">DragDrop</a></li>
<li><a href="#ctrl.common.props">DragIcon</a></li>
<li><a href="#ctrl.common.props">DragMode</a></li>
<li><a href="#ctrl.common.props">DragOver</a></li>
<li><a href="#lang.screen">DRAW</a></li>
<li><a href="#ctrl.drawing">DrawArrow</a></li>
<li><a href="#ctrl.drawing">DrawBevel</a></li>
<li><a href="#ctrl.drawing">DrawButtonFace</a></li>
<li><a href="#ctrl.drawing">DrawFocusRect</a></li>
<li><a href="#ctrl.picturebox">Drawing</a></li>
<li><a href="#ctrl.drawing">Drawing Methods</a></li>
<li><a href="#ctrl.drawing">DrawScrollArrow</a></li>
<li><a href="#ctrl.drawing">DrawScrollBar</a></li>
<li><a href="#ctrl.drawing">DrawStyle</a></li>
<li><a href="#ctrl.drawing">DrawWidth</a></li>
<li><a href="#ctrl.dropdown">DropDown</a></li>
<li><a href="#ide.overview">DVX BASIC</a></li>
<li><a href="#ctrl.drawing">dvxArrowUp</a></li>
<li><a href="#ctrl.form">dvxFullScreenActive</a></li>
<li><a href="#lang.loops">EACH</a></li>
<li><a href="#ide.menu.edit">Edit Menu</a></li>
<li><a href="#lang.conditionals">ELSE</a></li>
<li><a href="#lang.conditionals">ELSEIF</a></li>
<li><a href="#lang.variants">Empty</a></li>
<li><a href="#lang.runtime">Encryption</a></li>
<li><a href="#lang.misc">END</a></li>
<li><a href="#lang.declarations">END ENUM</a></li>
<li><a href="#lang.procedures">END FUNCTION</a></li>
<li><a href="#lang.conditionals">END IF</a></li>
<li><a href="#lang.conditionals">END SELECT</a></li>
<li><a href="#lang.procedures">END SUB</a></li>
<li><a href="#lang.declarations">END TYPE</a></li>
<li><a href="#lang.classes">END WITH</a></li>
<li><a href="#lang.printerobj">EndDoc</a></li>
<li><a href="#lang.declarations">ENUM</a></li>
<li><a href="#lang.func.misc">ENVIRON$</a></li>
<li><a href="#lang.func.fileio">EOF</a></li>
<li><a href="#lang.operators">EQV</a></li>
<li><a href="#lang.declarations">ERASE</a></li>
<li><a href="#lang.misc">ERL</a></li>
<li><a href="#lang.misc">ERR</a></li>
<li><a href="#lang.misc">Err</a></li>
<li><a href="#lang.misc">Err.Clear</a></li>
<li><a href="#lang.misc">Err.Description</a></li>
<li><a href="#lang.misc">Err.Number</a></li>
<li><a href="#lang.misc">Err.Raise</a></li>
<li><a href="#lang.misc">Err.Source</a></li>
<li><a href="#lang.misc">ERROR</a></li>
<li><a href="#lang.runtime">Error 453</a></li>
<li><a href="#lang.misc">ERROR$</a></li>
<li><a href="#lang.events">Event</a></li>
<li><a href="#lang.events">EVENT</a></li>
<li><a href="#lang.forms">Event Handlers</a></li>
<li><a href="#ctrl.common.props">Events</a></li>
<li><a href="#ide.menu.file">Exit</a></li>
<li><a href="#lang.flow">EXIT</a></li>
<li><a href="#lang.loops">EXIT DO</a></li>
<li><a href="#lang.loops">EXIT FOR</a></li>
<li><a href="#lang.procedures">EXIT FUNCTION</a></li>
<li><a href="#lang.classes">EXIT PROPERTY</a></li>
<li><a href="#lang.procedures">EXIT SUB</a></li>
<li><a href="#lang.func.math">EXP</a></li>
<li><a href="#ide.immediate">Expression Evaluation</a></li>
<li><a href="#lang.constants">False</a></li>
<li><a href="#lang.filesystem">File Attributes</a></li>
<li><a href="#ide.menu.file">File Menu</a></li>
<li><a href="#lang.runtime">File Transfers</a></li>
<li><a href="#lang.func.fileio">FILEATTR</a></li>
<li><a href="#lang.filesystem">FILECOPY</a></li>
<li><a href="#lang.runtime">FILEOPS_ATTR_EDITABLE</a></li>
<li><a href="#lang.runtime">FileOpsBootDrive$</a></li>
<li><a href="#lang.runtime">FileOpsDriveType</a></li>
<li><a href="#lang.runtime">FileOpsFilterMatch</a></li>
<li><a href="#lang.runtime">FileOpsIsWritable</a></li>
<li><a href="#lang.runtime">FileOpsJobBytesDone</a></li>
<li><a href="#lang.runtime">FileOpsJobClearAttr</a></li>
<li><a href="#lang.runtime">FileOpsKindBrowseDir$</a></li>
<li><a href="#lang.runtime">FileOpsKindDir$</a></li>
<li><a href="#lang.runtime">FileOpsKindFind$</a></li>
<li><a href="#lang.runtime">FileOpsKindList</a></li>
<li><a href="#lang.runtime">FileOpsKindName$</a></li>
<li><a href="#lang.runtime">FileOpsLongNames</a></li>
<li><a href="#lang.runtime">FileOpsMakePath</a></li>
<li><a href="#lang.runtime">FileOpsPathIsAbsolute</a></li>
<li><a href="#lang.runtime">FileOpsPathIsInside</a></li>
<li><a href="#lang.runtime">FileOpsPathNative$</a></li>
<li><a href="#lang.runtime">FileOpsPathSep$</a></li>
<li><a href="#lang.runtime">FileOpsReadOnlySystem</a></li>
<li><a href="#lang.runtime">FileOpsReplaceFile</a></li>
<li><a href="#lang.runtime">FileOpsSetModified</a></li>
<li><a href="#lang.runtime">FileOpsShortPath$</a></li>
<li><a href="#lang.runtime">FileOpsTempDir$</a></li>
<li><a href="#lang.runtime">FileOpsTotalBytes</a></li>
<li><a href="#lang.runtime">FileOpsUserDir$</a></li>
<li><a href="#lang.runtime">FileOpsUserInTemp</a></li>
<li><a href="#lang.runtime">FileOpsUserPath$</a></li>
<li><a href="#lang.runtime">FileOpsValidLongName</a></li>
<li><a href="#lang.runtime">FileOpsValidName</a></li>
<li><a href="#lang.runtime">FileOpsValidShortName</a></li>
<li><a href="#ctrl.drawing">FillColor</a></li>
<li><a href="#ctrl.drawing">FillStyle</a></li>
<li><a href="#lang.func.string">FILTER</a></li>
<li><a href="#ide.menu.edit">Find</a></li>
<li><a href="#ide.findreplace">Find</a></li>
<li><a href="#ide.menu.edit">Find Next</a></li>
<li><a href="#ide.findreplace">Find Next</a></li>
<li><a href="#ctrl.textarea">FindNext</a></li>
<li><a href="#ctrl.form">FitHeight</a></li>
<li><a href="#ctrl.form">FitWidth</a></li>
<li><a href="#lang.func.math">FIX</a></li>
<li><a href="#ctrl.wrapbox">Flow Layout</a></li>
<li><a href="#lang.runtime">FM synthesizer</a></li>
<li><a href="#lang.runtime">FmAlloc</a></li>
<li><a href="#lang.runtime">FmRawAcquire</a></li>
<li><a href="#lang.runtime">FmWrite</a></li>
<li><a href="#ctrl.drawing">Focus rectangle</a></li>
<li><a href="#ctrl.form">Font (form)</a></li>
<li><a href="#lang.runtime">Font Dialog</a></li>
<li><a href="#lang.runtime">Font properties</a></li>
<li><a href="#ide.properties">Font row</a></li>
<li><a href="#lang.runtime">font.bas</a></li>
<li><a href="#ctrl.common.props">FontBold</a></li>
<li><a href="#lang.runtime">FontFamilyCount</a></li>
<li><a href="#lang.runtime">FontFamilyName$</a></li>
<li><a href="#ctrl.common.props">FontItalic</a></li>
<li><a href="#ctrl.common.props">FontName</a></li>
<li><a href="#ctrl.form">FontName (form)</a></li>
<li><a href="#lang.runtime">Fonts</a></li>
<li><a href="#ctrl.common.props">Fonts (controls)</a></li>
<li><a href="#ide.project">Fonts Section</a></li>
<li><a href="#ctrl.drawing">FontScale</a></li>
<li><a href="#ctrl.common.props">FontSize</a></li>
<li><a href="#ctrl.common.props">FontStrikethru</a></li>
<li><a href="#lang.runtime">FontTextWidth</a></li>
<li><a href="#ctrl.common.props">FontUnderline</a></li>
<li><a href="#lang.loops">FOR</a></li>
<li><a href="#lang.fileio">FOR APPEND</a></li>
<li><a href="#lang.fileio">FOR BINARY</a></li>
<li><a href="#lang.loops">FOR EACH</a></li>
<li><a href="#lang.fileio">FOR INPUT</a></li>
<li><a href="#lang.fileio">FOR OUTPUT</a></li>
<li><a href="#lang.fileio">FOR RANDOM</a></li>
<li><a href="#ctrl.form">Form</a></li>
<li><a href="#ide.designer">Form Designer</a></li>
<li><a href="#lang.runtime">Form designers</a></li>
<li><a href="#ctrl.frm">Form File</a></li>
<li><a href="#lang.datatypes">Form Type</a></li>
<li><a href="#lang.func.string">FORMAT$</a></li>
<li><a href="#ctrl.frame">Frame</a></li>
<li><a href="#lang.sound">Frame rate</a></li>
<li><a href="#lang.runtime">FrameMissed</a></li>
<li><a href="#lang.sound">FRAMEWAIT</a></li>
<li><a href="#lang.func.fileio">FREEFILE</a></li>
<li><a href="#lang.classes">FRIEND</a></li>
<li><a href="#lang.classes">Friend</a></li>
<li><a href="#ctrl.frm">FRM</a></li>
<li><a href="#lang.screen">Full screen</a></li>
<li><a href="#lang.screen">FULLSCREEN</a></li>
<li><a href="#ctrl.form">FullScreen (form)</a></li>
<li><a href="#lang.procedures">FUNCTION</a></li>
<li><a href="#ide.editor">Function Dropdown</a></li>
<li><a href="#lang.runtime">game.bas</a></li>
<li><a href="#ctrl.form">GameInput</a></li>
<li><a href="#lang.runtime">GameKeyClear</a></li>
<li><a href="#lang.runtime">GameKeyDown</a></li>
<li><a href="#lang.runtime">GameWaitRetrace</a></li>
<li><a href="#lang.fileio">GET</a></li>
<li><a href="#lang.filesystem">GETATTR</a></li>
<li><a href="#lang.func.math">GETBLUE</a></li>
<li><a href="#lang.func.math">GETGREEN</a></li>
<li><a href="#ctrl.treeview">GetItemTag</a></li>
<li><a href="#ctrl.textarea">GetLine</a></li>
<li><a href="#lang.func.math">GETRED</a></li>
<li><a href="#ctrl.optionbutton">GetSelected</a></li>
<li><a href="#lang.flow">GOSUB</a></li>
<li><a href="#lang.flow">GOTO</a></li>
<li><a href="#ctrl.textarea">GoToLine</a></li>
<li><a href="#ide.designer">Grab Handles</a></li>
<li><a href="#ide.designer">Grid Snapping</a></li>
<li><a href="#ctrl.textarea">GutterClick</a></li>
<li><a href="#ctrl.treeview">HasChildren</a></li>
<li><a href="#ctrl.hbox">HBox</a></li>
<li><a href="#ide.usercontrols">Header Properties</a></li>
<li><a href="#lang.runtime">Help Files</a></li>
<li><a href="#ide.menu.help">Help Menu</a></li>
<li><a href="#ctrl.helppane">Help topic display</a></li>
<li><a href="#lang.runtime">Help viewer in BASIC</a></li>
<li><a href="#lang.runtime">help.bas</a></li>
<li><a href="#lang.runtime">HelpCompileMessages$</a></li>
<li><a href="#ctrl.helppane">HelpPane</a></li>
<li><a href="#lang.runtime">HelpPane (help files)</a></li>
<li><a href="#lang.runtime">HelpViewTopic</a></li>
<li><a href="#lang.func.string">HEX$</a></li>
<li><a href="#lang.forms">Hide</a></li>
<li><a href="#ctrl.form">Hide</a></li>
<li><a href="#lang.runtime">hlpfile.bas</a></li>
<li><a href="#lang.runtime">HlpLoadTopic</a></li>
<li><a href="#lang.runtime">HlpOpen</a></li>
<li><a href="#lang.runtime">HlpSearch</a></li>
<li><a href="#ctrl.hbox">Horizontal Layout</a></li>
<li><a href="#lang.runtime">HostLookup$</a></li>
<li><a href="#lang.runtime">HostLookupStart</a></li>
<li><a href="#lang.runtime">HostName$</a></li>
<li><a href="#ide.shortcuts">Hotkeys</a></li>
<li><a href="#lang.func.date">HOUR</a></li>
<li><a href="#ctrl.hscrollbar">HScrollBar</a></li>
<li><a href="#lang.runtime">http.bas</a></li>
<li><a href="#lang.runtime">HttpOpen</a></li>
<li><a href="#lang.runtime">HttpRunFor</a></li>
<li><a href="#lang.runtime">HttpSetBodyFile</a></li>
<li><a href="#ctrl.form">Icon (form)</a></li>
<li><a href="#lang.runtime">Icon views you draw yourself</a></li>
<li><a href="#ide.overview">IDE</a></li>
<li><a href="#lang.conditionals">IF</a></li>
<li><a href="#lang.func.misc">IIF</a></li>
<li><a href="#ctrl.image">Image</a></li>
<li><a href="#ctrl.imagebutton">ImageButton</a></li>
<li><a href="#ide.immediate">Immediate Window</a></li>
<li><a href="#lang.operators">IMP</a></li>
<li><a href="#lang.interfaces">Implements</a></li>
<li><a href="#lang.interfaces">IMPLEMENTS</a></li>
<li><a href="#lang.runtime">Include Libraries</a></li>
<li><a href="#ctrl.arrays">Index Property</a></li>
<li><a href="#lang.ini">INI</a></li>
<li><a href="#lang.ini">IniRead</a></li>
<li><a href="#lang.ini">IniWrite</a></li>
<li><a href="#lang.screen">INKEY$</a></li>
<li><a href="#lang.io">INPUT</a></li>
<li><a href="#lang.fileio">INPUT #</a></li>
<li><a href="#lang.func.fileio">INPUT$</a></li>
<li><a href="#lang.forms">InputBox$</a></li>
<li><a href="#lang.forms">INPUTBOX$</a></li>
<li><a href="#lang.func.string">INSTR</a></li>
<li><a href="#lang.func.string">INSTRREV</a></li>
<li><a href="#lang.func.math">INT</a></li>
<li><a href="#lang.datatypes">Integer</a></li>
<li><a href="#lang.interfaces">Interface</a></li>
<li><a href="#ctrl.timer">Interval</a></li>
<li><a href="#lang.variants">Invalid use of Null</a></li>
<li><a href="#lang.operators">IS</a></li>
<li><a href="#lang.variants">ISARRAY</a></li>
<li><a href="#lang.func.date">ISDATE</a></li>
<li><a href="#lang.variants">ISEMPTY</a></li>
<li><a href="#lang.variants">ISNULL</a></li>
<li><a href="#lang.variants">ISNUMERIC</a></li>
<li><a href="#lang.variants">ISOBJECT</a></li>
<li><a href="#lang.collection">Item</a></li>
<li><a href="#ctrl.treeview">ItemDepth</a></li>
<li><a href="#ctrl.treeview">ItemParent</a></li>
<li><a href="#lang.func.string">JOIN$</a></li>
<li><a href="#lang.runtime">JoyAxis</a></li>
<li><a href="#lang.runtime">JoyButton</a></li>
<li><a href="#lang.runtime">JoyCalibration</a></li>
<li><a href="#lang.runtime">JoyCount</a></li>
<li><a href="#lang.runtime">JoyHat</a></li>
<li><a href="#lang.runtime">JoyIsKeyboard</a></li>
<li><a href="#lang.runtime">JoyKeyCode</a></li>
<li><a href="#lang.runtime">JoyKeyIndex</a></li>
<li><a href="#lang.runtime">JoyKeyNameOf$</a></li>
<li><a href="#lang.runtime">Joystick</a></li>
<li><a href="#lang.runtime">joystick.bas</a></li>
<li><a href="#lang.runtime">JoyX</a></li>
<li><a href="#lang.runtime">JoyY</a></li>
<li><a href="#lang.runtime">JSON</a></li>
<li><a href="#lang.runtime">json.bas</a></li>
<li><a href="#lang.runtime">JsonParse</a></li>
<li><a href="#lang.clipboard">Key Codes</a></li>
<li><a href="#ide.shortcuts">Keyboard Shortcuts</a></li>
<li><a href="#lang.filesystem">KILL</a></li>
<li><a href="#lang.printerobj">KillDoc</a></li>
<li><a href="#ctrl.label">Label</a></li>
<li><a href="#lang.flow">Labels</a></li>
<li><a href="#lang.classes">Late Binding</a></li>
<li><a href="#lang.runtime">layout.bas</a></li>
<li><a href="#lang.func.fileio">LBOUND</a></li>
<li><a href="#lang.func.string">LCASE$</a></li>
<li><a href="#lang.func.string">LEFT$</a></li>
<li><a href="#lang.func.string">LEN</a></li>
<li><a href="#lang.declarations">LET</a></li>
<li><a href="#lang.runtime">Library not installed</a></li>
<li><a href="#lang.screen">Light pen</a></li>
<li><a href="#lang.operators">LIKE</a></li>
<li><a href="#ctrl.line">Line</a></li>
<li><a href="#lang.screen">LINE (graphics)</a></li>
<li><a href="#lang.screen">LINE INPUT</a></li>
<li><a href="#lang.fileio">LINE INPUT</a></li>
<li><a href="#ctrl.drawing">Line method</a></li>
<li><a href="#ide.editor">Line Numbers</a></li>
<li><a href="#lang.flow">Line Numbers</a></li>
<li><a href="#ctrl.textarea">LineCount</a></li>
<li><a href="#ctrl.textarea">LineNumbers</a></li>
<li><a href="#ctrl.helppane">LinkClick</a></li>
<li><a href="#ctrl.helppane">LinkTopic</a></li>
<li><a href="#ctrl.listbox">ListBox</a></li>
<li><a href="#ctrl.listbox">ListCount</a></li>
<li><a href="#lang.runtime">listhelp.bas</a></li>
<li><a href="#lang.runtime">ListIconLabel$</a></li>
<li><a href="#lang.runtime">ListIconMetric</a></li>
<li><a href="#ctrl.listbox">ListIndex</a></li>
<li><a href="#lang.runtime">Lists you draw yourself</a></li>
<li><a href="#lang.runtime">ListSelCreate</a></li>
<li><a href="#lang.runtime">ListSelNavigate</a></li>
<li><a href="#lang.runtime">ListTypeAhead</a></li>
<li><a href="#ctrl.listview">ListView</a></li>
<li><a href="#lang.forms">LOAD</a></li>
<li><a href="#ctrl.form">Load</a></li>
<li><a href="#ctrl.richedit">LoadFile</a></li>
<li><a href="#lang.forms">LoadFormText</a></li>
<li><a href="#lang.forms">LOADFORMTEXT</a></li>
<li><a href="#lang.func.misc">LOADPICTURE</a></li>
<li><a href="#lang.func.misc">LOADPICTUREDATA</a></li>
<li><a href="#lang.func.fileio">LOC</a></li>
<li><a href="#ide.debug.locals">Locals Window</a></li>
<li><a href="#lang.screen">LOCATE</a></li>
<li><a href="#lang.func.fileio">LOF</a></li>
<li><a href="#lang.func.math">LOG</a></li>
<li><a href="#lang.datatypes">Long</a></li>
<li><a href="#lang.runtime">Long File Names</a></li>
<li><a href="#lang.loops">LOOP</a></li>
<li><a href="#lang.io">LPRINT</a></li>
<li><a href="#lang.io">LPRINT USING</a></li>
<li><a href="#lang.declarations">LSET</a></li>
<li><a href="#lang.func.string">LTRIM$</a></li>
<li><a href="#ide.menu.file">Make Control</a></li>
<li><a href="#ide.usercontrols">Make Control</a></li>
<li><a href="#ide.package">Make Package</a></li>
<li><a href="#ctrl.textbox">Mask</a></li>
<li><a href="#ctrl.image">MaskColor</a></li>
<li><a href="#ctrl.textbox">Masked input</a></li>
<li><a href="#ctrl.databinding">Master-Detail</a></li>
<li><a href="#ctrl.hscrollbar">Max</a></li>
<li><a href="#ctrl.form">MaxHeight (form)</a></li>
<li><a href="#ctrl.form">MaxWidth (form)</a></li>
<li><a href="#lang.sound">MB</a></li>
<li><a href="#lang.forms">Me</a></li>
<li><a href="#lang.classes">Me in Classes</a></li>
<li><a href="#ctrl.menus">Menu</a></li>
<li><a href="#ctrl.menus">Menu Bar</a></li>
<li><a href="#ide.menu.view">Menu Editor</a></li>
<li><a href="#ctrl.common.props">Methods</a></li>
<li><a href="#lang.sound">MF</a></li>
<li><a href="#lang.func.string">MID$</a></li>
<li><a href="#lang.runtime">MIDI</a></li>
<li><a href="#lang.runtime">MIDI keyboard</a></li>
<li><a href="#lang.runtime">MidiAcquire</a></li>
<li><a href="#lang.runtime">MidiInClock</a></li>
<li><a href="#lang.runtime">MidiInMessage</a></li>
<li><a href="#lang.runtime">MidiInOpen</a></li>
<li><a href="#lang.runtime">MidiInTime</a></li>
<li><a href="#lang.runtime">MidiPortInfo$</a></li>
<li><a href="#lang.runtime">MidiPut</a></li>
<li><a href="#lang.runtime">MidiRecordNew</a></li>
<li><a href="#lang.runtime">MidiRecordSave</a></li>
<li><a href="#ide.changes">Migration</a></li>
<li><a href="#ctrl.hscrollbar">Min</a></li>
<li><a href="#lang.func.date">MINUTE</a></li>
<li><a href="#lang.variants">Missing</a></li>
<li><a href="#lang.filesystem">MKDIR</a></li>
<li><a href="#lang.operators">MOD</a></li>
<li><a href="#lang.runtime">Modem</a></li>
<li><a href="#lang.func.date">MONTH</a></li>
<li><a href="#lang.func.date">MONTHNAME</a></li>
<li><a href="#lang.constants">Mouse Constants</a></li>
<li><a href="#lang.runtime">MOUSE_DBLCLICK_DEFAULT_MS</a></li>
<li><a href="#lang.runtime">MOUSE_WHEEL_STEP_MAX</a></li>
<li><a href="#lang.screenobj">MousePointer</a></li>
<li><a href="#ctrl.common.props">MousePointer</a></li>
<li><a href="#ctrl.form">MousePointer (form)</a></li>
<li><a href="#ctrl.common.props">MoveBefore</a></li>
<li><a href="#ctrl.data">MoveFirst</a></li>
<li><a href="#ctrl.data">MoveNext</a></li>
<li><a href="#lang.forms">MsgBox</a></li>
<li><a href="#lang.forms">MSGBOX</a></li>
<li><a href="#ctrl.listview">Multi-Column List</a></li>
<li><a href="#lang.runtime">Music</a></li>
<li><a href="#lang.sound">Music macro language</a></li>
<li><a href="#lang.runtime">music.bas</a></li>
<li><a href="#lang.runtime">MusicControl</a></li>
<li><a href="#lang.runtime">MusicError$</a></li>
<li><a href="#lang.runtime">MusicFree</a></li>
<li><a href="#lang.runtime">MusicGetVolume</a></li>
<li><a href="#lang.runtime">MusicInfo$</a></li>
<li><a href="#lang.runtime">MusicLength</a></li>
<li><a href="#lang.runtime">MusicLoad</a></li>
<li><a href="#lang.runtime">MusicLoadMacro</a></li>
<li><a href="#lang.runtime">MusicMidiOpen</a></li>
<li><a href="#lang.runtime">MusicMidiSend</a></li>
<li><a href="#lang.runtime">MusicNoteOff</a></li>
<li><a href="#lang.runtime">MusicNoteOn</a></li>
<li><a href="#lang.runtime">MusicPatchSet$</a></li>
<li><a href="#lang.runtime">MusicPause</a></li>
<li><a href="#lang.runtime">MusicPitchBend</a></li>
<li><a href="#lang.runtime">MusicPlay</a></li>
<li><a href="#lang.runtime">MusicPlaying</a></li>
<li><a href="#lang.runtime">MusicPosition</a></li>
<li><a href="#lang.runtime">MusicProgram</a></li>
<li><a href="#lang.runtime">MusicResume</a></li>
<li><a href="#lang.runtime">MusicRomBank$</a></li>
<li><a href="#lang.runtime">MusicSeek</a></li>
<li><a href="#lang.runtime">MusicSetBank</a></li>
<li><a href="#lang.runtime">MusicStop</a></li>
<li><a href="#lang.runtime">MusicVolume</a></li>
<li><a href="#lang.filesystem">NAME</a></li>
<li><a href="#lang.declarations">Name Resolution</a></li>
<li><a href="#lang.procedures">Named Arguments</a></li>
<li><a href="#lang.declarations">Names</a></li>
<li><a href="#lang.runtime">net.bas</a></li>
<li><a href="#lang.runtime">NetState</a></li>
<li><a href="#lang.declarations">NEW</a></li>
<li><a href="#ctrl.form">New (forms)</a></li>
<li><a href="#ide.menu.file">New Class Module</a></li>
<li><a href="#ide.menu.file">New Project</a></li>
<li><a href="#ide.menu.file">New UserControl</a></li>
<li><a href="#ide.usercontrols">New UserControl</a></li>
<li><a href="#ctrl.form">NewArgs</a></li>
<li><a href="#lang.printerobj">NewPage</a></li>
<li><a href="#lang.loops">NEXT</a></li>
<li><a href="#lang.operators">NOT</a></li>
<li><a href="#lang.declarations">Nothing</a></li>
<li><a href="#lang.forms">Nothing</a></li>
<li><a href="#lang.func.date">NOW</a></li>
<li><a href="#lang.variants">Null</a></li>
<li><a href="#lang.runtime">Number input dialog</a></li>
<li><a href="#ide.editor">Object Dropdown</a></li>
<li><a href="#lang.datatypes">Object Type</a></li>
<li><a href="#lang.classes">Objects</a></li>
<li><a href="#lang.func.string">OCT$</a></li>
<li><a href="#lang.misc">ON ERROR</a></li>
<li><a href="#lang.misc">ON ERROR RESUME NEXT</a></li>
<li><a href="#lang.flow">ON GOSUB</a></li>
<li><a href="#lang.flow">ON GOTO</a></li>
<li><a href="#lang.fileio">OPEN</a></li>
<li><a href="#ide.menu.file">Open Project</a></li>
<li><a href="#lang.operators">Operators</a></li>
<li><a href="#lang.declarations">OPTION</a></li>
<li><a href="#lang.declarations">OPTION BASE</a></li>
<li><a href="#lang.declarations">OPTION COMPARE</a></li>
<li><a href="#ide.preferences">Option Explicit</a></li>
<li><a href="#lang.declarations">OPTION EXPLICIT</a></li>
<li><a href="#lang.procedures">OPTIONAL</a></li>
<li><a href="#ctrl.optionbutton">OptionButton</a></li>
<li><a href="#ctrl.optionbutton">OptionIndex</a></li>
<li><a href="#lang.operators">OR</a></li>
<li><a href="#ide.output">Output Window</a></li>
<li><a href="#ide.package">Package name</a></li>
<li><a href="#ide.package">Packages</a></li>
<li><a href="#ctrl.form">Padding</a></li>
<li><a href="#ctrl.hbox">Padding</a></li>
<li><a href="#ctrl.statusbar">Padding</a></li>
<li><a href="#ctrl.toolbar">Padding</a></li>
<li><a href="#ctrl.wrapbox">Padding</a></li>
<li><a href="#lang.screen">PAINT</a></li>
<li><a href="#ctrl.drawing">Paint event</a></li>
<li><a href="#ctrl.drawing">PaintPicture</a></li>
<li><a href="#lang.screen">PALETTE</a></li>
<li><a href="#lang.screen">PALETTE USING</a></li>
<li><a href="#lang.procedures">PARAMARRAY</a></li>
<li><a href="#ctrl.common.props">Parent</a></li>
<li><a href="#ide.menu.edit">Paste</a></li>
<li><a href="#lang.runtime">Path Separators</a></li>
<li><a href="#lang.screen">PCOPY</a></li>
<li><a href="#lang.screen">PEN</a></li>
<li><a href="#lang.screen">PEN ON</a></li>
<li><a href="#ctrl.image">Picture</a></li>
<li><a href="#ctrl.picturebox">PictureBox</a></li>
<li><a href="#lang.runtime">pkg.bas</a></li>
<li><a href="#lang.runtime">PkgBuildStart</a></li>
<li><a href="#lang.runtime">PkgCheckData</a></li>
<li><a href="#lang.runtime">PkgFileOwner$</a></li>
<li><a href="#lang.runtime">PkgInstallStart</a></li>
<li><a href="#lang.runtime">PkgKeygen</a></li>
<li><a href="#lang.runtime">PkgKeysRows$</a></li>
<li><a href="#lang.runtime">pkgnet.bas</a></li>
<li><a href="#lang.runtime">PkgNetOpenIn</a></li>
<li><a href="#lang.runtime">PkgOpen</a></li>
<li><a href="#lang.runtime">PkgOpenIn</a></li>
<li><a href="#lang.runtime">PkgPlan</a></li>
<li><a href="#lang.runtime">PkgRemoveStart</a></li>
<li><a href="#lang.runtime">PkgRunFor</a></li>
<li><a href="#lang.runtime">PkgSignData$</a></li>
<li><a href="#lang.runtime">PkgSignStart</a></li>
<li><a href="#lang.runtime">PkgUntrustKey</a></li>
<li><a href="#lang.runtime">PkgVerifyStart</a></li>
<li><a href="#lang.runtime">PkgVersionCompare</a></li>
<li><a href="#lang.runtime">PkgZipCreateStart</a></li>
<li><a href="#lang.runtime">PkgZipExtractStart</a></li>
<li><a href="#lang.runtime">PkgZipListStart</a></li>
<li><a href="#lang.runtime">PkgZipRows$</a></li>
<li><a href="#lang.sound">PLAY</a></li>
<li><a href="#lang.sound">PLAY function</a></li>
<li><a href="#lang.runtime">PlayNoise</a></li>
<li><a href="#lang.runtime">PlayTone</a></li>
<li><a href="#lang.runtime">PlayTriangle</a></li>
<li><a href="#lang.runtime">PlayWave</a></li>
<li><a href="#lang.runtime">PlayWaveLoop</a></li>
<li><a href="#lang.screen">PMAP</a></li>
<li><a href="#lang.screen">POINT</a></li>
<li><a href="#ctrl.drawing">Point method</a></li>
<li><a href="#ctrl.menus">PopupMenu</a></li>
<li><a href="#lang.screen">POS</a></li>
<li><a href="#lang.operators">Precedence</a></li>
<li><a href="#lang.constants">Predefined Constants</a></li>
<li><a href="#ide.menu.tools">Preferences</a></li>
<li><a href="#ide.preferences">Preferences</a></li>
<li><a href="#lang.runtime">prefs.bas</a></li>
<li><a href="#lang.runtime">PrefsChoiceDefault</a></li>
<li><a href="#lang.runtime">PrefsChoiceLabel$</a></li>
<li><a href="#lang.runtime">PrefsCreate</a></li>
<li><a href="#lang.runtime">PrefsDvxIni$</a></li>
<li><a href="#lang.runtime">PrefsGetChoice</a></li>
<li><a href="#lang.runtime">PrefsGetChoiceFrom</a></li>
<li><a href="#lang.runtime">PrefsGetSecret$</a></li>
<li><a href="#lang.runtime">PrefsKeyName$</a></li>
<li><a href="#lang.runtime">PrefsLoad</a></li>
<li><a href="#lang.runtime">PrefsSaveAs</a></li>
<li><a href="#lang.runtime">PrefsSetSecret</a></li>
<li><a href="#lang.runtime">PrefsVideoWidth</a></li>
<li><a href="#lang.screen">PRESET</a></li>
<li><a href="#lang.io">PRINT</a></li>
<li><a href="#lang.fileio">PRINT #</a></li>
<li><a href="#ctrl.drawing">Print method</a></li>
<li><a href="#ide.output">PRINT Output</a></li>
<li><a href="#lang.io">PRINT USING</a></li>
<li><a href="#lang.runtime">print.bas</a></li>
<li><a href="#ctrl.drawing">PrintAccel</a></li>
<li><a href="#lang.runtime">PrintChoose</a></li>
<li><a href="#lang.printerobj">Printer Object</a></li>
<li><a href="#lang.printerobj">Printer.Circle</a></li>
<li><a href="#lang.printerobj">Printer.Copies</a></li>
<li><a href="#lang.printerobj">Printer.EndDoc</a></li>
<li><a href="#lang.printerobj">Printer.FontSize</a></li>
<li><a href="#lang.printerobj">Printer.KillDoc</a></li>
<li><a href="#lang.printerobj">Printer.Line</a></li>
<li><a href="#lang.printerobj">Printer.NewPage</a></li>
<li><a href="#lang.printerobj">Printer.Page</a></li>
<li><a href="#lang.printerobj">Printer.PaintPicture</a></li>
<li><a href="#lang.printerobj">Printer.Print</a></li>
<li><a href="#lang.printerobj">Printer.PSet</a></li>
<li><a href="#lang.runtime">PrintForm</a></li>
<li><a href="#lang.runtime">PrintPageSetting</a></li>
<li><a href="#lang.runtime">PrintPageSetup</a></li>
<li><a href="#lang.runtime">PrintPictureDialog</a></li>
<li><a href="#lang.runtime">PrintPortStatus</a></li>
<li><a href="#lang.runtime">PrintTextDialog</a></li>
<li><a href="#lang.declarations">PRIVATE</a></li>
<li><a href="#lang.runtime">PROGMAN.INI</a></li>
<li><a href="#lang.runtime">Program groups</a></li>
<li><a href="#lang.runtime">Program priority</a></li>
<li><a href="#ide.output">Program Screen Window</a></li>
<li><a href="#ctrl.progressbar">ProgressBar</a></li>
<li><a href="#lang.runtime">ProjCtlHeader$</a></li>
<li><a href="#lang.runtime">ProjCtlKeys$</a></li>
<li><a href="#lang.runtime">ProjCtlNew$</a></li>
<li><a href="#lang.runtime">ProjCtlSetHeader$</a></li>
<li><a href="#ide.project">Project Explorer</a></li>
<li><a href="#ide.project">Project Files</a></li>
<li><a href="#lang.runtime">Project files</a></li>
<li><a href="#ide.project">Project Fonts</a></li>
<li><a href="#ide.menu.file">Project Properties</a></li>
<li><a href="#ide.project">Project System</a></li>
<li><a href="#ide.project">Project Type</a></li>
<li><a href="#lang.runtime">ProjGet$</a></li>
<li><a href="#lang.runtime">ProjNew</a></li>
<li><a href="#lang.runtime">ProjOpen</a></li>
<li><a href="#ctrl.common.props">Properties</a></li>
<li><a href="#ide.properties">Properties Panel</a></li>
<li><a href="#lang.classes">PROPERTY</a></li>
<li><a href="#lang.classes">PROPERTY GET</a></li>
<li><a href="#lang.classes">PROPERTY LET</a></li>
<li><a href="#ide.properties">Property List</a></li>
<li><a href="#lang.classes">PROPERTY SET</a></li>
<li><a href="#lang.screen">PSET</a></li>
<li><a href="#ctrl.drawing">PSet method</a></li>
<li><a href="#lang.declarations">PUBLIC</a></li>
<li><a href="#lang.fileio">PUT</a></li>
<li><a href="#lang.func.math">QBCOLOR</a></li>
<li><a href="#ctrl.optionbutton">Radio Button</a></li>
<li><a href="#lang.events">RaiseEvent</a></li>
<li><a href="#lang.events">RAISEEVENT</a></li>
<li><a href="#lang.misc">RANDOMIZE</a></li>
<li><a href="#lang.misc">RANDOMIZE TIMER</a></li>
<li><a href="#ctrl.drawing">Raster Operations</a></li>
<li><a href="#lang.io">READ</a></li>
<li><a href="#ctrl.spinbutton">RealMode</a></li>
<li><a href="#ctrl.menus">Recent files menu</a></li>
<li><a href="#lang.runtime">Recording</a></li>
<li><a href="#ctrl.data">RecordSource</a></li>
<li><a href="#lang.runtime">RecordStart</a></li>
<li><a href="#lang.runtime">RecordStop</a></li>
<li><a href="#lang.declarations">REDIM</a></li>
<li><a href="#lang.classes">Reference Counting</a></li>
<li><a href="#ide.changes">Release Notes</a></li>
<li><a href="#lang.statements">REM</a></li>
<li><a href="#lang.collection">Remove</a></li>
<li><a href="#ide.menu.file">Remove File</a></li>
<li><a href="#lang.forms">RemoveControl</a></li>
<li><a href="#ctrl.listbox">RemoveItem</a></li>
<li><a href="#ctrl.treeview">RemoveItem</a></li>
<li><a href="#ctrl.menus">RemoveMenuItem</a></li>
<li><a href="#ide.menu.file">Rename File</a></li>
<li><a href="#ctrl.timer">Repeat</a></li>
<li><a href="#ide.immediate">REPL</a></li>
<li><a href="#ide.menu.edit">Replace</a></li>
<li><a href="#ide.findreplace">Replace</a></li>
<li><a href="#lang.func.string">REPLACE$</a></li>
<li><a href="#ctrl.textarea">ReplaceAll</a></li>
<li><a href="#ctrl.textarea">ReplaceSelection</a></li>
<li><a href="#ctrl.data">Reposition</a></li>
<li><a href="#lang.runtime">RES_NAME_ICON</a></li>
<li><a href="#lang.runtime">ResAddData</a></li>
<li><a href="#lang.fileio">RESET</a></li>
<li><a href="#lang.runtime">ResGetData$</a></li>
<li><a href="#ctrl.form">Resizable</a></li>
<li><a href="#lang.runtime">resource.bas</a></li>
<li><a href="#lang.io">RESTORE</a></li>
<li><a href="#lang.misc">RESUME</a></li>
<li><a href="#lang.misc">RESUME NEXT</a></li>
<li><a href="#lang.flow">RETURN</a></li>
<li><a href="#lang.func.math">RGB</a></li>
<li><a href="#lang.runtime">RichEdit</a></li>
<li><a href="#ctrl.richedit">RichEdit</a></li>
<li><a href="#lang.runtime">RichLabel</a></li>
<li><a href="#ctrl.richlabel">RichLabel</a></li>
<li><a href="#lang.runtime">richtext.bas</a></li>
<li><a href="#lang.func.string">RIGHT$</a></li>
<li><a href="#lang.filesystem">RMDIR</a></li>
<li><a href="#lang.func.math">RND</a></li>
<li><a href="#lang.declarations">RSET</a></li>
<li><a href="#ctrl.richedit">RTF</a></li>
<li><a href="#lang.func.string">RTRIM$</a></li>
<li><a href="#ide.menu.run">Run</a></li>
<li><a href="#ide.menu.run">Run Menu</a></li>
<li><a href="#ide.menu.run">Run to Cursor</a></li>
<li><a href="#ide.menu.run">Run Without Recompile</a></li>
<li><a href="#lang.runtime">RunCreate</a></li>
<li><a href="#lang.runtime">Running programs</a></li>
<li><a href="#lang.runtime">RunOutput$</a></li>
<li><a href="#lang.runtime">RunPoll</a></li>
<li><a href="#lang.runtime">RunStart</a></li>
<li><a href="#ide.output">Runtime Errors</a></li>
<li><a href="#ide.menu.file">Save All</a></li>
<li><a href="#ide.menu.file">Save File</a></li>
<li><a href="#ide.menu.run">Save on Run</a></li>
<li><a href="#ide.menu.file">Save Project</a></li>
<li><a href="#ctrl.richedit">SaveFile</a></li>
<li><a href="#ctrl.form">SaveScreenshot</a></li>
<li><a href="#ctrl.drawing">Scale</a></li>
<li><a href="#ctrl.drawing">ScaleHeight</a></li>
<li><a href="#ctrl.drawing">ScaleLeft</a></li>
<li><a href="#ctrl.drawing">ScaleMode</a></li>
<li><a href="#ctrl.drawing">ScaleTop</a></li>
<li><a href="#ctrl.drawing">ScaleWidth</a></li>
<li><a href="#ctrl.drawing">ScaleX</a></li>
<li><a href="#ctrl.drawing">ScaleY</a></li>
<li><a href="#lang.screen">SCREEN</a></li>
<li><a href="#lang.screen">SCREEN function</a></li>
<li><a href="#lang.screenobj">Screen Object</a></li>
<li><a href="#lang.screen">Screen pages</a></li>
<li><a href="#lang.screenobj">Screen.Arrange</a></li>
<li><a href="#lang.screenobj">Screen.BitsPerPixel</a></li>
<li><a href="#lang.screenobj">Screen.DebugLayout</a></li>
<li><a href="#lang.screenobj">Screen.Height</a></li>
<li><a href="#lang.screenobj">Screen.MousePointer</a></li>
<li><a href="#lang.screenobj">Screen.Width</a></li>
<li><a href="#ctrl.scrollpane">Scrollable Container</a></li>
<li><a href="#ctrl.drawing">ScrollBarClick</a></li>
<li><a href="#ctrl.drawing">ScrollBarsNeeded</a></li>
<li><a href="#ctrl.scrollpane">ScrollPane</a></li>
<li><a href="#ctrl.common.props">ScrollToControl</a></li>
<li><a href="#ide.findreplace">Search</a></li>
<li><a href="#lang.runtime">SecAeadLock$</a></li>
<li><a href="#lang.runtime">SecAeadUnlock$</a></li>
<li><a href="#lang.runtime">SecCipherCreate</a></li>
<li><a href="#lang.runtime">SecDhCreate</a></li>
<li><a href="#lang.runtime">SecDhStep</a></li>
<li><a href="#lang.runtime">SecEd25519Check</a></li>
<li><a href="#lang.runtime">SecEd25519Sign$</a></li>
<li><a href="#lang.runtime">SecHmac$</a></li>
<li><a href="#lang.func.date">SECOND</a></li>
<li><a href="#lang.runtime">SecRandom$</a></li>
<li><a href="#lang.runtime">SecSha256$</a></li>
<li><a href="#lang.runtime">security.bas</a></li>
<li><a href="#lang.runtime">SecX25519$</a></li>
<li><a href="#lang.fileio">SEEK</a></li>
<li><a href="#ctrl.richedit">SelAlignment</a></li>
<li><a href="#ctrl.richedit">SelBold</a></li>
<li><a href="#ctrl.richedit">SelColor</a></li>
<li><a href="#ide.menu.edit">Select All</a></li>
<li><a href="#lang.conditionals">SELECT CASE</a></li>
<li><a href="#ctrl.textbox">SelectAll</a></li>
<li><a href="#ctrl.listview">SelectedRows</a></li>
<li><a href="#ctrl.richedit">SelFontName</a></li>
<li><a href="#ctrl.richedit">SelFontSize</a></li>
<li><a href="#ctrl.richedit">SelItalic</a></li>
<li><a href="#ctrl.textarea">SelLength</a></li>
<li><a href="#ctrl.richedit">SelRTF</a></li>
<li><a href="#ctrl.textarea">SelStart</a></li>
<li><a href="#ctrl.richedit">SelStrikethru</a></li>
<li><a href="#ctrl.textbox">SelText</a></li>
<li><a href="#ctrl.textarea">SelText</a></li>
<li><a href="#ctrl.richedit">SelUnderline</a></li>
<li><a href="#ctrl.terminal">Send Event</a></li>
<li><a href="#lang.runtime">SendKeys</a></li>
<li><a href="#ctrl.menus">Separator</a></li>
<li><a href="#ctrl.line">Separator</a></li>
<li><a href="#lang.runtime">SerLastError</a></li>
<li><a href="#lang.runtime">SerSet</a></li>
<li><a href="#lang.declarations">SET</a></li>
<li><a href="#ctrl.tabstrip">SetActive</a></li>
<li><a href="#lang.filesystem">SETATTR</a></li>
<li><a href="#ctrl.richlabel">SetColor</a></li>
<li><a href="#ctrl.listview">SetColumns</a></li>
<li><a href="#ctrl.textarea">SetCursor</a></li>
<li><a href="#lang.forms">SetEvent</a></li>
<li><a href="#ctrl.richlabel">SetFont</a></li>
<li><a href="#ctrl.treeview">SetItemTag</a></li>
<li><a href="#ctrl.treeview">SetItemText</a></li>
<li><a href="#ctrl.textarea">SetLineMarker</a></li>
<li><a href="#ctrl.picturebox">SetPenColor</a></li>
<li><a href="#ctrl.picturebox">SetPenSize</a></li>
<li><a href="#ctrl.picturebox">SetPictureData</a></li>
<li><a href="#ctrl.imagebutton">SetPictureData</a></li>
<li><a href="#ctrl.image">SetPictureData</a></li>
<li><a href="#ctrl.spinbutton">SetRange</a></li>
<li><a href="#ctrl.listview">SetRows</a></li>
<li><a href="#ctrl.optionbutton">SetSelected</a></li>
<li><a href="#ctrl.listview">SetSort</a></li>
<li><a href="#ctrl.spinbutton">SetStep</a></li>
<li><a href="#ctrl.richlabel">SetStyle</a></li>
<li><a href="#ctrl.textarea">SetSyntaxColor</a></li>
<li><a href="#ide.preferences">Settings</a></li>
<li><a href="#lang.runtime">Settings Files</a></li>
<li><a href="#ctrl.form">Several copies of a form</a></li>
<li><a href="#lang.func.math">SGN</a></li>
<li><a href="#lang.declarations">SHARED</a></li>
<li><a href="#lang.misc">SHELL</a></li>
<li><a href="#lang.runtime">SHELL_PRIORITY_NORMAL</a></li>
<li><a href="#lang.runtime">ShellAppId</a></li>
<li><a href="#lang.runtime">ShellAppIsHung</a></li>
<li><a href="#lang.runtime">ShellAppMemory</a></li>
<li><a href="#lang.runtime">ShellArg$</a></li>
<li><a href="#lang.runtime">ShellArgCount</a></li>
<li><a href="#lang.runtime">ShellArgQuote$</a></li>
<li><a href="#lang.runtime">ShellCommandArgs$</a></li>
<li><a href="#lang.runtime">ShellCommandProgram$</a></li>
<li><a href="#lang.runtime">ShellGroupsLoad</a></li>
<li><a href="#lang.runtime">ShellItemGet$</a></li>
<li><a href="#lang.runtime">ShellItemIcon$</a></li>
<li><a href="#lang.runtime">ShellItemKeyValid</a></li>
<li><a href="#lang.runtime">ShellPriority</a></li>
<li><a href="#lang.runtime">ShellProgramsFolder$</a></li>
<li><a href="#lang.runtime">ShellRunDosWait</a></li>
<li><a href="#lang.runtime">ShellRunningActivate</a></li>
<li><a href="#lang.runtime">ShellRunningClose</a></li>
<li><a href="#lang.runtime">ShellRunningFind</a></li>
<li><a href="#lang.runtime">ShellRunningId</a></li>
<li><a href="#lang.runtime">ShellRunningKill</a></li>
<li><a href="#lang.runtime">ShellRunningName$</a></li>
<li><a href="#lang.runtime">ShellRunningPriority</a></li>
<li><a href="#lang.runtime">ShellRunningSetPriority</a></li>
<li><a href="#lang.runtime">ShellSetPriority</a></li>
<li><a href="#ctrl.menus">Shortcut</a></li>
<li><a href="#ctrl.menus">Shortcut Keys</a></li>
<li><a href="#ctrl.menus">ShortcutText</a></li>
<li><a href="#lang.forms">Show</a></li>
<li><a href="#ctrl.form">Show</a></li>
<li><a href="#ctrl.helppane">ShowTopic</a></li>
<li><a href="#lang.runtime">Signatures</a></li>
<li><a href="#ide.package">Signing a package</a></li>
<li><a href="#lang.func.math">SIN</a></li>
<li><a href="#lang.datatypes">Single</a></li>
<li><a href="#lang.runtime">SizeChars</a></li>
<li><a href="#lang.runtime">SizePercent</a></li>
<li><a href="#lang.runtime">Sizes in characters</a></li>
<li><a href="#lang.misc">SLEEP</a></li>
<li><a href="#ctrl.hscrollbar">Slider</a></li>
<li><a href="#ctrl.listview">SortColumn</a></li>
<li><a href="#ctrl.listview">SortOrder</a></li>
<li><a href="#lang.sound">SOUND</a></li>
<li><a href="#lang.runtime">Sound</a></li>
<li><a href="#lang.runtime">sound.bas</a></li>
<li><a href="#lang.runtime">SoundCaps</a></li>
<li><a href="#lang.runtime">SoundCreate</a></li>
<li><a href="#lang.runtime">SoundError$</a></li>
<li><a href="#lang.runtime">SoundFont</a></li>
<li><a href="#lang.runtime">SoundFree</a></li>
<li><a href="#lang.runtime">SoundGetVolume</a></li>
<li><a href="#lang.runtime">SoundInfo$</a></li>
<li><a href="#lang.runtime">SoundLength</a></li>
<li><a href="#lang.runtime">SoundLoad</a></li>
<li><a href="#lang.runtime">SoundPause</a></li>
<li><a href="#lang.runtime">SoundPlay</a></li>
<li><a href="#lang.runtime">SoundPlayEvent</a></li>
<li><a href="#lang.runtime">SoundPlaying</a></li>
<li><a href="#lang.runtime">SoundResume</a></li>
<li><a href="#lang.runtime">SoundSetFrequency</a></li>
<li><a href="#lang.runtime">SoundSetPan</a></li>
<li><a href="#lang.runtime">SoundSetPitch</a></li>
<li><a href="#lang.runtime">SoundSetVolume</a></li>
<li><a href="#lang.runtime">SoundStreamClose</a></li>
<li><a href="#lang.runtime">SoundStreamFlush</a></li>
<li><a href="#lang.runtime">SoundStreamOpen</a></li>
<li><a href="#lang.runtime">SoundStreamWrite</a></li>
<li><a href="#lang.runtime">SoundVolume</a></li>
<li><a href="#ide.project">Source Map</a></li>
<li><a href="#lang.func.string">SPACE$</a></li>
<li><a href="#ctrl.spacer">Spacer</a></li>
<li><a href="#ctrl.form">Spacing</a></li>
<li><a href="#ctrl.hbox">Spacing</a></li>
<li><a href="#ctrl.statusbar">Spacing</a></li>
<li><a href="#ctrl.toolbar">Spacing</a></li>
<li><a href="#ctrl.wrapbox">Spacing</a></li>
<li><a href="#lang.io">SPC</a></li>
<li><a href="#ctrl.spinbutton">SpinButton</a></li>
<li><a href="#ctrl.spinbutton">Spinner</a></li>
<li><a href="#lang.func.string">SPLIT</a></li>
<li><a href="#ctrl.splitter">Split Pane</a></li>
<li><a href="#ctrl.splitter">Splitter</a></li>
<li><a href="#lang.runtime">sql.bas</a></li>
<li><a href="#lang.sql">SQLAffected</a></li>
<li><a href="#lang.sql">SQLClose</a></li>
<li><a href="#lang.sql">SQLEof</a></li>
<li><a href="#lang.sql">SQLError$</a></li>
<li><a href="#lang.sql">SQLEscape$</a></li>
<li><a href="#lang.sql">SQLExec</a></li>
<li><a href="#lang.sql">SQLField$</a></li>
<li><a href="#lang.sql">SQLFieldCount</a></li>
<li><a href="#lang.sql">SQLFieldDbl</a></li>
<li><a href="#lang.sql">SQLFieldInt</a></li>
<li><a href="#lang.sql">SQLFieldName$</a></li>
<li><a href="#lang.sql">SQLFieldText$</a></li>
<li><a href="#lang.sql">SQLFreeResult</a></li>
<li><a href="#lang.sql">SQLite</a></li>
<li><a href="#ctrl.data">SQLite</a></li>
<li><a href="#lang.sql">SQLNext</a></li>
<li><a href="#lang.sql">SQLOpen</a></li>
<li><a href="#lang.sql">SQLQuery</a></li>
<li><a href="#lang.func.math">SQR</a></li>
<li><a href="#ide.debug.callstack">Stack Trace</a></li>
<li><a href="#ctrl.timer">Start</a></li>
<li><a href="#lang.statements">Statements</a></li>
<li><a href="#lang.declarations">STATIC</a></li>
<li><a href="#ide.menu.view">Status Bar Toggle</a></li>
<li><a href="#ctrl.statusbar">StatusBar</a></li>
<li><a href="#lang.loops">STEP</a></li>
<li><a href="#ide.menu.run">Step Into</a></li>
<li><a href="#ide.menu.run">Step Out</a></li>
<li><a href="#ide.menu.run">Step Over</a></li>
<li><a href="#ide.debugger">Stepping</a></li>
<li><a href="#lang.sound">STICK</a></li>
<li><a href="#ide.menu.run">Stop</a></li>
<li><a href="#ctrl.timer">Stop</a></li>
<li><a href="#lang.runtime">StopAllSounds</a></li>
<li><a href="#lang.runtime">StopWave</a></li>
<li><a href="#lang.func.string">STR$</a></li>
<li><a href="#lang.func.string">STRCOMP</a></li>
<li><a href="#lang.sound">STRIG</a></li>
<li><a href="#lang.datatypes">String</a></li>
<li><a href="#lang.func.string">STRING$</a></li>
<li><a href="#lang.func.string">STRREVERSE$</a></li>
<li><a href="#lang.procedures">SUB</a></li>
<li><a href="#ctrl.menus">Submenu</a></li>
<li><a href="#lang.declarations">SWAP</a></li>
<li><a href="#ide.editor">Syntax Highlighting</a></li>
<li><a href="#lang.runtime">SYS_VIDEO_DEFAULT_WIDTH</a></li>
<li><a href="#lang.runtime">SysFontGlyphRow</a></li>
<li><a href="#lang.runtime">SysGetColor</a></li>
<li><a href="#lang.runtime">SysLibraryLoaded</a></li>
<li><a href="#lang.runtime">SysLoadTheme</a></li>
<li><a href="#lang.runtime">SysMemoryFreeKb</a></li>
<li><a href="#lang.runtime">SysMemoryTotalKb</a></li>
<li><a href="#lang.runtime">SysMouseButtons</a></li>
<li><a href="#lang.runtime">SysMouseX</a></li>
<li><a href="#lang.runtime">SysScreenshot</a></li>
<li><a href="#lang.runtime">SysSendKey</a></li>
<li><a href="#lang.runtime">SysSetColor</a></li>
<li><a href="#lang.runtime">SysSetMouse</a></li>
<li><a href="#lang.runtime">SysSetMousePos</a></li>
<li><a href="#lang.runtime">SysSetTextSmoothing</a></li>
<li><a href="#lang.runtime">SysSetVideoMode</a></li>
<li><a href="#lang.runtime">SysSetWallpaper</a></li>
<li><a href="#lang.runtime">SysShiftState</a></li>
<li><a href="#lang.runtime">System font glyphs</a></li>
<li><a href="#lang.runtime">system.bas</a></li>
<li><a href="#lang.io">TAB</a></li>
<li><a href="#ide.preferences">Tab Width</a></li>
<li><a href="#ctrl.tabstrip">TabControl</a></li>
<li><a href="#ctrl.tabstrip">TabStrip</a></li>
<li><a href="#ctrl.common.props">Tag</a></li>
<li><a href="#ctrl.form">Tag (form)</a></li>
<li><a href="#lang.func.math">TAN</a></li>
<li><a href="#lang.runtime">TcpConnect</a></li>
<li><a href="#lang.runtime">TcpConnectStart</a></li>
<li><a href="#lang.runtime">TcpPeek$</a></li>
<li><a href="#lang.runtime">TcpPeer$</a></li>
<li><a href="#lang.runtime">TcpRecv$</a></li>
<li><a href="#lang.runtime">TcpSendSome</a></li>
<li><a href="#lang.runtime">Telnet</a></li>
<li><a href="#ctrl.terminal">Terminal</a></li>
<li><a href="#ctrl.textbox">Text</a></li>
<li><a href="#lang.runtime">Text smoothing</a></li>
<li><a href="#ctrl.textarea">TextArea</a></li>
<li><a href="#ctrl.textbox">TextBox</a></li>
<li><a href="#ctrl.drawing">TextHeight</a></li>
<li><a href="#ctrl.richedit">TextRTF</a></li>
<li><a href="#ctrl.drawing">TextWidth</a></li>
<li><a href="#ctrl.drawing">TextWidthAccel</a></li>
<li><a href="#lang.conditionals">THEN</a></li>
<li><a href="#lang.func.date">TIME</a></li>
<li><a href="#lang.func.misc">TIME$</a></li>
<li><a href="#lang.func.math">TIMER</a></li>
<li><a href="#ctrl.timer">Timer</a></li>
<li><a href="#lang.func.date">TIMESERIAL</a></li>
<li><a href="#lang.func.date">TIMEVALUE</a></li>
<li><a href="#ide.menu.run">Toggle Breakpoint</a></li>
<li><a href="#ide.toolbar">Toolbar</a></li>
<li><a href="#ctrl.toolbar">Toolbar</a></li>
<li><a href="#ide.menu.view">Toolbar Toggle</a></li>
<li><a href="#ide.toolbox">Toolbox</a></li>
<li><a href="#ide.menu.tools">Tools Menu</a></li>
<li><a href="#ctrl.treeview">TreeView</a></li>
<li><a href="#lang.func.string">TRIM$</a></li>
<li><a href="#lang.constants">True</a></li>
<li><a href="#lang.declarations">TYPE</a></li>
<li><a href="#lang.variants">TYPENAME</a></li>
<li><a href="#lang.operators">TYPEOF</a></li>
<li><a href="#lang.func.fileio">UBOUND</a></li>
<li><a href="#lang.func.string">UCASE$</a></li>
<li><a href="#lang.runtime">UdpSend</a></li>
<li><a href="#lang.forms">UNLOAD</a></li>
<li><a href="#ctrl.form">Unload</a></li>
<li><a href="#lang.loops">UNTIL</a></li>
<li><a href="#ctrl.image">UseMaskColor</a></li>
<li><a href="#lang.runtime">User Folder</a></li>
<li><a href="#lang.usercontrol">UserControl</a></li>
<li><a href="#lang.usercontrol">USERCONTROL</a></li>
<li><a href="#ide.usercontrols">UserControls in the IDE</a></li>
<li><a href="#ide.usercontrols">UserMode in the Designer</a></li>
<li><a href="#lang.func.string">VAL</a></li>
<li><a href="#ctrl.data">Validate</a></li>
<li><a href="#ctrl.checkbox">Value</a></li>
<li><a href="#ide.immediate">Variable Assignment</a></li>
<li><a href="#ide.debug.locals">Variable Inspection</a></li>
<li><a href="#lang.variants">Variant</a></li>
<li><a href="#lang.variants">VARIANT</a></li>
<li><a href="#lang.datatypes">Variant Type</a></li>
<li><a href="#lang.screen">VARPTR$</a></li>
<li><a href="#lang.variants">VARTYPE</a></li>
<li><a href="#lang.classes">VB_Name</a></li>
<li><a href="#lang.classes">VB_UserMemId</a></li>
<li><a href="#lang.constants">vbArchive</a></li>
<li><a href="#lang.constants">vbArray</a></li>
<li><a href="#ctrl.common.props">vbArrow</a></li>
<li><a href="#lang.constants">vbAutomatic</a></li>
<li><a href="#lang.constants">vbBeginDrag</a></li>
<li><a href="#lang.constants">vbBinaryCompare</a></li>
<li><a href="#lang.constants">vbBlack</a></li>
<li><a href="#lang.constants">vbBlue</a></li>
<li><a href="#lang.constants">vbBoolean</a></li>
<li><a href="#ctrl.drawing">vbBoth</a></li>
<li><a href="#lang.constants">vbByte</a></li>
<li><a href="#lang.constants">vbCancel</a></li>
<li><a href="#lang.screenobj">vbCascade</a></li>
<li><a href="#lang.constants">vbCentimeters</a></li>
<li><a href="#lang.clipboard">vbCFText</a></li>
<li><a href="#lang.constants">vbCFText</a></li>
<li><a href="#lang.constants">vbCharacters</a></li>
<li><a href="#lang.constants">vbCritical</a></li>
<li><a href="#lang.constants">vbCross</a></li>
<li><a href="#ctrl.common.props">vbCrosshair</a></li>
<li><a href="#lang.clipboard">vbCtrlMask</a></li>
<li><a href="#lang.constants">vbCurrency</a></li>
<li><a href="#lang.constants">vbCyan</a></li>
<li><a href="#lang.constants">vbDash</a></li>
<li><a href="#lang.constants">vbDashDot</a></li>
<li><a href="#lang.constants">vbDashDotDot</a></li>
<li><a href="#lang.constants">vbDataObject</a></li>
<li><a href="#lang.constants">vbDate</a></li>
<li><a href="#lang.constants">vbDefault</a></li>
<li><a href="#lang.constants">vbDiagonalCross</a></li>
<li><a href="#lang.constants">vbDirectory</a></li>
<li><a href="#lang.constants">vbDot</a></li>
<li><a href="#lang.constants">vbDouble</a></li>
<li><a href="#lang.constants">vbDownwardDiagonal</a></li>
<li><a href="#lang.constants">vbEmpty</a></li>
<li><a href="#lang.constants">vbEndDrag</a></li>
<li><a href="#lang.constants">vbEnter</a></li>
<li><a href="#lang.constants">vbError</a></li>
<li><a href="#lang.constants">vbExclamation</a></li>
<li><a href="#lang.constants">vbFirstFourDays</a></li>
<li><a href="#lang.constants">vbFirstFullWeek</a></li>
<li><a href="#lang.constants">vbFirstJan1</a></li>
<li><a href="#lang.constants">vbFriday</a></li>
<li><a href="#lang.constants">vbFSSolid</a></li>
<li><a href="#lang.constants">vbFSTransparent</a></li>
<li><a href="#lang.constants">vbGet</a></li>
<li><a href="#ctrl.drawing">vbGrayCopy</a></li>
<li><a href="#lang.constants">vbGreen</a></li>
<li><a href="#lang.constants">vbHidden</a></li>
<li><a href="#lang.constants">vbHimetric</a></li>
<li><a href="#ctrl.drawing">vbHimetric</a></li>
<li><a href="#ctrl.drawing">vbHorizontal</a></li>
<li><a href="#lang.constants">vbHorizontalLine</a></li>
<li><a href="#lang.screenobj">vbHourglass</a></li>
<li><a href="#lang.constants">vbInches</a></li>
<li><a href="#lang.constants">vbInformation</a></li>
<li><a href="#lang.constants">vbInsideSolid</a></li>
<li><a href="#lang.constants">vbInteger</a></li>
<li><a href="#lang.constants">vbInvisible</a></li>
<li><a href="#lang.clipboard">vbKeyBack</a></li>
<li><a href="#lang.clipboard">vbKeyDelete</a></li>
<li><a href="#lang.clipboard">vbKeyReturn</a></li>
<li><a href="#lang.constants">vbLeave</a></li>
<li><a href="#lang.constants">vbLeftButton</a></li>
<li><a href="#lang.constants">vbLet</a></li>
<li><a href="#lang.constants">vbLong</a></li>
<li><a href="#lang.constants">vbMagenta</a></li>
<li><a href="#lang.constants">vbManual</a></li>
<li><a href="#lang.constants">vbMaximized</a></li>
<li><a href="#ctrl.form">vbMaximized</a></li>
<li><a href="#lang.constants">vbMethod</a></li>
<li><a href="#lang.constants">vbMiddleButton</a></li>
<li><a href="#lang.constants">vbMillimeters</a></li>
<li><a href="#lang.constants">vbMinimized</a></li>
<li><a href="#ctrl.form">vbMinimized</a></li>
<li><a href="#lang.forms">vbModal</a></li>
<li><a href="#ctrl.form">vbModal</a></li>
<li><a href="#lang.constants">vbMonday</a></li>
<li><a href="#lang.constants">vbNo</a></li>
<li><a href="#ctrl.common.props">vbNoDrop</a></li>
<li><a href="#lang.constants">vbNormal</a></li>
<li><a href="#lang.constants">vbNull</a></li>
<li><a href="#lang.constants">vbObject</a></li>
<li><a href="#lang.constants">vbObjectError</a></li>
<li><a href="#lang.constants">vbOK</a></li>
<li><a href="#lang.constants">vbOKCancel</a></li>
<li><a href="#lang.constants">vbOKOnly</a></li>
<li><a href="#lang.constants">vbOver</a></li>
<li><a href="#ctrl.vbox">VBox</a></li>
<li><a href="#lang.constants">vbPicTypeBitmap</a></li>
<li><a href="#lang.constants">vbPicTypeNone</a></li>
<li><a href="#lang.constants">vbPixels</a></li>
<li><a href="#lang.constants">vbPoints</a></li>
<li><a href="#lang.printerobj">vbPRCMColor</a></li>
<li><a href="#lang.printerobj">vbPRCMMonochrome</a></li>
<li><a href="#lang.printerobj">vbPRORLandscape</a></li>
<li><a href="#lang.printerobj">vbPRORPortrait</a></li>
<li><a href="#lang.constants">vbQuestion</a></li>
<li><a href="#lang.constants">vbReadOnly</a></li>
<li><a href="#lang.constants">vbRed</a></li>
<li><a href="#lang.constants">vbRetry</a></li>
<li><a href="#lang.constants">vbRetryCancel</a></li>
<li><a href="#lang.constants">vbRightButton</a></li>
<li><a href="#lang.constants">vbSaturday</a></li>
<li><a href="#ctrl.drawing">vbSBNone</a></li>
<li><a href="#lang.constants">vbSet</a></li>
<li><a href="#lang.constants">vbSingle</a></li>
<li><a href="#ctrl.common.props">vbSizeNESW</a></li>
<li><a href="#ctrl.common.props">vbSizeNS</a></li>
<li><a href="#ctrl.common.props">vbSizeNWSE</a></li>
<li><a href="#ctrl.common.props">vbSizeWE</a></li>
<li><a href="#lang.constants">vbSolid</a></li>
<li><a href="#ctrl.drawing">vbSrcCopy</a></li>
<li><a href="#lang.constants">vbString</a></li>
<li><a href="#lang.constants">vbSunday</a></li>
<li><a href="#lang.constants">vbSyntaxComment</a></li>
<li><a href="#lang.constants">vbSyntaxKeyword</a></li>
<li><a href="#lang.constants">vbSyntaxNumber</a></li>
<li><a href="#lang.constants">vbSyntaxOperator</a></li>
<li><a href="#lang.constants">vbSyntaxString</a></li>
<li><a href="#lang.constants">vbSyntaxText</a></li>
<li><a href="#lang.constants">vbSyntaxType</a></li>
<li><a href="#lang.constants">vbSystem</a></li>
<li><a href="#lang.constants">vbTextCompare</a></li>
<li><a href="#lang.constants">vbThursday</a></li>
<li><a href="#lang.screenobj">vbTileGrid</a></li>
<li><a href="#lang.screenobj">vbTileHorizontal</a></li>
<li><a href="#lang.screenobj">vbTileVertical</a></li>
<li><a href="#ctrl.drawing">vbTransparentCopy</a></li>
<li><a href="#lang.constants">vbTuesday</a></li>
<li><a href="#lang.constants">vbTwips</a></li>
<li><a href="#lang.constants">vbUpwardDiagonal</a></li>
<li><a href="#lang.constants">vbUseCompareOption</a></li>
<li><a href="#lang.constants">vbUser</a></li>
<li><a href="#lang.constants">vbUserDefinedType</a></li>
<li><a href="#lang.constants">vbUseSystem</a></li>
<li><a href="#lang.constants">vbUseSystemDayOfWeek</a></li>
<li><a href="#lang.constants">vbVariant</a></li>
<li><a href="#ctrl.drawing">vbVertical</a></li>
<li><a href="#lang.constants">vbVerticalLine</a></li>
<li><a href="#lang.constants">vbWednesday</a></li>
<li><a href="#lang.constants">vbWhite</a></li>
<li><a href="#lang.constants">vbYellow</a></li>
<li><a href="#lang.constants">vbYes</a></li>
<li><a href="#lang.constants">vbYesNo</a></li>
<li><a href="#lang.constants">vbYesNoCancel</a></li>
<li><a href="#ctrl.line">Vertical</a></li>
<li><a href="#ctrl.vbox">Vertical Layout</a></li>
<li><a href="#lang.screen">VIEW</a></li>
<li><a href="#ide.menu.view">View Menu</a></li>
<li><a href="#lang.screen">VIEW PRINT</a></li>
<li><a href="#ide.overview">Visual Basic</a></li>
<li><a href="#ctrl.terminal">VT100</a></li>
<li><a href="#ide.debug.watch">Watch Expressions</a></li>
<li><a href="#ide.debug.watch">Watch Window</a></li>
<li><a href="#lang.runtime">Wavetable synthesizer</a></li>
<li><a href="#lang.runtime">Web requests</a></li>
<li><a href="#lang.func.date">WEEKDAY</a></li>
<li><a href="#lang.func.date">WEEKDAYNAME</a></li>
<li><a href="#lang.loops">WEND</a></li>
<li><a href="#ide.changes">What's New</a></li>
<li><a href="#lang.loops">WHILE</a></li>
<li><a href="#ide.toolbox">Widget Palette</a></li>
<li><a href="#lang.screen">WIDTH</a></li>
<li><a href="#lang.fileio">WIDTH #</a></li>
<li><a href="#lang.fileio">WIDTH LPRINT</a></li>
<li><a href="#lang.screen">WINDOW</a></li>
<li><a href="#ctrl.form">Window</a></li>
<li><a href="#ide.menu.window">Window Menu</a></li>
<li><a href="#ctrl.form">WindowState</a></li>
<li><a href="#lang.forms">With</a></li>
<li><a href="#lang.classes">WITH</a></li>
<li><a href="#lang.classes">WITH...END WITH</a></li>
<li><a href="#lang.events">WithEvents</a></li>
<li><a href="#lang.events">WITHEVENTS</a></li>
<li><a href="#ctrl.wrapbox">WrapBox</a></li>
<li><a href="#lang.fileio">WRITE #</a></li>
<li><a href="#lang.usercontrol">Writing a control</a></li>
<li><a href="#lang.runtime">WtAlloc</a></li>
<li><a href="#lang.runtime">WtInfo$</a></li>
<li><a href="#lang.runtime">WtStart</a></li>
<li><a href="#lang.runtime">WtUpload</a></li>
<li><a href="#ide.designer">WYSIWYG</a></li>
<li><a href="#lang.runtime">xfer.bas</a></li>
<li><a href="#lang.runtime">XferAnswer</a></li>
<li><a href="#lang.runtime">XferCrc32</a></li>
<li><a href="#lang.runtime">XferStatus</a></li>
<li><a href="#lang.operators">XOR</a></li>
<li><a href="#lang.func.date">YEAR</a></li>
<li><a href="#lang.runtime">ZIP Files</a></li>
<li><a href="#lang.runtime">ZMODEM</a></li>
</ul>
</nav>
<main>
<div class="topic" id="ide.overview">
<h1>DVX BASIC IDE Guide</h1>
<p>DVX BASIC is a BASIC development environment for DVX. It provides a VB3-style integrated development environment with a code editor, form designer, project system, and a full interactive debugger -- all integrated into DVX itself.</p>
<p>This guide covers every feature of the IDE: menus, toolbar, editor, form designer, project management, debugger, and auxiliary windows.</p>
<h2>IDE Windows</h2>
<p>The DVX BASIC IDE is modeled after Visual Basic 3.0. It consists of several floating windows arranged on the DVX desktop:</p>
<ul>
<li>Main Toolbar Window -- anchored at the top of the screen. Contains the menu bar, toolbar buttons, and status bar.</li>
<li>Code Editor -- the primary editing surface for BASIC source code, with Object/Event dropdowns, syntax highlighting, and line numbers.</li>
<li>Form Designer -- a visual design surface for .frm files, showing a WYSIWYG preview of the form with grab handles for resizing controls.</li>
<li>Project Explorer -- a tree view listing all files in the project.</li>
<li>Toolbox -- a palette of available controls for placing on forms.</li>
<li>Properties Panel -- a tree of controls and a list of editable properties for the selected control.</li>
<li>Output Window -- displays PRINT output and runtime errors.</li>
<li>Immediate Window -- an interactive REPL for evaluating expressions and modifying variables at runtime.</li>
<li>Debug Windows -- Locals, Call Stack, Watch, and Breakpoints windows that appear automatically when debugging.</li>
</ul>
<p>The IDE compiles BASIC source into bytecode and runs it in an integrated virtual machine. Programs execute in cooperative slices, yielding to DVX between slices so the GUI remains responsive. Call DoEvents in long-running loops to keep the event loop flowing.</p>
<p><a href="#ide.menu.file">File Menu</a></p>
<p><a href="#ide.menu.edit">Edit Menu</a></p>
<p><a href="#ide.menu.run">Run Menu</a></p>
<p><a href="#ide.menu.view">View Menu</a></p>
<p><a href="#ide.menu.window">Window Menu</a></p>
<p><a href="#ide.menu.tools">Tools Menu</a></p>
<p><a href="#ide.menu.help">Help Menu</a></p>
<p><a href="#ide.toolbar">Toolbar</a></p>
<p><a href="#ide.editor">Code Editor</a></p>
<p><a href="#ide.designer">Form Designer</a></p>
<p><a href="#ide.project">Project System</a></p>
<p><a href="#ide.properties">Properties Panel</a></p>
<p><a href="#ide.toolbox">Toolbox</a></p>
<p><a href="#ide.debugger">Debugger</a></p>
<p><a href="#ide.debug.locals">Locals Window</a></p>
<p><a href="#ide.debug.callstack">Call Stack Window</a></p>
<p><a href="#ide.debug.watch">Watch Window</a></p>
<p><a href="#ide.debug.breakpoints">Breakpoints Window</a></p>
<p><a href="#ide.immediate">Immediate Window</a></p>
<p><a href="#ide.output">Output Window</a></p>
<p><a href="#ide.findreplace">Find / Replace</a></p>
<p><a href="#ide.preferences">Preferences</a></p>
<p><a href="#ide.shortcuts">Keyboard Shortcuts</a></p>
</div>
<div class="topic" id="ide.menu.file">
<h1>File Menu</h1>
<pre> Menu Item Shortcut Description
--------- -------- -----------
New Project... Create a new DVX BASIC project.
Open Project... Open an existing .dbp project file.
Save Project Save the current project file to disk.
Close Project Close the current project (prompts to save unsaved changes; Don't Save also discards unsaved Project Properties changes).
---
Project Properties... Edit project metadata (name, author, version, startup form, icon, etc.) and the command line arguments used when the program is run from the IDE.
---
Add File... Ctrl+O Add a .bas, .frm, .cls, or .ctl file to the project. If no project is open, creates an implicit project from the file. A file that cannot be read, or is 64 KB or larger, is refused with a message.
New Class Module Add a new, empty class module (Class1.cls, Class2.cls, ...) to the project and open it in the Code Editor. See Class Modules under Project System.
New UserControl Add a new UserControl, a control of your own (UserControl1.ctl, UserControl2.ctl, ...), to the project and open it in the Code Editor. See UserControls in the IDE.
Save File Ctrl+S Save the active file to disk.
Save All Save all modified files in the project.
---
Make Executable... Compile the project and save it as a standalone .app file. Prompts for a debug or release build. A release build leaves out debugging information and gives forms and controls short internal names, except in a program that uses names as text (the Name property, Controls, DesignSelection, or a DesignMouse event procedure), which keeps them.
Make Control... In a control project (Project Properties, Type Control) this item replaces Make Executable: it compiles the project and saves its controls as a control file (.wgt, named after the project). See UserControls in the IDE.
Make Package... Make the program (or, in a control project, the control file) and its help file into an add-on package (.DPK) that anyone can install with Software. See Making a Package.
---
Rename File... Give the file selected in the Project Explorer a new name, on disk and in the project. See Renaming a File under Project System.
Remove File Remove the selected file from the project (prompts to save if modified).
---
Exit Close the IDE (prompts to save unsaved changes).</pre>
<p>A project (.dbp) or source file (.bas, .frm, .cls, .ctl) named on the IDE's command line opens when the IDE starts, so double-clicking one in the File Manager, or starting it from the Program Manager, opens it in the IDE.</p>
<p>Files are saved exactly as edited (LF line endings). Each save writes a temporary file first and replaces the original only when the write succeeded. Opening a project that fails to load keeps the current project open and removes the failed entry from the Recent list.</p>
<p><a href="#ide.menu.edit">Edit Menu</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.menu.edit">
<h1>Edit Menu</h1>
<pre> Menu Item Shortcut Description
--------- -------- -----------
Cut Ctrl+X Cut the selection (text, or the selected control in the form designer) to the clipboard.
Copy Ctrl+C Copy the selection to the clipboard.
Paste Ctrl+V Paste from the clipboard. A pasted control keeps all of its properties.
---
Select All Ctrl+A Select all text in the active editor.
---
Delete Del Delete the selected text, or the selected control and everything inside it (in the form designer).
---
Find... Ctrl+F Open the Find/Replace dialog.
Find Next F3 Find the next occurrence of the search text (also after the dialog is closed).
Replace... Ctrl+H Open the Find/Replace dialog with replace enabled.</pre>
<p>Cut, Copy, Paste, Select All, and Delete act on the window you last worked in: the form designer's selected control, or the text of the code, output, or immediate window.</p>
<p><a href="#ide.menu.run">Run Menu</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.menu.run">
<h1>Run Menu</h1>
<pre> Menu Item Shortcut Description
--------- -------- -----------
Run F5 Compile and run the program. If paused at a breakpoint, resumes execution with debugging disabled (runs free).
Debug Shift+F5 Compile and run with the debugger active. Breakpoints are active but execution does not pause at the first statement. If paused, resumes to the next breakpoint.
Run Without Recompile Ctrl+F5 Re-run the last compiled module without recompiling.
Stop Esc Stop the running program. Run, Debug, and the project commands stay disabled until the program has finished shutting down.
---
Step Into F8 Execute one statement, stepping into SUB/FUNCTION calls. If idle, starts a debug session and breaks at the first statement.
Step Over Shift+F8 Execute one statement, stepping over SUB/FUNCTION calls.
Step Out Ctrl+Shift+F8 Run until the current SUB/FUNCTION returns.
Run to Cursor Ctrl+F8 Run until execution reaches the line where the cursor is positioned.
---
Output Window to Log Checkbox: when enabled, PRINT output (each line once) and compile and runtime error reports are also written to the DVX log. Persisted in preferences.
---
Toggle Breakpoint F9 Toggle a breakpoint on the current editor line.
---
Clear Output Clear the Output window.
---
Save on Run Checkbox: when enabled, all modified files are saved automatically before compiling. Persisted in preferences.</pre>
<p><a href="#ide.menu.view">View Menu</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.menu.view">
<h1>View Menu</h1>
<pre> Menu Item Shortcut Description
--------- -------- -----------
Code F7 Switch to Code view for the active file (or the file selected in the Project Explorer).
Designer Shift+F7 Switch to Design view for the active form file. With a module (.bas) active it reports that the file is not a form. The designer keeps its unsaved state while you work in a module.
---
Toolbar Checkbox: show or hide the toolbar. Persisted in preferences.
Status Bar Checkbox: show or hide the status bar. Persisted in preferences.
---
Menu Editor... Ctrl+E Open the Menu Editor dialog for the active form (a form must be active). Allows designing menu bars with captions, names, shortcut keys, levels, checked state, and enabled state. See Menu Editor below.</pre>
<p><a href="#ide.menu.window">Window Menu</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.menu.window">
<h1>Window Menu</h1>
<pre> Menu Item Description
--------- -----------
Code Editor Show or raise the Code Editor window.
Output Show or raise the Output window.
Immediate Show or raise the Immediate window.
Locals Show or raise the Locals debug window.
Call Stack Show or raise the Call Stack debug window.
Watch Show or raise the Watch debug window.
Breakpoints Show or raise the Breakpoints window.
---
Project Explorer Show or raise the Project Explorer window.
Toolbox Show or raise the Toolbox window.
Properties Show or raise the Properties panel.</pre>
<p><a href="#ide.menu.tools">Tools Menu</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.menu.tools">
<h1>Tools Menu</h1>
<pre> Menu Item Description
--------- -----------
Preferences... Open the Preferences dialog (editor settings and project defaults).
---
Debug Layout Checkbox: toggle a debug overlay that shows widget layout boundaries. Useful for diagnosing widget layout issues.</pre>
<p><a href="#ide.menu.help">Help Menu</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.menu.help">
<h1>Help Menu</h1>
<pre> Menu Item Shortcut Description
--------- -------- -----------
DVX BASIC Help F1 Open the DVX BASIC help (language reference, IDE guide, and control reference).
DVX API Reference Open the DVX developer API reference.
---
About DVX BASIC... Show the About dialog with version and copyright information.</pre>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.toolbar">
<h1>Toolbar</h1>
<p>The toolbar is organized into four groups separated by vertical dividers. Each button has a tooltip showing its name and keyboard shortcut.</p>
<h2>File Group</h2>
<pre> Button Shortcut Action
------ -------- ------
Open Ctrl+O Add a file to the project (same as File &gt; Add File).
Save Ctrl+S Save the active file.</pre>
<h2>Run Group</h2>
<pre> Button Shortcut Action
------ -------- ------
Run F5 Compile and run the program.
Stop Esc Stop the running program.</pre>
<h2>Debug Group</h2>
<pre> Button Shortcut Action
------ -------- ------
Debug Shift+F5 Start or resume a debug session.
Step Into F8 Step into the next statement.
Step Over Shift+F8 Step over the next statement.
Step Out Ctrl+Shift+F8 Step out of the current procedure.
Run to Cursor Ctrl+F8 Run to the cursor position.</pre>
<h2>View Group</h2>
<pre> Button Shortcut Action
------ -------- ------
Code F7 Switch to Code view.
Design Shift+F7 Switch to Design view.</pre>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.editor">
<h1>Code Editor</h1>
<p>The Code Editor is the primary editing window for BASIC source code. It occupies the center of the screen, below the toolbar and above the Output and Immediate windows.</p>
<h2>Object and Function Dropdowns</h2>
<p>At the top of the Code Editor are two dropdown lists:</p>
<ul>
<li>Object -- lists (General) plus all objects (form name, control names, menu item names, and the WithEvents variables the file declares). Selecting an object filters the Function dropdown.</li>
<li>Function -- lists all event handlers (procedures) for the selected object. Implemented handlers are listed first (plain text); unimplemented handlers follow in brackets (e.g., [Click]). Selecting an unimplemented event creates a new event handler stub. Only the events the object can get are listed: Paint, for example, appears for the form and for PictureBoxes, the objects a program draws on.</li>
</ul>
<p>A WithEvents variable (Dim WithEvents acct As Account, also Private or Public, in a module, a form, or a class module) is listed as an object; its events are the ones its class module declares with Event. Picking one of them creates the handler acct_EventName with the event's own parameters, so it matches what the class raises. Selecting the variable when it has no handler yet creates the handler for the class's first event, as a control's default event is created.</p>
<p>The editor shows one procedure at a time. Each procedure has its own buffer, and switching between them is instantaneous. The (General) section contains module-level declarations and code.</p>
<p>Text outside the procedure being shown is never lost: lines typed above or below the SUB move to (General), a second SUB typed into the buffer becomes a procedure of its own, and a procedure whose SUB line was deleted becomes (General) text. When you leave an event handler that was generated and never edited it is removed; empty SUBs and FUNCTIONs you wrote yourself are kept. After a save the editor shows exactly what was stored (blank lines around a procedure are normalized). A section too large for the editor opens read-only, with a message in the status bar.</p>
<h2>Syntax Highlighting</h2>
<p>The editor applies real-time syntax coloring as you type. Seven categories are highlighted in distinct colors; the colors themselves are editable in Tools &gt; Preferences &gt; Colors.</p>
<pre> Category Examples
-------- --------
Default Text Identifiers, whitespace.
Keywords IF, THEN, FOR, NEXT, SUB, FUNCTION, DIM, PRINT, SELECT, CASE, DO, LOOP, WHILE, WEND, END, EXIT, CALL, GOSUB, GOTO, RETURN, DECLARE, CONST, TYPE, AND, OR, NOT, XOR, MOD, etc.
Types INTEGER, LONG, SINGLE, DOUBLE, STRING, BOOLEAN, DATE, VARIANT, OBJECT, COLLECTION, TRUE, FALSE, NOTHING, EMPTY, NULL
Strings &quot;Hello, World!&quot;
Comments ' This is a comment, REM This is a comment
Numbers 42, 3.14, &amp;HFF, date literals such as #2026-09-30# and #1/15/2026 10:30 AM#
Operators =, &lt;, &gt;, +, -, *, /, \, &amp;</pre>
<p>Date literals are colored as numbers only when they are real dates, as the compiler reads them; the # of a file number (CLOSE #1) is not. Some words are colored like keywords without being reserved -- built-in type names, Empty, Null, EACH, EVENT, WITHEVENTS, and the console and graphics statements such as CLS, LOCATE, COLOR, SCREEN, PSET, CIRCLE, PAINT, PCOPY, and PMAP. A program may use them as its own names, and after a dot (Text1.Width, Picture1.Point) they are shown as ordinary names.</p>
<h2>Editor Features</h2>
<ul>
<li>Line numbers -- displayed in the gutter on the left side.</li>
<li>Auto-indent -- new lines are automatically indented to match the previous line.</li>
<li>Tab handling -- the Tab key is captured by the editor. Tab width and whether to insert spaces or tab characters are configurable in Preferences (default: 3 spaces).</li>
<li>Gutter click -- clicking in the line number gutter toggles a breakpoint on that line.</li>
<li>Line decorations -- breakpoint lines show a red dot in the gutter. The current debug line (when paused) is highlighted with a yellow background.</li>
</ul>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.designer">
<h1>Form Designer</h1>
<p>The Form Designer provides a visual design surface for editing .frm files. Switch to it with Shift+F7 or the Design toolbar button. It opens in a separate window showing a WYSIWYG preview of the form.</p>
<h2>Design Surface</h2>
<ul>
<li>Grid snapping -- controls snap to an 8-pixel grid when placed or resized.</li>
<li>Selection -- click a control to select it. The selected control is highlighted with grab handles.</li>
<li>Grab handles -- 6x6 pixel handles appear on the right edge (E), bottom edge (S), and bottom-right corner (SE) of the selected control. Drag a handle to resize the control.</li>
<li>Reordering -- drag a control to reorder it among its siblings in the layout (VBox/HBox). A container moves together with its contents.</li>
<li>Placing controls -- select a control type in the Toolbox, then click on the form to place a new instance. The control is auto-named (e.g., Command1, Command2), skipping names already used by a control, a menu item, or the form. Clicking the same tool again deselects it (toggles back to pointer mode). Controls nest at most 15 levels deep; a drop into a container that is already that deep goes into its parent container.</li>
<li>Menu bar preview -- if the form has menu items (defined via the Menu Editor), a preview menu bar is rendered on the design window.</li>
<li>Delete key -- removes the selected control and everything inside it.</li>
</ul>
<p>Opening a form in the designer does not mark it modified. A control whose Visible property is False is still shown on the design surface (the setting applies when the program runs). Disabling a container greys the controls inside it; a control's own Enabled = False is kept when the container is enabled again. A .frm file without an AutoSize line opens without AutoSize; AutoSize = True wins over Width and Height lines. Text values (Caption, Text, and so on) are limited to 379 characters.</p>
<h2>Menu Editor</h2>
<p>The Menu Editor (View &gt; Menu Editor, Ctrl+E) edits the active form's menu bar and popup menus. Menus nest at most 15 levels (0-14); indenting refuses when any item below would go deeper. OK rejects an item nested more than one level below the item above it, and a blank item that has sub-items (it must be named); blank items without sub-items are dropped. The window's close box cancels. Shortcut is a key that runs the item (F2, Ctrl+X, Alt+Enter ...), shown at its right; Text is key text shown without making a shortcut (see Menu Item Properties); OK rejects a Shortcut it does not know. Renaming a menu item renames its event handlers in the code and updates the ContextMenu setting of the form and its controls; inserting, deleting, and moving items does not rename anything.</p>
<h2>Form Properties</h2>
<p>Forms have the following design-time properties: Name, Caption, Width, Height, Left, Top, Layout (VBox or HBox), Centered, AutoSize, Resizable, HelpTopic, ContextMenu, and the font (the Font row; see Properties Panel).</p>
<p><a href="#ide.properties">Properties Panel</a></p>
<p><a href="#ide.toolbox">Toolbox</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.project">
<h1>Project System</h1>
<h2>Project Files (.dbp)</h2>
<p>A DVX BASIC project is stored as a .dbp file (DVX BASIC Project). The project file records:</p>
<ul>
<li>Name -- the project display name (up to 32 characters).</li>
<li>Startup Form -- which form to show automatically when the program starts.</li>
<li>Metadata -- Author, Company, Version, Copyright, Description (a single line), and Icon Path (for compiled binaries).</li>
<li>Arguments -- the command line the program gets (COMMAND$) when it is run from the IDE, for trying out a program that opens the file it is given. It is not built into the compiled program: there COMMAND$ returns whatever the program was started with.</li>
<li>More Than One Copy -- &quot;Allow more than one copy to run at once&quot; ([Settings] MultiInstance = True): the compiled program can be started again while it is running, and each copy runs on its own (like the Clock and the File Manager). Without it, starting the program again only says that it is already running.</li>
<li>Help File -- a compiled help file (.hlp) for the program. It is copied next to the compiled program, and F1 in the running program opens it, at the HelpTopic of the focused control or, failing that, of the form. Add help.bas to the project and call HelpView to open it from a Help menu.</li>
<li>Type -- what the project makes: a program (an .app, the default) or, with Type = Control, a control file (a .wgt holding the project's UserControls for every program). See UserControls in the IDE.</li>
<li>File list -- relative paths of all the project's files: modules (.bas) in the [Modules] section, class modules (.cls) in the [Classes] section, UserControls (.ctl) in the [Controls] section, and forms (.frm) in the [Forms] section.</li>
<li>Fonts -- the .DFN fonts the program carries, in the [Fonts] section (see Fonts a Program Carries).</li>
</ul>
<p>The file sections all have the same shape: one FileN line per file, numbered from 0, and a Count line:</p>
<pre><code>[Modules]
File0 = main.bas
Count = 1
[Classes]
File0 = account.cls
File1 = ledger.cls
Count = 2
[Forms]
File0 = form1.frm
Count = 1</code></pre>
<h2>Fonts a Program Carries</h2>
<p>A program can carry fonts of its own, so its text looks the same whatever fonts were installed. In Project &gt; Properties, Add... in the Fonts row picks a .DFN font (one outside the project's directory can be copied into it); Remove takes the chosen one off the list (the file stays). The fonts are listed in the [Fonts] section of the project file. Make builds them into the program as font resources, and the program has them whenever it runs; running it from the IDE gives it the same fonts until it stops. A program carries at most 64 fonts.</p>
<p>A program's fonts are its own: other programs never see them. Where a font it carries is of a family that is installed too, its sizes and styles come first and the installed family fills in the rest. Fonts are made with the SDK's mkfont from TrueType, Type 1, and bitmap fonts -- one size and only the characters the program uses keeps a font small -- or copied from DVX's FONTS folder. Each .DFN carries the notice and licence of the font it was made from.</p>
<h2>How Projects are Compiled</h2>
<p>When the project is compiled, all source files are concatenated into a single source stream: the modules first, then the class modules, then the UserControls, then the forms. The IDE tracks which lines belong to which file so error messages and debugger locations point to the correct .bas, .cls, or .frm file. The code section of each .frm file is preceded by a hidden BEGINFORM marker that ties its code to its form, and the code of each class module and UserControl is likewise marked with its class name; the header lines of a class module or UserControl are not compiled.</p>
<h2>Compile-Time Validation</h2>
<p>Before the source is handed to the compiler, the IDE scans every .frm file and cross-checks the forms against the widget registry and the statements that reference them. Three classes of error are caught and reported without producing a binary:</p>
<ul>
<li>Unknown widget types -- any Begin TypeName ... End block whose TypeName does not match a registered widget is flagged. The error message names the offending form, control, and type, and hints that DVX uses VB6-style names (SpinButton, not Spinner).</li>
<li>Unknown properties -- statements of the form CtrlName.Property = value, or reads of CtrlName.Property, are checked against the widget's declared property list. A typo such as btn.Captoin triggers a compile error with the form, control, and property name. A control name that is used with different types on different forms is not checked.</li>
<li>Unknown methods -- method calls CtrlName.Method ... are checked the same way against the widget's method list, catching mistakes like list.AddTiem before the program ever runs.</li>
<li>Menu items -- only Name (read), Checked, and Enabled can be used on a menu item in code; Caption, Visible, RadioCheck, Shortcut, and ShortcutText are design-time settings.</li>
</ul>
<p>These checks use the same metadata the Properties panel and Toolbox read from each installed control, so property and method names always match the current widget set without any separate list to maintain.</p>
<h2>Project Operations</h2>
<pre> Operation Description
--------- -----------
New Project Creates a blank project with a name and directory. A default .frm file is added automatically.
Open Project Opens a .dbp file and loads all referenced files into memory. A project file that is 64 KB or larger, or cannot be read, is not loaded; opening it later reports &quot;Cannot load &lt;file&gt;: unreadable or larger than 65535 bytes.&quot; Carriage returns are removed when files are loaded.
Save Project Writes the .dbp file to disk.
Close Project Closes the project, prompting to save unsaved changes.
Add File Adds a .bas, .frm, .cls, or .ctl file to the project. Opening a file without a project auto-creates an implicit project.
New Class Module Adds a new class module to the project and opens it (see Class Modules below).
New UserControl Adds a new UserControl to the project and opens it (see UserControls in the IDE).
Rename File Gives a file a new name on disk and in the project file (see Renaming a File below).
Remove File Removes a file from the project (prompts to save if modified). Removing the startup form clears the Startup Form setting.
Project Properties Opens a dialog for editing project metadata (name, type, author, company, version, copyright, description, icon, help file, startup form), the fonts the program carries, whether more than one copy may run at once, the Arguments for runs from the IDE, and the Package and Needs that File &gt; Make Package uses.</pre>
<h2>Renaming a File</h2>
<p>Select a file in the Project Explorer and choose File &gt; Rename File. Type the new file name; the extension may be left out (a module stays .bas, a class module .cls, a UserControl .ctl, and a form .frm, and cannot be given another kind's extension). The file is renamed in the project's directory and the project file is saved at once with the new name, so the two always agree. Nothing changes, and a message says why, when the name is not a valid file name, when another project file or any file in the directory already has it, or when the file or the project file cannot be written -- an existing file is never overwritten. A file that has never been saved is simply given the new name, and is written under it when you save.</p>
<p>A class module named after its file (it has no Attribute VB_Name line, or one that matches the file name, as File &gt; New Class Module writes it) takes the new name as its class name: its Attribute VB_Name line is changed to match (an edit that is saved with the file, like any other). The new name must then be a valid name that no other form, class module, or UserControl uses. Code that uses the old class name is not changed. A UserControl named after its file (as File &gt; New UserControl makes it) takes the new name too, on its Begin UserControl line; forms that use the old name are not changed. A form keeps its Name property; rename the form itself in the Properties window.</p>
<h2>Project Explorer</h2>
<p>The Project Explorer is a tree view window listing all project files, in four groups: Forms, Modules, Classes, and Controls (UserControls). Double-click a file to open it: .bas, .cls, and .ctl files open in Code view, .frm files open in Design view. The selected file in the Project Explorer determines the target for View &gt; Code and View &gt; Designer commands.</p>
<h2>Class Modules</h2>
<p>A class module (.cls file) defines a kind of object for your program: its member variables, properties, and methods. The BASIC Language Reference describes how to write one (see Objects and Class Modules); this section covers working with them in the IDE.</p>
<ul>
<li>Create -- choose File &gt; New Class Module. The IDE adds a new class module named Class1 (Class2, and so on, when that name is taken) to the Classes group, saved in the project's directory as Class1.cls, and opens it in the Code Editor. The new file holds only its header and Option Explicit; it is written to disk when you save it.</li>
<li>Add an existing one -- choose File &gt; Add File and pick a .cls file (the Class Modules file type). Class files from Visual Basic can be added as they are.</li>
<li>Open -- double-click it in the Project Explorer's Classes group. It opens in Code view; a class module has no designer.</li>
<li>Save -- File &gt; Save File or Save All, as for any other file. The project file lists class modules in its [Classes] section.</li>
<li>Remove -- select it in the Project Explorer and choose File &gt; Remove File. The file itself stays on disk.</li>
<li>Rename -- a class's name is the one in its Attribute VB_Name line, not the file name. File &gt; Rename File renames the file, and a class named after its file (as a new class module is) takes the new name too; see Renaming a File. To give a class a name different from its file, edit its Attribute VB_Name line (and the code that uses the old name) and save. A class module without an Attribute VB_Name line takes its name from the file name.</li>
</ul>
<p>A new class module starts with these header lines:</p>
<pre><code>VERSION DVX 1.00 CLASS
Attribute VB_Name = &quot;Class1&quot;
Option Explicit</code></pre>
<p>Leave the VERSION and Attribute lines at the top of the file; they are not compiled as code. Each class name must be different from the other class names, the UserControl names, and the form names in the project.</p>
<p><a href="#ide.usercontrols">UserControls in the IDE</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.package">
<h1>Making a Package</h1>
<p>File &gt; Make Package turns the project into an add-on package: one .DPK file holding the program (built as a release build) and its help file, which anyone can install with the Software program -- it puts the program in Program Manager's Installed Programs -- and remove again. In a control project the package holds the control file instead, and installs it for every program to use.</p>
<p>The first time, Make Package asks for the package name: who made it and what it is, with a dot between them, such as acme.chess (each part 1 to 8 lower-case letters, digits, or _). It suggests one from the project's Publisher and Name. Keep the same package name for every version, so that Software installs a new version over the old one. The name is kept in the project and can be changed under File &gt; Project Properties (Package).</p>
<p>It then asks where to save the package and which key to sign it with. Signing tells the people who install the package that it came from you and was not changed on the way; the list offers the keys in your KEYS folder (make one with Package Builder's New Key) and Not signed. The key chosen is offered first the next time.</p>
<p>The package takes the rest from the project: its name, Version (give each version you hand out a higher one, such as 1.0.0, then 1.1.0), Description (shown as its summary), Publisher, and Author. When the program needs other add-on packages to work, list them under Project Properties, Needs: each package name with the oldest version that will do, with commas between them, such as acme.cards 1.0, acme.dice 2.1 (a package name alone takes any version). DVX's own libraries need not be listed.</p>
<p>A program that needs more files than its help -- data files, or files in other folders -- is packaged with Package Builder, which takes a whole folder.</p>
<p><a href="#ide.project">Project System</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.usercontrols">
<h1>UserControls in the IDE</h1>
<p>A UserControl is a control you write in BASIC (see UserControls: Your Own Controls in the BASIC Language Reference for how to write one). This topic covers making one in the IDE, editing it, trying it on a form, and turning it into a control file every program can use.</p>
<h2>Making a UserControl</h2>
<p>Choose File &gt; New UserControl. The IDE adds a new UserControl named UserControl1 (UserControl2, and so on, when that name is taken) to the project's Controls group, saved in the project's directory as UserControl1.ctl, and opens it in the Code Editor. It is written to disk when you save it. A new UserControl starts like this:</p>
<pre><code>VERSION DVX 1.00
Begin UserControl UserControl1
Width = 64
Height = 64
End
Option Explicit
Private Sub UserControl_Paint ()
End Sub</code></pre>
<p>The lines up to End are the control's header; the code follows. To use a .ctl file you already have, choose File &gt; Add File and pick it (the UserControls file type). Open, save, rename, and remove .ctl files as you do class modules: a UserControl named after its file takes the new name when the file is renamed.</p>
<h2>Writing the Code</h2>
<p>In the Code Editor, the Object list of a UserControl holds UserControl (the control itself) beside (General). Its Function list has the events the control gets: Initialize, Terminate, Resize, Paint, Click, DblClick, MouseDown, MouseMove, MouseUp, MouseWheel, KeyDown, KeyPress, KeyUp, GotFocus, and LostFocus. Picking one that has no code yet writes its procedure with the right parameters, for example:</p>
<pre><code>Private Sub UserControl_MouseDown (Button As Integer, Shift As Integer, X As Single, Y As Single)
End Sub</code></pre>
<p>These procedures are Private: a Public one would be a method of the control.</p>
<h2>The Header in the Properties Window</h2>
<p>While a UserControl is the active file, the Properties window shows its header instead of a form's controls: Name, Width, Height, CanGetFocus, BackColor, ToolboxIcon, Description, and DefaultEvent, each with the value the control takes (its default when the header leaves it out). Double-click a row to change it:</p>
<pre> Row How it is changed
--- -----------------
Name Type a new name. It must be a valid name that no form, class module, or other UserControl of the project uses. Forms that use the old name are not changed.
Width, Height Enter a whole number of pixels (at least 1): the control's natural size.
CanGetFocus Each double-click switches between True and False.
BackColor Pick a color in the color dialog.
ToolboxIcon Type the name of a 24 x 24 picture file in the project's folder, or click Browse... to pick it.
Description Type the toolbox tooltip.
DefaultEvent Pick one of the control's Events (or none): the event the designer opens when a placed control is double-clicked.</pre>
<p>The change is written into the header lines of the file (the rest of the file stays as it is) and saved with the file. The Code Editor shows the new header; breakpoints in the code move with the lines below it. You can also edit the header lines in the Code Editor by hand.</p>
<h2>Trying It on a Form</h2>
<p>While the project is open, its UserControls are in the Toolbox like the controls DVX comes with: with the picture of their ToolboxIcon (or their name on the button), and their Description as the tooltip. Place one on a form as any other control. The control on the design surface is a real one: its code runs, with UserControl.UserMode False, so Initialize, Resize, and Paint draw it as it will look, while your clicks and keys go to the designer.</p>
<ul>
<li>The Properties window lists the control's properties that can be set (its Public variables and Property Let procedures), with the values its code gives them. A value you change there is passed to its Property Let and saved in the .frm; when the control's code calls UserControl.PropertyChanged, the window shows the new values.</li>
<li>The Code Editor's Function list for the placed control has the events the control raises, then the events a form gets for any of its controls (GotFocus, LostFocus, Validate, DragDrop, and DragOver); picking one writes its handler with the event's parameters (Sub Gauge1_Changed (ByVal Level As Integer)).</li>
<li>Double-clicking the control on the design surface opens its DefaultEvent's handler.</li>
</ul>
<p>The designer compiles the project's UserControls (with its modules and class modules, but not its forms) when the project opens and again when a .ctl file is saved, added, removed, or renamed, or its header is changed in the Properties window; the controls on the design surface are made again then. While the controls have a compile error the designer cannot show them (the status line says so); compile with F5 to see the error. The code of the project's modules (outside their procedures) does not run in the designer, so module variables start empty there. A UserControl whose name is the name of a control installed for every program cannot be shown in the designer, and the program stops when it is run (&quot;Control cannot be registered&quot;): give it another name.</p>
<p>When the program runs, its UserControls are its own: they are registered again for the program, separately from the copies in the designer.</p>
<h2>Control Projects and Make Control</h2>
<p>A project whose controls every program should be able to use is a control project: in File &gt; Project Properties set Type to Control. A control project needs no forms. File &gt; Make Executable becomes File &gt; Make Control: it compiles the project, asks where to save the control file (the project's name with .wgt) and for a debug or release build, and writes the file -- the same file the BASIC compiler makes from the project. Run (F5) only compiles a control project: it is not a program.</p>
<p>To install the control file, copy it into DVX's WIDGETS folder (in a folder of its own, like the controls DVX comes with). When DVX starts next, every program can use its controls, and the Toolbox shows them with their ToolboxIcon pictures and Descriptions.</p>
<p>A program project can hold UserControls too (list them under Controls): the program built from it (Make Executable) carries them, and only that program uses them.</p>
<p><a href="#lang.usercontrol">UserControls: Your Own Controls</a></p>
<p><a href="#ide.project">Project System</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.properties">
<h1>Properties Panel</h1>
<p>The Properties panel (Window &gt; Properties) has two sections:</p>
<ul>
<li>Control tree -- a TreeView at the top listing the form and all its controls in layout order. Click a control name to select it in both the Properties panel and the Form Designer. Drag items in the tree to reorder controls in the form's layout.</li>
<li>Property list -- a two-column ListView below the tree showing property names and values for the selected control. Double-click a property value to edit it via an InputBox dialog. A file property (Picture, DragIcon, the form's Icon, and a Data control's DatabaseName) has Browse... beside its box: a file picked in the project's folder (or a folder inside it) is kept relative to the project, so the project still works when it is moved. Changes take effect immediately in the designer preview.</li>
</ul>
<p>Each control type exposes different properties (e.g., Caption, Text, Width, Height, MaxWidth, MaxHeight, Weight, Alignment, Enabled, Visible, and type-specific properties like DataSource and DataField for data-bound controls). A UserControl placed on a form lists the properties its code defines.</p>
<p>The Font row shows the font the selected control, or the form, draws with: its family, size in pixels, and styles, such as &quot;DejaVu Sans, 14, Bold&quot;. Double-click it to choose a font in the Font dialog; the design surface shows it at once. The choice is kept as the six Font properties (FontName, FontSize, FontBold, FontItalic, FontUnderline, and FontStrikethru), which then appear in the list and can be changed one at a time too. Choosing the font the control would have anyway (its container's or the form's) removes them, so the control follows the form's font again. A font chosen for the form is used by every control that has none of its own. For a TextBox, TextArea, ComboBox, SpinButton, or Terminal the dialog lists only fixed-pitch families.</p>
<p>While a UserControl (.ctl) is the active file, the panel shows the control's header instead: Name, Width, Height, CanGetFocus, BackColor, ToolboxIcon, Description, and DefaultEvent (see UserControls in the IDE).</p>
<p><a href="#ide.designer">Form Designer</a></p>
<p><a href="#ide.usercontrols">UserControls in the IDE</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.toolbox">
<h1>Toolbox</h1>
<p>The Toolbox (Window &gt; Toolbox) is a floating palette of buttons, one for each available control type. Every widget registered with DVX that has a BASIC name appears in the toolbox: the controls DVX comes with, the controls written in BASIC that are installed for every program (control files in the WIDGETS folder), and the open project's own UserControls (see UserControls in the IDE). The buttons are in alphabetical order of the control's name. A button shows the control's picture, or its name when it has none; its tooltip is the control's description.</p>
<p>The Toolbox opens four buttons across and as tall as its buttons need, down to the bottom of the screen. Resize it like any window: the buttons rearrange to fill its width, and when they do not all fit, a scroll bar reaches the rest.</p>
<p>Click a tool to select it (the active tool name is stored in the designer state), then click on the form to place a new instance. Click the same tool again to deselect it and return to pointer mode.</p>
<h2>Available Controls</h2>
<pre> VB Name Description
------- -----------
CheckBox On/off checkbox.
ComboBox Drop-down combo box.
CommandButton Push button that triggers a Click event.
Data Data control for binding to a database.
DBGrid Data-bound grid for displaying database query results.
DropDown Simple drop-down list.
Frame Grouping container with a labeled border.
HBox Horizontal layout container.
HelpPane One topic of a help file, as the Help Viewer shows it.
HScrollBar Horizontal slider/scrollbar.
Label Static text label.
Line Horizontal or vertical separator line.
ListBox Scrollable list of items.
ListView Multi-column list with headers.
OptionButton Radio button (mutually exclusive within a group).
PictureBox Canvas for drawing and images.
ProgressBar Progress indicator bar.
RichEdit Text box for text in many fonts, styles, and colors.
RichLabel Text in many fonts, styles, and colors, in aligned paragraphs.
ScrollPane Scrollable container for large content.
Spacer Invisible spacing element for layout.
SpinButton Numeric up/down spinner.
Splitter Resizable split between two child panes.
StatusBar Status bar at the bottom of a form.
TabPage One page of a TabStrip, holding the controls shown on that tab.
TabStrip Tabbed container with multiple pages.
Terminal ANSI terminal emulator control.
TextArea Multi-line text editor.
TextBox Single-line text input field.
Timer Non-visual timer that fires periodic events.
Toolbar Toolbar container for buttons.
TreeView Hierarchical tree control.
VBox Vertical layout container.
WrapBox Flow layout container that wraps items to the next row.</pre>
<p>A new Image or ImageButton starts empty, 32 by 32 pixels so it can be seen and selected: set its Picture property to show a picture.</p>
<p><a href="#ide.designer">Form Designer</a></p>
<p><a href="#ide.usercontrols">UserControls in the IDE</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.debugger">
<h1>Debugger</h1>
<p>The DVX BASIC IDE includes a full interactive debugger. The debugger has three states:</p>
<pre> State Description
----- -----------
Idle No program loaded or running.
Running The program is executing.
Paused Execution is paused at a breakpoint or step point. The IDE is fully interactive -- you can inspect and change variables, set or clear breakpoints, step, continue, or stop.</pre>
<h2>Starting a Debug Session</h2>
<ul>
<li>Shift+F5 (Debug) -- compiles the project and starts execution in debug mode. Breakpoints are active but execution does not pause at the first statement.</li>
<li>F8 (Step Into) -- if idle, starts a debug session and breaks at the first statement.</li>
<li>F5 (Run) -- compiles and runs without the debugger. No breakpoints are active. If already paused, resumes execution with debugging disabled.</li>
</ul>
<h2>Breakpoints</h2>
<h3>Setting Breakpoints</h3>
<ul>
<li>Press F9 to toggle a breakpoint on the current editor line.</li>
<li>Click in the line number gutter to toggle a breakpoint on that line.</li>
</ul>
<h3>Breakpoint Validation</h3>
<p>Not every line can have a breakpoint. The IDE validates the line content and silently refuses to set breakpoints on:</p>
<ul>
<li>Blank lines</li>
<li>Comment lines (' or REM)</li>
<li>SUB and FUNCTION declaration lines</li>
<li>END SUB and END FUNCTION lines</li>
</ul>
<h3>Breakpoint Storage</h3>
<p>Each breakpoint records the file it belongs to, the line number within that file, and the procedure name (Object.Event). Breakpoints are stored in the project and survive compilation.</p>
<h3>Visual Indicators</h3>
<ul>
<li>Breakpoint lines show a red dot in the gutter.</li>
<li>The current debug line (when paused) has a yellow background.</li>
</ul>
<h3>Breakpoint Adjustment on Edit</h3>
<p>Breakpoints follow their statements when lines are added, removed, joined, split, or pasted. A breakpoint whose line is deleted is removed.</p>
<h2>Stepping</h2>
<pre> Action Shortcut Behavior
------ -------- --------
Step Into F8 Execute one statement. If the statement is a SUB/FUNCTION call, step into it.
Step Over Shift+F8 Execute one statement. If the statement is a SUB/FUNCTION call, execute the entire call and break at the next line in the current scope.
Step Out Ctrl+Shift+F8 Run until the current SUB/FUNCTION returns to its caller.
Run to Cursor Ctrl+F8 Run until execution reaches the line under the cursor.</pre>
<h2>Debug Run Behavior</h2>
<p>When a program is running under the debugger:</p>
<ul>
<li>The program runs in short cooperative slices so the IDE remains responsive.</li>
<li>When the program hits a breakpoint, execution pauses immediately. The IDE switches to Code View, navigates to the breakpoint line, highlights it in yellow, and opens the Locals and Call Stack windows if they are not already visible.</li>
<li>While paused, you can inspect variables in Locals and Watch, evaluate expressions in the Immediate window, assign new values to variables, toggle breakpoints, step, continue, or stop. A pause in module-level code works the same way as a pause in an event handler.</li>
<li>Resuming (F5, Shift+F5, or any Step command) returns the program to Running state.</li>
</ul>
<h2>Stopping</h2>
<p>Press Esc or click the Stop toolbar button at any time to halt execution. The program is terminated, the debugger returns to Idle, and the IDE restores any designer or code windows that were hidden at the start of the run.</p>
<p><a href="#ide.debug.locals">Locals Window</a></p>
<p><a href="#ide.debug.callstack">Call Stack Window</a></p>
<p><a href="#ide.debug.watch">Watch Window</a></p>
<p><a href="#ide.debug.breakpoints">Breakpoints Window</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.debug.locals">
<h1>Locals Window</h1>
<p>When the debugger pauses, the Locals and Call Stack windows are auto-opened (if not already visible). The Watch and Breakpoints windows can be opened manually from the Window menu.</p>
<p>Shows variables for the current execution scope. Displayed as a three-column ListView:</p>
<pre> Column Content
------ -------
Name Variable name (internal mangled names like static variable placeholders are filtered out).
Type Data type: Integer, Long, Single, Double, String, Boolean, Date, Variant, Array, UDT, or the type of object. Array types show the element type (e.g., Integer()).
Value Current value. Strings are shown in quotes. Booleans as True/False. Arrays show bounds and element count (e.g., Integer(0 To 9) [10]). Uninitialized arrays show (uninitialized).</pre>
<p>Variants show the value they currently hold, or Empty or Null; an OPTIONAL Variant parameter the caller left out shows Missing. Object variables show Nothing, or which object they refer to: the class name of a class instance, a Collection with its number of items, or the form or control.</p>
<p>The Locals window displays:</p>
<ul>
<li>Local variables of the current procedure, including its STATIC variables and the module variables it names in a SHARED statement.</li>
<li>Module-level variables. While execution is paused inside a SUB or FUNCTION, only the variables declared with DIM SHARED (or REDIM SHARED) are listed, because the procedure cannot see the others. This also applies inside a DEF FN function, although a DEF FN can read every module variable.</li>
<li>Form-scoped variables for the current form (if the program is executing within a form context), with the same SHARED rule.</li>
<li>Member variables of the object, while execution is paused in a procedure of a class module: the variables of the very object the procedure was called for (Me), Private ones included.</li>
</ul>
<p>The Watch window and the Immediate window follow the same rules. The window is resizable.</p>
<p><a href="#ide.debug.callstack">Call Stack Window</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.debug.callstack">
<h1>Call Stack Window</h1>
<p>Shows the current call chain as a two-column ListView:</p>
<pre> Column Content
------ -------
Procedure Procedure name (or (module) for module-level code).
Line Line number where execution is paused (shown for the topmost frame).</pre>
<p>The current location is shown first, followed by each caller in the call stack (walking from the deepest frame back to the module entry point). Up to 32 frames are displayed.</p>
<p><a href="#ide.debug.watch">Watch Window</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.debug.watch">
<h1>Watch Window</h1>
<p>Allows monitoring arbitrary expressions while debugging. The window has a text input at the top and a two-column ListView below:</p>
<pre> Column Content
------ -------
Expression The watch expression text.
Value Evaluated result (or &lt;error&gt; if evaluation fails). Blank when not paused.</pre>
<h2>Adding Watch Expressions</h2>
<p>Type an expression in the text input and press Enter. Up to 16 watch expressions can be active at once.</p>
<h2>Watch Expression Syntax</h2>
<p>Watch expressions support:</p>
<ul>
<li>Simple variable names: x, count</li>
<li>Array subscripts: arr(5), matrix(2, 3)</li>
<li>UDT field access: player.name</li>
<li>Combined: items(i).price</li>
<li>Arbitrary BASIC expressions (compiled and evaluated against the paused VM's state): x + y * 2, Len(name$)</li>
</ul>
<h2>Editing and Deleting</h2>
<ul>
<li>Double-click or press Enter on a watch entry to move it back into the input box for editing.</li>
<li>Press Delete to remove the selected watch expression.</li>
</ul>
<p><a href="#ide.debug.breakpoints">Breakpoints Window</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.debug.breakpoints">
<h1>Breakpoints Window</h1>
<p>Lists all set breakpoints as a three-column ListView:</p>
<pre> Column Content
------ -------
File Project file path.
Procedure Procedure name (Object.Event format, or (General)).
Line Code line number within the file.</pre>
<ul>
<li>Double-click a breakpoint to navigate the code editor to that location.</li>
<li>Press Delete to remove selected breakpoints (multi-select is supported).</li>
</ul>
<p><a href="#ide.debugger">Debugger</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.immediate">
<h1>Immediate Window</h1>
<p>The Immediate window is an interactive REPL at the bottom-right of the screen. Type a line of BASIC and press Enter to evaluate it. Results appear inline below your input. Enter evaluates the line it is pressed on (a line split by Enter is joined back first); Enter on an empty line does nothing. A statement that does not finish (for example DO: LOOP) is stopped with &quot;Error: Statement did not finish; stopped.&quot;</p>
<h2>Expression Evaluation</h2>
<p>If the input is not a recognized statement keyword, it is automatically wrapped in a PRINT statement. For example, typing 2 + 2 evaluates as PRINT 2 + 2 and displays 4.</p>
<p>You can also type full statements:</p>
<ul>
<li>PRINT x * 2 -- evaluate and print an expression.</li>
<li>DIM tmp As Integer -- declare a temporary variable.</li>
<li>LET x = 42 -- explicit assignment (see below).</li>
</ul>
<p>Parse or runtime errors are displayed inline with an Error: prefix.</p>
<h2>Inspecting Variables While Paused</h2>
<p>When the debugger is paused at a breakpoint, the Immediate window has access to the running program's state. Expressions like count or name$ &amp; &quot; test&quot; display live values.</p>
<h2>Assigning Variables While Paused</h2>
<p>When paused, you can modify variables in the running program directly from the Immediate window using assignment syntax:</p>
<pre><code>variableName = newValue</code></pre>
<p>The optional LET keyword is also accepted:</p>
<pre><code>LET variableName = newValue</code></pre>
<p>Assignment works for:</p>
<ul>
<li>Scalar variables -- x = 42, name$ = &quot;test&quot;, count = count + 1 (any expression is allowed on the right)</li>
<li>Array elements -- arr(5) = 100, matrix(2, 3) = 7.5</li>
<li>UDT fields -- player.score = 1000</li>
<li>Combined -- items(0).price = 9.99</li>
</ul>
<p>The new value is written directly into the running program's variable (local, global, or form scope). A confirmation message is displayed, and the Locals and Watch windows update automatically to reflect the change.</p>
<p>If the assignment target cannot be resolved (unknown variable, out-of-bounds index, wrong type), an error message is displayed.</p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.output">
<h1>Output Window</h1>
<p>The Output window is a read-only TextArea at the bottom-left of the screen. It displays:</p>
<ul>
<li>PRINT output -- PRINT statement output from the running program is appended here, until the program uses a console or graphics statement (CLS, LOCATE, COLOR, SCREEN, LINE, INKEY$, and the others): from then on PRINT and INPUT use the program's own screen window instead (see Console and Graphics in the language reference).</li>
<li>Runtime errors -- if the VM encounters a runtime error (division by zero, out-of-bounds, etc.), the error message and line number are displayed in the output with an Error on line N: prefix.</li>
<li>Compile errors -- if compilation fails, the error message and location are shown.</li>
</ul>
<p>The output buffer holds up to 32,768 characters; when it is full the oldest lines are dropped. The window always shows the newest output. Use Run &gt; Clear Output to clear it.</p>
<p>INPUT statements prompt the user via a modal InputBox dialog; the prompt text is also echoed to the Output window. A program that has its own screen window types its INPUT there instead.</p>
<h2>The Program's Screen Window</h2>
<p>A program that uses the console or graphics statements gets a window of its own, the size of its screen mode (80x25 text, or 640x480 or 320x200 graphics), titled with the project's name. Alt+Enter in that window (or FULLSCREEN in the program) shows it on the whole screen; Alt+Tab brings the desktop back and the program continues. Keys typed in the window go to the program (INKEY$ and INPUT). The window stays open after the program's code has finished, so its output can be read; closing it ends the program.</p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.findreplace">
<h1>Find / Replace</h1>
<p>Open with Ctrl+F (Find) or Ctrl+H (Replace). The Find/Replace dialog is modeless -- it stays open while you continue editing.</p>
<h2>Dialog Controls</h2>
<pre> Control Description
------- -----------
Find input The text to search for.
Replace checkbox + input Enable replacement mode and enter replacement text.
Scope Radio group: Function, Object, File, or Project. Default is Project.
Direction Radio group: Forward or Backward.
Match Case Checkbox: case-sensitive search.</pre>
<h2>Buttons</h2>
<pre> Button Action
------ ------
Find Next Find the next occurrence. Function scope searches the current procedure, Object scope the selected object's procedures, File scope the current file, and Project scope every file. At the end of the current procedure the search wraps around to its start.
Replace Replace the current match and find the next one.
Replace All Replace all occurrences within the selected scope.
Close Close the dialog.</pre>
<h2>Keyboard Shortcut</h2>
<p>F3 repeats the last search (Find Next) without opening the dialog, also after the dialog was closed (then searching the whole project, ignoring case). Scope and direction chosen with the keyboard take effect like mouse clicks.</p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.preferences">
<h1>Preferences</h1>
<p>Open via Tools &gt; Preferences. Settings are saved to dvxbasic.ini in the IDE's folder in your user folder (USER\APPS\KPUNCH\DVXBASIC). The dialog has two tabs.</p>
<h2>General Tab</h2>
<h3>Editor Section</h3>
<pre> Setting Description Default
------- ----------- -------
Skip comments/strings when renaming When renaming a control or form, skip occurrences inside comments and string literals. On
Require variable declaration (OPTION EXPLICIT) When enabled, newly created projects have OPTION EXPLICIT on by default. Off
Tab width Number of spaces per tab stop. 3
Insert spaces instead of tabs When enabled, pressing Tab inserts spaces. When disabled, inserts a real tab character. On</pre>
<h3>New Project Defaults Section</h3>
<p>These fields set the default values for new project metadata:</p>
<pre> Field Description Default
----- ----------- -------
Author Default author name. (empty)
Publisher Default publisher/company name. (empty)
Version Default version string. 1.0
Copyright Default copyright notice. (empty)
Description Default project description (one line). (empty)</pre>
<h2>Colors Tab</h2>
<p>Customizes the syntax-highlighting colors used in the code editor. The left side is a list of seven color entries (Default Text, Keywords, Strings, Comments, Numbers, Operators, Types). Select an entry to see its color, and its red, green, and blue amounts, on the right. Click Change... (or double-click the entry) to pick a new color in the color box: click a basic color or mix one with the Red, Green, and Blue sliders or number boxes, then click OK. Changes are applied to the open editor when you click OK in the Preferences dialog.</p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.shortcuts">
<h1>Keyboard Shortcuts</h1>
<pre> Shortcut Action
-------- ------
Ctrl+O Add File
Ctrl+S Save File
Ctrl+A Select All
Ctrl+X Cut
Ctrl+C Copy
Ctrl+V Paste
Ctrl+F Find
Ctrl+H Replace
Ctrl+E Menu Editor
F1 DVX BASIC Help
F3 Find Next
F5 Run
Shift+F5 Debug
Ctrl+F5 Run Without Recompile
Esc Stop
F7 Code View
Shift+F7 Design View
F8 Step Into
Shift+F8 Step Over
Ctrl+Shift+F8 Step Out
Ctrl+F8 Run to Cursor
F9 Toggle Breakpoint
Del Delete</pre>
<p><a href="#ide.changes">Changes in This Release</a></p>
<p><a href="#ide.overview">Back to Overview</a></p>
</div>
<div class="topic" id="ide.changes">
<h1>Changes in This Release</h1>
<p>This release fixes a large number of problems in the language, the runtime, the controls, and the IDE. Most programs keep working unchanged. Three changes need attention in existing programs: variable scope (see Module Variables Need SHARED), the order of the bytes in a color, and text stored in numbers (see Colors and Numbers Follow Visual Basic).</p>
<h2>Module Variables Need SHARED</h2>
<p>DVX BASIC now uses the QBasic scope rules. A SUB or FUNCTION sees a variable declared at module level (including the code section of a form) only when it is declared with DIM SHARED, or named in a SHARED statement inside the procedure. Before, every module variable was visible everywhere.</p>
<ul>
<li>In an existing program, change DIM to DIM SHARED for every module-level variable that a SUB, FUNCTION, or event handler uses.</li>
<li>Without that change such a name silently becomes a local variable of the procedure (or a compile error with OPTION EXPLICIT, or when the procedure indexes or dots it).</li>
<li>New: the SHARED statement inside a procedure, and REDIM SHARED at module level. DIM SHARED inside a procedure is a compile error.</li>
<li>CONSTs, TYPEs, procedures, forms, and controls are visible everywhere as before; a DEF FN still sees every module variable.</li>
</ul>
<p><a href="#lang.declarations">See: Variable Scope and SHARED</a></p>
<h2>Colors and Numbers Follow Visual Basic</h2>
<ul>
<li>A color is &amp;HBBGGRR, as in Visual Basic: RGB(255, 0, 0) is &amp;HFF (red) and &amp;HFF0000 is blue. RGB, GETRED / GETGREEN / GETBLUE, ForeColor, BackColor, FillColor, the drawing methods, POINT, the Canvas control, and DlgColor all use this form. A program that wrote colors as &amp;HRRGGBB numbers must swap the red and blue bytes, or build its colors with RGB. New: QBCOLOR(n) and the constants vbBlack, vbRed, vbGreen, vbYellow, vbBlue, vbMagenta, vbCyan, and vbWhite.</li>
<li>Text used as a number must be a number, as in Visual Basic: n = &quot;12&quot; stores 12, but n = &quot;abc&quot;, &quot;abc&quot; + 2, or a READ of DATA abc into a number raise error 13 (Type mismatch) and leave the variable as it was. VAL still reads the number at the start of any text, and INPUT reads numbers the way VAL does.</li>
<li>A Long result too large for a Long raises error 6 (Overflow), as in Visual Basic, instead of becoming a Double (an Integer result still becomes a Long). Use CDBL on an operand when a larger result is expected.</li>
</ul>
<p><a href="#lang.func.math">See: Color Functions</a></p>
<p><a href="#lang.datatypes">See: Data Types</a></p>
<h2>Language</h2>
<ul>
<li>GOSUB and RETURN work inside SUB and FUNCTION: each procedure call has its own GOSUB stack. RETURN with no pending GOSUB in the procedure raises error 3 (RETURN without GOSUB); before, RETURN inside a procedure left the procedure (use EXIT SUB / EXIT FUNCTION for that).</li>
<li>Labels belong to their SUB or FUNCTION (or to the module level). GOTO, GOSUB, ON GOTO/GOSUB, and ON ERROR GOTO reach only labels of the same procedure; the same label name can be used in several procedures, and a label may share a name with a variable. An undefined label, or a jump to a SUB or variable name, is a compile error. &quot;SubName:&quot; at the start of a line is an error instead of a silent label.</li>
<li>A CONST inside a SUB or FUNCTION is local and no longer overrides a module constant. CONST name AS type converts the literal (Integer and Long round and range-check); a string/number mismatch or an overflow is a compile error.</li>
<li>DEF FN must be defined before it is used; its free names are module variables.</li>
<li>DEFINT, DEFLNG, and the other DEFtype statements also apply to parameters, STATIC variables, and FUNCTION results. A typed FUNCTION converts the value assigned to it (FUNCTION F AS INTEGER with F = 2.5 returns 2). STATIC variables convert on store and their names no longer leak out of the procedure.</li>
<li>DIM a, b AS STRING, c(3) declares several variables in one statement.</li>
<li>name(...) in an expression only calls FUNCTIONs; a SUB there, or indexing a scalar or CONST, is a compile error.</li>
<li>A FUNCTION can be called as a statement (F 3), discarding its result.</li>
<li>DECLARE must match the definition's BYVAL and OPTIONAL flags too.</li>
<li>SWAP and GET #n, , arr(i) evaluate each subscript exactly once. A BYREF argument written as an expression such as arr(i) + 1 is passed by value.</li>
<li>Numeric literals: an Integer/Long suffix on a literal with a fraction or exponent rounds (1E3% is 1000); -32768% and -2147483648&amp; are accepted; 1. is a valid literal; an over-long literal is an error.</li>
<li>DATA: unquoted items are raw text up to the next comma, colon, comment, or end of line.</li>
<li>READ, INPUT, INPUT #, and LINE INPUT # accept array elements and TYPE fields; PRINT #n, alone writes an empty line.</li>
<li>PRINT USING: ; and , both separate values, and a trailing ; or , suppresses the newline.</li>
<li>More than 8 array dimensions, or an LBOUND/UBOUND dimension outside 1..8, is a compile error.</li>
<li>A missing END SUB, END FUNCTION, END TYPE, or END DECLARE is a compile error.</li>
<li>FOR: a constant fractional STEP with an Integer or Long counter is a compile error, and a computed STEP is rounded to the counter's type. A fractional STEP no longer turns a Single counter into a Double.</li>
<li>DECLARE LIBRARY arguments are always passed by value, converted to the declared parameter type (a Single parameter receives a Single).</li>
<li>Name(idx).Member works with any member name (including keywords such as Name and Text), with method calls, and in chains; Me.Method (x) is a method call.</li>
<li>Compile errors read &quot;Line N, Col C: message&quot; and point at what is wrong (the column is left out only at the end of the source). A SUB called but never defined is reported where it is called.</li>
<li>Built-in function names are not reserved: a variable, constant, SUB, or FUNCTION the program declares with the same name is used instead (see How Names Are Found in the language reference).</li>
<li>Assigning a whole TYPE value to a TYPE variable, array element, or field copies it into the record that is there, as in Visual Basic, so a SUB that was passed one of its fields by reference sees the new value.</li>
<li>A program's compiled code is no longer limited to 64 KB, and programs compile faster with less memory (a program with many procedures twice as fast).</li>
<li>New: COMMAND$ returns the arguments the program was started with (for example the document it was opened with), and COMMAND$(n) returns the nth argument without its quotes. The DVX programs that open documents (Notepad, Image Viewer, Icon Editor, Resource Editor, Help Editor) open the file named there when they start. In the IDE, set the arguments under Project Properties. A program that uses COMMAND$ does not run on an older DVX.</li>
<li>A SUB or FUNCTION may use at most 64 local slots (parameters, local variables, and hidden temporaries). More is a compile error &quot;Too many local variables in X (n, limit is 64)&quot; instead of a runtime error 9; READ and INPUT # into many array elements no longer use a slot per target.</li>
<li>SHARED naming a variable that does not exist at module level creates it there; in a form's code it becomes a variable of that form, not a program-wide one.</li>
<li>New types Byte (0 to 255) and Currency (an exact amount with four decimal places, suffix @), with CBYTE, CCUR, DEFBYTE, and DEFCUR. A variable declared with a type has that type before anything is stored in it (VARTYPE of an unassigned Long is vbLong).</li>
<li>Named arguments, as in Visual Basic: Report title:=&quot;Sales&quot;, width:=60 for SUBs, FUNCTIONs, class methods, and the built-in functions that have argument names (MsgBox, InputBox, Mid, InStr, Format, DateAdd, and others).</li>
<li>QBasic line numbers: a line may start with a number from 0 to 65529, which GOTO, GOSUB, ON GOTO, IF ... THEN 100, RESTORE, and RESUME can name; ERL gives the last line number before the error. RESTORE label and RESUME label are new too.</li>
<li>STATIC arrays and STATIC TYPE variables keep their contents between calls.</li>
<li>Members of an object whose class the compiler knows (declared As the class or As Collection, New, Me in a class) are checked when the program is compiled: a misspelled or Private member, the wrong number of arguments, a Sub used as a value, a property used as a statement or assigned without a Property Let are compile errors that point at the member, and the calls run faster. Through As Object and As Variant members are still found when the program runs. A class's own member variables can be used anywhere in the class, and Me reaches its Private members. Passing a number, text, or an object of another class to an object parameter of a known class is a compile error.</li>
</ul>
<h2>Objects, Classes, and Variants</h2>
<ul>
<li>New: class modules (.cls files) define your own objects, with Public and Private member variables, Subs and Functions, Property Get / Let / Set, Class_Initialize and Class_Terminate, Me, and a default member. Objects are made with NEW (DIM x AS NEW Account, SET x = NEW Account), compared with Is and tested with TypeOf ... Is. An object is freed, and its Class_Terminate run, as soon as nothing refers to it any more.</li>
<li>New: the Collection object (Add, Remove, Item, Count, with optional text keys) and FOR EACH ... NEXT over Collections and arrays.</li>
<li>New: the Variant type (DIM v AS VARIANT) with the special values Empty and Null, and the functions VARTYPE, TYPENAME, ISEMPTY, ISNULL, ISNUMERIC, ISOBJECT, ISARRAY, and CVAR, with the vb... VarType constants and vbObjectError.</li>
<li>New: PUBLIC and PRIVATE at module level (PUBLIC x is DIM SHARED x, PRIVATE x is DIM x).</li>
<li>New error numbers: 94 Invalid use of Null, 424 Object required, 438 Object doesn't support this property or method, 450 Wrong number of arguments or invalid property assignment, 451 Object not a collection, 457 duplicate Collection key.</li>
<li>Changed: CHOOSE with an index outside its list returns Null instead of raising error 5.</li>
<li>Changed: a PARAMARRAY without an AS clause is an array of Variants (TYPENAME &quot;Variant()&quot;).</li>
<li>A form or control name can be used directly wherever an object is expected: SET c = Text1, either side of Is, TypeOf, and an argument for an object parameter.</li>
<li>NEW, PROPERTY, PUBLIC, PRIVATE, and TYPEOF are now reserved words: a variable, SUB, or FUNCTION with one of these names must be renamed. VARIANT, OBJECT, COLLECTION, EMPTY, NULL, and EACH are colored like keywords but are not reserved.</li>
<li>IDE: File &gt; New Class Module, .cls files in Add File, a Classes group in the Project Explorer, and a [Classes] section in the project file. The debugger shows Variants, objects, and the member variables of the object whose code is running.</li>
<li>New: events -- EVENT and RAISEEVENT in class modules, DIM WithEvents variables in modules and forms with handlers named variable_EventName.</li>
<li>New: IMPLEMENTS -- a class can provide the members of another class (the interface) and its objects can be used through variables of the interface type.</li>
<li>New: ISMISSING for OPTIONAL Variant parameters; arguments can be left out in the middle of a call (Report a, , c); FORMAT$ without a format string; LSET of whole TYPE records.</li>
<li>Changed: objects that only refer to each other in a loop are found and freed while the program runs (their Class_Terminate runs first) instead of staying until the program ends.</li>
<li>Changed: an array stored in a Variant is a copy, not shared; ParamArray arguments that are variables are passed by reference; a left-out Variant argument of a method is Missing instead of Empty.</li>
<li>New error numbers: 448 Named argument not found (a Missing value used), 449 Argument not optional.</li>
<li>EVENT, RAISEEVENT, WITHEVENTS, and IMPLEMENTS are colored like keywords but are not reserved.</li>
<li>New: default values for OPTIONAL parameters (Optional count As Integer = 10), in procedures, class methods, and Property procedures.</li>
<li>New: a class module can declare WithEvents member variables and handle the events of the objects it holds; listening never keeps an object alive.</li>
<li>Changed: ParamArray arguments that are array elements, TYPE fields, or a class's member variables are passed by reference too, and so are variables and array elements given to a class's methods through As Object or As Variant variables (for parameters that are not BYVAL).</li>
<li>New: PLAY's X command and &quot;=&quot; numbers with VARPTR$, as in QBasic; each screen page keeps its own text cursor; a PictureBox fires Paint after its size changes.</li>
<li>New: OPTIONAL object parameters can have the default Nothing (Optional target As Object = Nothing).</li>
<li>New: TYPE fields given to a class's methods (obj.Move rec.x) are passed by reference; values a method stores in a variable passed by reference, or copies back from its ParamArray, are converted to the variable's type. The methods of forms and controls take their arguments by value.</li>
<li>Changed: REDIM (or ERASE of a dynamic array) while one of the array's elements is passed by reference to a running procedure raises error 10 (This array is fixed or temporarily locked), as in Visual Basic, instead of leaving the old element behind.</li>
<li>New: LOADPICTURE returns a Picture object for DragIcon and the Picture of Image and ImageButton (file names still work); new error 481 Invalid picture.</li>
<li>New: while a control is dragged, the pointer shows the &quot;no drop&quot; sign over objects that have no DragDrop event procedure and outside the program's forms.</li>
<li>IDE: File &gt; Rename File; WithEvents variables and their class's events in the code window's dropdowns; date literals and the console and graphics statement names are colored.</li>
<li>Changed: a parameter passed by reference is the caller's variable itself, as in Visual Basic. A TYPE field given to a SUB or FUNCTION (Bump rec.count, Bump recs(2).count) is now passed by reference (it was passed by value); a write reaches the variable at once instead of when the call returns, also through a ParamArray, a class's method, and RaiseEvent, so it stays when the procedure later stops with an error and every handler of an event writes to the same variable; a STRING * n variable or field keeps its length at every write. The debugger shows (and changes) the caller's variable for such a parameter.</li>
</ul>
<p><a href="#lang.classes">See: Objects and Class Modules</a></p>
<p><a href="#lang.events">See: Events</a></p>
<p><a href="#lang.interfaces">See: Interfaces (Implements)</a></p>
<p><a href="#lang.variants">See: Variants</a></p>
<h2>Sound, Joysticks, and Frames</h2>
<ul>
<li>New statements from QBasic: BEEP, SOUND frequency, duration (in clock ticks, 18.2 a second), and PLAY with the whole music macro language (notes, octaves, lengths, dots, pauses, tempo, MN/ML/MS, and MF/MB for foreground or background music), plus the PLAY(n) function (notes still waiting in the background). They play on whatever sound hardware the computer has, or silently when there is none.</li>
<li>PLAY's new I command plays the notes that follow on a General MIDI instrument (I1 to I128) through the music synthesizer; I0 goes back to tones.</li>
<li>New functions from QBasic: STICK(n) (joystick position, 1 to 200) and STRIG(n) (joystick buttons), on any joystick DVX knows, or the keyboard when there is none.</li>
<li>New statement FRAMEWAIT rate: waits for the next frame of a steady clock, keeping the desktop running, so a game loop runs at the same speed on every computer.</li>
<li>BEEP, SOUND, PLAY, and FRAMEWAIT are now keywords, and STICK and STRIG built-in functions: a variable, SUB, or FUNCTION with one of these names must be renamed.</li>
<li>Message boxes (MsgBox) play the desktop sound chosen for their kind on the Control Panel's Sounds tab.</li>
</ul>
<p><a href="#lang.sound">See: Sound, Joysticks, and Frames</a></p>
<h2>Runtime</h2>
<ul>
<li>Nested BYREF parameters reach the original variable or array element.</li>
<li>ON ERROR is per procedure. A procedure called from a handler can trap its own errors, returning from a procedure that only installed a handler leaves the caller's ERR alone, and an error inside a running handler passes to the caller's handler.</li>
<li>RESUME NEXT after an error in an IF/ELSEIF/WHILE/DO/LOOP condition skips the block or leaves the loop; after an error in a FOR statement the loop is skipped; after an error in the SELECT CASE expression the whole SELECT CASE block is skipped; after an error in a CASE test that test counts as false and the next value or CASE is tried; after an error in an ON selector no branch is taken.</li>
<li>New error numbers: 3 RETURN without GOSUB, 14 Out of string space, 28 Out of stack space (was reported as 7), 63 Bad record number, 91 Object variable not set. ERR is a Long, and ERROR n reports the standard message for known numbers.</li>
<li>Using a property or method (or Show, Hide, Unload) on a value that is not a form or control raises error 91 instead of doing nothing.</li>
<li>EXP, ^, and other math that leaves the numeric range raise error 6 (Overflow); an undefined result raises error 5.</li>
<li>INT, FIX, and SGN return an Integer (Long or Double when needed); RND returns a Double and follows QBasic (RND(0) repeats the last number, a negative argument reseeds). RANDOMIZE with a negative or very large seed, and RND with a very large negative argument, seed predictably (the seed is taken modulo 2^32), so the sequence for a negative RANDOMIZE seed may differ from before. -x of the most negative Integer or Long widens like 0 - x.</li>
<li>INSTR follows OPTION COMPARE TEXT. INSTR and the MID$ statement reject a start below 1 (error 5); MID$ with a length of 0 replaces nothing.</li>
<li>PRINT # writes a space after numbers, as PRINT does. PRINT USING and FORMAT$ show a value too wide for the field in scientific notation.</li>
<li>SEEK on a RANDOM file works in records (statement and function); a position below 1 is error 63. PUT of a value longer than the record length raises error 59 before writing anything.</li>
<li>SLEEP keeps the desktop and the program's forms running, SLEEP 0 just processes events, and closing the program ends the sleep.</li>
<li>DIR$ returns only files. GETATTR and SETATTR on a missing file raise error 53; SETATTR raises 75 when it cannot change the attributes.</li>
<li>IniRead and IniWrite use the same INI reader as the DVX system settings. IniWrite keeps the text of every other line (of any length) unchanged, ends every line of the saved file with CR LF, and raises error 75 when it cannot read the existing file or write the new one (a write failure used to be ignored); a failed write leaves the old file intact. IniRead no longer finds keys in the tail of a long line, and keys above the first section header are read with section &quot;&quot;. Section names are matched with surrounding blanks ignored.</li>
<li>VAL keeps the magnitude of very long digit strings. Running out of memory while building a string raises error 14.</li>
<li>REDIM PRESERVE of a TYPE array keeps the existing elements.</li>
<li>Appending to a String variable with s = s + x or s = s &amp; x no longer copies the whole string each time, so building long strings in a loop is much faster. When x is InputBox$, MsgBox, CreateForm, CreateControl, or Shell, s is still read before x runs (left to right).</li>
<li>And, Or, Xor, Eqv, and Imp of two Booleans give a Boolean, and Not of a Boolean gives a Boolean, as in Visual Basic 4 and later: Print (a &gt; 1) Or (b &gt; 1) prints True instead of -1, and TypeName gives &quot;Boolean&quot;. With a number on either side they still work on the bits and give a number.</li>
<li>Big disks and long file names: where the disk takes long file names (DVX under Windows, or a long file name driver loaded before DVX), OPEN, KILL, NAME, MKDIR, DIR$, and the other file statements use them, and the File Manager, the file dialogs, and Terminal downloads keep them. A file can be bigger than 2 GB on a FAT32 disk; LOF, FILELEN, LOC, and SEEK raise error 6 (Overflow) for a size or position past 2 GB rather than give a wrong number, and EOF stays right below it. FileOpsFreeBytes and FileOpsTotalBytes are right for disks past 2 GB.</li>
<li>Paths may be written with / or \ wherever a path is taken (OPEN, KILL, NAME, MKDIR, CHDIR, DIR$, FILELEN, and the file and folder functions of the libraries), mixed too; paths DVX gives back (CURDIR$, App.Path, App.Data, the file dialogs, the FileOps results) use \, as DOS shows them. New: FileOpsPathNative$ gives a path of your own that form. DIR$(&quot;C:\*.*&quot;) lists the root of C: (before, it listed C:'s current folder). SHELL commands still go to DOS as written, where / starts a switch.</li>
<li>The IDE shows a project's file paths with \ and keeps writing them with / in the .dbp file, so a project reads the same everywhere.</li>
<li>The Open and Save As dialogs (DlgFileOpen$, DlgFileSave$, and the IDE's own) have a Drive list beside the Path box (Alt+D); a drive with no disk in it says it is not ready.</li>
<li>New: DlgFolder$(title, folder) in commdlg.bas lets the user choose a folder, existing or new, for a Browse button beside a folder box. A title of &quot;&quot; gives any of the file dialogs its usual title (it used to leave the title bar empty).</li>
<li>Changed: FileOpsValidName takes the folder the name is for, FileOpsValidName(folder, itemName), since the rules depend on its disk; XferSafeName$ takes the folder a file is received into, XferSafeName$(name, folder). New: FileOpsLongNames, FileOpsShortPath$, FileOpsValidLongName, and FileOpsValidShortName (fileops.bas), and ShellArgQuote$ (shell.bas), which puts a path with spaces in quotes for a command line.</li>
<li>Programs compiled with an older release must be rebuilt. A program whose procedure table records more than 64 locals for a procedure is refused when it is loaded.</li>
<li>A class may have at most 65536 member variables and a form at most 65536 form-level variables (as many as the compiled program can number); more is a compile error (&quot;Too many member variables in X&quot;, &quot;Too many form-level variables&quot;), and a program file that records more is refused when it is loaded.</li>
</ul>
<h2>Forms and Controls</h2>
<ul>
<li>A reference to a removed control or to a control of an unloaded form raises an &quot;unknown control&quot; runtime error. CreateControl with a parent that is not a container on the same form raises &quot;CreateControl: invalid parent&quot;.</li>
<li>SetEvent works on forms (Me) and menu items; a handler without parameters is called without the event's arguments.</li>
<li>Frame: the Caption from the .frm file or set by code now shows on the frame's border, and reading Caption gives it back (it was ignored and read back &quot;&quot;).</li>
<li>A control's Index below 0, in a .frm file or typed in the designer, means the control is not in a control array, in the designer, the form loader, and the saved file alike (a negative Index was kept, saved without an Index line, and read back as a different control).</li>
<li>ListBox: a horizontal scroll bar appears when the box is narrower than its longest item (its MaxWidth, or a narrow form); Left and Right scroll it a character at a time.</li>
<li>Padding = 0 and Spacing = 0 now mean no padding and no space (before, 0 meant the default). A form, box, or ScrollPane that sets none keeps its own (4 pixels for forms, VBox, and HBox; a Frame's Spacing is 0, a ScrollPane's both 0), and reading Padding or Spacing gives the pixels in use. In the designer, an empty Padding or Spacing on the form means the layout's own.</li>
<li>MaxWidth and MaxHeight win over MinWidth / MinHeight and over the size a control's contents ask for, and the space above the cap goes to the other controls instead of staying empty.</li>
<li>New drawing members on forms and PictureBoxes: FontScale (Print, TextWidth, and TextHeight up to 8 times as large, for titles) and ScrollBarsNeeded (which scroll bars content of a size needs in an area, as the controls decide it; vbSBNone, vbHorizontal, vbVertical, vbBoth).</li>
<li>Fonts: every control and form has FontName, FontSize, FontBold, FontItalic, FontUnderline, and FontStrikethru, as in Visual Basic. A control without a font of its own uses its container's or its form's. Print, TextWidth, TextHeight, PrintAccel, and TextWidthAccel on forms and PictureBoxes use the object's font. The new DlgFont in commdlg.bas shows the font dialog.</li>
<li>Form.Visible = True/False behaves exactly like Show/Hide, but only on a real change: Visible = True on a form that is already shown does nothing (a modal form stays modal), and on a form that has no window it is ignored. MinWidth and MinHeight read back the value that was set. Size properties are limited to 0..32767.</li>
<li>Disabling a container (for example Frame.Enabled = False) blocks mouse and keyboard input to every control inside it (also inside a disabled ScrollPane or Splitter), and SetFocus on such a control does nothing.</li>
<li>OptionButton.Value is a read/write Boolean (True = selected); the button's index is the new read-only OptionIndex. Setting Value raises no Click.</li>
<li>HScrollBar has Min and Max properties. SpinButton's RealMode uses the range set with SetRange. PictureBox has read-only ImageWidth and ImageHeight.</li>
<li>ListBox SetItems &quot;&quot; empties the list, and every | separates items. ListView SetColumns has no length limit. TreeView Clear resets scrolling. TextArea FindNext finds a match that starts at the cursor, and the new SetCursor method moves the caret without selecting.</li>
<li>TabStrip/TabControl: a negative tab index selects the first tab and an index past the end the last one.</li>
<li>The mouse wheel over a DBGrid scrolls the rows without moving the current record, and over a Terminal scrolls its history locally.</li>
<li>.frm files: End followed by blanks or a comment (also End'comment) closes its block while End followed by a word does not, in the compiler, the build, and the release renamer exactly as in the loader, Begin followed by a tab is accepted, Enabled = False on popup-menu items is applied, properties after a nested child's End apply to the parent, and Layout on a control that is not a container is reported.</li>
<li>Include libraries: sql.bas, comm.bas, and commdlg.bas take and return Long (SQLFieldInt and SQLAffected no longer wrap above 32767); resource.bas string functions are declared AS STRING. CommHandshake takes an optional passphrase, and the new CommSetPlain accepts unencrypted data on a channel.</li>
<li>commdlg.bas functions are renamed to match the other include libraries: basFileOpen is now DlgFileOpen$, basFileSave is DlgFileSave$, basInputBox2 is DlgInputBox$, basInputCancelled is DlgInputCancelled, basChoiceDialog is DlgChoice, basIntInput is DlgIntInput, and basPromptSave is DlgPromptSave. The old names are gone; programs that use them must be updated and rebuilt.</li>
<li>New in comm.bas: CommRecvEncrypted(handle, channel) returns True when every byte the last CommRecv$ on that channel returned arrived encrypted and authenticated (also when it returned nothing), and False when any arrived unencrypted (before CommHandshake or on a CommSetPlain channel).</li>
<li>KeyDown: Shift, Ctrl, or Alt with F1-F12, and Alt with Home, End, PgUp, PgDn, Ins, Del, and the arrow keys, report the plain key's KeyCode with the modifier in Shift, even when the modifier is released before the program sees the key.</li>
<li>Data control: while its Validate handler runs, MoveFirst, MoveLast, MoveNext, MovePrevious, AddNew, Refresh, and Update on the same Data control are ignored (they used to validate the same record again without end); Delete is allowed. Only unloading the Data control itself from Validate or Reposition stops the operation that fired it; removing other controls does not.</li>
<li>Data control: writing a field back with the value it already has is not an edit, so leaving a bound control no longer fires Validate. With a SELECT query as RecordSource, edits are dropped when the current record changes. Update and Delete still find a record whose key is a number stored without a declared column type, or is NULL, when the key names exactly one record; Delete keeps the record shown when the database row could not be deleted.</li>
<li>DBGrid re-sorts and re-measures its columns when the Data control's records change (Refresh, AddNew, Delete, or an edit), keeping the chosen sort column, and not on a plain record move.</li>
<li>Image and ImageButton: Picture = &quot;&quot; clears the picture (Picture then reads back &quot;&quot;); a file that cannot be loaded leaves the picture and Picture unchanged. A disabled Image keeps its transparent color transparent.</li>
<li>Timer: a Timer whose handler shows a modal dialog no longer fires a second time from inside that dialog.</li>
<li>TextArea: the horizontal scroll bar appears as soon as the longest line fills the visible width, and the caret stays visible while typing at the right edge.</li>
<li>Terminal: pasting with Ctrl+V returns the view to the live screen and sends the text in small pieces.</li>
<li>ListBox and ListView: changing the items while an item is being dragged ends the drag.</li>
<li>TabControl: switching tabs closes an open drop-down list only when it belongs to a control on the page being hidden. A Label on a Toolbar is drawn on the toolbar's color.</li>
<li>Compile errors from the command-line compiler name the file and line. A .frm without a Begin Form line is an error. A release build that runs out of memory while renaming names fails instead of producing a broken program.</li>
<li>A form shown modal has no minimize gadget.</li>
<li>Menu items accept only Name (read-only), Checked, and Enabled in code; Caption, Visible, RadioCheck, Shortcut, and ShortcutText are design-time settings, and using them in code is a compile error in the IDE.</li>
</ul>
<h2>IDE</h2>
<ul>
<li>Properties window: Picture, DragIcon, the form's Icon, DatabaseName, and a UserControl's ToolboxIcon have Browse... beside the box; a file in the project's folder goes in relative to it.</li>
<li>Immediate window: Enter evaluates the line it is pressed on, assignments accept any expression, and a statement that does not finish is stopped.</li>
<li>A compile error puts the caret on the column of the error, not just its line.</li>
<li>Output window: always shows the newest output and drops the oldest lines when full; Output Window to Log also logs errors.</li>
<li>Find/Replace: Object and File scopes search only that object or file; F3 works after the dialog is closed.</li>
<li>Edit commands act on the window last worked in (designer control or text window). A pasted control keeps all its properties.</li>
<li>The code editor never drops text outside the shown procedure; only untouched generated event handlers are removed.</li>
<li>Files are saved exactly as written, with LF line endings, through a temporary file (for FORM1.FRM, FORM1.$FR, with the old file kept as FORM1.~FR until the save is complete; your own name.BAK is never touched); carriage returns are removed when files are loaded. Don't Save discards Project Properties changes too. A project file may hold up to 64 KB of text not counting carriage returns; a file of twice that size or more is refused without being read.</li>
<li>Debugger: while paused inside a SUB or FUNCTION, Locals and Watch show only the variables the procedure can see (its locals, its STATIC and SHARED names, and DIM SHARED module variables), and STATIC variables are now listed.</li>
<li>Compile-time checks of control properties and methods use the control on the form whose code is being compiled, so a control name used for different control types on different forms is checked too.</li>
<li>Form designer: Image and ImageButton are no longer in the Toolbox, controls nest at most 15 levels, Delete removes a control with its contents, AutoSize matches the runtime, TabStrip TabIndex and the form's ContextMenu are kept on save, control arrays inside containers no longer duplicate controls, and a control keeps any number of design-time properties.</li>
<li>Error and debugger line numbers in a form's code match the editor exactly (the indentation of the first code line is kept).</li>
<li>Menu Editor: at most 15 levels, the close box cancels, and only real renames rewrite event handlers.</li>
<li>Project Properties: Description is a single line.</li>
<li>A Sub or Function whose name already exists (typed or pasted) stays its own procedure, and the compiler reports the duplicate; before, it was moved into (General).</li>
<li>Breakpoints and the caret follow lines that the editor moves when it tidies a procedure (blank lines after End Sub, text typed outside a Sub, a deleted Sub line); a breakpoint whose line disappears is removed.</li>
<li>Immediate window: output leaves room for typing, and Enter in a completely full window evaluates nothing and says so in the status bar.</li>
<li>Debugger: a breakpoint reached while a stopped program is unwinding no longer pauses it.</li>
<li>The title bar's * also shows for a form changed in the designer but not yet saved.</li>
<li>Form designer: a .frm whose container has properties after the controls inside it (Index, Caption ...; DVX writes them before) opens as it runs: the properties are kept and the controls stay in that container. Before, they were dropped, and such a file with another control of the container's name opened as a blank form. Menu items' properties after their submenus are kept too. FrmOpen reads .frm files the same way.</li>
<li>The Toolbox lists the controls in alphabetical order, as CtlTypeName$ does.</li>
<li>Properties window: the Font row sets a control's or the form's font in the Font dialog, and the design surface shows the fonts.</li>
<li>Toolbox: it can be resized, its buttons rearrange to fit, and a scroll bar appears when they do not all fit (with many controls installed, the bottom rows used to be off the screen).</li>
<li>UserControls: File &gt; New UserControl, a Controls group in the Project Explorer, the UserControl object and its events in the Code Editor, the header in the Properties window, the project's UserControls in the Toolbox and on the design surface (their code runs, with UserMode False), and control projects with File &gt; Make Control. A program built with Make Executable carries its UserControls. See UserControls in the IDE.</li>
<li>Form designer: a property value may be as long as a full .frm line (511 characters); a value too long for the line it is saved on (deeply nested controls) stops the save with &quot;A property value is too long to save at its position in the form&quot;. Making a container part of a control array keeps its contents. Only one OptionButton per container keeps Value = True: setting it on one (in the property grid or by pasting a selected one) clears the others.</li>
</ul>
<p><a href="#ide.overview">Back to Overview</a></p>
<hr>
<p>DVX BASIC 1.0 -- Copyright 2026 Scott Duensing</p>
</div>
<div class="topic" id="lang.datatypes">
<h1>Data Types</h1>
<p>DVX BASIC supports the following data types. Each type has a corresponding type suffix character that can be appended to variable names.</p>
<h2>Primary Types</h2>
<pre> Type Size Suffix Range / Description
---- ---- ------ -------------------
Byte 1 byte (none) 0 to 255
Integer 2 bytes % -32768 to 32767
Long 4 bytes &amp; -2147483648 to 2147483647
Single 4 bytes ! 32-bit float, approximately 7 digits precision
Double 8 bytes # 64-bit float, approximately 15 digits precision
Currency 8 bytes @ -922337203685477.5808 to 922337203685477.5807, exact to four decimal places
String variable $ Variable-length, reference-counted, dynamic string
Boolean 2 bytes (none) True (-1) or False (0)
Date 8 bytes (none) A date and time of day from 1/1/100 to 12/31/9999
Variant varies (none) Any value at all: a number, text, a date, an object, an array, or the special values Empty and Null (see Variants)</pre>
<h2>Object Types</h2>
<p>An object variable does not hold a value of its own; it refers to an object that lives elsewhere, so two variables can refer to the same object. Store a reference with Set, use the object's properties and methods with a dot, and set the variable to Nothing when you are done with it.</p>
<pre> Declared As Holds
----------- -----
Control A control on a form (any type of control)
Form A form
Object Any object: a form, a control, an instance of a class module, or a Collection
ClassName An instance of that class module (see Objects and Class Modules)
Collection A Collection object (see Collection Object)</pre>
<pre><code>Dim c As Control
Set c = Text1
c.Text = &quot;Hello&quot;
Dim people As New Collection
people.Add &quot;Ann&quot;</code></pre>
<p>An object variable that has not been Set holds Nothing. Control, Form, and Object variables accept each other's values; a variable declared As a class name or As Collection accepts only an object of that kind, or Nothing: an object of another kind raises error 13 (Type mismatch), and a value that is not an object at all raises error 424 (Object required). The Source parameter of the DragDrop and DragOver events is a Control.</p>
<p><a href="#lang.classes">See also: Objects and Class Modules</a></p>
<h2>Internal Types</h2>
<p>These types are not directly declarable but are used internally by the runtime.</p>
<pre> Internal Type Description
------------- -----------
Array Reference-counted multi-dimensional array (up to 8 dimensions)
UDT User-defined type instance (created with TYPE...END TYPE)
Object Reference to a form, a control, a class instance, or a Collection; declarable as Control, Form, Object, a class name, or Collection
Ref Reference to a variable, array element, TYPE field, or class member variable (what a ByRef parameter holds)</pre>
<h2>Type Suffixes</h2>
<p>Type suffixes can be appended to variable names to declare their type implicitly:</p>
<pre><code>count% = 42 ' Integer
total&amp; = 100000 ' Long
rate! = 3.14 ' Single
pi# = 3.14159265 ' Double
price@ = 19.99 ' Currency
name$ = &quot;Hello&quot; ' String</code></pre>
<h2>Numeric Literals</h2>
<pre> Form Example Description
---- ------- -----------
Decimal integer 42 Values -32768..32767 are Integer; larger are Long
Hex integer &amp;HFF, &amp;H1234 Hexadecimal literal (0-9, A-F)
Octal integer &amp;O10, &amp;O77 Octal literal (0-7)
Binary integer &amp;B1010, &amp;B11111111 Binary literal (0-1)
Integer suffix 42% Force Integer type
Long suffix 42&amp;, &amp;HFF&amp; Force Long type
Floating-point 3.14, 1.5E10, 2.5D3 Any number containing a decimal point or exponent is Double by default
Single suffix 3.14! Force Single type
Double suffix 3.14# Force Double type
Currency suffix 19.99@, 5@ Force Currency type (more than four decimal places round, halves to even)</pre>
<blockquote><strong>Note:</strong> Both E and D can introduce an exponent (e.g. 1.5E10 and 2.5D3 are equivalent forms of a scientific-notation double).</blockquote>
<p>A literal with an Integer or Long suffix and a fraction or exponent is rounded (1E3% is 1000, 2.5% is 2). The most negative values -32768% and -2147483648&amp; are valid. A trailing decimal point is allowed (1. is the Double 1). A numeric literal too long to read is a compile error.</p>
<h2>Type Promotion</h2>
<p>When mixing types in expressions, values are automatically promoted to a common type: Byte -&gt; Integer -&gt; Long -&gt; Single -&gt; Double. A Currency with a Byte, Integer, Long, or Currency stays Currency (see Byte and Currency below). Whole-number arithmetic keeps the type of its operands: an Integer result too large for an Integer becomes a Long (32767 + 1 is the Long 32768) and a Byte result outside 0 to 255 becomes an Integer, but a Long result too large for a Long raises error 6 (Overflow), as in Visual Basic. Convert an operand when a larger result is expected: CDBL(2147483647) + 1 is 2147483648.</p>
<p>+ joins two strings. When a string meets a number in an arithmetic operator (including +) or a comparison, the string must hold a number, as in Visual Basic: &quot;1&quot; + 2 is 3 and &quot; 2.5 &quot; * 2 is 5, but text that is not a number (&quot;abc&quot; + 2, &quot;12abc&quot; + 2) raises error 13 (Type mismatch). VAL reads the number at the start of any text instead (VAL(&quot;12abc&quot;) is 12). Use &amp; to join text and numbers, and VAL / STR$ to convert explicitly.</p>
<h2>Assignment Conversion</h2>
<p>Storing a value into a variable declared as Byte, Integer, Long, Single, Double, Currency, String, Boolean, or Date (by suffix, by AS clause, by DEFtype, or as a typed parameter, STATIC variable, FUNCTION result, TYPE field, or array element) converts the value to that type: a number stored in a String variable becomes its text as STR$ gives it without the leading space (&quot;5&quot;). Text stored in a numeric variable must be a number, as in Visual Basic: &quot;12&quot; and &quot; 3.5 &quot; convert, while text that is not a number (&quot;abc&quot;, &quot;12abc&quot;) raises error 13 (Type mismatch) and the variable keeps its value. DEFtype statements also give parameters, STATIC variables, and FUNCTION results their default type. Byte, Integer, and Long round to the nearest whole number, with halves rounding to the nearest even number (2.5 becomes 2, 3.5 becomes 4), and raise error 6 (Overflow) when the result does not fit; Currency rounds to four decimal places the same way. Single keeps about 7 significant digits, so PRINT shows at most 7 digits of it. Boolean stores True for any non-zero number or non-empty string and False otherwise. Date takes a number as a date's number of days and reads a string as a date (error 13 when the text is not a date, error 6 outside 1/1/100 to 12/31/9999); INPUT into a Date variable reads the date the same way. A variable declared with DIM but without a type is Single (or the DEFtype for its first letter). A variable that is never declared keeps whatever type the assigned value has. A variable declared with a type holds that type from the start, before anything is stored in it: VARTYPE of a Long that was never assigned is 3 (vbLong) and of a String 8 (vbString).</p>
<pre><code>Dim n As Integer
n = 3.7 ' n is 4
n = 40000 ' Error 6: Overflow
n = &quot;12&quot; ' n is 12
n = &quot;twelve&quot; ' Error 13: Type mismatch (n is still 12)
Dim b As Boolean
b = 3 ' b is True
Dim s
s = 1 / 3 ' s is Single: prints 0.3333333
x = 1 / 3 ' x was never declared and keeps the Double: prints 0.333333333333333</code></pre>
<h2>Boolean Values</h2>
<p>Boolean values use -1 for True and 0 for False. Any non-zero numeric value is treated as True in a conditional context. The keywords True and False are reserved and may be used anywhere a Boolean value is expected.</p>
<h2>Byte and Currency</h2>
<p>A Byte holds a whole number from 0 to 255 in one byte. Storing a value outside that range raises error 6 (Overflow). Arithmetic on two Bytes gives a Byte when the result is 0 to 255 and an Integer otherwise; negating a Byte gives an Integer. CBYTE converts a value to a Byte.</p>
<p>A Currency holds an amount of money exactly: it counts ten-thousandths, so it has four decimal places and adding, subtracting, or multiplying amounts never drifts (adding 0.1@ ten times gives exactly 1). A value with more decimal places is rounded to four, halves to the nearest even digit (CCUR(2.00005) is 2, CCUR(2.00015) is 2.0002), and a result outside the Currency range raises error 6 (Overflow). +, -, and * on a Currency and a Byte, Integer, Long, or Currency give a Currency; with a Single or Double they give a Double, and / always gives a Double. Comparisons of Currency values are exact. PRINT and STR$ show a Currency with only the decimals it needs (12.5); FORMAT$ lays it out like any other number. A FOR loop with a Currency counter steps exactly. CCUR converts a value to a Currency.</p>
<pre><code>Dim total As Currency
Dim i As Integer
For i = 1 To 3
total = total + 19.99@
Next
Print total ' 59.97
Print FORMAT$(total, &quot;0.00&quot;)</code></pre>
<p>GET and PUT store a Byte in 1 byte and a Currency in 8 (see GET / PUT).</p>
<h2>Date Values</h2>
<p>A Date holds a calendar date and a time of day, as in Visual Basic: the whole part of its number counts days from 12/30/1899 and the fraction is the time (0.5 is noon, so 36526.5 is noon on 1/1/2000). Days before 12/30/1899 are negative numbers whose time still counts forward from midnight: -1.25 is 6:00 AM on 12/29/1899. CDBL gives a date's number and CDATE turns a number back into a date.</p>
<p>Write a date literal between # signs. The month comes before the day; a year can also come first, and month names (full or abbreviated) work too. A time can follow the date or stand alone:</p>
<pre><code>Dim d As Date
d = #1/15/2000# ' January 15, 2000
d = #2000-01-15 15:30# ' year first, 24-hour time
d = #Jan 15, 2000 3:30:00 PM#
d = #3:30 PM# ' a time alone is on 12/30/1899</code></pre>
<p>Two-digit years 00 to 29 are 2000 to 2029 and 30 to 99 are 1930 to 1999. Date is not a reserved word, so a program may still use Date (or any of the date function names) for its own variables and procedures; the program's own name wins.</p>
<p>PRINT, STR$, CSTR, and the &amp; operator show a date as m/d/yyyy h:mm:ss AM (1/15/2000 3:30:00 PM). A date at midnight shows only the date and a time on 12/30/1899 only the time; a Date variable that was never assigned is 12:00:00 AM. Use FORMAT$ for any other layout.</p>
<p>Adding a number of days to a date, or subtracting one, gives a date (fractions are parts of a day, so d + 0.25 is six hours later); subtracting one date from another gives the number of days between them as a Double. Comparisons put dates in time order, and a string compared with a date is read as a date:</p>
<pre><code>Dim due As Date
due = Date + 30 ' thirty days from today
If due &gt; #12/31/2025# Then Print &quot;Next year&quot;
Print #3/1/2000# - #2/1/2000# ' 29 (2000 is a leap year)
If due = &quot;1/15/2026&quot; Then Print &quot;Match&quot;</code></pre>
<p>A Date variable has no Empty or Null state (a Variant does): a date that is out of range is error 6 (Overflow), and text that is not a date is error 13 (Type mismatch).</p>
<p><a href="#lang.func.conversion">See also: Conversion Functions</a></p>
<p><a href="#lang.variants">See also: Variants</a></p>
</div>
<div class="topic" id="lang.variants">
<h1>Variants</h1>
<p>A Variant is a variable that can hold any kind of value: a number, text, a date, True or False, an object, or a whole array. It takes on the type of whatever is stored in it, and can change type each time something new is stored. A Variant can also hold two special values that no other type has: Empty (nothing has been stored yet) and Null (the value is unknown or missing).</p>
<pre><code>Dim v As Variant
Print TypeName(v) ' Empty
v = 42
Print TypeName(v) ' Integer
v = &quot;forty-two&quot;
Print TypeName(v) ' String
v = #1/15/2000#
Print TypeName(v) ' Date
v = Null
Print IsNull(v) ' True</code></pre>
<p>Declare a Variant with AS VARIANT. Arrays of Variants (DIM list(10) AS VARIANT), Variant parameters, and FUNCTIONs and properties AS VARIANT work the same way; each element of a Variant array starts Empty. A variable declared with DIM but no AS clause, or never declared at all, is not a Variant: it keeps the older rules described under Assignment Conversion.</p>
<p>Storing a Variant in a variable of another type converts the value to that type, as for any other assignment. A Variant that is given an array gets its own copy of the array, as in Visual Basic: after v = list, changing list(1) does not change v(1), and w = v copies again. The same holds when a Variant holding an array is passed BYVAL, stored in an object's member, or added to a Collection. Index it like the array itself, v(1).</p>
<pre><code>Dim list(2) As Integer, v As Variant
list(0) = 1
v = list ' v holds a copy
list(0) = 5
Print v(0); list(0) ' 1 5</code></pre>
<h2>Empty</h2>
<p>Empty means that nothing has been stored in the Variant yet. A new Variant is Empty, and assigning Empty makes it Empty again. In arithmetic Empty counts as 0 and in text as &quot;&quot;, so a counter kept in a Variant needs no starting value; PRINT shows nothing for it.</p>
<pre><code>Dim total As Variant
total = total + 5 ' Empty counts as 0: total is 5
If IsEmpty(v) Then Print &quot;Nothing stored yet&quot;</code></pre>
<h2>Null</h2>
<p>Null means &quot;no valid value&quot; -- for example a field that was never filled in. Null spreads through most expressions: anything calculated from a Null is Null too, so a missing value is not mistaken for a real one.</p>
<pre> Expression Result
---------- ------
Null + 1, Null * x, -Null, Not Null Null
Null = 1, Null &lt; x, Null = Null Null (a comparison with Null is never True)
Abs(Null), Int(Null), Fix(Null), Sgn(Null) Null
Left(Null, 1), UCase(Null), Len(Null), ... Null (the Variant string functions; see below)
&quot;Name: &quot; &amp; Null &quot;Name: &quot; (&amp; treats Null as &quot;&quot;)
Null &amp; Null Null
False And Null False
True Or Null True
False Imp Null, Null Imp True True
Any other And, Or, Xor, Eqv, or Imp with Null Null</pre>
<p>An IF, ELSEIF, WHILE, DO, or LOOP condition that is Null counts as False. Any other use that needs a real number -- storing Null in a numeric, Boolean, or Date variable, CINT(Null) and the other conversion functions, a string function ending in $ such as UCASE$ or LEFT$, or an array subscript -- raises error 94 (Invalid use of Null).</p>
<p>As in Visual Basic, the string functions without $ are Variant functions that pass Null through: LEFT, RIGHT, MID, UCASE, LCASE, TRIM, LTRIM, RTRIM, CHR, HEX, OCT, STR, SPACE, and STRING give Null when their text (or number) argument is Null, and so do LEN, INSTR, INSTRREV, STRCOMP, LIKE, and the date parts YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, WEEKDAY, and DATEPART. Their $ forms (LEFT$, UCASE$ ...) always give text and raise error 94 for Null.</p>
<p>Because Null = Null is itself Null, test for Null with ISNULL, never with =:</p>
<pre><code>If IsNull(price) Then
Print &quot;No price yet&quot;
Else
Print &quot;Price: &quot;; price
End If</code></pre>
<p>Empty and Null are not reserved words: a program that declares its own variable or constant named Empty or Null keeps using it.</p>
<h2>Variant Functions</h2>
<pre> Function Returns Description
-------- ------- -----------
VARTYPE(v) Integer A number for the kind of value v holds (see VarType Constants): vbEmpty (0), vbNull (1), vbInteger (2), vbString (8), vbObject (9), and so on. For an array it is vbArray (8192) plus the element type, so an Integer array is 8194 and a Variant array 8204.
TYPENAME(v) String The name of the kind of value: &quot;Byte&quot;, &quot;Integer&quot;, &quot;Long&quot;, &quot;Single&quot;, &quot;Double&quot;, &quot;Currency&quot;, &quot;String&quot;, &quot;Boolean&quot;, &quot;Date&quot;, &quot;Empty&quot;, &quot;Null&quot;, &quot;Error&quot; (a left-out OPTIONAL argument), the name of a TYPE, &quot;Integer()&quot; for an array, and for objects the class name, &quot;Collection&quot;, &quot;Nothing&quot;, or the type of a form or control.
ISEMPTY(v) Boolean True when v is Empty.
ISNULL(v) Boolean True when v is Null.
ISNUMERIC(v) Boolean True when v is a number, True or False, Empty, or text that reads as a number (&quot;12&quot;, &quot;1.5&quot;). False for Null, dates, and other text.
ISOBJECT(v) Boolean True when v is an object reference, including Nothing.
ISARRAY(v) Boolean True when v is an array.
ISMISSING(v) Boolean True when v is an OPTIONAL Variant parameter the caller left out (see Procedures).
ISDATE(v) Boolean True for a Date or text holding a date (see Date and Time Functions).
CVAR(v) Variant v unchanged, as a Variant.
ARRAY(a, ...) Variant A Variant holding an array of copies of the values, numbered from OPTION BASE (0 unless OPTION BASE 1); ARRAY() is empty (UBOUND -1).</pre>
<pre><code>Dim days As Variant
days = Array(&quot;Mon&quot;, &quot;Tue&quot;, &quot;Wed&quot;)
Print days(1) ' Tue
For Each d In Array(1, 2, 3)
Print d;
Next</code></pre>
<pre><code>Sub Describe(ByVal v As Variant)
Select Case VarType(v)
Case vbEmpty
Print &quot;(empty)&quot;
Case vbNull
Print &quot;(unknown)&quot;
Case vbString
Print &quot;Text: &quot;; v
Case Else
Print TypeName(v); &quot;: &quot;; v
End Select
End Sub</code></pre>
<p><a href="#lang.datatypes">See also: Data Types</a></p>
<p><a href="#lang.constants">See also: VarType Constants</a></p>
</div>
<div class="topic" id="lang.operators">
<h1>Operators</h1>
<p>Operators listed from highest precedence (evaluated first) to lowest precedence (evaluated last). Parentheses override precedence and may be nested freely.</p>
<pre> Precedence Operator Description
---------- -------- -----------
1 (highest) ^ Exponentiation
2 - (unary), + (unary) Negation (unary plus is a no-op)
3 * / Multiply, float divide
4 \ Integer divide
5 MOD Modulus
6 + - Addition, subtraction (+ also concatenates strings)
7 &amp; String concatenation
8 = &lt;&gt; &lt; &gt; &lt;= &gt;= Is Like Comparison (returns Boolean)
9 NOT Logical/bitwise NOT
10 AND Logical/bitwise AND
11 XOR Logical/bitwise exclusive-or
12 OR Logical/bitwise OR
13 EQV Logical/bitwise equivalence
14 (lowest) IMP Logical/bitwise implication</pre>
<h2>Arithmetic Operators</h2>
<pre> Operator Description
-------- -----------
+ Addition (or string concatenation when both operands are strings)
- Subtraction (or negation when used as a unary prefix)
* Multiplication
/ Floating-point division (result is always Single or Double)
\ Integer division (result is Long, fractional part discarded)
MOD Integer modulus (remainder)
^ Exponentiation (result is Double)</pre>
<h2>Comparison Operators</h2>
<p>Comparison operators return True (-1) or False (0).</p>
<pre> Operator Description
-------- -----------
= Equal to
&lt;&gt; Not equal to
&lt; Less than
&gt; Greater than
&lt;= Less than or equal to
&gt;= Greater than or equal to
Is Both sides refer to the same object (objects only)
Like The text on the left matches the pattern on the right</pre>
<p>String comparisons are controlled by OPTION COMPARE. With OPTION COMPARE BINARY (the default) strings are compared by byte value. With OPTION COMPARE TEXT comparisons are case-insensitive. A comparison with Null gives Null (see Variants).</p>
<p>Is compares object references, not values: a Is b is True when both refer to the very same object, and x Is Nothing tests for an object variable that holds no object. Either side may be a form or control name. Using Is on something that is not an object raises error 424 (Object required).</p>
<p>text Like pattern is True when the whole of text matches the pattern. In the pattern, ? stands for any one character, * for any run of characters (none too), # for one digit 0 to 9, [list] for one character in the list, and [!list] for one character not in it; anything else stands for itself. A list holds characters and ranges such as a-z ([A-Za-z0-9_]); to match a literal ?, *, #, or [, put it in brackets ([*]). OPTION COMPARE TEXT makes the match ignore case. Like with Null gives Null, and a pattern with a [ that has no ] raises error 93.</p>
<pre><code>If name$ Like &quot;A*&quot; Then Print &quot;Starts with A&quot;
If code$ Like &quot;[A-Z]##&quot; Then Print &quot;A letter and two digits&quot;
If file$ Like &quot;*.[!b]*&quot; Then Print &quot;Not a .b... extension&quot;</code></pre>
<p>TypeOf object Is TypeName is True when the object is of that type. TypeName can be a class module's name, Collection, Form, Control (any control), Object (any object that is not Nothing), or a control type such as TextBox. It is False for Nothing. Use Not TypeOf ... Is ... for the opposite test.</p>
<pre><code>If player Is Nothing Then Set player = New Player
If a Is b Then Print &quot;Same object&quot;
If TypeOf Source Is TextBox Then Print Source.Text</code></pre>
<h2>Logical / Bitwise Operators</h2>
<p>The logical operators work on Boolean values and also perform bitwise operations on integer values. As in Visual Basic, two Booleans give a Boolean (True And False is False, Not True is False, and Print (a &gt; 1) Or (b &gt; 1) prints True); when either side is a number they work on the bits and give a number (an Integer, or a Long when a side is Long): True And 3 is 3. With Null they give Null unless the other side decides the answer (False And Null is False, True Or Null is True, a Boolean as the other side is); see Variants.</p>
<pre> Operator Description
-------- -----------
NOT Logical/bitwise complement
AND Logical/bitwise AND
OR Logical/bitwise OR
XOR Logical/bitwise exclusive-or
EQV Logical/bitwise equivalence (same as NOT (a XOR b))
IMP Logical/bitwise implication (same as (NOT a) OR b)</pre>
<h2>String Concatenation</h2>
<p>Use &amp; to concatenate strings. The + operator also concatenates when both operands are strings. Prefer &amp; because it does not depend on operand types.</p>
<pre><code>result$ = &quot;Hello&quot; &amp; &quot; &quot; &amp; &quot;World&quot;
result$ = firstName$ &amp; &quot; &quot; &amp; lastName$
' + also concatenates when both operands are strings
greeting$ = &quot;Hi &quot; + name$</code></pre>
</div>
<div class="topic" id="lang.statements">
<h1>Statements</h1>
<p>Multiple statements can appear on one line separated by : (colon). A line can be continued onto the next physical line by ending it with an underscore (_) preceded by whitespace. Comments start with ' (apostrophe) or the REM keyword and run to the end of the line. The character ? is a shorthand for PRINT.</p>
<pre><code>a = 10 : b = 20 : c = a + b ' three statements on one line
total = price * quantity _
+ shipping + tax ' one statement continued across lines
REM This is a comment
' So is this
? &quot;Hello&quot; ' same as PRINT &quot;Hello&quot;</code></pre>
<p><a href="#lang.declarations">Declaration Statements (DIM, REDIM, CONST, TYPE, DECLARE)</a></p>
<p><a href="#lang.conditionals">Conditional Statements (IF, SELECT CASE)</a></p>
<p><a href="#lang.loops">Loop Statements (FOR, DO, WHILE)</a></p>
<p><a href="#lang.procedures">Procedures (SUB, FUNCTION, DEF FN)</a></p>
<p><a href="#lang.flow">Flow Control (EXIT, CALL, GOTO, GOSUB, ON)</a></p>
<p><a href="#lang.io">Input/Output (PRINT, INPUT, DATA/READ)</a></p>
<p><a href="#lang.misc">Miscellaneous Statements (ON ERROR, SHELL, SLEEP, END)</a></p>
<p><a href="#lang.sound">Sound, Joysticks, and Frames (BEEP, SOUND, PLAY, STICK, STRIG, FRAMEWAIT)</a></p>
<p><a href="#lang.classes">Objects and Class Modules (NEW, PROPERTY, Class_Initialize, Me)</a></p>
<p><a href="#lang.collection">Collection Object (Add, Remove, Item, Count)</a></p>
</div>
<div class="topic" id="lang.declarations">
<h1>Declaration Statements</h1>
<h2>DIM</h2>
<p>Declares variables and arrays with an explicit type. If no type is given, the type defaults to whatever DEFtype (if any) is in effect for the variable's first letter; without a DEFtype statement the default is Single.</p>
<pre><code>DIM variable AS type
DIM variable(upperBound) AS type
DIM variable(lower TO upper) AS type
DIM variable(dim1, dim2, ...) AS type
DIM variable() AS type
DIM variable AS UdtName
DIM variable AS STRING * n
DIM variable AS NEW ClassName
DIM SHARED variable AS type
DIM variable1 [AS type], variable2 [AS type], ...</code></pre>
<p>An array declared with bounds is a fixed array. DIM variable() with empty parentheses declares a dynamic array that has no storage until a REDIM gives it bounds; using it before then raises error 13. An array that is first created by REDIM, and an array parameter, are dynamic too (see ERASE for the difference).</p>
<p>One DIM can declare several variables, separated by commas. Each one takes its own AS clause; a name without one gets its suffix or DEFtype type (Single by default), so DIM a, b AS STRING makes only b a String. Arrays can have up to 8 dimensions; more is a compile error. A variable declared with type suffix does not need the AS clause:</p>
<pre><code>Dim name$, count%, total&amp; ' suffixes infer the types
Dim first, last As String, list(10) As Integer</code></pre>
<p>Examples:</p>
<pre><code>Dim name As String
Dim count As Integer
Dim values(100) As Double
Dim matrix(1 To 10, 1 To 10) As Single
Dim Shared globalFlag As Boolean
Dim record As PersonType
Dim fixedStr As String * 20</code></pre>
<blockquote><strong>Note:</strong> A module-level variable is visible inside a SUB or FUNCTION only when it is declared with DIM SHARED (or named in a SHARED statement in that procedure). See Variable Scope below. Inside a SUB or FUNCTION, DIM declares a local variable that is recreated on each call (use STATIC to retain its value between calls). A SUB or FUNCTION holds at most 64 parameters and local variables together, including a few hidden ones that statements such as ON ... GOTO, SWAP, and READ into array elements use while they run; a procedure that needs more fails to compile with &quot;Too many local variables&quot;. A program holds at most 512 module-level variables, a form at most 65536 form-level variables, and a class at most 65536 member variables; more fails to compile.</blockquote>
<p>Fixed-length strings (STRING * n) are padded with spaces and truncated when assigned so their length is always exactly n.</p>
<p>DIM variable AS NEW ClassName (or AS NEW Collection) creates a new object at the DIM and stores it in the variable; without NEW an object variable starts as Nothing. See Objects and Class Modules. DIM variable AS NEW FormName makes a new copy of a form of the project (see Several Copies of a Form in the Form topic); DIM variable AS FormName declares a variable for that form or a copy of it.</p>
<h2>Variable Scope and SHARED</h2>
<p>DVX BASIC follows the QBasic scope rules:</p>
<ul>
<li>Variables declared (or first used) at module level -- outside every SUB and FUNCTION -- are module variables. The code section of a form (.frm) is module-level code of that form.</li>
<li>A SUB or FUNCTION sees a module variable only when it was declared with DIM SHARED at module level, or when the procedure names it in a SHARED statement. This applies to arrays as well.</li>
<li>Any other name used inside a SUB or FUNCTION is a local variable of that procedure, even when a module variable of the same name exists. With OPTION EXPLICIT, using such a name without a DIM is a compile error that says the module variable is not SHARED.</li>
<li>Indexing (name(...)) or dotting (name.member) a module variable the procedure cannot see is a compile error.</li>
<li>CONSTs declared at module level, TYPEs, SUBs, FUNCTIONs, class modules, forms, and controls are visible everywhere; no SHARED is needed for them. PUBLIC at module level is the same as DIM SHARED (see PUBLIC / PRIVATE).</li>
<li>A DEF FN is module-level code: its expression sees every module variable.</li>
</ul>
<pre><code>DIM SHARED total AS LONG ' visible in every SUB and FUNCTION
DIM count AS INTEGER ' module code only
SUB AddUp(n AS INTEGER)
total = total + n ' the module variable
count = 1 ' a local variable, not the module's count
END SUB
SUB ShowCount
SHARED count ' this procedure uses the module's count
PRINT count
END SUB</code></pre>
<p>DIM SHARED and REDIM SHARED are only allowed at module level. Inside a procedure use the SHARED statement:</p>
<pre><code>SHARED variable [()] [AS type] [, variable [()] [AS type] ...]</code></pre>
<p>SHARED gives the procedure access to the named module variables (write name() for an array). The AS type, when given, must match the module variable's declaration. Naming a variable that does not exist at module level creates it there (in a form's code, as a variable of that form).</p>
<h2>How Names Are Found</h2>
<p>Every name in a program is looked up the same way, in this order:</p>
<ul>
<li>A name the program declares is that declaration: first the procedure's own parameters, local variables, and STATIC and SHARED names; then, in a class module, the class's own members; then the variables of the form whose code it is; then the module's variables, SUBs, FUNCTIONs, constants, TYPEs, ENUMs, and classes, and the predefined vb constants. Inside a procedure a module variable counts only when it is shared (see above); a class's members always do.</li>
<li>Otherwise a built-in function of that name is used. Built-in names are not reserved: a variable, constant, SUB, or FUNCTION the program declares with the same name wins (a FUNCTION named StrReverse replaces the built-in one).</li>
<li>Otherwise, where an object is expected -- before a dot (name.Caption), after SET, around Is or TypeOf, or as an argument for an Object or class parameter -- the name is a control of the current form, or a form of that name. Form1.Text1.Text names the control Text1 on the form Form1.</li>
<li>Otherwise the name is a new variable: local inside a procedure, a module variable elsewhere (a DEF FN expression's names are module variables). With OPTION EXPLICIT this is a compile error.</li>
</ul>
<p>A SUB or FUNCTION can be called before its definition, and a TYPE, ENUM, or class -- with its member variables and procedures -- can be used before it is declared: the compiler reads every declaration first. A name after a dot is a member of the object before it: when that object's class is known (see Objects and Class Modules) the member is looked up in the class when the program is compiled, else when it runs.</p>
<h2>PUBLIC / PRIVATE</h2>
<p>At module level, PUBLIC and PRIVATE can be used in place of DIM, as in Visual Basic. PUBLIC declares a variable that every SUB and FUNCTION can use (the same as DIM SHARED); PRIVATE declares one that only module-level code sees (the same as DIM).</p>
<pre><code>Public highScore As Long ' same as Dim Shared highScore As Long
Private tries As Integer ' same as Dim tries As Integer</code></pre>
<p>PUBLIC and PRIVATE may also be written in front of SUB and FUNCTION. Outside a class module they change nothing, because procedures are visible to the whole program anyway. In a class module they decide what code outside the class can use; see Objects and Class Modules. Inside a procedure, use DIM.</p>
<h2>REDIM</h2>
<p>Reallocates an array, optionally preserving existing data. The array may have been declared with DIM name() or with bounds, or not declared at all (REDIM then declares a dynamic array).</p>
<pre><code>REDIM array(newBounds) AS type
REDIM PRESERVE array(newBounds) AS type
REDIM SHARED array(newBounds) AS type</code></pre>
<p>REDIM SHARED (module level only) also makes the array visible in every SUB and FUNCTION, like DIM SHARED.</p>
<pre><code>ReDim items(newSize) As String
ReDim Preserve scores(1 To newCount) As Integer</code></pre>
<h2>CONST</h2>
<p>Declares a named constant. The value is worked out once, when the program is compiled, and can never change -- you cannot assign a new value to a constant or pass it by reference. Several constants can be declared in one CONST statement, separated by commas.</p>
<pre><code>CONST name = expression
CONST name AS type = expression
CONST name = expression, name = expression, ...</code></pre>
<pre><code>Const MAX_SIZE = 100
Const PI = 3.14159265
Const APP_NAME = &quot;DVX App&quot;
Const DEBUG_MODE = True
Const HEADER As String = &quot;=== Report ===&quot;
Const LAUNCH = #7/20/1969 8:17 PM#
Const LAST_INDEX = MAX_SIZE - 1, HALF = MAX_SIZE \ 2
Const TITLE = APP_NAME &amp; &quot; &quot; &amp; &quot;1.0&quot;
Const CRLF = Chr$(13) &amp; Chr$(10)
Const TEAL = RGB(0, 128, 128)
Const BIG = MAX_SIZE &gt; 50</code></pre>
<p>The value can be any expression built from:</p>
<ul>
<li>literals (numbers, strings, True and False, #date# literals);</li>
<li>constants declared earlier, including ENUM members (Member or EnumName.Member);</li>
<li>the arithmetic operators + - * / \ MOD ^, the comparison operators, AND OR NOT XOR EQV IMP, and string joining with &amp; or +;</li>
<li>these built-in functions: ABS, ASC, ATN, CBOOL, CDATE, CDBL, CHOOSE, CHR$, CINT, CLNG, COS, CSNG, CSTR, DATEADD, DATEDIFF, DATEPART, DATESERIAL, DATEVALUE, DAY, EXP, FIX, FORMAT$, GETBLUE, GETGREEN, GETRED, HEX$, HOUR, IIF, INSTR, INSTRREV, INT, ISDATE, LCASE$, LEFT$, LEN, LOG, LTRIM$, MID$, MINUTE, MONTH, MONTHNAME, OCT$, REPLACE$, RGB, RIGHT$, RTRIM$, SECOND, SGN, SIN, SPACE$, SQR, STR$, STRCOMP, STRING$, STRREVERSE$, TAN, TIMESERIAL, TIMEVALUE, TRIM$, UCASE$, VAL, WEEKDAY, WEEKDAYNAME, and YEAR.</li>
</ul>
<p>Anything else -- a variable, a FUNCTION of your own, or a built-in whose answer can change from run to run such as TIMER, NOW, RND, or DIR$ -- is a compile error (&quot;Constant expression required&quot;). An expression that fails, such as a division by zero or a result too big for its type, is also reported when the program is compiled. Text comparisons in a constant follow the OPTION COMPARE setting in effect where the constant is declared. A string constant can be at most 255 characters long.</p>
<p>Without an AS clause the constant takes the type of its value: a whole number makes a Long constant, a number with a fraction a Double constant, and strings, Booleans, and dates keep their type. With an AS clause the value is converted to that type: Integer and Long values are rounded and must fit the type, and a string for a numeric type (or a number for String) is a compile error.</p>
<p>Constants declared at module level are visible to all procedures. A CONST declared inside a SUB or FUNCTION is local to that procedure; it may reuse the name of a module constant without changing it.</p>
<p>PUBLIC CONST and PRIVATE CONST work as in Visual Basic. A Private constant, and any constant of a form or class module, belongs to the file it is declared in: another module, form, or class of the project can declare its own constant of the same name, and does not see this one. A Public constant, or a plain CONST in a module, is seen by the whole program. A class module or form cannot have a Public constant (&quot;Constants are not allowed as Public members of a class module or form&quot;).</p>
<pre><code>Public Const APP_VERSION = &quot;2.1&quot; ' every file of the project
Private Const BUFFER_SIZE = 512 ' this file only</code></pre>
<h2>TYPE...END TYPE</h2>
<p>Defines a user-defined type (record/structure).</p>
<pre><code>TYPE TypeName
fieldName AS type
fieldName AS STRING * n
...
END TYPE</code></pre>
<pre><code>Type PersonType
firstName As String
lastName As String * 20
age As Integer
End Type
Dim p As PersonType
p.firstName = &quot;Scott&quot;
p.age = 30</code></pre>
<p>UDT fields can themselves be UDTs (nested types), and field access chains through array elements too: shapes(i).origin.x = 5. A new instance starts with numeric fields at 0, Boolean fields False, variable strings empty, and STRING * n fields padded to n spaces. TYPE variables can be written to and read from RANDOM and BINARY files with PUT and GET (see GET / PUT).</p>
<h2>ENUM...END ENUM</h2>
<p>Defines a set of named whole-number constants, and a type name for variables that hold one of them.</p>
<pre><code>ENUM EnumName
member
member = expression
...
END ENUM</code></pre>
<pre><code>Enum Direction
North ' 0
East ' 1
South = 10
West ' 11
End Enum
Enum Style
Bold = 1
Italic = Bold * 2
Underline = Style.Italic * 2
AllStyles = Bold Or Italic Or Underline
End Enum
Dim heading As Direction
heading = West
If heading = Direction.West Then Print &quot;Going west&quot;</code></pre>
<p>The first member is 0 and each member without a value is one more than the member before it. A value may be any constant expression (see CONST), including members declared earlier in the same ENUM or in another one. Members are Long constants and can be used on their own (West) or with the ENUM name in front (Direction.West). If two ENUMs have a member with the same name, that name must be written with its ENUM name.</p>
<p>The ENUM name can be used as a type wherever a type is allowed: DIM, parameters, FUNCTION results, and TYPE fields. Such a variable is a Long, so it can hold any whole number, not only the members. ENUMs are declared at module level (not inside a SUB or FUNCTION) and are visible everywhere in the program; declare an ENUM before the code that uses its members. PRIVATE ENUM keeps the ENUM and its members to the file it is declared in, like PRIVATE CONST; PUBLIC ENUM (the same as a plain ENUM) is seen everywhere. Members are constants: Direction.West = 3 is a compile error (&quot;Cannot assign to a constant&quot;).</p>
<h2>DECLARE</h2>
<p>Forward-declares a SUB or FUNCTION. This is rarely required because the compiler supports forward references within a module, but it is still accepted for compatibility:</p>
<pre><code>DECLARE SUB name ([BYVAL] [OPTIONAL] param AS type, ...)
DECLARE FUNCTION name ([BYVAL] [OPTIONAL] param AS type, ...) AS returnType</code></pre>
<p>A DECLARE must match the SUB or FUNCTION it declares: the same parameter types, BYVAL and OPTIONAL flags, and return type.</p>
<h2>DECLARE LIBRARY</h2>
<p>Declares external functions from a native library bundled with DVX. This is how BASIC programs reach operating-system services, serial ports, databases, and other native facilities. Rather than writing DECLARE LIBRARY blocks yourself, add one of the shipped include files (such as commdlg.bas or sql.bas) to your project; the include file contains the proper declarations.</p>
<pre><code>DECLARE LIBRARY &quot;libraryName&quot;
DECLARE SUB name ([BYVAL] param AS type, ...)
DECLARE FUNCTION name ([BYVAL] param AS type, ...) AS returnType
END DECLARE</code></pre>
<pre><code>Declare Library &quot;basrt&quot;
Declare Function SQLOpen(ByVal path As String) As Long
Declare Sub SQLClose(ByVal db As Long)
End Declare</code></pre>
<p>Arguments are always passed by value. Each argument is converted to the type its parameter is declared with before the call, so a Double passed to a Long parameter arrives as a whole number and a Single parameter receives a Single. Declare Integer only for native values that fit in 16 bits; use Long for 32-bit values, or large results are cut down to 16 bits. A Byte parameter or result is 8 bits. A Currency parameter receives the amount as a 64-bit whole number of ten-thousandths; a DECLARE FUNCTION cannot return a Currency.</p>
<p>A String parameter or result declared AS STRING is text: it ends at the first CHR$(0). To pass or receive any bytes, CHR$(0) included (network data, sound samples, encrypted data, checksums of binary data), the declaration says BINARY STRING instead. To the program it is an ordinary String; LEN, MID$, ASC, and the other string functions see every byte. BINARY STRING is allowed only in a DECLARE LIBRARY block, and the shipped include files already use it where a function works with bytes.</p>
<pre><code>Declare Library &quot;mylib&quot;
Declare Function MyChecksum(ByVal bytes As Binary String) As Long
Declare Function MyRead$(ByVal handle As Long, ByVal maxLen As Long) As Binary String
End Declare
packet$ = &quot;A&quot; + Chr$(0) + &quot;B&quot;
Print MyChecksum(packet$)</code></pre>
<p><a href="#lang.runtime">See also: BASIC Runtime Libraries</a></p>
<h2>STATIC</h2>
<p>Declares a local variable that retains its value between calls.</p>
<pre><code>STATIC variable AS type</code></pre>
<pre><code>Sub Counter()
Static count As Integer
count = count + 1
Print count
End Sub</code></pre>
<p>Several variables can be declared in one STATIC statement, separated by commas, each with its own AS clause; STRING * n works as in DIM. Arrays and TYPE variables can be STATIC too and keep their contents between calls: a fixed-size array (Static hits(1 To 10) As Long) or a dynamic one sized later with REDIM (Static names() As String). In a class module each object has its own copy of a procedure's STATIC variables, arrays, and TYPE variables, as in Visual Basic: two objects counting calls count separately. A STATIC AS NEW object or WithEvents variable is not supported (a compile error); use a module-level or member variable for those.</p>
<pre><code>Sub Remember(ByVal word As String)
Static seen(1 To 3) As String
Static count As Integer
count = count + 1
seen((count - 1) Mod 3 + 1) = word
Print seen(1); &quot; &quot;; seen(2); &quot; &quot;; seen(3)
End Sub</code></pre>
<p>Writing STATIC after a SUB or FUNCTION header makes every local variable of the procedure static, the ones declared with DIM and the ones used without a declaration (QBasic and Visual Basic):</p>
<pre><code>Sub Tally(points As Integer) Static
total = total + points ' keeps its value between calls
Dim calls As Integer ' a STATIC variable too
calls = calls + 1
Print calls; total
End Sub</code></pre>
<h2>OPTION</h2>
<p>Sets compiler options. Must appear before any executable code.</p>
<pre><code>OPTION BASE 0 ' Arrays start at index 0 (default)
OPTION BASE 1 ' Arrays start at index 1
OPTION COMPARE BINARY ' Case-sensitive string comparisons (default)
OPTION COMPARE TEXT ' Case-insensitive string comparisons
OPTION EXPLICIT ' All variables must be declared with DIM</code></pre>
<h2>DEFtype Statements</h2>
<p>Set the default type for variables based on their first letter.</p>
<pre><code>DEFINT letterRange
DEFLNG letterRange
DEFSNG letterRange
DEFDBL letterRange
DEFSTR letterRange
DEFBYTE letterRange
DEFCUR letterRange</code></pre>
<pre><code>DefInt I-N ' Variables starting with I through N default to Integer
DefStr S ' Variables starting with S default to String</code></pre>
<h2>Assignment</h2>
<p>Assigns a value to a variable, array element, or UDT field.</p>
<pre><code>variable = expression
array(index) = expression
udt.field = expression
LET variable = expression</code></pre>
<p>The LET keyword is optional and supported for compatibility.</p>
<p>Assigning a whole TYPE value to a TYPE variable, array element, or field copies the value's fields into the record that is already there, as in Visual Basic: the two stay separate records (changing one later does not change the other), and a SUB that was passed one of the target's fields by reference sees the new value.</p>
<h2>SWAP</h2>
<p>Exchanges the values of two variables or array elements. The two operands should be the same type.</p>
<pre><code>SWAP variable1, variable2
SWAP array(index), variable</code></pre>
<pre><code>Swap a, b
Swap names(i), names(j)</code></pre>
<h2>LSET / RSET</h2>
<p>Stores a string into a string variable without changing the variable's length: LSET places the value at the left and RSET at the right, filling the rest with spaces. A value longer than the variable is cut off at the right.</p>
<pre><code>LSET variable = expression
RSET variable = expression</code></pre>
<pre><code>Dim field As String
field = Space$(8)
LSet field = &quot;Name&quot; ' &quot;Name &quot;
RSet field = &quot;42&quot; ' &quot; 42&quot;</code></pre>
<p>The target may be an array element or a TYPE field. It must hold a string; any other value raises error 13 (Type mismatch).</p>
<p>LSET also copies a whole record: when the target is a TYPE variable, the value must be another TYPE variable, and its bytes -- laid out as PUT writes the record to a file -- are copied into the target, even when the two are of different TYPEs. When the source is shorter the rest of the target is filled with spaces; when it is longer the extra bytes are dropped. This is meant for records of numbers and fixed-length strings (STRING * n), as used with random-access files; a variable-length string field does not copy meaningfully between different TYPEs. RSET cannot copy records.</p>
<pre><code>Type Header
kind As String * 2
size As Integer
End Type
Type Raw
bytes As String * 4
End Type
Dim h As Header, r As Raw
r.bytes = &quot;AB&quot; + Chr$(10) + Chr$(0)
LSet h = r ' h.kind = &quot;AB&quot;, h.size = 10</code></pre>
<h2>SET</h2>
<p>Stores an object reference -- a form, a control, an instance of a class module, a Collection, or Nothing -- in a variable, array element, TYPE field, or property. After SET both names refer to the same object; nothing is copied.</p>
<pre><code>SET variable = objectExpression
SET variable = NEW ClassName
SET variable = NEW FormName
SET variable = Nothing</code></pre>
<pre><code>Dim frm As Form
Set frm = CreateForm(&quot;MyForm&quot;, 320, 240)
frm.Caption = &quot;Built in code&quot;
Dim c As Control
Set c = Text1 ' a control on the form
c.Text = &quot;Hello&quot;
Dim list As Collection
Set list = New Collection ' a new, empty Collection
Set list = Nothing ' let it go
Dim w As Form1
Set w = New Form1 ' a second Form1 window
w.Show</code></pre>
<p>The value must be an object or Nothing; anything else raises error 424 (Object required). SET is not used for ordinary numeric or string assignment.</p>
<h2>ERASE</h2>
<p>Frees the memory of a dynamic array (declared with DIM name(), created by REDIM, or an array parameter) and resets it to the undimensioned state; using it again before a REDIM raises error 13. A fixed array (declared with bounds) keeps its bounds and has every element reset to zero, an empty string, False, or a fresh TYPE instance.</p>
<pre><code>ERASE arrayName
ERASE array1, array2, ...</code></pre>
<p>One ERASE can name several arrays, separated by commas.</p>
</div>
<div class="topic" id="lang.conditionals">
<h1>Conditional Statements</h1>
<h2>IF...THEN...ELSE...END IF</h2>
<p>Conditional execution. Supports single-line and multi-line forms.</p>
<h3>Single-line form</h3>
<pre><code>IF condition THEN statement
IF condition THEN statement ELSE statement</code></pre>
<h3>Multi-line form</h3>
<pre><code>IF condition THEN
statements
ELSEIF condition THEN
statements
ELSE
statements
END IF</code></pre>
<pre><code>If x &gt; 10 Then
Print &quot;Large&quot;
ElseIf x &gt; 5 Then
Print &quot;Medium&quot;
Else
Print &quot;Small&quot;
End If
If ready Then Print &quot;Go!&quot;</code></pre>
<h2>SELECT CASE</h2>
<p>Multi-way branch based on an expression value.</p>
<pre><code>SELECT CASE expression
CASE value
statements
CASE value1, value2
statements
CASE low TO high
statements
CASE IS operator value
statements
CASE ELSE
statements
END SELECT</code></pre>
<pre><code>Select Case grade
Case 90 To 100
Print &quot;A&quot;
Case 80 To 89
Print &quot;B&quot;
Case Is &gt;= 70
Print &quot;C&quot;
Case 60, 65
Print &quot;D (borderline)&quot;
Case Else
Print &quot;F&quot;
End Select</code></pre>
<p>CASE items can be combined with commas. The IS keyword allows comparison operators: &lt;, &gt;, &lt;=, &gt;=, =, &lt;&gt;.</p>
</div>
<div class="topic" id="lang.loops">
<h1>Loop Statements</h1>
<h2>FOR...NEXT</h2>
<p>Counted loop with an optional step value.</p>
<pre><code>FOR variable = start TO limit [STEP step]
statements
NEXT [variable]</code></pre>
<pre><code>For i = 1 To 10
Print i
Next i
For x = 10 To 0 Step -2
Print x
Next</code></pre>
<p>The variable name after NEXT is optional. Use EXIT FOR to break out early.</p>
<p>With an Integer or Long counter a constant STEP must be a whole number (STEP 0.5 is a compile error); a STEP computed at run time is rounded to the counter's type. A Single or Double counter takes any step.</p>
<h2>FOR EACH...NEXT</h2>
<p>Runs the loop once for every item in a Collection or every element of an array, without counting.</p>
<pre><code>FOR EACH item IN group
statements
NEXT [item]</code></pre>
<pre><code>Dim names As New Collection
names.Add &quot;Ann&quot;
names.Add &quot;Bob&quot;
Dim person As Variant
For Each person In names
Print &quot;Hello, &quot;; person
Next person
Dim scores(1 To 3) As Integer
Dim s As Variant
For Each s In scores
total = total + s
Next</code></pre>
<p>group can be a Collection, an array (of any number of dimensions; elements are visited in row order, the last subscript changing fastest), a Variant holding an array, or a ParamArray. On each pass item receives a copy of the next item: for a Collection of objects it refers to the object itself, but assigning a new value to item does not change the array or Collection. Declare item AS VARIANT, or as an object type for a Collection of objects. The number of items is checked on every pass, so items added or removed inside the loop are taken into account.</p>
<p>EXIT FOR leaves the loop early. Looping over something that is not an array or Collection raises error 13 (Type mismatch), or error 451 (Object not a collection) for an object that is not a Collection. EACH and IN are not reserved words.</p>
<h2>DO...LOOP</h2>
<p>General-purpose loop with pre-test, post-test, or infinite forms.</p>
<pre><code>DO [WHILE condition | UNTIL condition]
statements
LOOP [WHILE condition | UNTIL condition]</code></pre>
<pre><code>' Pre-test
Do While count &lt; 10
count = count + 1
Loop
' Post-test
Do
line$ = ReadLine()
Loop Until line$ = &quot;quit&quot;
' Infinite loop (exit with EXIT DO)
Do
DoEvents
If done Then Exit Do
Loop</code></pre>
<h2>WHILE...WEND</h2>
<p>Simple pre-test loop (legacy form; prefer DO...LOOP).</p>
<pre><code>WHILE condition
statements
WEND</code></pre>
<pre><code>While Not EOF(1)
Line Input #1, line$
Print line$
Wend</code></pre>
</div>
<div class="topic" id="lang.procedures">
<h1>Procedures</h1>
<h2>SUB...END SUB</h2>
<p>Defines a subroutine (no return value).</p>
<pre><code>SUB name ([BYVAL | BYREF] [OPTIONAL] param AS type, ...) [STATIC]
SUB name (arrayParam() AS type, ...)
statements
END SUB</code></pre>
<pre><code>Sub Greet(ByVal name As String)
Print &quot;Hello, &quot; &amp; name
End Sub</code></pre>
<p>A SUB, FUNCTION, or Property procedure stands on its own in the program: defining one inside another procedure, or inside an IF, FOR, DO, WHILE, SELECT CASE, or WITH block, is a compile error.</p>
<p>Parameters are passed by reference by default (nested calls pass the same variable on, so a SUB called from a SUB can still change the original); BYREF may be written out to say so, and BYVAL selects value semantics. A by-reference parameter is the caller's variable itself, as in Visual Basic: a write to it changes the variable at once (the caller's code, or another parameter naming the same variable, sees the new value straight away, even if the procedure later stops with an error), and what is stored is converted to the variable's own type (a STRING * n keeps its length). This holds for a plain variable, an array element (`bump a(3)` changes `a(3)` in place), a TYPE field (`bump rec.count`, `bump recs(2).count`, `bump rec.inner.count`) and, inside a class, one of the class's own member variables. While an array element (or a field of one) is passed by reference, its array cannot be given a new size or erased: REDIM of that array, or ERASE of it when it is a dynamic array, raises error 10 (This array is fixed or temporarily locked), as in Visual Basic (ERASE of a fixed-size array only clears its elements and is allowed). The array is free again as soon as the call returns. Assigning a whole TYPE value to the variable (or element) whose field is being passed copies the value into the same record, so the parameter sees the new value (as in Visual Basic). A parameter written as name() receives a whole array by reference; the caller passes `arr()` (or just `arr`), and the SUB may index, REDIM, or ERASE it. Use EXIT SUB to return early. A SUB is called either with or without parentheses; when used as a statement, parentheses are optional:</p>
<pre><code>Greet &quot;World&quot;
Greet(&quot;World&quot;)
Call Greet(&quot;World&quot;)</code></pre>
<p>As in Visual Basic and QBasic, a single argument in parentheses after the name of a SUB called without CALL (Bump (n), or Bump(n)) is an expression in parentheses, so it is passed by value: the SUB gets a copy and n is not changed. Write Bump n, or Call Bump(n), to pass n by reference.</p>
<p>An argument is converted to the type of a typed parameter (one declared with AS, a type suffix, or a DEFtype rule). A value -- a literal, an expression, a variable in its own parentheses, or anything given to a BYVAL parameter -- is converted the way an assignment would convert it (Report 3.7 gives an Integer parameter 4). A variable, array element, or TYPE field given to a by-reference parameter must have the parameter's own type, as in Visual Basic: an Integer parameter cannot be the caller's Double variable (&quot;ByRef argument type mismatch&quot; when the program is compiled); pass CINT(d), or (d) in its own parentheses, to pass a converted copy. A variable declared without a type (a Variant) holds any value and is passed as it is. Through an object variable declared As Object the procedure is only found when the program runs, so a variable of another type is passed as a converted copy instead.</p>
<pre><code>Sub Fill(v() As Integer, ByRef count As Integer)
ReDim v(9) As Integer
v(9) = 7
count = count + 1
End Sub
Dim a(3) As Integer
Dim n As Integer
Fill a(), n</code></pre>
<h3>Optional Parameters</h3>
<p>Mark a parameter OPTIONAL to allow callers to omit it. An optional parameter must be positioned after all required parameters. A caller can leave out the optional parameters at the end, or any optional parameter in the middle by writing nothing between the commas: Report a, , c. A left-out parameter of a type receives that type's empty value (0, &quot;&quot;, False, a date of 0, Nothing); a left-out Variant parameter is Missing, which ISMISSING detects. Leaving out a parameter that is not OPTIONAL is a compile error (Argument not optional).</p>
<pre><code>Sub Announce(ByVal msg As String, Optional ByVal loud As Integer)
If loud Then
Print UCase$(msg)
Else
Print msg
End If
End Sub
Announce &quot;hello&quot; ' loud defaults to 0
Announce &quot;hello&quot;, True ' loud is -1</code></pre>
<p>An OPTIONAL parameter can also name the value it takes when it is left out, after an equals sign: Optional count As Integer = 10. The default is a constant expression, like the value of a CONST: numbers, strings, dates, other constants, and the built-in functions CONST allows, converted to the parameter's type (a value that does not fit is a compile error). A parameter with a default is never Missing -- ISMISSING is False for it -- whether it is left out at the end, skipped between commas, or the procedure is reached through an object. Defaults work for SUB and FUNCTION procedures and for the procedures and Property procedures of class modules, including calls written before the procedure itself. As in Visual Basic the default is the one the declaration being called gives: a call through an interface (a variable declared As the interface class) passes the interface's default, even when the implementing class declares another. An object parameter (As Object, As Control, As Form, or As a class) can only have the default Nothing, as in Visual Basic: Optional target As Object = Nothing; a Variant parameter may have Nothing too. A default cannot be given to a required parameter, an array, or a TYPE, or in DEF FN and DECLARE LIBRARY. A DECLARE SUB / FUNCTION line must say whether each parameter has a default, as its definition does.</p>
<pre><code>Const SIDE = 10
Function Area(Optional w As Integer = SIDE, Optional h As Integer = SIDE * 2) As Long
Area = w * h
End Function
Print Area() ' 200
Print Area(2) ' 40
Print Area(, 3) ' 30</code></pre>
<p>ISMISSING works as in Visual Basic: only an OPTIONAL Variant parameter without a default can be Missing, and a Missing value passed on to another procedure's OPTIONAL Variant parameter is still Missing there. ISMISSING of anything else is False. Using a Missing value in any other way -- in arithmetic, in text, or storing it in a typed variable -- raises error 448.</p>
<pre><code>Sub Greet(ByVal name As String, Optional title As Variant)
If IsMissing(title) Then
Print &quot;Hello, &quot;; name
Else
Print &quot;Hello, &quot;; title; &quot; &quot;; name
End If
End Sub
Greet &quot;Ada&quot; ' Hello, Ada
Greet &quot;Ada&quot;, &quot;Countess&quot; ' Hello, Countess Ada</code></pre>
<h3>Named Arguments</h3>
<p>An argument can be given by the name of its parameter, followed by := and the value, as in Visual Basic. Named arguments come after any positional ones, in any order; the parameters left out must be OPTIONAL.</p>
<pre><code>Sub Report(ByVal title As String, Optional ByVal width As Integer = 40, Optional ByVal footer As String = &quot;&quot;)
Print title; width; footer
End Sub
Report &quot;Sales&quot;, footer:=&quot;(end)&quot; ' width is 40
Report width:=60, title:=&quot;Stock&quot;
Print Mid$(String:=&quot;hello&quot;, Start:=2) ' ello
MsgBox Prompt:=&quot;Saved&quot;, Title:=&quot;Notes&quot;</code></pre>
<p>Named arguments work for SUB and FUNCTION procedures, DEF FN functions, DECLARE LIBRARY procedures, and the procedures of class modules (through a variable of the class, or through an Object or Variant variable), and for the built-in functions that Visual Basic gives argument names to: MsgBox (Prompt, Buttons, Title), InputBox (Prompt, Title, Default), Mid (String, Start, Length), Left and Right (String, Length), InStr (Start, String1, String2), InStrRev (StringCheck, StringMatch, Start, Compare), Replace (Expression, Find, Replace, Start, Count, Compare), Split (Expression, Delimiter, Limit, Compare), Join (SourceArray, Delimiter), Filter (SourceArray, Match, Include, Compare), StrComp (String1, String2, Compare), String (Number, Character), Format (Expression, Format), IIf (Expression, TruePart, FalsePart), DateAdd (Interval, Number, Date), DateDiff and DatePart (Interval, Date1 and Date2 or Date, FirstDayOfWeek, FirstWeekOfYear), DateSerial (Year, Month, Day), TimeSerial (Hour, Minute, Second), Weekday (Date, FirstDayOfWeek), WeekdayName (Weekday, Abbreviate, FirstDayOfWeek), MonthName (Month, Abbreviate), and a Collection's Add (Item, Key, Before, After), Item, and Remove (Index).</p>
<p>A name the procedure does not have is a compile error (Named argument not found), and so is a parameter given twice. When the procedure is only found as the program runs (a method called through an Object or Variant variable) the same mistakes raise error 448 (Named argument not found) and error 450 (Wrong number of arguments). The methods of forms and controls do not take named arguments (error 446, Object doesn't support named arguments), and neither does a ParamArray parameter.</p>
<h3>ParamArray</h3>
<p>The last parameter of a SUB or FUNCTION can be marked PARAMARRAY to accept any number of extra arguments. It is written as an array, name(), and receives every remaining argument as an array numbered from 0. With no extra arguments the array is empty: UBOUND returns -1.</p>
<pre><code>Sub PrintAll(ByVal title As String, ParamArray items())
Dim i As Integer
Print title;
For i = 0 To UBound(items)
Print &quot; &quot;; items(i);
Next
Print
End Sub
PrintAll &quot;Totals:&quot;, 1, &quot;two&quot;, 3.5 ' three items: 0 To 2
PrintAll &quot;Nothing:&quot; ' UBound(items) is -1
Function Sum(ParamArray n() As Double) As Double
Dim i As Integer
Dim total As Double
For i = 0 To UBound(n)
total = total + n(i)
Next
Sum = total
End Function</code></pre>
<p>Without an AS clause (and no type suffix or DEFtype rule for the name) the ParamArray is an array of Variants (TYPENAME gives &quot;Variant()&quot;): each element holds the argument that was passed with its own type, so numbers, strings, and objects can be mixed, and FOR EACH can walk it. With an AS clause every argument is converted to that type. An argument that is a variable, a whole array, an array element (a(i), m(i, j)), a TYPE field (rec.f, arr(i).f, rec.inner.f) or, inside a class, one of the class's own member variables is passed by reference, as in Visual Basic: the element of the ParamArray is that variable, so a write to it changes the variable at once, converted to the variable's type (a value that cannot be converted raises its error at the assignment), and passing the element on (Bump v(0)) passes the variable. With an AS clause an argument is passed by reference only when its own type is that type; others are converted and passed by value. The same holds for a class's methods, whether the object variable is declared as the class or As Object / As Variant. While the call runs, the arrays whose elements were given are locked: REDIM of one of them (or ERASE of a dynamic one) raises error 10, as for any array element passed by reference. Copying the ParamArray (keep = v) copies the values, not the variables. Expressions and object properties are passed by value. Leaving an argument out (Sum 1, , 3) gives a Missing element. A PARAMARRAY cannot be combined with OPTIONAL parameters, cannot be BYVAL or BYREF, cannot hold a TYPE, and takes at most 31 arguments. It is not available in DEF FN or DECLARE LIBRARY.</p>
<h2>FUNCTION...END FUNCTION</h2>
<p>Defines a function with a return value.</p>
<pre><code>FUNCTION name ([BYVAL] [OPTIONAL] param AS type, ...) AS returnType [STATIC]
statements
name = returnValue
END FUNCTION</code></pre>
<p>STATIC after the header keeps every local variable of the SUB or FUNCTION between calls (see STATIC).</p>
<pre><code>Function Square(ByVal n As Double) As Double
Square = n * n
End Function</code></pre>
<p>Assign to the function name to set the return value. The value is converted to the function's type (AS clause, type suffix, or DEFtype), so FUNCTION F AS INTEGER with F = 2.5 returns 2. Inside the function its name on its own reads the value set so far (Total = Total + n), as in Visual Basic; with an argument list -- F() or F(n - 1) -- it calls the function again. Use EXIT FUNCTION to return early.</p>
<p>A FUNCTION can also be called as a statement, with or without parentheses; its result is discarded:</p>
<pre><code>Function Beep2(ByVal n As Integer) As Integer
Beep2 = n * 2
End Function
Beep2 3 ' result discarded</code></pre>
<p>name(...) in an expression calls a FUNCTION; using a SUB there is a compile error.</p>
<h3>Labels, GOSUB, and Variables in Procedures</h3>
<p>Labels belong to the SUB or FUNCTION they are written in (or to the module level). GOTO, GOSUB, ON ... GOTO/GOSUB and ON ERROR GOTO can only reach a label of the same procedure, and different procedures can reuse the same label name. GOSUB and RETURN work inside a procedure; see GOTO / GOSUB / RETURN. A procedure sees module variables only when they are SHARED; see Variable Scope and SHARED.</p>
<h2>DEF FN</h2>
<p>Defines a single-expression function. The function name begins with FN and is invoked just like a normal function. DEF FN functions cannot span multiple statements. A DEF FN must be defined before it is used, and only at module level (not inside a SUB or FUNCTION). Names in the expression other than the parameters are module variables, SHARED or not; the parameters are always passed by value.</p>
<pre><code>DEF FNname(params) = expression</code></pre>
<pre><code>Def FnSquare(x) = x * x
Print FnSquare(5) ' prints 25
Def FnCelsius(f As Double) = (f - 32) * 5 / 9
Print FnCelsius(212) ' prints 100</code></pre>
</div>
<div class="topic" id="lang.flow">
<h1>Flow Control</h1>
<h2>EXIT</h2>
<p>Exits the current block early.</p>
<pre><code>EXIT FOR
EXIT DO
EXIT SUB
EXIT FUNCTION
EXIT PROPERTY</code></pre>
<p>EXIT PROPERTY leaves a Property Get, Let, or Set procedure of a class module (see Objects and Class Modules).</p>
<h2>CALL</h2>
<p>Explicitly calls a subroutine or function. The return value (if any) is discarded.</p>
<pre><code>CALL name
CALL name(args)</code></pre>
<p>Normally you can omit CALL and just use the name directly.</p>
<h2>GOTO / GOSUB / RETURN</h2>
<pre><code>GOTO label
GOSUB label
RETURN</code></pre>
<p>A label is a name followed by a colon at the start of a line, or a line number at the start of a line (see Line Numbers below). Labels belong to the SUB or FUNCTION they are in (module-level labels to the module level): a jump can only reach a label of the same procedure, the same label name can be used in several procedures, and a label may have the same name as a variable. A jump to a label that is not defined in the procedure, or to a SUB or variable name, is a compile error.</p>
<p>GOSUB records where it was called from, runs the code at the label, and RETURN goes back to the statement after the GOSUB. This works at module level and inside a SUB or FUNCTION alike. Each procedure call has its own set of pending GOSUBs: RETURN only returns from a GOSUB made in the same procedure call, and leaving the procedure (END SUB, EXIT SUB, EXIT FUNCTION, or an error handled in a caller) discards the ones still pending. RETURN with no pending GOSUB raises error 3 (RETURN without GOSUB). To leave a SUB or FUNCTION, use EXIT SUB / EXIT FUNCTION.</p>
<pre><code>GoSub Initialize
Print &quot;Done&quot;
End
Initialize:
count = 0
name$ = &quot;&quot;
Return</code></pre>
<pre><code>Sub Report(n As Integer)
GoSub Heading
Print &quot;value&quot;; n
Exit Sub
Heading:
Print &quot;--- report ---&quot;
Return
End Sub</code></pre>
<h2>ON...GOTO / ON...GOSUB</h2>
<p>Computed branch based on an integer expression.</p>
<pre><code>ON expression GOTO label1, label2, ...
ON expression GOSUB label1, label2, ...</code></pre>
<p>If the expression evaluates to 1, control goes to the first label; 2, the second; and so on. If out of range, execution falls through. The labels follow the same rules as GOTO and GOSUB (same procedure only).</p>
<h2>Line Numbers</h2>
<p>As in QBasic, a line can start with a line number, a whole number from 0 to 65529. A line number is a label: GOTO, GOSUB, ON ... GOTO / GOSUB, ON ERROR GOTO, RESUME, and RESTORE can name it, it belongs to its procedure like any other label, and the same number cannot start two lines of a procedure. Numbers need not be in order, lines without a number are fine, and the number is read as a value, so 010 and 10 name the same line. IF can branch to a line number directly: IF x THEN 100 ELSE 200 is IF x THEN GOTO 100 ELSE GOTO 200, and IF x GOTO 100 works too.</p>
<pre><code>10 INPUT &quot;Guess&quot;; g
20 IF g = 7 THEN 50
30 PRINT &quot;No&quot;
40 GOTO 10
50 PRINT &quot;Yes&quot;</code></pre>
<p>In a program with line numbers, ERL gives the number of the last numbered line at or before the statement where the error happened (0 when there is none); in a program without them it gives the source line.</p>
</div>
<div class="topic" id="lang.io">
<h1>Input/Output Statements</h1>
<h2>PRINT</h2>
<p>Writes expressions to the output window, or to a file channel. Once the program has used a console or graphics statement (see Console and Graphics), PRINT writes on the program's screen instead, at the cursor, in the current COLOR.</p>
<pre><code>PRINT [expression [{; | ,} expression] ...]
PRINT #channel, expression [; expression] ...
PRINT USING format$; expression [; expression] ...</code></pre>
<ul>
<li>; between items -- no separator (items appear next to each other, or separated by a space for numbers)</li>
<li>, between items -- advance to the next 14-column tab zone</li>
<li>A trailing ; or , suppresses the newline normally written at the end of the statement (PRINT USING and PRINT # too)</li>
<li>? is an alias for PRINT</li>
</ul>
<p>PRINT # writes numbers exactly as PRINT shows them, with the space after each number, so PRINT #1, 1; 2 writes &quot;1 2 &quot;. PRINT #n, with nothing after the comma writes an empty line.</p>
<p>Special functions inside PRINT:</p>
<ul>
<li>SPC(n) -- print n spaces</li>
<li>TAB(n) -- advance to column n (first column is 1); when the cursor is already past column n, a new line is started first</li>
</ul>
<pre><code>Print &quot;Name:&quot;; Tab(20); name$
Print &quot;X=&quot;; x, &quot;Y=&quot;; y ' comma = next 14-column zone
Print #1, &quot;Written to file&quot;</code></pre>
<h2>LPRINT</h2>
<p>Prints on the printer instead of the screen. Everything PRINT accepts works the same way: ; and , between items, SPC, TAB, and LPRINT USING. The printer keeps its own column for TAB and the 14-column zones.</p>
<pre><code>LPRINT [expression [{; | ,} expression] ...]
LPRINT USING format$; expression [; expression] ...</code></pre>
<p>The output goes to the printer chosen in the Control Panel (a printer port, or a file). Each LPRINT is sent at once, and lines end the way printers expect. Nothing starts a new page by itself: LPRINT CHR$(12) ejects the page. If the printer has a problem (out of paper, off line), the user is asked to fix it and choose Retry, or Cancel; after Cancel the LPRINT raises error 57. With no printer to print on, LPRINT raises error 68.</p>
<pre><code>LPrint &quot;Invoice&quot;; Tab(40); Date$
LPrint Using &quot;Total: $$####.##&quot;; total
LPrint Chr$(12) ' eject the page</code></pre>
<p>For a whole document with margins, a header, a footer, and page numbers, and for the Print dialog, use the Printing Library (print.bas, see Include Libraries).</p>
<h3>PRINT USING</h3>
<p>PRINT USING formats each following expression according to a format string and prints the result. The expressions after the format are separated by ; or , (both work the same here). The format string is a mix of fields and literal text: each expression consumes the next field, the literal text before it is printed as it is, and the literal text after the last field is printed at the end. If more expressions are supplied than there are fields, the format string is reused from the start.</p>
<pre> Format character Meaning
---------------- -------
# Digit position; unused positions on the left become spaces
0 Digit position that is always printed (zero padded); the first 0 sets the minimum number of digits
. Decimal-point position
, Insert thousands separator
+ At start or end: always show a sign character
- At end: show a trailing minus sign only when negative
** At start: fill leading spaces with asterisks
$$ At start: floating dollar sign
^^^^ Anywhere: format the value in scientific notation
! First character of a string only
&amp; Entire string (variable length)
\ ... \ Fixed-length string field (width = 2 + number of spaces between backslashes)
_ The next character is printed literally</pre>
<p>A numeric field is as wide as its format characters; the value is right-aligned in it and a negative sign (or a leading +) floats directly in front of the first digit. A value that does not fit is printed in full with a leading %; a value too long to print in full is shown in scientific notation behind the %. A trailing + in a format with no digit positions is printed as literal text. A string expression must meet a string field and a numeric expression a numeric field, otherwise error 13 (Type mismatch) is raised.</p>
<pre><code>Print Using &quot;###.##&quot;; -3.14159 ' &quot; -3.14&quot;
Print Using &quot;+###&quot;; 42 ' &quot; +42&quot;
Print Using &quot;$$#,##0.00&quot;; 1234.5 ' &quot; $1,234.50&quot;
Print Using &quot;**#,##0.00&quot;; 42.5 ' &quot;*****42.50&quot;
Print Using &quot;###&quot;; 12345 ' &quot;%12345&quot;
Print Using &quot;####.####^^^^&quot;; 0.000123 ' scientific notation
Print Using &quot;\ \&quot;; &quot;Hello&quot; ' fixed-width 4-char: &quot;Hell&quot;
Print Using &quot;&amp; likes &amp;&quot;; name$; food$ ' &quot;Scott likes pizza&quot;
Print Using &quot;Total: ###.## units&quot;; 7.5 ' &quot;Total: 7.50 units&quot;
Print Using &quot;## and ##&quot;; 1; 2; 3 ' &quot; 1 and 2 3 and &quot;</code></pre>
<h2>INPUT</h2>
<p>Reads a line of text from the user or from a file channel. The user types it in a dialog box, or on the program's screen once it has one (see Console and Graphics).</p>
<pre><code>INPUT variable
INPUT &quot;prompt&quot;; variable
INPUT #channel, variable</code></pre>
<pre><code>Input &quot;Enter your name: &quot;; name$
Input #1, line$</code></pre>
<p>The target may be a variable, an array element, or a TYPE field (INPUT, INPUT #, LINE INPUT #, and READ alike). INPUT and INPUT # read a number into a numeric target the way VAL does (12abc gives 12).</p>
<h2>DATA / READ / RESTORE</h2>
<p>Inline data pool for constants.</p>
<pre><code>DATA value1, value2, &quot;string&quot;, ...
READ variable1, variable2, ...
RESTORE [label]</code></pre>
<p>DATA statements define a pool of values. READ reads the next value from the pool into a variable, array element, or TYPE field. RESTORE resets the read pointer to the beginning; RESTORE label (or a line number) makes the next READ take the first DATA item at or after that label. An item in quotes is a string; an unquoted item is taken as raw text up to the next comma, colon, comment, or end of line (so keywords, several words, and text such as 12abc are read as they are written) and converted when READ into a numeric variable, which raises error 13 (Type mismatch) when the item is not a number. The most negative Integer and Long values (-32768, -2147483648) are accepted.</p>
<pre><code>Data 10, 20, 30, &quot;Hello&quot;
Read a, b, c, msg$
Print a; b; c; msg$
Restore</code></pre>
</div>
<div class="topic" id="lang.misc">
<h1>Miscellaneous Statements</h1>
<h2>Error Handling</h2>
<pre><code>ON ERROR GOTO label ' Enable error handler
ON ERROR GOTO 0 ' Disable error handler
ON ERROR RESUME NEXT ' Go on at the next statement after any error
RESUME ' Retry the statement that caused the error
RESUME NEXT ' Continue at the next statement after the error
RESUME label ' Continue at a label or line number (RESUME 0 is RESUME)
ERROR n ' Raise a runtime error with error number n</code></pre>
<p>The ERR keyword returns the current error number (a Long) in expressions and ERL the source line the error was raised on, or in a program with line numbers the last line number at or before it (both are 0 when no error is active, and both reset after RESUME). RESUME or RESUME NEXT executed while no error is active raises error 20 (RESUME without error). ERROR n raises error n with its standard message (ERROR 11 reports &quot;Division by zero&quot;); numbers without a standard message report &quot;User-defined error&quot;.</p>
<p>Each SUB and FUNCTION has its own ON ERROR handler:</p>
<ul>
<li>An error is handled by the handler of the procedure it happens in; if that procedure has none, the calling procedures are searched outward.</li>
<li>A procedure called from a running handler can trap its own errors with its own handler.</li>
<li>Returning from a procedure that merely installed a handler leaves the caller's ERR and handler alone.</li>
<li>An error raised inside a running handler passes to the calling procedure's handler (untrapped if there is none).</li>
<li>The label named by ON ERROR GOTO must be in the same procedure.</li>
</ul>
<p>An error that no handler traps ends the program, as in Visual Basic, wherever it happens: in module-level code or in an event handler (a Click, a Timer, a form's Load ...). DVX shows it in a BASIC Runtime Error box -- the error number, the line, and the message -- and writes it to the DVX log; the program's windows close once the box is dismissed. In the IDE the Output window shows the error and the editor goes to its line.</p>
<p>ON ERROR RESUME NEXT, as in Visual Basic, needs no handler: a statement that fails is abandoned and the program goes on at the next one, with ERR (Err.Number) and Err.Description telling what went wrong. An error in a procedure that has no handler of its own leaves that procedure, and the program goes on after the statement that called it. The statement clears ERR, and so does the end of the procedure that used it; check ERR right after the statements that may fail:</p>
<pre><code>On Error Resume Next
Kill &quot;old.tmp&quot;
If Err.Number &lt;&gt; 0 Then Print &quot;Not deleted: &quot;; Err.Description
Err.Clear
On Error GoTo 0</code></pre>
<h3>The Err Object</h3>
<p>Err holds the current error the way ERR and ERROR do:</p>
<pre> Member Meaning
------ -------
Err or Err.Number The error number (0 when there is none); Err.Number = n sets it without raising it
Err.Description The error's message (&quot;&quot; when there is none)
Err.Source The source text the last Err.Raise gave (&quot;&quot; otherwise)
Err.Raise number [, source [, desc]] Raises error number (1 to 65535) with that source and description; without a description the number's standard message
Err.Clear Clears the error: ERR becomes 0, the description and source &quot;&quot;</pre>
<p>ERROR$(n) (or ERROR(n)) gives the standard message of error number n, &quot;User-defined error&quot; for a number without one, and &quot;&quot; for 0; without an argument, the current error's message.</p>
<pre><code>On Error GoTo Failed
Err.Raise 1001, &quot;Loader&quot;, &quot;The file has no header&quot;
Exit Sub
Failed:
Print Err.Number; Err.Description; &quot; (&quot;; Err.Source; &quot;)&quot;
Resume Next</code></pre>
<p>RESUME NEXT continues after the failing statement. When the error happened in the condition of an IF, ELSEIF, WHILE, DO, or LOOP, the condition counts as false (the block is skipped, the loop is left); after an error in a FOR statement the loop is skipped; after an error in the SELECT CASE expression the whole SELECT CASE block is skipped; after an error in a CASE test that test counts as false (the next value or CASE is tried); after an error in an ON ... GOTO/GOSUB selector no branch is taken and execution continues with the next statement.</p>
<pre><code>On Error GoTo ErrorHandler
Open &quot;missing.txt&quot; For Input As #1
Exit Sub
ErrorHandler:
Print &quot;Error number:&quot;; Err; &quot;on line&quot;; Erl
Resume Next</code></pre>
<h3>Common Error Numbers</h3>
<pre> Number Meaning
------ -------
1 FOR loop error (NEXT without FOR, NEXT variable mismatch, FOR stack underflow)
3 RETURN without GOSUB
4 Out of DATA
5 Illegal function call (bad argument to a built-in function; an undefined math result such as a negative number to a fractional power)
6 Overflow (value does not fit the target type; EXP, ^, or other math leaving the numeric range; a file size or position past 2 GB in LOF, FILELEN, LOC, SEEK, GET, or PUT)
7 Out of memory
9 Subscript out of range / invalid variable or field index
10 This array is fixed or temporarily locked (REDIM, or ERASE of a dynamic array, while one of its elements, or a field of one, is passed by reference to a procedure that is still running)
11 Division by zero
13 Type mismatch (text that is not a number where a number is needed) / not an array / not a TYPE instance
14 Out of string space (no memory to build a string)
18 User interrupt occurred (a control's code ran too long without returning and was stopped)
20 RESUME without error
26 FOR loop nesting too deep
28 Out of stack space (calls or expressions nested too deeply)
51 Internal error (bad opcode)
52 Bad file number or file not open
53 File not found (OPEN for INPUT, KILL, FILELEN, ...)
54 Bad file mode (also: a printer opened for anything but OUTPUT or APPEND)
57 Device I/O error (printing failed or was cancelled)
58 File already exists or rename failed
59 Bad record length (OPEN ... LEN must be 1 to 32767; GET/PUT data longer than LEN)
63 Bad record number (SEEK, GET, or PUT position below 1)
64 Bad file name (WIDTH of a device DVX does not have)
67 Too many files open
68 Device unavailable (no printer to print on)
75 Path/file access error
76 Path not found
91 Object variable not set (property, method, Show/Hide/Unload on a value that is not a form or control, or on Nothing)
93 Invalid pattern string (a LIKE pattern with a [ that has no ])
94 Invalid use of Null (Null where a real number or text is needed; see Variants)
424 Object required (SET, Is, or TypeOf with a value that is not an object)
438 Object doesn't support this property or method (the object has no member of that name, or it is Private)
446 Object doesn't support named arguments (a form or control method called with Name:=value)
448 Named argument not found (a Name:= the method does not have; a left-out OPTIONAL Variant argument, Missing, used as a value)
449 Argument not optional (a method call through an object left out a parameter that is not OPTIONAL)
450 Wrong number of arguments or invalid property assignment
451 Object not a collection (FOR EACH over an object that is not a Collection)
453 Library or function not installed (a DECLARE LIBRARY function whose library is not on this computer; see Include Libraries)
457 This key is already associated with an element of this collection (Collection.Add with a key in use)
481 Invalid picture (LOADPICTURE of a file that is not a picture DVX can show)
1000 No form runtime (a form or control statement ran without the form runtime, e.g. under a headless runner)</pre>
<h2>SHELL</h2>
<p>Executes an operating-system command.</p>
<pre><code>SHELL &quot;command&quot;</code></pre>
<p>When used as a function, SHELL returns the exit code of the command, or -1 when it did not run.</p>
<pre><code>Shell &quot;DIR /B&quot;
exitCode = Shell(&quot;COPY A.TXT B.TXT&quot;)</code></pre>
<p>DVX steps aside while the command runs, as it does for a DOS program started from Program Manager: the screen goes back to text, and the command has the keyboard, the mouse, and the hardware to itself. Nothing of DVX runs meanwhile, so the other programs that are running are named first and asked to close (your program stays and waits); choosing No, or a program that keeps a window open, means the command does not run (-1). When the command ends, the desktop comes back and your program goes on. A command that prints and ends at once is gone from the screen as soon as it ends: ShellRunDos (shell.bas) can wait for a key first.</p>
<p>The command goes to DOS as it is written. DOS commands read / as the start of a switch (DIR /B), so write the paths in a command with \ (SHELL &quot;DEL C:\TEMP\X.TXT&quot;); FileOpsPathNative$ (fileops.bas) turns a path built with / into that form. Everywhere else in DVX BASIC a path may use / or \.</p>
<h2>SLEEP</h2>
<p>Pauses execution for the given number of seconds. With no argument, sleeps for 1 second. The desktop and the program's own forms keep running while it sleeps, SLEEP 0 just lets pending events run, and closing the program ends the sleep.</p>
<pre><code>SLEEP [seconds]</code></pre>
<h2>RANDOMIZE</h2>
<p>Seeds the random number generator. Without an argument (not shown here) and without a prior RANDOMIZE, the sequence is the same on every run. Use RANDOMIZE TIMER to get a different sequence each run.</p>
<pre><code>RANDOMIZE seed
RANDOMIZE TIMER ' Seed from system clock</code></pre>
<h2>END</h2>
<p>Terminates program execution immediately. Any form that is loaded is unloaded before the program exits.</p>
<pre><code>END</code></pre>
</div>
<div class="topic" id="lang.sound">
<h1>Sound, Joysticks, and Frames</h1>
<p>These statements work as they do in QBasic, on whatever sound hardware the computer has: a sound card, the PC speaker, or none at all, in which case the program runs the same but silently. Several programs can make sound at once. For sound files, tones of any shape, and music files, see the sound.bas and music.bas include libraries; for more joystick detail, joystick.bas.</p>
<h2>BEEP</h2>
<p>Sounds a short beep (800 hertz for a quarter of a second).</p>
<pre><code>BEEP</code></pre>
<h2>SOUND</h2>
<p>Plays a tone of frequency hertz (37 to 32767) for duration clock ticks; there are 18.2 ticks in a second, and fractions are allowed. A duration of 0 stops every sound the program has queued. Frequencies too high to hear (above 20000) are silent. Anything out of range is error 5 (Illegal function call).</p>
<pre><code>SOUND frequency, duration
SOUND 440, 18.2 ' A for one second
SOUND 440, 0 ' stop</code></pre>
<h2>PLAY</h2>
<p>Plays a tune written in the music macro language. Letters may be upper or lower case and spaces are ignored. The settings (octave, length, tempo, style, instrument, foreground or background) stay from one PLAY to the next.</p>
<pre><code>PLAY commands$
PLAY &quot;T160 O3 L8 E D C D E E E4&quot;</code></pre>
<pre> Command Meaning
------- -------
A to G Play the note in the current octave. Follow it with # or + for sharp, - for flat, then optionally a length (1 to 64, as for L) and dots.
N n Play note n (1 to 84, seven octaves from the lowest C); N0 is a rest.
O n Octave 0 to 6 (default 4). Octave 3 starts at middle C.
&gt; and &lt; Go up or down one octave.
L n Length of the notes that follow: 1 a whole note, 2 a half, 4 a quarter (the default) ... 64.
P n Pause (rest) of length n (1 to 64).
. A dot after a note or pause makes it half as long again; each further dot adds half again.
T n Tempo in quarter notes a minute (32 to 255, default 120).
MN Music normal: each note sounds for 7/8 of its length (the default).
ML Music legato: notes sound for their whole length.
MS Music staccato: notes sound for 3/4 of their length.
MF Music foreground: PLAY, SOUND, and BEEP wait until the sound has finished (the default).
MB Music background: the program goes on while the music plays; it only waits when more than 32 notes are waiting.
I n DVX's own: play the notes that follow on General MIDI instrument n (1 to 128; 1 is the piano, 41 the violin, 74 the flute) through the music synthesizer. I0 goes back to plain tones (the default).
V n Volume of the notes that follow, 0 to 100 percent (default 100), as in QB64. On an instrument it sets how hard the note is played.
@ n Waveform of the tones that follow, as in QB64: @1 square (the default, like the PC speaker), @3 triangle (softer), @5 noise (drums, explosions). QB64's @2 and @4 are not available.
X &quot;X&quot; + VARPTR$(s$) plays the commands in s$ at that point (s$ may use X itself, up to 16 levels deep).
= Any number above may be written as &quot;=&quot; + VARPTR$(n), n a numeric expression: &quot;T=&quot; + VARPTR$(tempo).</pre>
<p>A string with a mistake in it plays nothing and raises error 5 (Illegal function call). X and &quot;=&quot; work as in QBasic, with VARPTR$ as for DRAW (see the program screen's DRAW): the value is taken when VARPTR$ runs. A whole tune may be at most 32767 characters once X and &quot;=&quot; are filled in.</p>
<pre><code>verse$ = &quot;L8 E D C D E E E4&quot;
tempo = 160
PLAY &quot;T=&quot; + VARPTR$(tempo) + &quot;O3 X&quot; + VARPTR$(verse$) + &quot;X&quot; + VARPTR$(verse$)</code></pre>
<p>Building the string with + works too, such as PLAY &quot;O&quot; + STR$(n). Without I, the notes are tones -- square waves like the PC speaker's unless @ chooses another -- and with it, they play on the same synthesizer as MIDI music. The PC speaker plays only square tones at one volume: there V and @ make no difference, except that V0 is silent.</p>
<pre><code>PLAY &quot;MB T120 L4 CDEF GAB&gt;C&quot; ' a scale in the background
PLAY &quot;I74 O4 L8 GAB&gt;C&quot; ' on the flute
PLAY &quot;@3 V60 L8 CEG&gt;C&quot; ' softer, quieter</code></pre>
<h2>PLAY Function</h2>
<p>PLAY(n) returns how many notes are still waiting to be played in the background (n is ignored). A game can use it to keep its music going:</p>
<pre><code>If PLAY(0) &lt; 4 Then PLAY &quot;MB &quot; + tune$</code></pre>
<h2>STICK and STRIG</h2>
<p>STICK(n) returns where a joystick points, from 1 (all the way left or up) to 200 (all the way right or down), about 100 in the middle, or 0 when there is no such joystick. STICK(0) reads joystick A's X and remembers A's Y and joystick B's X and Y, which STICK(1), STICK(2), and STICK(3) then return; so call STICK(0) first.</p>
<p>STRIG(n) returns True (-1) or False (0) for the buttons:</p>
<pre> n Returns True when
- -----------------
0 joystick A's first button was pressed since the last STRIG(0)
1 joystick A's first button is down
2 joystick B's first button was pressed since the last STRIG(2)
3 joystick B's first button is down
4 joystick A's second button was pressed since the last STRIG(4)
5 joystick A's second button is down
6 joystick B's second button was pressed since the last STRIG(6)
7 joystick B's second button is down</pre>
<p>Joystick A is the first joystick; joystick B the second one, or the second stick of a joystick with four axes. When no joystick is connected the keyboard stands in for joystick A (see the Control Panel's Game Controllers tab). STRIG ON, STRIG OFF, and ON STRIG are not supported; test STRIG in a Timer or a loop instead.</p>
<pre><code>x = STICK(0)
y = STICK(1)
If STRIG(0) Then FireShot</code></pre>
<h2>FRAMEWAIT</h2>
<p>Waits until the next frame of a steady clock of rate frames a second begins, keeping the desktop and the program's forms running meanwhile. A game loop that calls it once a frame runs at the same speed on every computer. Frames the program was too busy for are skipped, not caught up; FrameMissed() in game.bas counts them. rate must be at least 1; rates above 1000 count as 1000. Changing the rate starts the clock over.</p>
<pre><code>FRAMEWAIT rate
Do
MoveEverything
DrawEverything
FRAMEWAIT 30
Loop Until quitting</code></pre>
</div>
<div class="topic" id="lang.screen">
<h1>Console and Graphics</h1>
<p>These statements work as they do in QBasic. The first one a program uses gives it a screen of its own: a window, titled with the program's name, the size of the screen mode. From then on PRINT and INPUT use that screen too (before it, PRINT writes to the output window and INPUT asks in a dialog box, as always). Keys typed in the window go to INKEY$ and INPUT. The window stays open when the program's code has finished, so its output can be read; closing it ends the program.</p>
<p>The names are not reserved: a program that has its own variable, SUB, or constant called Color, Cls, Draw, and so on keeps using it.</p>
<h2>Screen Modes</h2>
<pre> Mode Size and colours Text (WIDTH choices) Pages
---- ---------------- -------------------- -----
SCREEN 0 Text only, 16 colours 80 or 40 x 25, 43 or 50 8 (4 at 80 x 43, 80 x 50)
SCREEN 1 320 x 200, 4 colours (two palettes) 40 x 25 1
SCREEN 2 640 x 200, 2 colours 80 x 25 1
SCREEN 7 320 x 200, 16 colours 40 x 25 8
SCREEN 8 640 x 200, 16 colours 80 x 25 4
SCREEN 9 640 x 350, 16 of 64 colours 80 x 25 or 80 x 43 2
SCREEN 10 640 x 350, 4 shades (some blinking) 80 x 25 or 80 x 43 2
SCREEN 11 640 x 480, 2 colours 80 x 30 or 80 x 60 1
SCREEN 12 640 x 480, 16 colours 80 x 30 or 80 x 60 1
SCREEN 13 320 x 200, 256 colours 40 x 25 1</pre>
<p>A program starts in SCREEN 0. SCREEN with a new mode (and WIDTH) clears the screen and restores the mode's colours: the 16 standard colours, and in SCREEN 13 the standard 256-colour palette. SCREEN with the mode the program is already in only changes the pages, so a program can flip pages in a loop. Other mode numbers, and graphics statements in SCREEN 0, are error 5 (Illegal function call). The colour switch argument is accepted and ignored.</p>
<p>Text uses 16-pixel-high characters in SCREEN 0 (25 rows), 11 and 12 (30 rows), 14-pixel ones in SCREEN 9 and 10 (25 rows), and 8-pixel ones everywhere else. The window shows each mode in the shape it has on a monitor: the 640 x 200 modes with every line doubled, 40-column text with every column doubled; SCREEN 9 and 10 show at 640 x 350 as they are. On the whole screen the 320 x 200 modes use the computer's 320 x 200 mode and the others the nearest mode, centred.</p>
<pre><code>SCREEN mode [, [colorswitch] [, [activepage] [, visualpage]]]
WIDTH [columns] [, rows]</code></pre>
<h2>Screen Pages and PCOPY</h2>
<p>The pages of a mode (see the table) are separate screens. Drawing and PRINT go to the active page; the window shows the visual page. Drawing on a page that is not shown and then showing it (or copying it to the shown page) gives smooth animation. A visual page left out follows the active page. In SCREEN 0 each page has its own text. Each page also keeps its own text cursor, as in QBasic: LOCATE and PRINT move the active page's cursor, and switching pages brings back the cursor where it was on that page.</p>
<pre><code>SCREEN 7, , 1, 0 ' draw on page 1, show page 0
Do
CLS
CIRCLE (x, 100), 20, 14
PCOPY 1, 0 ' show the finished picture
x = (x + 2) MOD 320
FRAMEWAIT 30
Loop</code></pre>
<p>PCOPY source, destination copies one page (text and pixels) onto another. A page number the mode does not have is error 5.</p>
<h2>FULLSCREEN</h2>
<p>Shows the program's screen on the whole screen, or back in its window. Alt+Enter in the window does the same. While the program has the whole screen, Alt+Tab brings the desktop back (the program keeps running in its window) and switching back to the program returns it to the whole screen. Other programs keep running either way. When the computer has no suitable video mode, the screen stays in its window.</p>
<pre><code>FULLSCREEN [ON | OFF]
FULLSCREEN expression ' True: whole screen, False: window
isFull = FULLSCREEN ' True while the program's screen has the whole screen</code></pre>
<p>Used as a value, FULLSCREEN tells whether the program's screen has the whole screen (also while the desktop is shown for another program, since the screen comes back with the focus): False when no suitable video mode could be set, or before SCREEN or any drawing made a screen. A form takes the whole screen with its FullScreen property instead.</p>
<h2>Text: CLS, LOCATE, COLOR, CSRLIN, POS, SCREEN( )</h2>
<pre><code>CLS [n]
LOCATE [row] [, [column] [, cursor]]
COLOR [foreground] [, background]
row = CSRLIN
column = POS(0)
code = SCREEN(row, column [, colorflag])</code></pre>
<ul>
<li>CLS clears the screen and puts the cursor in the top-left corner (the top of the text viewport). In a graphics mode with a VIEW set, CLS (or CLS 1) clears only the view; with a VIEW PRINT set, CLS (or CLS 2) clears only the text viewport; CLS 0 clears everything.</li>
<li>LOCATE moves the cursor (rows and columns count from 1). cursor 1 shows the text cursor in SCREEN 0, 0 hides it (the default). QBasic's cursor size arguments are accepted and ignored.</li>
<li>COLOR in SCREEN 0 takes a foreground 0 to 31 and a background 0 to 15. Foregrounds 16 to 31 blink (colour minus 16); as on a VGA, backgrounds 8 to 15 show as 0 to 7 and make the text blink too.</li>
<li>COLOR in SCREEN 1 takes a background colour (0 to 15) and a palette: an even number gives green, red, and brown for colours 1 to 3, an odd one (the default) cyan, magenta, and white. SCREEN 2 has no COLOR statement. In SCREEN 7 to 10 COLOR takes a foreground and a background colour (the colour of attribute 0: 0 to 15 in SCREEN 7 and 8, an EGA colour 0 to 63 in SCREEN 9, a shade 0 to 8 in SCREEN 10). In SCREEN 11 to 13 it takes only a foreground. The foreground is also the default colour of the drawing statements.</li>
<li>CSRLIN is the cursor's row and POS(0) its column. Before the program has a screen, POS(0) is the output window's column.</li>
<li>SCREEN(row, column) is the character code shown there; with a colorflag of 1, its colour (in SCREEN 0, foreground + 16 * background).</li>
<li>PRINT scrolls the screen (or the text viewport) up at the bottom. CHR$(13) and CHR$(10) start a new line and CHR$(9) moves to the next multiple of 8 columns.</li>
</ul>
<h2>VIEW PRINT</h2>
<p>Makes rows top to bottom the text viewport: PRINT scrolls only those rows, so the rows around them stay as they are (a title, a status line). The cursor goes to the viewport's first row. VIEW PRINT alone makes the whole screen the viewport again. LOCATE can still reach every row.</p>
<pre><code>VIEW PRINT [top TO bottom]</code></pre>
<h2>INKEY$</h2>
<p>Returns the next key typed in the program's window without waiting: &quot;&quot; when there is none, one character for a character key, and CHR$(0) + CHR$(scan code) for other keys (arrows, function keys). Keys held with Alt, and function keys held with Shift, Ctrl, or Alt, give the codes QBasic gives: Alt+A is CHR$(0) + CHR$(30), Alt+1 CHR$(0) + CHR$(120), Shift+F1 CHR$(0) + CHR$(84), Ctrl+F1 CHR$(0) + CHR$(94), and Alt+F1 CHR$(0) + CHR$(104). Keys wait for INKEY$ in a queue of 64.</p>
<pre><code>Do
k$ = INKEY$
Loop While k$ = &quot;&quot;
If k$ = Chr$(0) + Chr$(72) Then Print &quot;Up arrow&quot;</code></pre>
<h2>PEN</h2>
<p>QBasic's light pen; the mouse on the program's screen stands in for it, as the mouse drivers of the time did. PEN ON lets the program read it, PEN OFF stops that (PEN STOP is accepted too). PEN(n) then tells:</p>
<pre> n PEN(n)
- ------
0 True (-1) if the left button went down since PEN(0) was last read, else 0
1, 2 x and y (pixels) where it last went down
3 True (-1) while the left button is down, else 0
4, 5 x and y where the mouse last was over the screen
6, 7 text row and column where it last went down
8, 9 text row and column where it last was</pre>
<p>PEN(n) before PEN ON, after PEN OFF, or with another n raises error 5.</p>
<pre><code>Screen 12
Pen On
Do
If Pen(0) Then PSet (Pen(1), Pen(2)), 14
Loop While InKey$ = &quot;&quot;</code></pre>
<h2>INPUT and LINE INPUT on the Screen</h2>
<p>On the program's screen INPUT shows its prompt at the cursor and reads what is typed there: Backspace takes back a character, Esc clears the line, and Enter ends it. LINE INPUT reads a whole line, commas included, without adding &quot;? &quot; to the prompt. Without the program's screen LINE INPUT asks in a dialog box, like INPUT.</p>
<pre><code>LINE INPUT [&quot;prompt&quot;;] variable$</code></pre>
<h2>Graphics Coordinates</h2>
<p>Points are (x, y) in pixels from the top-left corner. STEP(x, y) is relative to the last point drawn (the centre of the screen at first). VIEW makes a smaller part of the screen the drawing area (coordinates start at its corner, and drawing stays inside it); WINDOW gives it coordinates of your own. Colour numbers are attributes: 0 to 3 in SCREEN 1 and 10, 0 and 1 in SCREEN 2 and 11, 0 to 15 in SCREEN 7, 8, 9, and 12, 0 to 255 in SCREEN 13; anything else is error 5.</p>
<pre><code>VIEW [[SCREEN] (x1, y1)-(x2, y2) [, [fill] [, border]]]
WINDOW [[SCREEN] (x1, y1)-(x2, y2)]
value = PMAP(coordinate, n)</code></pre>
<ul>
<li>VIEW with coordinates of its own sets the view; fill fills it and border draws a frame around it. VIEW SCREEN keeps coordinates counting from the screen's corner. VIEW alone is the whole screen again.</li>
<li>WINDOW (x1, y1)-(x2, y2) maps the view to those coordinates with y going up; WINDOW SCREEN keeps y going down. WINDOW alone goes back to pixels.</li>
<li>PMAP converts between WINDOW coordinates and pixels of the view: n = 0 gives the pixel column of an x, 1 the pixel row of a y, 2 the x of a pixel column, and 3 the y of a pixel row. Without a WINDOW both are pixels.</li>
</ul>
<h2>PSET, PRESET, POINT</h2>
<pre><code>PSET [STEP](x, y) [, color]
PRESET [STEP](x, y) [, color]
c = POINT(x, y)
v = POINT(n)</code></pre>
<p>PSET draws a point in the given colour or the COLOR foreground, PRESET in the given colour or colour 0. POINT(x, y) is the colour at a point, or -1 outside the view. POINT(0) and POINT(1) are the last point in pixels, POINT(2) and POINT(3) in WINDOW coordinates.</p>
<h2>LINE</h2>
<pre><code>LINE [[STEP](x1, y1)]-[STEP](x2, y2) [, [color] [, [B | BF] [, style]]]</code></pre>
<p>Draws a line, a box (B), or a filled box (BF). Without a start point the line starts at the last point. style is a 16-bit pattern: each set bit (from the top) draws a pixel, each clear one skips it.</p>
<pre><code>LINE (10, 10)-(100, 50), 4, BF
LINE -STEP(20, 0), 15
LINE (0, 100)-(319, 100), 7, , &amp;HF0F0</code></pre>
<h2>CIRCLE</h2>
<pre><code>CIRCLE [STEP](x, y), radius [, [color] [, [start] [, [end] [, aspect]]]]</code></pre>
<p>Draws a circle, an ellipse, or an arc. start and end are angles in radians (0 to 2 * pi, counterclockwise from the right); a negative angle also draws the radius to that end, so CIRCLE can draw pie slices. aspect is the height divided by the width; the default makes circles round on a 4:3 monitor (0.83 in SCREEN 13, 1 in SCREEN 12), so in SCREEN 13 a circle in the window looks slightly flat and a round one needs aspect 1.</p>
<pre><code>CIRCLE (160, 100), 50, 14
CIRCLE (160, 100), 50, 4, -0.0001, -1.5708 ' a quarter pie slice
CIRCLE (160, 100), 80, 2, , , 0.5 ' an ellipse</code></pre>
<h2>PAINT</h2>
<pre><code>PAINT [STEP](x, y) [, [color] [, border]]
PAINT [STEP](x, y), tile$ [, [border] [, background$]]</code></pre>
<p>Fills the area around the point with color, up to pixels of the border colour (by default the fill colour itself).</p>
<p>With a string instead of a colour, PAINT fills the area with a pattern, as in QBasic. Each row of the pattern is one byte for each colour plane of the mode, and each bit is a pixel (the first bit is the left pixel): in SCREEN 2 and 11 one byte is eight pixels, colour 0 or 1; in SCREEN 7, 8, 9, and 12 four bytes (the blue, green, red, and bright planes) make eight pixels of 16 colours; in SCREEN 10 two bytes. In SCREEN 1 each byte is four pixels of two bits, and in SCREEN 13 each byte is one pixel. A pattern has up to 64 rows and repeats over the screen. The fill stops at the border colour (by default the COLOR foreground) and covers the whole area once, even where it already has the pattern's colours. background$ is accepted as in QBasic: a pattern with more than two rows in a row equal to it is error 5.</p>
<pre><code>SCREEN 12
LINE (0, 0)-(100, 100), 15, B
PAINT (50, 50), CHR$(&amp;HAA) + CHR$(&amp;H55) + CHR$(0) + CHR$(0), 15 ' blue and green stripes</code></pre>
<h2>DRAW</h2>
<p>Draws with a small command language. Letters may be upper or lower case; spaces and semicolons are ignored.</p>
<pre> Command Meaning
------- -------
U n Up n (without n: 1).
D n Down n.
L n Left n.
R n Right n.
E n Diagonally up and right.
F n Diagonally down and right.
G n Diagonally down and left.
H n Diagonally up and left.
M x,y Move to x, y; with a sign (M+10,-5) move by that much.
B Before a move: move without drawing.
N Before a move: draw, then come back to where the move started.
C n Colour of the lines that follow.
S n Scale: moves are n/4 pixels a unit (1 to 255, default 4).
A n Turn the directions by n * 90 degrees (0 to 3).
TA n Turn the directions by n degrees (-360 to 360).
P c,b PAINT at the current point with colour c up to border colour b.</pre>
<p>The pen starts at the last point and stays where it ends. The colour, scale, and turn stay from one DRAW to the next. A mistake in the string is error 5.</p>
<p>As in QBasic, X runs another DRAW string and &quot;=&quot; takes a number, both given with VARPTR$: DRAW &quot;X&quot; + VARPTR$(shape$) and DRAW &quot;C=&quot; + VARPTR$(c) + &quot;R=&quot; + VARPTR$(n). DVX BASIC has no memory addresses, so VARPTR$ packs the value itself into its result (taken when VARPTR$ runs), and it takes any expression. Building the string with + and STR$ works too, such as DRAW &quot;R&quot; + STR$(n).</p>
<pre><code>DRAW &quot;BM100,100 C14 R50 D50 L50 U50&quot; ' a square
DRAW &quot;BM160,100 TA45 C2 R40&quot; ' a line at 45 degrees
box$ = &quot;R10 D10 L10 U10&quot;
FOR i = 1 TO 5
DRAW &quot;BM&quot; + STR$(i * 20) + &quot;,20 X&quot; + VARPTR$(box$)
NEXT i</code></pre>
<h2>PALETTE</h2>
<pre><code>PALETTE [attribute, color]
PALETTE USING array[(first)]</code></pre>
<p>Changes the colour an attribute shows. In SCREEN 11, 12, and 13, color is blue * 65536 + green * 256 + red with each part 0 to 63; in SCREEN 0 and 9 it is an EGA colour number 0 to 63; in SCREEN 1, 2, 7, and 8 one of the 16 standard colours; in SCREEN 10 a shade 0 to 8 (0 off, 4 grey, 8 bright, and 1 to 3, 5 to 7 blinking between two of them). PALETTE alone restores the mode's colours. PALETTE USING sets every attribute of the mode (256 in SCREEN 13) from a one-dimensional LONG array starting at element first (or its first element); -1 leaves that attribute as it is. On the whole screen a palette change shows at once, like on a VGA card; in the window, whatever is already drawn in that attribute changes colour too.</p>
<pre><code>SCREEN 13
PALETTE 1, 63 * 65536 ' attribute 1 becomes bright blue
FOR i = 0 TO 63
PALETTE 2, i ' a red that fades in
FRAMEWAIT 30
NEXT i</code></pre>
<h2>Example</h2>
<pre><code>SCREEN 13
CLS
COLOR 14
PRINT &quot;Press a key&quot;
CIRCLE (160, 100), 60, 4
PAINT (160, 100), 1, 4
LINE (0, 0)-(319, 199), 15, B
DRAW &quot;BM150,90 C15 R20 D20 L20 U20&quot;
Do
Loop While INKEY$ = &quot;&quot;
FULLSCREEN
Do
Loop While INKEY$ = &quot;&quot;</code></pre>
<h2>Writing a Screen Saver</h2>
<p>A screen saver is a program with no form that shows its screen on the whole screen and draws until DVX closes it. Put the program (.app) in the SAVERS folder of your user folder (FileOpsKindDir$(FILEOPS_KIND_SAVERS, True)); it is then listed on Control Panel's Desktop page by its project Name. DVX starts it with the command line /S after the wait with no input, and closes its screen at the next key or mouse movement, which ends the program, so it needs no INKEY$ of its own.</p>
<pre><code>SCREEN 13
CLS
FULLSCREEN ON
DO
' draw a frame
FRAMEWAIT 30
LOOP</code></pre>
<p>SysScreenSaver$, SysSetScreenSaver, SysScreenSaverStart, and SysIdleSeconds (system.bas) read and change the screen saver from a program.</p>
</div>
<div class="topic" id="lang.fileio">
<h1>File I/O</h1>
<h2>OPEN</h2>
<p>Opens a file for reading, writing, or appending.</p>
<pre><code>OPEN filename$ FOR INPUT AS #channel
OPEN filename$ FOR OUTPUT AS #channel
OPEN filename$ FOR APPEND AS #channel
OPEN filename$ FOR RANDOM AS #channel [LEN = recordSize]
OPEN filename$ FOR BINARY AS #channel</code></pre>
<pre> Mode Description
---- -----------
INPUT Open for sequential reading. File must exist.
OUTPUT Open for sequential writing. Creates or truncates.
APPEND Open for sequential writing at end of file.
RANDOM Open for random-access record I/O. LEN sets the record size in bytes (default 128).
BINARY Open for raw binary I/O.</pre>
<h3>Printing Through OPEN</h3>
<p>The names LPT1:, LPT2:, LPT3: (a printer port) and PRN (the printer chosen in the Control Panel) open a printer, in any case and with or without the colon. Only OUTPUT and APPEND work (anything else raises error 54). PRINT # and WRITE # collect the output, and CLOSE sends it to the printer; a printer problem the user cancels makes CLOSE raise error 57, and a printer that cannot be reached makes OPEN raise error 68.</p>
<pre><code>Open &quot;LPT1:&quot; For Output As #1
Print #1, &quot;Line one&quot;
Print #1, &quot;Line two&quot;
Close #1 ' now it prints</code></pre>
<h2>CLOSE</h2>
<p>Closes open file channels.</p>
<pre><code>CLOSE #channel
CLOSE #channel, #channel, ...
CLOSE
RESET</code></pre>
<p>CLOSE with a list closes each channel in it (the # is optional); CLOSE alone, and RESET, close every open file. Closing a channel that is not open does nothing; a number outside the channels DVX has raises error 52.</p>
<h2>PRINT #</h2>
<p>Writes text to a file, formatted exactly as PRINT shows it: numbers are followed by a space, a comma moves to the next 14-column zone, a semicolon keeps the line going, and TAB(n), SPC(n), and PRINT #channel, USING work as they do for PRINT. See PRINT.</p>
<pre><code>PRINT #channel, expression [; | , expression ...]
PRINT #channel, USING format$; expression [; expression ...]</code></pre>
<h2>WIDTH #</h2>
<p>Sets the line width of an open file, the screen, or the printer: output longer than the width goes on in a new line, as in QBasic. 255 means no limit (the default).</p>
<pre><code>WIDTH #channel, width
WIDTH &quot;SCRN:&quot;, width
WIDTH &quot;LPT1:&quot;, width
WIDTH LPRINT width</code></pre>
<p>WIDTH &quot;SCRN:&quot; is the same as WIDTH width for the program's screen. WIDTH &quot;LPT1:&quot; (LPT2:, LPT3:, PRN) and WIDTH LPRINT set the width of the printer's lines, for LPRINT and for files opened on that printer afterwards. A width outside 1 to 255 raises error 5, a file number that is not open error 52, and a device DVX does not have (such as &quot;COM1:&quot;) error 64.</p>
<h2>INPUT #</h2>
<p>Reads comma-delimited data from a file, one field per variable. Quoted strings written by WRITE # are read back without their quotes; numeric variables receive the converted value.</p>
<pre><code>INPUT #channel, variable [, variable ...]</code></pre>
<pre><code>Open &quot;data.txt&quot; For Input As #1
Input #1, name$, age%, score#
Close #1</code></pre>
<h2>LINE INPUT #</h2>
<p>Reads an entire line from a file into a string variable.</p>
<pre><code>LINE INPUT #channel, variable$</code></pre>
<h2>WRITE #</h2>
<p>Writes comma-delimited data to a file. Strings are enclosed in quotes, numbers are undecorated. Each statement writes a newline at the end.</p>
<pre><code>WRITE #channel, expr1, expr2, ...</code></pre>
<pre><code>Write #1, &quot;Scott&quot;, 42, 3.14
' Output: &quot;Scott&quot;,42,3.14</code></pre>
<h2>GET / PUT</h2>
<p>Read and write records in RANDOM or BINARY mode files. When recordNum is omitted the transfer starts at the current file position.</p>
<pre><code>GET #channel, [recordNum], variable
PUT #channel, [recordNum], variable</code></pre>
<p>In RANDOM mode recordNum is a 1-based record number and each record is LEN bytes (see OPEN). Numbers are stored in their binary form (Byte 1 byte, Integer and Boolean 2, Long 4, Single 4, Double, Currency, and Date 8); a String is stored as a 2-byte length followed by its characters. PUT always writes a whole record, padding the unused part with zero bytes, and GET always advances to the next record; data longer than LEN raises error 59 before anything is written.</p>
<p>In BINARY mode recordNum is a 1-based byte position. Numbers are stored as in RANDOM mode. PUT writes the characters of a String with no length prefix, and GET reads as many bytes as the String variable currently holds, so set its length first (for example with SPACE$ or by declaring it as STRING * n).</p>
<p>The variable may be a TYPE variable. Its fields are packed in declaration order with the sizes above; a STRING * n field takes exactly n bytes (padded with spaces), a variable-length String field is stored with its 2-byte length prefix in both modes, and nested TYPE fields are packed inline. GET fills the fields of the existing variable in place.</p>
<p>The variable may also be an array element, arr(i), of any type including a TYPE: PUT writes that element and GET reads into it. The index expression is evaluated once.</p>
<pre><code>Type RecT
id As Integer
score As Double
nm As String * 6
End Type
Dim r As RecT
Open &quot;recs.dat&quot; For Random As #1 Len = 32
r.id = 1
Put #1, 1, r ' 16 bytes of fields, padded to a 32-byte record
Get #1, 1, r
Close #1</code></pre>
<pre><code>Dim buf As String
Open &quot;raw.bin&quot; For Binary As #1
buf = Space$(16)
Get #1, 1, buf ' read bytes 1-16
Put #1, 33, &quot;TAG&quot; ' write 3 bytes at position 33
Close #1</code></pre>
<h2>SEEK</h2>
<p>Sets the file position. As a function, returns the current position. On a RANDOM file the position is a record number (statement and function); on other files it is a 1-based byte position. A position below 1 raises error 63 (Bad record number).</p>
<pre><code>SEEK #channel, position ' Statement: set position
pos = SEEK(channel) ' Function: get current position</code></pre>
</div>
<div class="topic" id="lang.filesystem">
<h1>File System Statements</h1>
<p>DVX BASIC provides statements for working with the file system -- creating, deleting, renaming, and copying files and directories, and reading or setting file attributes.</p>
<p>A path may be written with / or \ between its parts, mixed too: OPEN &quot;DATA/SCORES.TXT&quot; and OPEN &quot;DATA\SCORES.TXT&quot; open the same file, and so do the FileOps, Shell, and other library functions that take a path (SHELL commands are the exception: see SHELL). Paths DVX gives back -- CURDIR$, App.Path, App.Data, the file dialogs, FileOpsPathJoin$, and the other FileOps results -- use \, the separator DOS shows; FileOpsPathNative$ gives a path of your own that form before you show it.</p>
<h2>KILL</h2>
<p>Deletes a file.</p>
<pre><code>KILL filename$</code></pre>
<pre><code>Kill &quot;temp.bak&quot;</code></pre>
<h2>NAME ... AS</h2>
<p>Renames (or moves) a file.</p>
<pre><code>NAME oldName$ AS newName$</code></pre>
<pre><code>Name &quot;draft.txt&quot; As &quot;final.txt&quot;</code></pre>
<h2>FILECOPY</h2>
<p>Copies a file. If the destination already exists it is overwritten. While a big file copies, the rest of DVX and the program's own events go on, as with DoEvents (in a control's code they wait until the copy ends).</p>
<pre><code>FILECOPY source$, destination$</code></pre>
<pre><code>FileCopy &quot;data.db&quot;, &quot;data.bak&quot;</code></pre>
<h2>MKDIR / RMDIR</h2>
<p>Creates or removes a directory.</p>
<pre><code>MKDIR path$
RMDIR path$</code></pre>
<pre><code>MkDir App.Data &amp; &quot;\backups&quot;
RmDir &quot;C:\OLD&quot;</code></pre>
<h2>CHDIR / CHDRIVE</h2>
<p>Changes the current working directory or drive.</p>
<pre><code>CHDIR path$
CHDRIVE drive$</code></pre>
<pre><code>ChDir &quot;C:\DVX\PROJECTS&quot;
ChDrive &quot;D&quot;</code></pre>
<h2>GETATTR / SETATTR</h2>
<p>GETATTR returns the attributes of a file (as a function). SETATTR sets them (as a statement). Attributes are a bitmask of the vb file-attribute constants. A missing file raises error 53 (File not found); SETATTR raises error 75 when the attributes cannot be changed.</p>
<pre><code>attrs = GETATTR(filename$)
SETATTR filename$, attrs</code></pre>
<pre> Constant Value Attribute
-------- ----- ---------
vbNormal 0 Normal file (no attributes set)
vbReadOnly 1 Read-only
vbHidden 2 Hidden
vbSystem 4 System file
vbDirectory 16 Entry is a directory
vbArchive 32 File has been modified since last backup</pre>
<pre><code>If (GetAttr(&quot;readme.txt&quot;) And vbReadOnly) &lt;&gt; 0 Then
Print &quot;File is read-only.&quot;
End If
SetAttr &quot;secret.dat&quot;, vbHidden + vbReadOnly</code></pre>
<h2>CURDIR$ / DIR$</h2>
<p>CURDIR$ returns the current directory. DIR$ returns the first file matching a pattern; subsequent calls with no arguments return additional matches (or &quot;&quot; when done). DIR$ returns only files: never &quot;.&quot;, &quot;..&quot;, or subdirectories. The pattern uses DOS's wildcards, as the file dialog does: * stands for any characters and ? for one, case does not matter, and *.* is every file, with or without an extension. DIR$(&quot;C:\*.*&quot;) lists the root of C: (DIR$(&quot;C:*.*&quot;) the drive's current folder). Looking through a big folder for a rare match lets the rest of DVX and the program's own events go on, as with DoEvents; if one of those events starts a new DIR$ listing, the call returns &quot;&quot; (in a control's code nothing else runs meanwhile).</p>
<pre><code>cwd$ = CURDIR$
first$ = DIR$(&quot;*.txt&quot;)
WHILE first$ &lt;&gt; &quot;&quot;
Print first$
first$ = DIR$ ' next match, no argument
WEND</code></pre>
<h2>FILELEN</h2>
<p>Returns the length of a file in bytes. A file that does not exist raises error 53 (File not found); one past 2 GB raises error 6 (Overflow).</p>
<pre><code>bytes = FILELEN(filename$)</code></pre>
</div>
<div class="topic" id="lang.func.string">
<h1>String Functions</h1>
<pre> Function Returns Description
-------- ------- -----------
ASC(s$) Integer ASCII code of the first character of s$ (error 5 for an empty string)
ASCW(s$) Long Unicode code point of the first character of s$ (error 5 for an empty string)
CHR$(n) String Character with ASCII code n
CHRW$(n) String Character for Unicode code point n (&quot;?&quot; when DVX has no such character; error 5 outside 0 to &amp;H10FFFF)
FILTER(arr, match$ [, include [, compare]]) String array The elements of arr that contain match$ (or, with include False, that do not)
FORMAT$(value [, fmt$]) String Formats a number or a date using a format string
HEX$(n) String Hexadecimal representation of n (uppercase, no leading &amp;H)
INSTR(s$, find$) Long Position of find$ in s$ (1-based), 0 if not found
INSTR(start, s$, find$) Long Search starting at position start (1-based)
INSTRREV(s$, find$ [, start [, compare]]) Long Position of the last find$ in s$ that ends at or before start (default: the end), 0 if not found
JOIN$(arr [, delim$]) String The elements of a one-dimensional array joined with delim$ between them (default: a space)
LCASE$(s$) String Converts s$ to lowercase
LEFT$(s$, n) String Leftmost n characters of s$
LEN(s$) Long Length of s$ in characters
LTRIM$(s$) String Removes leading spaces from s$
MID$(s$, start) String Substring from start (1-based) to end of string
MID$(s$, start, length) String Substring of length characters starting at start
OCT$(n) String Octal representation of n (no leading &amp;O)
REPLACE$(s$, find$, repl$ [, start [, count [, compare]]]) String s$ from position start (default 1) on, with the first count (default all) occurrences of find$ replaced by repl$
RIGHT$(s$, n) String Rightmost n characters of s$
RTRIM$(s$) String Removes trailing spaces from s$
SPACE$(n) String String of n spaces (n up to 65535)
SPLIT(s$ [, delim$ [, limit [, compare]]]) String array The pieces of s$ between occurrences of delim$ (default: a space), at most limit of them (default: all)
STRCOMP(a$, b$ [, compare]) Integer -1 if a$ sorts before b$, 0 if they are equal, 1 if a$ sorts after b$
STR$(n) String Converts number n to string (leading space for non-negative)
STRING$(n, char) String String of n copies of char (char can be an ASCII code or single-character string; n up to 65535)
STRREVERSE$(s$) String s$ with its characters in reverse order
TRIM$(s$) String Removes leading and trailing spaces from s$
UCASE$(s$) String Converts s$ to uppercase
VAL(s$) Double Converts string s$ to a numeric value; stops at first non-numeric character</pre>
<p>A negative count or position passed to LEFT$, RIGHT$, MID$, SPACE$, or STRING$, or a count above 65535 passed to SPACE$ or STRING$, raises error 5 (Illegal function call). INSTR follows OPTION COMPARE TEXT (a case-insensitive search), and an INSTR start position below 1 raises error 5.</p>
<p>REPLACE$, JOIN$, and STRREVERSE$ may also be written without the $. Items in square brackets may be left out.</p>
<h2>Comparing Text</h2>
<p>The compare argument of FILTER, INSTRREV, REPLACE$, SPLIT, and STRCOMP chooses how text is matched: vbBinaryCompare (0) matches exactly, vbTextCompare (1) ignores upper and lower case, and vbUseCompareOption (-1, the default) follows OPTION COMPARE. Any other value raises error 5.</p>
<pre><code>Print StrComp(&quot;apple&quot;, &quot;Apple&quot;) ' 1 (&quot;a&quot; sorts after &quot;A&quot;)
Print StrComp(&quot;apple&quot;, &quot;Apple&quot;, vbTextCompare) ' 0
Print Replace$(&quot;Red red RED&quot;, &quot;red&quot;, &quot;blue&quot;, 1, -1, vbTextCompare) ' blue blue blue
Print InStrRev(&quot;C:\DVX\APPS\EDIT.APP&quot;, &quot;\&quot;) ' 12</code></pre>
<h2>REPLACE$ Details</h2>
<p>REPLACE$ returns the text from position start on, so REPLACE$(&quot;abcabc&quot;, &quot;b&quot;, &quot;x&quot;, 3) is &quot;caxc&quot; -- the characters before start are left out, as in Visual Basic. A count of -1 replaces every occurrence. An empty find$ returns the text unchanged. A start below 1 or a count below -1 raises error 5.</p>
<h2>SPLIT, JOIN$, and FILTER</h2>
<p>SPLIT returns a string array numbered from 0. Assign it to a dynamic array (one declared with empty parentheses) and use UBOUND to find the last piece. The last piece keeps the rest of the text when limit stops the split. Splitting an empty string, or a limit of 0, gives an array with no elements: its UBOUND is -1. An empty delim$ gives the whole string as the only piece.</p>
<pre><code>Dim parts() As String
Dim i As Integer
parts = Split(&quot;red,green,,blue&quot;, &quot;,&quot;)
For i = 0 To UBound(parts)
Print i; &quot;[&quot; &amp; parts(i) &amp; &quot;]&quot; ' the empty third piece is kept
Next i
Print Join$(parts, &quot; / &quot;) ' red / green / / blue</code></pre>
<p>JOIN$ works on any one-dimensional array; numbers are converted as STR$ would, without the leading space. FILTER returns a new string array holding the elements that contain match$ (include True, the default) or that do not contain it (include False), or an array with no elements when nothing matches. Passing JOIN$ or FILTER something that is not a one-dimensional array raises error 13 (Type mismatch).</p>
<h2>INSTRREV Details</h2>
<p>INSTRREV searches backward: INSTRREV(&quot;abcabc&quot;, &quot;bc&quot;) is 5 and INSTRREV(&quot;abcabc&quot;, &quot;bc&quot;, 4) is 2. A start of -1 (the default) searches from the end. It returns 0 when s$ is empty or start is past the end of s$, and start when find$ is empty. A start of 0 or below -1 raises error 5.</p>
<h2>FORMAT$</h2>
<p>FORMAT$ formats a numeric value using a BASIC-style format string. The format characters are the same as the ones used by PRINT USING.</p>
<pre><code>s$ = FORMAT$(value, fmt$)
s$ = FORMAT$(value)</code></pre>
<pre><code>Print Format$(3.14159, &quot;###.##&quot;) ' &quot; 3.14&quot;
Print Format$(-7, &quot;+###&quot;) ' &quot; -7&quot;
Print Format$(42, &quot;00000&quot;) ' &quot;00042&quot;
Print Format$(1234.5, &quot;#,##0.00&quot;) ' &quot;1,234.50&quot;
Print Format$(5, &quot;#,##0.00&quot;) ' &quot; 5.00&quot;
Print Format$(0.5, &quot;PERCENT&quot;) ' &quot;50%&quot;</code></pre>
<p>The whole format string is one numeric field (for a number). The accepted format characters are # (digit or pad space), 0 (digit that is always printed; zero pads up to the first 0), . (decimal point), , (thousands separator), + and - (sign placement), $$ (floating dollar sign), ** (asterisk fill), ^^^^ (scientific notation), and the literal word PERCENT (multiplies by 100 and appends %). Unlike PRINT USING, a value wider than the field is printed in full without a % marker. See PRINT USING for details on each character.</p>
<p>With no format string (or an empty one), FORMAT$ gives the value's plain text, as CSTR does: a number without the leading space STR$ puts before it (Format$(42) is &quot;42&quot;), a date in the usual m/d/yyyy h:mm:ss AM form, text as it is, True / False, and &quot;&quot; for Empty.</p>
<p>FORMAT (without the $) is the same function.</p>
<h2>FORMAT$ with Dates</h2>
<p>When the format string holds a date or time code, or is one of the named date formats, FORMAT$ formats its value as a date. The value may be a Date, a number (taken as a date's number of days), or a string that holds a date (anything else raises error 13). A Date with an empty format string gives the usual m/d/yyyy h:mm:ss AM form. The codes may be written in upper or lower case.</p>
<pre> Code Result
---- ------
d / dd Day of the month (dd: two digits)
ddd / dddd Weekday name, abbreviated (Mon) or full (Monday)
ddddd Short date (m/d/yyyy)
dddddd Long date (dddd, mmmm d, yyyy)
w Day of the week (1 = Sunday)
ww Week of the year (the week holding January 1 is week 1)
m / mm Month number (mm: two digits); the minute when it follows an hour or comes before a second
mmm / mmmm Month name, abbreviated (Jan) or full (January)
q Quarter (1-4)
y Day of the year (1-366)
yy / yyyy Year as two or four digits
h / hh Hour (hh: two digits); 1-12 when the format has AM/PM, else 0-23
n / nn Minute
s / ss Second
ttttt Long time (h:mm:ss AM/PM)
c The usual date and time form
AM/PM am/pm AM or PM in the case written; A/P and a/p give one letter; AMPM gives AM or PM
&quot;text&quot; Text in double quotes is copied as it is
\x The character after a backslash is copied as it is</pre>
<p>Any other character, such as / : - , or a space, is copied as it is. These names give whole formats:</p>
<pre> Name Format Example
---- ------ -------
General Date (the usual form) 1/5/2000 3:04:05 PM
Long Date dddd, mmmm d, yyyy Wednesday, January 5, 2000
Medium Date dd-mmm-yy 05-Jan-00
Short Date m/d/yyyy 1/5/2000
Long Time h:mm:ss AM/PM 3:04:05 PM
Medium Time hh:mm AM/PM 03:04 PM
Short Time hh:mm 15:04</pre>
<pre><code>Dim d As Date
d = #1/5/2000 3:04:05 PM#
Print Format$(d, &quot;yyyy-mm-dd hh:nn:ss&quot;) ' 2000-01-05 15:04:05
Print Format$(d, &quot;dddd, mmmm d&quot;) ' Wednesday, January 5
Print Format$(d, &quot;h:mm AM/PM&quot;) ' 3:04 PM
Print Format$(d, &quot;Long Date&quot;) ' Wednesday, January 5, 2000
Print Format$(Now, &quot;Short Time&quot;) ' the time now, e.g. 09:41</code></pre>
<h2>MID$ Assignment</h2>
<p>MID$ can also be used on the left side of an assignment to replace a portion of a string without changing its length:</p>
<pre><code>Mid$(s$, start [, length]) = replacement$</code></pre>
<pre><code>Dim s$
s$ = &quot;Hello, World!&quot;
Mid$(s$, 8, 5) = &quot;DVX--&quot;
Print s$ ' Hello, DVX--!</code></pre>
<p>If length is omitted, MID$ replaces up to LEN(replacement$) characters; a length of 0 replaces nothing. The target string's total length never changes -- extra characters in replacement$ are truncated and shorter replacements leave trailing characters in place. A start position below 1 or a negative length raises error 5 (Illegal function call).</p>
</div>
<div class="topic" id="lang.func.math">
<h1>Math Functions</h1>
<pre> Function Returns Description
-------- ------- -----------
ABS(n) Double Absolute value of n
ATN(n) Double Arctangent of n (result in radians)
COS(n) Double Cosine of n (n in radians)
EXP(n) Double e raised to the power n
FIX(n) Integer Truncates n toward zero (drops the fractional part)
INT(n) Integer Largest integer less than or equal to n (floor)
LOG(n) Double Natural logarithm (base e) of n
RND[(n)] Double Random number in the range 0 &lt;= RND &lt; 1
SGN(n) Integer Sign of n: -1 if negative, 0 if zero, 1 if positive
SIN(n) Double Sine of n (n in radians)
SQR(n) Double Square root of n
TAN(n) Double Tangent of n (n in radians)
TIMER Double Seconds since midnight, to a fraction of a millisecond (it keeps rising between the clock's 55 ms ticks)</pre>
<p>RND follows QBasic: RND or RND(n) with n &gt; 0 returns the next number in the sequence, RND(0) repeats the last number, and RND(n) with n &lt; 0 reseeds the generator from n (the same n always gives the same number). The result is a Double, 0 &lt;= RND &lt; 1.</p>
<p>INT, FIX, and SGN return an Integer, widening to Long or Double when the value does not fit. EXP, ^, and the other functions raise error 6 (Overflow) when the result leaves the numeric range, and error 5 when it is undefined (for example a negative number to a fractional power).</p>
<blockquote><strong>Note:</strong> Use RANDOMIZE or RANDOMIZE TIMER to seed the generator so you don't get the same sequence each run.</blockquote>
<h2>Color Functions</h2>
<p>The color functions work with 24-bit colors packed into a Long the way Visual Basic packs them, &amp;HBBGGRR: red is the low byte, green the middle byte, and blue the high byte. RGB(255, 0, 0) and &amp;HFF are red, RGB(0, 0, 255) and &amp;HFF0000 are blue. ForeColor, BackColor, FillColor, the drawing methods of forms and picture boxes (PSet, Line, Circle, Point), the Canvas control, and the color dialog all use this form (the console graphics statements of SCREEN modes use QBasic color numbers instead), as do the color constants vbBlack, vbRed, vbGreen, vbYellow, vbBlue, vbMagenta, vbCyan, and vbWhite (see Predefined Constants).</p>
<pre> Function Returns Description
-------- ------- -----------
RGB(r, g, b) Long Combine red, green, and blue components (0-255) into a color: r + g * 256 + b * 65536
QBCOLOR(n) Long The color of QBasic color number n (0 to 15: 0 black, 1 blue, 2 green, 4 red, 7 white, 8 gray, 15 bright white, ...); error 5 for any other number
GETRED(color) Integer Red component (0-255) of a color
GETGREEN(color) Integer Green component (0-255) of a color
GETBLUE(color) Integer Blue component (0-255) of a color</pre>
<pre><code>Dim c As Long
c = RGB(255, 128, 0) ' bright orange, &amp;H0080FF
Print GetRed(c); GetGreen(c); GetBlue(c) ' 255 128 0
Me.BackColor = RGB(0, 0, 128) ' dark blue background
Me.ForeColor = QBColor(14) ' yellow</code></pre>
</div>
<div class="topic" id="lang.func.conversion">
<h1>Conversion Functions</h1>
<pre> Function Returns Description
-------- ------- -----------
CBOOL(n) Boolean Returns True (-1) if n is nonzero or a non-empty string; False (0) otherwise
CBYTE(n) Byte Converts n to Byte with the rounding CINT uses; error 6 (Overflow) outside 0 to 255
CCUR(n) Currency Converts n to Currency, rounded to four decimal places (halves to even); error 6 (Overflow) outside the Currency range
CDATE(v) Date Converts a number (days since 12/30/1899) or date text to a Date; error 13 for text that is not a date, error 6 outside 1/1/100 to 12/31/9999
CDBL(n) Double Converts n to Double (a Date gives its number of days)
CINT(n) Integer Converts n to Integer; halves round to the nearest even number (2.5 -&gt; 2, 3.5 -&gt; 4); error 6 (Overflow) outside -32768 to 32767
CLNG(n) Long Converts n to Long with the same rounding; error 6 (Overflow) outside the Long range
CSNG(n) Single Converts n to Single
CSTR(n) String Converts n to its String representation (a Date gives m/d/yyyy h:mm:ss AM)
CVAR(v) Variant Returns v unchanged as a Variant</pre>
<p>Passing Null to any of these except CVAR raises error 94 (Invalid use of Null). Text passed to one that gives a number must hold a number (CINT(&quot;12&quot;) is 12); other text raises error 13 (Type mismatch). VARTYPE, TYPENAME, and the IS functions (ISNULL, ISEMPTY, ISNUMERIC, ...) are described under Variants.</p>
<p><a href="#lang.variants">See also: Variants</a></p>
</div>
<div class="topic" id="lang.func.date">
<h1>Date and Time Functions</h1>
<p>These functions work with Date values (see Data Types). Wherever a date is expected, a Date, a number of days since 12/30/1899, or a string holding a date may be given; text that is not a date raises error 13 (Type mismatch).</p>
<pre> Function Returns Description
-------- ------- -----------
NOW Date The current date and time
DATE Date Today's date (at midnight)
TIME Date The current time of day (on 12/30/1899)
DATESERIAL(year, month, day) Date The date with those parts
TIMESERIAL(hour, minute, second) Date The time with those parts
DATEVALUE(d) Date The date part of d (its time dropped)
TIMEVALUE(d) Date The time part of d (on 12/30/1899)
YEAR(d) Integer Year (100-9999)
MONTH(d) Integer Month (1-12)
DAY(d) Integer Day of the month (1-31)
WEEKDAY(d [, firstDay]) Integer Day of the week, 1 for firstDay (default vbSunday)
HOUR(d) Integer Hour (0-23)
MINUTE(d) Integer Minute (0-59)
SECOND(d) Integer Second (0-59)
DATEADD(interval$, n, d) Date d moved by n intervals (n may be negative)
DATEDIFF(interval$, d1, d2 [, firstDay [, firstWeek]]) Long Intervals from d1 to d2 (negative when d2 is earlier)
DATEPART(interval$, d [, firstDay [, firstWeek]]) Integer One part of d
ISDATE(v) Boolean True when v is a Date or a string holding a valid date
MONTHNAME(month [, abbreviate]) String January ... December (Jan ... Dec when abbreviate is True)
WEEKDAYNAME(n [, abbreviate [, firstDay]]) String Name of day n of the week counted from firstDay (default vbSunday)</pre>
<p>NOW, DATE, and TIME need no parentheses. DATE$ and TIME$ still return the date and time as text.</p>
<h2>Intervals</h2>
<p>DATEADD, DATEDIFF, and DATEPART take the interval as a string, in upper or lower case:</p>
<pre> Interval Meaning
-------- -------
&quot;yyyy&quot; Year
&quot;q&quot; Quarter
&quot;m&quot; Month
&quot;y&quot; Day of the year
&quot;d&quot; Day
&quot;w&quot; Weekday
&quot;ww&quot; Week
&quot;h&quot; Hour
&quot;n&quot; Minute
&quot;s&quot; Second</pre>
<p>Any other interval raises error 5 (Illegal function call).</p>
<h2>DATESERIAL and TIMESERIAL</h2>
<p>A year from 0 to 29 means 2000 to 2029 and one from 30 to 99 means 1930 to 1999. Months, days, hours, minutes, and seconds outside their usual range carry into the next or previous unit, so DATESERIAL(2000, 13, 1) is 1/1/2001, DATESERIAL(2000, 3, 0) is the last day of February 2000, and TIMESERIAL(0, 90, 0) is 1:30 AM. Fractional arguments are rounded. A result before 1/1/100 or after 12/31/9999 raises error 5.</p>
<pre><code>Dim lastDay As Date
lastDay = DateSerial(Year(Date), Month(Date) + 1, 0) ' last day of this month
Print Day(lastDay)</code></pre>
<h2>DATEADD</h2>
<p>Adding months, quarters, or years keeps the day of the month where it can; when the new month is shorter the day becomes its last day, so DATEADD(&quot;m&quot;, 1, #1/31/2000#) is 2/29/2000. The time of day is kept. &quot;y&quot;, &quot;d&quot;, and &quot;w&quot; all add days and &quot;ww&quot; adds weeks. A fractional n drops its fraction. A result outside the Date range raises error 5.</p>
<pre><code>Print DateAdd(&quot;m&quot;, 1, #1/31/2001#) ' 2/28/2001
Print DateAdd(&quot;h&quot;, -2, #1/1/2000#) ' 12/31/1999 10:00:00 PM</code></pre>
<h2>DATEDIFF</h2>
<p>DATEDIFF counts how many interval boundaries lie between d1 and d2: DATEDIFF(&quot;yyyy&quot;, #12/31/1999#, #1/1/2000#) is 1 although the dates are a day apart, and DATEDIFF(&quot;d&quot;, ...) counts midnights, whatever the times of day. &quot;w&quot; counts whole weeks (7 days) and &quot;ww&quot; counts calendar weeks -- the number of firstDay days (Sundays by default) after d1 up to and including d2. A result too large for a Long raises error 6 (Overflow).</p>
<pre><code>Print DateDiff(&quot;d&quot;, #1/1/2000#, #3/1/2000#) ' 60
Print DateDiff(&quot;ww&quot;, #1/1/2000#, #1/2/2000#) ' 1 (1/2/2000 is a Sunday)
Print DateDiff(&quot;w&quot;, #1/1/2000#, #1/2/2000#) ' 0</code></pre>
<h2>DATEPART and Weeks of the Year</h2>
<p>DATEPART returns the part of d the interval names: &quot;w&quot; is the day of the week (1 for firstDay) and &quot;ww&quot; the week of the year. firstDay is one of vbSunday (1, the default) to vbSaturday (7), or vbUseSystemDayOfWeek (0, meaning Sunday). firstWeek chooses which week is week 1:</p>
<pre> Constant Value Week 1 is
-------- ----- ---------
vbUseSystem 0 Same as vbFirstJan1
vbFirstJan1 1 The week holding January 1 (the default)
vbFirstFourDays 2 The first week with at least four days in the new year
vbFirstFullWeek 3 The first full week of the year</pre>
<p>Days before week 1 belong to the last week of the previous year. A firstDay or firstWeek outside these values raises error 5.</p>
<pre><code>Print DatePart(&quot;q&quot;, #5/15/2000#) ' 2
Print DatePart(&quot;ww&quot;, #1/1/2000#, vbSunday, vbFirstFourDays) ' 52</code></pre>
<h2>ISDATE, MONTHNAME, and WEEKDAYNAME</h2>
<p>ISDATE is True for a Date and for a string that holds a valid date or time; numbers are not dates to ISDATE. MONTHNAME with a month outside 1 to 12, and WEEKDAYNAME with n outside 1 to 7, raise error 5.</p>
<pre><code>If IsDate(Text1.Text) Then due = CDate(Text1.Text)
Print MonthName(Month(Date)); &quot; &quot;; WeekdayName(Weekday(Date), True)</code></pre>
</div>
<div class="topic" id="lang.func.fileio">
<h1>File I/O Functions</h1>
<pre> Function Returns Description
-------- ------- -----------
EOF(channel) Boolean True if the file pointer is at end of file
FREEFILE Integer Next available file channel number (1..16)
INPUT$(n, #channel) String Reads exactly n characters from the file
LOC(channel) Long BINARY: position of the last byte read or written (0 at the start); RANDOM: number of the last record read or written; sequential: number of 128-byte blocks read or written
LOF(channel) Long Length of the file in bytes
FILEATTR(channel, 1) Long How the file is open: 1 INPUT, 2 OUTPUT, 4 RANDOM, 8 APPEND, 32 BINARY (QBasic's numbers)
FILEATTR(channel, 2) Long The operating system's handle for the open file
SEEK(channel) Long RANDOM: number of the next record; other modes: 1-based position of the next byte to be read or written
FILELEN(path$) Long Length of the named file in bytes (no OPEN needed; error 53 when missing)
GETATTR(path$) Integer File attribute bits (see vbReadOnly, vbHidden, etc.)
CURDIR$ String Current working directory
DIR$(pattern$) String First filename matching pattern, or &quot;&quot;
DIR$ String Next match from the last DIR$(pattern$), or &quot;&quot; when done
LBOUND(array [, dim]) Integer Lower bound of an array dimension (default dim = 1)
UBOUND(array [, dim]) Integer Upper bound of an array dimension (default dim = 1)</pre>
<p>The dim argument of LBOUND and UBOUND must be a constant from 1 to 8.</p>
<p>File sizes and positions are Longs, so they stop at 2 GB (2,147,483,647 bytes). A disk can hold bigger files (up to 4 GB on FAT32); LOF, FILELEN, LOC, and SEEK raise error 6 (Overflow) for a size or position past 2 GB rather than give a wrong number, and GET and PUT do the same for a record that would end past it. EOF stays right while the position is below 2 GB. FileOpsListSize and FileOpsTreeBytes (fileops.bas) give any file's size as a Double.</p>
</div>
<div class="topic" id="lang.func.misc">
<h1>Miscellaneous Functions</h1>
<pre> Function Returns Description
-------- ------- -----------
DATE$ String Current date as &quot;MM-DD-YYYY&quot;
TIME$ String Current time as &quot;HH:MM:SS&quot; (24-hour)
TIMER Double Seconds since midnight, to a fraction of a millisecond
ENVIRON$(name$) String Value of the environment variable; empty string if not set
COMMAND$ String The arguments the program was started with; empty string if none
COMMAND$(n) String The nth argument (1 = first) without its quotes; empty string when there are fewer; COMMAND$(0) is the same as COMMAND$
ERR Long Current runtime error number (0 if no error)
SHELL(cmd$) Integer Exit code of the command (also usable as a statement, discarding the code)
IIF(cond, a, b) (any) a when cond is True, b when it is False
CHOOSE(n, a, b, ...) (any) The nth value of the list (1 = a), or Null when there is no nth value; up to 31 values
LOADPICTURE([file$ [, size [, colordepth [, x, y]]]]) Object A Picture object for a picture property (DragIcon, Picture), with Width, Height, and Type; no file (or &quot;&quot;) gives an empty picture</pre>
<p>DATE$ and TIME$ return text; the Date and Time Functions return Date values.</p>
<h2>IIF and CHOOSE</h2>
<p>IIF and CHOOSE evaluate every argument before picking one, as in Visual Basic, so a function called in an argument runs even when its value is not chosen. A fractional n in CHOOSE drops its fraction (2.9 picks the second value). An n below 1 or past the end of the list gives Null, as in Visual Basic (test it with ISNULL; see Variants).</p>
<pre><code>Print IIf(score &gt;= 50, &quot;Pass&quot;, &quot;Fail&quot;)
Print Choose(Weekday(Date), &quot;Sun&quot;, &quot;Mon&quot;, &quot;Tue&quot;, &quot;Wed&quot;, &quot;Thu&quot;, &quot;Fri&quot;, &quot;Sat&quot;)</code></pre>
<h2>LOADPICTURE</h2>
<p>LOADPICTURE(file$) reads a picture file (BMP, PNG, JPEG, or GIF) -- or the icon of a DVX program, widget, or library file (.app, .wgt, .lib) -- and returns a Picture object (TypeName &quot;Picture&quot;) that can be given to a picture property: a control's DragIcon, the Picture of an Image or ImageButton. Use SET, or a plain assignment, as with a file name; file names still work too. LOADPICTURE() or LOADPICTURE(&quot;&quot;) gives an empty picture, which clears the property. A missing file raises error 53 (File not found), a file that is not a picture error 481 (Invalid picture), so the check happens where the picture is loaded. The check reads the picture's header only (the control that shows it reads the rest): a picture file damaged after its header shows nothing. Loading the same file again gives the same Picture object. Reading a picture property back gives a Picture object too (TypeName &quot;Picture&quot;), as in Visual Basic; used as a value (printed, joined to text, compared) it stands for its file name, so code that treats the property as a file name keeps working. The name of a program, widget, or library file works wherever a picture file's name does (a Picture property, DragIcon, PaintPicture, a Toolbar's AddButton) and shows its icon; such a file without an icon is not a picture (error 481).</p>
<p>The optional size and colordepth arguments are Visual Basic's: size is vbLPSmall (0), vbLPLarge (1), vbLPSmallShell (2), vbLPLargeShell (3), or vbLPCustom (4, with x and y giving the size), colordepth vbLPDefault (0), vbLPMonochrome (1), vbLPVGAColor (2), or vbLPColor (3). They choose among the images of an icon file; every DVX picture is a single bitmap, so, as for a bitmap in Visual Basic, they are checked and otherwise make no difference. A value outside these, or a negative x or y, raises error 5.</p>
<p>A Picture object has three properties, which can only be read:</p>
<pre> Property Type Description
-------- ---- -----------
Width Long The picture's width in HiMetric units (hundredths of a millimetre), as in Visual Basic; 0 for an empty picture.
Height Long The picture's height in HiMetric units; 0 for an empty picture.
Type Integer vbPicTypeBitmap (1) for a loaded picture, vbPicTypeNone (0) for an empty one.</pre>
<p>The HiMetric sizes assume a standard display of 96 pixels an inch (the same as ScaleMode), so a pixel is about 26.46 HiMetric units. Convert them to pixels or another scale with a form's or PictureBox's ScaleX and ScaleY methods (see Drawing on Forms and PictureBoxes). Visual Basic's Handle property and Render method are not available: DVX pictures have no system handle.</p>
<pre><code>Set Label1.DragIcon = LoadPicture(&quot;drag.bmp&quot;)
Image1.Picture = LoadPicture(&quot;logo.bmp&quot;)
Set Label1.DragIcon = LoadPicture() ' back to the dotted outline
Dim pic As Object
Set pic = LoadPicture(&quot;logo.bmp&quot;)
Print Me.ScaleX(pic.Width, vbHimetric, vbPixels); &quot;x&quot;; Me.ScaleY(pic.Height, vbHimetric, vbPixels)</code></pre>
<h2>LOADPICTUREDATA</h2>
<p>LOADPICTUREDATA(bytes$) does what LOADPICTURE does for a picture held in a string rather than in a file: the bytes of a BMP, PNG, JPEG, or GIF file, such as HttpBody$ gives for a picture downloaded from the web, or ResGetData$ for a picture resource of a DVX program, widget, or library file (any of its resources, not only its icon). The Picture object it returns goes wherever a LOADPICTURE picture goes: the Picture of an Image, an ImageButton, or a PictureBox, a control's DragIcon, a form's Icon, and PaintPicture; reading such a property back gives the same object. Its Width, Height, and Type are a loaded picture's; used as a value it stands for &quot;&quot;, since it has no file name. Bytes that are not a picture raise error 481 (Invalid picture); LOADPICTUREDATA(&quot;&quot;) gives an empty picture. Giving one to a control that shows no picture (a Label's Picture, for example) stops the program with an error.</p>
<p>A Picture object made this way keeps its bytes until the program ends, and the same bytes give the same object, so loading a picture again costs nothing. To show many different pictures one after another (a slide show, pictures from the web), use the SetPictureData method of the Image, ImageButton, or PictureBox instead: Image1.SetPictureData bytes$ shows the picture without keeping it, and returns True, or False when the bytes are not a picture.</p>
<pre><code>Image1.Picture = LoadPictureData(HttpBody$(req))
Set Label1.DragIcon = LoadPictureData(ResGetData$(&quot;mygame.app&quot;, &quot;card&quot;)) ' resource.bas in the project
If Not Picture1.SetPictureData(HttpBody$(req)) Then MsgBox &quot;That is not a picture.&quot;</code></pre>
<h2>COMMAND$</h2>
<p>COMMAND$ returns the program's arguments exactly as they were given, as in Visual Basic (QBasic turned them into capitals; DVX keeps them as they are). Arguments are separated by blanks; an argument with blanks in it is written in double quotes. COMMAND$(n) picks out one argument with its quotes removed, so a program that opens the document it was started with only needs:</p>
<pre><code>IF COMMAND$(1) &lt;&gt; &quot;&quot; THEN
OpenFile COMMAND$(1)
END IF</code></pre>
<p>A program gets arguments when a document of a type associated with it is opened (the document is the argument), from a Program Manager item's Arguments, or from a command typed in a Run box. When the program runs in the IDE, COMMAND$ returns the Arguments set in Project Properties. A negative n is error 5 (Illegal function call).</p>
</div>
<div class="topic" id="lang.forms">
<h1>Form and Control Statements</h1>
<p>DVX BASIC supports Visual Basic-style forms and controls for building graphical user interfaces. A form is normally designed visually in the IDE and saved as a .frm file, but forms and their controls can also be built entirely in code.</p>
<h2>Loading and Unloading Forms</h2>
<pre><code>LOAD FormName
UNLOAD FormName
UNLOAD Me
UNLOAD formVariable</code></pre>
<p>LOAD creates the form and its controls in memory. It fires the form's Load event (Form1_Load for a form named Form1) when the form is first loaded. UNLOAD destroys the form, firing its QueryUnload event (which can cancel the close) and then its Unload event. The form name here is the literal name of the form as it appears in its .frm file; UNLOAD Me unloads the form whose event handler is running. UNLOAD also takes a Form variable, or anything else that gives a form (for example a form made with CreateForm and kept in an object's property), and unloads that form.</p>
<h2>Showing and Hiding Forms</h2>
<pre><code>FormName.Show [mode]
FormName.Hide
Me.Show [mode]
Me.Hide</code></pre>
<p>Pass vbModal (1) to Show for a modal dialog that blocks until the user closes it. Omit the mode for a modeless (non-blocking) window.</p>
<pre><code>Form2.Show vbModal
Me.Hide</code></pre>
<h2>Property Access</h2>
<p>Read and write control properties using dot notation:</p>
<pre><code>ControlName.Property = value
value = ControlName.Property</code></pre>
<pre><code>Text1.Text = &quot;Hello&quot;
Label1.Caption = &quot;Name: &quot; &amp; name$
x = Text1.Left</code></pre>
<p>A control on another form is reached through that form's name, or through a variable holding a form reference: FormName.ControlName.Property works in both assignments and expressions, and so does FormName.ControlName.Method. Me.ControlName.Property does the same for the current form.</p>
<p>Using a property or method (or Show, Hide, Unload) on a variable that does not hold a form or control raises error 91 (Object variable not set). In the IDE, a property or method name that the control's type does not have is reported when the program is compiled.</p>
<pre><code>Form2.Label1.Caption = &quot;From Form1&quot;
total = Form2.List1.ListCount
Form2.List1.Clear</code></pre>
<h2>Method Calls</h2>
<pre><code>ControlName.Method [args]</code></pre>
<pre><code>List1.AddItem &quot;New entry&quot;
List1.Clear</code></pre>
<h2>Me Keyword</h2>
<p>Me refers to the current form -- that is, the form whose event handler is running. Use it to access the form's own properties, controls, and methods from within event handlers, especially when the form's name may change or when the same code runs from multiple forms. In the code of a class module, Me is instead the object whose procedure is running (see Objects and Class Modules).</p>
<pre><code>Me.Caption = &quot;Updated Title&quot;
Me.Text1.Text = &quot;&quot;
Me.Hide</code></pre>
<h2>Nothing</h2>
<p>Nothing is a null object reference. Assign it with SET to an object variable to indicate &quot;no object&quot;, and test for it with Is. An object variable that has not been Set holds Nothing, and using a property or method of Nothing raises error 91 (Object variable not set).</p>
<pre><code>Set myCtrl = Nothing
If myCtrl Is Nothing Then Print &quot;No control chosen&quot;</code></pre>
<p>Setting the last variable that refers to a class instance or Collection to Nothing frees the object; see Objects and Class Modules.</p>
<h2>Control Arrays</h2>
<p>Multiple controls can share a name with unique indices. Access individual controls with parenthesized indices:</p>
<pre><code>Option1(0).Value = True
Label1(idx).Caption = &quot;Item &quot; &amp; Str$(idx)
Me.Label1(i).Visible = True</code></pre>
<h2>WITH</h2>
<p>The WITH block provides a shorthand for setting several properties on the same control or for making several method calls. Inside the block, begin each property or method with a dot and omit the control name.</p>
<pre><code>WITH ControlName
.Property1 = value1
.Property2 = value2
.Method arg1, arg2
END WITH</code></pre>
<pre><code>With Label1
.Caption = &quot;Status: Ready&quot;
.ForeColor = RGB(0, 128, 0)
.Visible = True
End With</code></pre>
<h2>Building Forms in Code</h2>
<p>In addition to loading forms from .frm files, you can build a form entirely from code with CreateForm, CreateControl, SetEvent, and RemoveControl. The returned reference should be stored with SET.</p>
<h3>CreateForm</h3>
<pre><code>SET formVar = CreateForm(name$, width%, height%)</code></pre>
<p>Creates a new form with the given name and initial size. Returns a form reference. If a form of that name is already loaded, CreateForm returns that form; to open another copy of a form designed in a .frm file, use New FormName (see Several Copies of a Form in the Form topic).</p>
<h3>CreateControl</h3>
<pre><code>SET ctrlVar = CreateControl(formRef, typeName$, ctrlName$ [, parentCtrlRef])</code></pre>
<p>Creates a control on the given form. typeName$ is the control type (e.g. &quot;CommandButton&quot;, &quot;Label&quot;, &quot;TextBox&quot;). ctrlName$ is the unique name for the new control. If a parentCtrlRef is supplied, the new control is nested inside it (useful for placing controls inside containers like HBox or Frame); the parent must be a container on the same form, otherwise a runtime error (CreateControl: invalid parent) is raised.</p>
<h3>SetEvent</h3>
<pre><code>SETEVENT ctrlRef, eventName$, handlerName$</code></pre>
<p>Wires an arbitrary SUB as the handler for an event of a control, a form (Me or a form reference), or a menu item. The default event-handler convention (ControlName_EventName) is used automatically for controls defined in a .frm file; SetEvent is for controls you create dynamically or for reusing a single handler across multiple controls. A handler declared without parameters is called without the event's arguments.</p>
<h3>RemoveControl</h3>
<pre><code>REMOVECONTROL formRef, ctrlName$</code></pre>
<p>Removes a control from a form. A later reference to the removed control raises a runtime error (unknown control), as does a reference to a control of a form that has been unloaded.</p>
<h3>LoadFormText</h3>
<pre><code>SET formVar = LOADFORMTEXT(frmText$)</code></pre>
<p>Loads a form from the text of a .frm file -- one a program made, read from a file, or got from somewhere else -- and returns it, loaded but hidden like Load (its Load event runs; call Show). A form whose name is already loaded becomes another copy of its own, as with New. The form's controls fire events to procedures named after them in the running program (Gen1_Load, Go_Click), as for any form; a code section after the form's End is not compiled. Text that is not a form raises error 5 (Illegal function call). Form designers use it to show a .frm file being edited; Controls, CallByName, and the designer.bas functions then read and change it.</p>
<pre><code>Dim f As Object
Dim n As Integer
Dim t As String
n = FreeFile
Open &quot;PREVIEW.FRM&quot; For Binary As #n
t = Input$(LOF(n), #n)
Close #n
Set f = LoadFormText(t)
f.Show
Print f.Controls.Count; f.Controls(1).Name</code></pre>
<pre><code>Dim frm As Form
Dim lbl As Control
Set frm = CreateForm(&quot;MyDlg&quot;, 300, 200)
frm.Caption = &quot;Built in code&quot;
Set lbl = CreateControl(frm, &quot;Label&quot;, &quot;StatusLabel&quot;)
StatusLabel.Caption = &quot;Hello, world!&quot;
Dim btn As Control
Set btn = CreateControl(frm, &quot;CommandButton&quot;, &quot;BtnClose&quot;)
BtnClose.Caption = &quot;Close&quot;
SetEvent btn, &quot;Click&quot;, &quot;OnCloseClick&quot;
frm.Show
Sub OnCloseClick
Unload Me
End Sub</code></pre>
<h2>DoEvents</h2>
<p>Yields control to DVX so the GUI can process pending events. Call this in long-running loops to keep the UI responsive (otherwise the window will appear frozen).</p>
<pre><code>DOEVENTS</code></pre>
<pre><code>For i = 1 To 10000
' process data
If i Mod 100 = 0 Then DoEvents
Next</code></pre>
<h2>MsgBox</h2>
<p>Displays a message-box dialog. Can be used as a statement (discards the result) or as a function (returns the button clicked).</p>
<pre><code>MSGBOX message$ [, flags [, title$]]
result = MSGBOX(message$ [, flags [, title$]])</code></pre>
<p>flags is the sum of a button-style constant and an icon constant. See Predefined Constants for the complete list. The message box plays the desktop sound chosen for its icon on the Control Panel's Sounds tab (the default beep without an icon).</p>
<pre><code>MsgBox &quot;Operation complete&quot;
answer = MsgBox(&quot;Continue?&quot;, vbYesNo + vbQuestion, &quot;Confirm&quot;)
If answer = vbYes Then
' proceed
End If</code></pre>
<h2>InputBox$</h2>
<p>Displays an input dialog and returns the user's text entry. Returns an empty string if the user cancels.</p>
<pre><code>result$ = INPUTBOX$(prompt$ [, title$ [, default$]])</code></pre>
<pre><code>name$ = InputBox$(&quot;Enter your name:&quot;, &quot;Name Entry&quot;, &quot;&quot;)
If name$ &lt;&gt; &quot;&quot; Then
Print &quot;Hello, &quot;; name$
End If</code></pre>
<h2>Event Handler Convention</h2>
<p>Event handlers are named ControlName_EventName and defined as SUBs. A form's own events are named after the form: the Load event of a form named Form1 is Form1_Load. (Visual Basic's Form_Load spelling is not used: every procedure name is shared by the whole program, so each form's handlers need names of their own.)</p>
<pre><code>Sub Command1_Click()
MsgBox &quot;Button clicked!&quot;
End Sub
Sub Form1_Load()
Me.Caption = &quot;My App&quot;
End Sub
Sub Text1_Change()
Label1.Caption = &quot;You typed: &quot; &amp; Text1.Text
End Sub</code></pre>
<h3>Common Events</h3>
<pre> Event Description
----- -----------
Click Control was clicked
DblClick Control was double-clicked
Change Control value or text changed
KeyPress Printable key was pressed (receives ASCII code)
KeyDown Any key was pressed (receives key code and shift state)
KeyUp Key was released
MouseDown Mouse button pressed (receives button, X, Y)
MouseUp Mouse button released
MouseMove Mouse moved over the control
Scroll Control was scrolled (mouse wheel or scrollbar)
GotFocus Control received input focus
LostFocus Control lost input focus
Form1_Load Form is being loaded (fires once, after controls are created)
Form1_QueryUnload Form is about to close; set Cancel = 1 to abort
Form1_Unload Form is being unloaded
Form1_Resize Form was resized
Form1_Activate Form gained focus
Form1_Deactivate Form lost focus
Form1_NewArgs The running program was handed new arguments (COMMAND$ changed)
Timer1_Timer Timer control interval elapsed (Timer control's default event)</pre>
</div>
<div class="topic" id="lang.classes">
<h1>Objects and Class Modules</h1>
<p>A class module lets you define your own kind of object. The class describes what every object of that kind knows (its member variables and properties) and what it can do (its methods). Each object made from the class -- an instance -- has its own copy of the member variables, so you can have as many independent objects as you need, much as you can put several TextBoxes on a form.</p>
<h2>A First Class</h2>
<p>This class module, saved as Account.cls, describes a bank account:</p>
<pre><code>VERSION DVX 1.00 CLASS
Attribute VB_Name = &quot;Account&quot;
Option Explicit
Public Owner As String
Private mBalance As Double
Public Sub Deposit(ByVal amount As Double)
mBalance = mBalance + amount
End Sub
Public Property Get Balance() As Double
Balance = mBalance
End Property
Private Sub Class_Initialize()
Print &quot;Account created&quot;
End Sub
Private Sub Class_Terminate()
Print &quot;Account for &quot;; Owner; &quot; closed&quot;
End Sub</code></pre>
<p>Any other code in the project can then make and use Account objects:</p>
<pre><code>Dim acct As Account
Set acct = New Account ' prints &quot;Account created&quot;
acct.Owner = &quot;Scott&quot;
acct.Deposit 100
acct.Deposit 50
Print acct.Owner &amp; &quot;: &quot; &amp; acct.Balance ' Scott: 150
Set acct = Nothing ' prints &quot;Account for Scott closed&quot;</code></pre>
<p>Owner is Public, so code outside the class can read and change it. mBalance is Private: only the class's own code can touch it, and the outside world reads it through the Balance property, which has no way to change it.</p>
<h2>Class Module Files (.cls)</h2>
<p>Each class module is kept in its own .cls file, listed in the project's Classes group (see the IDE Guide). The file can begin with a few header lines, as a Visual Basic class file does; the IDE writes them for a new class module:</p>
<pre><code>VERSION DVX 1.00 CLASS
Attribute VB_Name = &quot;Account&quot;
Option Explicit</code></pre>
<p>The header is everything before the first line of code: blank lines, a VERSION line, a BEGIN ... END block and Attribute VB_... lines, in that order. All of it is optional, and a Visual Basic .cls file can be added as it is. The class's name comes from the Attribute VB_Name line; without one, the name is the file's name without .cls (ACCOUNT.CLS makes a class named ACCOUNT). The class name is the type name used in DIM ... AS, NEW, TypeOf, and TYPENAME.</p>
<h2>What a Class Contains</h2>
<p>Outside its procedures, a class module may hold only declarations: member variables, CONSTs, OPTION and DEFtype statements, and Attribute lines. Statements that do something belong in a procedure, usually Class_Initialize. The members are:</p>
<pre> Member Written as Used from outside as
------ ---------- --------------------
Public member variable Public name As type obj.name (read and assign)
Private member variable Private name As type, or Dim name As type not visible outside
Method Sub or Function (Public unless Private) obj.Method args, x = obj.Func(args)
Read property Property Get name(...) As type x = obj.name
Write property Property Let name(..., value) obj.name = x
Object property Property Set name(..., value) Set obj.name = someObject
Friend procedure Friend Sub / Function / Property ... obj.name, by the program's own code</pre>
<p>A Sub, Function, or Property is Public unless it is marked Private; Private procedures can be called only by the class's own code. A Friend one, as in Visual Basic, can be called by the rest of the program through a variable declared as the class, but it is not part of the object's late-bound interface: through As Object or As Variant it raises error 438, and an Implements interface does not include it. Inside the class's procedures the member variables are used by name, with no SHARED needed, and each call works with the variables of the object it was called for. The class's code can also use the program's DIM SHARED (or PUBLIC) module variables, procedures, and constants.</p>
<h2>Properties</h2>
<p>A property looks like a variable from outside, but reading or assigning it runs a procedure, so the class can check or calculate the value:</p>
<pre><code>Private mC As Double
Public Property Get Celsius() As Double
Celsius = mC
End Property
Public Property Let Celsius(ByVal v As Double)
mC = v
End Property
Public Property Get Fahrenheit() As Double
Fahrenheit = mC * 9 / 5 + 32
End Property
Public Property Let Fahrenheit(ByVal v As Double)
mC = (v - 32) * 5 / 9
End Property</code></pre>
<pre><code>Dim t As New Thermometer
t.Celsius = 100
Print t.Fahrenheit ' 212</code></pre>
<p>Property Get returns the value: assign it to the property name, as in a FUNCTION. Property Let receives the value being assigned as its last parameter; Property Set does the same for an object assigned with SET. A property can take arguments of its own before the value, such as Property Get Cell(r, c) and Property Let Cell(r, c, v), used as obj.Cell(1, 2) = 7. A property with only a Property Get is read-only: assigning it is a compile error through a variable of the class (error 438 through As Object). EXIT PROPERTY leaves a property procedure early.</p>
<p>Property procedures can also be written in an ordinary module, as in Visual Basic. The property is then used by its name like a variable, anywhere in the program: Size = 4 runs Property Let Size, Print Size runs Property Get Size, and Item(2) = &quot;two&quot; passes 2 and the value to Property Let Item.</p>
<h2>Creating and Releasing Objects</h2>
<p>An object variable starts as Nothing. NEW makes an object:</p>
<pre><code>Dim a As Account ' Nothing so far
Set a = New Account ' now an Account
Dim b As New Account ' an Account is made right here, at the DIM</code></pre>
<p>When an object is made, its Class_Initialize runs; when it is freed, its Class_Terminate runs. Both are Subs without parameters, usually Private, and both are optional.</p>
<p>An object stays alive as long as something refers to it: a variable, an array element, a TYPE field, a Collection, a Variant, or a member variable of another object. Each SET to another variable adds a reference; nothing is copied. When the last reference goes away -- SET to Nothing or to another object, a local variable at the end of its SUB or FUNCTION, removal from a Collection, ERASE -- the object is freed and its Class_Terminate runs right then, just after the statement that let go of it:</p>
<pre><code>Dim a As New Account
Dim b As Account
Set b = a ' two references to one account
Set a = Nothing ' still alive: b refers to it
Set b = Nothing ' last reference gone: Class_Terminate runs now</code></pre>
<p>Objects that refer to each other, directly or around a longer loop, keep each other alive even after the program's own variables let them go. DVX BASIC finds such groups while the program runs: after every thousand or so new objects (more when the program keeps many objects), and when the program's code runs to its end, it looks for objects that only the group itself still refers to. Each of those whose class has a Class_Terminate gets it called once, oldest object first, with every object of the group still intact; afterwards the group is freed. An object that a Class_Terminate stores somewhere (Set saved = Me) stays alive, and its Class_Terminate does not run again. Breaking the loop yourself (for example Set a.Partner = Nothing) still frees the objects at once instead of at the next check.</p>
<p>When the program ends normally -- its code runs to the end, and with forms the last form is unloaded -- the module variables are released as in Visual Basic, so the objects only they still hold get their Class_Terminate then. When the program ends with END (or is stopped), every object still alive is freed without running Class_Terminate, as with END in Visual Basic. Work that must always happen, such as saving a file, belongs in a method the program calls itself, not only in Class_Terminate.</p>
<h2>Me</h2>
<p>Inside a class's procedures, Me is the object the procedure was called for. Use it to pass the object to other code, or to go through the object's own properties (Me.Balance runs Property Get Balance):</p>
<pre><code>Public Sub Move(ByVal dx As Double)
Me.X = Me.X + dx ' uses Property Get X and Property Let X
End Sub</code></pre>
<h2>Using Objects</h2>
<p>When the compiler knows an object's class -- a variable, array, parameter, member variable, or FUNCTION declared As the class name or As Collection, New ClassName, or Me in a class module -- its members are found when the program is compiled (early binding), as in Visual Basic. A misspelled member, a Private one, a Sub used where a value is needed, a property used as a statement, assigning a property that has no Property Let or Set, reading one that has no Property Get, and the wrong number of arguments are then compile errors that point at the member. Calls made this way are also faster. A class's own members can be used anywhere in the class, also above the line that declares them, and through Me a class reaches its Private members as well (Me.mTotal).</p>
<p>Through a variable declared As Object or As Variant the member is found by name when the program runs (late binding): obj.Deposit 5 looks for a Public member named Deposit in whatever object obj holds at that moment. A misspelled or Private member then raises error 438 when the line runs, and the wrong number of arguments raises error 450. Using a member of Nothing raises error 91 either way. An object of another class that reaches a variable of a class anyway (for example through a ByRef As Object argument) has its members found by name, as late binding would.</p>
<p>An argument that can never fit an object parameter of a SUB, FUNCTION, or method is a compile error too: a number or text, or an object of another class than the parameter's (unless that class Implements it).</p>
<p>An object can be kept in a variable declared as its class name, As Object, or As Variant, in an array, in a TYPE field, in a Collection, or in another object's member variable. It can be passed to a SUB or FUNCTION and returned from a FUNCTION (assign the result with SET inside the function, Set MakeAccount = acct). TYPENAME gives an object's class name, and TypeOf obj Is ClassName tests it; Is tells whether two variables refer to the same object.</p>
<p>Arguments of a class's procedures follow the rules of SUB and FUNCTION calls when the object variable is declared as the class name: a parameter without BYVAL gets the caller's variable, so the procedure can change it, an omitted OPTIONAL argument gets its default, and a ParamArray collects the rest. When the object is reached through a variable declared As Object or As Variant, a variable or array element given as an argument is passed by reference too if the procedure's parameter is not BYVAL (Visual Basic's rule; other expressions go by value). What the procedure stores in such a parameter is converted to the type of the caller's variable (an Integer stays an Integer, as in Visual Basic). A TYPE field given as an argument (obj.Move rec.x, obj.Move pts(1).x) is passed by reference as well (a BYVAL parameter gets its value). The methods of forms and controls always take their arguments by value. An argument left out in the middle of a call (obj.Report a, , c) or at the end is an OPTIONAL parameter's default value, else its empty value: 0, &quot;&quot;, and so on for a typed parameter, Missing for a Variant (ISMISSING is True). Leaving out a parameter that is not OPTIONAL raises error 449 (Argument not optional).</p>
<p>An object parameter is itself passed like any other parameter: without BYVAL, SET on the parameter changes the caller's variable (a SUB can make a new object for the caller); with BYVAL, the procedure gets its own reference to the same object, and SET on it does not affect the caller.</p>
<h2>CALLBYNAME</h2>
<pre><code>result = CALLBYNAME(object, memberName$, callType [, arguments...])
CALLBYNAME object, memberName$, callType [, arguments...]</code></pre>
<p>Uses the member of an object whose name the program has in a string, as if it had been written after a dot: a form, a control, a class instance, or a Collection. callType says what to do: vbGet reads a property (with arguments, a property that takes them), vbLet assigns it the last argument, vbSet assigns it an object (the last argument), vbMethod calls a method or function with the arguments. The function gives the property's value or the method's result (Empty for vbLet and vbSet); as a statement the result is dropped. Another callType raises error 5 (Illegal function call), as does vbLet or vbSet without a value; a member the object does not have raises the error the same member written after a dot would. A form designer's property window uses it to read and set the properties designer.bas lists for a control type.</p>
<pre><code>Dim prop As String
prop = &quot;Caption&quot;
Print CallByName(Command1, prop, vbGet) ' Command1.Caption
CallByName Command1, prop, vbLet, &quot;OK&quot; ' Command1.Caption = &quot;OK&quot;
CallByName List1, &quot;AddItem&quot;, vbMethod, &quot;one&quot; ' List1.AddItem &quot;one&quot;
Print CallByName(acct, &quot;Balance&quot;, vbGet) ' a class instance's property</code></pre>
<h2>Default Member</h2>
<p>A class can name one property or method as its default member, used when the object is written with parentheses directly after it. Put this line in the class, inside the procedure (as Visual Basic writes it) or on its own at the top of the class:</p>
<pre><code>Attribute Item.VB_UserMemId = 0</code></pre>
<p>With Item as the default member, obj(3) means obj.Item(3), and obj(3) = x calls Property Let Item. Collection's default member is Item, which is why c(1) and c(&quot;key&quot;) work. A call's result can be indexed directly, too: c(1)(0) is element 0 of the array item 1 holds, and Split(s, &quot;,&quot;)(2) the third part.</p>
<p>Where a value is needed -- in arithmetic, a comparison, text, PRINT, a typed variable, or a typed parameter -- an object stands for its default member's value, as in Visual Basic: with Value as the default member, total = obj + 1 reads obj.Value, and obj = 9 (without SET) stores 9 through it. A member variable can be the default member too (Attribute Label.VB_UserMemId = 0). An object without a default member used as a value raises error 13. The object name on its own still means the object itself wherever an object is expected: SET, Is, passing it to an object parameter, adding it to a Collection. Controls have default properties as well (Text1 means Text1.Text); see the control overview.</p>
<h2>WITH...END WITH</h2>
<p>WITH names an object or a TYPE record once for a block of statements; inside it, a name starting with a dot (.Value, .Add 3) is that object's member or that record's field:</p>
<pre><code>With acct
.Owner = &quot;Ada&quot;
.Deposit 100
Print .Balance
End With
With shapes(i).origin ' a TYPE record: its fields
.x = 5
.y = .x * 2
End With</code></pre>
<p>The expression after WITH is worked out once, when the block starts: With New Account makes one object that lives until End With, and With list(i) keeps the element it named even if i changes inside. WITH blocks can be nested; a dot then means the innermost one. A word after a space that starts with a dot is a new argument of its own (Bump .Count passes the member to Bump). Me works too (With Me). Leaving the block by GOTO or EXIT is allowed.</p>
<h2>Errors in a Class</h2>
<p>A class reports a problem with ERROR, normally numbered from vbObjectError so that its numbers cannot be mistaken for the built-in ones. The error is handled by the ON ERROR handler of the code that called the class, as with any procedure:</p>
<pre><code>' in the class
Public Sub Withdraw(ByVal amount As Double)
If amount &gt; mBalance Then Error vbObjectError + 1
mBalance = mBalance - amount
End Sub
' in the program
On Error GoTo NoMoney
acct.Withdraw 500
Exit Sub
NoMoney:
If Err = vbObjectError + 1 Then MsgBox &quot;Not enough money&quot;
Resume Next</code></pre>
<h2>Rules and Limits</h2>
<ul>
<li>A member's name cannot be a reserved word. Names such as Name, Show, Hide, Load, Print, Open, Close, Line, Input, Get, Put, Type, Error, and Timer are keywords in DVX BASIC and cannot be used; Text, Caption, Value, Count, Item, and Add are fine.</li>
<li>SHARED and DIM SHARED cannot be used in a class module; a class's code reaches the program's module variables that are declared DIM SHARED or PUBLIC.</li>
<li>A STATIC variable in a class procedure is kept per object, as in Visual Basic: each object has its own copy.</li>
<li>A class has at most 65536 member variables, its procedures' STATIC variables included; more fails to compile with &quot;Too many member variables in ClassName&quot;.</li>
<li>Class_Initialize and Class_Terminate take no parameters.</li>
<li>A class module cannot hold statements outside its procedures; the compiler reports &quot;Only declarations are allowed outside procedures in a class module&quot;.</li>
<li>NEW, PROPERTY, PUBLIC, PRIVATE, and TYPEOF are reserved words. VARIANT, OBJECT, COLLECTION, EMPTY, NULL, EACH, and IN are not.</li>
</ul>
<p><a href="#lang.events">See also: Events</a></p>
<p><a href="#lang.interfaces">See also: Interfaces (Implements)</a></p>
<p><a href="#lang.usercontrol">See also: UserControls: Your Own Controls</a></p>
<p><a href="#lang.collection">See also: Collection Object</a></p>
<p><a href="#lang.variants">See also: Variants</a></p>
<p><a href="#lang.declarations">See also: SET and PUBLIC / PRIVATE</a></p>
</div>
<div class="topic" id="lang.events">
<h1>Events</h1>
<p>A class module can announce that something happened -- a download finished, a value changed, a step of a long job was done -- and let the code that uses its objects react, the way a form reacts to a button's Click. The class declares the event and raises it; the program declares a variable WithEvents and writes a SUB for each event it wants to handle.</p>
<h2>Declaring and Raising an Event</h2>
<p>In the class module, declare each event at the top with EVENT, then raise it from any of the class's procedures with RAISEEVENT:</p>
<pre><code>' class module Downloader
Public Event Progress(ByVal percent As Integer, cancel As Boolean)
Public Event Done()
Public Sub Start()
Dim stopNow As Boolean
Dim p As Integer
For p = 10 To 100 Step 10
RaiseEvent Progress(p, stopNow)
If stopNow Then Exit Sub
Next
RaiseEvent Done
End Sub</code></pre>
<p>An event may have parameters but no return value. Its parameters cannot be OPTIONAL or a PARAMARRAY, and an event is always public (Public Event and Event mean the same; Private Event is an error). RAISEEVENT can only be used inside the class's own procedures, with exactly the arguments the event declares. A parameter without BYVAL is passed by reference, so a handler can change the variable given for it -- the cancel flag above is how a handler asks the class to stop. This holds for a variable, an array element (a(i)), and a TYPE field (rec.f, arr(i).f), as in Visual Basic. When several handlers get the event they all get the same variable, so each sees what the one before it stored; every store is converted to the variable's or field's type at once, as an assignment would be. While the handlers run, the arrays whose elements (or elements' fields) were given are locked: REDIM of one of them (or ERASE of a dynamic one) raises error 10. An expression, or a variable in its own parentheses, given for a by-reference parameter is passed as one temporary value that every handler shares, as in Visual Basic: the variable itself does not change, but a handler sees what the one before it stored. An argument is converted to the type of a typed event parameter, with the rules of SUB calls (a variable of another type given by reference is a compile error).</p>
<h2>Handling Events</h2>
<p>In a module, a form, or another class module, declare a variable of the class WithEvents, outside any procedure, and write a SUB named variable_EventName with the same parameters as the event:</p>
<pre><code>Dim WithEvents dl As Downloader
Sub StartDownload()
Set dl = New Downloader
dl.Start
End Sub
Sub dl_Progress(ByVal percent As Integer, cancel As Boolean)
Label1.Caption = percent &amp; &quot;%&quot;
If percent &gt;= 50 And StopWanted Then cancel = True
End Sub
Sub dl_Done()
MsgBox &quot;Finished&quot;
End Sub</code></pre>
<p>The handler's parameters must match the event's: the same number, the same types, and the same BYVAL / BYREF choice, or the program does not compile. A handler is optional: an event nobody handles does nothing. RAISEEVENT calls the handler of every WithEvents variable that holds the raising object at that moment -- two variables holding the same object both get the event, in the order they were declared -- and waits for them to finish before the class's code continues. Setting the variable to another object (or to Nothing) moves the handlers to the new object at once.</p>
<p>A WithEvents variable in a form belongs to that form: its handlers run with the form's own variables and controls, even when the event is raised while another form's code is running, and a form that is loaded twice gets its own variable each time. Unloading the form stops its handlers.</p>
<h2>Events in a Class Module</h2>
<p>A class can handle the events of objects it holds. The variable is a member variable (usually Private) and the handlers are the class's own procedures; each object of the class handles the events of the object in its own variable, and the handler runs for that object (Me):</p>
<pre><code>' Class module Logger
Private WithEvents source As Downloader
Private lines As Integer
Public Sub Watch(d As Downloader)
Set source = d
End Sub
Private Sub source_Progress(ByVal percent As Integer, cancel As Boolean)
lines = lines + 1
Print &quot;log&quot;; lines; percent
End Sub</code></pre>
<p>Lifetime rule: listening never keeps an object alive. The object that raises an event does not hold a reference to its listeners; only the listener's own variable refers to the source. So:</p>
<ul>
<li>A listener lives as long as the program holds it, like any other object. When its last reference goes, its Class_Terminate runs and it hears nothing more -- an event is never delivered to an object that has ended.</li>
<li>While a handler runs, the listener is held for the call, so a handler may drop the last outside reference to its own object (or Set its WithEvents variable to Nothing) safely; Class_Terminate then runs after the handler returns.</li>
<li>A cycle -- the source holding a reference back to its listener, for example a Parent or Owner member -- is collected like any other cycle of objects: when nothing outside refers to them, both Class_Terminate procedures run (the older object first) and the objects are freed. An event raised during those Class_Terminate calls still reaches listeners that have not been freed yet.</li>
<li>Several listeners may hold the same source: RAISEEVENT calls the module and form handlers first, then those of listening objects, the most recently created first.</li>
</ul>
<h2>Rules</h2>
<ul>
<li>WITHEVENTS goes with DIM, PUBLIC, or PRIVATE at the top level of a module, form, or class module (not inside a procedure), for a single variable declared as a class module's name. It cannot be an array and cannot use New: Set it to an object in code.</li>
<li>A WithEvents variable is visible to the procedures of its module or form without SHARED, as the handlers and the code that sets it need; in a class module it is a member variable of each object.</li>
<li>Handlers are SUBs named variable_EventName in the same module, form, or class module as the variable.</li>
<li>EVENT, RAISEEVENT, WITHEVENTS, and IMPLEMENTS are not reserved words: they only have their meaning where a name follows them in those places, so a program may still use them as its own names.</li>
</ul>
<p><a href="#lang.classes">See also: Objects and Class Modules</a></p>
<p><a href="#lang.interfaces">See also: Interfaces (Implements)</a></p>
</div>
<div class="topic" id="lang.interfaces">
<h1>Interfaces (Implements)</h1>
<p>An interface is a set of properties and methods that several classes promise to provide, so that code can work with any of them through one variable type. In DVX BASIC, as in Visual Basic, the interface is an ordinary class module -- its procedures are usually left empty -- and a class that provides it says IMPLEMENTS:</p>
<pre><code>' class module IShape
Public Function Area() As Double
End Function
Public Sub Scale(ByVal factor As Double)
End Sub
' class module Circle
Implements IShape
Private r As Double
Private Function IShape_Area() As Double
IShape_Area = 3.14159 * r * r
End Function
Private Sub IShape_Scale(ByVal factor As Double)
r = r * factor
End Sub</code></pre>
<p>For every public member of the interface, the implementing class writes a procedure named Interface_Member of the same kind (Sub, Function, Property Get / Let / Set) with the same number of parameters, ending in a ParamArray exactly when the interface's does; they are usually Private, so they are only reached through the interface. A call through the interface reaches the implementation directly (the compiler records which procedure implements each member), and an implementation's BYVAL parameter gets a value even where the interface's parameter is ByRef. A public variable of the interface is implemented as a Property Get and a Property Let (Property Set for an object variable). A class that leaves one out does not compile.</p>
<p>Code then uses the objects through a variable declared as the interface:</p>
<pre><code>Dim s As IShape
Set s = New Circle
s.Scale 2
Print s.Area ' runs Circle's IShape_Area
Print TypeOf s Is IShape ' True
Print TypeName(s) ' Circle</code></pre>
<p>Through a variable declared as the interface, a member always means the interface's member, even when the class has a public member of the same name of its own. Through the class's own type, As Object, or As Variant, the class's own public members are used. SET into a variable of the interface type accepts an object of any class that Implements it (and of the interface class itself); TypeOf obj Is Interface is True for them. A class can implement several interfaces with one IMPLEMENTS line for each. An argument left out of a call through the interface takes the default the interface's procedure declares, as in Visual Basic, even if the implementing procedure declares another. Friend procedures are not part of an interface.</p>
<p><a href="#lang.classes">See also: Objects and Class Modules</a></p>
<p><a href="#lang.events">See also: Events</a></p>
</div>
<div class="topic" id="lang.collection">
<h1>Collection Object</h1>
<p>A Collection is a ready-made object that holds a list of items of any kind -- numbers, text, objects -- in order. Items can be looked up by position or by a text key, added anywhere in the list, and removed, and FOR EACH walks through them. The list grows as needed; there is no size to declare.</p>
<pre><code>Dim fruit As New Collection
fruit.Add &quot;Apple&quot;, &quot;a&quot;
fruit.Add &quot;Cherry&quot;, &quot;c&quot;
fruit.Add &quot;Banana&quot;, &quot;b&quot;, &quot;c&quot; ' before the item with key &quot;c&quot;
Print fruit.Count ' 3
Print fruit(1) ' Apple
Print fruit(&quot;B&quot;) ' Banana (keys ignore case)
Dim f As Variant
For Each f In fruit
Print f ' Apple, Banana, Cherry
Next
fruit.Remove &quot;a&quot;
fruit.Remove 1 ' removes Banana, now the first item</code></pre>
<h2>Members</h2>
<pre> Member Description
------ -----------
Add item [, key] [, before] [, after] Adds item at the end of the list, or before or after the item given by position or key. key, when given, is text that names the item.
Remove indexOrKey Removes the item at that position (1 = first) or with that key.
Item(indexOrKey) The item at that position or with that key. Item is the default member: c(2) is c.Item(2) and c(&quot;key&quot;) is c.Item(&quot;key&quot;).
Count The number of items.</pre>
<p>Positions start at 1 and change as items are added and removed. A key must be text, is compared without regard to upper and lower case, and must be unique in the Collection. Give either before or after, not both; leave out the arguments you do not use with commas (c.Add item, , 1 puts item first). Items are stored as they are: an object added to a Collection stays alive while the Collection holds it.</p>
<p>Make a Collection with DIM c AS NEW COLLECTION or SET c = NEW COLLECTION. Like any object, it is freed when the last reference to it goes.</p>
<p>Through a variable declared As Collection the members are checked when the program is compiled: another member name, the wrong number of arguments, using Add or Remove as a value, Count or Item as a statement, and assigning any of them are compile errors. Keyed lookups compare a hash of the key first, so finding an item by key stays fast in large Collections.</p>
<h2>Errors</h2>
<pre> Error When
----- ----
5 A key that is not in the Collection (Item, Remove, before, or after), or Add given both before and after
9 A position that is not in the Collection
13 A key that is not text
438 A member other than Add, Remove, Item, and Count, or assigning one, through As Object or As Variant
450 The wrong number of arguments, through As Object or As Variant
457 Add with a key that is already in use</pre>
<p><a href="#lang.classes">See also: Objects and Class Modules</a></p>
<p><a href="#lang.loops">See also: FOR EACH...NEXT</a></p>
</div>
<div class="topic" id="lang.sql">
<h1>SQL Functions</h1>
<p>DVX BASIC includes SQLite database support through the sql.bas include library. Add sql.bas to your project to gain access to these functions. All functions use database handles and result-set handles (Long integers) returned by SQLOpen and SQLQuery. Numeric parameters and results are Long, so row counts and integer column values keep their full 32-bit range.</p>
<p>SQLite is in the Databases part of DVX, which can be left out when DVX is installed. Without it the SQL functions do nothing: SQLOpen returns 0, and SQLError$ says that Databases are not installed. SysLibraryLoaded(&quot;dvxsql&quot;) (system.bas) tells beforehand.</p>
<h2>Opening and Closing Databases</h2>
<h3>SQLOpen</h3>
<p>Opens a SQLite database file and returns a database handle (&gt; 0) or 0 on failure. The file is created if it does not exist. A file that cannot be changed (for example one marked read-only) still opens, but only for reading. When SQLOpen returns 0, SQLError$(0) tells you why.</p>
<pre><code>db = SQLOpen(path$)</code></pre>
<pre><code>db = SQLOpen(App.Data &amp; &quot;\mydata.db&quot;)</code></pre>
<h3>SQLClose</h3>
<p>Closes an open database.</p>
<pre><code>SQLClose db</code></pre>
<h2>Executing SQL</h2>
<h3>SQLExec</h3>
<p>Executes a SQL statement that does not return data (INSERT, UPDATE, DELETE, CREATE TABLE, etc.). Returns True on success.</p>
<pre><code>ok = SQLExec(db, sql$)</code></pre>
<pre><code>SQLExec db, &quot;CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)&quot;
SQLExec db, &quot;INSERT INTO users (name) VALUES ('Scott')&quot;
ok = SQLExec(db, &quot;DELETE FROM users WHERE id = 5&quot;)</code></pre>
<p>Put text values in single quotes, as in the examples. Text in double quotes is read as a column name, so &quot;Scott&quot; in place of 'Scott' gives the error &quot;no such column: Scott&quot;.</p>
<h3>SQLEscape$</h3>
<p>Returns text with every single quote doubled, the way SQL writes a quote inside a quoted value. Use it on text the user typed (or read from a file) before you put it between quotes in a statement: a name such as O'Brien would otherwise end the value early and break the statement.</p>
<pre><code>SQLExec db, &quot;INSERT INTO users (name) VALUES ('&quot; &amp; SQLEscape$(name$) &amp; &quot;')&quot;</code></pre>
<p>SQLExec runs every statement in sql$, one after another, before it returns.</p>
<h3>Long Statements</h3>
<p>A statement can take a while: one that changes many rows, CREATE INDEX on a big table, or the first SQLNext of a query that sorts or groups, which reads every row first. While a statement runs, DVX and the other programs keep going, and your program's events run as they do during DoEvents. Ending the program (End, or closing its last form) stops the statement, and what it changed is undone.</p>
<p>An event that runs meanwhile cannot use the database the statement is running on: SQLExec, SQLQuery, and SQLNext return False or 0, and SQLError$ says &quot;A statement is still running on this database&quot;. Its field functions return &quot;&quot; or 0. SQLFreeResult and SQLClose wait until the statement ends. Other databases can be used as always.</p>
<p>Code in a control file (a control written in BASIC) does not wait like this: its statements run to the end.</p>
<h3>SQLAffected</h3>
<p>Returns the number of rows affected by the last INSERT, UPDATE, or DELETE.</p>
<pre><code>count = SQLAffected(db)</code></pre>
<h2>Querying Data</h2>
<h3>SQLQuery</h3>
<p>Executes a SELECT query and returns a result-set cursor.</p>
<pre><code>rs = SQLQuery(db, sql$)</code></pre>
<pre><code>rs = SQLQuery(db, &quot;SELECT id, name FROM users ORDER BY name&quot;)</code></pre>
<h3>SQLNext</h3>
<p>Advances the cursor to the next row. Returns True if a row is available, False when there are no more rows.</p>
<pre><code>hasRow = SQLNext(rs)</code></pre>
<h3>SQLEof</h3>
<p>Returns True if the cursor is past the last row.</p>
<pre><code>done = SQLEof(rs)</code></pre>
<h2>Reading Fields</h2>
<h3>SQLField$ / SQLFieldText$</h3>
<p>Returns a field value as a string. Use SQLField$ to look up by column name; use SQLFieldText$ to look up by 0-based column index.</p>
<pre><code>value$ = SQLField$(rs, columnName$)
value$ = SQLFieldText$(rs, columnIndex)</code></pre>
<pre><code>name$ = SQLField$(rs, &quot;name&quot;)
first$ = SQLFieldText$(rs, 0)</code></pre>
<h3>SQLFieldName$</h3>
<p>Returns the column name for a given 0-based column index.</p>
<pre><code>colName$ = SQLFieldName$(rs, columnIndex)</code></pre>
<h3>SQLFieldInt</h3>
<p>Returns a field value as a Long integer.</p>
<pre><code>value = SQLFIELDINT(rs, columnIndex)</code></pre>
<h3>SQLFieldDbl</h3>
<p>Returns a field value as a double.</p>
<pre><code>value# = SQLFIELDDBL(rs, columnIndex)</code></pre>
<h3>SQLFieldCount</h3>
<p>Returns the number of columns in the result set.</p>
<pre><code>count = SQLFieldCount(rs)</code></pre>
<h2>Result Set Cleanup</h2>
<h3>SQLFreeResult</h3>
<p>Frees a result-set cursor. Always call this when finished iterating a query.</p>
<pre><code>SQLFreeResult rs</code></pre>
<h2>Error Information</h2>
<h3>SQLError$</h3>
<p>Returns the last error message for the database.</p>
<pre><code>msg$ = SQLError$(db)</code></pre>
<p>When a database file could not be opened, read, or written, the message ends with the reason in parentheses, for example &quot;unable to open database file (No such file or directory)&quot;. If another program, or another handle in your own program, is changing the same database at that moment, the message is &quot;database is locked&quot;: try again once the other change is finished, and free result sets with SQLFreeResult as soon as you are done with them, because an open result set stops other handles from saving changes.</p>
<h2>Complete SQL Example</h2>
<pre><code>Dim db As Long
Dim rs As Long
db = SQLOpen(App.Data &amp; &quot;\contacts.db&quot;)
SQLExec db, &quot;CREATE TABLE IF NOT EXISTS contacts (name TEXT, phone TEXT)&quot;
SQLExec db, &quot;INSERT INTO contacts VALUES ('Alice', '555-1234')&quot;
rs = SQLQuery(db, &quot;SELECT name, phone FROM contacts&quot;)
Do While SQLNext(rs)
Print SQLField$(rs, &quot;name&quot;); Tab(20); SQLField$(rs, &quot;phone&quot;)
Loop
SQLFreeResult rs
SQLClose db</code></pre>
</div>
<div class="topic" id="lang.app">
<h1>App Object</h1>
<p>The App object provides read-only properties for the program's folders.</p>
<pre> Property Returns Description
-------- ------- -----------
App.Path String The folder the program is in
App.User String The program's own folder in the user folder: its settings and every file it saves (databases, saved games, documents)
App.Data String The DATA folder in the program's folder: the files the program comes with (read-only)</pre>
<p>App.User is the place to write: it is kept apart from the program, so installing a new version never overwrites what is there, and backing up the user folder keeps it. Every copy of the program gets the same folder. It is made the first time App.User is used. App.Data is for reading only: on a CD-ROM it cannot be written at all. Programs never write in DVX's SHARED folder.</p>
<pre><code>settingsFile$ = App.User &amp; &quot;\settings.ini&quot;
dbPath$ = App.User &amp; &quot;\myapp.db&quot;
levelFile$ = App.Data &amp; &quot;\level1.dat&quot;
Print &quot;Running from: &quot; &amp; App.Path</code></pre>
</div>
<div class="topic" id="lang.clipboard">
<h1>Clipboard Object</h1>
<p>The Clipboard object shares text with other programs and with the copy and paste of text boxes, as in Visual Basic. The DVX clipboard holds text only, so the format arguments accept vbCFText (1): any other format is never present and GetText returns &quot;&quot; for it.</p>
<pre> Method Returns Description
------ ------- -----------
Clipboard.Clear (none) Empty the clipboard.
Clipboard.GetFormat(format) Boolean True when the clipboard holds data of that format (text for vbCFText).
Clipboard.GetText([format]) String The clipboard text, or &quot;&quot; when it is empty.
Clipboard.SetText text [, format] (none) Put text on the clipboard, replacing what was there. A format other than vbCFText is an error.</pre>
<pre><code>Clipboard.SetText Text1.Text
If Clipboard.GetFormat(vbCFText) Then Text2.Text = Clipboard.GetText()</code></pre>
<p>A control or form of your own named Clipboard takes the name's place.</p>
</div>
<div class="topic" id="lang.printerobj">
<h1>Printer Object</h1>
<p>The Printer object draws pages on the printer chosen in the Control Panel, as in Visual Basic: text in any font at a size in points, lines, boxes, circles, dots, and pictures, anywhere on the page, page after page. It needs a printer model that prints pictures (the Control Panel's Printer page); on a color printer the colors print as they are, on the others in shades of grey.</p>
<p>On a PostScript printer the page is drawn by the printer itself, as lines, curves, and letters rather than dots, so it prints as sharp as the printer can. Text is in the printer's own Helvetica, Times, or Courier, whichever is nearest FontName: Courier for a fixed-pitch font or a name with Mono or Courier in it, Times for a name with Serif, Times, Roman, Tinos, or Ledger in it (but not Sans), and Helvetica for the rest. TextWidth and TextHeight measure the printer's letters, so text lines up as it will print.</p>
<p>A page is 8 by 10 inches. Its coordinates are twips (1440 an inch) until ScaleMode or Scale changes them, as on Visual Basic's Printer, so a program can place things in inches, centimetres, points, or its own units. Drawing goes to the page being made; NewPage prints it and starts the next, and EndDoc prints the last one and ends the document. The document starts when the first page is printed, at the printer and with the copies the program's last PrintChoose (print.bas) chose, or else as the Control Panel has them; while it prints, the Printing window shows, with Cancel. A program that ends with a page drawn or a document started has EndDoc done for it.</p>
<pre> Method Description
------ -----------
Printer.Print items Text at CurrentX / CurrentY in the font and ForeColor, as PRINT lays it out: ; joins, a comma goes to the next 14-character zone, TAB(n) and SPC(n) count characters of the font (its 0's width), and a new line goes down a line of the font. CurrentX / CurrentY move past it.
Printer.Line [(x1, y1)]-(x2, y2) [, color] [, B | BF] A line, a box, or a filled box, as on a PictureBox (STEP works too).
Printer.Circle (x, y), r [, color [, start, end [, aspect]]] A circle, ellipse, or arc; filled in FillColor when FillStyle is not transparent. Circles are round on paper on every printer.
Printer.PSet (x, y) [, color] One dot (DrawWidth across).
Printer.PaintPicture pic, x, y [, w, h [, srcX, srcY, srcW, srcH]] A picture (a PictureBox, a file, or LoadPicture's), stretched to w x h; without them, at its size on the screen (15 twips a pixel).
Printer.NewPage Print the page (even a blank one) and start the next; Page goes up by 1.
Printer.EndDoc Print the page drawn and end the document; Page goes back to 1.
Printer.KillDoc Throw the page drawn away and end the document (pages already printed stay printed).
Printer.TextWidth(text), TextHeight(text) The size text takes in the font, in the Printer's scale.
Printer.Scale (x1, y1)-(x2, y2), ScaleX, ScaleY As on a PictureBox: a scale of your own, and lengths from one scale to another.</pre>
<pre> Property Description
-------- -----------
CurrentX, CurrentY Where the next drawing starts.
ForeColor, FillColor, FillStyle, DrawWidth, DrawStyle As on a PictureBox (black, transparent fills, a solid pen 1 dot wide to start).
ScaleMode, ScaleLeft, ScaleTop, ScaleWidth, ScaleHeight The scale (vbTwips to start).
FontName, FontSize, FontBold, FontItalic, FontUnderline, FontStrikethru The font of Print's text; FontSize is in points (12 to start, in DejaVu Sans). Text prints crisp where the font has sizes made for printing (DejaVu Sans, Serif, and Sans Mono have them from 6 to 24 points at 300 dpi), and a little softer where a smaller size is enlarged.
Copies How many times each page prints (1 to 99); as PrintChoose chose when it is not set.
Page The page being drawn (1 first). Read only.
Width, Height The page's size in twips (11520 by 14400). Read only.
TwipsPerPixelX, TwipsPerPixelY Twips in one of the printer's dots. Read only.
ColorMode vbPRCMColor on a color printer, else vbPRCMMonochrome. Read only.
Orientation vbPRORPortrait: pages print upright only.
DeviceName, Port The printer model and where it is connected, as the Control Panel names them. Read only.</pre>
<pre><code>Sub mnuReport_Click ()
Printer.ScaleMode = vbInches
Printer.FontSize = 18
Printer.FontBold = True
Printer.CurrentX = 1
Printer.CurrentY = 1
Printer.Print &quot;Sales by Region&quot;
Printer.FontSize = 11
Printer.FontBold = False
Printer.Line (1, 1.5)-(7, 1.5)
Printer.FillStyle = 0
Printer.FillColor = vbBlue
Printer.Line (1, 2)-(1 + nNorth / 100, 2.4), vbBlue, B
Printer.CurrentX = 1: Printer.CurrentY = 2.5
Printer.Print &quot;North&quot;; Tab(20); nNorth
Printer.EndDoc
End Sub</code></pre>
<p>The Printer has no Cls, Point, PAINT, or DRAW (Visual Basic's Printer has none of them either), and no Printer.Font object: use FontName, FontSize, and the other Font properties. A raster operation given to PaintPicture is not used on paper. A control or form of your own named Printer takes the name's place.</p>
<h2>Printer Constants</h2>
<pre> Constant Value Description
-------- ----- -----------
vbPRORPortrait 1 Printer.Orientation: upright pages (the only one)
vbPRORLandscape 2 Printer.Orientation: sideways pages (not supported)
vbPRCMMonochrome 1 Printer.ColorMode: black (and grey) only
vbPRCMColor 2 Printer.ColorMode: color</pre>
</div>
<div class="topic" id="lang.screenobj">
<h1>Screen Object</h1>
<p>The Screen object is the DVX desktop, as in Visual Basic: its size, so a program can place its forms (for example in a corner of the screen), its colour depth, the mouse pointer, and the arrangement of the windows on it.</p>
<pre> Property Type R/W Description
-------------------- ------- --- -----------
Screen.Width Long R Width of the desktop in pixels
Screen.Height Long R Height of the desktop in pixels
Screen.BitsPerPixel Long R Colour depth of the display: 8, 15, 16, 24, or 32 bits per pixel
Screen.MousePointer Integer R/W vbHourglass (11) for the busy pointer while a long job runs; another pointer (vbArrow, vbCrosshair, vbSizeNS, vbSizeWE, vbSizeNWSE, vbSizeNESW, vbNoDrop: see Mouse Constants) over every form of the program, whatever their controls' MousePointer; vbDefault (0) back to each control's own
Screen.ActiveControl Control R The control of the program that has the keyboard focus, Nothing when none has it (another program's window has the focus)
Screen.DebugLayout Boolean R/W True draws a coloured border around every layout container (VBox, HBox, Frame ...) in every window, to see how a form is laid out; False removes them</pre>
<p>The sizes are in pixels, the unit of a form's Left, Top, Width, and Height in DVX (Visual Basic uses twips there).</p>
<pre><code>' Put the form at the right edge, 40 pixels from the top
Me.Left = Screen.Width - Me.Width - 40
Me.Top = 40</code></pre>
<p>Set the hourglass before a long job and put the arrow back after it. The pointer is the whole desktop's, so the program should not leave it busy; when the program ends, a busy pointer it set goes back to the arrow.</p>
<pre><code>Screen.MousePointer = vbHourglass
CountWords
Screen.MousePointer = vbDefault</code></pre>
<h2>Arrange</h2>
<p>Screen.Arrange arrangement puts every window on the desktop that is shown and not minimized (those of other programs too) in order, as the Window menu of a program does:</p>
<pre> Constant Value Arrangement
---------------- ----- -----------
vbCascade 0 Overlapping, each one a little down and to the right of the one before
vbTileHorizontal 1 Stacked from top to bottom, each the full width of the screen
vbTileVertical 2 Side by side from left to right, each the full height of the screen
vbTileGrid 4 In rows and columns</pre>
<p>The values are those of Visual Basic's MDIForm.Arrange (vbTileGrid is DVX's own; 3, Visual Basic's vbArrangeIcons, is not used).</p>
<pre><code>Sub mnuCascade_Click ()
Screen.Arrange vbCascade
End Sub</code></pre>
<p>Any other property, method, or value stops the program with an error. The QBasic statement SCREEN and function SCREEN(row, column) are unaffected: Screen followed by a dot is the object. A control or form of your own named Screen takes the name's place.</p>
</div>
<div class="topic" id="lang.ini">
<h1>INI Functions</h1>
<p>DVX BASIC provides built-in functions for reading and writing standard INI configuration files (the same text format used by DVX system configuration).</p>
<h2>IniRead</h2>
<p>Reads a value from an INI file. Returns the default value if the file, section, or key is not found. All four arguments are required. Section and key names match without regard to case, and blanks around them are ignored ([ User ] is section User). If a name appears twice, the first one counts. Keys above the first section header belong to section &quot;&quot; (an empty section name). Lines starting with ; or # are comments.</p>
<pre><code>value$ = IniRead(file$, section$, key$, default$)</code></pre>
<pre><code>name$ = IniRead(App.User &amp; &quot;\app.ini&quot;, &quot;User&quot;, &quot;Name&quot;, &quot;Unknown&quot;)
fontSize = Val(IniRead(App.User &amp; &quot;\app.ini&quot;, &quot;Display&quot;, &quot;FontSize&quot;, &quot;12&quot;))</code></pre>
<h2>IniWrite</h2>
<p>Writes a value to an INI file. Creates the file, section, or key if they do not exist. A new key goes after the last key of its section and a new section at the end of the file. Every other line -- comments, blank lines, other keys, lines of any length -- is kept exactly as it is. The changed key is written as key = value. Every line of the saved file ends in a carriage return and line feed (CR LF). The file is saved through a temporary file, so a failed write leaves the old file intact. If the file exists but cannot be read, or the new file cannot be written, IniWrite raises error 75 (Path/file access error) and leaves the file alone.</p>
<pre><code>INIWRITE file$, section$, key$, value$</code></pre>
<pre><code>IniWrite App.User &amp; &quot;\app.ini&quot;, &quot;User&quot;, &quot;Name&quot;, &quot;Scott&quot;
IniWrite App.User &amp; &quot;\app.ini&quot;, &quot;Display&quot;, &quot;FontSize&quot;, Str$(fontSize)</code></pre>
</div>
<div class="topic" id="lang.constants">
<h1>Predefined Constants</h1>
<p>The following constants are predefined by the compiler and available in all programs. No DIM or CONST declaration is required to use them.</p>
<h2>MsgBox Button Style Flags</h2>
<pre> Constant Value Description
-------- ----- -----------
vbOKOnly 0 OK button only (default)
vbOKCancel 1 OK and Cancel buttons
vbYesNo 2 Yes and No buttons
vbYesNoCancel 3 Yes, No, and Cancel buttons
vbRetryCancel 4 Retry and Cancel buttons</pre>
<h2>MsgBox Icon Flags</h2>
<p>Add an icon flag to the button style (with + or OR) to display an icon in the message box.</p>
<pre> Constant Value Description
-------- ----- -----------
vbInformation &amp;H10 Information icon (i)
vbExclamation &amp;H20 Warning icon (!)
vbCritical &amp;H30 Error/critical icon (X)
vbQuestion &amp;H40 Question icon (?)</pre>
<h2>MsgBox Return Values</h2>
<pre> Constant Value Description
-------- ----- -----------
vbOK 1 User clicked OK
vbCancel 2 User clicked Cancel
vbYes 3 User clicked Yes
vbNo 4 User clicked No
vbRetry 5 User clicked Retry</pre>
<h2>Show Mode Flags</h2>
<pre> Constant Value Description
-------- ----- -----------
vbModal 1 Show form as modal dialog</pre>
<h2>Window State, Arrangement, and Mouse Pointer</h2>
<p>A form's WindowState and Screen.Arrange (see Form and Screen Object); the MousePointer values are under Mouse Constants.</p>
<pre> Constant Value Description
-------- ----- -----------
vbNormal 0 WindowState: a normal window
vbMinimized 1 WindowState: shown only as an icon
vbMaximized 2 WindowState: filling the screen
vbCascade 0 Arrange: overlapping windows
vbTileHorizontal 1 Arrange: windows stacked top to bottom
vbTileVertical 2 Arrange: windows side by side
vbTileGrid 4 Arrange: windows in rows and columns</pre>
<h2>File Attribute Flags</h2>
<p>Bit values used with GETATTR and SETATTR.</p>
<pre> Constant Value Description
-------- ----- -----------
vbNormal 0 Normal file (no attributes)
vbReadOnly 1 Read-only
vbHidden 2 Hidden
vbSystem 4 System file
vbDirectory 16 Entry is a directory
vbArchive 32 File has been modified since last backup</pre>
<h2>Compare Constants</h2>
<p>The compare argument of FILTER, INSTRREV, REPLACE$, SPLIT, and STRCOMP.</p>
<pre> Constant Value Description
-------- ----- -----------
vbUseCompareOption -1 Follow OPTION COMPARE (the default)
vbBinaryCompare 0 Exact match
vbTextCompare 1 Ignore upper and lower case</pre>
<h2>Day and Week Constants</h2>
<p>The firstDay and firstWeek arguments of the date functions, and WEEKDAY results.</p>
<pre> Constant Value Description
-------- ----- -----------
vbUseSystemDayOfWeek 0 Weeks start on Sunday
vbSunday 1 Sunday
vbMonday 2 Monday
vbTuesday 3 Tuesday
vbWednesday 4 Wednesday
vbThursday 5 Thursday
vbFriday 6 Friday
vbSaturday 7 Saturday
vbUseSystem 0 Week 1 holds January 1
vbFirstJan1 1 Week 1 holds January 1
vbFirstFourDays 2 Week 1 is the first with four days in the new year
vbFirstFullWeek 3 Week 1 is the first full week</pre>
<h2>Drag and Drop Constants</h2>
<p>The DragMode property, the Drag method, and the State argument of DragOver.</p>
<pre> Constant Value Description
-------- ----- -----------
vbManual 0 DragMode: the program starts drags with Drag
vbAutomatic 1 DragMode: pressing the control starts a drag
vbBeginDrag 1 Drag: start dragging (the default)
vbEndDrag 2 Drag: drop where the mouse is (Drag 0 cancels)
vbEnter 0 DragOver: the drag came onto the object
vbLeave 1 DragOver: the drag went off the object
vbOver 2 DragOver: the drag moved over the object</pre>
<h2>Clipboard Constants</h2>
<pre> Constant Value Description
-------- ----- -----------
vbCFText 1 Text, the format the DVX clipboard holds</pre>
<h2>Mouse Constants</h2>
<p>The Button argument of the MouseDown, MouseUp, and MouseMove events (several bits when several buttons are down), and the values of MousePointer (controls, forms, and Screen).</p>
<pre> Constant Value Description
-------- ----- -----------
vbLeftButton 1 The left button
vbRightButton 2 The right button
vbMiddleButton 4 The middle button
vbDefault 0 MousePointer: the control's own pointer
vbArrow 1 MousePointer: the arrow
vbCrosshair 2 MousePointer: a cross, for placing things
vbSizeNESW 6 MousePointer: two-way arrow, top right to bottom left
vbSizeNS 7 MousePointer: two-way arrow, up and down
vbSizeNWSE 8 MousePointer: two-way arrow, top left to bottom right
vbSizeWE 9 MousePointer: two-way arrow, left and right
vbHourglass 11 MousePointer: busy
vbNoDrop 12 MousePointer: a circle with a line through it</pre>
<p>Visual Basic's other pointers (vbIbeam, vbUpArrow, custom pointers) have no DVX shape; DVX has no MouseIcon.</p>
<h2>Syntax Colour Constants</h2>
<p>The kinds of text a TextArea colours: the index of SetSyntaxColor and GetSyntaxColor, and the digits of the Colors argument of the Colorize event (&quot;0&quot; is vbSyntaxText ... &quot;6&quot; vbSyntaxType).</p>
<pre> Constant Value Description
-------- ----- -----------
vbSyntaxText 0 Ordinary text (ForeColor)
vbSyntaxKeyword 1 Keywords
vbSyntaxString 2 Strings
vbSyntaxComment 3 Comments
vbSyntaxNumber 4 Numbers
vbSyntaxOperator 5 Operators
vbSyntaxType 6 Type names</pre>
<h2>CallByName Constants</h2>
<pre> Constant Value Description
-------- ----- -----------
vbMethod 1 Call a method (or a function of a class)
vbGet 2 Read a property
vbLet 4 Assign a property a value
vbSet 8 Assign a property an object (Set)</pre>
<h2>Key Code Constants</h2>
<p>The KeyCode a KeyDown event gets, and the bits of its Shift argument. These are DVX's codes, so compare KeyCode with the constants rather than with numbers from Visual Basic. A character key gives its character's code (Asc(&quot;a&quot;) with no Shift), and Ctrl with a letter gives 1 to 26 (Ctrl+A is 1, Ctrl+C 3, Ctrl+V 22, Ctrl+X 24).</p>
<pre> Constant Value Description
-------- ----- -----------
vbKeyBack 8 Backspace
vbKeyTab 9 Tab
vbKeyReturn 13 Enter
vbKeyEscape 27 Esc
vbKeySpace 32 Space bar
vbKeyPageUp, vbKeyPageDown &amp;H149, &amp;H151 Page Up, Page Down
vbKeyEnd, vbKeyHome &amp;H14F, &amp;H147 End, Home
vbKeyLeft, vbKeyUp &amp;H14B, &amp;H148 Arrow keys
vbKeyRight, vbKeyDown &amp;H14D, &amp;H150 Arrow keys
vbKeyInsert, vbKeyDelete &amp;H152, &amp;H153 Ins, Del
vbKeyF1 to vbKeyF10 &amp;H13B to &amp;H144 Function keys F1 to F10
vbKeyF11, vbKeyF12 &amp;H185, &amp;H186 Function keys F11 and F12
vbShiftMask 3 Shift argument: a Shift key is down
vbCtrlMask 4 Shift argument: Ctrl is down
vbAltMask 8 Shift argument: Alt is down</pre>
<pre><code>Sub List1_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyDelete Then
DeleteSelected
ElseIf KeyCode = 1 And (Shift And vbCtrlMask) &lt;&gt; 0 Then
SelectEverything ' Ctrl+A
End If
End Sub</code></pre>
<h2>Scale and Picture Constants</h2>
<p>The scale units of ScaleMode and of the ScaleX / ScaleY methods, and the values of a Picture object's Type (see Drawing on Forms and PictureBoxes, and LOADPICTURE).</p>
<pre> Constant Value Description
-------- ----- -----------
vbUser 0 The object's own scale (Scale, ScaleWidth ...)
vbTwips 1 Twips (1440 an inch, 15 a pixel)
vbPoints 2 Points (72 an inch)
vbPixels 3 Pixels (the DVX default ScaleMode)
vbCharacters 4 Characters (120 twips across, 240 down)
vbInches 5 Inches
vbMillimeters 6 Millimetres
vbCentimeters 7 Centimetres
vbHimetric 8 Hundredths of a millimetre (ScaleX / ScaleY only; a Picture's Width and Height)
vbPicTypeNone 0 Picture.Type of an empty picture
vbPicTypeBitmap 1 Picture.Type of a loaded picture</pre>
<h2>Fill and Pen Constants</h2>
<p>The values of FillStyle and DrawStyle on Forms, PictureBoxes, and the Printer (see Drawing on Forms and PictureBoxes).</p>
<pre> Constant Value Description
-------- ----- -----------
vbFSSolid 0 FillStyle: filled solid in FillColor
vbFSTransparent 1 FillStyle: not filled (the default)
vbHorizontalLine 2 FillStyle: horizontal lines
vbVerticalLine 3 FillStyle: vertical lines
vbUpwardDiagonal 4 FillStyle: lines rising to the right
vbDownwardDiagonal 5 FillStyle: lines falling to the right
vbCross 6 FillStyle: a cross hatch
vbDiagonalCross 7 FillStyle: a diagonal cross hatch
vbSolid 0 DrawStyle: a solid pen (the default)
vbDash 1 DrawStyle: dashes
vbDot 2 DrawStyle: dots
vbDashDot 3 DrawStyle: dash, dot
vbDashDotDot 4 DrawStyle: dash, dot, dot
vbInvisible 5 DrawStyle: no lines or outlines (fills still drawn)
vbInsideSolid 6 DrawStyle: solid</pre>
<h2>VarType Constants</h2>
<p>The values VARTYPE returns (see Variants). For an array, VARTYPE adds vbArray to the type of its elements.</p>
<pre> Constant Value Kind of value
-------- ----- -------------
vbEmpty 0 Empty (nothing stored yet)
vbNull 1 Null
vbInteger 2 Integer
vbLong 3 Long
vbSingle 4 Single
vbDouble 5 Double
vbCurrency 6 Currency
vbDate 7 Date
vbString 8 String
vbObject 9 An object or Nothing
vbError 10 Error value (Visual Basic only; no DVX value has this type)
vbBoolean 11 Boolean
vbVariant 12 Variant (only in vbArray + vbVariant, an array of Variants)
vbDataObject 13 Data object (Visual Basic only; no DVX value has this type)
vbByte 17 Byte
vbUserDefinedType 36 A TYPE variable
vbArray 8192 Added to the element type for an array</pre>
<h2>Error Constants</h2>
<pre> Constant Value Description
-------- ----- -----------
vbObjectError -2147221504 Base for your own error numbers, as in Visual Basic: a class module raises ERROR vbObjectError + n, and the handler recovers n with ERR - vbObjectError</pre>
<h2>Color Constants</h2>
<p>Colors in the form RGB makes (&amp;HBBGGRR, see Color Functions), as in Visual Basic.</p>
<pre> Constant Value Color
-------- ----- -----
vbBlack &amp;H0 Black
vbRed &amp;HFF Red
vbGreen &amp;HFF00 Green
vbYellow &amp;HFFFF Yellow
vbBlue &amp;HFF0000 Blue
vbMagenta &amp;HFF00FF Magenta
vbCyan &amp;HFFFF00 Cyan
vbWhite &amp;HFFFFFF White</pre>
<h2>Boolean Constants</h2>
<pre> Constant Value Description
-------- ----- -----------
True -1 Boolean true
False 0 Boolean false</pre>
</div>
<div class="topic" id="lang.runtime">
<h1>Include Libraries</h1>
<p>DVX ships a set of BASIC include files (.bas) in the sdk/include/basic directory. Each file is a small library of DECLARE LIBRARY wrappers around native DVX runtime functions. Add an include file to your project (the IDE's Add File command, or editing the .dbp with another tool) and the declared functions become available to your code.</p>
<pre> File Provides
---- --------
commdlg.bas File Open/Save dialogs (DlgFileOpenIn$ and DlgFileSaveIn$ start in a folder you name), the folder dialog (DlgFolder$, for a Browse button), input dialogs, choice dialogs, save-prompt dialogs, the color dialog, the font dialog (DlgFont), message boxes with your own buttons (DlgButtons)
sql.bas SQLite database access (SQLOpen, SQLQuery, SQLNext, SQLField$, etc.)
comm.bas Serial-port I/O (raw and packet) and optional encrypted links; port settings read back and changed, why a call failed, breaks, ring, and line errors (SerOpen, SerSet, SerLastError, CommOpen, CommOpenTcp, CommHandshakeStep, ...)
conn.bas Connections the way Terminal makes them: a serial port, a modem that dials, the secure link to the DVX host proxy, or Telnet, shown on a Terminal control, with capture, answerback, and file transfers (ConnCreate, ConnOpen, ConnPoll, ConnAttach, ConnSendFiles, ...)
xfer.bas File transfers with XMODEM, XMODEM-1K, YMODEM, and ZMODEM, on a serial port or a connection, with their progress and questions (XferSendFile, XferStatus, XferBytes, XferAnswer, ...)
prefs.bas Settings files (INI): load one, read and change its settings, list the keys of a section, save it; DVX's own settings file, the screen mode it starts in, the names its choices are stored as and its default choices, and choices stored by names of your own (PrefsLoad, PrefsGet$, PrefsSet, PrefsKeyName$, PrefsSaveAs, PrefsDvxIni$, PrefsVideoWidth, PrefsChoiceLabel$, PrefsChoiceDefault, PrefsGetChoiceFrom, ...)
resource.bas Read and write DVX resource blocks (icons, text, binary data) in bundled files
help.bas Compile help source files and see the compiler's messages, and open the DVX help viewer, at a topic if you like (HelpCompile, HelpCompileMessages$, HelpView, HelpViewTopic; HelpView &quot;&quot; opens the DVX user guide)
hlpfile.bas Read compiled help files yourself, for a help viewer of your own: topics, table of contents, keyword index, full-text search, and each topic's headings, text, links, and pictures; show a topic in a HelpPane control (HlpOpen, HlpTocTitle$, HlpIndexKeyword$, HlpSearch, HlpLoadTopic, ...)
net.bas Network connections: TCP (TcpConnect, TcpListen, TcpSend, TcpRecv$, TcpPeer$, ...), UDP messages and name lookups, any bytes; the network settings and status (NetConfigLoad, NetConfigSet, NetConfigStore, NetRestart, NetStatus$, ...)
print.bas Printing: text with the page setup and pictures, with or without the Print dialog; a form; the Page Setup dialog; the printer and page settings; the printer ports (PrintModelLabel$, PrintSettingsStore, PrintPageSetting, PrintChoose, PrintForm, PrintPortStatus, ...)
listhelp.bas Lists and icon views you draw yourself (a UserControl, a PictureBox) that behave like ListBox and Program Manager: selection with Shift and Ctrl, the arrow keys in a list or a grid, Ctrl+A, Space, type-ahead, where a dragged item lands, and Program Manager's icon view rules -- its cells, the grid with a scroll bar, names on two lines, dragging and dropping (ListSelCreate, ListSelClick, ListSelNavigate, ListTypeAhead, ListIconMetric, ListIconLabel$, ...)
security.bas Security: random bytes for keys, key exchanges, ciphers, sealing, SHA-256 hashes, HMAC and public-key signatures, key making, and a safe compare (SecRandom$, SecX25519$, SecAeadLock$, SecEd25519Sign$, SecSha256$, SecHkdf$, ...)
game.bas Games: whether a key is being held down right now, forgetting held keys, frames FRAMEWAIT skipped, waiting for the screen's retrace (GameKeyDown, GameKeyClear, FrameMissed, GameWaitRetrace)
joystick.bas Joysticks: how many there are, their names, where each stick points, and which buttons are pressed (JoyCount, JoyX, JoyY, JoyButton, ...); setting them up: calibration, dead zone, game port mode, keyboard joystick keys (JoySetCalibration, JoyCalibration, JoyRescan, JoyKeyIndex, JoySettingsStore, ...)
sound.bas Sound: play WAV and VOC files, tones and noise, set the volume (PlayWave, PlayTone, StopWave, SoundInfo$, ...); sounds loaded once and played with volume, pan, and pitch, sound made by the program as it goes, recording from a microphone or line input (RecordStart, RecordStop, RecordLevel, ...), the FM synthesizer chip, a wavetable card's voices and memory (SoundLoad, SoundPlay, SoundSetPitch, SoundCreate, SoundStreamOpen, SoundStreamWrite, FmAlloc, FmWrite, WtAlloc, WtStart, ...); DVX's own event sounds (SoundPlayEvent), master volume, sound driver, and MIDI settings (SoundEventFile$, SoundSetMasterVolume, SoundSettingsStore, ...)
music.bas Music: play MOD, S3M, XM, IT, MIDI, WAV, and VOC files, and play notes yourself (MusicLoad, MusicPlay, MusicStop, MusicNoteOn, MusicInfo$, ...); instruments from banks and SoundFonts, a sound card's own (MusicSetBank, MusicPatchSet$, MusicRomBank$); raw bytes to the MIDI port (MidiAcquire, MidiPut, MidiRelease, MidiPortInfo$); what a MIDI keyboard plays, heard as it comes and recorded into MIDI files (MidiInOpen, MidiInMessage, MusicMidiSend, MidiRecordNew, MidiRecordSave, ...)
fileops.bas Files and folders: folder listings for a file list, paths and names, the file dialogs' filter rule, attributes and the time a file was changed, sizes, free space and disk sizes, drive kinds, whether a folder can be written, the folder for scratch files, making a folder path, and copying, moving, and deleting whole folders at once or as a job with progress, Cancel, and questions (FileOpsList, FileOpsListRows$, FileOpsFilterMatch, FileOpsSetModified, FileOpsDriveType, FileOpsIsWritable, FileOpsMakePath, FileOpsJobCreate, FileOpsJobRunFor, ...)
system.bas What Control Panel changes, at once for the whole desktop: the screen mode, the system colors and themes, the wallpaper, text smoothing, and the mouse (with DVX's limits and defaults, MOUSE_* and SYS_VIDEO_DEFAULT_*), and storing them in DVX's settings; the system font's character pictures; the mouse pointer and the Shift, Ctrl, and Alt keys anywhere on the screen, moving the pointer, typing keys into the window in front, a picture of the whole screen, the memory, and whether a library is installed (SysSetVideoMode, SysSetColor, SysLoadTheme, SysSetWallpaper, SysSetTextSmoothing, SysSetMouse, SysColorsStore, SysFontGlyphRow, SysMouseX, SysSendKey, SysScreenshot, SysMemoryFreeKb, SysLibraryLoaded, ...)
font.bas Fonts: the font families DVX has, the sizes each comes in, whether one is fixed-pitch, and how wide text and how tall a line is in a font (FontFamilyCount, FontFamilyName$, FontFamilyFixed, FontSizeCount, FontSizeAt, FontNearestSize, FontTextWidth, FontLineHeight, FontAscent, FontRescan)
richtext.bas RTF without a control: an RTF document as plain text and plain text as RTF (RtfToText$, TextToRtf$); a RichEdit control reads and writes RTF itself (TextRTF, SelRTF, LoadFile, SaveFile)
layout.bas Control sizes in characters or in percent of the container instead of pixels (SizeChars, SizePercent)
compiler.bas The BASIC compiler: compile a project or files you give it, find compile errors in their files, list a program's procedures and the language's keywords, build an .app or a control file; put a project's UserControls on a form designer's toolbox; read source text as the compiler does (tokens, code or string or comment, renaming a control in code, WithEvents variables, class Events), F1 help topics; open, change, and save project files and UserControl headers (CompSourceFromProject, CompSourceAdd, CompCompile, CompError$, CompMapFile$, CompProcList$, CompBuildApp, CompDesignControls, CompTokens$, CompRenameInCode$, CompHelpTopic$, ProjOpen, ProjSave, ProjCtlSetHeader$, ...)
debug.bas Run a compiled program inside yours and debug it: breakpoints, stepping, its variables, expressions, Immediate-window lines, its PRINT output (RunCreate, RunStart, RunPoll, DbgSetBreakpoints, DbgStepOver, DbgLocals$, DbgEval$, DbgExec$, ...)
designer.bas Form designers: the control types, whether each holds other controls and can be placed, the names of new controls, default events, toolbox tooltips and icons, and each type's properties (with their types and value names), methods, and events (with each event's parameters); the names in .frm and class module text; .frm files as data to read, edit, and write, controls copied and pasted as text, and a loaded form written back as .frm text (CtlTypeCount, CtlTypeName$, CtlTypeFlags, CtlPropCount, CtlPropName$, CtlPropType, CtlEventList$, CtlEventParams$, CtlTypeEventParams$, FrmFormName$, FrmControlNames$, ClsClassName$, FrmOpen, FrmText$, FrmCtlAdd, FrmCtlText$, FrmCtlPaste, FrmMenuAdd, FormText$, ...)
shell.bas DVX itself, everything Program Manager and Task Manager do: start programs (DVX's and DOS programs) and open documents, command lines (split into their parts) and the Run dialog, the installed programs and their names, file types, the running programs (find one, bring it to the front, ask it to close, or end it, and their priority), this program's priority, keys that work in every program, Task Manager, system information, Exit DVX, the desktop and the program started after it, the DVX log; Program Manager's program groups with their items, shortcut keys, and icons (ShellRun, ShellRunProgram, ShellRunDos, ShellProgramScan, ShellAssocCount, ShellRunningId, ShellRunningActivate, ShellRunningClose, ShellArg$, ShellSetPriority, HotkeyAdd, ShellExitDvx, ShellGroupsLoad, ShellItemGet$, ShellItemIcon$, ...)
pkg.bas Add-on packages: the packages installed in DVX and their details, files, and needs; reading .DPK files, installing, removing, making, and signing packages as jobs with progress, and planning what installing them takes; trusting a publisher's key; and making keys (PkgOpen, PkgInstalledRows$, PkgOfferFileStart, PkgPlan, PkgInstallStart, PkgRunFor, PkgRemoveStart, PkgBuildStart, PkgSignStart, PkgKeygen, ...)
json.bas JSON: read a document (a web service's reply, a settings file) and find values in it by path such as packages[3].version, and quote text for JSON of your own (JsonParse, JsonText$, JsonNumber, JsonCount, JsonKey$, JsonQuote$, ...)
http.bas Web requests: GET a page, a file, or a web service's answer, or POST to one, over the network a little at a time with progress, to memory or to a file (resuming one left part-way), following redirects (HttpOpen, HttpStart, HttpRunFor, HttpStatus, HttpBody$, HttpSaveTo, ...)
pkgnet.bas A package server: what it offers, what it has that is newer than what is installed, and fetching packages with what they need, for pkg.bas to install (PkgNetOpen, PkgNetCatalogue, PkgNetUpdates, PkgNetFetch, PkgNetRunFor, PkgNetRows$, ...)</pre>
<h2>Using an Include Library</h2>
<pre><code>' With commdlg.bas added to the project
Dim path As String
path = DlgFileOpen$(&quot;Open a file&quot;, &quot;Text Files (*.txt)|All Files (*.*)&quot;)
If path &lt;&gt; &quot;&quot; Then
Print &quot;Selected: &quot; &amp; path
End If</code></pre>
<h2>When a Library Is Not Installed</h2>
<p>Some libraries are optional parts of DVX (the network, printing, sound, joysticks ...). Calling a function of a library that is not on the computer raises run-time error 453, &quot;Library or function not installed&quot;, which ON ERROR can trap -- for example to show a message instead of a page of settings, as Control Panel does:</p>
<pre><code>Dim status As String
On Error Resume Next
status = NetStatus$(&quot;message&quot;)
If Err.Number = 453 Then
lblNet.Caption = &quot;The network is not installed.&quot;
Else
lblNet.Caption = status
End If
On Error GoTo 0</code></pre>
<h2>Message Boxes with Your Own Buttons</h2>
<p>MsgBox offers fixed sets of buttons (OK, Yes and No, ...). With commdlg.bas in the project, DlgButtons(title, message, buttons, icon) shows a message box with the buttons you list, separated by |, with &amp; before each button's access key. It returns the index of the button chosen: 0 for the first, which Enter presses. Esc and closing the box choose the last button, so make the last one the choice that changes nothing. icon is vbQuestion, vbInformation, vbExclamation, vbCritical, or 0. Up to six buttons; -1 is returned when the list is empty or longer.</p>
<pre><code>Select Case DlgButtons(&quot;Copy&quot;, &quot;notes.txt already exists. Replace it?&quot;, &quot;&amp;Yes|&amp;No|Yes to &amp;All|&amp;Cancel&quot;, vbQuestion)
Case 0
' replace this one
Case 2
' replace this and every other one
Case Else
' keep it (No), or stop (Cancel)
End Select</code></pre>
<h2>Color Dialog</h2>
<p>With commdlg.bas in the project, DlgColor(title, defaultColor) shows the color dialog: a palette of basic colors, Red, Green, and Blue sliders with number boxes, and a preview. It starts at defaultColor and returns the color chosen, in the form RGB makes and ForeColor and BackColor use, or -1 when the user cancels.</p>
<pre><code>Dim c As Long
c = DlgColor(&quot;Text Color&quot;, Label1.ForeColor)
If c &lt;&gt; -1 Then
Label1.ForeColor = c
End If</code></pre>
<h2>Font Dialog</h2>
<p>With commdlg.bas in the project, DlgFont(title, family, size, style, flags) shows the font dialog: the font families, the styles and sizes each comes in, Underline and Strikeout boxes, and a sample. It starts at the font named by family, size (in pixels), and style, and returns True when the user chooses OK. DlgFontName$(), DlgFontSize(), and DlgFontStyle() then give the font chosen; after Cancel they give the font the dialog started at. style adds up FONT_BOLD, FONT_ITALIC, FONT_UNDERLINE, and FONT_STRIKE, the constants of font.bas (add it to the project too, or use 1, 2, 4, and 8). With flags DLG_FONT_FIXED the dialog lists only the fixed-pitch families, for text that must line up in columns; with 0 it lists them all. The dialog's Licence button shows the chosen font's notice and licence. The answers fit a control's or a form's Font properties (see Fonts).</p>
<pre><code>' With commdlg.bas and font.bas added to the project
Dim style As Long
If Label1.FontBold Then style = style + FONT_BOLD
If Label1.FontItalic Then style = style + FONT_ITALIC
If DlgFont(&quot;Label Font&quot;, Label1.FontName, Label1.FontSize, style, 0) Then
Label1.FontName = DlgFontName$()
Label1.FontSize = DlgFontSize()
Label1.FontBold = (DlgFontStyle() And FONT_BOLD) &lt;&gt; 0
Label1.FontItalic = (DlgFontStyle() And FONT_ITALIC) &lt;&gt; 0
Label1.FontUnderline = (DlgFontStyle() And FONT_UNDERLINE) &lt;&gt; 0
Label1.FontStrikethru = (DlgFontStyle() And FONT_STRIKE) &lt;&gt; 0
End If</code></pre>
<h2>Number Input Dialog</h2>
<p>With commdlg.bas in the project, DlgIntInput(title, prompt, default, min, max) asks for a whole number with a spin box, and DlgIntInputStep(title, prompt, default, min, max, step) does the same with the arrows moving by step. Both return the number entered, or default when the user cancels; DlgInputCancelled() (True after a Cancel, False after OK) tells the two apart, as it does for DlgInputBox$.</p>
<pre><code>n = DlgIntInputStep(&quot;Zoom&quot;, &quot;Zoom in percent:&quot;, 100, 25, 400, 25)
If Not DlgInputCancelled() Then
SetZoom n
End If</code></pre>
<h2>Resources in Files</h2>
<p>With resource.bas in the project, a program reads and writes the named resources DVX keeps at the end of program, widget, and library files: icons, text, and any bytes. ResOpen, ResCount, ResName$, ResType, and ResSize list them; ResGetText$ and ResAddText read and write text; ResAddFile and ResExtract copy a resource from or to a file; ResRemove takes one out. ResGetData$(file, name) gives every byte of a resource as a String (CHR$(0) included) -- LoadPictureData(ResGetData$(file, name)) shows a picture resource -- and ResAddData file, name, type, bytes adds or replaces a resource of any bytes (type RES_TYPE_BINARY, RES_TYPE_TEXT, RES_TYPE_ICON, or RES_TYPE_FONT, a .DFN font the program carries; see Fonts). RES_NAME_ICON (&quot;icon32&quot;) and RES_NAME_WIDGET_ICON (&quot;icon24&quot;) are the names DVX gives a program's and a widget's icon; a name is at most RES_NAME_MAX - 1 characters.</p>
<pre><code>Dim settings As String
settings = Chr$(1) + Chr$(0) + Chr$(255)
If ResAddData(&quot;mygame.app&quot;, &quot;state&quot;, RES_TYPE_BINARY, settings) Then
Print Len(ResGetData$(&quot;mygame.app&quot;, &quot;state&quot;)) ' 3
End If</code></pre>
<blockquote><strong>Note:</strong> DVX BASIC does not have an $INCLUDE directive. Libraries are added to the project so that the compiler sees their DECLARE LIBRARY blocks.</blockquote>
<h2>Encrypted Serial Links</h2>
<p>With comm.bas in the project, CommOpen opens a packet link and CommHandshake sets up encryption. Give both ends the same passphrase to authenticate the connection. Without a passphrase the link is still encrypted and tamper-checked, but it cannot tell who is on the other end. CommHandshake returns False if the passphrases differ, if only one side gives one, or if the link fails.</p>
<pre><code>Dim link As Long
link = CommOpen(1, 115200, 8, &quot;N&quot;, 1, SER_HANDSHAKE_NONE)
If CommHandshake(link, &quot;shared secret&quot;) Then
CommSend link, &quot;hello&quot;, 0, True
Else
Print &quot;Handshake failed&quot;
End If</code></pre>
<p>After the handshake, data that arrives unencrypted is ignored unless that channel is opened for it with CommSetPlain link, channel, True.</p>
<p>The same link runs over the network: with net.bas in the project too, CommOpenTcp(conn) opens it on a connection from TcpConnect or TcpAccept (both ends do), with every channel, the handshake, and encryption as on a COM port. The connection stays the program's: close it with TcpClose after CommClose.</p>
<pre><code>conn = TcpConnect(&quot;bbs.example.org&quot;, 2323)
link = CommOpenTcp(conn)
If CommHandshake(link, &quot;shared secret&quot;) Then CommSend link, &quot;hello&quot;, 5, True</code></pre>
<p>CommHandshake waits until the key exchange is done (up to 30 seconds), and CommSend waits while the link has as much in flight as it can; the program's events run while they wait, as they do in DoEvents. CommHandshakeStep(link, passphrase) does one step of it and returns at once, so a program can keep working: call it from a Timer until it returns something other than COMM_PENDING -- COMM_OK when the link is ready, else a COMM_ERR_ code. CommLastError(link) gives the COMM_ code of the last CommHandshake, CommHandshakeStep, CommSend, CommSetPlain, or CommPoll, which tells a wrong passphrase (COMM_ERR_AUTH) from a line that does not answer (COMM_ERR_TIMEOUT). CommDropped(link) counts arriving packets thrown away because they were tampered with or came unencrypted where that is refused. Channels are numbered 0 to COMM_MAX_CHANNEL.</p>
<pre><code>Sub Timer1_Timer ()
Select Case CommHandshakeStep(link, txtPass.Text)
Case COMM_PENDING
lblState.Caption = &quot;Connecting...&quot;
Case COMM_OK
Timer1.Enabled = False
lblState.Caption = &quot;Connected&quot;
Case COMM_ERR_AUTH
Timer1.Enabled = False
lblState.Caption = &quot;Wrong passphrase&quot;
Case Else
Timer1.Enabled = False
lblState.Caption = &quot;The other side does not answer&quot;
End Select
End Sub</code></pre>
<h2>Serial Port Settings and Errors</h2>
<p>With comm.bas, SerOpen returns False when a port cannot be opened; SerLastError(com) then says why, as an SER_ERR_ constant (SER_ERR_NO_UART: there is no port there, SER_ERR_IRQ_NOT_FOUND, SER_ERR_INVALID_BAUD, ...), or SER_OK when the last SerOpen or SerSet worked.</p>
<pre> Function Description
-------- -----------
SerSet(com, baud, dataBits, parity, stopBits, handshake) Change the settings of an open port (SerOpen's arguments). True when done.
SerGetBaud(com), SerGetDataBits(com), SerGetParity$(com), SerGetStopBits(com), SerGetHandshake(com) The settings of an open port; parity is &quot;N&quot;, &quot;E&quot;, &quot;O&quot;, &quot;M&quot;, or &quot;S&quot;. When the port is not open the numbers are an SER_ERR_ code and the parity &quot;&quot;.
SerTxPending(com), SerFlushTx com Bytes written but not sent yet; throw them away.
SerSetBreak com, state Send a break: True holds the line in the break state, False releases it (hold it a quarter to half a second).
SerGetRi(com) True while the other end rings.
SerLineErrors(com) Errors seen on received data, added up: SER_LINE_OVERRUN (data came faster than it was read), SER_LINE_PARITY, SER_LINE_FRAMING, SER_LINE_BREAK; 0 for none.</pre>
<h2>Printing</h2>
<p>With print.bas in the project, a program prints like the programs that come with DVX. PrintTextDialog shows the Print dialog (printer, copies, pages) and prints the text on pages laid out by the page setup: margins, a header, and a footer with the document name, date, and page number. PrintPageSetup shows the Page Setup dialog, which the user's choices are saved from for every program. PrintPictureDialog prints a picture file scaled to the page, on printer models that print pictures (PrintCanPrintPictures says whether the chosen one does), in color on a color printer (PrintCanPrintColor says whether it is one) and in shades of grey on the others. PrintText and PrintPicture print without asking first. Each returns True when it printed.</p>
<pre><code>Sub mnuPrint_Click ()
PrintTextDialog txtNotes.Text, &quot;Notes&quot;
End Sub
Sub mnuPageSetup_Click ()
PrintPageSetup
End Sub</code></pre>
<p>For printer output a line at a time, see LPRINT and OPEN &quot;LPT1:&quot;. To draw whole pages (text in any font and size, lines, boxes, circles, and pictures), use the Printer object.</p>
<p>A program that prints its own way has more:</p>
<pre> Function Description
-------- -----------
PrintPageCount(text) How many pages text takes with the saved page setup and printer.
PrintTextPages(text, title, firstPage, lastPage, copies) Print text without asking: those pages (0 and 0 for all), copies times.
PrintChoose(title, pageCount) Show the Print dialog only (the page range when pageCount is above 0). True when the user chose Print; then PrintChoiceDest, PrintChoiceFile$, PrintChoiceCopies, PrintChoiceFirst, and PrintChoiceLast say what was chosen (pages 0 and 0: all).
PrintForm(formName) / PrintFormDialog(formName) Print what a loaded form shows, scaled to the page (a printer model that prints pictures); the second shows the Print dialog first.
PrintPortPresent(port), PrintPortStatus(port) Whether printer port LPTn (1 to 3) exists, and its state: PRINT_STATUS_ values added up (PRINT_STATUS_PAPER_OUT, PRINT_STATUS_SELECTED, PRINT_STATUS_NOT_BUSY, ...).
PrintStatusProblem$(status, afterWrite, where) What is wrong with a printer in that state, in words (&quot;&quot; when nothing is), for printer where such as &quot;LPT1&quot;.</pre>
<pre><code>If PrintChoose(&quot;Report&quot;, 0) Then
If PrintDestIsFile(PrintChoiceDest()) Then
Open PrintChoiceFile$() For Output As #1
Else
Open &quot;LPT&quot; &amp; (PrintChoiceDest() + 1) &amp; &quot;:&quot; For Output As #1
End If
Print #1, &quot;Report&quot;
Close #1
End If</code></pre>
<p>The page setup can be read and changed without the Page Setup dialog. Like the printer settings these take a handle from prefs.bas:</p>
<pre> Function Description
-------- -----------
PrintPageSetting(prefs, field) A number of the page setup: &quot;Lines&quot; (lines per page, 0 = the printer's usual length), &quot;Columns&quot;, &quot;MarginTop&quot;, &quot;MarginBottom&quot;, &quot;MarginLeft&quot;, &quot;MarginRight&quot;, &quot;TabWidth&quot;, or &quot;Wrap&quot; (True: long lines wrap at a space); -1 for an unknown field.
PrintPageText$(prefs, field) &quot;Header&quot; or &quot;Footer&quot;. In them &amp;f is the document name, &amp;p the page, &amp;n the number of pages, &amp;d the date, &amp;t the time, &amp;&amp; an ampersand; &amp;l, &amp;c, and &amp;r put what follows left, centred, or right.
PrintPageSetupProblem$(lines, columns, marginTop, marginBottom, marginLeft, marginRight, tabWidth, wrap, header, footer) &quot;&quot; when this page setup can be used, else why not.
PrintPageSettingsStore(prefs, lines, columns, marginTop, marginBottom, marginLeft, marginRight, tabWidth, wrap, header, footer) Put a page setup into the settings (then PrefsSave). False for one PrintPageSetupProblem$ objects to.
PrintPageLines(prefs, model) Lines per page the setup gives on printer model.</pre>
<p>The limits are CONSTs: PRINT_LINES_MIN to PRINT_LINES_MAX, PRINT_COLUMNS_MIN to PRINT_COLUMNS_MAX, PRINT_TAB_MAX, PRINT_COPIES_MAX, with the defaults PRINT_COLUMNS_DEFAULT, PRINT_MARGIN_TB_DEFAULT, PRINT_MARGIN_LR_DEFAULT, and PRINT_TAB_DEFAULT.</p>
<p>A program can also change the printer settings the way the Control Panel's Printer page does. They are kept in DVX's settings file, so these calls take a handle from prefs.bas (add prefs.bas to the project too). Printer models and destinations are numbered from 0.</p>
<pre> Function Description
-------- -----------
PrintModelCount() / PrintModelLabel$(model) How many printer models there are, and the name of each.
PrintDestCount() / PrintDestLabel$(dest) How many places the printer can be connected to (LPT1 to LPT3, COM1 to COM4, a file), and the name of each.
PrintDestIsFile(dest) True for the destination that prints into a file.
PrintDestIsSerial(dest) True for a serial port (COM1 to COM4), which needs a speed and a handshake.
PrintBaudRate(index) The serial speeds offered, from index 0 (0 past the last).
PrintHandshakeCount() / PrintHandshakeLabel$(handshake) How many handshakes there are, and the name of each (None, XON / XOFF, Hardware (CTS), Hardware (DSR, Apple)).
PrintSettingBaud(prefs), PrintSettingHandshake(prefs) A serial printer's speed and handshake in the settings.
PrintSerialStore(prefs, baud, handshake) Put a serial printer's speed and handshake into the settings; False for a speed not offered.
PrintSettingModel(prefs) The printer model in the settings.
PrintSettingDest(prefs) Where the printer is connected.
PrintSettingFile$(prefs) The file printed into when the destination is a file.
PrintSettingsProblem$(dest, filePath) &quot;&quot; when this choice can be used, else why not (printing to a file needs its name).
PrintSettingsStore(prefs, model, dest, filePath) Put the choice into the settings, keeping the page setup as it is; then save with PrefsSave.</pre>
<pre><code>Dim prefs As Long
Sub Form1_Load ()
Dim i As Long
prefs = PrefsLoad(PrefsDvxIni$())
For i = 0 To PrintModelCount() - 1
cboModel.AddItem PrintModelLabel$(i)
Next i
cboModel.ListIndex = PrintSettingModel(prefs)
End Sub
Sub cmdOK_Click ()
If PrintSettingsStore(prefs, cboModel.ListIndex, PrintSettingDest(prefs), PrintSettingFile$(prefs)) Then
PrefsSave prefs
End If
PrefsClose prefs
End Sub</code></pre>
<h2>Files and Folders</h2>
<p>With fileops.bas in the project, a program can show and change what is on the disks. FileOpsList(folder, filter) reads a folder once -- its folders and the files matching filter -- and returns a listing (a number; FileOpsListFree frees it). FileOpsListRows$ gives the whole listing as name, size, type, and date columns, ready for a ListView's SetRows, so even a folder of hundreds of files fills the list at once; FileOpsListSort re-sorts it by name, size, type, or date with folders first. FileOpsListName$, FileOpsListIsFolder, and FileOpsListSize read single entries, and FileOpsListFind finds one by name. FileOpsListFolders(listing) makes a new listing of just the folders in one, sorted by name, without reading the disk again (handy for a folder tree next to a file list).</p>
<p>Paths: FileOpsPathNormalize$ (the full path of an existing folder, or &quot;&quot;), FileOpsPathParent$, FileOpsPathJoin$, FileOpsPathSame, FileOpsPathIsRoot, FileOpsPathIsAbsolute (True for a path that is complete by itself, such as &quot;C:\DOCS&quot;, False for one that counts from the current folder), FileOpsPathIsInside(path, folder) (True when path is folder itself or anywhere inside it: check it before copying or moving a folder, so it is never copied into itself), FileOpsPathSep$ (the character between folder names, &quot;\&quot; on DOS), FileOpsPathNative$ (a path written with that character, for showing it: &quot;C:/DOCS/A.TXT&quot; becomes &quot;C:\DOCS\A.TXT&quot;), FileOpsBaseName$, and FileOpsExtension$. Every one of them takes / and \ alike and gives back \. FileOpsFilterMatch(itemName, filter) tells whether a name matches a filter the way the file dialogs match it: wildcards * and ?, several patterns separated by ; such as &quot;*.bmp;*.png&quot;, case not mattering.</p>
<p>Files: FileOpsMakeDir and FileOpsRename (FileOpsError$ says why one failed), FileOpsTempPath$ and FileOpsReplaceFile (save safely: write the new file to FileOpsTempPath$(path$), then FileOpsReplaceFile swaps it in; the old file comes back if that fails), FileOpsValidName(folder, itemName) (whether a name can be used for a new file or folder in folder, by the rules of its disk; FileOpsError$ says why not), FileOpsValidLongName and FileOpsValidShortName (the long-name or the 8.3 rules by themselves, whatever the disk takes), FileOpsShortPath$ (the short 8.3 form of an existing path, for an old program that cannot take long names or blanks), FileOpsMakePath (a folder and every missing folder above it, which MKDIR does not make), FileOpsIsFolder, FileOpsGetAttr, and FileOpsSetAttr (the FILEOPS_ATTR_ bits), FileOpsModified$ and FileOpsSetModified (when a file was last changed, read and set in the form &quot;YYYY-MM-DD HH:MM&quot;; FileOpsSetModified returns False for a date that does not exist), FileOpsTreeSize with FileOpsTreeBytes, FileOpsTreeFiles, and FileOpsTreeFolders (the size of a whole folder), and FileOpsFormatSize$.</p>
<p>Drives: FileOpsDriveList$ (the drive letters), FileOpsDriveType (FILEOPS_DRIVE_FIXED for a hard disk, FILEOPS_DRIVE_REMOVABLE for a floppy disk drive, FILEOPS_DRIVE_REMOTE for a network drive or a CD-ROM; asking never makes a drive spin up), FileOpsBootDrive$ (the drive the computer started from), FileOpsFreeBytes, FileOpsFreeKb, and FileOpsTotalBytes (the size of the disk; right for disks past 2 GB too), FileOpsLongNames(path) (True when the disk holding path takes long file names: up to 255 characters, with spaces and several dots; otherwise names are 8.3). FileOpsIsWritable(folder) is False where files cannot be made (a CD-ROM, a write-protected floppy), and FileOpsReadOnlySystem() is True when nothing can be saved: DVX runs from such a disk and there is no TEMP folder to keep the user folder in. FileOpsTempDir$() is the folder for scratch files (&quot;&quot; when there is none).</p>
<p>DVX's folders: FileOpsUserDir$() is the user folder (USER in the DVX folder, or the folder DVXUSER names), where everything DVX and its programs save goes; FileOpsUserPath$(name) is a file or folder in it, for example FileOpsUserPath$(&quot;DOWNLOAD&quot;); FileOpsUserInTemp() is True when DVX runs from a disk it cannot write to and keeps the user folder in the TEMP folder. A program's own folder there is App.User. The fonts, sounds, themes, desktop pictures, MIDI instrument banks, and screen savers come in two folders each, DVX's own (and add-on packages') in SHARED and the user's in the user folder; the kinds are FILEOPS_KIND_FONTS, FILEOPS_KIND_SOUNDS, FILEOPS_KIND_THEMES, FILEOPS_KIND_WPAPER, FILEOPS_KIND_BANKS, and FILEOPS_KIND_SAVERS. An add-on's files are in a folder of its vendor's inside a kind's folder and are named VENDOR\NAME (for example ACME\SPACE.THM). FileOpsKindDir$(kind, user) is DVX's folder of a kind (user False) or the user's (True); FileOpsKindBrowseDir$(kind) is the one a file dialog starts in (the user's when it exists); FileOpsKindFind$(kind, fileName) finds a file by name, the user's first (&quot;&quot; when there is none); FileOpsKindName$(kind, path) is the name alone of a file in one of the two folders, the way settings store it (&quot;&quot; for any other path); FileOpsKindList(kind) lists both folders as one, sorted by name, a user's file hiding DVX's of the same name (a list for FileOpsListCount, FileOpsListName$, and the rest; FileOpsListFree when done). Programs read DVX's SHARED folder but never write in it.</p>
<p>FileOpsCopyTree, FileOpsMoveTree, and FileOpsDeleteTree do a whole folder in one call, as does FileOpsTreeSize. While one works, the rest of DVX goes on and so do the program's own events, as with DoEvents (in a control's code they wait until the call ends); if the program is ended meanwhile, the call stops and returns False. For a long copy, move, or delete with progress and questions, run the work as a job, a little at a time from a Timer: FileOpsJobCreate, then FileOpsJobAddSource for each file or folder, then FileOpsJobRunFor from the timer until it returns FILEOPS_STEP_DONE or FILEOPS_STEP_CANCELLED. When it returns FILEOPS_STEP_ASK (a file already exists, a file is read-only) or FILEOPS_STEP_ERROR, show FileOpsJobMessage$ and pass the user's choice to FileOpsJobAnswer. FileOpsJobCurrent$, FileOpsJobFilesDone, FileOpsJobFilesTotal, FileOpsJobFoldersTotal, FileOpsJobPercent, FileOpsJobBytesDone, and FileOpsJobBytesTotal show the progress, and FileOpsJobCancel stops the job. A FILEOPS_MEASURE job only counts: the files (FileOpsJobFilesTotal), the folders inside what was added (FileOpsJobFoldersTotal), and the bytes (FileOpsJobBytesTotal), changing nothing and asking nothing; FileOpsJobUnread says how many folders could not be read. A Properties dialog counts a big folder this way without stopping the program. Files copied from a CD-ROM are read-only; FileOpsJobClearAttr job, FILEOPS_ATTR_READONLY before the job runs makes every copy changeable (FILEOPS_ATTR_EDITABLE clears all four attribute bits). Whatever a program leaves open is freed when it ends.</p>
<pre><code>Dim job As Long
Sub cmdCopy_Click ()
job = FileOpsJobCreate(FILEOPS_COPY, &quot;C:\BACKUP&quot;)
If FileOpsJobAddSource(job, &quot;C:\DOCS&quot;) Then Timer1.Enabled = True
End Sub
Sub Timer1_Timer ()
Select Case FileOpsJobRunFor(job, 50)
Case FILEOPS_STEP_ASK
If MsgBox(FileOpsJobMessage$(job), vbYesNo + vbQuestion) = vbYes Then
FileOpsJobAnswer job, FILEOPS_ANSWER_YES
Else
FileOpsJobAnswer job, FILEOPS_ANSWER_NO
End If
Case FILEOPS_STEP_ERROR
FileOpsJobAnswer job, FILEOPS_ANSWER_SKIP
Case FILEOPS_STEP_DONE, FILEOPS_STEP_CANCELLED
Timer1.Enabled = False
FileOpsJobFree job
Case Else
ProgressBar1.Value = FileOpsJobPercent(job)
End Select
End Sub</code></pre>
<h2>Working with DVX</h2>
<p>With shell.bas in the project, a program works with DVX the way Program Manager does -- a whole desktop can be written in BASIC.</p>
<p>Starting programs. ShellRun program, args starts a program (args is what it gets as COMMAND$), runs a DOS program, or opens a document in the program set for its type; it returns True when it started (or the DOS program will run). ShellRunProgram(program, args, folder) does the same the way a Program Manager item does: file names in args, and a document named without a folder, are looked for in folder first (&quot;&quot; for none), and it returns the new program's id (SHELL_RUN_DOS for a DOS program, 0 when it did not start; DVX has already said why). DOS programs are .EXE, .COM, and .BAT files (ShellIsDosProgram(path) says whether a file is one). ShellRunDos program, args, folder, pause runs one with DVX stepped aside: once your procedure has returned, DVX names the programs running besides the desktop, this one included, and asks them to close (each asks about unsaved work; No, or a program kept open, cancels the run); the screen then becomes the DOS screen until the program ends, and DVX comes back with the desktop. folder is where it runs (&quot;&quot; for its own folder); pause True shows &quot;Press any key to return to DVX.&quot; when it ends. ShellRunDosWait(program, args, folder, pause) does the same and waits for it, as SHELL does: your program is not asked to close, its events run meanwhile, and the DOS program's exit code (its ERRORLEVEL) comes back, -1 when it did not run. ShellMinimizeApp id runs that program minimized: its windows become icons, including the ones it opens while it starts. ShellRunCommand(commandLine) runs a whole command line (a program, in double quotes when its name has a blank, then its arguments) and returns the id too. ShellRunDialog$(history) shows DVX's Run dialog offering history (earlier commands, newest first, one per line) and returns what the user chose, &quot;&quot; for Cancel. ShellOpenDocument path opens a document in the program set for its type in the Control Panel.</p>
<p>Installed programs. ShellProgramScan(folder, skipPath) finds every program in folder and its subfolders (&quot;&quot; for the APPS folder) and returns a list: ShellProgramCount(list) programs, ShellProgramPath$(list, index) each one's path (index from 0), ShellProgramFree list when done (a list not freed is freed when the program ends). Give ShellAppPath$() as skipPath to leave this program out. ShellProgramName$(path) and ShellProgramDescription$(path) are the name and description a program shows, and ShellIsProgram(path) tells a program from a document. LOADPICTURE of a program gives its icon, so a PictureBox can show a grid of programs with PaintPicture. ShellProgramsFolder$() is the folder the installed programs are in (where ShellProgramScan(&quot;&quot;) looks), for example to start a Browse for a program there with DlgFileOpenIn$.</p>
<p>File types. ShellAssocProgram$(extension) tells which program opens files with that extension (with &quot;,arguments&quot; after it when it is given any), ShellAssocCommand$(document) just the program that opens a document. ShellAssocCount() file types are set; ShellAssocExt$(index) and ShellAssocValue$(index) read them (index from 0). ShellAssocSet(extension, program) sets one and ShellAssocRemove(extension) removes one, saved at once; ShellAssocNormalize$(extension) is the extension as stored (&quot;.txt&quot; gives &quot;TXT&quot;; &quot;&quot; when it cannot be one).</p>
<p>Running programs. ShellRunningCount() says how many programs are running, and ShellRunningId(index) is the id of each one (index from 0; the same id ShellRunProgram returns). ShellAppId() is this program's own id. ShellRunningName$(id) and ShellRunningPath$(id) are the name a running program shows and the path of its .app (&quot;&quot; when it is not running), and ShellRunningFind(program) is the id of a running copy of a program, 0 when it is not running. ShellRunningActivate id brings a program to the front the way Task Manager's Switch To does (a minimized window is restored). ShellRunningClose id asks a program to close as if the user had closed its windows: it may ask to save its work and the user may cancel, and it is asked once your code has returned to DVX, so check from a Timer whether it is still running. ShellRunningKill id ends a program at once without asking it, the way Task Manager's End Task does: whatever it had not saved is lost, so keep it for a program that does not respond. ShellAppIsHung(id) is True when a program has been busy for 5 seconds or longer (&quot;Not responding&quot; in Task Manager). A program cannot end itself with ShellRunningKill (END does that). ShellAppMemory(id) is how many bytes of memory a program is using. ShellChangeCount() changes whenever a program starts or ends: check it from a Timer and update what you show when it is not the value you saw last. ShellTaskManager opens the Task Manager, ShellSystemInfo$() describes the computer (several lines), and ShellExitDvx exits DVX: every program is asked to close, each asking about unsaved work, and a program that stays open stops the exit (ask the user first).</p>
<pre><code>Sub cmdNotepad_Click ()
Dim id As Long
id = ShellRunningFind(&quot;APPS\KPUNCH\NOTEPAD\NOTEPAD.APP&quot;)
If id = 0 Then
ShellRun &quot;APPS\KPUNCH\NOTEPAD\NOTEPAD.APP&quot;, &quot;&quot;
Else
ShellRunningActivate id
End If
End Sub
Sub FillTaskList ()
Dim i As Long, id As Long
lstTasks.Clear
For i = 0 To ShellRunningCount() - 1
id = ShellRunningId(i)
If ShellAppIsHung(id) Then
lstTasks.AddItem ShellRunningName$(id) &amp; &quot; (not responding)&quot;
Else
lstTasks.AddItem ShellRunningName$(id)
End If
Next i
End Sub</code></pre>
<p>Command lines. ShellCommandProgram$(commandLine) and ShellCommandArgs$(commandLine) split a command line the way ShellRunCommand does: the program (the first word, or the text in double quotes when it starts with one) and the arguments after it. ShellArgCount(commandLine) and ShellArg$(commandLine, index) split any command line into its words (index from 0) by DVX's rule: words are separated by blanks, and a word with blanks in it is written in double quotes, which ShellArg$ leaves off (&quot;&quot; past the last word). ShellArgQuote$(text) writes one word that way: text in double quotes when it holds blanks, as it is otherwise, so a folder or file name with spaces in it reaches the program it is passed to whole (ShellRun &quot;notepad.app&quot;, ShellArgQuote$(path$)). COMMAND$(n) gives this program's own arguments the same way.</p>
<p>Keys for every program. HotkeyAdd(keyText) makes a key such as &quot;Ctrl+Alt+E&quot; work whichever program is in front and returns its id (0 when it is not a key, needs Ctrl or Alt, or another program uses it). The program asks for the keys pressed from a Timer: HotkeyNext() returns the id of the oldest one not asked for yet, 0 when there is none. HotkeyRemove id stops one; the rest stop when the program ends. HotkeyText$(keyText) writes a key the way DVX does (&quot;ctrl+alt+e&quot; gives &quot;Ctrl+Alt+E&quot;; &quot;&quot; when it is not a key), handy for checking what the user typed. ShellItemKeyValid(keyText) is Program Manager's rule for an item's shortcut: Ctrl together with Alt or Shift, so it never takes a key a program uses itself (&quot;&quot; for no shortcut is valid too).</p>
<p>This program. ShellAppPath$ is this program's own path (ShellRun ShellAppPath$(), &quot;&quot; starts another copy), and ShellInstanceCount says how many copies are running, for example to place each new window a little lower and to the right. ShellSetPriority(priority) gives this program more or less of the computer's time while other programs run too: SHELL_PRIORITY_LOW, SHELL_PRIORITY_NORMAL (what every program starts with), SHELL_PRIORITY_HIGH, or any number between; ShellPriority() reads it. A program busy with long work leaves the others room at low priority. A program allows more than one copy when Project Properties has &quot;Allow more than one copy to run at once&quot; ticked. A program keeps its settings in App.User, as DVX's own programs do; keep a desktop's groups there with prefs.bas. ShellLog text writes a line to the DVX log. ShellSetDesktop program makes a program the desktop DVX starts with the next time (&quot;&quot; for Program Manager again); when the desktop ends, DVX ends. ShellSetWelcome program sets the program DVX starts after the desktop the next time it starts (&quot;&quot; for none).</p>
<p>Program groups. Program Manager keeps its groups in PROGMAN.INI; a desktop written in BASIC uses the same model and file format. ShellGroupsLoad(path) opens a groups file (a file not saved yet has the groups Main and Startup) and returns a handle, ShellGroupsSave(groups, path) writes it, and ShellGroupsFree frees it. Groups and items are numbered from 0; group 0 is Installed Programs, which ShellGroupsScan(groups, skipPath) fills with every installed program and which is never saved. ShellGroupsChanged tells cheaply whether a program was installed or removed since. ShellGroupCount, ShellGroupName$, ShellGroupFind, ShellGroupAdd, ShellGroupRename, ShellGroupDelete, and ShellGroupNameValid manage the groups. ShellItemCount and ShellItemAdd(groups, group, name, program) list and add items; ShellItemGet$ and ShellItemSet read and change an item's fields by name (&quot;name&quot;, &quot;program&quot;, &quot;args&quot;, &quot;folder&quot;, &quot;icon&quot;, &quot;key&quot;, &quot;minimized&quot;, &quot;col&quot;, &quot;row&quot;, &quot;description&quot;); ShellItemDelete, ShellItemCopy, ShellItemMove, ShellItemReorder, and ShellItemPlace rearrange them, ShellGroupArrange and ShellGroupPlaceUnplaced lay out an icon grid, and ShellItemMatches is Program Manager's search. ShellGroupsGet and ShellGroupsSet read and set the options (&quot;view&quot;: SHELL_VIEW_LARGE, SHELL_VIEW_SMALL, or SHELL_VIEW_LIST; &quot;group&quot;, the group shown; &quot;autoArrange&quot;, &quot;minimizeOnRun&quot;, &quot;restoreAlone&quot;), and ShellGroupsHistory$ / ShellGroupsHistoryAdd keep the Run history (what ShellRunDialog$ takes). ShellItemIcon$(iconFile, program) is the file an item's icon comes from -- its icon file, else its program or picture, else the program that opens the document -- ready for LOADPICTURE.</p>
<pre><code>Dim groups As Long, main As Long, i As Long
groups = ShellGroupsLoad(App.User &amp; &quot;\groups.ini&quot;)
main = ShellGroupFind(groups, &quot;Main&quot;)
i = ShellItemAdd(groups, main, &quot;Notepad&quot;, &quot;APPS\KPUNCH\NOTEPAD\NOTEPAD.APP&quot;)
If Not ShellItemSet(groups, main, i, &quot;key&quot;, &quot;Ctrl+Alt+N&quot;) Then MsgBox &quot;Not a shortcut.&quot;
picIcon.Picture = LOADPICTURE(ShellItemIcon$(ShellItemGet$(groups, main, i, &quot;icon&quot;), ShellItemGet$(groups, main, i, &quot;program&quot;)))
If Not ShellGroupsSave(groups, App.User &amp; &quot;\groups.ini&quot;) Then MsgBox &quot;Not saved.&quot;
ShellGroupsFree groups</code></pre>
<pre><code>Sub Form1_Load ()
Dim copies As Long
copies = ShellInstanceCount()
Me.Left = 40 + (copies - 1) * 20
Me.Top = 30 + (copies - 1) * 20
End Sub</code></pre>
<p>A desktop's Timer keeps its running count current and starts the programs whose keys were pressed:</p>
<pre><code>Sub Timer1_Timer ()
Dim id As Long
If ShellChangeCount() &lt;&gt; lastChange Then
lastChange = ShellChangeCount()
lblRunning.Caption = ShellRunningCount() &amp; &quot; programs running&quot;
End If
id = HotkeyNext()
Do While id &lt;&gt; 0
StartItemWithKey id
id = HotkeyNext()
Loop
End Sub</code></pre>
<h2>Add-on Packages</h2>
<p>With pkg.bas in the project, a program installs, removes, and makes add-on packages -- the .DPK files Software installs -- the way Software and Package Builder (both written in BASIC) do. PkgOpen() starts a session (a number; PkgClose ends it), and PkgError$(session) says why the last call that failed did. PkgOpenIn(root) starts one on another DVX folder (a copy being made ready on another disk, say): its installed packages and the keys its user folder trusts. Lists come back as rows for a ListView's SetRows: cells separated by TAB, each row ending in a line feed.</p>
<p>What is installed. PkgInstalledRows$ lists every installed package (DVX itself is kpunch.dvx): id, name, version, kind, and summary. A package is named by its id, vendor.name (acme.chess). PkgField$(s, id, field) gives one detail (PKG_FIELD_NAME, PKG_FIELD_VERSION, PKG_FIELD_PUBLISHER, PKG_FIELD_SIGNER_NAME, ...); PkgFilesRows$, PkgDependsRows$, and PkgNeededBy$ its files, what it needs, and what needs it. PkgFileOwner$(s, fileName) is the other way: the id of the package that put a file there (its name from the DVX folder, such as &quot;SHARED\FONTS\KPUNCH\ARIMO.DFN&quot;; &quot;&quot; when none did).</p>
<p>Jobs. Reading package files, installing, removing, and making and signing packages each take a while (checking a signature alone takes a moment on a 486), so each is a job: a ...Start function starts it, and PkgRunFor(s, milliseconds) runs it a little at a time, returning PKG_RUN_BUSY until it is PKG_RUN_DONE or PKG_RUN_FAILED (PkgRunMessage$ says why); PkgRunPercent and PkgRunCurrent$ show how far it is. A session runs one job at a time.</p>
<p>Installing. PkgOfferFileStart(s, path) reads a package file and every package beside it (what it may need) as offers, numbered from 0; the one at path is 0, and the job fails when it cannot be read. PkgOfferField$ and PkgOfferFilesRows$ describe an offer before it is installed; PKG_FIELD_TRUST says whether DVX trusts who signed it. PkgPlan(s, &quot;0&quot;) plans installing it with everything it needs, checked against this DVX and the packages installed (False, with PkgError$ saying why, when it cannot be installed); PkgPlanRows$ lists what will go in, PkgPlanBytes the disk space, and PkgPlanRestart whether libraries or widgets are among them (they work from the next time DVX starts). PkgInstallStart(s) then starts installing.</p>
<pre><code>Function RunJob(s As Long) As Long
Dim rc As Long
Do
rc = PkgRunFor(s, 60)
pbJob.Value = PkgRunPercent(s)
DoEvents
Loop While rc = PKG_RUN_BUSY
RunJob = rc
End Function
If PkgOfferFileStart(s, path) Then
If RunJob(s) = PKG_RUN_DONE And PkgPlan(s, &quot;0&quot;) Then
If PkgInstallStart(s) Then
rc = RunJob(s)
End If
End If
End If</code></pre>
<p>Removing. PkgDependents$(s, ids) lists the installed packages that need the ones going (they must go too), and PkgOrphans$(s, ids) those only they needed. PkgRemoveStart(s, ids, removeChanged) starts removing, run with PkgRunFor like an install; files changed since they were installed stay unless removeChanged, and PkgRunKept$ lists them.</p>
<p>Stopping. PkgRunCancel(s) stops a job after the package it is on: one still being unpacked is left as it was, and one whose files are already in is finished first, so keep calling PkgRunFor until it stops saying PKG_RUN_BUSY. A package being made or signed stops at once, and nothing of it is left behind.</p>
<p>Trust. A publisher signs a package with a key so people can tell it came from them. PkgTrustKey(s, keyPath) trusts a publisher's key file (.KEY) from then on. PkgKeysRows$(s) lists the keys DVX trusts (name, id, and &quot;system&quot; for DVX's own or &quot;user&quot; for one trusted this way), and PkgUntrustKey(s, keyId) stops trusting one of the user's.</p>
<p>Checking a package. PkgVerifyStart(s, path, keyPath) checks a package file without installing it, a job run with PkgRunFor: every file in it against the size and fingerprint its manifest lists, so a damaged or changed package is found. With keyPath (a .KEY file) the package must also be signed by that key, in it or beside it, or nothing starts.</p>
<p>Signing any data. PkgSignData$(s, bytes, secretPath) signs any bytes (a file read into a string, a message) with a secret key file, giving the signature as text; PkgCheckData(s, bytes, signature, keyPath) says whether a signature was made over those bytes by the key in keyPath, or with keyPath &quot;&quot; by a key DVX trusts.</p>
<p>Plain ZIP files. A session also lists, unpacks, and makes ordinary .ZIP files, as jobs run with PkgRunFor: PkgZipListStart(s, zipPath) reads one to its end, every file in it checked; PkgZipExtractStart(s, zipPath, folder) unpacks it into folder (a name that would leave folder stops it); PkgZipCreateStart(s, zipPath, files) makes one from rows of a name in it and the file it comes from (as PkgFolderRows$ gives them). PkgZipRows$(s) lists what the last of them read or packed: name, size, date, and &quot;folder&quot; for a folder.</p>
<p>From a package server. With pkgnet.bas in the project too, a program gets packages from a package server the way Software does. PkgNetOpen(&quot;&quot;) returns a handle on the server DVX's settings name, with the account they give; PkgNetClose frees it. PkgNetServer$, PkgNetPort, PkgNetUser$, and PkgNetPassword$ read those settings (PkgNetUrl$ is the address they make), and PkgNetSaveSettings(server, port, user, password) changes them. A job is started with PkgNetCatalogue (every package the server offers), PkgNetUpdates (what it has that is newer than the packages installed, DVX itself among them), or PkgNetFetch(n, ids) (packages by id, with everything they need that is not installed), and run with PkgNetRunFor(n, milliseconds) until it is PKGNET_DONE or PKGNET_FAILED (PkgNetError$ says why); PkgNetPercent and PkgNetCurrent$ show how far a fetch is. PkgNetRows$ lists the answer (id, name, version, kind, summary, size, and the version installed, if any), and PkgNetField$ and PkgNetDependsRows$ describe one package in it (PKG_FIELD_SHA256 is its file's fingerprint, PKG_FIELD_REPO_SIGNED whether the repository signed it). PkgNetOpenIn(server, root, downloadDir) works for another DVX folder and fetches into another folder. Each package fetched is checked against the size and fingerprint the server gives, and the server's signature of it comes with it, so it is trusted or not exactly as a package file is. What was fetched is in PkgNetDir$: PkgOfferFolderStart(s, folder) reads every package there as the offers (a job), and PkgOfferIndex(s, id) gives the number of the one wanted, to plan and install as above; PkgNetClear removes them afterwards. With an account (the settings', or PkgNetAccount(n, email, password) for another server), PkgNetUpload(n, path) publishes a package file for the server's review, and PkgNetMine(n) asks what the account has sent: PkgNetMineRows$ lists it (id, name, version, state, and the review's note); both sign in first.</p>
<pre><code>n = PkgNetOpen(&quot;&quot;)
If PkgNetFetch(n, &quot;acme.chess&quot;) Then
Do
rc = PkgNetRunFor(n, 60)
pbJob.Value = PkgNetPercent(n)
DoEvents
Loop While rc = PKGNET_BUSY
End If
If rc = PKGNET_DONE And PkgOfferFolderStart(s, PkgNetDir$(n)) Then
rc = RunJob(s)
offer = PkgOfferIndex(s, &quot;acme.chess&quot;)
' plan and install offer as above, then PkgNetClear n
End If</code></pre>
<p>Making packages. PkgBuildStart(s, template, files, out, secret) starts building a package, a job run with PkgRunFor like an install (PkgRunCurrent$ is the file it is on): template is a settings file with a [package] section (id, name, version, kind, and summary, publisher, author, licence, homepage, dvx as wanted) and a [depends] section (id = oldest version for each package it needs); files are rows of a name in the package (from the DVX folder, such as APPS\ACME\CHESS\CHESS.APP) and the file it is made from; secret is the secret key file (.SEC) to sign with, or &quot;&quot;. PkgFolderRows$(s, folder, prefix) gives those rows for every file in a folder, and PkgKindFolder$(kind, id) the folder a package of that kind keeps its files in. PkgSignStart(s, path, secret, detached) signs a package already built: into it, a job run the same way, or beside it (NAME.SIG) when detached, done at once. PkgKeygen(s, name, base) makes a key pair (base.KEY to give out, base.SEC to keep private), and PkgKeyInfo$ reads a key file's name and id. PkgIdValid and PkgVersionValid check an id and a version before building; PkgVersionCompare(a, b) says which of two versions is newer (-1, 0, or 1: &quot;1.10.0&quot; is newer than &quot;1.9.2&quot;); PkgKindName$ lists the kinds.</p>
<h2>Web Requests and JSON</h2>
<p>With http.bas in the project, a program asks web servers for pages, files, and web services' answers. HttpOpen(method, url) makes a request (&quot;GET&quot; to fetch, &quot;POST&quot; to send) and returns a handle; HttpClose frees it. Before starting it, HttpAddHeader adds a header, HttpSetBody gives a body to send with its type (&quot;application/json&quot;, say), HttpSetBodyFile sends a file's bytes instead (a piece at a time, so a file of any size), HttpSaveTo writes the answer's body to a file instead of keeping it (with keepPart True, a file left part-way is finished rather than started again), and HttpSetTimeout sets how many seconds without progress mean the server is not answering (30 to start with). HttpStart starts it (False for an address that is not http://; there is no encryption), and HttpRunFor(h, milliseconds) runs it a little at a time, returning HTTP_BUSY until it is HTTP_DONE or HTTP_FAILED:</p>
<pre><code>h = HttpOpen(&quot;GET&quot;, &quot;http://example.com/news.txt&quot;)
IF HttpStart(h) THEN
DO
rc = HttpRunFor(h, 60)
lblProgress.Caption = CStr(HttpBytes(h)) &amp; &quot; bytes&quot;
DoEvents
LOOP WHILE rc = HTTP_BUSY
END IF
IF rc = HTTP_DONE AND HttpStatus(h) = 200 THEN txtNews.Text = HttpBody$(h)
IF rc = HTTP_FAILED THEN MsgBox HttpError$(h)
HttpClose h</code></pre>
<p>HTTP_DONE means the server answered: HttpStatus is how (200 OK, 404 not found, ...), HttpBody$ what it sent, HttpReplyHeader$ one of its headers, and HttpUrl$ where the answer came from when the server sent the request elsewhere (redirects are followed). HTTP_FAILED means no answer came, and HttpError$ says why. HttpBytes and HttpTotal (-1 until the server says) show progress.</p>
<p>With json.bas in the project, JsonParse(text) reads JSON -- what most web services answer with -- and returns a handle (0 when it is not JSON: JsonError$ says why and on which line); JsonFree frees it. The other functions find a value by its path from the top: member names and item numbers from 0, such as &quot;packages[3].version&quot;. JsonType says what is there (JSON_STRING, JSON_NUMBER, JSON_ARRAY, ..., JSON_NONE for nothing), JsonText$ gives a string, JsonNumber a number, JsonBool True or False, JsonCount how many items an array or members an object has, and JsonKey$(h, path, i) the name of an object's member i. JsonQuote$(text) puts text in quotes with its special characters escaped, for building JSON to send. Text comes and goes as DVX characters: an accented letter or a line-drawing character in a reply is the same character in JsonText$ (&quot;?&quot; stands for one DVX does not have), and JsonQuote$ writes such characters so that any web service reads them right:</p>
<pre><code>h = JsonParse(HttpBody$(req))
FOR i = 0 TO JsonCount(h, &quot;packages&quot;) - 1
lstPackages.AddItem JsonText$(h, &quot;packages[&quot; &amp; CStr(i) &amp; &quot;].name&quot;)
NEXT i
JsonFree h
body = &quot;{&quot; &amp; JsonQuote$(&quot;name&quot;) &amp; &quot;: &quot; &amp; JsonQuote$(txtName.Text) &amp; &quot;}&quot;</code></pre>
<h2>Changing DVX's Settings</h2>
<p>With system.bas in the project, a program changes what Control Panel changes, at once for the whole desktop. Add prefs.bas too: the settings are saved through a prefs.bas handle.</p>
<p>Screen mode: SysVideoModeCount() says how many modes the display offers (numbered from 0), and SysVideoModeWidth, SysVideoModeHeight, and SysVideoModeBpp (bits per pixel) describe each. SysSetVideoMode(wide, high, bpp) changes the mode and keeps every window; it returns False when the mode could not be set (the old one stays), also while a program has the whole screen to itself. A mode the monitor cannot show leaves the user unable to answer, so do as Control Panel does: ask &quot;Keep this mode?&quot; and go back to the old mode by itself after some seconds. Screen.Width, Screen.Height, and Screen.BitsPerPixel tell the mode in use, and SYS_VIDEO_DEFAULT_WIDTH, SYS_VIDEO_DEFAULT_HEIGHT, and SYS_VIDEO_DEFAULT_BPP the mode DVX starts in when its settings name none. SysScreenshot(path) saves the whole screen as a picture file (BMP when path ends in .bmp, PNG otherwise) and returns True when it was written.</p>
<p>Colors: the system colors are numbered from 0 to SysColorCount() - 1. SysColorLabel$(id) is the text to show for one (&quot;Desktop&quot;, &quot;Window Face&quot; ...), SysColorName$(id) the name it is stored as, and SysColorId(colorName) the id of a name (-1 for none) -- to draw in the user's colors, for example SysGetColor(SysColorId(&quot;desktop&quot;)). SysGetColor and SysSetColor read and set a color as an RGB() value; each SysSetColor redraws the whole screen. SysResetColors goes back to DVX's own colors. SysLoadTheme(path) and SysSaveTheme(path) read and write a theme file (.THM; DVX's own are in SHARED\THEMES, the user's in the THEMES folder of the user folder, FileOpsKindDir$(FILEOPS_KIND_THEMES, True)); both return True when they worked.</p>
<p>Wallpaper: SysSetWallpaper(path) shows a BMP, JPG, PNG, or GIF image behind the desktop (&quot;&quot; for none) and returns False when the image could not be loaded (the old one stays). SysSetWallpaperMode mode says how it fills the screen, a choice of PREFS_CHOICE_WALLPAPER (Stretch, Tile, or Center; see Settings Files). SysWallpaper$() and SysWallpaperMode() tell what is in use.</p>
<p>Screen saver: SysSetScreenSaver fileName, minutes chooses the screen saver -- a program in the SAVERS folders, named as FileOpsKindList(FILEOPS_KIND_SAVERS) lists it, or &quot;&quot; for none -- and the minutes with no key or mouse input before it starts (SCREEN_SAVER_WAIT_MIN to SCREEN_SAVER_WAIT_MAX; DVX's default is SCREEN_SAVER_WAIT_DEFAULT). SysScreenSaver$() and SysScreenSaverWait() tell what is in use, SysScreenSaverStart() starts it now as Control Panel's Test does (False when none is chosen or one is running), and SysScreenSaverRunning() is True while one runs. SysIdleSeconds() is how long it has been since the last key or mouse input anywhere on the screen.</p>
<p>Text: SysSetTextSmoothing True smooths the edges of text and SysSetTextSmoothing False stops it; SysTextSmoothing() tells which the user chose. Text is smoothed only when the screen shows more than 256 colors, and only in the fonts and sizes that come smoothed. Every window is drawn again when it changes.</p>
<p>Mouse: SysSetMouse wheelDir, dblClickMs, accel, mickeys, wheelStep applies a whole mouse setup at once: the scroll wheel's direction (1 or -1, the values of PREFS_CHOICE_WHEEL), the double-click time in milliseconds, the acceleration (a value of PREFS_CHOICE_ACCEL), how far the mouse moves for 8 pixels of pointer movement (8 is normal, higher is slower), and the lines scrolled per wheel notch (1 to 10). An accel or mickeys of 0 leaves that one as it is. SysMouseWheelDir, SysMouseDoubleClick, SysMouseAccel, SysMouseMickeys, and SysMouseWheelStep read the setup in effect. MOUSE_WHEEL_STEP_MIN and MOUSE_WHEEL_STEP_MAX are the limits of the wheel step, and MOUSE_WHEEL_STEP_DEFAULT, MOUSE_DBLCLICK_DEFAULT_MS, and MOUSE_SPEED_DEFAULT are DVX's defaults (what a Default button puts back).</p>
<p>The pointer and the keyboard: SysMouseX() and SysMouseY() are where the mouse pointer is on the screen, and SysMouseButtons() the buttons held (vbLeftButton, vbRightButton, and vbMiddleButton bits) -- also while the pointer is over another program's window, where your MouseMove events do not see it. SysSetMousePos x, y moves the pointer (it is kept on the screen). SysShiftState() is the Shift, Ctrl, and Alt keys held now (vbShiftMask, vbCtrlMask, and vbAltMask bits). SysSendKey(keyCode, shift) types a key into the window that has the focus as if the user pressed it, like SendKeys in other BASICs: keyCode as a KeyDown event gets it -- a character code such as ASC(&quot;a&quot;) or 13 for Enter, or a vbKey constant such as vbKeyF1 -- and shift the vbShiftMask, vbCtrlMask, and vbAltMask bits held with it (SysSendKey ASC(&quot;s&quot;), vbCtrlMask is Ctrl+S). The keys arrive in order, one at a time, once your code has returned to DVX; up to 64 can wait, and SysSendKey returns False when that many are waiting. A program cannot press the mouse buttons: to &quot;click&quot; a control, call its event procedure or set its value.</p>
<p>Memory: SysMemoryTotalKb() is the computer's memory in KB and SysMemoryFreeKb() how much of it is free (-1 when it cannot be told).</p>
<p>Libraries: some parts of DVX are optional (Setup's &quot;What to install&quot; page; Software lists each as one package), and so are their libraries: Networking has dvxnet, http, and pkgnet (net.bas, http.bas, pkgnet.bas), Databases has dvxsql (sql.bas), and Communications has conn and xfer (conn.bas, xfer.bas). SysLibraryLoaded(libName) is True when the library a DECLARE LIBRARY line names (any case) is installed (DVX loads a library when it is first needed, so asking loads it). A program that can do without such a library asks first and leaves out what needs it: calling a function of a library that is not there stops the program with &quot;External function not found&quot;. Software, for one, keeps its package server pages off without pkgnet.</p>
<pre><code>If SysLibraryLoaded(&quot;pkgnet&quot;) Then
handle = PkgNetOpen(&quot;&quot;)
Else
lblStatus.Caption = &quot;The package server needs DVX's Networking part.&quot;
End If</code></pre>
<p>System font: SysFontWidth() and SysFontHeight() are the size of every character of the system font in pixels, and SysFontFirstChar() to SysFontFirstChar() + SysFontCharCount() - 1 the character codes it has. SysFontGlyphRow(code, row) is one row of a character's picture: a bit per pixel, &amp;H80 the leftmost -- for drawing text dot by dot, enlarged or in a font editor of your own.</p>
<p>Saving: SysColorsStore, SysWallpaperStore, SysScreenSaverStore, SysFontsStore, and SysMouseStore write the colors, the wallpaper, the screen saver, text smoothing, and the mouse setup into a prefs.bas handle, in the sections DVX reads when it starts; PrefsSetVideoMode does the same for a screen mode. Store them in PrefsLoad(PrefsDvxIni$()) and save it, and DVX starts with them next time. SysColorsLoad, SysWallpaperLoad, SysScreenSaverLoad, SysFontsLoad, and SysMouseLoad apply what a handle holds. A PrefsCreate handle filled with the Store calls is a snapshot in memory: load it again to undo every change, the way Cancel works in Control Panel.</p>
<pre><code>Dim snap As Long
Dim oldW As Long, oldH As Long, oldBpp As Long
Sub Form1_Load ()
snap = PrefsCreate()
SysColorsStore snap
SysWallpaperStore snap
SysFontsStore snap
SysMouseStore snap
oldW = Screen.Width
oldH = Screen.Height
oldBpp = Screen.BitsPerPixel
End Sub
Sub cmdOK_Click ()
Dim ini As Long
ini = PrefsLoad(PrefsDvxIni$())
SysColorsStore ini
SysWallpaperStore ini
SysFontsStore ini
SysMouseStore ini
PrefsSetVideoMode ini, Screen.Width, Screen.Height, Screen.BitsPerPixel
If Not PrefsSave(ini) Then MsgBox &quot;The settings could not be saved.&quot;
PrefsClose ini
Unload Me
End Sub
Sub cmdCancel_Click ()
SysColorsLoad snap
SysWallpaperLoad snap
SysFontsLoad snap
SysMouseLoad snap
If Screen.Width &lt;&gt; oldW Or Screen.Height &lt;&gt; oldH Or Screen.BitsPerPixel &lt;&gt; oldBpp Then
SysSetVideoMode oldW, oldH, oldBpp
End If
Unload Me
End Sub</code></pre>
<h2>Fonts</h2>
<p>Besides the System font (the 8x16 font DVX draws everything with unless told otherwise), DVX comes with font families in its FONTS folder: families for text (sans-serif, serif, and fixed-pitch), display and handwriting families for headings, and pixel fonts. Which of them a computer has depends on how DVX was installed: Setup puts in none, the base set (DejaVu Sans, Sans Mono, and Serif), or all of them. Text in a family that is not installed is drawn in the System font, so a program that cares can look for the family first (FontFamilyCount and FontFamilyName$). With font.bas in the project a program can list them and measure text in them.</p>
<p>A family comes in up to four styles -- regular, bold, italic, and bold italic -- and in the pixel sizes it was made at. A font is always drawn at one of those sizes, never scaled: asking for another size gives the nearest one (FontNearestSize says which), and asking for a style a family has no face for makes it from the nearest face, bold by thickening and italic by slanting. Name a font by its family, size, and style on every call; a family name DVX does not have means the System font. Style is 0 for regular or FONT_BOLD + FONT_ITALIC; FONT_UNDERLINE and FONT_STRIKE are lines drawn with the text.</p>
<pre><code>' With font.bas added to the project: every family and its sizes
Dim i As Long
Dim j As Long
Dim sizes As String
For i = 0 To FontFamilyCount() - 1
sizes = &quot;&quot;
For j = 0 To FontSizeCount(FontFamilyName$(i), 0) - 1
sizes = sizes &amp; &quot; &quot; &amp; Str$(FontSizeAt(FontFamilyName$(i), 0, j))
Next j
Print FontFamilyName$(i); &quot;:&quot;; sizes
Next i
' How wide a heading is in 24-pixel bold DejaVu Sans
Print FontTextWidth(&quot;DejaVu Sans&quot;, 24, FONT_BOLD, &quot;Chapter One&quot;)</code></pre>
<p>FontFamilyFixed tells a fixed-pitch family (every character as wide as every other, for columns and code) from a proportional one. FontLineHeight is the height of one line of text and FontAscent the distance from the top of a line to the baseline the letters sit on. FontRescan reads the FONTS folder again after fonts were added or removed. FontLicence$(family, size, style) gives the notice and licence that go with a font: where it came from, its copyright notices, and its licence text (empty for the System font).</p>
<p>A program can carry fonts of its own, so its text looks the same whatever fonts were installed. List the .DFN files in the project's Fonts (Project &gt; Properties in the IDE): Make builds them into the program, and they are its fonts whenever it runs, from the IDE too. FontAddFile(path), FontAddData(label, bytes), and FontAddResources(file) add more while it runs. A program's fonts are its own -- other programs never see them -- and they go when it ends. Where a font it carries is of a family that is installed too, its sizes and styles come first and the installed family fills in the rest: a program that carries DejaVu Sans Bold at 36 pixels draws that size from its own font and every other size and style of DejaVu Sans from the FONTS folder. Fonts are made from TrueType, Type 1, and bitmap fonts with the SDK's mkfont, or copied from the FONTS folder; each .DFN carries its own licence.</p>
<pre><code>' With font.bas added to the project: a title in a font the program carries
If FontAddFile(App.Path + &quot;\TITLE.DFN&quot;) Then
lblTitle.FontName = &quot;DejaVu Sans&quot;
lblTitle.FontSize = 36
lblTitle.FontBold = True
End If</code></pre>
<p>Every control and every form can have a font of its own, set with the properties FontName, FontSize (in pixels), FontBold, FontItalic, FontUnderline, and FontStrikethru, as in Visual Basic; they need no include file. A control that is given no font uses the font of the control it is in (a Frame, for example), else its form's, so setting a form's font changes every control on it that has none. Reading one of the properties gives the font the object draws with: a FontSize the family does not come in reads back as the nearest size it has, and a FontName DVX does not have reads back as &quot;System&quot;. Setting one changes only that part of the font, keeping the size the font has: where a family's styles come in different sizes (a font the program carries in bold only, say), set FontBold and FontItalic before FontSize, so the size is picked from the style's own sizes. Controls that edit text in columns (TextBox, TextArea, ComboBox, SpinButton, and Terminal) take only fixed-pitch families and show the System font in place of a proportional one. Print, TextWidth, TextHeight, PrintAccel, and TextWidthAccel on forms and picture boxes use the object's font. In the form designer, the Font row of the Properties window sets the six properties at once, and they are saved in the .frm file; DlgFont (see Font Dialog) lets the user choose a font while the program runs.</p>
<pre><code>Sub Form1_Load ()
Me.FontName = &quot;DejaVu Sans&quot; ' every control without a font of its own
Me.FontSize = 14
lblTitle.FontSize = 24 ' the title larger, in DejaVu Sans too
lblTitle.FontBold = True
txtNotes.FontName = &quot;DejaVu Sans Mono&quot;
End Sub</code></pre>
<p>Two controls mix fonts in one control. A RichLabel shows text built by calls -- SetFont, SetStyle, and SetColor choose how the text added next looks, AddText adds it -- in paragraphs aligned left, centered, or right. A RichEdit is a text box the user writes such text in, like a small word processor: the Sel properties (SelBold, SelFontName, SelColor, SelAlignment, ...) read and change the selection's look, TextRTF holds the whole text with its looks as RTF, and LoadFile and SaveFile read and write files. richtext.bas turns RTF into plain text and back without a control. See the controls' own pages for their properties.</p>
<pre><code>Sub cmdBold_Click ()
RichEdit1.SelBold = Not RichEdit1.SelBold
End Sub</code></pre>
<h2>Held Keys for Games</h2>
<p>With game.bas in the project, GameKeyDown(keyCode) tells whether a key is being held down right now, so a game can move something for as long as a key is held instead of waiting for key presses. It returns True only while one of the program's own windows is active. Name the key with one of the GAMEKEY_ constants (the arrow keys, Shift, Ctrl, Alt, Space, Enter, Esc, and a few letters) or with its PC keyboard scan code (add &amp;H80 for the grey keys between the typing keys and the number pad). A Timer polls it:</p>
<pre><code>Sub Timer1_Timer ()
If GameKeyDown(GAMEKEY_LEFT) Then shipX = shipX - 2
If GameKeyDown(GAMEKEY_RIGHT) Then shipX = shipX + 2
End Sub</code></pre>
<p>GameKeyClear forgets the keys held now, so each reads as up until it is pressed again (after a pause screen, say); like GameKeyDown it only works while one of the program's windows is active. FrameMissed() counts the frames FRAMEWAIT skipped because the program was too slow to draw them in time, since it began waiting at its present rate (0 before the first FRAMEWAIT), so a game can draw less when it falls behind. GameWaitRetrace waits until the screen starts drawing its next picture from the top; a full-screen game that draws right after it does not tear.</p>
<pre><code>Do
MoveEverything
If FrameMissed() &gt; lastMissed Then
lastMissed = FrameMissed()
detail = detail - 1
End If
DrawEverything
FRAMEWAIT 60
Loop Until quitting</code></pre>
<h2>Joysticks</h2>
<p>With joystick.bas in the project, a program reads joysticks and game pads. JoyCount() says how many there are; they are numbered from 1, and so are their axes, buttons, and hats. JoyX(joy) and JoyY(joy) say where the stick points, from -32768 (all the way left or up) to 32767 (all the way right or down), 0 in the middle; JoyAxis(joy, axis) reads any axis (3 and 4 are a throttle or rudder). JoyButton(joy, button) is True while the button is held down, and also once after a quick press that happened since the program last asked about that button, so a Timer never misses a shot. JoyHat(joy, hat) gives the direction a hat switch is pushed in degrees (0 is up, 90 right) or JOY_HAT_CENTERED. JoyName$(joy), JoyAxes(joy), and JoyButtons(joy) describe the joystick.</p>
<pre><code>Sub Timer1_Timer ()
If JoyCount() = 0 Then Exit Sub
shipX = shipX + JoyX(1) \ 8192
If JoyButton(1, 1) Then FireShot
End Sub</code></pre>
<p>A program can also hear of every change instead of reading the joystick: JoyWatch joy, True starts keeping that joystick's changes (False stops), and JoyEvent() gives the next one since it was last asked, each once and in order (the last 64 are kept): JOY_EVENT_AXIS (an axis moved), JOY_EVENT_BUTTON_DOWN, JOY_EVENT_BUTTON_UP, JOY_EVENT_HAT, or JOY_EVENT_NONE when nothing has changed. JoyEventJoy() and JoyEventIndex() say which joystick and which axis, button, or hat, and JoyEventValue() an axis's new position or a hat's direction. A button pressed and let go between two Timer ticks still gives both.</p>
<pre><code>Sub Form1_Load ()
ok = JoyWatch(1, True)
End Sub
Sub Timer1_Timer ()
Dim kind As Long
kind = JoyEvent()
Do While kind &lt;&gt; JOY_EVENT_NONE
If kind = JOY_EVENT_BUTTON_DOWN And JoyEventIndex() = 1 Then FireShot
If kind = JOY_EVENT_AXIS And JoyEventIndex() = 1 Then shipSpeed = JoyEventValue() \ 8192
kind = JoyEvent()
Loop
End Sub</code></pre>
<p>When no joystick is connected the keyboard stands in for one (the arrow keys, with Left Ctrl, Space, Left Shift, and Z as buttons), and it only answers while one of the program's windows is active. Joysticks are calibrated, and the keyboard joystick's keys chosen, on the Control Panel's Game Controllers tab. QBasic's STICK and STRIG work too, without joystick.bas.</p>
<p>joystick.bas can also set joysticks up, as the Control Panel does. JoyHats(joy) counts the hats, JoyAxisPresent(joy, axis) is True when an axis answers, JoyConnected(joy) is False once a joystick stops answering, and JoyCanCalibrate(joy) is True for one with analog axes. For calibrating, JoyRawAxis(joy, axis) gives an axis's raw reading and JoyRawButtons(joy) the buttons held (1 for button 1, 2 for button 2, 4 for button 3, ... added up); JoySetCalibration(joy, axis, minV, centerV, maxV) takes the readings at one end, the middle, and the other end, and JoyClearCalibration(joy, axis) lets the axis find its own range again. JoyDeadZone(joy) and JoySetDeadZone(joy, percent) are the dead zone round the middle (0 to 50 percent). JoyChoiceCount, JoyChoiceLabel$, JoyChoice, and JoySetChoice list and change the game port's mode (JOY_CHOICE_GAMEPORT) and when the keyboard joystick stands in (JOY_CHOICE_FALLBACK); JoyKeyCount and JoyKeyName$(index) list the keys the keyboard joystick can use, and JoyKbdSlot(slot) and JoySetKbdSlot(slot, keyIndex) its keys for up, down, left, right, and buttons 1 to 4 (slots 0 to 7). These lists are numbered from 0, so they fill a DropDown in order. JoyKeyIndex(keyName) gives a key's number by its name (-1 when unknown), JoyKeyCode(index) its raw key code, which GameKeyDown in game.bas takes, and JoyKeyNameOf$(rawCode) the name of a raw key code. JoyIsKeyboard(joy) is True for the keyboard standing in for a joystick, and JoyCalibration(joy, axis, part) reads back an axis's calibration: part JOY_CAL_MIN, JOY_CAL_CENTER, or JOY_CAL_MAX of the readings set with JoySetCalibration, or of the range the axis found by itself (0 for a joystick that cannot be calibrated). JoySetting$(key, default) and JoySetSetting key, value reach any other joystick setting; JOY_KEY_POLL_HZ is the key of how often joysticks are read, JOY_POLL_HZ_MIN to JOY_POLL_HZ_MAX times a second (JOY_POLL_HZ_DEFAULT normally), and dead zones go up to JOY_DEADZONE_MAX percent (JOY_DEADZONE_DEFAULT normally). After a new game port mode, JoyRescan() looks for joysticks again; it returns the new count, or -1 while another program is using a joystick. Every change applies at once; JoySettingsStore handle puts them all into a settings handle from prefs.bas for the program to save, and JoySettingsLoad handle takes them back from one, to undo.</p>
<pre><code>Sub cmdCenter_Click ()
' The stick rests in the middle: remember the readings
centerX = JoyRawAxis(1, 1)
End Sub
Sub cmdFinish_Click ()
If Not JoySetCalibration(1, 1, lowX, centerX, highX) Then
MsgBox &quot;Move the stick all the way to each side.&quot;
End If
End Sub</code></pre>
<p><a href="#lang.sound">See: STICK and STRIG</a></p>
<h2>Sound</h2>
<p>With sound.bas in the project, a program plays sound files and tones through whatever sound hardware the computer has: a Sound Blaster, the PC speaker (tones only, unless sampled sound on the speaker is switched on), or nothing at all, in which case the program works the same but is silent. Several programs can play at once, and everything a program plays stops when it ends.</p>
<p>PlayWave(fileName) plays a WAV or VOC file once and PlayWaveLoop(fileName) over and over; PlayTone(frequency, milliseconds, volume) plays a tone of frequency hertz (20 to 20000) and PlayNoise(frequency, milliseconds, volume) noise, which sounds brighter the higher the frequency; a length of 0 plays until stopped. Each returns a voice number, or SOUND_FAILED (0) when the sound could not be played, and then SoundError$() says why. StopWave(voice) stops one sound, StopAllSounds() all of the program's sounds, and SoundPlaying(voice) is True while a sound is still playing. SoundVolume(volume) sets the volume of everything the program plays. Volumes are percent (0 to 100). SoundInfo$() describes the sound device, like &quot;Sound Blaster 16 (DSP 4.05) at 220h, 22050 Hz, 16-bit stereo&quot;.</p>
<pre><code>Dim Shared boom As Long
Sub cmdFire_Click ()
boom = PlayWave(&quot;BOOM.WAV&quot;)
If boom = SOUND_FAILED Then
lblStatus.Caption = SoundError$()
End If
End Sub</code></pre>
<p>WAV files must be uncompressed (8 or 16 bits, mono or stereo); VOC files may be 8- or 16-bit. QBasic's BEEP, SOUND, and PLAY work too, without sound.bas.</p>
<p>PlayTriangle(frequency, milliseconds, volume) plays a triangle tone, softer than PlayTone's square tone. SoundGetVolume() gives the volume of everything the program plays. SoundCaps(field) tells what the sound device can do, by name in any case: &quot;dac&quot; (it plays recorded sound), &quot;synth&quot; (it has a music synthesizer), &quot;tone&quot; (it plays tones on a tone generator), &quot;running&quot;, and &quot;record&quot; (it records sound) are True or False; &quot;voices&quot; (how many sounds play at once), &quot;rate&quot; (hertz), &quot;bits&quot;, &quot;channels&quot;, and &quot;recordsources&quot; (the inputs it records from) are numbers. SoundDriver$() is the short name of the sound driver playing (&quot;sb&quot;, &quot;speaker&quot;, ...; &quot;&quot; when none is), and SoundStats(field) what the mixer has done since the device started: &quot;renders&quot; (blocks of sound made), &quot;frames&quot; (samples made), &quot;underruns&quot; (stream samples that were due but not yet written), &quot;clipped&quot; (samples too loud), &quot;dropped&quot; (sounds dropped because too many played at once), and &quot;playing&quot; (voices playing now). SoundPlayEvent eventIdx, wait plays one of DVX's own event sounds (SOUND_EVENT_DEFAULT, SOUND_EVENT_ERROR, SOUND_EVENT_WARNING, ...), the one the settings choose; with wait True it returns once the sound has played (DVX and the program's events go on meanwhile, as in DoEvents; in a control file's code, and once the program is ending, it does not wait).</p>
<p>A sound played often is best loaded once. SoundLoad(fileName) loads a WAV or VOC file and returns a sound number, or 0 (SoundError$() says why); it reads and decodes the whole file before it returns, so for a long recording (a minute or more) use MusicLoad and MusicPlay (music.bas), which play a WAV or VOC file as they read it; SoundCreate(data, rate, bits, channels) makes a sound from raw sound data in a string: 8-bit samples (0 to 255, 128 is silence) or 16-bit ones (two bytes each, the low byte first), mono or stereo (left, right, left, ...), rate times a second (SOUND_RATE_MIN to SOUND_RATE_MAX). SoundLoadData(bytes) loads one from the bytes of a WAV or VOC file held in a string, such as ResGetData$ (resource.bas) or HttpBody$ (http.bas) gives. SoundPlay(sound, volume, pan, loopIt) plays it on a new voice and returns the voice number; pan goes from SOUND_PAN_LEFT (-100) through SOUND_PAN_CENTER (0) to SOUND_PAN_RIGHT (100). SoundLength(sound) is its length in milliseconds, SoundRate(sound), SoundBits(sound), and SoundChannels(sound) how it was recorded, and SoundFree sound stops its voices and forgets it. While a voice plays, SoundSetVolume voice, volume, SoundSetPan voice, pan, and SoundSetPitch voice, percent change it (pitch is a percent of the recorded speed: SOUND_PITCH_NORMAL is 100, 200 is an octave higher, from SOUND_PITCH_MIN 25 to SOUND_PITCH_MAX 400), and SoundSetFrequency voice, hertz changes a tone's frequency. SoundPause voice holds a sound's voice where it is, silent, and SoundResume voice goes on from there (a tone cannot be paused). A program's sounds are freed when it ends.</p>
<p>To hear of every sound ending, call SoundEnded() from a Timer: it gives the next of the program's voices that ended since it was last asked (each once, in the order they ended; the last 64 are kept), or 0 when none has, and SoundEndReason() says why that one ended: SOUND_END_FINISHED (it played to its end), SOUND_END_STOPPED (StopWave, StopAllSounds, or its sound was freed), or SOUND_END_DROPPED (too many sounds played at once and it was the quietest).</p>
<pre><code>Sub Timer1_Timer ()
Dim v As Long
v = SoundEnded()
Do While v &lt;&gt; 0
If v = engine And SoundEndReason() = SOUND_END_FINISHED Then engine = SoundPlay(idle, 60, 0, True)
v = SoundEnded()
Loop
End Sub</code></pre>
<pre><code>Dim Shared laser As Long
Sub Form1_Load ()
laser = SoundLoad(&quot;LASER.WAV&quot;)
End Sub
Sub Fire (x As Integer)
Dim v As Long
v = SoundPlay(laser, 80, (x - 160) * 100 \ 160, False)
SoundSetPitch v, 90 + Int(Rnd * 20)
End Sub</code></pre>
<p>A program can also make its sound as it goes, for speech or music of its own. SoundStreamOpen(rate, bits, channels, bufferMs) opens a stream that starts playing at once (silence until data arrives) and holds bufferMs milliseconds of sound (0 for the usual SOUND_STREAM_MS_DEFAULT; SOUND_STREAM_MS_MIN to SOUND_STREAM_MS_MAX). SoundStreamWrite(stream, data) adds raw sound data in the stream's format and returns how many bytes it took; keep the rest and write it again later. SoundStreamSpace(stream) is the room left and SoundStreamQueued(stream) what is waiting to play, both in samples (a stereo sample counts once). SoundStreamVoice(stream) is the stream's voice, for SoundSetVolume, SoundSetPan, SoundSetPitch, SoundPause, and SoundResume. SoundStreamFlush stream drops what is waiting to play, so what is written next is heard at once (to jump to another place in what you play), and SoundStreamClose stream stops it. A Timer keeps a stream fed:</p>
<pre><code>Sub Timer1_Timer ()
Dim taken As Long
taken = SoundStreamWrite(stream, pending)
pending = Mid$(pending, taken + 1)
If Len(pending) = 0 Then pending = MakeMoreSound()
End Sub</code></pre>
<p>A melody of tones -- a game's tune or a sound effect -- plays without a gap or a stumble in a note queue. NotesOpen(wave, volume) opens one in a waveform (SOUND_WAVE_SQUARE, SOUND_WAVE_TRIANGLE, or SOUND_WAVE_NOISE) and returns its number, or 0. NotesAdd(queue, hertz, milliseconds) adds a tone (0 hertz for a rest; fractions count) and returns True, or False when 256 are already waiting; each lasts exactly as long as asked, as long as the next is added before the one playing ends. NotesSetTone(queue, wave, volume) changes the waveform and volume (percent of the queue's) of the tones added from then on, so they change in time with the tune. NotesQueued(queue) is how many tones and rests have not finished (0 once it has gone quiet) and NotesSpace(queue) how many more fit; NotesVoice(queue) is its voice, for SoundSetVolume and SoundSetPan. NotesClear queue silences it and forgets what it holds, and NotesClose queue closes it. PLAY's V and @ commands give PLAY tunes a volume and a waveform too.</p>
<pre><code>q = NotesOpen(SOUND_WAVE_TRIANGLE, 80)
For f = 200 To 800 Step 50
ok = NotesAdd(q, f, 15) ' a rising sweep, 15 ms a step
Next f</code></pre>
<p>A program can record sound from the sound card's microphone, line, or CD input into a WAV file, or into memory. SoundCaps(&quot;record&quot;) says whether the card can, and SoundCaps(&quot;recordsources&quot;) which inputs it has (the bit 2 ^ RECORD_MIC, RECORD_LINE, or RECORD_CD set for each). RecordStart(fileName, rate, bits, channels, inputSource) starts recording (0 for 22,050 Hz, 16-bit, mono) and returns True, or False with SoundError$ saying why; the card records at its nearest, which RecordRate(), RecordBits(), and RecordChannels() tell. While it records, RecordLength() is how long the recording is (milliseconds) and RecordLevel() the loudest sound since it was last asked (percent: a level meter); RecordLost() counts samples dropped because DVX was too busy. RecordStop() ends it and returns True when the file was all written; Recording() is True in between. With a file name of &quot;&quot;, RecordStart records into memory instead: RecordRead$(maxBytes) takes up to maxBytes of what was recorded and not yet taken, as raw sound data in the recording's format (as SoundCreate and SoundStreamWrite take it), and RecordQueued() is how many bytes are waiting. Take them often, from a Timer: about two seconds are kept, and what does not fit is lost (RecordLost()). A program can show the sound as it comes, change it, or send it over the network. Most sound cards record or play, not both, so nothing plays while a program records, and one program records at a time. A program's recording ends when the program does.</p>
<pre><code>If RecordStart(&quot;NOTE.WAV&quot;, 0, 0, 0, RECORD_MIC) Then
' ... a Timer shows RecordLength() and RecordLevel()
ok = RecordStop()
End If</code></pre>
<p>On a computer with an FM synthesizer chip (AdLib and most Sound Blasters), a program can play instruments of its own. FmInfo$(field) describes the chip: &quot;description&quot; (like &quot;OPL3 FM synthesizer at 388h&quot;, &quot;&quot; when there is none), &quot;voices&quot;, &quot;free&quot; (voices no program has), &quot;stereo&quot;, and &quot;owned&quot; (one program has the whole chip). FmAlloc() takes one of its two-operator voices (0 when none is free), FmWrite(voice, register, value) sets one of the voice's registers (the FM_ constants: FM_MOD_CHAR, FM_CAR_LEVEL, FM_FNUM_LOW, FM_KEY_BLOCK with FM_KEY_ON, ...; True when it worked), and FmFree voice gives it back. A player of chip music files can take the whole chip with FmRawAcquire() (False while another program has it), set any register with FmRawWrite(register, value) (bank * FM_BANK_REGS + register; the second bank only on an OPL3) and give it back with FmRawRelease. A frequency number for FM_FNUM_LOW and FM_KEY_BLOCK is hertz * 2 ^ 20 / (FM_CHIP_HZ * 2 ^ block).</p>
<p>On a wavetable sound card (a Gravis UltraSound, a Sound Blaster AWE32 or AWE64), a program can play recorded sounds on the card's own voices from the card's memory. WtInfo$(field) describes the card: &quot;description&quot; (&quot;&quot; when there is none), &quot;voices&quot;, &quot;free&quot; (voices no program has), &quot;memory&quot;, &quot;freememory&quot; (the largest free block), and &quot;freetotal&quot; (all free, in blocks maybe apart; bytes), &quot;level&quot; (how many centibels louder a voice at full volume is than the loudest recorded sound the card plays: 0 when it is the same or not known), and what the card does itself (&quot;envelopes&quot;, &quot;lfos&quot;, &quot;filter&quot;, &quot;effects&quot;, &quot;8bit&quot;, &quot;rom&quot;; True or False as text). WtMemAlloc(bytes, bits) takes memory for samples of 8 or 16 bits (its address, -1 when there is no room), WtUpload(address, pcm, bits) copies 16-bit mono samples there (a binary string, two bytes a sample; True when it worked), and WtMemFree address gives it back. WtAlloc() takes a voice (0 when none is free); WtStart(voice, address, startFrame, endFrame, loopStart, loopEnd, loopMode, bits, pitch, attenuation, pan) plays a sample on it from startFrame (0: its first; loopMode 0 plays once, 1 loops, 3 loops until WtRelease; pitch in cents, 0 for 44,100 samples a second and 1200 an octave higher; attenuation in centibels, 0 loudest and 60 half as loud; pan -100 to 100); on a card with a General MIDI sample ROM (WtInfo$(&quot;rom&quot;)) the address may be WT_ADDR_ROM plus the bytes from the ROM's start. WtSetPitch, WtSetAttenuation, and WtSetPan change a playing voice, WtStop silences it, WtActive(voice) is True while it sounds, and WtFree voice gives it back. WtShape(voice, field, value) shapes the voice's notes as a SoundFont instrument does, one value by name, where the card can (WtInfo$ &quot;envelopes&quot;, &quot;lfos&quot;, &quot;filter&quot;, &quot;effects&quot;): the volume envelope (&quot;voldelay&quot;, &quot;volattack&quot;, &quot;volhold&quot;, &quot;voldecay&quot;, &quot;volsustain&quot;, &quot;volrelease&quot;), the modulation envelope (&quot;moddelay&quot; to &quot;modrelease&quot;, &quot;modenvpitch&quot;, &quot;modenvfilter&quot;), the modulation and vibrato LFOs (&quot;modlfodelay&quot;, &quot;modlfofreq&quot;, &quot;modlfopitch&quot;, &quot;modlfofilter&quot;, &quot;modlfovolume&quot;, &quot;viblfodelay&quot;, &quot;viblfofreq&quot;, &quot;viblfopitch&quot;), the filter (&quot;filterfc&quot;, &quot;filterq&quot;), and the effects (&quot;reverb&quot;, &quot;chorus&quot;), in the units sound.bas lists. A value is kept for the voice's next WtStart; the filter, the effects, and the LFO depths also change a note that is sounding. Everything a program took is given back when it ends.</p>
<p>sound.bas also changes DVX's own sound settings, as the Control Panel's Sounds page does. DVX plays a sound for each of SoundEventCount() events, numbered from 0: SoundEventLabel$(eventIdx) names one (&quot;Start DVX&quot;, &quot;Error&quot;, ...) and SoundEventKey$(eventIdx) gives its key in DVX.INI. With a settings handle from prefs.bas (PrefsLoad(PrefsDvxIni$())), SoundEventFile$(handle, eventIdx) is the event's sound file (&quot;&quot; for none) and SoundSetEventFile handle, eventIdx, fileName changes it; after the program saves the file, SoundEventsReload makes DVX play the new sounds. SoundTestFile(fileName) plays a file the way DVX plays its event sounds (0 when it cannot, and SoundError$() says why), and SoundFolder$() is the folder of DVX's own sounds. SoundMasterVolume() and SoundSetMasterVolume percent are the volume of all sound from every program. SoundDriverCount() reads the list of sound drivers and SoundDriverName$(index) names each; SoundDriverAuto$() is the setting that means &quot;find the best one&quot;. SoundMidiCount() and SoundMidiLabel$(index) list where MIDI music can play, SoundMidiInCount() and SoundMidiInLabel$(index) where MIDI input can come from, and SoundModulesCount() and SoundModulesLabel$(index) where music modules can play. SoundSettingDriver$(handle), SoundSettingMidi(handle), SoundSettingModules(handle), and SoundSettingVolume(handle) read the sound driver, MIDI choice, modules choice, and master volume from the settings, and SoundSettingsStore handle, driver, midi, modules, volume stores them (a new driver or MIDI choice takes effect when DVX next starts, a modules choice with the next music); SoundSettingMidiIn(handle) and SoundSettingMidiInStore handle, midiIn read and store the MIDI input choice (it takes effect when DVX next starts).</p>
<pre><code>Dim ini As Long
Dim i As Long
ini = PrefsLoad(PrefsDvxIni$())
For i = 0 To SoundEventCount() - 1
lstEvents.AddItem SoundEventLabel$(i) &amp; &quot;: &quot; &amp; SoundEventFile$(ini, i)
Next i</code></pre>
<p><a href="#lang.sound">See: BEEP, SOUND, and PLAY</a></p>
<h2>Music</h2>
<p>With music.bas in the project, a program plays music files: tracker modules (MOD, S3M, XM, and IT files, made of recorded instrument sounds) wherever the computer can play sampled sound (on a Gravis UltraSound's or Sound Blaster AWE's own voices, which takes the computer little time), MIDI files (.MID, types 0 and 1) on the computer's music synthesizer, or on a built-in synthesizer that sounds much the same when there is none, and WAV and VOC sound files wherever the computer can play sampled sound (a long WAV recording is read from the disk as it plays, so it needs no memory). Several programs can play music at once, and everything a program plays stops when it ends.</p>
<p>MusicLoad(fileName) loads a music file and returns its music number, or MUSIC_FAILED (0) when it could not be loaded; MusicError$() then says why. MusicLoadData(bytes) does the same with the bytes of a music or sound file held in a string (from ResGetData$ or HttpBody$, say). MusicPlay(music, loopIt) plays it from where it is (the start after loading or stopping); with loopIt True it starts over at the end until it is stopped. MusicStop(music) stops and goes back to the start, MusicPause(music) and MusicResume(music) pause and go on, and MusicPlaying(music) is True while it plays. MusicEnded(music) is True once after the music played to its end (not when it was stopped) since MusicPlay started it: a Timer that asks it can start the next tune on time. MusicVolume(music, volume) sets its volume in percent (0 to 100). MusicPosition(music) and MusicLength(music) give the place and the length in milliseconds, and MusicSeek(music, milliseconds) goes to a place (a module goes to the start of the part that holds it). MusicFree(music) stops a music and forgets it.</p>
<p>MusicLoadMacro(macro) makes a music from a music macro string, the kind PLAY takes, with its notes on the General MIDI instruments its I commands name (the piano before any I): the tune can then be played in the background, paused, stopped, and made quieter like any music. MIDI music plays on the instruments chosen in Control Panel; MusicSetBank music, bank plays one music on another instrument bank, named as in the banks folders (&quot;&quot; is DVX's standard bank), before the music first plays (MusicError$ says when the bank is missing or damaged). A SoundFont (.SF2 or .SBK) gives the recorded instruments for a wavetable card or the built-in SoundFont synthesizer, as can a Gravis UltraSound's own patches: MusicPatchSet$() names them (their ULTRASND.INI, &quot;&quot; when there are none), and MusicRomBank$() names the instruments built into a Sound Blaster AWE card (&quot;&quot; when Creative's software is not installed).</p>
<pre><code>tune = MusicLoadMacro(&quot;T150 I41 O4 L8 CEG&gt;C4&quot;)
MusicSetBank tune, &quot;DMXOPL.OP2&quot;
MusicPlay tune, False</code></pre>
<pre><code>Dim Shared tune As Long
Sub Form1_Load ()
tune = MusicLoad(&quot;THEME.MOD&quot;)
If tune = MUSIC_FAILED Then
lblStatus.Caption = MusicError$()
Else
MusicPlay tune, True
End If
End Sub</code></pre>
<p>A program can also play notes itself, like a keyboard. MusicMidiOpen() returns a live music that is already playing. MusicNoteOn(music, channel, note, velocity) starts a note and MusicNoteOff(music, channel, note) ends it; MusicProgram(music, channel, program) chooses a channel's instrument, MusicControl(music, channel, controller, value) sets a controller (7 volume, 10 pan, 11 expression, 64 the sustain pedal, 123 all notes off), and MusicPitchBend(music, channel, bend) bends the channel's notes (-8192 to 8191, two semitones either way at the ends). Channels are 1 to 16, and channel 10 (MUSIC_DRUMS) plays drums, one per note. Notes, velocities, instruments, and controller values are 0 to 127; middle C is note 60, and instruments are numbered as in General MIDI (0 piano, 24 guitar, 40 violin, 56 trumpet, 73 flute). The same calls work on a MIDI file that is playing.</p>
<pre><code>Dim Shared keys As Long
Sub Form1_Load ()
keys = MusicMidiOpen()
MusicProgram keys, 1, 73
End Sub
Sub cmdC_Click ()
MusicNoteOn keys, 1, 60, 100
tmrNoteOff.Enabled = True
End Sub
Sub tmrNoteOff_Timer ()
MusicNoteOff keys, 1, 60
tmrNoteOff.Enabled = False
End Sub</code></pre>
<p>MusicGetVolume(music) gives a music's volume in percent. MusicInfo$(music, field) tells about it, by name in any case: &quot;title&quot; (a module's own title, or the name a MIDI file gives itself; &quot;&quot; for a sound file), &quot;output&quot; (where it plays, for people), &quot;kind&quot; (&quot;module&quot;, &quot;midi&quot;, &quot;live&quot;, or &quot;sound&quot;), &quot;where&quot; (&quot;stream&quot;, &quot;mpu401&quot;, &quot;fm&quot;, &quot;software&quot;, &quot;wave&quot;, or &quot;softwave&quot;; &quot;wave&quot; is a wavetable card's voices, for a module too; &quot;&quot; before it first plays), and &quot;paused&quot; and &quot;looping&quot; (True or False as text; VAL gives the value).</p>
<p>A program that sends MIDI itself (system exclusive messages, a sequencer of its own) can have the MIDI port, one program at a time, when the settings send MIDI music to the MIDI port. MidiPortInfo$(field) describes it: &quot;description&quot; (&quot;&quot; when there is none), &quot;present&quot;, &quot;owned&quot; (a program has it), &quot;input&quot; (it brings MIDI in), and &quot;inputowned&quot; (a program reads what comes in). MidiAcquire() takes the port (False when another program has it or there is none), MidiPut(byteValue) sends one byte (False when the port could not take it yet: send it again), and MidiRelease gives the port back.</p>
<p>When the settings take MIDI input from the MIDI port (Control Panel, Sounds, MIDI in), a program can read what a MIDI keyboard or another instrument plays. MidiInOpen() starts reading (False when there is no MIDI input or another program reads it; SoundError$() says which) and MidiInClose stops; a program's reading stops when it ends. MidiInMessage() gives the next message that came, or MIDI_NONE (-1) when none waits. A message is packed into one number: the status is midiMsg AND 255 (its kind, midiMsg AND MIDI_KIND_MASK, is MIDI_NOTE_ON, MIDI_NOTE_OFF, MIDI_CONTROL, MIDI_PROGRAM, MIDI_PITCH_BEND, MIDI_KEY_PRESSURE, or MIDI_CHANNEL_PRESSURE, and its channel, numbered as MusicNoteOn numbers them, is (midiMsg AND MIDI_CHANNEL_MASK) + 1), the first data byte (the note) is (midiMsg \ 256) AND 255, and the second (the velocity) (midiMsg \ 65536) AND 255. A note on with a velocity of 0 is a note off too. MidiInTime() is when the message MidiInMessage gave last came and MidiInClock() the time now, both in milliseconds since MidiInOpen; MidiInLost() counts bytes lost because the program read too late. MusicMidiSend music, midiMsg plays a message as it came on a live music (MIDI thru), so what is played is heard.</p>
<p>A MIDI recording keeps messages with their times and saves them as a MIDI file that MusicLoad plays. MidiRecordNew() returns a recording number (0 when there is no room; MusicError$() says why), MidiRecordAdd recording, milliseconds, midiMsg adds a message (MidiInTime() is the time to give, when the recording started with MidiInOpen), MidiRecordCount(recording) and MidiRecordLength(recording) tell how many messages it has and when the last came, MidiRecordSave(recording, fileName) writes the file (False when it could not be written; MusicError$() says why; a note still held at the end is let go), and MidiRecordFree recording frees it. A program's recordings are freed when it ends. The Sound Recorder records a MIDI keyboard this way:</p>
<pre><code>Dim Shared take As Long
Dim Shared keys As Long
Sub cmdRecord_Click ()
If MidiInOpen() Then
take = MidiRecordNew()
keys = MusicMidiOpen()
tmrTake.Enabled = True
End If
End Sub
Sub tmrTake_Timer ()
Dim midiMsg As Long
midiMsg = MidiInMessage()
Do While midiMsg &lt;&gt; MIDI_NONE
MusicMidiSend keys, midiMsg
MidiRecordAdd take, MidiInTime(), midiMsg
midiMsg = MidiInMessage()
Loop
End Sub
Sub cmdStop_Click ()
tmrTake.Enabled = False
MidiInClose
MusicFree keys
If Not MidiRecordSave(take, &quot;SONG.MID&quot;) Then
Print &quot;Not saved: &quot; &amp; MusicError$()
End If
MidiRecordFree take
End Sub</code></pre>
<h2>Network Connections</h2>
<p>With net.bas in the project, a program talks to other computers over the network set up in the Control Panel. TcpConnect returns a handle (0 when it failed; NetError$ says why), TcpSend sends text, and TcpRecv$ returns whatever has arrived without waiting, so a Timer keeps the program responsive:</p>
<pre><code>Dim conn As Long
Sub Form1_Load ()
conn = TcpConnect(&quot;bbs.example.org&quot;, 23)
If conn = 0 Then
Print &quot;Could not connect: &quot; &amp; NetError$()
End If
End Sub
Sub Timer1_Timer ()
If TcpPending(conn) &gt; 0 Then Print TcpRecv$(conn)
If TcpConnected(conn) = 0 Then Timer1.Enabled = False
End Sub</code></pre>
<pre> Function Description
-------- -----------
HostLookup$(hostName) The address of a name, such as &quot;192.0.2.10&quot;, or &quot;&quot; when it is not found. Waits for the answer; other programs keep running.
HostLookupStart(hostName) The same without waiting: a lookup handle (0 when too many are under way).
HostLookupPoll(lookup) NET_BUSY while the lookup goes on, NET_DONE once found, NET_FAILED (NetError$ says why).
HostLookupResult$(lookup) The address found, once HostLookupPoll says NET_DONE.
HostLookupClose lookup Free a lookup handle (or give the lookup up).
HostName$(address) The name of an address; the address itself when no name is known for it.
NetAddress$() This computer's address (&quot;&quot; while it has none).
NetError$() Why the last call failed, in plain words.
TcpConnect(host, port) Connect; a handle, or 0. Waits up to 20 seconds; other programs keep running.
TcpConnectStart(host, port) The same without waiting: the connection's handle at once (0 when it cannot start).
TcpConnectPoll(handle) NET_BUSY while the host is looked up and the connection made, NET_DONE once it is (the handle then works as TcpConnect's), NET_FAILED (close it).
TcpListen(port) Wait for connections on port; a listening handle, or 0.
TcpAccept(handle) A connection that arrived on a listening handle, or 0 when none is waiting.
TcpSend(handle, bytes) Send text or any other bytes; the bytes sent, or -1. Waits while the connection's buffer is full.
TcpSendSome(handle, bytes) Send what the connection takes now, never waiting: the bytes taken from the start (0 while it is full), or -1.
TcpPending(handle) Bytes waiting to be read (-1 for a bad handle).
TcpRecv$(handle) What has arrived (up to 4096 bytes), or &quot;&quot;.
TcpPeek$(handle) What has arrived (up to 4096 bytes), left waiting for the next TcpRecv$: look for a line's end or a message's length first.
TcpConnected(handle) 1 while the connection is open, 0 once the other side closed it.
TcpShutdown(handle) Tell the other side nothing more will be sent; what it sends can still be read.
TcpPeer$(handle) &quot;address:port&quot; of the other side (&quot;&quot; when not connected).
TcpLocalPort(handle) The port a handle uses on this computer (the one TcpListen(0) picked).
TcpSetNoDelay(handle, enable) True: send small pieces at once instead of gathering them (typing, games).
TcpSetKeepAlive(handle, enable) True: check now and then that the other side of an idle connection is still there.
TcpClose handle Close a connection or a listening handle.
UdpOpen(port) A UDP handle on port (0 = any free port), or 0.
UdpSend(handle, host, port, text) Send one message; the bytes sent, or -1. &quot;255.255.255.255&quot; reaches every computer nearby.
UdpRecv$(handle) The next message that arrived, or &quot;&quot;.
UdpFrom$() &quot;address:port&quot; of the sender of the last UdpRecv$ message.
UdpClose handle Close a UDP handle.</pre>
<p>The strings sent and received may hold any bytes, CHR$(0) too, so binary protocols work as well as text. Every connection a program opens is closed for it when the program ends.</p>
<p>HostLookup$, TcpConnect, and TcpSend wait until they are done. Other programs keep running meanwhile, but yours does not: its windows do not answer, and the first lookup after DVX starts can also wait for the network to get its settings (DHCP). To stay responsive, start the lookup or connection and check on it from a Timer:</p>
<pre><code>Dim conn As Long
Sub cmdConnect_Click ()
conn = TcpConnectStart(&quot;bbs.example.org&quot;, 23)
Timer1.Enabled = conn &lt;&gt; 0
End Sub
Sub Timer1_Timer ()
Select Case TcpConnectPoll(conn)
Case NET_DONE
Timer1.Enabled = False
lblStatus.Caption = &quot;Connected&quot;
Case NET_FAILED
Timer1.Enabled = False
lblStatus.Caption = &quot;Could not connect: &quot; &amp; NetError$()
TcpClose conn
End Select
End Sub</code></pre>
<p>A program can also edit the network settings the way the Control Panel's Network page does, and show the network's state. The settings are kept in DVX's settings file, so NetConfigLoad and NetConfigStore take a handle from prefs.bas (add prefs.bas to the project too). NetConfigLoad gives a settings handle (0 when none is free); read and change its fields by name, check them, store them, and restart the network only when they changed:</p>
<pre><code>Dim prefs As Long
Dim cfg As Long
Sub Form1_Load ()
prefs = PrefsLoad(PrefsDvxIni$())
cfg = NetConfigLoad(prefs)
txtName.Text = NetConfigGet$(cfg, &quot;hostname&quot;)
lblState.Caption = NetStatus$(&quot;message&quot;)
End Sub
Sub cmdOK_Click ()
NetConfigSet cfg, &quot;hostname&quot;, txtName.Text
If NetConfigProblem$(cfg) &lt;&gt; &quot;&quot; Then
MsgBox NetConfigProblem$(cfg)
Exit Sub
End If
NetConfigStore cfg, prefs
PrefsSave prefs
If NetConfigChanged(cfg) Then NetRestart
NetConfigFree cfg
PrefsClose prefs
End Sub</code></pre>
<pre> Function Description
-------- -----------
NetConfigLoad(prefs) A settings handle holding the network settings of prefs (0 for the usual settings), or 0 when none is free.
NetConfigGet$(cfg, field) One setting as text: &quot;dhcp&quot; (&quot;-1&quot; when the address comes from the network automatically, &quot;0&quot; when it is fixed), &quot;address&quot;, &quot;netmask&quot;, &quot;gateway&quot;, &quot;dns1&quot;, &quot;dns2&quot;, &quot;hostname&quot;, &quot;vector&quot; (the packet driver's interrupt, 0 = find it).
NetConfigSet(cfg, field, value) Change one setting (same names; &quot;dhcp&quot; and &quot;vector&quot; take numbers). True when the field exists.
NetConfigProblem$(cfg) &quot;&quot; when the settings can be used, else why not in plain words.
NetConfigChanged(cfg) True when the settings differ from what NetConfigLoad read.
NetConfigStore(cfg, prefs) Put the settings into prefs (then save it with PrefsSave). True when done.
NetConfigFree cfg Free the settings handle.
NetVectorCount() / NetVector(index) The packet driver interrupts to choose from: index 0 is 0 (find it), then each one the settings accept.
NetRestart() Stop the network and start it with the saved settings. True when it is running.
NetStop Stop the network (every program's connections are closed) until NetRestart.
NetState() The network's state as a number: NET_STATE_STOPPED, NET_STATE_NO_DRIVER (no network card driver found), NET_STATE_CONFIGURING (waiting for an address from the network), or NET_STATE_UP.
NetStatus$(field) The network's state as text: &quot;message&quot; (in plain words), &quot;up&quot; and &quot;link&quot; (&quot;-1&quot; / &quot;0&quot;), &quot;dhcp&quot;, &quot;address&quot;, &quot;netmask&quot;, &quot;gateway&quot;, &quot;dns1&quot;, &quot;dns2&quot;, &quot;hostname&quot;, &quot;driver&quot; (the network card's driver), &quot;mac&quot; (its hardware address), &quot;vector&quot;, &quot;sockets&quot;, &quot;rxpackets&quot;, &quot;rxbytes&quot;, &quot;rxdropped&quot;, &quot;txpackets&quot;, &quot;txbytes&quot;. &quot;&quot; for an unknown field.</pre>
<p>Settings handles a program leaves open are freed for it when it ends.</p>
<p>CommRecvEncrypted(handle, channel) tells whether the data the last CommRecv$ on that channel returned can be trusted. It returns True when every byte of it arrived encrypted and authenticated, and also when that CommRecv$ returned nothing or CommRecv$ has not been called on the channel yet. It returns False when any byte arrived unencrypted, which can only happen before CommHandshake or on a channel opened with CommSetPlain, and for an invalid handle or a channel outside 0-127.</p>
<pre><code>Dim msg As String
msg = CommRecv$(link, 1)
If msg &lt;&gt; &quot;&quot; And Not CommRecvEncrypted(link, 1) Then
Print &quot;Unencrypted: &quot; &amp; msg
End If</code></pre>
<h2>Connections and Terminals</h2>
<p>With conn.bas in the project, a program talks to another computer the way the Terminal program does, whatever is in between: a serial port, a modem (it sends its setup command, dials, dials again when the line is busy, and notices when the carrier is lost), the secure link to the DVX host proxy (encrypted, and authenticated with a passphrase), or Telnet over the network. ConnCreate makes a connection (a number); ConnSetSerial, ConnSetModem, ConnSetHost, and ConnSetPassphrase set it up, and ConnOpen(conn, type) starts it. Opening only starts: dialing and the key exchange go on while the program runs, so call ConnPoll often from a Timer. ConnState says where it is (CONN_CLOSED, CONN_OPENING, CONN_OPEN) and ConnStatus$ what is happening or why it ended; ConnStatusSerial changes whenever ConnStatus$ does.</p>
<p>ConnAttach conn, &quot;Term1&quot; puts what arrives on the Terminal control Term1 (ConnPoll moves it there) and sends what is typed in it. ConnPoll then also appends what arrives to a capture file (ConnCapture), answers the other side's ENQ with an answerback (ConnSetAnswerback), and notices a ZMODEM sender starting a download: ConnZmodemRequest is True once, and the program answers with ConnReceiveFiles in the same Timer event. ConnSetEcho shows what is typed on the Terminal too. Without a Terminal, read with ConnRead$ and send with ConnWrite (any bytes, CHR$(0) too). ConnOpen returns CONN_OK or a CONN_ERR_ code; ConnErrorText$ puts the code in words. ConnSetXferWindow conn, bytes limits how much a ZMODEM sender may send before it waits for an answer (0 = no limit, up to XFER_WINDOW_MAX; -1, the default, picks by the line). ConnSendBreak holds a serial line in the break state for a moment; ConnClose hangs up and ConnFree forgets the connection.</p>
<pre><code>Dim Shared conn As Long
Dim Shared download As Long
Sub Form1_Load ()
conn = ConnCreate()
ConnSetSerial conn, 2, 115200, 8, &quot;N&quot;, 1, CONN_FLOW_RTSCTS
ConnAttach conn, &quot;Term1&quot;
ConnOpen conn, CONN_SERIAL
End Sub
Sub Timer1_Timer ()
ConnPoll conn
If ConnZmodemRequest(conn) Then download = ConnReceiveFiles(conn, XFER_ZMODEM, &quot;DOWNLOAD&quot;, XFER_EXIST_RENAME, False)
End Sub</code></pre>
<h2>File Transfers</h2>
<p>With xfer.bas in the project, a program sends and receives files with XMODEM, XMODEM-1K, YMODEM, or ZMODEM. A transfer is a number: XferSendFile and XferReceive start one on a serial port opened with SerOpen (comm.bas), and ConnSendFiles and ConnReceiveFiles start one on a connection (conn.bas). XferSendFiles and XferReceiveFiles (a serial port) and the Conn ones take the options Terminal has: a batch of files (one path per line), escaping every control character, asking the receiver to continue interrupted files, and what to do with a file that is already there. On a serial port XferPoll moves the transfer along; on a connection ConnPoll does. XferStatus tells where it is (XFER_RUNNING until it ends with XFER_DONE, XFER_FAILED, or XFER_CANCELLED), and XferBytes, XferSize, XferFile$, XferFileIndex, XferFileCount, XferBatchBytes, XferBatchSize, XferResumedAt, and XferErrors show its progress; XferMessage$ says how it ended. A receive with XFER_EXIST_ASK stops in XFER_ASKING when a file already exists: XferAskSize, XferAskRemoteSize (the size the sender offers, -1 when it did not say), and XferCanResume describe it, and XferAnswer continues with an XFER_EXIST_ choice. XferCancel stops a transfer and XferClose frees it.</p>
<p>XferCrc16(bytes) and XferCrc32(bytes) give the check values the protocols use (CRC-16 as XMODEM computes it, 0 to 65535; the CRC-32 of ZMODEM and ZIP files as a Long, negative when its top bit is set) for any bytes. XferSafeName$(name, folder) gives the name a receive into folder stores a sender's file name as: no folder or device name; a long name, its case kept, where folder's disk takes long names (a character a name cannot hold becomes _), else an 8.3 name of characters every disk accepts.</p>
<h2>Lists You Draw Yourself</h2>
<p>With listhelp.bas in the project, a list or icon view a program draws itself -- in a UserControl or a PictureBox -- follows the same rules as ListBox and ListView. ListSelCreate(multi, count) makes a selection for count items (several at a time when multi is True) and returns a handle; it remembers which items are selected and which one is current (the one the keyboard moves). Items are numbered from 0. Give it the clicks and keys, and ask it what to draw:</p>
<pre> Function Description
-------- -----------
ListSelClick sel, index, shift A click on an item, with the MouseDown event's Shift: alone it selects only that item, with Ctrl it turns the item on or off, with Shift it selects the items from the last click up to it.
ListSelKey(sel, keyCode, shift) Ctrl+A selects every item (returns LISTSEL_KEY_ALL), Space turns the current item on or off (LISTSEL_KEY_TOGGLE); LISTSEL_KEY_NONE for other keys.
ListSelNavigate(sel, keyCode, shift, columns, pageRows) The arrow keys, Home, End, PgUp, and PgDn, in a list (columns 1) or a grid with columns items per row, pageRows rows a page; with Shift they select from the last click. The new current item, or -1 when nothing moved.
ListSelMove sel, index, shift Make an item current as the keyboard does (after type-ahead).
ListSelCursor(sel), ListSelSetCursor sel, index The current item (-1: none); make one item current and the only one selected.
ListSelIsSelected(sel, index), ListSelSelectedCount(sel) Whether an item is selected; how many are.
ListSelSetItem sel, index, selected; ListSelSetAll sel, selected Select or clear one item, or all.
ListSelInsert sel, index; ListSelRemove sel, index An item was added or removed: the others keep their selection.
ListSelReorder sel, fromIndex, dest An item was dragged to dest: its selection goes with it.
ListReorderDest(fromIndex, toSlot, count) Where an item dragged from fromIndex lands when dropped in front of slot toSlot (count: after the last item); -1 when the drop changes nothing.
ListSelReset sel, count; ListSelCount(sel); ListSelFree sel The list now holds count new items; how many it holds; free the handle.
ListNavigateIndex(keyCode, current, count, pageSize), ListGridNavigate(keyCode, current, count, columns, pageRows) The same keys without a selection handle.
ListTypeAhead(ch, items, current) The next item after current whose text starts with the letter ch, any case (going round to the first); items holds the texts separated by CHR$(10). -1 when none does.
ListTypeAheadMatch(ch, text) True when text starts with the letter ch.</pre>
<pre><code>Sub UserControl_KeyDown (KeyCode As Integer, Shift As Integer)
If ListSelKey(sel, KeyCode, Shift) &lt;&gt; LISTSEL_KEY_NONE Then UserControl.Refresh
If ListSelNavigate(sel, KeyCode, Shift, columns, rowsShown) &gt;= 0 Then UserControl.Refresh
End Sub
Sub UserControl_KeyPress (KeyAscii As Integer)
Dim i As Long
i = ListTypeAhead(Chr$(KeyAscii), itemTexts, ListSelCursor(sel))
If i &gt;= 0 Then
ListSelMove sel, i, 0
UserControl.Refresh
End If
End Sub</code></pre>
<p>Selections a program leaves open are freed when it ends.</p>
<p>An icon view drawn with listhelp.bas looks and behaves like Program Manager's: the same cells for large icons, small icons, and the list, the same frame and scroll bar, a large icon's name on two lines, and the same rules for the keys, dragging and dropping. The grid functions take the view mode (LISTICON_VIEW_LARGE, LISTICON_VIEW_SMALL, or LISTICON_VIEW_LIST), the size of a character (TextWidth(&quot;W&quot;) and TextHeight(&quot;W&quot;)), the size of the whole view, how many items it shows, and rowsTaken: LISTICON_BY_ORDER when the items fill the grid in order, else how many rows items placed in cells of their own take. Draw the view's frame with DrawBevel (LISTICON_FRAME wide; with the face -1 after the items, so a row cut off at the bottom stops at the frame) and its scroll bar with DrawScrollBar as a control's bar (its control argument True); the grid leaves room for it.</p>
<pre> Function Description
-------- -----------
ListIconMetric(mode, metric, cw, ch, w, h, count, rowsTaken) One value of the grid: a cell's size (LISTICON_CELL_W, LISTICON_CELL_H), where its picture goes and how big it is (LISTICON_PICTURE_X, LISTICON_PICTURE_Y, LISTICON_PICTURE_SIZE), where its name goes and how many characters it shows (LISTICON_TEXT_X, LISTICON_TEXT_Y, LISTICON_NAME_CHARS; a large icon's two lines are each centred in the cell), the list's detail column (LISTICON_DETAIL_X, 0 in the other views); the inside of the frame less the scroll bar (LISTICON_INNER_X, LISTICON_INNER_Y, LISTICON_INNER_W, LISTICON_INNER_H), the columns, the rows shown whole and in all (LISTICON_COLUMNS, LISTICON_ROWS_SHOWN, LISTICON_ROWS), the largest top row (LISTICON_TOP_ROW_MAX), True when the scroll bar is needed (LISTICON_SCROLLBAR), where the text of an empty view goes (LISTICON_EMPTY_X, LISTICON_EMPTY_Y), the frame's width (LISTICON_FRAME), and the rows a wheel notch scrolls (LISTICON_WHEEL_ROWS).
ListIconCellAt(mode, cw, ch, w, h, count, rowsTaken, topRow, x, y) The cell under x, y with the view scrolled to topRow, numbered row * columns + column; -1 outside the grid.
ListIconLabel$(name, maxChars, lineNo) Line 1 or 2 of a large icon's name, maxChars characters a line (LISTICON_NAME_CHARS): the first line ends at the last blank that fits, else it is cut; the second is the rest, cut. &quot;&quot; for a line the name does not need.
ListIconNavigate(keyCode, current, cells, columns, pageRows) The item the arrow keys, Home, End, PgUp, or PgDn move to when the items stand in cells of their own, gaps allowed: cells holds each item's column and row, all separated by commas (&quot;0,0,2,0,1,1&quot;). -1 for another key or when no item is that way.
ListIconScrollPress(mode, cw, ch, w, h, count, rowsTaken, topRow, x, y) A left press on the scroll bar: the top row after it (an arrow moves a row, the trough a page, the thumb nothing); -1 when x, y is not on the scroll bar.
ListIconScrollGrab(mode, cw, ch, w, h, count, rowsTaken, topRow, x, y) How far below the top of the thumb a press is; -1 when it is not on the thumb.
ListIconScrollDrag(mode, cw, ch, w, h, count, rowsTaken, grab, y) The top row with the thumb, held grab pixels below its top, dragged to y. While the button is down the control gets the mouse even outside it.
ListIconDragStarted(dx, dy) True when a press has moved far enough to start a drag.
ListIconDragScroll(mode, cw, ch, w, h, count, rowsTaken, topRow, y) While an item is dragged: the top row after the view scrolls a row because the mouse is above or below the grid.
ListIconDropCell(mode, cw, ch, w, h, count, rowsTaken, topRow, x, y) The cell a dragged item would be dropped on (above or below the grid: the nearest row); -1 for none.
ListIconDropDest(fromIndex, cell, count) Items in order: the place an item dragged from fromIndex takes when dropped on a cell -- that cell's, the last place for a cell past the end; -1 when the drop changes nothing.</pre>
<pre><code>Sub UserControl_Paint ()
Dim cw As Long, ch As Long
cw = UserControl.TextWidth(&quot;W&quot;)
ch = UserControl.TextHeight(&quot;W&quot;)
UserControl.DrawBevel 0, 0, UserControl.Width, UserControl.Height, True, vbWhite, ListIconMetric(LISTICON_VIEW_LARGE, LISTICON_FRAME, cw, ch, UserControl.Width, UserControl.Height, itemCount, LISTICON_BY_ORDER)
' ... each item in its cell, its name in two lines:
UserControl.Print ListIconLabel$(itemName, ListIconMetric(LISTICON_VIEW_LARGE, LISTICON_NAME_CHARS, cw, ch, UserControl.Width, UserControl.Height, itemCount, LISTICON_BY_ORDER), 1);
End Sub</code></pre>
<h2>Security</h2>
<p>With security.bas in the project, a program has the building blocks of DVX's encrypted serial link for its own protocols and files. All of them take and give strings that may hold any bytes, CHR$(0) too.</p>
<pre> Function Description
-------- -----------
SecRandom$(count) count random bytes, good for keys and salts (RND is not). SecAddEntropy bytes stirs something unpredictable (key timings, mouse positions) into the generator.
SecX25519PublicKey$(secretKey) The public key to send the other side, for a secret key of SEC_X25519_KEY_SIZE random bytes (SecRandom$).
SecX25519$(secretKey, otherPublicKey) The secret both sides now share, which nobody listening can work out (&quot;&quot; for a key the other side should not have sent). About a sixth of a second on a slow computer. Make keys from it with SecHkdf$.
SecX25519Start(secretKey, otherPublicKey) The same without the wait: SecX25519Step(h) then does a ninth of the work a call, returning SEC_X25519_PENDING until it is done (SEC_OK); SecX25519End$(h) gives the secret (with otherPublicKey &quot;&quot;, the public key) and frees the handle.
SecAeadLock$(key, nonce, extra, bytes) bytes sealed: encrypted with a SEC_AEAD_KEY_SIZE-byte key and a SEC_AEAD_NONCE_SIZE-byte nonce, followed by a tag that proves them, and extra (sent in the clear), unchanged. Use a new nonce for every message: SecRandom$(SEC_AEAD_NONCE_SIZE) is safe.
SecAeadUnlock$(key, nonce, extra, sealed) What SecAeadLock$ sealed, or &quot;&quot; when anything was changed (or the key, nonce, or extra differs).
SecEd25519KeyPair$(seed) A signing key made from SecRandom$(SEC_ED25519_SEED_SIZE); keep it private. SecEd25519PublicKey$(key) is the key to give out.
SecEd25519Sign$(key, bytes) The signature of bytes; SecEd25519Check(signature, publicKey, bytes) is True only for exactly those bytes signed with that key.
SecDhCreate() The older key exchange (Diffie-Hellman), with fresh keys (a few seconds on a slow computer); a handle, or 0.
SecDhCreateStart() The same without the wait: SecDhStep(dh) then computes the keys a slice at a time, returning SEC_DH_PENDING until they are ready (SEC_OK).
SecDhPublicKey$(dh) This side's public key (SEC_DH_KEY_SIZE bytes), to send to the other side.
SecDhComputeSecret(dh, otherPublicKey) Combine with the other side's public key: SEC_OK, or SEC_ERR_PARAM for a key that is not acceptable.
SecDhComputeStart(dh, otherPublicKey) The same a slice at a time: SEC_DH_PENDING (or SEC_ERR_PARAM at once), then SecDhStep as above.
SecDhSecret$(dh) The secret both sides now share, which nobody listening can work out. Make keys from it with SecHkdf$; never use it as a key itself. SecDhFree dh frees the handle.
SecCipherCreate(key) The older cipher (XTEA), with a SEC_XTEA_KEY_SIZE-byte key; 0 for a key of another length. It does not show tampering: add SecHmac$, or seal instead.
SecCipherCrypt$(cipher, bytes) Encrypt -- or decrypt, the same call -- bytes. SecCipherSetCounter cipher, n sets the position in the key stream; the same key and position must never encrypt two different messages. SecCipherFree cipher frees it.
SecSha256$(bytes) The SHA-256 hash (SEC_SHA256_SIZE bytes). For data in pieces: SecSha256Open, SecSha256Add h, piece, then SecSha256End$(h), which also frees the handle.
SecHmac$(key, bytes) The HMAC-SHA256 signature of bytes with key; SecHmacOpen(key), SecHmacAdd, and SecHmacEnd$ for pieces.
SecHkdf$(salt, secret, info, length) length bytes (up to SEC_HKDF_MAX_OUT) of keys made from secret; a different info gives different keys.
SecEqual(a, b) True when a and b hold the same bytes, compared in the same time wherever they differ (for signature checks).</pre>
<pre><code>' Both sides: make keys, swap public keys (here over a TCP connection), agree a sealing key
Dim mine As String, theirs As String, key As String, nonce As String
mine = SecRandom$(SEC_X25519_KEY_SIZE)
TcpSend conn, SecX25519PublicKey$(mine)
' ... receive the other side's public key into theirs ...
key = SecHkdf$(&quot;&quot;, SecX25519$(mine, theirs), &quot;chat&quot;, SEC_AEAD_KEY_SIZE)
' Send a message: the nonce, then the sealed bytes
nonce = SecRandom$(SEC_AEAD_NONCE_SIZE)
TcpSend conn, nonce &amp; SecAeadLock$(key, nonce, &quot;&quot;, &quot;Hello&quot;)</code></pre>
<p>Handles a program leaves open are freed, and their keys wiped, when it ends.</p>
<h2>Settings Files</h2>
<p>With prefs.bas in the project, a program keeps its settings in an INI file the way DVX's own programs do. PrefsLoad(path) reads the file once (a file that is not there reads as empty); PrefsGet$, PrefsGetInt, and PrefsGetBool read a key of a section (each with the value to use when it is missing), and PrefsSet, PrefsSetInt, PrefsSetBool, and PrefsRemove change it in memory. PrefsSave writes it back, keeping comments and every line it did not change. To write a whole new file -- dropping sections that are no longer wanted -- fill a PrefsCreate handle and save it with PrefsSaveAs: the old file is replaced only once the new one is completely written. PrefsClose frees a handle. IniRead and IniWrite (built in) do one value at a time and read or write the whole file each time; prefs.bas is the faster choice for many settings.</p>
<p>A password is better kept with PrefsSetSecret handle, section, key, value and read back with PrefsGetSecret$(handle, section, key) (&quot;&quot; when it is missing). The file then holds a &quot;*&quot; and a row of letters and digits that change each time it is saved, not the password itself, so it cannot be read over someone's shoulder. This scrambles the password; it does not lock it away: anyone who knows how DVX scrambles it can unscramble it, so treat the file with the same care as the password. A value typed into the file by hand, without the &quot;*&quot;, is read as it is.</p>
<pre><code>Dim ini As Long
ini = PrefsLoad(App.User &amp; &quot;\MYAPP.INI&quot;)
userName = PrefsGet$(ini, &quot;User&quot;, &quot;Name&quot;, &quot;Unknown&quot;)
PrefsSetInt ini, &quot;Window&quot;, &quot;Left&quot;, Me.Left
If Not PrefsSave(ini) Then MsgBox &quot;The settings could not be saved.&quot;
PrefsClose ini</code></pre>
<p>PrefsDvxIni$() is the path of DVX's own settings file, DVX.INI, which Control Panel changes; other libraries (system.bas, joystick.bas, net.bas, print.bas, and sound.bas) read and store their part of it through a prefs.bas handle. PrefsSetVideoMode handle, wide, high, bpp stores the screen mode DVX starts in, and PrefsVideoWidth(handle), PrefsVideoHeight(handle), and PrefsVideoBpp(handle) read it (DVX's own start-up mode, SYS_VIDEO_DEFAULT_* in system.bas, for a value that is not there). PrefsKeyName$(handle, section, index) is the name of key number index of a section (from 0, in the order of the file; &quot;&quot; past the last key), to go through every key of a section.</p>
<p>Some settings are stored by name, from a fixed list of choices: the mouse acceleration (PREFS_CHOICE_ACCEL), the wallpaper mode (PREFS_CHOICE_WALLPAPER), and the scroll wheel direction (PREFS_CHOICE_WHEEL). For each list, PrefsChoiceCount(table) says how many choices it has (numbered from 0), PrefsChoiceLabel$(table, i) is the text to show, PrefsChoiceName$(table, i) the name stored in the file, and PrefsChoiceValue(table, i) the value it stands for (what SysSetMouse takes). PrefsChoiceIndex(table, choiceName) and PrefsChoiceIndexOfValue(table, value) find a choice (-1 when there is none), and PrefsGetChoice(handle, section, key, table) reads one from a file, giving DVX's default choice when the key is missing or unknown. PrefsChoiceDefault(table) is that default choice, what a Defaults button selects. For a list of your own, PrefsGetChoiceFrom(handle, section, key, choiceNames, defaultName) does the same with the names separated by &quot;|&quot; (&quot;large|small|list&quot; stores choice 1 as &quot;small&quot;), giving defaultName's choice for a missing or unknown key.</p>
<pre><code>For i = 0 To PrefsChoiceCount(PREFS_CHOICE_ACCEL) - 1
cboAccel.AddItem PrefsChoiceLabel$(PREFS_CHOICE_ACCEL, i)
Next i
cboAccel.ListIndex = PrefsChoiceIndexOfValue(PREFS_CHOICE_ACCEL, SysMouseAccel())</code></pre>
<h2>Help Files</h2>
<p>With help.bas in the project, HelpCompile(source, output) compiles a help source file (.dhs) into a help file (.hlp), True when it worked; its .image pictures are looked for in the source's folder. HelpCompileMessages$() gives the compiler's errors and warnings, one per line, each with the file and line (&quot;error: NOTES.DHS:1: directive .h1 outside of a topic&quot;). While a big file compiles, the rest of DVX and the program's own events go on, as with DoEvents: one compile runs at a time, so a second HelpCompile meanwhile returns False at once, and the compile stops if the program ends. HelpView file opens a help file in the DVX Help Viewer (a file named without a folder is looked for beside the program; &quot;&quot; opens the DVX user guide). HelpViewTopic file, topicId opens it at a topic, the way F1 does. A Help Viewer that is already open shows the file in its window instead of a second copy starting.</p>
<p>With hlpfile.bas, a program reads help files itself -- everything a help viewer needs. HlpOpen(path) opens a help file and returns a handle (0 when it is not one); HlpClose closes it (a program's open files are closed when it ends). Topics are numbered from 0: HlpTopicCount, HlpTopicTitle$ and HlpTopicId$ (the name links and HelpTopic use), HlpFindTopic(handle, topicId) (-1 when there is none), and HlpStartTopic(handle, topicId), the topic to show first (topicId when the file has it, else the file's own start page). HlpTocCount, HlpTocTitle$, HlpTocDepth, HlpTocTopic, and HlpTocExpanded give the table of contents in order -- a depth of 0 is the top level, a topic of -1 a heading that only groups others -- ready to fill a TreeView. HlpIndexCount, HlpIndexKeyword$, and HlpIndexTopic give the keyword index (sorted), for a list or DlgChoice. HlpSearch(handle, words) searches the titles, text, and keywords as the Help Viewer does and returns how many topics have every word; HlpSearchTopic(handle, n) gives them.</p>
<p>To show a topic, put a HelpPane control on the form and call HelpPane1.ShowTopic handle, topic: headings, paragraphs, lists, notes, code, tables, pictures, and links look as they do in the Help Viewer, and the text wraps to the control's width. A click on a link, or Enter on one reached with Tab, fires the HelpPane's LinkClick event with the ID of the topic the link names; the program decides what to do, usually show that topic and remember it for a Back button. A program that draws topics itself reads them with HlpLoadTopic(handle, topic) and HlpRecordType, HlpRecordFlags, HlpRecordText$, and HlpRecordLink$ (the HLP_REC_ constants), saves a picture for LOADPICTURE with HlpRecordImageSave, and wraps text with HlpWrap$.</p>
<pre><code>Dim hlp As Long
Dim history(63) As Long, histPos As Long
Sub Form1_Load ()
hlp = HlpOpen(App.Path + &quot;\MYAPP.HLP&quot;)
For i = 0 To HlpTocCount(hlp) - 1
If HlpTocDepth(hlp, i) = 0 Then
Toc.AddItem HlpTocTitle$(hlp, i)
Else
Toc.AddChildItem lastTop, HlpTocTitle$(hlp, i)
End If
If HlpTocDepth(hlp, i) = 0 Then lastTop = Toc.ItemCount() - 1
Toc.SetItemTag Toc.ItemCount() - 1, Str$(HlpTocTopic(hlp, i))
Next i
GoTopic HlpStartTopic(hlp, &quot;&quot;)
End Sub
Sub GoTopic (ByVal topic As Long)
histPos = histPos + 1
history(histPos) = topic
HelpPane1.ShowTopic hlp, topic
Me.Caption = HlpTopicTitle$(hlp, topic) + &quot; - My Help&quot;
End Sub
Sub HelpPane1_LinkClick (Topic As String)
GoTopic HlpFindTopic(hlp, Topic)
End Sub
Sub Toc_Change ()
If Val(Toc.GetItemTag(Toc.ListIndex)) &gt;= 0 Then GoTopic Val(Toc.GetItemTag(Toc.ListIndex))
End Sub</code></pre>
<p>A help viewer written in BASIC can also take the place of DVX's own: installed as APPS\KPUNCH\DVXHELP\DVXHELP.APP with a NewArgs event procedure, it is handed &quot;helpfile topic&quot; when F1 is pressed while it is open (see New Arguments in the Form topic).</p>
<h2>Sizes in Characters</h2>
<p>Control sizes (Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight) are pixels. With layout.bas in the project, SizeChars(n) is a size of n characters of the system font and SizePercent(n) one of n percent of the container (0 to 100); give them to a size property and the layout works out the pixels each time it arranges the form, so a box for an address keeps its width whatever the font. Reading the property back gives the pixels it stands for at that moment.</p>
<pre><code>txtAddress.MinWidth = SizeChars(16)
lstFiles.MaxHeight = SizePercent(50)</code></pre>
<h2>Compiling and Debugging Programs</h2>
<p>With compiler.bas in the project, a program compiles BASIC programs -- what a development tool written in BASIC needs. A source set holds the files of one program: CompSourceFromProject(src, dbpPath) reads a whole project (.dbp) from disk, or CompSourceAdd(src, path, text, kind) adds files one at a time, in the order a project compiles: modules, then class modules, then UserControls, then forms (COMP_KIND_AUTO tells them apart by the file name; a form's whole .frm text is added, and the code after its layout is compiled; a UserControl's whole .ctl text, its header and its code). CompCompile(src, optionExplicit, validate) gives a compiled module, or 0 with CompError$() saying what is wrong and CompErrorFile$() / CompErrorFileLine() where. With validate True, Label1.Captoin and other misspelled control members, and controls of an unknown type, are found while compiling instead of when the line runs (the set's own UserControls are known types).</p>
<p>Line numbers of compiled programs (errors, breakpoints, the line a program is paused on) count through all the files of the source set. CompMapFile$(src, line) and CompMapLine(src, line) give the file and the line in it; CompConcatLine(src, path, fileLine) goes the other way. CompSourceFiles$ lists the files in compile order. CompBuildApp(module, src, outPath, release) builds an .app the way the IDE's Make Executable does, with the project's name, icon, and help file, its forms, and its UserControls. For a control project (its Type setting is &quot;Control&quot;) it builds a control file instead (outPath NAME.wgt), the way the IDE's Make Control does: the project's UserControls with their toolbox pictures and names, there for every program once the file is copied into DVX's WIDGETS folder (DVX loads it when it starts). CompProcList$(text) lists the SUB and FUNCTION blocks of source text with their first and last lines (also for code that does not compile yet), CompIsIdent checks a name and CompKeyword$ lists the language's keywords, CompKeywordClass the kind of each (COMP_KW_OTHER, COMP_KW_TYPE, or COMP_KW_LITERAL), and CompKeywordReserved whether a program may also use it as a name of its own.</p>
<p>Project files: ProjOpen(dbpPath) opens a project file (.dbp) and ProjNew(name, folder) starts a new one; ProjSave writes it and ProjClose frees it. ProjFileCount, ProjFile$ (the name as the project lists it), ProjFilePath$ (the full path), ProjFileKind (COMP_KIND_MODULE, COMP_KIND_FORM, COMP_KIND_CLASS, or COMP_KIND_CONTROL), and ProjFileFind list its files; ProjAddFile, ProjRemoveFile, and ProjRenameFile (on disk and in the project together, saved at once) change the list. ProjGet$ and ProjSet read and set its settings by their names in the file: Name, Type (&quot;Control&quot; for a control project, empty for a program), Author, Publisher, Version, Copyright, Description, Icon, HelpFile, CommandArgs, StartupForm, OptionExplicit, and MultiInstance (the last two &quot;true&quot; or &quot;false&quot;). This is the project model the DVX BASIC IDE uses.</p>
<p>A UserControl's header (the Begin UserControl block at the top of its .ctl file) is read and changed the way the IDE's Properties window does it, the rest of the text left as it is: ProjCtlKeys$() lists the keys in the window's order with the kind of value each takes (Name, Width, Height, CanGetFocus, BackColor, ToolboxIcon, Description, DefaultEvent; the kinds Name, Integer, Boolean, Color, and Text), ProjCtlHeader$(text, key) reads one (its default when the header leaves it out), ProjCtlSetHeader$(text, key, value) gives the text with one set (an empty value removes it; Name renames the control), and ProjCtlNew$(name) the text of a new UserControl, as File &gt; New UserControl makes it.</p>
<p>With debug.bas too, a program runs a compiled module as a child program inside itself: RunCreate(module, src, appDir, args) prepares it, RunStart(run, startupForm, breakOnStart) loads its forms, and RunPoll(run, ms), called from a Timer, runs it for at most ms milliseconds at a time and returns what it is doing: RUN_RUNNING, RUN_EVENTS (waiting for events on its forms), RUN_PAUSED, RUN_ENDED, or RUN_ERROR (RunError$ and RunErrorLine tell why and where). RunOutput$ collects what it PRINTs; INPUT asks with an input box. RunStop ends it and RunFree forgets it.</p>
<p>DbgSetBreakpoints run, &quot;12, 40&quot; sets breakpoints (line numbers of the source set). While the program is paused, DbgLine and DbgProc$ say where, DbgLocals$ and DbgCallStack$ give the variables and the calls as rows for a ListView's SetRows, DbgEval$(run, expr) shows a variable or expression as the IDE's Watch window does, DbgExec$(run, line) runs an Immediate-window line (x = 5 changes a variable, anything else is printed), and DbgSetVar changes a variable; DbgStepInto, DbgStepOver, DbgStepOut, DbgRunToLine, and DbgContinue go on, DbgPause stops it at the next line. The program's form captions show [break] while it is paused.</p>
<p>A program paused in its module-level code waits until you step or continue it. One paused inside one of its event handlers -- or in its forms' Load code, which runs inside RunStart -- waits right there while your Timer and menus keep working; RunPoll called meanwhile returns at once, and RunStart returns only after such a pause.</p>
<pre><code>' compiler.bas and debug.bas in the project; tmrRun is a Timer
Dim Shared src As Long, mdl As Long, kid As Long
Sub StartDebugging
src = CompSourceCreate()
If Not CompSourceFromProject(src, &quot;C:\PROJ\HELLO.DBP&quot;) Then MsgBox CompError$(): Exit Sub
mdl = CompCompile(src, True, True)
If mdl = 0 Then MsgBox CompErrorFile$() &amp; &quot; line&quot; &amp; Str$(CompErrorFileLine()) &amp; &quot;: &quot; &amp; CompError$(): Exit Sub
kid = RunCreate(mdl, src, &quot;&quot;, &quot;&quot;)
DbgSetBreakpoints kid, Str$(CompConcatLine(src, &quot;C:\PROJ\MAIN.BAS&quot;, 12))
If RunStart(kid, &quot;&quot;, False) Then tmrRun.Enabled = True
End Sub
Sub tmrRun_Timer
Select Case RunPoll(kid, 40)
Case RUN_PAUSED
lstLocals.SetRows DbgLocals$(kid)
lblWhere.Caption = CompMapFile$(src, DbgLine(kid)) &amp; &quot;:&quot; &amp; Str$(CompMapLine(src, DbgLine(kid)))
Case RUN_ENDED, RUN_ERROR
tmrRun.Enabled = False
txtOutput.Text = txtOutput.Text &amp; RunOutput$(kid) &amp; RunError$(kid)
End Select
End Sub</code></pre>
<h2>Form Designers and Code Editors</h2>
<p>A form designer or a code editor written in BASIC uses the same pieces as the DVX BASIC IDE. designer.bas describes the control types, which CtlTypeName$(0 to CtlTypeCount - 1) gives in alphabetical order: the toolbox lists the types CtlTypeFlags marks CTL_FLAG_DESIGNABLE (with CtlTypeTooltip$ and the icon CtlTypeIconFile writes), new controls are named CtlTypeNamePrefix$ plus a number, and the properties window lists CtlPropName$ for 0 to CtlPropCount - 1 with CtlPropType (CTL_PROP_STRING ... CTL_PROP_ENUM, plus CTL_PROP_READONLY) and CtlPropEnum$ for an enumerated property's choices. &quot;Form&quot; and &quot;Menu&quot; stand for the form itself and a menu item. The event list is CtlEventList$, and CtlEventParams$ writes an event procedure's parameter list; CtlTypeEventParams$(typeName, eventName) does it for one type, whose events may have parameters of their own (a UserControl's events), and &quot;UserControl&quot; stands for the object in a UserControl's own code (UserControl_MouseDown has Button, Shift, X, and Y). For a project's files, FrmFormName$ and FrmControlNames$ read a .frm file's form and control names (the Object list), FrmCode$ its code, and ClsClassName$ a class module's name.</p>
<p>The form being designed is a real form: CreateControl and RemoveControl add and remove controls, CallByName reads and sets a property by its name, Me.Controls lists the controls, Container (Set ctl.Container = Frame1) and MoveBefore move them, and LoadFormText shows a .frm file. Its DesignMode (see the Form control) stops the controls from working and reports the mouse and keys in DesignMouse and DesignKey, with the selection handles drawn for DesignSelection.</p>
<p>A project's own UserControls go on the toolbox too, as in the IDE. Compile the project -- its forms may be left out -- and give the module and the source set to CompDesignControls(module, src, appDir) from compiler.bas: the UserControls are then control types of this program alone, listed by CtlTypeName$ with their Description as the tooltip and their ToolboxIcon as the icon, with their properties, methods, and events, and known to CreateControl and LoadFormText. On the forms they run their code -- not the project's module-level code -- with UserControl.UserMode False on a form in DesignMode; App.Path is appDir, or the project's folder for &quot;&quot;. When a control's code calls UserControl.PropertyChanged, the form raises DesignPropertyChanged (CtrlName, PropertyName), so the properties window can read them again. Call CompDesignControls again after a UserControl changed (the ones before are let go first) and CompDesignRelease when the project closes; the end of the program lets them go too. The module stays in use while they are there, even after CompModuleFree, and must be one this program compiled.</p>
<pre><code>' compiler.bas and designer.bas in the project; Canvas is the form
' being designed
Sub LoadProjectControls(dbpPath As String)
Dim src As Long
Dim mdl As Long
Dim made As Long
src = CompSourceCreate()
If CompSourceFromProject(src, dbpPath) Then mdl = CompCompile(src, True, False)
If mdl = 0 Then
MsgBox CompError$()
Else
made = CompDesignControls(mdl, src, &quot;&quot;)
If CompError$() &lt;&gt; &quot;&quot; Then MsgBox CompError$()
CompModuleFree mdl
End If
CompSourceFree src
End Sub
Sub Canvas_DesignPropertyChanged(CtrlName As String, PropertyName As String)
If CtrlName = Canvas.DesignSelection Then RefreshPropertyList
End Sub</code></pre>
<p>A .frm file can also be worked on as data, the way the DVX BASIC IDE does it, without showing it. FrmOpen(text$), FrmOpenFile(path$), or FrmNew(name$) gives a handle to a form model (0 when the text is not a form); FrmText$ writes it back as .frm text in the form the IDE saves and FrmSave writes it to a file; FrmFree frees it (a program's open handles are freed when it ends). FrmGet$ and FrmSet read and change the form's properties (Caption, Width, AutoSize, Layout, Icon, Tag ...; Name renames the form), FrmGetCode$ and FrmSetCode its code. The controls are numbered from 0 in file order, each one followed by the controls inside it: FrmCtlCount, FrmCtlFind, FrmCtlName$, FrmCtlType$, FrmCtlIndex (its control array index, -1 when it is not in an array), and FrmCtlParent (the container, -1 for the form) describe them; FrmCtlGet$ and FrmCtlSet read and set any property as text (Name renames the control and its whole control array, the controls inside it follow; Index makes it an array member; an OptionButton set to True clears the others in its container), FrmCtlRemoveProp takes a set one out, and FrmCtlPropCount / FrmCtlPropName$ list the ones that were set. FrmCtlAdd adds a control (its name &quot;&quot; gives the next free one, Command1, Label2 ...) as the last control of a container (-1: the form), FrmCtlRemove removes one with what is inside it, FrmCtlMove puts one before another of the same container, and FrmCtlReparent into another container. FrmCtlText$ gives a control with what is inside it as .frm text, what a designer puts on the Clipboard to copy it, and FrmCtlPaste puts such text into a container: a name that is already taken is replaced by a free one. The menu items are numbered from 0 in menu order with a Level (0 for a menu on the menu bar or a popup menu, 1 for its items, 2 and more for submenus): FrmMenuCount, FrmMenuGet$ / FrmMenuSet (Name, Caption, Shortcut, ShortcutText, Checked, RadioCheck, Enabled, Visible, Level), FrmMenuAdd, FrmMenuRemove (with the items under it), FrmMenuMove (past the previous or next item of its level), and FrmMenuIndent (one level in or out, with the items under it). Only what was set is written: a property a control has by default is left out of the file.</p>
<p>FormText$(formName$) writes a loaded form as it is now as .frm text -- one shown with LoadFormText, made with CreateForm and CreateControl, or one of the program's own: its properties, its controls in their containers with each property that differs from a new control of that type, and its menus (a form loaded this way has no code). A designer that keeps its form live saves it with FormText$, and FrmOpen(FormText$(...)) reads it as a model.</p>
<p>compiler.bas reads source text as the compiler does, for a code editor: CompTokens$(source) lists its tokens (line, column, length, kind, and text, the kind one of Keyword, Identifier, String, Number, Date, Symbol, Comment, and Error); CompInCode(source, position) tells whether a character is code rather than inside a string or a comment; CompRenameInCode$(source, oldName, newName, codeOnly) renames a form, control, or menu item where code refers to it (Command1.Caption, Command1_Click), leaving strings and comments alone with codeOnly; CompWithEvents$ lists the WithEvents variables a file declares and CompClassEvents$ the Events of a class module, for the Object and Event lists; CompHelpTopic$(word) and CompHelpCtrlTopic$(typeName) are the help topics F1 opens (HelpViewTopic on dvxbasic.hlp beside the IDE).</p>
<p>A code editor is a TextArea: SetSyntaxMode &quot;bas&quot; colours BASIC as the IDE does (SetSyntaxColor changes the colours), SetLineMarker marks breakpoints and the current line, GutterClick reports clicks on the line numbers, SelStart / SelLength / SelText and Cut, Copy, Paste, SelectAll, and Undo give the Edit menu, FindNext / ReplaceSelection / ReplaceAll find and replace, and LineCount / GetLine / CursorLine / CursorCol read the text (see TextArea).</p>
<pre><code>' designer.bas in the project: put a copy of the first control of a
' .frm file into a Frame of the same form and save it
Sub CopyIntoFrame(path As String)
Dim h As Long
Dim box As Long
h = FrmOpenFile(path)
If h = 0 Then Exit Sub
box = FrmCtlAdd(h, &quot;Frame&quot;, &quot;&quot;, -1)
If FrmCtlSet(h, box, &quot;Caption&quot;, &quot;Copies&quot;) And FrmCtlPaste(h, FrmCtlText$(h, 0), box) &gt;= 0 Then
If Not FrmSave(h, path) Then MsgBox &quot;Could not save &quot; &amp; path
End If
FrmFree h
End Sub</code></pre>
<pre><code>' designer.bas in the project: fill a properties list for a control
Sub ShowProperties(ctl As Object, typeName As String)
Dim i As Integer
Dim v As String
lstProps.Clear
For i = 0 To CtlPropCount(typeName) - 1
If (CtlPropType(typeName, i) And CTL_PROP_TYPEMASK) &lt;&gt; CTL_PROP_OBJECT Then
v = CallByName(ctl, CtlPropName$(typeName, i), vbGet)
lstProps.AddItem CtlPropName$(typeName, i) &amp; &quot; = &quot; &amp; v
End If
Next
End Sub</code></pre>
<p><a href="#lang.declarations">See also: DECLARE LIBRARY</a></p>
</div>
<div class="topic" id="ctrl.common.props">
<h1>Common Properties, Events, and Methods</h1>
<p>Every control in DVX BASIC inherits a set of common properties, events, and methods. These are handled by the form runtime before dispatching to widget-specific interface descriptors.</p>
<h2>Common Properties</h2>
<pre> Property Type R/W Description
---------- ------- --- -------------------------------------------
Name String R The control's name (e.g. &quot;Command1&quot;). Read-only at runtime.
Left Integer R/W X position in pixels relative to the parent container.
Top Integer R/W Y position in pixels relative to the parent container.
Width Integer R/W Current width in pixels. Setting this changes the minimum width constraint.
Height Integer R/W Current height in pixels. Setting this changes the minimum height constraint.
MinWidth Integer R/W Minimum width for layout. Setting it works like setting Width; reading it returns the minimum that was set.
MinHeight Integer R/W Minimum height for layout. Setting it works like setting Height; reading it returns the minimum that was set.
MaxWidth Integer R/W Maximum width cap (0 = no limit, stretch to fill). It wins over MinWidth and over the width the control's contents ask for.
MaxHeight Integer R/W Maximum height cap (0 = no limit, stretch to fill). It wins over MinHeight and over the height the control's contents ask for.
Weight Integer R/W Layout weight. 0 = fixed size, &gt;0 = share extra space proportionally.
Visible Boolean R/W Whether the control is visible.
Enabled Boolean R/W Whether the control accepts user input. Disabling a container (Frame, VBox, HBox...) also blocks mouse and keyboard input to every control inside it.
BackColor Long R/W Background color as a 24-bit RGB value packed in a Long (use the RGB function to construct).
ForeColor Long R/W Foreground (text) color as a 24-bit RGB value packed in a Long (use the RGB function to construct).
FontName String R/W The family of the font the control draws its text in, such as &quot;DejaVu Sans&quot; (&quot;System&quot; is DVX's own 8 x 16 font). A family DVX does not have gives the System font. See Fonts below.
FontSize Integer R/W The size of the font in pixels. A size the family does not come in becomes the nearest one it has.
FontBold Boolean R/W True for the bold style of the font.
FontItalic Boolean R/W True for the italic style of the font.
FontUnderline Boolean R/W True to underline the text.
FontStrikethru Boolean R/W True to draw a line through the text.
TabIndex Integer R Accepted for VB compatibility but ignored. DVX has no tab order.
ToolTipText String R/W Tooltip text shown after the mouse hovers over the control. Empty string or unset = no tooltip.
HelpTopic String R/W Help topic opened by F1 while the control has the focus. Empty = the form's HelpTopic. F1 uses the project's help file.
DragMode Integer R/W vbManual (0, the default): the program starts a drag with the Drag method. vbAutomatic (1): pressing the left mouse button on the control starts a drag. See Drag and Drop below.
DragIcon Picture R/W Picture shown under the mouse while the control is dragged: a picture file name (BMP, PNG, JPEG, or GIF) or a Picture object from LOADPICTURE or LOADPICTUREDATA (Set works too). Reading it gives a Picture object, which stands for the file name where a value is needed. Empty = a dotted outline the size of the control.
Parent Form R The form the control is on (Text1.Parent.Caption).
Tag String R/W Any text the program wants to keep with the control (DVX does nothing with it), as in Visual Basic. Also in the .frm file.
MousePointer Integer R/W The mouse pointer shown over the control (and the controls inside it that have none of their own): vbDefault (0, the control's own pointer), vbArrow (1), vbCrosshair (2), vbSizeNESW (6), vbSizeNS (7), vbSizeNWSE (8), vbSizeWE (9), vbHourglass (11), or vbNoDrop (12). A form's MousePointer is used where no control has one, and Screen.MousePointer over every form of the program. Change it in MouseMove to show different pointers over parts of a control. Also in the .frm file; another value is an error.
Container Object R/W The container control the control is in (a Frame, VBox, TabPage ...), or its form. Set Text1.Container = Frame1 moves the control into Frame1, after the controls there; Set Text1.Container = Me moves it onto the form itself. The new container must be a container control on the same form, not the control itself or one inside it.</pre>
<p>Size properties (Width, Height, and the Min/Max sizes) are limited to 0..32767.</p>
<h2>Fonts</h2>
<p>The six Font properties are one font. A control that has not been given one draws in the font of the control it is in (a Frame, for example), or else in its form's; the properties read the font the control draws with. Setting one of them gives the control a font of its own with that one part changed, keeping the others: Label1.FontBold = True makes the label's text bold in whatever family and size it had. Controls that edit text in columns (TextBox, TextArea, ComboBox, SpinButton, and Terminal) take only fixed-pitch families, such as &quot;DejaVu Sans Mono&quot;, and show the System font in place of any other. The fonts DVX has, and the sizes each comes in, are listed by font.bas; DlgFont in commdlg.bas lets the user choose one. In the form designer the Font row of the Properties window sets all six, and they are saved in the .frm file.</p>
<h2>Default Properties</h2>
<p>As in Visual Basic, a control's name used where a value is needed means its default property: Text1 = &quot;hi&quot; sets Text1.Text, Print Label1 prints Label1.Caption, and If Check1 Then reads Check1.Value. Where an object is expected -- SET, Is, an object parameter, Collection.Add, TypeOf -- the name still means the control itself.</p>
<pre> Control Default property
------- ----------------
TextBox, TextArea, ComboBox, DropDown, ListBox, DBGrid Text
Label, Frame, Data Caption
CheckBox, OptionButton, CommandButton Value
HScrollBar, SpinButton, ProgressBar Value
Image, ImageButton, PictureBox Picture
Timer Enabled</pre>
<p>Other controls, forms, and menu items have no default property: using one as a value raises error 13.</p>
<h2>Common Events</h2>
<p>These events are wired on every control, whether it is loaded from a .frm file or created at runtime with CreateControl (whose handlers SetEvent names).</p>
<pre> Event Parameters Description
--------- ------------------------------------------- -------------------------------------------
Click (none) Fires when the control is clicked.
DblClick (none) Fires when the control is double-clicked.
Change (none) Fires when the control's value or text changes.
GotFocus (none) Fires when the control receives keyboard focus.
LostFocus (none) Fires when the control loses keyboard focus.
KeyPress KeyAscii As Integer Fires when a printable key is pressed. KeyAscii is the ASCII code.
KeyDown KeyCode As Integer, Shift As Integer Fires when any key is pressed down, after the control has handled it. KeyCode is the key (vbKeyDelete, vbKeyReturn, ... or a character's code; Ctrl+A to Ctrl+Z are 1 to 26); Shift holds vbShiftMask, vbCtrlMask, and vbAltMask bits (see Key Code Constants in the language reference).
KeyUp KeyCode As Integer, Shift As Integer Fires when a key is released.
MouseDown Button As Integer, X As Integer, Y As Integer Fires when a mouse button is pressed over the control.
MouseUp Button As Integer, X As Integer, Y As Integer Fires when a mouse button is released over the control.
MouseMove Button As Integer, X As Integer, Y As Integer Fires when the mouse moves over the control.
Scroll Delta As Integer Fires when the control is scrolled (mouse wheel or scrollbar).
DragDrop Source As Control, X As Integer, Y As Integer Fires when a dragged control is dropped on this control. Source is the dragged control; X and Y are where, in this control.
DragOver Source As Control, X As Integer, Y As Integer, State As Integer Fires while a dragged control moves over this control. State is vbEnter (0) when it comes onto the control, vbOver (2) as it moves across, vbLeave (1) when it goes off.</pre>
<h2>Common Methods</h2>
<pre> Method Parameters Description
-------- ---------- -------------------------------------------
SetFocus (none) Gives keyboard focus to this control.
Refresh (none) Forces the control to repaint.
Drag [Action] Starts or ends dragging this control: vbBeginDrag (1, the default) starts, vbEndDrag (2) drops it where the mouse is, 0 cancels the drag without a drop.
MoveBefore [Control] Moves the control just before another control (into that control's container when it is in another one), or with none to the end of its own container. The layout places controls in this order, and Controls lists them in it.
ScrollToControl Control Of a ScrollPane: scrolls so that a control inside it (the control, or its name as a string) is in view, also one that cannot take the focus (a Label). On another control, or with a control that is not inside it, it is an error.</pre>
<h2>Drag and Drop</h2>
<p>Any control can be dragged onto another control or onto a form, as in Visual Basic. While a control is dragged, a dotted outline of it (or its DragIcon picture) follows the mouse, and the controls and forms it passes over get DragOver events. Releasing the mouse button drops it: the control or form under the mouse gets a DragDrop event, with the dragged control as Source. Pressing Esc cancels the drag.</p>
<p>The mouse pointer shows where a drop can land: over a control or form that has a DragDrop event procedure it is the usual arrow; over one without, and outside the program's forms, it is the &quot;no drop&quot; sign (a circle with a line through it). The outline or DragIcon picture still follows the mouse either way.</p>
<p>With DragMode set to vbAutomatic, pressing the left mouse button on the control starts the drag, and the control gets no Click, MouseDown, or MouseUp from the left button. With DragMode vbManual, start the drag yourself, usually in MouseDown. A drag started while the mouse button is up ends at the next click. During a drag no mouse events other than DragOver and DragDrop are raised.</p>
<p>Drop targets only react: nothing is moved or copied for you. Use Source in DragDrop to decide what to do, for example read its Name or Caption, or check what kind of control it is with TypeOf Source Is TextBox (see Operators).</p>
<p>Note that vbCancel is the MsgBox Cancel value (2), which as a Drag action means vbEndDrag; cancel a drag with Drag 0.</p>
<p>DragIcon takes a file name or a picture loaded with LOADPICTURE or LOADPICTUREDATA: Set Label1.DragIcon = LoadPicture(&quot;drag.bmp&quot;). A missing file or one that is not a picture raises its error at LOADPICTURE; a file name that cannot be read when the drag starts shows the outline instead.</p>
<pre><code>' Label1 has DragMode = 1 (vbAutomatic) in the form designer.
Sub List1_DragOver(Source As Control, X As Integer, Y As Integer, State As Integer)
If State = vbEnter Then Label2.Caption = &quot;Drop to add &quot; &amp; Source.Caption
End Sub
Sub List1_DragDrop(Source As Control, X As Integer, Y As Integer)
List1.AddItem Source.Caption
End Sub
' DragMode vbManual: the button starts its own drag, left button only.
Sub Command1_MouseDown(Button As Integer, X As Integer, Y As Integer)
If Button = 1 Then Command1.Drag vbBeginDrag
End Sub</code></pre>
<p><a href="#ctrl.form">Form</a></p>
<p><a href="#ctrl.databinding">Data Binding</a></p>
<p><a href="#ctrl.frm">FRM File Format</a></p>
</div>
<div class="topic" id="ctrl.drawing">
<h1>Drawing on Forms and PictureBoxes</h1>
<p>Forms and PictureBoxes have Visual Basic's drawing methods. They draw with the same code as the QBasic graphics statements (see Console and Graphics in the language reference), in pixels unless ScaleMode or Scale says otherwise, with colours as Visual Basic RGB values, &amp;HBBGGRR (RGB(255, 0, 0) or &amp;HFF is red). A PictureBox draws on its picture; a form gets a drawing area the size of its window the first time it draws, placed with its controls like a PictureBox (so draw on a form that has no controls, or use a PictureBox beside them).</p>
<p>Drawings stay until they are drawn over or cleared. In a form's own code, write Me.Line, Me.Circle, and so on: Line, Circle, and PSet without an object are the QBasic graphics statements (they draw on the program's screen), and Print without an object is the PRINT statement.</p>
<h2>Drawing Methods</h2>
<pre> Method Description
------ -----------
Cls Clears the drawing to BackColor; CurrentX and CurrentY go to 0.
PSet [Step](x, y) [, color] Draws a point (DrawWidth wide).
Line [[Step](x1, y1)]-[Step](x2, y2) [, color] [, B | BF] Draws a line, a box (B), or a filled box (BF). A box without F is filled with FillColor when FillStyle is 0.
Circle [Step](x, y), radius [, color [, start [, end [, aspect]]]] Draws a circle, ellipse, or arc, filled with FillColor when FillStyle is 0 (full circles).
DrawFocusRect x, y, width, height [, color] Draws the dotted rectangle DVX shows around the control that has the keyboard focus (every other pixel of its edge), for things a program draws itself, such as the focused link of a help topic. A negative width or height counts from the other edge.
Point(x, y) The colour of a pixel, -1 outside the picture. With fewer than 16 million colours on the screen it is the colour the screen shows: black, white, and full colours such as RGB(255, 0, 0) read back exactly, others may differ slightly.
Print items Writes text at CurrentX, CurrentY in ForeColor, in the object's font FontScale times as large, with PRINT's separators (; and ,), SPC, and TAB (counted in the font's character width); ends by moving to the next line unless the last item is followed by ; or ,.
PaintPicture picture, x, y [, width, height [, srcX, srcY, srcWidth, srcHeight [, opcode]]] Copies a picture, stretched to width x height: an image file (BMP, PNG, JPEG, or GIF), a picture from LOADPICTURE, or a PictureBox given by its name as a string or by a Control variable. opcode combines each pixel with the one already there (see Raster Operations).
Scale [(x1, y1)-(x2, y2)] Gives the drawing coordinates of its own: (x1, y1) is the top-left corner and (x2, y2) the bottom-right one (y2 below y1 makes y go up). Scale alone goes back to pixels.
ScaleX(width [, fromScale [, toScale]]) A width in fromScale converted to toScale (see Scales).
ScaleY(height [, fromScale [, toScale]]) A height in fromScale converted to toScale.
TextWidth(text) Width of the text in the object's font, in the scale's units, at the FontScale size.
TextHeight(text) Height of a line of text in the object's font, in the scale's units, at the FontScale size.</pre>
<h2>Drawing the DVX Look</h2>
<p>These methods draw the parts DVX's own controls are made of, in the colours of the current theme, for controls a program draws itself (a PictureBox that acts as a list or a toolbar). Coordinates and lengths are in the scale's units; colours are RGB values.</p>
<pre> Method Description
------ -----------
DrawBevel x, y, width, height [, sunken [, face [, border]]] A raised box like a window or button edge, or with sunken True a sunken one like a text box's. face is the fill colour (the theme's face colour when left out; -1 leaves the inside as it is, to frame what is already drawn); border is the edge width in pixels (2).
DrawButtonFace x, y, width, height [, pressed [, face]] A button face, up or with pressed True pushed down.
DrawArrow x, y, size, direction [, color] A solid triangle centred on x, y, size pixel rows tall, pointing dvxArrowUp (0), dvxArrowDown (1), dvxArrowLeft (2), or dvxArrowRight (3), in ForeColor unless a colour is given.
DrawScrollBar x, y, length, position, visible, total [, horizontal [, control]] A scroll bar with its arrows and its thumb, for a list of total rows of which visible are shown from row position, with its top-left corner at x, y. It stands upright (16 pixels wide, length tall, arrows at the top and bottom) unless horizontal is True: then it lies across (length wide, 16 pixels tall, arrows at the left and right ends). With control True it is the narrower bar of a control such as ListBox (14 pixels).
DrawScrollArrow x, y, size, direction One arrow button of a scroll bar, as at the ends of DrawScrollBar's bars: a square button size wide and tall (size in the scale's horizontal units) with its top-left corner at x, y and an arrow pointing dvxArrowUp, dvxArrowDown, dvxArrowLeft, or dvxArrowRight, in the theme's scroll bar colours.
ScrollBarClick(length, offset, position, visible, total [, horizontal [, control]]) The new position after a click on a scroll bar DrawScrollBar drew with the same length, rows, direction, and kind: offset is how far the click is from the top of the bar, or from its left end when horizontal is True. The arrows move one row, the trough a page, the thumb leaves it as it is. Needs no drawing.
ScrollBarsNeeded(contentWidth, contentHeight, areaWidth, areaHeight) Which scroll bars content that big needs in an area that big, as DVX's controls decide it: vbSBNone (0), vbHorizontal (1), vbVertical (2), or vbBoth (3). A vertical bar narrows the area and may make a horizontal one needed, and the other way round. The sizes are in the object's scale. Needs no drawing.
PrintAccel text [, enabled] Prints a caption in the object's font at CurrentX, CurrentY with the letter after &amp; underlined (&amp;&amp; prints one &amp;); enabled False gives the greyed, embossed look of a disabled control. CurrentX moves past the text.
TextWidthAccel(text) Width of a caption without its &amp; signs in the object's font, in the scale's units.
AccelKey(text) The access key of a caption in lower case (&quot;f&quot; for &quot;&amp;File&quot;), &quot;&quot; when it has none.</pre>
<pre><code>Sub Picture1_Paint()
Picture1.DrawBevel 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, True, vbWhite
Picture1.DrawButtonFace 4, 4, 60, 20, pressed
Picture1.CurrentX = 10: Picture1.CurrentY = 8
Picture1.PrintAccel &quot;&amp;Go&quot;, Picture1.Enabled
Picture1.DrawScrollBar Picture1.ScaleWidth - 18, 2, Picture1.ScaleHeight - 22, topRow, 8, 40
Picture1.DrawScrollBar 2, Picture1.ScaleHeight - 18, Picture1.ScaleWidth - 22, leftCol, 10, 60, True
End Sub
Sub Picture1_MouseDown(Button As Integer, X As Integer, Y As Integer)
' A click on the bar along the bottom scrolls sideways
If Y &gt;= Picture1.ScaleHeight - 18 And X &lt; Picture1.ScaleWidth - 20 Then
leftCol = Picture1.ScrollBarClick(Picture1.ScaleWidth - 22, X - 2, leftCol, 10, 60, True)
Picture1.Refresh
End If
End Sub</code></pre>
<p>Without a colour, drawing uses ForeColor. Step makes a point relative to CurrentX, CurrentY, which every drawing method leaves at its last point. Coordinates, radii, CurrentX and CurrentY, and PaintPicture's rectangles are in the scale's units (a radius in its horizontal units); DrawWidth is always in pixels. A colour or angle out of range stops the program with an error.</p>
<h2>Raster Operations</h2>
<p>PaintPicture's opcode says how each copied pixel is combined with the pixel already there (the destination) and with the FillColor (the pattern), as in Visual Basic. Leaving it out copies the picture (vbSrcCopy).</p>
<pre> Constant Value Result
-------- ----- ------
vbSrcCopy &amp;HCC0020 The picture
vbSrcPaint &amp;HEE0086 Picture OR destination
vbSrcAnd &amp;H8800C6 Picture AND destination
vbSrcInvert &amp;H660046 Picture XOR destination
vbSrcErase &amp;H440328 Picture AND NOT destination
vbNotSrcCopy &amp;H330008 NOT picture
vbNotSrcErase &amp;H1100A6 NOT (picture OR destination)
vbMergeCopy &amp;HC000CA Picture AND pattern
vbMergePaint &amp;HBB0226 NOT picture OR destination
vbPatCopy &amp;HF00021 The pattern
vbPatPaint &amp;HFB0A09 Pattern OR NOT picture OR destination
vbPatInvert &amp;H5A0049 Pattern XOR destination
vbDstInvert &amp;H550009 NOT destination
vbGrayCopy &amp;H1000000 The picture greyed, as DVX shows a disabled picture (DVX only)
vbTransparentCopy &amp;H2000000 Every pixel of the picture but the key colour: a colour given after the opcode, else the colour of the picture's top-left pixel (DVX only)</pre>
<p>vbGrayCopy and vbTransparentCopy copy the picture at its own size (width and height are not used): Picture1.PaintPicture &quot;ship.bmp&quot;, x, y, 32, 32, 0, 0, 32, 32, vbTransparentCopy, vbMagenta draws a sprite. A picture file (or a LOADPICTURE picture) drawn again and again, a sprite in a game loop say, is read from the disk only the first time while the program runs and the file does not change (about a megabyte of pictures is kept that way).</p>
<p>Any of the 256 raster operations of Windows can be given by its number; the bits work on the pixel values, so with fewer than 32 bits a pixel the results follow the display's colour format.</p>
<pre><code>Picture1.PaintPicture Picture2, 0, 0, 32, 32, 0, 0, 32, 32, vbSrcInvert ' XOR the picture in
Picture1.PaintPicture Picture2, 0, 0, 32, 32, 0, 0, 32, 32, vbSrcInvert ' and out again</code></pre>
<h2>Scales</h2>
<p>ScaleMode picks the units: 0 user (set by Scale or the Scale properties), 1 twips (1440 an inch, 15 a pixel), 2 points (72 an inch), 3 pixels, 4 characters (120 twips across, 240 down), 5 inches, 6 millimetres, 7 centimetres. Unlike Visual Basic, whose default is twips, DVX starts every form and PictureBox in pixels (ScaleMode 3), and Scale without arguments goes back to pixels. Setting ScaleLeft, ScaleTop, ScaleWidth, or ScaleHeight makes a user scale from the current one; ScaleWidth and ScaleHeight may not be 0. With a user scale the units stay fixed to the picture's edges when it is resized; other scale modes keep their unit size.</p>
<p>The constants vbUser (0), vbTwips (1), vbPoints (2), vbPixels (3), vbCharacters (4), vbInches (5), vbMillimeters (6), and vbCentimeters (7) name the scale modes. The units assume a standard display of 96 pixels an inch (15 twips a pixel), whatever the screen really is, so an inch is always 96 pixels.</p>
<p>ScaleX and ScaleY convert a width or a height from one scale to another, as in Visual Basic: fromScale is the scale the value is in, vbHimetric (8, hundredths of a millimetre, the unit of a Picture's Width and Height) when it is left out; toScale the scale wanted, the object's ScaleMode when left out. vbUser means the object's current scale. Visual Basic's vbContainerPosition and vbContainerSize are not available; any other scale number stops the program with an error.</p>
<pre><code>Picture1.Scale (0, 100)-(100, 0) ' 0..100 across, y going up
Picture1.Line (0, 0)-(100, 100), RGB(255, 0, 0)
Picture1.ScaleMode = 7 ' centimetres
Picture1.Circle (2, 2), 1
Dim pic As Object
Set pic = LoadPicture(&quot;logo.bmp&quot;)
w = Me.ScaleX(pic.Width, vbHimetric, vbPixels) ' the picture's width in pixels</code></pre>
<h2>AutoRedraw and the Paint Event</h2>
<p>A form or PictureBox fires its Paint event when it is shown, when the form is resized, when a PictureBox changes size (its Width or Height set to a new value, or its Resize method) while its form is showing, and when the program calls its Refresh method, so a program can draw everything in Paint as in Visual Basic. Unlike Visual Basic, DVX keeps what was drawn even with AutoRedraw False (the default), so drawing outside Paint also stays on the screen. With AutoRedraw = True, Paint does not fire. A program that sets AutoRedraw = False itself gets Visual Basic's behaviour exactly: the drawing is cleared to BackColor before each Paint.</p>
<pre><code>Sub Picture1_Paint ()
Picture1.Circle (50, 50), 40, RGB(0, 128, 0)
End Sub</code></pre>
<h2>Drawing Properties</h2>
<pre> Property Type Default Description
-------- ---- ------- -----------
ForeColor Long &amp;H000000 Colour of drawing and printing.
BackColor Long &amp;HFFFFFF Colour Cls clears to. Setting it clears the drawing to the new colour.
CurrentX Single 0 Where the next drawing or printing starts.
CurrentY Single 0
DrawWidth Integer 1 Pen width in pixels.
DrawStyle Integer 0 The pen's lines and outlines: 0 solid, 1 dashes, 2 dots, 3 dash-dot, 4 dash-dot-dot (a pen 1 pixel wide only; a wider one draws solid), 5 none at all (fills are still drawn), 6 solid. Other values are an error. The constants vbSolid to vbInsideSolid name them.
FillStyle Integer 1 How boxes (B) and circles are filled with FillColor: 0 solid, 1 (the default) not at all, 2 horizontal lines, 3 vertical lines, 4 upward diagonals, 5 downward diagonals, 6 a cross hatch, 7 a diagonal cross hatch (the lines 8 pixels apart, the gaps left as they are). Other values are an error. BF fills solid in the line's colour. The constants vbFSSolid to vbDiagonalCross name them.
FillColor Long &amp;H000000 Colour boxes and circles are filled with.
FontScale Integer 1 How many times as large Print writes its text (1 to 8): each dot of the font becomes a FontScale x FontScale block, for titles and banners. TextWidth and TextHeight follow it; PrintAccel does not.
AutoRedraw Boolean False True: no Paint events (see above).
ScaleMode Integer 3 Units of the coordinates (see Scales).
ScaleLeft Single 0 Coordinate of the left edge.
ScaleTop Single 0 Coordinate of the top edge.
ScaleWidth Single (size) Width of the drawing in the scale's units.
ScaleHeight Single (size) Height of the drawing in the scale's units.</pre>
<h2>Example</h2>
<pre><code>Sub Command1_Click ()
Picture1.Resize 200, 150
Picture1.BackColor = RGB(255, 255, 255)
Picture1.DrawWidth = 2
Picture1.Line (10, 10)-(190, 140), RGB(0, 0, 255), B
Picture1.FillStyle = 0
Picture1.FillColor = RGB(255, 255, 0)
Picture1.Circle (100, 75), 40, RGB(255, 0, 0)
Picture1.CurrentX = 70
Picture1.CurrentY = 120
Picture1.Print &quot;Hello!&quot;
End Sub</code></pre>
<p><a href="#ctrl.picturebox">PictureBox</a></p>
<p><a href="#ctrl.form">Form</a></p>
</div>
<div class="topic" id="ctrl.databinding">
<h1>Data Binding</h1>
<p>DVX BASIC provides VB3-style data binding through three properties that can be set on most controls:</p>
<pre> Property Set On Description
---------- ----------- -------------------------------------------
DataSource Any control Name of the Data control to bind to (e.g. &quot;Data1&quot;).
DataField Any control Column name from the Data control's recordset to display.</pre>
<h2>How It Works</h2>
<ul>
<li>Place a Data control on the form and set its DatabaseName and RecordSource properties.</li>
<li>Place one or more display/edit controls (TextBox, Label, etc.) and set their DataSource to the Data control's name and DataField to a column name.</li>
<li>When the form loads, the Data control auto-refreshes: it opens the database, runs the query, and navigates to the first record.</li>
<li>Bound controls are updated automatically each time the Data control repositions (the Reposition event fires, and the runtime pushes the current record's field values into all bound controls).</li>
<li>When a bound control loses focus (LostFocus), its current text is written back to the Data control's record cache, and Update is called automatically to persist changes.</li>
</ul>
<h2>Master-Detail Binding</h2>
<p>For hierarchical data (e.g. orders and order items), use two Data controls:</p>
<ul>
<li>A master Data control bound to the parent table.</li>
<li>A detail Data control with its MasterSource set to the master's name, MasterField set to the key column in the master, and DetailField set to the foreign key column in the detail table.</li>
</ul>
<p>When the master record changes, the detail Data control automatically re-queries using the master's current value for filtering. All controls bound to the detail are refreshed.</p>
<h2>DBGrid Binding</h2>
<p>Set the DBGrid's DataSource to a Data control name. The grid auto-populates columns from the query results and refreshes whenever the Data control refreshes.</p>
<h2>Example</h2>
<pre><code>VERSION DVX 1.00
Begin Form frmData
Caption = &quot;Data Binding Example&quot;
AutoSize = False
Width = 400
Height = 280
Begin Data Data1
DatabaseName = &quot;myapp.db&quot;
RecordSource = &quot;customers&quot;
End
Begin Label lblName
Caption = &quot;Name:&quot;
End
Begin TextBox txtName
DataSource = &quot;Data1&quot;
DataField = &quot;name&quot;
End
Begin Label lblEmail
Caption = &quot;Email:&quot;
End
Begin TextBox txtEmail
DataSource = &quot;Data1&quot;
DataField = &quot;email&quot;
End
End
Sub Data1_Reposition ()
Print &quot;Current record changed&quot;
End Sub
Sub Data1_Validate (Cancel As Integer)
If txtName.Text = &quot;&quot; Then
MsgBox &quot;Name cannot be empty!&quot;
Cancel = 1
End If
End Sub</code></pre>
<p><a href="#ctrl.data">Data</a></p>
<p><a href="#ctrl.dbgrid">DBGrid</a></p>
</div>
<div class="topic" id="ctrl.menus">
<h1>Menu System</h1>
<p>Menus are defined in the .frm file using Begin Menu blocks. Each menu item has a name, caption, and nesting level. Menu items fire Click events dispatched as MenuName_Click.</p>
<h2>FRM Syntax</h2>
<pre><code>Begin Form Form1
Caption = &quot;Menu Demo&quot;
Begin Menu mnuFile
Caption = &quot;&amp;File&quot;
Begin Menu mnuOpen
Caption = &quot;&amp;Open&quot;
End
Begin Menu mnuSave
Caption = &quot;&amp;Save&quot;
End
Begin Menu mnuSep1
Caption = &quot;-&quot;
End
Begin Menu mnuExit
Caption = &quot;E&amp;xit&quot;
End
End
Begin Menu mnuEdit
Caption = &quot;&amp;Edit&quot;
Begin Menu mnuCopy
Caption = &quot;&amp;Copy&quot;
End
Begin Menu mnuPaste
Caption = &quot;&amp;Paste&quot;
End
End
End</code></pre>
<h2>Menu Item Properties</h2>
<p>In the .frm file a menu item takes these keys:</p>
<pre> Key Type Description
---------- ------- -------------------------------------------
Caption String The text displayed. Use &amp; for accelerator key. Set to &quot;-&quot; for a separator.
Checked Boolean Whether the menu item shows a checkmark. An item with a Checked line (True or False) is a check item: choosing it turns its checkmark on or off before its Click event runs, so the handler reads the new state.
RadioCheck Boolean Show the check as a radio dot instead of a checkmark. Radio items next to each other form a group: choosing one checks it and clears the others.
Shortcut String A key that runs the item from anywhere in the form, shown at the right of the item: &quot;F2&quot;, &quot;Ctrl+X&quot;, &quot;Alt+Enter&quot;, &quot;Shift+Del&quot; (Ctrl, Alt, and Shift, then a letter, digit, F1 to F12, or Backspace, Del, Down, End, Enter, Esc, Home, Ins, Left, PgDn, PgUp, Right, Space, Tab, Up).
ShortcutText String Key text shown at the right of the item without making a shortcut, for keys a control handles itself (for example &quot;Del&quot; on a Delete item whose list deletes on Del in its KeyDown handler, so a text box keeps its own Del). Shown instead of the Shortcut's text when both are set.
Enabled Boolean Whether the menu item is enabled (default True).
Visible Boolean On a top-level menu, False makes it a popup menu (for ContextMenu) instead of a menu bar entry. On an item or separator inside a menu, False hides it until code sets Visible = True.</pre>
<p>A Shortcut key works while the form's window has the focus, before the focused control sees the key, so give one only to keys no control there needs (F-keys, Ctrl, or Alt combinations). F1 always opens the help and never reaches a shortcut. An unknown Shortcut stops the program with an error when the form loads.</p>
<pre><code>Begin Menu mnuRename
Caption = &quot;&amp;Rename...&quot;
Shortcut = &quot;F2&quot;
End
Begin Menu mnuDelete
Caption = &quot;&amp;Delete&quot;
ShortcutText = &quot;Del&quot;
End</code></pre>
<p>At run time code can use only these properties of a menu item:</p>
<pre> Property Type R/W Description
-------- ------- --- -------------------------------------------
Name String R The menu item's name.
Caption String R/W The item's text, with &amp; before its access key. Setting it keeps the item's key text (Shortcut or ShortcutText), and reading it gives the text without it.
Checked Boolean R/W Whether the menu item shows a checkmark. Setting it on an item that has neither Checked nor RadioCheck in the .frm makes it a check item (as in VB, any item can be checked).
Enabled Boolean R/W Whether the menu item is enabled.
Visible Boolean R/W Whether the item (or separator) is in its menu. A hidden item keeps its caption, checkmark, and place: shown again, it returns where it was. A submenu cannot be hidden (hide or remove its items, or set Enabled = False).
Shortcut String R/W The key that runs the item (&quot;Ctrl+K&quot;, written as in the .frm file, &quot;&quot; for none). Setting it changes the key and the key text shown in the item; &quot;&quot; removes both. An unknown key is an error.</pre>
<p>RadioCheck and ShortcutText are design-time only: using them on a menu item in code is a compile error in the IDE and a runtime error (Unknown menu property) otherwise. The top-level menus of the menu bar (File, Edit) have no run-time properties.</p>
<h2>Menus at Run Time</h2>
<p>These methods work on any control of a form, or on the form itself (Me.AddMenuItem ...). They name menus by their .frm names: a top-level menu of the menu bar, a submenu, a popup menu from the .frm, or one made with CreateMenu.</p>
<pre> Method Parameters Description
---------------- --------------------------------- -------------------------------------------
PopupMenu menu$ [, x, y] Shows the menu as a popup at the mouse, or at x, y in the control.
CreateMenu menu$ Makes an empty popup menu of that name (nothing happens if one exists).
AddMenu menu$, caption$ Adds a menu at the end of the form's menu bar, which appears with the first one (so a form made with CreateForm can have a menu bar). Add items to it by its name. The window keeps its size; the controls get the height the bar takes.
RemoveMenu menu$ Removes a menu of the menu bar with all its items; with the last one the bar goes too. Not for popup menus (DestroyMenu) or items (RemoveMenuItem).
AddMenuItem menu$, item$, caption$ [, shortcut$] Adds an item at the end of the menu. Choosing it runs the Sub item_Click, and item.Caption, .Checked, .Enabled, .Visible, and .Shortcut work as for .frm items. shortcut$ gives it a key, as Shortcut in the .frm file.
AddMenuRadioItem menu$, item$, caption$ [, checked] Adds a radio item: radio items next to each other form a group, and choosing one checks it and clears the others.
AddMenuSeparator menu$ [, separator$] Adds a separator line at the end of the menu. With a name it can be hidden and removed like an item.
AddSubMenu menu$, submenu$, caption$ Adds a submenu at the end of the menu; add items to it by its name.
RemoveMenuItem item$ Removes an item or named separator (shown or hidden) from its menu. An unknown name does nothing. A submenu cannot be removed.
DestroyMenu menu$ Frees a popup menu made with CreateMenu (or from the .frm) and every item in it.</pre>
<p>A recent-files list at the end of the File menu, rebuilt whenever it changes:</p>
<pre><code>Dim recentCount As Integer
Sub ShowRecent(files() As String, count As Integer)
Dim i As Integer
For i = 1 To recentCount
Me.RemoveMenuItem &quot;mnuRecent&quot; &amp; i
Next
Me.RemoveMenuItem &quot;mnuRecentSep&quot;
If count &gt; 0 Then Me.AddMenuSeparator &quot;mnuFile&quot;, &quot;mnuRecentSep&quot;
For i = 1 To count
Me.AddMenuItem &quot;mnuFile&quot;, &quot;mnuRecent&quot; &amp; i, &quot;&amp;&quot; &amp; i &amp; &quot; &quot; &amp; files(i)
Next
recentCount = count
End Sub</code></pre>
<p>Each item made this way needs its own Click procedure (Sub mnuRecent1_Click and so on), or fixed items in the .frm switched on and off with Visible serve the same purpose.</p>
<h2>Nesting</h2>
<p>Menu items are nested by placing Begin Menu blocks inside other Begin Menu blocks:</p>
<ul>
<li>Level 0: top-level menu bar headers (e.g. &quot;File&quot;, &quot;Edit&quot;).</li>
<li>Level 1: items within a top-level menu.</li>
<li>Level 2+: submenu items.</li>
</ul>
<p>A level-0 menu that contains children becomes a top-level menu header. A non-level-0 menu that contains children becomes a submenu.</p>
<h2>Event Dispatch</h2>
<p>Choosing a menu item (not a header, separator, or submenu) fires MenuName_Click, whether it is on the menu bar or in a popup menu.</p>
<pre><code>Sub mnuOpen_Click ()
MsgBox &quot;Open was clicked&quot;
End Sub
Sub mnuExit_Click ()
Unload Form1
End Sub</code></pre>
<p><a href="#ctrl.form">Form</a></p>
<p><a href="#ctrl.frm">FRM File Format</a></p>
</div>
<div class="topic" id="ctrl.arrays">
<h1>Control Arrays</h1>
<p>DVX BASIC supports VB-style control arrays. Multiple controls can share the same name, differentiated by an Index property. When an event fires on a control array element, the element's index is passed as the first parameter.</p>
<h2>Defining Control Arrays in FRM</h2>
<pre><code>Begin CommandButton Command1
Caption = &quot;Button A&quot;
Index = 0
End
Begin CommandButton Command1
Caption = &quot;Button B&quot;
Index = 1
End
Begin CommandButton Command1
Caption = &quot;Button C&quot;
Index = 2
End</code></pre>
<h2>Event Handler Convention</h2>
<p>When a control has an Index property (&gt;= 0), the event handler receives Index As Integer as the first parameter, before any event-specific parameters.</p>
<pre><code>Sub Command1_Click (Index As Integer)
Select Case Index
Case 0
MsgBox &quot;Button A clicked&quot;
Case 1
MsgBox &quot;Button B clicked&quot;
Case 2
MsgBox &quot;Button C clicked&quot;
End Select
End Sub</code></pre>
<h2>Accessing Array Elements in Code</h2>
<p>Use the indexed form ControlName(Index) to access a specific element:</p>
<pre><code>Command1(0).Caption = &quot;New Text&quot;
Command1(1).Enabled = False</code></pre>
<blockquote><strong>Note:</strong> Control array elements share the same event handler Sub. The runtime prepends the Index argument automatically. If you define parameters on the Sub, Index comes first, followed by the event's own parameters (e.g. KeyPress would be Sub Ctrl1_KeyPress (Index As Integer, KeyAscii As Integer)).</blockquote>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.frm">FRM File Format</a></p>
</div>
<div class="topic" id="ctrl.frm">
<h1>FRM File Format</h1>
<p>The .frm file is a text file that describes a form's layout, controls, menus, and code. It follows a format compatible with VB3 .frm files, with DVX-specific extensions.</p>
<h2>Structure</h2>
<pre><code>VERSION DVX 1.00
Begin Form FormName
form-level properties...
Begin Menu mnuFile
Caption = &quot;&amp;File&quot;
Begin Menu mnuOpen
Caption = &quot;&amp;Open&quot;
End
End
Begin TypeName ControlName
property = value
...
End
Begin Frame Frame1
Caption = &quot;Group&quot;
Begin TypeName ChildName
...
End
End
End
BASIC code follows...
Sub FormName_Load ()
...
End Sub</code></pre>
<h2>Rules</h2>
<ul>
<li>The VERSION line is optional. VERSION DVX 1.00 marks a native DVX form. VB forms with version &lt;= 2.0 are accepted for import.</li>
<li>The form block begins with Begin Form Name and ends with End.</li>
<li>Controls are nested with Begin TypeName Name / End.</li>
<li>Container controls (Frame, VBox, HBox, Toolbar, TabStrip, ScrollPane, Splitter, WrapBox) can have child controls nested inside them.</li>
<li>Properties are assigned as Key = Value. String values are optionally quoted.</li>
<li>A Key = Value line belongs to the innermost block that is still open, also when it comes after the blocks nested inside it. DVX writes a block's properties before the blocks inside it.</li>
<li>Everything after the form's closing End is BASIC source code.</li>
<li>Comments in the form section use ' (single quote).</li>
<li>Blank lines are ignored in the form section.</li>
</ul>
<h2>Common FRM Properties</h2>
<pre> Property Applies To Description
----------------------- --------------- -------------------------------------------
Caption Form, controls Display text or window title.
Text TextBox, ComboBox Initial text content.
MinWidth / Width Controls Minimum width. Both names are accepted.
MinHeight / Height Controls Minimum height. Both names are accepted.
MaxWidth Controls Maximum width (0 = no cap).
MaxHeight Controls Maximum height (0 = no cap).
Weight Controls Layout weight for flexible sizing.
Left Form, controls X position (used by Form when Centered=False; informational for controls).
Top Form, controls Y position.
Index Controls Control array index (-1 or absent = not in array).
Visible Controls Initial visibility.
Enabled Controls Initial enabled state.
Layout Form &quot;VBox&quot; or &quot;HBox&quot;.
AutoSize Form Auto-fit window to content.
Resizable Form Allow runtime resizing.
Centered Form Center window on screen.
DatabaseName Data SQLite database file path.
RecordSource Data Table name or SQL query.
DataSource Bound controls Name of the Data control.
DataField Bound controls Column name in the recordset.</pre>
<p><a href="#ctrl.form">Form</a></p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.menus">Menu System</a></p>
<p><a href="#ctrl.arrays">Control Arrays</a></p>
</div>
<div class="topic" id="ctrl.form">
<h1>Form</h1>
<p>VB Equivalent: Form -- DVX Widget: Window + VBox/HBox root</p>
<p>The Form is the top-level container representing a DVX window. It is declared in the .frm file with Begin Form FormName. All controls are children of the form's content box, which uses either VBox (default) or HBox layout.</p>
<h2>Form Properties</h2>
<pre> Property Type Default Description
---------- ------- -------------- -------------------------------------------
Name String &quot;Form1&quot; The form's name, used for event dispatch and Load statement.
Caption String (same as Name) Window title bar text.
Width Integer 400 Window width in pixels. In the .frm file it is ignored when AutoSize is True.
Height Integer 300 Window height in pixels. In the .frm file it is ignored when AutoSize is True.
Left Integer 0 Initial X position. Used when Centered is False.
Top Integer 0 Initial Y position. Used when Centered is False.
Layout String &quot;VBox&quot; Content box layout: &quot;VBox&quot; (vertical) or &quot;HBox&quot; (horizontal).
AutoSize Boolean False When True, the window shrink-wraps to fit its content.
Resizable Boolean True Whether the user can resize the window at runtime.
Centered Boolean True When True, the window is centered on screen. When False, Left/Top are used.
Visible Boolean False True shows the form and False hides it, exactly like Show and Hide (the first show fires Activate).
ContextMenu String &quot;&quot; Name of a popup menu shown when the form is right-clicked.
HelpTopic String &quot;&quot; Help topic opened by F1 while the form is active and the focused control has no HelpTopic of its own. Empty opens the project's help file at its default page.
Padding Integer 4 Space in pixels between the window's edges and the controls (the content box's Padding); 0 is none.
Spacing Integer 4 Space in pixels between one control and the next (the content box's Spacing); 0 is none.
WindowState Integer 0 vbNormal (0), vbMinimized (1, shown only as an icon at the bottom of the screen), or vbMaximized (2, filling the screen). Set on a hidden form (or in the .frm file), it takes effect when the form is shown; reading it then gives the state the form will have.
Controls Collection (none) The form's controls (read-only), in the order they were made: Me.Controls.Count, Me.Controls(1) (the first), Me.Controls(&quot;Text1&quot;), For Each c In Me.Controls. Elements of a control array are in it too but have no name key. Each use makes a new Collection; changing it does not change the form.
DesignMode Boolean False True puts the form in design mode, for a form designer: see Designing Forms below. Not in .frm files.
Icon Picture (DVX's) The picture shown for the window while it is minimized: a picture file name (BMP, PNG, JPEG, or GIF) or a picture from LOADPICTURE or LOADPICTUREDATA (Set works too); &quot;&quot; puts DVX's back. Reading it gives a Picture object. Also in the .frm file. A file that is not a picture is an error.
Tag String &quot;&quot; Any text the program wants to keep with the form, as for controls.
MousePointer Integer 0 The mouse pointer over the form where its controls have none (see MousePointer under Common Properties).
FontName String &quot;System&quot; The form's font: the font of every control on it that has none of its own, and of the form's Print and TextWidth. FontSize, FontBold, FontItalic, FontUnderline, and FontStrikethru go with it, as for controls (see Fonts under Common Properties). Also in the .frm file.
ActiveControl Control (none) The control of the form that has the keyboard focus (read-only), Nothing when none of them has it: Me.ActiveControl.SelText for an Edit menu's Copy. Screen.ActiveControl is the focused control of the whole program. Not in .frm files.
DesignSelection String &quot;&quot; The name of the control (Text1, or Text1(2) in a control array) whose selection handles are drawn while the form is in design mode; &quot;&quot; for none. Not in .frm files.
MaxWidth Integer 0 The widest the user can make the window, by dragging or maximizing; 0 is the screen's width. A window wider than a new MaxWidth shrinks to it. Also in the .frm file.
MaxHeight Integer 0 The tallest the window can be made, as MaxWidth; 0 is the screen's height.
GameInput Boolean False True for a game: while the form has the keyboard, every key goes to it -- none to F1 (help), F10 or Alt (the menu bar), menu shortcuts, or DVX's shortcut keys. Only Alt+Tab, Ctrl+Esc, and Alt+F4 still reach DVX. Also in the .frm file.
FullScreen Boolean False True gives the form the whole screen: a video mode as large as the form's inside (its controls and drawing, without the title bar), the form shown on it at the largest whole multiple of its size that fits, centred on black, kept up to date as it changes. The mouse works on it as in the window, and every key goes to it as with GameInput. A hidden form is shown first. When the user switches to another program (Alt+Tab, Ctrl+Esc), or the program shows a message box or another form, the desktop comes back; the form gets the whole screen again with the focus. Reads False when no video mode could be set (the form stays in its window). False gives the desktop back. Run time only; see the FullScreen event.</pre>
<p>Maximizing a window, or restoring a maximized one, changes its size, so Resize fires. Minimizing does not change the size and fires no Resize. A minimized window keeps its maximized state: set WindowState = vbMaximized to bring it back filling the screen, vbNormal to bring it back at its normal size.</p>
<pre><code>frmTerminal.Show
frmTerminal.WindowState = vbMinimized ' starts as an icon</code></pre>
<h2>Form Events</h2>
<pre> Event Parameters Description
----------- --------------------- -------------------------------------------
Load (none) Fires after the form and all controls are created. This is the default event.
Unload (none) Fires when the form is being closed or unloaded.
QueryUnload Cancel As Integer Fires before Unload. Set Cancel = 1 to abort the close.
Resize (none) Fires when the window changes size: resized by the user, maximized, or restored (by the user or WindowState).
Activate (none) Fires when the window gains focus.
Deactivate (none) Fires when the window loses focus.
Paint (none) Fires when the form is shown or resized and on Refresh, unless AutoRedraw is True (see Drawing on Forms and PictureBoxes).
DragDrop Source As Control, X As Integer, Y As Integer Fires when a dragged control is dropped on an empty part of the form. X and Y are where, in the form.
DragOver Source As Control, X As Integer, Y As Integer, State As Integer Fires while a dragged control moves over an empty part of the form. State is vbEnter, vbLeave, or vbOver.
NewArgs (none) Fires when the running program is handed new arguments: COMMAND$ has changed (see New Arguments below).
FullScreen State As Integer With FullScreen True: dvxFullScreenActive (1) when the form has the whole screen (draw anything that must look new then), dvxFullScreenSuspended (2) when the desktop came back while another window has the focus, dvxFullScreenEnded (0) when the form's video mode could not be set again (FullScreen is False now).
DesignMouse Action As Integer, Button As Integer, X As Integer, Y As Integer, CtrlName As String, Handle As Integer In design mode: the mouse was pressed, moved, released, or double-clicked in the form. See Designing Forms below.
DesignKey KeyCode As Integer, Shift As Integer In design mode: a key was pressed in the form (KeyCode and Shift as in KeyDown).
DesignPropertyChanged CtrlName As String, PropertyName As String In design mode: the code of a UserControl on the form called PropertyChanged. See Designing Forms below.</pre>
<p>See Drag and Drop under Common Properties, Events, and Methods. While a control is dragged over a form with no DragDrop event procedure, the mouse pointer shows the &quot;no drop&quot; sign.</p>
<h2>New Arguments</h2>
<p>A program with a NewArgs event procedure on any of its forms can be handed new arguments while it runs, instead of DVX starting another copy of it. COMMAND$ (and COMMAND$(1), COMMAND$(2), ...) then give the new arguments, and NewArgs fires on every loaded form that has the procedure. When the arguments arrive while one of the program's event procedures is still running -- for example while it shows a message box or a dialog, or a form with vbModal -- they are held, and NewArgs fires once that procedure has finished; if several arrive meanwhile, only the last is given.</p>
<p>DVX hands new arguments to the help viewer: F1 and the Help menus of programs (and HelpView in BASIC) send &quot;helpfile topic&quot; to the program installed as APPS\KPUNCH\DVXHELP\DVXHELP.APP when it is already running. A help viewer written in BASIC and installed there gets them in NewArgs. Starting a program that is already running -- from Program Manager, the Run dialog, a document opened in it, or ShellRun -- gives it the new arguments when it allows only one copy and has a NewArgs procedure: its window comes to the front and NewArgs fires. Without a NewArgs procedure DVX says it is already running; a program that allows more than one copy (Project Properties) starts another copy instead.</p>
<pre><code>Sub Form1_NewArgs ()
' F1 in another program while this help viewer is open
If COMMAND$(1) &lt;&gt; openFile Then OpenHelpFile COMMAND$(1)
GoTopic HlpStartTopic(hlp, COMMAND$(2))
End Sub</code></pre>
<h2>Form Methods</h2>
<pre> Statement Description
------------------ -------------------------------------------
Load FormName Load the form (creates the window and controls, fires Load event).
Unload FormName Unload the form (fires Unload, destroys window).
FormName.Show Make the form visible.
FormName.Show 1 Show as a modal dialog (vbModal): the statement returns when the form is hidden or unloaded, so the code after it can read what the user chose.
FormName.Hide Hide the form without unloading it.
FormName.FitWidth Make the window just wide enough for its controls, keeping its height (AutoSize fits both).
FormName.FitHeight Make the window just tall enough for its controls, keeping its width.
FormName.SaveScreenshot file$ Save a picture of what the window shows inside its frame to a file: BMP when the name ends in .bmp, PNG otherwise. An error when the form has no window or the file cannot be written.</pre>
<h2>Several Copies of a Form</h2>
<p>A form can be open more than once, the way a program opens a second document window. New FormName makes another copy of the form: its own window, controls, menus, and form-level variables, built from the same .frm. Its Load event runs, and it starts hidden like any loaded form, so call Show. Keep the copy in a variable declared As the form's name (or As Form, As Object):</p>
<pre><code>Dim f As Form1 ' a Form1 copy, or the form itself
Set f = New Form1 ' a new copy
f.Caption = &quot;Second window&quot;
f.Text1.Text = &quot;Hello&quot; ' this copy's Text1
f.Show
Dim g As New Form1 ' declares and makes a copy at once</code></pre>
<p>The code of the form serves every copy. In it, Me, the controls named on their own (Text1), and the form-level variables are those of the copy whose event is running, so each window keeps its own state. Unload f closes that copy only.</p>
<p>The form's name (Form1.Caption, Form1.Show, Load Form1) always means the first copy loaded -- the one the program starts with -- as in Visual Basic. If that copy was unloaded, the name means the next one still open.</p>
<h2>Designing Forms</h2>
<p>A form designer written in BASIC shows the form being designed as a real form and turns on its design mode. While DesignMode is True, the controls on the form take no mouse clicks or keys and fire no events (Timers too are quiet); the form instead tells the designer what the user does:</p>
<ul>
<li>DesignMouse (Action, Button, X, Y, CtrlName, Handle): Action is DSGN_MOUSE_DOWN (1, a button was pressed), DSGN_MOUSE_MOVE (2), DSGN_MOUSE_UP (3), or DSGN_MOUSE_DBLCLICK (4, a double click: open the code, say). Button is the button pressed or released (1 left, 2 right, 4 middle; for a move, the buttons held). X and Y are where, in the form. CtrlName is the control there -- the innermost one when containers hold others -- or &quot;&quot; for the form itself. Handle is the selection handle of the selected control under the mouse: DSGN_HANDLE_E (3, the right edge: drag to change the width), DSGN_HANDLE_SE (4, the corner), or DSGN_HANDLE_S (5, the bottom edge), or DSGN_HANDLE_NONE (-1).</li>
<li>DesignKey (KeyCode, Shift): a key, for Delete, the arrow keys, and so on.</li>
<li>DesignPropertyChanged (CtrlName, PropertyName): the code of a UserControl on the form -- one of the project's own, put on the designer's toolbox with CompDesignControls (compiler.bas) -- called UserControl.PropertyChanged PropertyName: read its properties again. Such controls run their code on the form with UserControl.UserMode False.</li>
</ul>
<p>DesignSelection names the selected control; the form draws its eight selection handles over the controls (the three that resize in black) and shows the resize mouse pointers over them. The constants are in designer.bas, which also lists the control types, their properties, and events (see Include Libraries in the language reference). Together with CreateControl, RemoveControl, CallByName, Controls, Container, MoveBefore, LoadFormText, and the .frm model of designer.bas (FrmOpen, FrmText$, FrmCtlText$ / FrmCtlPaste to copy and paste controls, FormText$ to write the live form as .frm text), a designer has what the DVX BASIC IDE's own designer uses.</p>
<pre><code>Sub Canvas_DesignMouse(Action As Integer, Button As Integer, X As Integer, Y As Integer, CtrlName As String, Handle As Integer)
If Action = DSGN_MOUSE_DOWN Then
If Handle &lt;&gt; DSGN_HANDLE_NONE Then
resizing = True ' drag the selected control's size
Else
Canvas.DesignSelection = CtrlName
ShowProperties CtrlName
End If
ElseIf Action = DSGN_MOUSE_UP Then
resizing = False
End If
End Sub</code></pre>
<h2>Drawing</h2>
<p>Forms have Visual Basic's drawing methods and properties (Cls, PSet, Line, Circle, Point, Print, PaintPicture, DrawFocusRect, DrawBevel, DrawButtonFace, DrawArrow, DrawScrollBar, DrawScrollArrow, ScrollBarClick, ScrollBarsNeeded, PrintAccel, Scale, CurrentX, CurrentY, ForeColor, BackColor, DrawWidth, DrawStyle, FillColor, FillStyle, FontScale, AutoRedraw, ScaleMode, ScaleLeft, ScaleTop, ScaleWidth, ScaleHeight): see Drawing on Forms and PictureBoxes. In the form's own code use Me.Line, Me.Circle, and so on.</p>
<h2>Example</h2>
<pre><code>Sub Form1_Load ()
Form1.Caption = &quot;Hello World&quot;
Print &quot;Form loaded!&quot;
End Sub
Sub Form1_QueryUnload (Cancel As Integer)
If MsgBox(&quot;Really quit?&quot;, 4) &lt;&gt; 6 Then
Cancel = 1
End If
End Sub
Sub Form1_Resize ()
Print &quot;Window resized&quot;
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.drawing">Drawing on Forms and PictureBoxes</a></p>
<p><a href="#ctrl.frm">FRM File Format</a></p>
</div>
<div class="topic" id="lang.usercontrol">
<h1>UserControls: Your Own Controls</h1>
<p>A UserControl is a control you write in DVX BASIC. Once written, it is used exactly like the controls DVX comes with: you put it on a form in the designer (or in a .frm file with Begin), set its properties, call its methods, and write handlers for its events. Programs written in C can create and use it too.</p>
<p>A UserControl lives in a .ctl file. In the IDE, File &gt; New UserControl makes one (see UserControls in the IDE). The file starts with a header that describes the control, then holds the control's code. The code is a class: every control on a form is one object of the class, with its own copies of the class's variables.</p>
<pre><code>VERSION DVX 1.00
Begin UserControl Gauge
Width = 120 ' natural (smallest) size in pixels
Height = 30
CanGetFocus = True
BackColor = &amp;H00FFFFFF&amp;
ToolboxIcon = &quot;gauge.bmp&quot; ' 24 x 24 picture for the toolbox
Description = &quot;A gauge&quot; ' the toolbox tooltip
DefaultEvent = &quot;Changed&quot;
End
Option Explicit
Public Event Changed(ByVal Level As Integer)
Private mLevel As Integer
Public Property Get Level() As Integer
Level = mLevel
End Property
Public Property Let Level(ByVal Value As Integer)
mLevel = Value
RaiseEvent Changed(mLevel)
UserControl.Refresh
End Property
Private Sub UserControl_Paint()
UserControl.Cls
UserControl.Line (0, 0)-(mLevel * UserControl.Width \ 100, UserControl.Height - 1), RGB(0, 128, 0), BF
End Sub</code></pre>
<p>A form uses it like any control:</p>
<pre><code>Begin Form Form1
Begin Gauge Gauge1
Level = 40
End
End
Sub Gauge1_Changed (ByVal Level As Integer)
lblLevel.Caption = Str$(Level)
End Sub</code></pre>
<h2>The Header</h2>
<p>The header is a Begin UserControl block: the control's name (the type name forms use) and its settings. Every setting is optional. In the IDE, the Properties window shows and changes them while the .ctl file is the active file.</p>
<pre> Setting Meaning
------- -------
Width, Height The natural size in pixels: the smallest size the form's layout gives it (64 x 64 when not given). The code changes it with UserControl.MinWidth and MinHeight.
CanGetFocus True (the default): a click or Tab gives it the keyboard focus. False: it never has the focus and gets no keys.
BackColor The colour Cls clears it to (white when not given).
ToolboxIcon A 24 x 24 picture file in the project folder, shown in the designer's toolbox.
Description The toolbox tooltip (its name when not given).
DefaultEvent The event the designer opens when the control is double-clicked.</pre>
<h2>Properties, Methods, and Events</h2>
<p>The control's public members are what programs use:</p>
<ul>
<li>Public Property Get / Let (or Set) pairs and Public variables are its properties. A property with only Property Get is read-only, with only Property Let write-only. A property whose type is Integer, Long, or Byte is a whole number, Boolean is True / False, Single and Double (and Currency) are numbers, String, Date, and Variant are text; a property of an object type, an array, or a TYPE cannot be a property of a control.</li>
<li>A property declared As an ENUM is a choice of its members, as a built-in control's Alignment is: the designer's Properties window shows the member's name and a double-click steps to the next member, the form file stores the name (Look = Circle), and code sets it with a member, its number, or its name as text (Shape1.Look = Circle, Shape1.Look = 1, Shape1.Look = &quot;Circle&quot;). This needs the members numbered 0, 1, 2, and so on, each number once, as an ENUM numbers them when no values are given; an ENUM with other values (Small = 10) makes a whole-number property.</li>
<li>Public Subs and Functions are its methods. They take any arguments; a Function's value is the method's result.</li>
<li>Public Events are its events. RaiseEvent sends one to the program that has the control: its handler CtrlName_EventName runs with the arguments, and a ByRef parameter the handler changes (a number, a Boolean, or a String) comes back changed.</li>
</ul>
<p>Names that every control already has (Name, Left, Top, Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight, Weight, Visible, Enabled, ReadOnly, BackColor, ForeColor, Caption, Text, ToolTipText, ContextMenu, HelpTopic, DataSource, DataField, Tag, MousePointer ...) belong to the form: a control's own property of such a name is not used. Give your properties other names (Title instead of Caption, Value or Level instead of Text).</p>
<p>A property's default is the value it has after UserControl_Initialize ran. The form's .frm sets only the properties the designer user changed, through your Property Let, after Initialize.</p>
<h2>The UserControl Object</h2>
<p>Inside the control's code, UserControl is the control itself: the surface it draws on and the side the program sees.</p>
<pre> Member Description
------ -----------
Width, Height Its current size in pixels (read-only; the form's layout decides it).
MinWidth, MinHeight Its natural size: the form lays it out again when you change them.
Enabled False while the control, or a container it is in, is disabled (read-only).
HasFocus True while it has the keyboard focus (read-only).
CanGetFocus The header's CanGetFocus (read-only).
UserMode False while it sits in a form designer (the IDE's, or a form with Form.DesignMode = True), True in a running program. In the designer the code draws it, but the user's clicks and keys go to the designer.
Name The name the program gave the control (&quot;&quot; when a C program gave none).
SetFocus Gives it the keyboard focus.
Refresh Runs UserControl_Paint now and shows the result.
Invalidate Asks for UserControl_Paint at the next chance, once however often it is called before then: change many things (add a hundred items) and the control is drawn once.
PropertyChanged name Tells a designer that a property changed, so its property sheet shows the new value.
Cls, Line, PSet, Circle, Print, Point, PaintPicture, DrawFocusRect, TextWidth, TextHeight, Scale, ScaleX, ScaleY Drawing, as on a PictureBox.
DrawBevel, DrawButtonFace, DrawArrow, DrawScrollBar, DrawScrollArrow, ScrollBarClick, ScrollBarsNeeded, PrintAccel, TextWidthAccel, AccelKey Drawing in DVX's own look (bevels, button faces, arrows, upright and horizontal scroll bars and their arrow buttons, captions with an underlined access key), as on a PictureBox.
CurrentX, CurrentY, ForeColor, BackColor, FillColor, FillStyle, FontScale, DrawWidth, DrawStyle, AutoRedraw, ScaleMode, ScaleLeft, ScaleTop, ScaleWidth, ScaleHeight Drawing properties, as on a PictureBox.</pre>
<p>The drawing members work exactly as on a PictureBox (see Drawing on Forms and PictureBoxes). Write them with UserControl in front -- UserControl.Line, UserControl.Print -- as a form's code writes Me.Line: a drawing statement on its own (Line, Cls, Print) draws on the program's screen, not on the control.</p>
<p>The drawing stays until you draw again. UserControl_Paint runs when the control first appears, after its size changed, when you call Refresh, and after you call Invalidate; draw everything there and call UserControl.Invalidate (or UserControl.Refresh, to see the result at once) whenever what it shows changes.</p>
<h2>The Control's Events</h2>
<p>The program runs these procedures of the control's code when they exist. Each is a Private Sub with exactly these parameters:</p>
<pre> Procedure When
--------- ----
UserControl_Initialize () The control was made (before the form's property values are set).
UserControl_Terminate () The control is going away (its form unloads). It cannot draw any more.
UserControl_Resize () Its size changed (and once when it first appears).
UserControl_Paint () It must be drawn (after Resize, after Refresh).
UserControl_Click () The left button was pressed and let go over it.
UserControl_DblClick () A second quick left press.
UserControl_MouseDown (Button As Integer, Shift As Integer, X As Single, Y As Single) A button went down over it.
UserControl_MouseMove (Button As Integer, Shift As Integer, X As Single, Y As Single) The mouse moved over it (Button 0), or with the left button held after a press on it, anywhere.
UserControl_MouseUp (Button As Integer, Shift As Integer, X As Single, Y As Single) A button went up.
UserControl_MouseWheel (Delta As Integer) The wheel turned over it (Delta is positive downwards).
UserControl_KeyDown (KeyCode As Integer, Shift As Integer) A key went down while it has the focus.
UserControl_KeyPress (KeyAscii As Integer) A character key was typed.
UserControl_KeyUp (KeyCode As Integer, Shift As Integer) A key went up.
UserControl_GotFocus () It got the keyboard focus.
UserControl_LostFocus () It lost the keyboard focus.</pre>
<p>Button is vbLeftButton, vbRightButton, or vbMiddleButton (in MouseMove, the buttons held). Shift holds vbShiftMask, vbCtrlMask, and vbAltMask. X and Y are pixels from the control's top-left corner. The compiler reports a handler with other parameters.</p>
<p>These events are the control's own: the program does not see them. The program sees only the events the control raises. To let a program react to clicks, raise your own Click (Public Event Click, then RaiseEvent Click in UserControl_Click); an event named Click, DblClick, Change, KeyPress, KeyDown, KeyUp, MouseDown, MouseUp, MouseMove, or Scroll reaches the program's CtrlName_Click (and so on) handler as for any control. Give those events Visual Basic's parameters: Button, Shift, X, Y for MouseDown, MouseUp, and MouseMove; KeyCode, Shift for KeyDown and KeyUp; KeyAscii for KeyPress; Delta for Scroll. GotFocus and LostFocus reach the program by themselves.</p>
<h2>Using Controls in a Program</h2>
<p>In the IDE, File &gt; New UserControl (or File &gt; Add File with a .ctl file) adds a control to the open project; while the project is open the control is in the Toolbox, ready to be placed on the project's forms. In the project file, the .ctl file is listed in the [Controls] section of the project's .dbp:</p>
<pre><code>[Controls]
File0 = gauge.ctl
Count = 1</code></pre>
<p>When the program starts, its controls are registered before any form is loaded, so its forms can use them; they go away when the program ends. They belong to the program: other programs (and other copies of the same program) can have controls of the same name, and each program uses its own. The control's code runs in the program, with the program's rules: an error the code does not handle ends the program, and DoEvents works as anywhere.</p>
<h2>Installing a Control for Every Program</h2>
<p>A control project holds only controls (no forms): its .dbp says</p>
<pre><code>[Project]
Name = GAUGE
Type = Control
[Controls]
File0 = gauge.ctl
Count = 1</code></pre>
<p>Building it -- in the IDE, File &gt; Make Control (set the project's Type to Control in File &gt; Project Properties first); or with the BASIC compiler, bascomp gauge.dbp (on DVX, SYSTEM\BASCOMP.EXE) -- makes gauge.wgt, a control file. Copied into DVX's WIDGETS folder (in a folder of its own, like the controls DVX comes with), it is loaded when DVX starts: every program can use its controls, the designer's toolbox shows them with their ToolboxIcon and Description, and C programs create them by name. A control project may hold several controls and the modules they need; its help file goes beside the control file as for any widget.</p>
<p>All the programs using an installed control file share one copy of its code and its module variables: module-level code of the control project runs once, when the first of its controls is made. A control's own variables (its class members) are separate for each control. Because the code is shared:</p>
<ul>
<li>DoEvents does nothing in an installed control's code, and its code never lets another program run in between.</li>
<li>While its code runs for one program, another program that needs it (to paint or for an event) is turned away: the control keeps its old picture and the event is dropped (DVX.LOG notes it once).</li>
<li>An error its code does not handle is shown, and the control carries on; it does not end the program that was using it.</li>
</ul>
<h2>Limits</h2>
<ul>
<li>A control cannot hold other controls; it draws what it shows on its UserControl surface.</li>
<li>Properties are numbers, Booleans, text, and ENUM choices; a property of an ENUM whose members are not numbered 0, 1, 2 ... is a whole number in the Properties window.</li>
<li>CanGetFocus is fixed by the header (read-only in code).</li>
<li>UserControl_Terminate cannot draw: the surface is already gone.</li>
<li>A program cannot have a control of the same name as one installed in WIDGETS (the program stops with &quot;Control cannot be registered&quot;).</li>
</ul>
<p><a href="#ide.usercontrols">See also: UserControls in the IDE</a></p>
<p><a href="#lang.classes">See also: Objects and Class Modules</a></p>
<p><a href="#lang.events">See also: Events</a></p>
<p><a href="#ctrl.drawing">See also: Drawing on Forms and PictureBoxes</a></p>
</div>
<div class="topic" id="ctrl.terminal">
<h1>Terminal</h1>
<p>DVX Extension -- DVX Widget: ansiterm</p>
<p>A VT100/ANSI terminal emulator with a text-mode cell buffer, 16-color CGA palette, and scrollback history. Processes standard ANSI escape sequences (cursor control, erase, scroll, SGR colors, DEC private modes) typically used by DOS BBS software. Default size is 80 columns by 25 rows. Supports text selection with the mouse, Ctrl+C to copy, and Ctrl+V to send clipboard text as input. Shift+PgUp and Shift+PgDn page through the scrollback history and the mouse wheel scrolls it; any other key is sent to the host and returns the view to the live screen.</p>
<p>Its font must be fixed-pitch, every character the same width; given a proportional font it draws in the system font instead. A fixed-pitch font of any size changes the size of every cell.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
---------- ------- -------------------------------------------
Cols Integer Number of character columns (1-512). Setting Cols or Rows gives the terminal a new size, starting as a new terminal: empty screen and scrollback, modes the host set reset (its colors and connection stay); set the form's AutoSize to True afterwards to fit the window to it.
Music Boolean Whether ANSI music sequences (ESC[M, ESC[N, ESC[| followed by PLAY text, as BBSes send) are recognised (True at first): each raises the Music event instead of being shown. False: ESC[M is always Delete Line, and ESC[N and ESC[| do nothing.
Rows Integer Number of character rows (1-512).
Scrollback Integer Maximum number of scrollback lines. Older lines are dropped (default 500). Setting it discards the existing history.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
Clear Clear the terminal screen and reset the cursor to the home position.
Copy() Copy the selected text to the clipboard and clear the selection. Returns False when nothing is selected.
Paste Send the clipboard's text to the attached connection as if it were typed (new lines as Enter), as Ctrl+V does. With no connection attached it goes to the Send event.
Poll Poll the attached communication channel for incoming bytes and feed them into the ANSI parser.
ResetColors Back to the standard 16 colors.
SetColor index%, color&amp; The color (RGB(), as ForeColor takes it) of text attribute index (0-15, in CGA order: black, blue, green, cyan, red, magenta, brown, light gray, then their bright forms). An index outside 0-15 is ignored.
Write text$ Write a string to the terminal with full ANSI escape processing. Every byte of the string is written, CHR$(0) included (a CHR$(0) itself is padding and shows nothing, as on other terminals), so text read from a connection of the program's own can be written as it came. A very long text appears over the next few moments, a part at a time, so the program and the rest of DVX keep going; Clear after it still clears all of it.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Description
----- -----------
Bell A bell character (BEL, CHR$(7)) arrived. The terminal makes no sound itself: the program decides (Beep, a sound of its own, or nothing).
Music (Macro As String) An ANSI music sequence arrived (Music True): Macro is its PLAY text, to play with PLAY or MusicLoadMacro.
Send (Bytes As String) The terminal has bytes for the host and no connection is attached: the keys the user typed, a paste, or the terminal's answer to the host asking where the cursor is. A program with a connection of its own (a TCP socket, a modem it drives itself) sends Bytes on. Bytes may hold any character, CHR$(0) included.</pre>
<p>No default event. The common events are raised too.</p>
<h2>Serial Communication</h2>
<p>The conn.bas library connects a Terminal the way the Terminal program does -- a serial port, a modem, the secure link, or Telnet -- with capture, answerback, and file transfers (ConnAttach; see Include Libraries). For a packet link of your own, use the comm.bas library:</p>
<pre><code>Dim link As Long
link = CommOpen(1, 115200, 8, &quot;N&quot;, 1, SER_HANDSHAKE_NONE)
If link &lt;&gt; 0 Then
If CommHandshake(link, &quot;secret&quot;) Then
CommAttach link, &quot;Terminal1&quot;, 0, True
Else
MsgBox &quot;Handshake failed&quot;
End If
End If</code></pre>
<p>The passphrase is optional. Both ends must give the same passphrase, or both give none; otherwise CommHandshake returns False. See comm.bas for the full communications API.</p>
<h2>A Connection of Your Own</h2>
<p>Without an attached connection, Write shows what the program received and the Send event hands over what the terminal would send back:</p>
<pre><code>Sub Sock_Data ()
Terminal1.Write ReceivedText$
End Sub
Sub Terminal1_Send (Bytes As String)
SendToHost Bytes
End Sub</code></pre>
<h2>Example</h2>
<pre><code>Begin Terminal Terminal1
MinWidth = 640
MinHeight = 400
End
Sub Form1_Load ()
Terminal1.Write &quot;Welcome!&quot; &amp; Chr$(13) &amp; Chr$(10)
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.frame">
<h1>Frame</h1>
<p>VB Equivalent: Frame -- DVX Widget: frame (titled container)</p>
<p>A container with a titled border. Child controls are placed inside the frame using VBox layout. In the .frm file, nest Begin/End blocks inside the Frame block.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Caption String The title displayed in the frame border.</pre>
<pre> Property Type Description
-------- ------- -------------------------------------------
Alignment Enum Where the children sit along the frame from top to bottom when they do not fill it: Left (the top, the default), Center, or Right (the bottom).
Padding Integer Space in pixels between the border and the children: 4 unless set; 0 is none.
Spacing Integer Space in pixels between one child and the next: none unless set.</pre>
<p>No type-specific methods or events.</p>
<p>Setting Enabled = False on a Frame disables every control inside it for mouse and keyboard input.</p>
<p>Container: Yes</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin Frame Frame1
Caption = &quot;Options&quot;
Begin CheckBox Check1
Caption = &quot;Option A&quot;
End
Begin CheckBox Check2
Caption = &quot;Option B&quot;
End
End</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.hbox">
<h1>HBox</h1>
<p>DVX Extension -- DVX Widget: hbox (horizontal layout container)</p>
<p>A container that arranges its children horizontally, left to right. No visible border. Use Weight on children to distribute extra space proportionally.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Alignment Enum Where the children sit along the row when they do not fill it: Left (the left, the default), Center, or Right (the right).
Padding Integer Space in pixels between the edge of the box and the children: 4 unless set; 0 is none.
Spacing Integer Space in pixels between one child and the next: 4 unless set; 0 is none.</pre>
<p>Alignment = Right puts a row of buttons at the right, as dialog boxes have them.</p>
<p>No type-specific methods or events.</p>
<p>Container: Yes</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin HBox ButtonRow
Spacing = 4
Begin CommandButton Command1
Caption = &quot;OK&quot;
End
Begin CommandButton Command2
Caption = &quot;Cancel&quot;
End
End</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.vbox">VBox</a></p>
</div>
<div class="topic" id="ctrl.vbox">
<h1>VBox</h1>
<p>DVX Extension -- DVX Widget: vbox (vertical layout container)</p>
<p>A container that arranges its children vertically, top to bottom. No title or border. Use Weight on children to distribute extra space proportionally.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Alignment Enum Where the children sit along the column when they do not fill it: Left (the top, the default), Center, or Right (the bottom).
Padding Integer Space in pixels between the edge of the box and the children: 4 unless set; 0 is none.
Spacing Integer Space in pixels between one child and the next: 4 unless set; 0 is none.</pre>
<p>No type-specific methods or events.</p>
<p>Container: Yes</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin VBox Column1
Spacing = 4
Begin Label Label1
Caption = &quot;Name:&quot;
End
Begin TextBox Text1
End
End</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.hbox">HBox</a></p>
</div>
<div class="topic" id="ctrl.button">
<h1>CommandButton</h1>
<p>VB Equivalent: CommandButton -- DVX Widget: button | Name Prefix: Command</p>
<p>A push button that triggers an action when clicked. The Caption may include a '&amp;' before a character to mark an accelerator key (e.g. &quot;&amp;OK&quot; underlines 'O', and Alt+O activates the button).</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------ -------------------------------------------
Caption String The text displayed on the button. Use '&amp;' for an accelerator key.
Default Boolean True: Enter presses this button, wherever the focus is on its form (unless the focus is on another button, which Enter presses instead).
Cancel Boolean True: Escape presses this button, wherever the focus is on its form.</pre>
<p>Default and Cancel make a form work like a dialog box: give the OK button Default = True and the Cancel button Cancel = True. If several buttons on a form have the property, the first one (in the order they were made) that is visible and enabled is pressed.</p>
<p>No type-specific methods or events.</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin Form Form1
Caption = &quot;Button Demo&quot;
Begin CommandButton Command1
Caption = &quot;&amp;Click Me!&quot;
End
End
Sub Command1_Click ()
MsgBox &quot;Button was clicked!&quot;
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.picturebox">
<h1>PictureBox</h1>
<p>VB Equivalent: PictureBox -- DVX Widget: canvas | Name Prefix: Picture</p>
<p>A drawing surface (canvas). Supports drawing lines, rectangles, circles, text, and individual pixels. Can load BMP, PNG, JPEG, and GIF images and save BMP or PNG images. The default canvas size is 64x64 pixels.</p>
<p>Colors are Visual Basic RGB values, &amp;HBBGGRR, as RGB() makes them (RGB(255, 0, 0) or &amp;HFF is red).</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ---- -----------
BorderStyle Enum 0 - None: no frame, the control is exactly the size of the drawing. 1 - FixedSingle (the default): a sunken frame 2 pixels wide around the drawing. Mouse coordinates and drawing positions start inside the frame either way.
ImageHeight Integer Height of the drawing in pixels (read-only). After Load it is the loaded image's height.
ImageWidth Integer Width of the drawing in pixels (read-only). After Load it is the loaded image's width.
Picture String The picture file the canvas shows (&quot;&quot; when it shows none). Setting it to a file name, or to LoadPicture(path$), loads that file as Load does; LoadPictureData(bytes$) shows a picture from bytes; setting it to &quot;&quot; (or LoadPicture(&quot;&quot;)) clears the canvas to white. Clear and Resize wipe the picture, so Picture becomes &quot;&quot;. The default property: Picture1 = &quot;logo.bmp&quot; loads it.</pre>
<p>Load and Save return 0 on success and -1 on failure (missing or unreadable file, unsupported format, path that cannot be written). Call them as functions to check the result, or as statements to ignore it. A failed Load leaves the drawing unchanged.</p>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
Clear color% Fill the entire canvas with the specified color.
DrawLine x0%, y0%, x1%, y1%, color% Draw a line between two points.
DrawRect x%, y%, w%, h%, color% Draw a rectangle outline.
DrawText x%, y%, text$ Draw text at the given position.
FillCircle cx%, cy%, radius%, color% Draw a filled circle.
FillRect x%, y%, w%, h%, color% Draw a filled rectangle.
GetPixel(x%, y%) Returns the color at a pixel. With fewer than 16 million colors on the screen it is the color the screen shows: black, white, and full colors such as RGB(255, 0, 0) read back exactly, others may differ slightly.
Load(path$) Load a BMP, PNG, JPEG, or GIF image; the canvas takes the image's size. Returns 0 on success, -1 on failure.
Resize w%, h% Resize the canvas to new dimensions. The drawing is cleared to white.
Save(path$) Save the canvas: BMP when path$ ends in .bmp, PNG otherwise. Returns 0 on success, -1 on failure.
SetPenColor color% Set the drawing color for subsequent operations.
SetPenSize size% Set the pen/brush size in pixels (1 to 255; larger values use 255).
SetPictureData(bytes$ [, name$]) Show the picture held in bytes$ (the bytes of a BMP, PNG, JPEG, or GIF file, such as HttpBody$ or ResGetData$ gives) as Load shows a file, without keeping a Picture object as Picture = LoadPictureData(bytes$) does. Picture then reads name$ (&quot;&quot; without it). Returns True, or False (the drawing unchanged) when the bytes are not a picture.
SetPixel x%, y%, color% Set the color of a single pixel.</pre>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Picture1.Resize 200, 150
Picture1.Clear &amp;HFFFFFF
Picture1.SetPenSize 2
Picture1.DrawRect 10, 10, 180, 130, &amp;H000000
Picture1.FillCircle 100, 75, 40, RGB(255, 0, 0)
Picture1.DrawText 60, 130, &quot;Hello!&quot;
If Picture1.Save(&quot;output.bmp&quot;) &lt;&gt; 0 Then
MsgBox &quot;Could not save output.bmp&quot;
End If</code></pre>
<p>A PictureBox also has Visual Basic's drawing methods and properties (Cls, PSet, Line, Circle, Point, Print, PaintPicture, DrawFocusRect, DrawBevel, DrawButtonFace, DrawArrow, DrawScrollBar, DrawScrollArrow, ScrollBarClick, ScrollBarsNeeded, PrintAccel, Scale, CurrentX, CurrentY, ForeColor, BackColor, DrawWidth, FillColor, FillStyle, FontScale, AutoRedraw, ScaleMode, ScaleLeft, ScaleTop, ScaleWidth, ScaleHeight) and a Paint event: see Drawing on Forms and PictureBoxes.</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.drawing">Drawing on Forms and PictureBoxes</a></p>
</div>
<div class="topic" id="ctrl.checkbox">
<h1>CheckBox</h1>
<p>VB Equivalent: CheckBox -- DVX Widget: checkbox</p>
<p>A toggle control with a label. The checked state is exposed as a Boolean. Supports accelerator keys (put '&amp;' before a character in the Caption). Press Space or Enter to toggle when focused.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Caption String The text displayed next to the checkbox.
Value Boolean True if checked, False if unchecked.</pre>
<p>No type-specific methods or events.</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin CheckBox Check1
Caption = &quot;Enable feature&quot;
End
Sub Check1_Click ()
If Check1.Value Then
Label1.Caption = &quot;Feature ON&quot;
Else
Label1.Caption = &quot;Feature OFF&quot;
End If
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.combobox">
<h1>ComboBox</h1>
<p>VB Equivalent: ComboBox -- DVX Widget: combobox (editable text field + drop-down list, default maxLen 256)</p>
<p>A combination of a single-line text input and a drop-down list. The user can either type a value or pick one from the list. Selecting a list item copies its text into the edit field. Supports the same AddItem / RemoveItem / Clear / SetItems / List methods as ListBox.</p>
<p>Its font must be fixed-pitch, every character the same width; the designer's Font dialog offers only those families for it. Given a proportional font it draws in the system font instead.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
--------- ------- -------------------------------------------
Text String The text in the editable field.
ListIndex Integer Index of the currently selected list item (-1 = user typed something not in the list).
MaxLength Integer Most characters the edit field holds (0 = the default, 256). Longer text is cut when it is set.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
AddItem text$ Append an item to the drop-down list.
Clear Remove all items.
List(index%) Return the text of the item at the given index.
ListCount() Return the number of items in the list.
RemoveItem index% Remove the item at the given index. The selection stays on the same item; removing the selected item leaves no selection (the text is kept).
SetItems items$ Replace all the items at once from a &quot;|&quot;-separated list (&quot;Red|Green|Blue&quot;; every &quot;|&quot; separates two items, &quot;&quot; empties the list). Nothing is selected afterwards. The text is kept.</pre>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin ComboBox Combo1
End
Sub Form1_Load ()
Combo1.AddItem &quot;Small&quot;
Combo1.AddItem &quot;Medium&quot;
Combo1.AddItem &quot;Large&quot;
End Sub
Sub Combo1_Change ()
Label1.Caption = &quot;Selected: &quot; &amp; Combo1.Text
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.listbox">See ListBox for details</a></p>
</div>
<div class="topic" id="ctrl.data">
<h1>Data</h1>
<p>VB Equivalent: Data -- DVX Widget: data | Name Prefix: Data</p>
<p>A data access control that connects to a SQLite database and provides record navigation. Other controls bind to a Data control via their DataSource and DataField properties. The Data control cache is populated by calling Refresh. Move operations and Refresh auto-save the current row if dirty; a move is refused while the save fails, and Refresh discards an edit that cannot be saved. Updates find the record by the key value it was loaded with, so the key column itself can be edited; a key stored as a number in a column without a declared type, or a missing (NULL) key, is still found as long as it identifies exactly one record. Writing a field back with the value it already has is not an edit and does not fire Validate. While a Validate handler runs, MoveFirst, MoveLast, MoveNext, MovePrevious, AddNew, Refresh, and Update on the same Data control are ignored (they would save, and validate, the same record again); Delete is allowed. A RecordSource that is a SELECT query is read-only, and edits made to its records are dropped when the current record changes.</p>
<p>A big record set is read a part at a time: Refresh reads the first 64 records, and the rest arrive while your program and DVX go on, so RecordCount grows until every record is in. MoveLast, AddNew, Update, and Delete read the rest first, and MoveNext and AbsolutePosition read as far as they need. Until every record is in, other programs (and SQLExec) cannot change that database: their changes fail with &quot;database is locked&quot;.</p>
<p>EOF and BOF work as in Visual Basic, so a loop like this reads every record once:</p>
<pre><code>Data1.Refresh
Do Until Data1.EOF
total = total + Val(Data1.GetField(&quot;amount&quot;))
Data1.MoveNext
Loop</code></pre>
<p><a href="#ctrl.databinding">See Data Binding for details</a></p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
------------ ------- -------------------------------------------
DatabaseName String Path to the SQLite database file.
RecordSource String Table name or SQL SELECT query for the recordset.
KeyColumn String Primary key column name (used for UPDATE/DELETE operations).
Caption String Text displayed on the navigator bar.
BOF Boolean True after MovePrevious at the first record (which stays the current record), or when there are no records; moving onto a record clears it (read-only).
EOF Boolean True after MoveNext at the last record (which stays the current record), or when there are no records; moving onto a record clears it (read-only).
MasterSource String Name of a master Data control (for master-detail binding).
MasterField String Column in the master recordset to read for the filter value.
DetailField String Column in this recordset that matches the master field.
RecordCount Long The number of records read so far: all of them once the rest has arrived, or after MoveLast (read-only).
FieldCount Integer The number of columns (read-only).
AbsolutePosition Long The current record, 0 for the first (-1 when there are none). Setting it moves there (saving pending changes first, as the Move methods do) and fires Reposition; a value out of range does nothing.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Parameters Description
------------ ---------- -------------------------------------------
MoveFirst (none) Navigate to the first record.
MoveLast (none) Navigate to the last record (every record is read first).
MoveNext (none) Navigate to the next record.
MovePrevious (none) Navigate to the previous record.
AddNew (none) Append a blank record and move to it.
Delete (none) Delete the current record.
Refresh (none) Re-query the database and reload records.
Update (none) Write pending changes to the database.
GetField(col$) The current record's value of a column, as text, without a bound control (&quot;&quot; for an unknown column).
SetField col$, value$ Change a column of the current record; written to the database by Update (or when the record changes).
FieldName(index%) The name of a column, 0 for the first (&quot;&quot; past the last).
GetCell(row&amp;, col%) The text of any cell (both from 0) without moving the current record (&quot;&quot; outside).</pre>
<h2>Type-Specific Events</h2>
<pre> Event Parameters Description
---------- ----------------- -------------------------------------------
Reposition (none) Fires after the current record changes. Default event.
Validate Cancel As Integer Fires before writing. Set Cancel = 1 to abort.</pre>
<p>Default Event: Reposition</p>
<h2>Example</h2>
<pre><code>Begin Data Data1
DatabaseName = &quot;books.db&quot;
RecordSource = &quot;titles&quot;
KeyColumn = &quot;id&quot;
End
Begin TextBox Text1
DataSource = &quot;Data1&quot;
DataField = &quot;title&quot;
End
Sub Form1_Load ()
Data1.Refresh
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.databinding">Data Binding</a></p>
<p><a href="#ctrl.dbgrid">DBGrid</a></p>
</div>
<div class="topic" id="ctrl.dbgrid">
<h1>DBGrid</h1>
<p>VB Equivalent: DBGrid -- DVX Widget: dbgrid | Name Prefix: DBGrid</p>
<p>A data-bound grid that displays records from a Data control in a tabular format. Columns auto-populate from the query results. Bind the grid using the DataSource property. Click a column header to sort; drag a column border to resize. The highlighted row is always the bound Data control's current record: selecting a row moves the Data control's cursor, and navigating the Data control moves the highlight. Re-binding keeps the sort order and column settings, and a column width set by dragging a border is kept. A column's automatic width fits its header and its first 200 records; text wider than its column is clipped. Records that arrive later (a Data control reads a big record set a part at a time) appear as they come, in the grid's sort order. The mouse wheel scrolls the rows without changing the current record.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
---------- ------- -------------------------------------------
DataSource String Name of the Data control that supplies records.
GridLines Boolean Show or hide grid lines between cells (default: True).
SelectedRow Integer Index of the current record's row (-1 = no records). Setting it moves the Data control's cursor; negative values are ignored.
Text String The current record's first visible column (&quot;&quot; with no record), read-only. It is the grid's default property, so Print DBGrid1 prints it. For another field, read the Data control's recordset or the field's bound control.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Parameters Description
---------------- ------------------------------- -------------------------------------------
Refresh (none) Reload and redraw the grid from the Data control.
SetColumnHeader Field As String, Header As String Set the displayed header text for a column.
SetColumnVisible Field As String, Visible As Boolean Show or hide a column by field name.
SetColumnWidth Field As String, Width As Integer Set the pixel width of a column by field name.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Parameters Description
-------- ---------- -------------------------------------------
Click (none) Fires when a row is clicked.
DblClick (none) Fires when a row is double-clicked. Default event.</pre>
<p>Default Event: DblClick</p>
<h2>Example</h2>
<pre><code>Begin Data Data1
DatabaseName = &quot;books.db&quot;
RecordSource = &quot;titles&quot;
End
Begin DBGrid DBGrid1
DataSource = &quot;Data1&quot;
GridLines = True
End
Sub Form1_Load ()
Data1.Refresh
End Sub
Sub DBGrid1_DblClick ()
MsgBox &quot;Opening row &quot; &amp; Str$(Data1.BOF)
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.data">Data</a></p>
<p><a href="#ctrl.databinding">Data Binding</a></p>
</div>
<div class="topic" id="ctrl.dropdown">
<h1>DropDown</h1>
<p>DVX Extension -- DVX Widget: dropdown (non-editable drop-down list)</p>
<p>A read-only drop-down list. Unlike ComboBox, the user cannot type free text; they can only select from the provided items. Supports AddItem / RemoveItem / Clear / SetItems / List. Use the Up and Down keys to change the choice. F4, Alt+Down, Space, or Enter opens the list; in the open list use the arrow keys to move and Enter (or F4, Alt+Down) to pick. Esc closes the list without changing the choice.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
--------- ------- -------------------------------------------
ListIndex Integer Index of the currently selected item (-1 = none).</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
AddItem text$ Append an item to the drop-down list.
Clear Remove all items.
List(index%) Return the text of the item at the given index.
ListCount() Return the number of items in the list.
RemoveItem index% Remove the item at the given index. The selection stays on the same item; removing the selected item leaves no selection.
SetItems items$ Replace all the items at once from a &quot;|&quot;-separated list (&quot;Red|Green|Blue&quot;; every &quot;|&quot; separates two items, &quot;&quot; empties the list). Nothing is selected afterwards.</pre>
<p>Default Event: Change (fires when the user picks a new item; Click fires only when the arrow opens the popup)</p>
<h2>Example</h2>
<pre><code>Begin DropDown DropDown1
End
Sub Form1_Load ()
DropDown1.AddItem &quot;Small&quot;
DropDown1.AddItem &quot;Medium&quot;
DropDown1.AddItem &quot;Large&quot;
DropDown1.ListIndex = 1
End Sub
Sub DropDown1_Change ()
Label1.Caption = &quot;Picked: &quot; &amp; DropDown1.List(DropDown1.ListIndex)
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.listbox">See ListBox for details</a></p>
</div>
<div class="topic" id="ctrl.helppane">
<h1>HelpPane</h1>
<p>VB Equivalent: (none) -- DVX Widget: helpview</p>
<p>Shows one topic of a help file the way the DVX Help Viewer does: headings, paragraphs, and lists wrapped to the control's width, notes, code, tables, pictures, rules, and links, with a scroll bar when the topic is longer than the control. Open the help file with hlpfile.bas (HlpOpen) and give its handle to ShowTopic. With a TreeView for the table of contents and a few buttons, a HelpPane makes a complete help viewer (see Help Files under Include Libraries).</p>
<p>A link is followed with a click, or with Enter or Space after Tab has moved to it: the HelpPane fires LinkClick with the ID of the topic the link names and remembers it in LinkTopic. It does not change topic by itself -- the LinkClick event procedure usually shows the topic and adds it to its Back list. Everything a topic shows is copied when it is shown, so closing the help file afterwards does not change what the HelpPane shows.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type R/W Description
--------- ------- --- -------------------------------------------
Topic Integer R The topic shown (numbered from 0, as hlpfile.bas numbers them); -1 when nothing is shown.
LinkTopic String R The topic ID of the last link followed (&quot;&quot; before any).</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
ShowTopic hlpFile&amp;, topic&amp; Show a topic of an open help file (an HlpOpen handle) from the top. A topic that is not in the file, or a closed handle, shows nothing.
Clear Show nothing.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Parameters Description
--------- ----------------- -------------------------------------------
LinkClick Topic As String A link was followed (clicked, or Enter or Space on it). Topic is the ID of the topic it names; HlpFindTopic gives its number.</pre>
<p>Default Event: LinkClick</p>
<h2>Example</h2>
<pre><code>' hlpfile.bas in the project
Dim hlp As Long
Sub Form1_Load ()
hlp = HlpOpen(App.Path + &quot;\MYAPP.HLP&quot;)
HelpPane1.ShowTopic hlp, HlpStartTopic(hlp, &quot;&quot;)
End Sub
Sub HelpPane1_LinkClick (Topic As String)
HelpPane1.ShowTopic hlp, HlpFindTopic(hlp, Topic)
Me.Caption = HlpTopicTitle$(hlp, HelpPane1.Topic)
End Sub
Sub Form1_Unload ()
HlpClose hlp
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.imagebutton">
<h1>ImageButton</h1>
<p>DVX Extension -- DVX Widget: imagebutton</p>
<p>A button that displays an image instead of text. Has the same press/release behavior as CommandButton, but shows a bitmap. Typically used inside a Toolbar.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
----------- ------- -------------------------------------------
Picture Picture Path to an image file to load (or a Picture object from LOADPICTURE or LOADPICTUREDATA); a program, widget, or library file gives its icon. Reads back as a Picture object for the picture shown, which stands for the file name (&quot;&quot; for a picture from bytes) where a value is needed. Setting it to &quot;&quot; clears the image. A file that cannot be loaded leaves the image and Picture unchanged.
ImageWidth Integer Width of the loaded image in pixels (read-only).
ImageHeight Integer Height of the loaded image in pixels (read-only).</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
SetPictureData(bytes$ [, name$]) Show the picture held in bytes$ (the bytes of a BMP, PNG, JPEG, or GIF file, such as HttpBody$ or ResGetData$ gives), as Picture = LoadPictureData(bytes$) does but without keeping a Picture object, so it suits showing many pictures in turn. Picture then reads name$ (&quot;&quot; without it). Returns True, or False (the picture unchanged) when the bytes are not a picture.</pre>
<p>No type-specific events.</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin Toolbar Toolbar1
Begin ImageButton ImageButton1
Picture = &quot;icons/save.bmp&quot;
End
Begin ImageButton ImageButton2
Picture = &quot;icons/open.bmp&quot;
End
End
Sub ImageButton1_Click ()
MsgBox &quot;Save clicked&quot;
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.image">
<h1>Image</h1>
<p>VB Equivalent: Image -- DVX Widget: image</p>
<p>A static image display control. Loads bitmap images from file. Set the Picture property at design-time (in the .frm file) or at runtime to load a file.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
----------- ------- -------------------------------------------
Picture Picture Path to an image file to load (or a Picture object from LOADPICTURE or LOADPICTUREDATA); a program, widget, or library file gives its icon. Reads back as a Picture object for the picture shown, which stands for the file name (&quot;&quot; for a picture from bytes) where a value is needed. Setting it to &quot;&quot; clears the image. A file that cannot be loaded leaves the image and Picture unchanged. A disabled Image is drawn grayed (its transparent color stays transparent).
Stretch Boolean When True, an image larger than the control is scaled down to fit, keeping its proportions; a smaller image stays at natural size. When False, the image is shown at natural size.
ImageWidth Integer Width of the loaded image in pixels (read-only).
ImageHeight Integer Height of the loaded image in pixels (read-only).
MaskColor Long The transparent colour (an RGB value): with UseMaskColor True, pixels of this colour are not drawn, so the form shows through.
UseMaskColor Boolean True leaves out the pixels of MaskColor (default False).</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
SetPictureData(bytes$ [, name$]) Show the picture held in bytes$ (the bytes of a BMP, PNG, JPEG, or GIF file, such as HttpBody$ or ResGetData$ gives), as Picture = LoadPictureData(bytes$) does but without keeping a Picture object, so it suits showing many pictures in turn. Picture then reads name$ (&quot;&quot; without it). Returns True, or False (the picture unchanged) when the bytes are not a picture.</pre>
<p>No type-specific events.</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin Image Image1
Picture = &quot;assets/logo.bmp&quot;
Stretch = True
End
Sub Image1_Click ()
MsgBox &quot;Size: &quot; &amp; Str$(Image1.ImageWidth) &amp; &quot;x&quot; &amp; Str$(Image1.ImageHeight)
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.label">
<h1>Label</h1>
<p>VB Equivalent: Label -- DVX Widget: label</p>
<p>A static text label. Supports left, center, and right alignment. Put '&amp;' before a character in the Caption to define an accelerator that moves focus to the next focusable control.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
--------- ---- -------------------------------------------
Caption String The text displayed by the label.
Alignment Enum Text alignment: Left (default), Center, or Right.</pre>
<p>No type-specific methods or events.</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Begin Label Label1
Caption = &quot;Hello, World!&quot;
Alignment = &quot;Center&quot;
End</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.listbox">
<h1>ListBox</h1>
<p>VB Equivalent: ListBox -- DVX Widget: listbox</p>
<p>A scrollable list of selectable items. Items are managed via methods (AddItem, RemoveItem, Clear). Supports single and multi-select modes, drag-to-reorder, and keyboard navigation with type-ahead search. When the box is narrower than its longest item (its width limited by MaxWidth or by the form), a horizontal scroll bar appears; it and the Left and Right keys scroll the items sideways a character at a time.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
--------- ------- -------------------------------------------
ListIndex Integer Index of the currently selected item (-1 = no selection).
Text String The selected item (&quot;&quot; with none); the default property, so Print List1 prints it. Setting it selects the first item that is that text (case ignored); with none, the selection stays as it is.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Parameters Description
--------------- --------------------------------------- -------------------------------------------
AddItem Text As String Add an item to the end of the list.
Clear (none) Remove all items from the list.
ClearSelection (none) Deselect all items.
IsItemSelected Index As Integer Returns True if the item at Index is selected.
List Index As Integer Return the text of the item at the given index.
ListCount (none) Return the number of items in the list.
RemoveItem Index As Integer Remove the item at the given index. Items after it keep their selection; removing the selected item leaves no selection.
SelectAll (none) Select all items (multi-select mode).
SetItemSelected Index As Integer, Selected As Boolean Select or deselect a specific item.
SetItems Items As String Bulk-load items from a pipe-delimited string (e.g. &quot;Red|Green|Blue&quot;). Replaces existing items. Every &quot;|&quot; separates two items (&quot;a|&quot; is &quot;a&quot; and an empty item); &quot;&quot; empties the list.
SetMultiSelect Multi As Boolean Enable or disable multi-select mode.
SetReorderable Reorderable As Boolean Enable or disable drag-to-reorder.</pre>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Sub Form1_Load ()
List1.AddItem &quot;Apple&quot;
List1.AddItem &quot;Banana&quot;
List1.AddItem &quot;Cherry&quot;
End Sub
Sub List1_Click ()
Dim idx As Integer
idx = List1.ListIndex
If idx &gt;= 0 Then
Label1.Caption = &quot;Selected: &quot; &amp; List1.List(idx)
End If
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.combobox">ComboBox</a></p>
<p><a href="#ctrl.dropdown">DropDown</a></p>
</div>
<div class="topic" id="ctrl.listview">
<h1>ListView</h1>
<p>VB Equivalent: ListView -- DVX Widget: listview</p>
<p>A multi-column list with column headers. Supports sorting, multi-select, and drag-to-reorder.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type R/W Description
---------- ------- --- -------------------------------------------
ListIndex Integer R/W Index of the currently selected row (-1 = none).
SortColumn Integer R/W The column the list is sorted by, -1 when it is unsorted: what SetSort or the user's last click on a column header chose. Setting it sorts by that column in the current SortOrder (ascending when the list was unsorted); -1 unsorts the list.
SortOrder Integer R/W The order of the sort: 0 = none, 1 = ascending, 2 = descending (a click on the same header again reverses it). Setting it re-sorts the SortColumn in that order; 0 unsorts the list, and an unsorted list stays unsorted.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
AddItem text$ Add a row (sets first column text).
Clear Remove all rows.
ClearSelection Deselect all rows.
GetCell$(row%, col%) Returns the text of a cell.
IsItemSelected(index%) Returns True if the row is selected.
ListCount() Returns the number of rows (the same as RowCount; also read as the ListCount property).
RemoveItem index% Remove a row by index. Rows after it keep their selection; removing the selected row leaves no selection.
RowCount() Returns the number of rows.
SelectAll Select all rows.
SelectedRows$() Returns the numbers of the selected rows (as IsItemSelected numbers them) separated by spaces, &quot;&quot; when none: one call instead of IsItemSelected for every row of a long list.
SetCell row%, col%, text$ Set the text of a cell.
SetColumns spec$ Define columns. Pipe-delimited &quot;Name,Width,Align|Name,Width&quot;: the width in characters (missing or 0 = as wide as the contents), then Left (the default), Center, or Right for the column's text.
SetItemSelected index%, selected Select or deselect a row.
SetMultiSelect multi Enable or disable multi-select.
SetReorderable reorderable Enable or disable row reordering.
SetRows text$ Replace all the rows at once: one row per line (separated by CHR$(10)), cells separated by CHR$(9) (Tab); missing cells are blank and extra ones are dropped. Much faster than AddItem and SetCell for long lists. The selection is cleared and the cursor goes to the first row.
SetSort col%, dir% Sort by column. dir: 0=none, 1=ascending, 2=descending. An invalid column or direction clears the sort. Has no effect while reordering is enabled.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Parameters Description
----------- ---------------------- -------------------------------------------
ColumnClick Column As Integer A column header was clicked (Column 0 is the first). The list has already sorted itself by that column's text (the same column again reverses), with or without a handler; a program that orders the rows itself calls SetSort -1, 0 in the handler (or SetSort for another order) and fills the list in its own order.</pre>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>ListView1.SetColumns &quot;Name,20|Size,10|Type,15&quot;
ListView1.AddItem &quot;readme.txt&quot;
ListView1.SetCell 0, 1, &quot;1024&quot;
ListView1.SetCell 0, 2, &quot;Text&quot;
ListView1.SetSort 0, 1
' Many rows at once; the size column right-aligned
ListView2.SetColumns &quot;Name,14|Size,10,Right&quot;
ListView2.SetRows &quot;a.txt&quot; &amp; Chr$(9) &amp; &quot;120&quot; &amp; Chr$(10) &amp; &quot;b.txt&quot; &amp; Chr$(9) &amp; &quot;4,096&quot;</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.progressbar">
<h1>ProgressBar</h1>
<p>VB Equivalent: ProgressBar -- DVX Widget: progressbar</p>
<p>A progress indicator bar, lying flat (the default) or standing upright.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Value Integer Current progress value (0-100).
Vertical Boolean True: the bar stands upright and fills from the bottom up. False (the default): it lies flat and fills from left to right. Can be set in the designer or at run time.</pre>
<p>No type-specific events or methods. No default event.</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.optionbutton">
<h1>OptionButton</h1>
<p>VB Equivalent: OptionButton -- DVX Widget: radio (radio group + radio button) | Name Prefix: Option</p>
<p>A radio button for mutually exclusive choices. OptionButtons placed in the same container form a group: selecting one clears the others. The Value property is True for the selected button.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Caption String The text displayed next to the radio button.
Value Boolean True when this button is selected. Setting it to True selects this button and clears the others in its container; setting it to False deselects it. Setting Value does not raise Click.
OptionIndex Integer The index of this button among the OptionButtons of its container (read-only).</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Parameters Description
----------- ----------------- -------------------------------------------
GetSelected (none) Returns the index (as OptionIndex counts) of the selected OptionButton of this button's container, or -1 when none is: one call instead of reading every button's Value.
SetSelected Index As Integer Select the OptionButton at the given index within this button's container.</pre>
<p>Default Event: Click</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.richedit">
<h1>RichEdit</h1>
<p>VB Equivalent: RichTextBox -- DVX Widget: richedit</p>
<p>A text box for text in many fonts, sizes, and colors, bold, italic, underlined, or struck through, in paragraphs aligned left, centered, or right -- a small word processor's page. The user types, selects, and edits as in any text box; a program reads and changes the selection's look with the Sel properties, and the whole text, with its looks, as RTF (Rich Text Format, the format word processors save), so it can be saved to a file and loaded again.</p>
<p>Text starts in the control's own font (FontName, FontSize, and the other Font properties, or the form's) and in its ForeColor; text left in them follows the control when they change. The Sel properties read the first character of the selection; setting one changes the selection, or with nothing selected, the text typed next. SelStart counts characters from 0, and the break between two paragraphs is one character.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ---- -----------
TextRTF String The whole text with its fonts, styles, colors, and alignment, as RTF. Setting it replaces the text (plain text is taken as it is).
SelRTF String The selection as RTF. Setting it replaces the selection.
SelStart Integer Where the selection starts (the caret when nothing is selected).
SelLength Integer How many characters are selected.
SelText String The selection's text. Setting it replaces the selection with plain text.
SelBold Boolean Bold.
SelItalic Boolean Italic.
SelUnderline Boolean Underlined.
SelStrikethru Boolean Struck through.
SelColor Long The color, as RGB() makes it; -1 for the control's ForeColor.
SelFontName String The font family (&quot;&quot; for the control's own).
SelFontSize Integer The size in pixels (the nearest one the family comes in).
SelAlignment Integer The alignment of the selection's paragraphs: 0 left, 1 centered, 2 right.
CanUndo Boolean An edit can be undone (read-only).
CanRedo Boolean An undone edit can be done again (read-only).</pre>
<p>Text (a common property) is the plain text, a line per paragraph; setting it replaces everything with plain text. ReadOnly lets the user select and copy but not change the text.</p>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
Undo Undo the last edit (typing a run of characters is one edit). Up to 100 edits are kept.
Redo Do an undone edit again.
Cut, Copy, Paste The clipboard. Text copied from a RichEdit pastes back into a RichEdit with its looks; text from elsewhere takes the look of the text typed next.
SelectAll Select all the text.
Find(text[, matchCase]) Select the next place text is, from the selection on and around past the end; returns where it starts, or -1. Any case unless matchCase is True.
LoadFile(path) Load a file: RTF when it is RTF, else plain text. Returns 0, or -1 when it cannot be read.
SaveFile(path) Save the text: as RTF when path ends in .rtf, else as plain text. Returns 0, or -1 when it cannot be written.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Parameters Description
----- ---------- -----------
SelChange (none) The selection or the caret moved.</pre>
<p>Change fires after every edit. Default Event: Change</p>
<h2>Keys</h2>
<pre> Key Action
--- ------
Ctrl+B, Ctrl+I, Ctrl+U Bold, italic, or underline on or off.
Ctrl+L, Ctrl+E, Ctrl+R Align the paragraph left, centered, or right.
Ctrl+Z, Ctrl+Y Undo, Redo.
Ctrl+X, Ctrl+C, Ctrl+V Cut, Copy, Paste.
Ctrl+A Select all.
Ctrl+Left, Ctrl+Right A word back or on.
Ctrl+Home, Ctrl+End The start or the end of the text.
Shift with a moving key Extend the selection.</pre>
<p>A double click selects a word, a triple click the paragraph.</p>
<h2>Example</h2>
<pre><code>Sub Form_Load ()
RichEdit1.Text = &quot;Dear friend,&quot;
RichEdit1.SelStart = 0
RichEdit1.SelLength = 4
RichEdit1.SelBold = True
RichEdit1.SelColor = RGB(0, 0, 160)
End Sub
Sub cmdItalic_Click ()
RichEdit1.SelItalic = Not RichEdit1.SelItalic
End Sub
Sub cmdSave_Click ()
If RichEdit1.SaveFile(&quot;LETTER.RTF&quot;) &lt;&gt; 0 Then MsgBox &quot;The letter could not be saved.&quot;
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.richlabel">
<h1>RichLabel</h1>
<p>DVX Widget: richlabel</p>
<p>Text that mixes fonts, sizes, bold and italic, underlining, and colors, in paragraphs that are each aligned left, centered, or right. Build the text with calls: SetFont, SetStyle, and SetColor choose how the text you add next looks; AddText adds it; AddLineBreak starts a new line; and AddParagraph starts a new paragraph. Clear empties the control so you can build it again.</p>
<p>Text starts in the control's own font (FontName, FontSize, and the other Font properties, or the form's). Set Width to have the text wrap at that width; otherwise each paragraph stays on one line and the control is as wide as its longest line.</p>
<h2>Methods</h2>
<pre> Method Description
------ -----------
Clear Remove all the text. The font, style, and color go back to the control's own.
SetFont family, size The font family (for example &quot;DejaVu Serif&quot;) and size in pixels of the text added next. &quot;&quot; and 0 go back to the control's own font and size.
SetStyle style FONT_BOLD, FONT_ITALIC, FONT_UNDERLINE, and FONT_STRIKE added together (from font.bas; FONT_REGULAR for none) for the text added next.
SetColor color The color of the text added next, as RGB() makes it; -1 for the control's ForeColor.
AddText text Add text in the font, style, and color chosen.
AddLineBreak Start a new line in the same paragraph.
AddParagraph alignment Start a new paragraph: 0 left, 1 centered, 2 right (as a Label's Alignment).</pre>
<p>Changing the font, style, or color affects only the text added afterwards. A line is as tall as the largest font on it.</p>
<p>No type-specific properties or events.</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>Sub Form_Load ()
RichLabel1.Clear
RichLabel1.SetFont &quot;DejaVu Serif&quot;, 18
RichLabel1.SetStyle FONT_BOLD
RichLabel1.AddText &quot;Welcome&quot;
RichLabel1.AddParagraph 0
RichLabel1.SetFont &quot;&quot;, 0
RichLabel1.SetStyle 0
RichLabel1.AddText &quot;Text in &quot;
RichLabel1.SetColor RGB(160, 0, 0)
RichLabel1.AddText &quot;red&quot;
RichLabel1.SetColor -1
RichLabel1.AddText &quot; and &quot;
RichLabel1.SetStyle FONT_ITALIC + FONT_UNDERLINE
RichLabel1.AddText &quot;italic underlined&quot;
RichLabel1.SetStyle 0
RichLabel1.AddText &quot; words.&quot;
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.scrollpane">
<h1>ScrollPane</h1>
<p>DVX Extension -- DVX Widget: scrollpane | Name Prefix: Scroll</p>
<p>A scrollable container. Place child controls inside and the ScrollPane automatically provides scrollbars when the content exceeds the visible area. Clicking on content that does not respond to the mouse (a Label, an Image, or empty space) gives the ScrollPane the focus, so the arrow and page keys scroll it.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
NoBorder Boolean When True, suppresses the border around the scroll pane.
Padding Integer Space in pixels between the edge and the controls inside (0, the default, is none).
Spacing Integer Space in pixels between the controls inside, which are stacked top to bottom (0, the default, is none).
ScrollTop Integer How far the content is scrolled down, in pixels (run time). Values past the end stop at the end.
ScrollLeft Integer How far the content is scrolled to the right, in pixels (run time). Values past the end stop at the end.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
ScrollToTop Scroll back to the top-left corner of the content.
ScrollToControl ctrl Scroll so that a control inside the pane (the control, or its name) is in view, also one that cannot take the focus.</pre>
<h2>Events</h2>
<pre> Event Description
----- -----------
Change The user scrolled the content (the scrollbars, dragging a scroll box, the arrow, page, Home, and End keys); read ScrollTop and ScrollLeft for the new position. Setting ScrollTop or ScrollLeft, or ScrollToTop, does not fire it.</pre>
<h2>Scrolling a Picture Bigger Than the Window</h2>
<p>A ScrollPane with NoBorder = True filling a form, holding a PictureBox larger than the window, gives the form scrollbars of its own: the user scrolls the picture, Change says where it is, and ScrollTop / ScrollLeft move it from code. To draw only the part in view (for a picture too large to keep whole), keep the PictureBox the size of the view, and draw from Change with ScrollTop and ScrollLeft as the offset.</p>
<pre><code>Sub Form1_Load ()
picBig.Resize 1200, 900
picBig.Line (0, 0)-(1199, 899), RGB(0, 0, 255), B
End Sub
Sub spView_Change ()
lblWhere.Caption = &quot;Top &quot; &amp; spView.ScrollTop &amp; &quot;, left &quot; &amp; spView.ScrollLeft
End Sub</code></pre>
<p>Container: Yes</p>
<p>No default event.</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.line">
<h1>Line</h1>
<p>VB Equivalent: Line -- DVX Widget: separator</p>
<p>A visual separator line, horizontal or vertical. A Line placed in a horizontal container (HBox, Toolbar) starts vertical; anywhere else it starts horizontal. Set Vertical to turn it the other way, for example a vertical Line between two side-by-side groups inside a VBox.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Vertical Boolean True for a vertical line, False for a horizontal one.</pre>
<p>No type-specific events or methods.</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.hscrollbar">
<h1>HScrollBar</h1>
<p>VB Equivalent: HScrollBar -- DVX Widget: slider | Name Prefix: HScroll</p>
<p>A horizontal slider/scrollbar control. The value ranges between Min and Max (default 0 to 100). Arrow keys move the value by 1, Page Up/Page Down by a tenth of the range, Home/End to the limits. The Change event fires only when the value actually changes.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Value Integer The current slider position (clamped to the Min..Max range).
Min Integer Lowest value (default 0). Setting Min above Max raises Max to match.
Max Integer Highest value (default 100). Setting Max below Min lowers Min to match.</pre>
<p>Default Event: Change</p>
<h2>Example</h2>
<pre><code>Begin HScrollBar HScroll1
MinWidth = 200
End
Sub HScroll1_Change ()
Label1.Caption = &quot;Value: &quot; &amp; Str$(HScroll1.Value)
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.spacer">
<h1>Spacer</h1>
<p>DVX Extension -- DVX Widget: spacer</p>
<p>An invisible layout spacer. Takes up space in the layout without rendering anything. Useful for pushing controls apart. Give it a Weight to absorb extra space.</p>
<p>No type-specific properties, events, or methods.</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.spinbutton">
<h1>SpinButton</h1>
<p>DVX Extension -- DVX Widget: spinner | Name Prefix: Spin</p>
<p>A numeric input with up/down buttons. Supports integer mode (default) and real-number mode with configurable decimal places. Up/Down arrows step by the step size, Page Up/Page Down by ten steps. Typed or pasted text is committed on Enter or when the control loses focus; Esc cancels the edit. Ctrl+Z undoes the last edit of the typed text; once the text is committed or reformatted there is nothing to undo. Reading Value while the user is typing returns the typed number without interrupting the edit. Change also fires as each character is typed; stepping at a limit, or committing text that parses to the unchanged value, does not fire it.</p>
<p>Its font must be fixed-pitch, every character the same width; the designer's Font dialog offers only those families for it. Given a proportional font it draws in the system font instead.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Value Integer Current value (in real mode, the value truncated to an integer).
RealMode Boolean True to use floating-point mode; False for integer mode.
Decimals Integer Number of decimal places shown in real mode.
RealValue Double The value in real mode, with its fraction (Value is it cut to a whole number). Setting it keeps it inside the range.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Parameters Description
-------- ------------------------------ -------------------------------------------
SetRange Min As Integer, Max As Integer Set the allowed value range (used in both integer and real mode; default 0 to 100).
SetStep Step As Integer Set the increment per button click.
SetRealRange Min As Double, Max As Double The range in real mode, with fractions (SetRange takes whole numbers).
SetRealStep Step As Double The increment per click in real mode (0 or less gives 0.01).</pre>
<p>Default Event: Change</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.splitter">
<h1>Splitter</h1>
<p>DVX Extension -- DVX Widget: splitter</p>
<p>A resizable split pane. Holds exactly two child widgets separated by a draggable divider. By default the divider is vertical and the panes sit side by side; set Vertical to False for a horizontal divider with one pane above the other.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Position Integer Position of the divider in pixels from the left (or, when Vertical is False, from the top).
Vertical Boolean True (the default): panes side by side. False: one pane above the other. Can be set in the designer or at run time.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Description
----- -----------
Change The user moved the divider: raised as it is dragged, Position giving where it is. Not raised for a Position set in code.</pre>
<p>Container: Yes</p>
<p>No default event.</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.statusbar">
<h1>StatusBar</h1>
<p>VB Equivalent: StatusBar -- DVX Widget: statusbar</p>
<p>A horizontal container styled as a status bar, typically placed at the bottom of a form. Put Labels (or other controls) inside it as its panes: they sit side by side, each drawn with a sunken-panel border for the classic segmented status-bar look. Give the pane that should take the spare room Weight = 100. Panes can be nested in the designer or the .frm, or added at run time with CreateControl(form, &quot;Label&quot;, name$, StatusBar1).</p>
<p>Container: Yes</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
--------- ------- -------------------------------------------
Alignment Enum Where the panes sit along the bar when they do not fill it: Left (the default), Center, or Right.
Padding Integer Space in pixels between the edge of the bar and the panes: 1 unless set; 0 is none.
Spacing Integer Space in pixels between one pane and the next: 2 unless set; 0 is none.</pre>
<p>No type-specific events or methods.</p>
<h2>Example</h2>
<pre><code>Begin StatusBar Status1
Begin Label lblStatus
Caption = &quot;Ready&quot;
Weight = 100
End
Begin Label lblPos
Caption = &quot;Line 1, Col 1&quot;
End
End</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.tabstrip">
<h1>TabStrip</h1>
<p>VB Equivalent: TabStrip -- DVX Widget: tabcontrol</p>
<p>A tabbed container. Each tab page is a separate container that holds child controls. Switching tabs shows one page and hides others.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
TabIndex Integer Index of the active tab (0-based). Setting it switches tabs as SetActive does.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
AddPage title$ Add a new tab page with the given title.
GetActive() Returns the index of the active tab.
SetActive index% Switch to the tab at the given index (the same as setting TabIndex). A negative index selects the first tab and an index past the last tab selects the last tab. Switching closes a drop-down list opened from the page being hidden and moves the focus to the tab strip if it was on a control of the page being hidden. No event is raised for a switch made in code.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Description
----- -----------
Change The user switched tabs, with the mouse or the keys (not raised for a switch made in code). GetActive (or TabIndex) says which tab is active now.</pre>
<p>Container: Yes</p>
<p>Default Event: Click</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.textbox">
<h1>TextBox</h1>
<p>VB Equivalent: TextBox -- DVX Widget: textbox (single-line text input, 256 chars unless MaxLength says otherwise)</p>
<p>A single-line text input field. Supports data binding via DataSource and DataField properties.</p>
<p>Its font must be fixed-pitch, every character the same width; the designer's Font dialog offers only those families for it. Given a proportional font it draws in the system font instead.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
------------ ------ -------------------------------------------
Text String The text content of the input field. Setting it clears the undo history.
MaxLength Integer The most characters the box holds (0 = the default, 256; at most 32767). A longer text is cut, and typing stops at the limit.
PasswordChar String &quot;&quot; for a plain box; a character makes it a password box that shows that character for each one typed and does not copy or cut its text.
Mask String &quot;&quot; for a plain box; an input mask makes it a masked box: # takes a digit, A a letter, * any character, and every other character of the mask is fixed text the cursor skips (Mask = &quot;(###) ###-####&quot; for a phone number). The text keeps the mask's shape (empty places show _), and what the box held fills its places in order. Mask = &quot;&quot; makes it a plain box again holding the formatted text, with its MaxLength from before. A masked box is not a password box.
DataSource String Name of a Data control for data binding.
DataField String Column name for data binding.
SelStart Integer Where the selection starts, or the cursor when nothing is selected (0 = before the first character). Setting it moves the cursor there and selects nothing.
SelLength Integer The number of characters selected (0 = none). Setting it selects that many characters from SelStart.
SelText String The selected text. Setting it replaces the selection (or inserts at the cursor), leaves the cursor after the new text, and fires Change; in a masked box it fills the places from the selection's start, as pasting does.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
Copy Copy the selection to the clipboard (Ctrl+C); a password box copies nothing.
Cut Copy the selection to the clipboard and remove it (Ctrl+X); fires Change. A password box does nothing.
Paste Put the clipboard's text in place of the selection (Ctrl+V; line breaks are left out); fires Change.
SelectAll Select the whole text (Ctrl+A).
Undo Take back the last change (Ctrl+Z); a second Undo puts it back.</pre>
<p>The methods do what the keys do, so Cut, Paste, and Undo do nothing in a read-only box. An Edit menu works on whichever box has the focus with Me.ActiveControl (see Form).</p>
<p>Default Event: Change</p>
<h2>Example</h2>
<pre><code>Begin TextBox Text1
Text = &quot;Enter text here&quot;
End
Sub Text1_Change ()
Label1.Caption = &quot;You typed: &quot; &amp; Text1.Text
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
<p><a href="#ctrl.databinding">Data Binding</a></p>
</div>
<div class="topic" id="ctrl.textarea">
<h1>TextArea</h1>
<p>VB Equivalent: TextArea (DVX extension) -- DVX Widget: textarea (multi-line text input, default max 65536 chars)</p>
<p>A multi-line text editing area. This is a DVX extension with no direct VB3 equivalent (VB uses a TextBox with MultiLine=True). Supports line numbers, auto-indent, find/replace, and tab configuration.</p>
<p>Its font must be fixed-pitch, every character the same width; the designer's Font dialog offers only those families for it. Given a proportional font it draws in the system font instead.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type R/W Description
---------- ------- --- -------------------------------------------
Text String R/W The full text content. Setting it clears the undo history.
CursorLine Integer R Current cursor line number (1-based).
CursorCol Integer R Current cursor column (1 = the start of the line; a tab counts as one).
LineCount Integer R The number of lines (an empty text has one).
SelStart Integer R/W Where the selection starts, or the cursor when nothing is selected (0 = before the first character). Setting it moves the cursor there and selects nothing.
SelLength Integer R/W The number of characters selected (0 = none). Setting it selects that many characters from SelStart.
SelText String R/W The selected text. Setting it replaces the selection (or inserts at the cursor when nothing is selected), leaves the cursor after the new text, and fires Change; Undo takes it back.
MaxLength Integer R/W The most characters the area holds (0 = the default, 65536; at most 262144). A smaller value cuts the text.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
AppendText text$ Append text to the end of the buffer and invalidate the widget.
ClearLineMarkers Remove every line marker.
Copy Copy the selection to the clipboard (Ctrl+C).
CursorToEnd Put the cursor after the last character, nothing selected.
Cut Copy the selection to the clipboard and remove it (Ctrl+X); fires Change.
FindNext needle$, caseSensitive, forward Search from the cursor and select the match. A forward search finds a match starting at the cursor; repeating it moves on to the next match. Returns True if found.
GetLine(line%) Returns the text of a line (1 = the first) without its line end; &quot;&quot; past the last line.
GetSyntaxColor(index%) Returns the colour the syntax colouring draws that kind of text in (index as for SetSyntaxColor); -1 for the area's ForeColor.
GetWordAtCursor() Returns the word under the cursor.
GoToLine line% Scroll to the given line and select it.
Paste Put the clipboard's text in place of the selection (Ctrl+V); fires Change.
ReplaceAll needle$, replacement$, caseSensitive Replace all occurrences. Returns count of replacements.
ReplaceSelection(needle$, replacement$, caseSensitive, forward) When the selection is needle$, replace it (Change fires); then find the next needle$ in that direction, as FindNext does. Returns True when it replaced or found something (a Replace button).
SelectAll Select the whole text (Ctrl+A).
SetAutoIndent enabled Enable or disable automatic indentation.
SetCaptureTabs enabled When True, Tab key inserts a tab/spaces (firing Change) instead of moving focus.
SetCursor line%, col% Move the cursor to a line and column (both start at 1) without selecting anything. Values past the end clamp to the text.
SetLineMarker line%, gutterColor&amp;, backColor&amp; Mark a line (1 = the first): a dot of gutterColor in the line-number gutter (a breakpoint) and / or the line's background in backColor (the current line). -1 leaves that part out; -1 for both removes the marker. Markers stay on their line numbers when the text changes.
SetShowLineNumbers show Show or hide the line number gutter.
SetSyntaxColor index%, color&amp; The colour of one kind of text: 0 plain text, 1 keywords, 2 strings, 3 comments, 4 numbers, 5 operators, 6 types (and True, False, Nothing); -1 restores the default.
SetSyntaxMode mode$ Activate syntax highlighting. Modes: &quot;dhs&quot; (help source), &quot;bas&quot; (BASIC, coloured as the DVX BASIC IDE colours it), &quot;custom&quot; (the program colours each line in the Colorize event). Pass &quot;&quot; to disable.
SetTabWidth width% Set the tab stop width in characters.
SetUseTabChar useChar When True, Tab inserts a tab character; when False, inserts spaces.
Undo Take back the last change (Ctrl+Z; characters typed one after another are one change); a second Undo puts it back.</pre>
<p>Cut, Paste, and Undo do nothing in a read-only area.</p>
<h2>Type-Specific Events</h2>
<pre> Event Parameters Description
----------- ----------------------- -------------------------------------------
GutterClick LineNumber As Integer The line-number gutter (shown by SetShowLineNumbers) was clicked beside a line: toggle a breakpoint there. A click in the gutter does not move the cursor.
Colorize LineText As String, Colors As String With SetSyntaxMode &quot;custom&quot;, for every line as it is drawn: Colors comes with one &quot;0&quot; for each character of LineText; set each to the digit of a syntax colour (vbSyntaxText 0 to vbSyntaxType 6, colours as SetSyntaxColor sets them). Characters it leaves out stay plain. It runs when a line is drawn with text it has not coloured lately (the colours it gave are kept with the text, so a line drawn again unchanged does not ask again), so it must be quick and must not change the area; its colours should depend only on LineText. SetSyntaxMode &quot;custom&quot; again colours every line afresh (after the program changes how it colours).</pre>
<pre><code>TextArea1.SetSyntaxMode &quot;custom&quot;
Sub TextArea1_Colorize (LineText As String, Colors As String)
Dim i As Integer
For i = 1 To Len(LineText)
If Mid$(LineText, i, 1) = &quot;#&quot; Then Mid$(Colors, i, 1) = CStr(vbSyntaxComment)
Next
End Sub</code></pre>
<p>Default Event: Change</p>
<h2>Example</h2>
<pre><code>TextArea1.SetShowLineNumbers True
TextArea1.SetAutoIndent True
TextArea1.SetTabWidth 4
TextArea1.SetCaptureTabs True
' Search for text
If TextArea1.FindNext(&quot;TODO&quot;, False, True) Then
Print &quot;Found at line&quot;; TextArea1.CursorLine
End If
'' Replace all occurrences
Dim count As Integer
count = TextArea1.ReplaceAll(&quot;old&quot;, &quot;new&quot;, False)
Print &quot;Replaced&quot;; count; &quot;occurrences&quot;
' A code editor: BASIC colours, a breakpoint dot on the clicked line
TextArea1.SetSyntaxMode &quot;bas&quot;
Sub TextArea1_GutterClick (LineNumber As Integer)
TextArea1.SetLineMarker LineNumber, RGB(200, 0, 0), -1
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.timer">
<h1>Timer</h1>
<p>VB Equivalent: Timer -- DVX Widget: timer (non-visual)</p>
<p>A non-visual control that fires its event at a regular interval. The Timer widget is invisible at runtime -- it has no on-screen representation.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
-------- ------- -------------------------------------------
Enabled Boolean True to start the timer, False to stop it.
Interval Integer Timer interval in milliseconds. Setting it restarts the countdown. An Interval of 0 (or less) disables the Timer event.
Repeat Boolean True (the default) to fire every Interval; False for a one-shot timer that fires once and stops itself (Enabled turns False), until Start or Enabled = True runs it again.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Parameters Description
------ ---------- -------------------------------------------
Start (none) Start the timer.
Stop (none) Stop the timer.</pre>
<h2>Type-Specific Events</h2>
<pre> Event Parameters Description
----- ---------- -------------------------------------------
Timer (none) Fires each time the interval elapses. This is the default event. A one-shot timer is already stopped when its event runs, so the handler can call Start to run it again.</pre>
<blockquote><strong>Note:</strong> The Timer control fires the Timer event instead of Change. The onChange callback on the underlying widget is remapped automatically.</blockquote>
<h2>Example</h2>
<pre><code>Begin Timer Timer1
Interval = 1000
Enabled = True
End
Dim Shared counter As Integer
Sub Timer1_Timer ()
counter = counter + 1
Label1.Caption = &quot;Ticks: &quot; &amp; Str$(counter)
End Sub</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.toolbar">
<h1>Toolbar</h1>
<p>VB Equivalent: Toolbar -- DVX Widget: toolbar</p>
<p>A horizontal container styled as a toolbar, with compact padding and spacing. Place buttons, labels, or other controls inside.</p>
<p>Container: Yes</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
--------- ------- -------------------------------------------
Alignment Enum Where the controls sit along the toolbar when they do not fill it: Left (the default), Center, or Right.
Padding Integer Space in pixels between the edge of the toolbar and the controls: 2 unless set; 0 is none.
Spacing Integer Space in pixels between one control and the next: 2 unless set; 0 is none.</pre>
<p>No type-specific events or methods.</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.treeview">
<h1>TreeView</h1>
<p>VB Equivalent: TreeView -- DVX Widget: treeview</p>
<p>A hierarchical tree of expandable/collapsible nodes. Supports multi-select and drag-to-reorder. Items are accessed by depth-first index (0-based): an item's children follow it, before its next sibling. Adding children under an item that has none puts them right after it (index + 1, index + 2, ...), and moves the items after them along.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type R/W Description
--------- ------- --- -------------------------------------------
ListIndex Integer R/W Index of the current (selected) node, -1 when none. Setting it selects that node as a click would: its parents are expanded, it is scrolled into view, and the Change event fires.</pre>
<h2>Type-Specific Methods</h2>
<pre> Method Description
------ -----------
AddChildItem parentIndex%, text$ Add a child node under the node at the given index.
AddItem text$ Add a root-level node.
Clear Remove all nodes.
GetItemTag$(index%) Returns the text SetItemTag stored on the node (&quot;&quot; when none).
GetItemText$(index%) Returns the text of the node at the given index.
HasChildren(index%) Returns True if the node has nodes under it.
IsExpanded(index%) Returns True if the node at the given index is expanded.
IsItemSelected(index%) Returns True if the node at the given index is selected.
ItemCount() Returns the total number of nodes (all levels).
ItemDepth(index%) Returns how many nodes the node is under: 0 for a root-level node, 1 for its children, and so on (-1 when there is no such node).
ItemParent(index%) Returns the index of the node's parent, or -1 for a root-level node (or when there is no such node).
RemoveItem index% Remove the node and every node under it. The nodes after them move up.
SetExpanded index%, expanded Expand or collapse the node at the given index. Collapsing a node that hides the current item moves the current item to that node.
SetItemSelected index%, selected Select or deselect the node at the given index. Without multi-select this sets (or clears) the single selected node.
SetItemTag index%, tag$ Keep any text with the node (like VB's Node.Tag): a file path, a key. &quot;&quot; removes it.
SetItemText index%, text$ Change the text of the node at the given index.
SetMultiSelect multi Enable or disable multi-select mode. Turning it off clears the multi-selection.
SetReorderable reorderable Enable or disable node reordering.</pre>
<p>The Change event fires when the current node changes (a click, the arrow keys, or ListIndex set by the program).</p>
<p>Default Event: Click</p>
<h2>Example</h2>
<pre><code>TreeView1.AddItem &quot;Animals&quot;
TreeView1.AddChildItem 0, &quot;Cat&quot;
TreeView1.AddChildItem 0, &quot;Dog&quot;
TreeView1.AddItem &quot;Plants&quot;
TreeView1.AddChildItem 3, &quot;Oak&quot;
TreeView1.SetExpanded 0, True
Print &quot;Items:&quot;; TreeView1.ItemCount()</code></pre>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
<div class="topic" id="ctrl.wrapbox">
<h1>WrapBox</h1>
<p>DVX Extension -- DVX Widget: wrapbox | Name Prefix: WrapBox</p>
<p>A container that arranges children in a flowing layout, wrapping to the next row when the available width is exceeded. Similar to CSS flexbox with flex-wrap: wrap.</p>
<h2>Type-Specific Properties</h2>
<pre> Property Type Description
--------- ------- -------------------------------------------
Alignment Enum Horizontal alignment of items: Left, Center, or Right.
Padding Integer Space in pixels between the edge of the box and the items: 2 unless set; 0 is none.
Spacing Integer Space in pixels between one item and the next, and between rows: 4 unless set; 0 is none.</pre>
<p>Container: Yes</p>
<p>Default Event: Click</p>
<p><a href="#ctrl.common.props">Common Properties, Events, and Methods</a></p>
</div>
</main>
</body>
</html>