VISUAL BASIC

 PC Hardware  |  PC Software  |  Networking  |  Web Designs  |  News Letter   |  Home

Visual Basic  |  C++  |  Java

COMMON VISUAL BASIC PROGRAMMING QUESTIONS 

What's the difference between MODAL and MODELESS forms?

MODAL forms are forms which require user input before any other actions can be taken place. In other words, a modal form has exclusive focus in that application until it is dismissed. When showing a modal form, the controls outside this modal form will not take user interaction until the form is closed. The internal MsgBox and InputBox forms are examples of modal forms. To show a form modally, use the syntax:

MyForm.SHOW vbModal 'a predeclared constant for 1

MODELESS forms are those which are shown but do not require immediate user input. MDI child forms are always modeless. To show a form modeless, use the syntax:

MyForm.SHOW

When/Why should I use Option Explicit?

Option Explicit forces you to declare all variables before using them. Opinions vary greatly on this subject. The main reason to use the OPTION EXPLICIT statement at the top of all modules is to minimize the amount of bugs introduced into your code by misspelling a variable name. Most variants of BASIC (including VB) have the capability to create variables 'on the fly' (without any declarations). This capability can be a double edged sword.

The OPTION EXPLICIT statement causes VB to 'disable' its ability to create variables on the fly. Thus, all variables must be declared using a DIM or REDIM statement. All variables not declared will cause an error when the OPTION EXPLICIT statement is used. This will eliminate bugs caused by a misspelled variable. The option works module-wide, so you can have some modules with and some without this option in your project. Declaring variables "on the fly" makes all but the most trivial code difficult to debug and maintain.

VB creates Variant type variables by default.

Why does everybody say I should save in TEXT not BINARY?

Applies only to VB 3.0 and below: Actually, saving in binary mode is a bit faster, so why do we recommend you to save in text?

If you save the source and the project as text, it becomes ASCII (or really, ANSI) code that you can edit with any text editor or (if you are careful when you save) word processor. If you save in binary, only the VB development environment, current or later versions, will understand the code. The Setup Wizard can not scan binary projects. Also, source documenters and other programming tools usually require text mode. If you use text, you can use a simple text editor (e.g. notepad) to cut and paste code from other source/form modules into your current project. Some 'tricks' (like making an array of 1 control into a single non-array control again) is easily done with an editor but not that easy in the environment. If you want to print your project to paper the file|print option in the VB environment is often not good enough; you may want to import the text files into your word processor. And, finally, if something goes wrong (only one byte is changed!) you may be out of luck in binary mode. In text mode you will more easily be able to fix it.

VB 4.0 and 5.0 does not offer the option of saving in binary, saving us from a lot of problems.

Is the Variant type slower than using other variable types?

Generally, yes, if we are talking numeric variable types. The Variant type also increases memory overhead. To test the speed difference, try the following piece of code in something like a button_click event and keep the debug window on the screen:

See code

This test shows (on our test system using VB 4.0) that integers are ~60% faster! However, for strings there where no real difference, or in some instances, variants were faster than strings for routines with heavy conversion usage. For the best result in your application, test your routines directly.

How do I make a text box not beep but do something else when I hit the Enter key?

Put "something else" in your _KeyPress event, depending on what you really want. This code example makes nothing happen, for an extended period of time:

Sub Text1_KeyPress (KeyAscii As Integer)

If KeyAscii = 13 Then '13 is Key_Return
KeyAscii = 0

End If

End Sub

