article

Updated - 27 VB Hints and Tricks you should know

Email
Submitted on: 2/14/2015 1:11:00 PM
By: Filipe Lage (from psc cd)  
Level: Intermediate
User Rating: By 15 Users
Compatibility: VB 6.0
Views: 1577
 
     Just a bunch of VB6 hints and tricks I thought I could share with you. Many new hints and tricks you should know in VB6. How to add events to Windows Application log How to add controls in run time VB6 and the 2GB File limit - Be aware How to hide your application from task manager ASM Subclassing - Moving back is the safest way How to check for non-Modal permitions How to implement DIR$ correctly in your application. Convert ByteArrays to String and vice versa And more...

 
				

VB Hints:

Give description to your print jobs:

Before printing set APP.TITLE to the description of the print job.
This way, the description of the document being printer will appear in the printer job window instead of your application
name.
Ex:

app.title = "Invoice #1234"

[do the printing code and enddoc]

Quickly get data from a separated string

Let's consider

dim a as string
dim atmp() as string
a="Text1;Text2;Text3;Text4"
atmp=split(a,";")
Test = a(3)

Now let's look at...

dim a as string
a="Text1;Text2;Text3;Text4"
Test = split(a,";")(3)

This way you can get the "Text4" string directly from split instead of mapping a temporary string (previous example).
It's actually faster too ;)

Naturally, this also applies to tab delimited files. Example, Create a file in excel and export as TXT (Tab delimited)
You can get the cell from the respective row and column after reading contents to memory

function CellData(data as string, row as integer, column as integer) as variant
CellData = split(split(data,vbcrlf)(Row),vbtab)(Column)
end function

Quickly get rounding of a number the right way:

Since VB rounds fail in mathematical functions (ex: Round(2.5) results in 2 instead of 3)
we can avoid that by creating a new Round Function in VB

function MathRound(value as Double, optional lngDecimals as Long = 0) as double
MathRound = CDbl(Format$(value * 10^lngDecimals, "0")) / 10^lngDecimals
end function

This function also supports negative decimal places.
Ex: MathRound(1100,-3)=1000

There's a faster function (also created by me) available on the net if you prefer speed over simplicity.
Check it at
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=61414&lngWId=1

Immediate window

In case you don't know, you can use "?" to replace "debug.print" in the immediate window
Ex:
Go to immediate window and type:

? 1+1

It will appear: 2 (naturally)
It's useful to test functions or parts of code parsing the output value to the immediate window, or simply to check variables.
Ex:

? a=3
False

BTW, if type it in your VB code itself, the "?" will be replaced to "Print" just after you press enter.
Ex:

me.? "test"

will be automatically replaced to:

Me.Print test

Use mouseweelfix

VB6 doesn't support mousewheel natively, so you can't scroll up and down with your mouse.
But there's a fix... actually, it's an addon for VB that scrolls the text and implements that so-much-needed function.
You can find it in microsoft here: http://support.microsoft.com/?id=837910

How to register an ActiveX in code.

Just make a declaration such as:

Private Declare Function REGISTER_MYDLL Lib "MYDLL.DLL" _
Alias "DllRegisterServer" () As Long
Private Declare Function UNREGISTER_MYDLL Lib "MYDLL.DLL" _
Alias "DllUnregisterServer" () As Long
Private Const ERROR_SUCCESS = &H0

Then, simply call

REGISTER_DLL

or

UNREGISTER_DLL

in your code to register or unregister the dll.

There are more advanced functions that enable you to specify the DLL to get registered on code instead of
mapping the actual DLL file in the declaration. But if you know your DLL's, then simply include the declarations in the EXE
and add
an option to Fix components by calling the respectivefunctions
This also works for OCX files.

XCOPY Install?

YES! That is, if you only use OCX files...
In case your EXE requires external OCX files, and you put them in the same path as the EXE, they are loaded without any
problems! :)
Doesn't work for dll's though. You still have to register them using regsvr32 or using the previous hint.
If you want to make sure your app works even without VB6 Runtimes, simply include MSVBVM60.DLL to your EXE path, but don't
register it.
But if you want to run your application even though you're not sure if the target system has VB6 runtimes, just include
the MSVBVM60.DLL in the same path as the EXE... it works :).
Note for "Virgin" Win95/98:
Must have DCOM previous installed (it is installed with IE 4.5 anyway and MDAC's, and other updates)

How to enable/disable all controls in a form/container

to disable:

on error resume next
for each o in me.controls: o.enabled = False: next

to enable:

on error resume next
for each o in me.controls: o.enabled = True: next

How to change container of an object.

Example, place a commandbutton in a form, and add a frame next to it.
Note that both controls will have Form1 as a parent.
If you want commandbutton to be included inside the frame, but to make it work in runtime simply add:

SET Command1.container = Frame1

Avoid using VB strings greater than 32k

VB Strings is the "Achilles's heel" of VB in terms of speed. (ok, strings and threading/subclassing)
I recomend you use a stringhelper object (check AllocString page at http://www.xbeat.net/vbspeed/) if you want
big strings (1MB or more) to store data. Beware of this AllocString since the data inside the string will not be blank!

 

[Added 2006-02-02]
Read file from disk into memory (Fastest way possible without API with low cpu usage)

I've done this function to obtain all data from an existing file to memory. Note that if you have very large files (like 1GB) it will take 1GB of RAM as well... It's great to read data and handle it in memory. I get about 7MBytes/second in my P4-3000.

Public Function ReadFullFile(file As String) As Byte()
Dim a As Long
a = FreeFile
Open file For Binary As #a
ReDim ReadFullFile(LOF(a)-1)
Get #a, , ReadFullFile
Close #a
End Function

It stores all data in a bytearray... It's better than storing in a VB String, since all VB strings are stored in UNICODE, meaning that for each byte in the file, it will take 2 bytes of RAM. So, if I used a string, I would need 200MB of RAM to read a file of 100MB.

Naturally, you can convert it to string using the code:

Dim FileData as string
FileData = StrConv(Readfullfile(file),vbUnicode)

Be careful, since you can run out of out of memory with very large files!
You should also take in consideration, that if the file has 0 bytes or simply doesn't exist, it will result in an error, so you should make sure that the file being read exists and it's not 0 bytes long.

You can also change the function to read the file directly to a string, by using

Public Function ReadFullFile(file As String) As String
Dim a As Long
a = FreeFile
Open file For Binary As #a
ReadFullFile = Space(LOF(a)) ' You can use the VBSpeed's StringHelper to make this faster for large files
Get #a, , ReadFullFile
Close #a
End Function

Avoid VB IDE bugs

I've used VB for several years now, and I've discovered several bugs that many times corrupt projects and you should be aware of that.

Lost bags
First of all, if you have an UserControl present in your EXE project, remember that if you change the project name, all properties previously set in your forms will be lost. To be exact, all propbag's in your user controls become "blanks" and defaults are used.
Example:
You've added an UserControl to your project and you're using it in Form1. One of the properties of that user control is "Caption" and you've set that to "Hello world"... Nice, that is saved on the usercontrol's propbag... If you change the EXE project name, and check your form again, the "Hello world" is now gone.

Corrupt VBP's
One of the most annoying things in VB6 is that it sometimes corrupts the VBP's by mistaking some ActiveX objects with ActiveX controls.
Example: If you have ActiveX DLL's in your project references, and you also use external ActiveX Objects (usercontrols) in your forms, sometimes VB6 will list the object as a reference. In conclusion, when you open the VBP once again, it will give a load error and all forms that use the "mixed up" control will have their objects replaced with a picture box.

This happens when you open several projects in VB (ex: EXE + DLL) and use an external OCX UserControl, compile the DLL with the other projects loaded, quit VB and save changes. After that, just load the EXE VBP.
When this problem happens, the solution I've found is to open the VBP with notepad and delete the "Reference" line that includes the OCX/VBP. Open the VBP, include the OCX once again in the add controls, and re-save the project (just the VBP). Reopen the VBP and all is well again.


[Added 2006-03-07]
Avoid using Subclassing... At least with ASM code on it
    Until recently, I've been using the ASM subclassing from (the great) VBAccelerator.com. The file ssubtmr6.dll to be exact.
    Unfortunatly, I had to return to the previous non-ASM code since every call crashed my application in a computer I had...
    I investigated, and I found the reason... DEP - Data Execution Prevention...
    Naturally, when DEP is used Windows XP and 2003.NET with a DEP compliant CPU (ex: AMD64 or the latests Intel CPU's), Windows will deny the ASM part of the subclassing to run (since the code is stored in a variable area and not in a code execution area)...
    Windows automatically shows a GPF when the subclassing is initialized in this mode and the application is closed.

    There are two ways to avoid the problem:
    1) Not recomended
        Change the boot.ini of the operating system (not recomended) or add your application to the DEP 'exclusion' lists.
        Either way, it doesn't garantee a crash free operation, and the user has to add your application to the exclusion list manually.
    2) Recomended
        Return to the previous subclassing that doesn't use the ASM code.
        A little slower, but it's crash free with DEP compliant cpu's.

    This is my recomendation if you want to make a stable, subclassing application to be used in Windows XP and/or 2003.NET.

 

On error resume next... Beware!
    If you want a 99% crash free app, you can always add the on error resume next on the first line of every sub and function... I don't recomend it, but at least it won't show any VB Runtime errors... However, remember to set "on error goto 0" before the end of the function/sub, if not, your code may not work at all (exits the first function calls another one without resuming the next line if an error was raised in the second function).   


 

DIR$ - A great thing if you implement it right.
    VB has the DIR$ function so you can list folders and files, however you should be aware that this function is shared across your entire application. So, if you have one function that does something like:

    Sub ListFolder()
    mainpath = "c:\windows"
    a$=Dir$(mainpath)
    do until a$=""
    b$=HowManyDirs(mainpath & "\" & a$)
    a$=Dir$
    Loop

    Function HowManyDirs(f) as long
    b$=dir$(f,vbDirectory)
    do until b$=""
    HowManyDirs=HowManyDirs+1
    b$=dir$
    loop
    end function

    This code won't work at all, since the Dir$ function is common in the entire application. If the first sub is using the Dir$, no function should use it before the first sub finishes. You won't get the right results if you do.

 

Beyond 2GB files with VB
    
All VB functions to get file size (LOF(x) or FileLen(f)) are limited to longs...
    That means that you only have 31 bits (+1 bit for sign) to store the size of the file... That gives VB a limit of 2147483648 bytes (2GB).
    Using internal functions and calls, like OPEN, SEEK, etc, you can't get data beyond this point, so you'll need to use the API for that.
    Anyway, you should be aware of this VB6 limitation if your project deals with very large files (ex: VOB's, MPG's, AVI's, etc) so you can implement the necessary 64-bit functions to avoid this limitation.
    In terms of internal results (ex: a function you implement to get the file size in 64-bits), I recomend you use the CURRENCY to get the file size... Even though "Currency" data type isn't a full integer type, you'll have the limit raised to 922.337.203.685.477 bytes (around 920 TeraBytes) per file that I think is good enough for the next few years ;)

    Hint: If you're using a function to check if a file exists on the hard disk, and your code is similar to:
   
        Function DoesFileExist(f as string) as Boolean
              On error resume next
              DoesFileExist = (filelen(f)>0)
              End Function
    You should be aware that VB's FileLen function reports negative values when a file is bigger than 2GB, so avoid using it unless you know what you're doing. In some cases, it can even report that the file doesn't exist even though the file is there.

 

Use VB's Application LogEvent to track your application status:
    VB provides a good way to log events to a file or to Windows NT/XP Application Log.
    Note that this will only in the compiled file. No event will be logged in IDE mode.
 
    How to log events to an external file:
        
App.StartLogging "c:\test.log", vbLogToFile ' or VbLogOverwrite
              App.LogEvent "Hello world", vbLogEventTypeError
              App.LogEvent "Hello world", vbLogEventTypeWarning
              App.LogEvent "Hello world", vbLogEventTypeInformation

    How to log events to NT Application Log:
              App.StartLogging "My Application", vbLogToNT
              App.LogEvent "Hello world", vbLogEventTypeError
              App.LogEvent "Hello world", vbLogEventTypeWarning
              App.LogEvent "Hello world", vbLogEventTypeInformation
     
One great thing about this is that your other calls (ex: DLL's and OCX's) can use the logevent to the same log as the main EXE file.
    This is great to debug a applications or communication services.
    Just remember not to log TOO MUCH or else it will be filled with irrelevent data.

 

Some functions that most people are unware of
    How to convert a byte array to a string:
       
MyString = strconv(MyByteArray, vbUnicode)

    How to convert a string to a byte array:
       
MyByteArray = StrConv(MyString, vbFromUnicode)

    How to add controls to your forms in run mode:
  
        Private WithEvents Text1 As TextBox ' So you can also have events
            Sub AddTextBox()
            Set Text1 = Me.Controls.Add("VB.TextBox", "Text1")
            ' Now we have the control, just as if it was added on design mode.
            Text1.Move 0, 0, 500, 100
            Text1.Visible = True
            End With
        This also works with other controls (ex: Winsock) as long as the control is present in your project's VB toolbox.
        In this case you also need to remove the check 'Remove information about unused ActiveX' in
        the VB compilation options unless if you have at least one control present in any of your project forms.

    How can you check the number of forms currently loaded:
       
NumberOfFormsLoaded = vb.Forms.Count

    How to unload all forms in a MDI project safely:
  
       do until vb.Forms.Count <=0
            unload vb.forms(0)
            loop
        Note: if you have in your form's QueryUnload or Unload events, the possibility of a cancel operation this code won't work properly.

    Check if you can show a non-Modal form before you try it to show it.
   
       MyForm.Show (1+App.NonModalAllowed)
        This will automatically show your form in Modal mode is a previous form is already in that mode...
        Note that if you try to show a non-Modal form when a Modal form is visible, VB will stop the execution with a run time error, crashing your application entirely, so this is safe to use ensuring that no "Non-Modal" run time error occurs.

    How to hide your application from the Task Manager's "Applications" tab (however it will be visible in the "Processes" tab):
   
        App.TaskVisible = False

Cheers

// FCLage

2006-03-07


Other 6 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Intermediate category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments


 There are no comments on this submission.
 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.