This might not be a very nice thing to do, since your users usually have some intention when they press Enter. Often they will want to jump to the next control, like the Tab key does. To have the Enter key emulate the Tab key action, you will need to add the line 'SendKeys "{tab}"' above 'KeyAscii=0' in the example above (Yes, I thought KeyAscii=9 works but it doesn't! Tab is obviously handled by Windows on a lower level).

By the way, you'll also find this in the Microsoft VB Knowledge Base (see KB Q78305 and Q85562).

Note: If MultiLine=True you will not want to disable the normal behaviour of the Enter key.

How do I implement an incremental search in list/dir/combo/file boxes?

This is your lucky day. Dan Champagne (Dan_Champagne@dell.com) made some VB code (no DLLs are necessary!) which easily provides this feature for your applications: See code

How do I get the Tab key to be treated like a normal character?

You must set TabStop = False for ALL controls on the active form. Then the user will be able to insert Tab (chr 9) characters in controls like the text box.

If you feel you need the Tab key to behave like "normal" (e.g. jump to next control) outside this specific control, it is trivial to emulate its functionality in code:

Sub Command1_KeyDown (KeyCode As Integer, Shift As Integer)

If KeyCode = 9 Then
If Shift = 0 Then

Command2.SetFocus 'Tab=Next control

ElseIf Shift = 1 Then

Command3.SetFocus 'Shift-Tab=Prev.ctrl.

End If
End If

End Sub

...etc.

How do I make an animated icon for my program?

For an example on how you change the icon for your application as it is displayed when it is minimized, see the example REDTOP in the \samples\picclip directory for VB/Win 3 Pro. This demonstrates a sort-of fancy animated icon.

What is passing by reference?

Arguments are either passed by reference or by value. When they are passed by value, they cannot be changed by the procedure or function they are passed to. They can be altered when passed by reference, since passing by reference is just passing the address.

Note that procedures are less strict about variable types when you use BYVAL. If you declare that your Sub takes a Variant, VB takes that seriously and gives a nasty "mismatch error" if you try to pass e.g. a string to it. Make it ByVal (at the cost of some speed) and your sub will be more tolerant.

Also note the following nasty trap: Arguments are passed by reference unless enclosed by parentheses or declared using the ByVal keyword. [VB 3.0 Language Ref., p. 55]

I get a "file not found" error on the IIF function when I distribute by program. Uh?

There's a documentation error in VB 3.0, since the manual does not tell you that the IIF function requires the file MSAFINX.DLL to be distributed with your application. No, IIF is not really a financial function so go figure.

Is there any way to pass a variable to a form apart from using global variables?

The standard workaround is to put an invisible text box (or caption or any other control that suits your use.) on the target form and access it by Form.textbox = "value". Then you can use the Change event of that control to do anything you want in that form. Also, check out the .Tag property which is a "what-you-want" property where you can hook any string you want onto a control. This property can also be accessed from other modules.
[Dave Mitton <mitton@dave.enet.dec.com>]

Perhaps a more elegant and flexible way is to implement a stack with similar routines. I've done this for a math project, but this stack was rather complicated and special purpose (and inspired by HP calculators, of which I'm a great fan).

Jan G.P. Sijm <jan.sijm@intouch.nl> has implemented some routines for general stacks: See code

How should dates be implemented so they work with other language and country formats?

If you use e.g. MM/DD/YY format dates in a program, you will get either a runtime-error (e.g. month>12) or the wrong date (e.g. March 12 instead of December 3) when your program is used in Europe. And vice versa, of course. Even Microsoft's own example programs (like the MAPI sample in VB3) make this stupid mistake and fail miserably. Use the Format command to make sure you get the date you want. For example:

strTodaysDate = Format[$](Now, "Short Date")

As a side note, Microsoft has taken much heat on the newsgroup for VB's bad support for internationalization! Just try to make a date literal in source code that works everywhere as a little exercise. Answer elsewhere in this document. No prizes :-)

Can a VB application be an OLE server?

No. Well, in VB 4.0 and 5.0 you can create OLE DLLs (OCXes) which sort-of qualifies.

How do I dial a phone number without using the MSCOMM VBX?

[32-bit] For 32-bit programming, you can call the phone dialer directly through the API. If you make a standard one-form project with two buttons (Ok, Cancel), and two text boxes (txtName and txtNumber), you can use the following code to dial a number:

Private Declare Function tapiRequestMakeCall Lib "TAPI32.DLL" _
 (ByVal DestAddr$, ByVal AppName As String, _
 ByVal CalledParty As String, ByVal Comment As String) As Long
 
Public Sub CallPhone(Number As String, Name As String)
  Dim lRes As Long
  If (Trim(Number) = "") Then
    MsgBox "Sorry, no phone number defined"
    Exit Sub
End If
If (MsgBox("About to call " & Trim(Name) _
& " at phone number " & Trim(Number) & vbCrLf & "Do it?", _
 vbYesNo, App.Title) = vbYes) Then
lRes = tapiRequestMakeCall(Trim(Number), App.Title, Trim(Name), "")
Debug.Print Now; " CallPhone -> tapiRequestMakeCall Result code = "; lRes
  End If
End Sub
 

Private Sub btnCancel_Click()
  Unload Me
End Sub
 

Private Sub btnDial_Click()
  CallPhone txtNumber.Text, txtName.Text
End Sub

This information provided by Peter Ibbotson <peter@ibbotson.demon.co.uk>

For a more rough approach, try the following code:

PhoneNumber$ = "(123)456-7890"
Open "COM2:" For Output As #1 'or COM1
Print #1, "ATDT" & PhoneNumber$ & Chr$(13)
Close #1

Ian Storrs <exuian@exu.ericsson.se> first informed me that he had experienced problems with this when the VB program was run from a network drive. A file named "COM1" was created on the disk! Jeff Rife <jrife@health.org> was the one to put in the ":" after COM2 to solve that problem!

This trick is probably not a good idea for bigger applications, but it's nice for small personal utilities.

I have [several] megabytes of memory. Why do I get an "out of memory" error?

This problem and its solution(s) are not applicable to Windows 95, but only Windows 3.x. If you receive this error using Win95 or NT, it will probably be the wrong error message for some other problem.

Unfortunately, Microsoft has earlier been more famous for memory barriers than anything else. This is a late descendant of the infamous 640K barrier that has been plaguing us for years. Although Windows allows the user to access several megabytes of memory, it uses two limited (64K) memory areas called User Heap and GDI Heap for some specific data structures. Go to the Help|About box in Program Manager to see the percentage of free resources in the most exhausted heap. If these areas are exhausted, you are out of luck. VB programs are unfortunately rather greedy on these structures. Windows 4 is supposed to free us from this limitation...

Note that every visible control (ie every button) is a window to Windows. Every new control takes up some bytes in the precious User heap.

Also, there is another way to run out of memory in Windows, not related to VB. Windows requires free Upper Memory Area (UMA, also called Upper Memory Blocks, not to be confused with High RAM, which is the first 64K of extended memory) to do certain tasks. If you use QEMM or DOS 6+ MemMaker and you have many device drivers (network, etc) this area may have been filled up before you launch Windows. You will then be unable to start applications, even though you have plenty of free RAM. The problem can be solved with careful memory setup, but this is far beyond the scope of this FAQ.

On a completely unrelated problem: When you run a program with an outline control with some ATI graphics cards, it may crash with just that error message. (see Knowledge Base Q100194 PRB: "Some ATI Video Drivers Hang When Using MSOUTLIN.VBX"). I assume this problem is fixed both from ATI and Microsoft now.

How do I mimic a toggle button?

The only "fix" we know for this problem is to use a picture or image control to mimic the action of a button or button3d control. You need two bitmaps, one for buttonup and one for buttondown (and perhaps one more for inactive state). This is a kluge, we know. Look at the button bar used in the MDINOTE sample program supplied with VB for an example of this.

How do I get my application on top?

To make your window truly topmost, use the SetWindowPos API call. First, make these declares:

#IF WIN32 THEN

Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" _
(ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _
ByVal x As Long, ByVal y As Long, ByVal cx As Long, _
ByVal cy As Long, ByVal wFlags As Long) As Long

#ELSE 'Win16

Declare Sub SetWindowPos Lib "User" (ByVal hWnd As Integer, _
ByVal hWndInsertAfter As Integer, ByVal X As Integer, _
ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, _
ByVal wFlags As Integer)

#END IF

Global Const SWP_NOMOVE = 2
Global Const SWP_NOSIZE = 1
Global Const FLAGS = SWP_NOMOVE Or SWP_NOSIZE
Global Const HWND_TOPMOST = -1
Global Const HWND_NOTOPMOST = -2

To set Form1 as a top-most form, do the following:

#IF WIN32 THEN

Dim lResult as Long
lResult = SetWindowPos (me.hWnd, HWND_TOPMOST, _
0, 0, 0, 0, FLAGS)

#ELSE '16-bit API uses a Sub, not a Function

SetWindowPos me.hWnd, HWND_TOPMOST, _
0, 0, 0, 0, FLAGS

#END IF

To turn off topmost (make the form act normal again), do the following:

#IF WIN32 THEN

Dim lResult as Long
lResult = SetWindowPos (me.hWnd, HWND_NOTOPMOST, _
0, 0, 0, 0, FLAGS)

#ELSE '16-bit API uses a Sub, not a Function

SetWindowPos me.hWnd, HWND_NOTOPMOST, _
0, 0, 0, 0, FLAGS

#END IF

If you don’t want to force a window on top, which will prevent the user from seeing below it, but simply want to move a Window to the top for the user’s attention, do this:

Form1.ZOrder

You can, to make the application stay on top, put the ZOrder method in a Timer event repeatedly called, say, every 1000 milliseconds. This makes a "softer" on-top than other methods, and allows the user to make a short peek below the form.

There are two different Zorder’s of windows (forms) in Windows, both implemented internally as linked lists. One is for "normal" windows, the other for "topmost" windows (like the Clock application which is distributed with Windows). The ZOrder command above simply moves your window to the top of the "normal" window stack. There is another, independent stack for topmost windows – like those created by the example code above – which resolves problems if several of those should conflict.

Note that when a form is minimized, it loses its topmost attribute and you will have to set it again.

Is there a way to break long lines in VB code?

Visual Basic 4.0 and above breaks any lines by placing " _" (space+underscore) at the end of the line which will continue below. You cannot break inside literals (ie. quotes). This was a much welcome addition!

For earlier VB versions, the answer is you can't break long lines. This feature first came with Excel 5 VBA.

There are a few tricks you can use to reduce line length, but unfortunately there is very little to do with DECLARE statements which can get very long. Still: Print your source in landscape :-/

How do I remove/change the picture property of a control at design time?

Workaround for VB 3.0 bug: Mark the (bitmap) or (icon) text in the property window and press Del or Backspace. "No!" I hear you cry, "It doesn't work". Well, it does if you first select the object from the combo box at the top of the Properties Window, and then immediately afterwards doubleclick (or paint over) the "(bitmap)" text and press Del. Alternatively, just click on another control, then click back to the first control. Now Del works. Who said "bug"?

If you want to paste your picture directly into the VB program by pressing Ctrl-V when you are editing the picture property, you will have to use a semilar procedure: select the control, select the property, press Ctrl-V. If you try it again without deselecting the control first (or selecting it from the combo box), it doesn't work.

How do I make my applications screen-resolution independent?

There are two methods: Either get a custom control that does the job for you, or you write lots of complicated code in the Load and Resize events.

For the first option, check out VideoSoft's $hareware VSVBX.VBX/OCX. Go to http://www.videosoft.com for updated info. It has a will of its own, as you will experience, but it's generally better than trying what is described below.

For the brave (or stupid), try to write "screen resolution-smart code" in the form's Load event. If the form is resizable (normally it should be), you'll have to put some magic into the Resize event as well. There are 4 rules of thumb:

  1. Do not trust the form's height and width properties. These measure the entire form, not the client area where your controls are. To see this in action, create a simple applet with the only code being in the resize event which resets a line control from 0,0 to the form's width,height properties. The top left corner is in the client area, the bottom right corner disappears. The API call GetClientRect will return the size of the client area in pixels. You can use the screen object's TwipsPerPixelX and TwipsPerPixelY properties to convert from pixels to twips. If that's not enough, GetWindowRect will return the actual size of the entire form, client and non-client areas combined. GetSystemMetrics will return individual pieces of things like border width/hight, caption height, etc.
  2. Use the TextWidth and TextHeight properties. You can use them off the form if all your controls share the same font, otherwise use them off of the given control. I typically do a TextWidth("X") and TextHeight("X") to get a value which I use as a margin between controls. I grab these values on startup, and multiply it by 2, 1.5, .75, .5, .25 to get varying margin sizes, depending on how close or far apart I want to space things. If your control has an autosize property, you may want to use it, and then calculate the maximum width of a control in a given "column" of controls on your screen and position all of them accordingly.
  3. Try not to resize your controls in the resize event. You will spawn another resize event in the process. Of course, you can use a flag to determine whether the resize event is the original event or the spawned one. Using the load event, and setting the forms borders to fixed minimizes the amount of work you have to do.
  4. Make sure you use a consistant scale. I don't even bother with the scale properties, but instead just convert pixels (from API calls) into twips and be done with it. If you do use scale properties, be sure you convert your numbers correctly. I had no end of difficulty when I failed to convert into twips with one number that was used in a series of calculations to position controls. Also be sure all your controls share the same SCALE -- another nasty problem I had before I gave up on them completely.
    [Thanks to our generous anonymous source "D"]

How do I do Peek and Poke and other low-level stuff?

VB provides no direct mechanism for this.

On The Microsoft Developer Network Library CD, you’ll find a utility called VBASM which provides full access to all sorts of low-level routines: peek, poke, memory pointer, port i/o and interrupts. You should be able to find vbasm.dll easily by searching for it on the net.

[Deane Gardner <deaneg@ix.netcom.com> quotes Microsoft]

There are several 3rd party packages which provide this functionality. Also, this often comes up in regards to the communication ports and you can many times do what you want with the MsComm control (which comes with the professional/enterprise editions of VB).

Why doesn't "my string" & Chr$(13) do what I want?

You need to also add a Chr$(10): "my string" & Chr$(13) & Chr$(10) will give you a CR and LF.
[George Tatge (gat@csn.org)]

There are constants that make this more readable: "my string" & vbCrLf and "mystring" & vbCR & vbLF both equals the above.

How do I prevent multiple instances of my program?

In VB 3 and above, the property App.PrevInstance is set to True if an older instance of the program already exist.

This following piece of code, stolen from MS KB article Q102480, will activate the old instance and then terminate itself.

As Robert Knienider(rknienid@email.tuwien.ac.at) informed me, this piece of code will not work for non-English versions of Mirosoft Windows where the word for "Restore" does not have "R" as the underlined word. Replace the "R" in the SendKeys line above with "{ENTER}" or "~".

Note that you shouldn't prevent multiple instances of your application unless you have a good reason to do so, since this is a very useful feature in MS Windows. Windows will only load the code and dynamic link code once, so it (normally) uses much less memory for the later instances than the first.

How do I implement an accelerator key for a text box?

You want to use a label caption to identify a text box and to act as if it were the text box caption:

Example:

&Label1 [text1 ]

How should I do to set the focus to text1, by typing <ALT>L

Make sure that the TabIndex property for the text box is 1 greater than the label's TabIndex. Since a label can't have the focus, the focus will go to the next item in the tab order, which would be the text box.

Here's any easy way to set the TabIndex for a busy form. Select the object that should be last in the tab order and then select the TabIndex property. Press 0 (zero), click on the next to last object, press 0, click on the the next object back, press 0, etc. When you're done, all of the TabIndexes will be in order, because VB increments all of the higher TabIndexes when you put in a lower number.

Many thanks to Jonathan Kinnick and Gary Weinfurther that provided the answer on the FIDO net echo VISUAL_BASIC.
[Tiago Leal (Tiago.Leal@p25.f1.n283.z2.gds.nl)]

How do I force a file list box to reread the current disk?

If you make a simple dialogue box modelled after common dialogue (normally you should use the common dialogue control), you will notice that reselecting the diskette drive will not really rescan the disk. Very annoying to change to C:, and to reselect A: just to make it read the directory of a new diskette.

To solve this problem, put

drive1.refresh
dir1.refresh
file1.refresh

in the code for the "Reread" button (or whatever).

How do I get the number of free bytes on a disk?

See Article Q113590 (or Q106553) in Microsoft's VB KnowledgeBase. A short extract follows:

Declare Function DiskSpaceFree Lib "SETUPKIT.DLL" () As Long
Dim free_space& 'Holds number of bytes returned from DiskSpaceFree().
ChDrive "c:" 'Change to the drive you want to test.
free_space& = DiskSpaceFree()

[Geir Tutturen <itfgt@nlh10.nlh.no>]

As far as I know, there are three possibilities:

  1. SETUPKIT.DLL as mentioned above
  2. Arjen Broeze's VBIO.VBX or something like that, with a lot of options.
  3. Make your own DISKINFO.DLL from the example code in VBKB article Q106553.

Data Control missing from toolbox when I use VB under NT 3.5. Huh?

Applies to VB 3.0 with Windows NT 3.5: Open the VB.INI file and add these lines under the [Visual Basic] heading:

ReportDesign=1
DataAccess=1

[Danny Ames<dames@pic.net>]

How do I avoid the overflow error when assigning values to my variable?

Be wary of the scopes of variables. In particular, be wary of the Integer. It accepts values from -32,768 to 32,767. Anything else causes an overflow run-time error:

i% = 30000 + 30000 'fails

There is little reason to not use the Long data type instead, which brings us to some other, more subtle problem. Try this:

l& = 30000 + 30000 'fails. Huh?

The reason for this very odd problem is that VB evaluates the expression internally, using the type of the constants, and in this case it's still Integer. So the run-time error occurs even before it tries to assign the value to the Long  type variable. To make it work, you have to do the following:

i&=30000& + 30000& 'ok

While the Long uses two bytes more internal space, this is nothing to worry about. Since the 32-bit CPU actually works with 32-bit long integers internally, it is even a (theoretical) bit faster than the shorter counterpart. So if in doubt, and even if not, stick to Longs.

[PET PEEVE] Why doesn't VB provide an unsigned integer, which can take values from 0 to 65,535? This is a major omission.

[NOTE] Some perfectly sane programmers prefer to create their VB applications using the Variant data type almost exclusively. While that would not solve the actual problem above, it certainly will remove most type-conversion and mismatch problems with VB. The extra execution time and memory overhead is rarely significant.

 

For more details contact the webmaster