101 Tech Tips For VB Developers 006
101 Tech Tips For VB Developers 006
101 Tech Tips For VB Developers 006
For VB Developers
VB4 16/32
Level: Intermediate
Add this code, which includes the required API declarations and the SetHScroll routine, to a BAS module. The SetHScroll routine uses the SendMessage API function to send the LB_SETHORIZONTALEXTENT message to a list box. The last argument is an item from the list, preferably one of the longest items. SetHScroll determines the strings width in pixels and passes this value to the list box along with the LB_SETHORIZONTALEXTENT message. The list box sets its horizontal extent to this value, and if it is wider than the list-box control, the list box displays a horizontal scrollbar:
#If Win32 Then Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" ( _ ByVal hwnd As Long, ByVal wMsg As Long, _ ByVal wParam As Long, lParam As Long) As Long #Else Declare Function SendMessage Lib "user32" _ Alias SendMessageA ( _ ByVal hwnd As Integer, ByVal wMsg As Integer, _ ByVal wParam As Integer, lParam As Long) As Long #End If 'Define constant for message to list-box control Const LB_SETHORIZONTALEXTENT = &H194 Public Sub SetHScroll(Frm As Form, Ctrl As _ Control, strText As String) Dim nScaleMode As Integer Dim nTextWidth As Integer 'Scale in pixels for window message nScaleMode = Frm.ScaleMode Frm.ScaleMode = 3 'Get the width, in pixels, of the text string nTextWidth = Frm.TextWidth(strText) 'Send a message to the list box SendMessage Ctrl.hwnd, _ LB_SETHORIZONTALEXTENT, nTextWidth, 0 'Restore previous scale mode Frm.ScaleMode = nScaleMode End Sub
VB4 16/32
Level: Intermediate
http://www.windx.com
1 01 TECH TIPS
For VB Developers
If you have more than a few items, put this code in a loop:
intSelectedItems = 0 For iCount = 0 to N 'N = total number of option boxes minus one intSelectedItem = - _ Option(iCount).Value * iCount Next
intSelectedItem is the index of the option button that the user selected. Bruce H. Bitterman, San Antonio, Texas
ThisOne is the Index of the member you want to be selected. Getting the True member of an option array is not so simple. Because you need to perform this kind of task in almost any reasonably complex program, adding this function to your code library or generic module simplifies the task. You dont need to know the array size in advance:
Function OptionTrueIs(OptionArrayName As _ Variant) As Integer ' Returns the index of the True ' member of an option array Dim Ctl as Control For Each Ctl in OptionArrayName If Ctl.Value = True Then OptionTruels = Ctl.Index Exit For End If Next End Function
You can use the routine to set a Public variable from a Properties sheet using this format:
SomePublicVariable = OptionTrueIs(SomeOptionArray())
http://www.windx.com
1 01 TECH TIPS
For VB Developers
For Each v In txtFields If v.Text = "" Then MsgBox "All fields must be " & _ "filled out.", vbExclamation + _ vbOKOnly Exit Sub End If Next
Because txtFields is a collection, you can also determine how many text boxes are in the array by checking the value of txtFields.Count. For more information, see Karl E. Petersons Q&A column, The Keys to Your Controls [VBPJ August 1997]. Daniel Buskirk, The Bronx, New York
Now, you only need to create indexes. You can use this method to convert text files in excess of 100,000 records in a few seconds. Richard Mageau, Warren, Rhode Island
Logical operators return a value like any other operator. Instead, use this syntax:
Greater = x > 3
This way, you move directly to the result of the comparison in your flag. It is shorter and faster than the form example. Martin Girard, Chicoutimi, Quebec, Canada
http://www.windx.com
1 01 TECH TIPS
For VB Developers
End If Next If tempfont <> 0 Then FindFont = Printer.Fonts(i%) Else 'take an action if no similar fonts are 'found on this printer End If End Function
DISPLAY TOOLTIPS
You can easily duplicate the tooltips that appear when you float the mouse over a button in Microsofts products. This code displays the tooltip in the lower right-hand corner of the control (normally a button):
' xTip: string to display as the tip ' xCtrl: control you want the tip to show for. ' xTipControl: control being used to display ' the tip (an SSPanel) Public Sub ShowTip(xTip As String, xCtrl As _ Control, xTipControl As Control) xTipControl.Left = xCtrl.Left + xCtrl.Width xTipControl.Top = xCtrl.Top + xCtrl.Height xTipControl.Caption = xTip xTipControl.Visible = True End Sub
In your error handler, use this function in conjunction with the FontName property of the Printer object. After you take this corrective measure, resume the execution of your program:
Printer.FontName = FindFont(SpecifiedFont) Resume Next
Place the ShowTip function in the MouseMove event of the control(s) for which you want to display a tip. Place the HideTip function in the other control(s) for which you dont want to display a tip:
Sub Command1_MouseMove (Button As Integer, _ Shift As Integer, X As Single, Y As Single) ShowTip "Command1", Command1, SSPanel1 End Sub Sub Command2_MouseMove (Button As Integer, _ Shift As Integer, X As Single, Y As Single) ShowTip "Command2", Command2, SSPanel1 End Sub Sub Form_MouseMove (Button As Integer, _ Shift As Integer, X As Single, Y As Single) 'No tooltip for form HideTip Text1 End Sub
VB5
Level: Intermediate
http://www.windx.com
1 01 TECH TIPS
For VB Developers
MakeSubscript RichTextBox1, 1, 1, -2 MakeSubscript RichTextBox1, 4, 1, -2 End Sub Private Sub OffsetRichText(box As _ RichTextBox, start As Integer, _ length As Integer, offset As Integer) box.SelStart = start box.SelLength = length box.SelFontSize = box.Font.Size + offset box.SelCharOffset = -ScaleY(offset, _ vbPoints, vbTwips) box.SelStart = 0 box.SelLength = 0 End Sub
Note that you must compile this application and run the resulting EXE directly for this code to work because it relies on the application instance handle. While in the VB development environment, App.Instance returns an instance handle to the running VB32.EXE process, not the application under development. For a complete description of PlaySound( ), refer to the Multimedia section of the Win32 SDK. Steve Davis, Gaithersburg, Maryland
VB4 32
Level: Advanced
This works for almost any programming language. Alex Bootman, Foster City, California
The name MySound is a placeholder for a name you supply to refer to this WAV resource in code. Compile the resource file using the resource compiler (RC.EXE) to create a RES file. Include this file in your VB project. Use this code to play the sound:
Private Declare Function PlaySound Lib _ "winmm.dll" Alias "PlaySoundA" ( _ ByVal lpszName As String, _ ByVal hModule As Long, _ ByVal dwFlags As Long) As Long Private Const SND_ASYNC& = &H1 ' Play asynchronously Private Const SND_NODEFAULT& = &H2 ' Silence if sound not found Private Const SND_RESOURCE& = &H40004 ' Name is resource name or atom Dim hInst As Long ' Handle to Application Instance Dim sSoundName As String ' String to hold sound resource name Dim lFlags As Long ' PlaySound() flags Dim lRet As Long ' Return value Private Sub Command1_Click() hInst = App.hInstance sSoundName = "MySound" lFlags = SND_RESOURCE + SND_ASYNC + _
The only problem with this method is that your app wont respond to user input while it sleeps, so dont let it sleep too long. Derek Robinson, Pretoria, South Africa
http://www.windx.com
1 01 TECH TIPS
For VB Developers
If (n <> Upper - Lower + 1) Then n = Upper - Lower + 1 i = 0 n1 = n k = 2 Do While k <= n1 If (n1 Mod k = 0) Then If (i = 0 Or PrimeFactor(i) <> k) Then i = i + 1 PrimeFactor(i) = k End If n1 = n1 / k Else k = k + 1 End If Loop b = 1 For j = 1 To I b = b * PrimeFactor(j) Next j If n Mod 4 = 0 Then b = b * 2 a = b + 1 c = Int(n * .66) t = True Do While t t = False For j = 1 To I If ((c Mod PrimeFactor(j) = 0) Or _ (c Mod a = 0)) Then t = True Next j If t Then c = c - 1 Loop Randomize s = Rnd(n) End If s = (a * s + c) Mod n Shuffle = s + Lower End Function
By using the brackets and the dot operator, you get a completely proper output in the ISAM database type of your choice. Also, if you choose Text as the database type, the statement creates a SCHEMA.INI for you automatically, or adds a new section for your new data file to a SCHEMA.INI already in the path folder. You can do any kind of export the client wants without using a DBMS on the machine. This makes your life easier when you notice that some users running Word 97 have problems mailmerging with text files you originally created with Write# and Print# methods. Robert Smith, San Francisco, California
This trick also works with VB5, but you might find the Comment Block command on the Edit toolbar much handier. Frewin Chan, Scarborough, Ontario, Canada
http://www.windx.com
1 01 TECH TIPS
For VB Developers
Else .dmFields = DM_PELSWIDTH Or _ DM_PELSHEIGHT Or DM_BITSPERPEL End If .dmPelsWidth = Width .dmPelsHeight = Height If Color <> -1 Then .dmBitsPerPel = Color End If End With pDevmode = lstrcpy(NewDevMode, NewDevMode) SetDisplayMode = ChangeDisplaySettings(pDevmode, 0) End Function
You can change the display mode easily with this function. For example, write this code that changes the resolution to 640by-480 and the color palette to 24-bit True Color:
i = SetDisplayMode(640, 480, 24)
VB5
Level: Intermediate
Or place the code in a public Sub procedure and call it from any text box in your project:
http://www.windx.com
1 01 TECH TIPS
For VB Developers
Private Sub Text2_GotFocus() PreSel Text2 End Sub Public Sub PreSel(txt As Control) If TypeOf txt Is TextBox Then txt.SelStart = 0 txt.SelLength = Len(txt) End If End Sub
Because you can call the PreSel procedure from anywhere, you should limit the procedure to acting on TextBox controls to prevent errors. The TypeOf function tests if youve passed the procedure a TextBox control, and if not, it skips over the selection code. Ron Schwarz, Mt. Pleasant, Michigan
http://www.windx.com
1 01 TECH TIPS
For VB Developers
To give users a way to begin the move, place a little colored PictureBox in one corner of the form and let its MouseDown event begin the process:
Private Sub Picture1_MouseDown(Button As _ Integer, Shift As Integer, X As Single, Y As Single) ReleaseCapture SendMessage hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0& End Sub
Use this code to make the form stay on top in the form module:
SetWindowPos hwnd, HWND_TOPMOST, 0, 0, 0, 0, _ SWP_NOMOVE + SWP_NOSIZE
VB5
Level: Beginning
Use this code to make the form no longer stay on top in the form module:
SetWindowPos Parent.hwnd, HWND_NOTOPMOST, _ 0, 0, 0, 0, SWP_NOMOVE + SWP_NOSIZE
In 16-bit systems, use the 16-bit equivalents. Rod Stephens, Boulder, Colorado
Validity checking is not done when assigning values to the special-typed variable. Even though the TimeOfDay values range from zero to two, VB doesnt attempt to keep you from assigning a value of four, or another number, to such a variable. Be especially aware of this when writing Property Let procedures, which accept an enumerated parameter. Charles Caison, Greensboro, North Carolina
http://www.windx.com
1 01 TECH TIPS
For VB Developers
the variable iCounter, it returns Integer rather than Variant. In addition to specifying a specific character, you can also specify a range or list of letters. This code assigns variables that begin with the letters i, j, or k as integers, and those variables that begin with s or c as strings:
DefStr s, c DefInt i-k Dim iCounter ' an integer Dim sName ' a string
Here are more default variable type declarations: DefBool (Boolean) DefByte (Byte) DefLng (Long) DefCur (Currency) DefSng (Single) DefDbl (Double) DefDec (Decimal) DefDate (Date) DefStr (String) DefObj (Object) DefVar (Variant) Charles Caison, Greensboro, North Carolina
Because Visual Basic must calculate the location of the array element to resolve its value ( base + intAr rayIndex * sizeof_intArray_type), it makes sense that the code executes faster the less the calculation is performed. This code provides a faster implementation:
TheValue = intArray(intArrayIndex) If TheValue = 5 or TheValue = 10 Then
This technique offers performance gains that are even more dramatic when used in a loop:
For intArrayIndex = 0 to 10 TheValue = intArray(intArrayIndex) If TheValue = 5 or TheValue = 10 Then ' Do something here End If Next
By eliminating the redundant subexpression and assigning the value to the variable named TheValue only once per loop (executes 10 times) instead of twice per loop (executes 20 times), you significantly reduce the amount of work that VB must perform to complete this loop. Charles Caison, Greensboro, North Carolina
The first section of code fails because the URL is set after the username and password are set. The second section of code works because the URL is set first. Charles Casion, Greensboro, North Carolina
1 01 TECH TIPS
For VB Developers
There are two morals to this story. First, if your VB3 apps claim that dates are invalid when they look correct, check the Control Panel settings. Second, if you need to enforce a particular date format in your VB4 and VB5 programs, you need to take steps beyond using IsDate. For example, you can use maskededit controls or extra code to validate date formats. Jon Pulsipher, Plano, Texas
' PictureBox, hide taskbar ElseIf (X > PicTaskBar.Width) Then PicTaskBar.Visible = False End If End Sub
When you declare these variables, typing STRFETCHTHIS or icountme results in the editors changing them to the declared appearance when you move on. Randall Arnold, Coppell, Texas
Private Sub Form_Load() ' Set Width of PictureBox to 1/4 size of Parent form ' when form is loaded. This is wide enough to show ' all of the controls I embedded in the PictureBox, ' and will vary with each application. PicTaskBar.Width = Me.ScaleWidth / 4 End Sub Private Sub Form_MouseMove(Button As _ Integer, Shift As Integer, X As Single, Y As Single) ' When the horizontal mouse position is less ' than or equal to defined hot zone ' (in this case, horizontal pixel position 4), show taskbar If (X <= 4) Then PicTaskBar.Visible = True ' When the horizontal mouse position is ' greater than the width of the
http://www.windx.com
11
1 01 TECH TIPS
For VB Developers
Else SpecificWeekday = DateAdd("d", IIf(_ iAdd <= 0, iAdd, iAdd - 7), d) End If End Function
Normally, you should set this variable to False. During debugging, however, set it to True (DebugMode = True). Place this sub in the module:
Public Sub WriteDebugMessage(ByVal Msg as String) If DebugMode then 'write a message, including the system time End If End Sub
Enter this code as the first statement in every subroutine and function in your project:
Call WriteDebugMessage("Entering NameOfSubroutine")
Enter this code as the last statement in every subroutine and function:
Call WriteDebugMessage("Exiting NameOfSubroutine")
VB4 introduced conditional compilation, which offers a simpler way to implement this scheme. By defining a conditional compiler constant rather than a global flag variable, you can optimize your final EXE by toggling the constant to False. Conditional calls to the WriteDebugMessage routine wont be compiled into your shipping build:
#Const DebugMode = False ' for final code, true to test #If DebugMode Then Call WriteDebugMessage("Important Info") #End If
Use drag-and-drop to copy the image from the source control to the drop target control. All scaling and drawing is handled automatically. You dont need to set the ScaleMode property of your destination object. You can use this technique when you want to decorate forms with complex shapes or create a Balloon Help form, a process control modeling application in which the images represent the elements of the production flow, or a flow-chart application. Rob Parsons, Dee Why, New South Wales, Australia
Use this code to write other debug information to the log, such as variable values. Dont forget to turn off Debug mode when youre not using it to avoid writing massive amounts of unneeded data to the log. Shannon Huggins, Lancaster, South Carolina
' modal
12
http://www.windx.com
1 01 TECH TIPS
For VB Developers
Pass parameters to a form by writing a wrapper utility that handles the passing of these parameters to and from the called dialog:
Sub cmd_Click() CalculatorDialog_Show txtAmount End Sub Sub CalculatorDialog_Show (C As Control) '' Display the Calculator_Dialog and return '' the calculated value as a string Load Calculator_Dialog Calculator_Dialog.lblReadout = _ Format(Val(C.Text), "#.###############") ' Pass the number to dialog Calculator_Dialog.Op1 = Format(Val(C.Text), _ #.###############) ' simulate user input Calculator_Dialog.LastInput = "NUMS" Calculator_Dialog.Show 1 ' modal If Calculator_Dialog.Action = True Then C.Text = Format(Calculator_Dialog._ lblReadout, "General Number") End If Unload Calculator_Dialog Set Calculator_Dialog = Nothing End Sub
RunLongProcess CmdStartStop.Enabled = True End If End Sub Private Sub RunLongProcess() Do While Running ' Do something repeatedly. : DoEvents Loop End Sub
The parameters are passed to hidden label controls on the Calculator_Dialog form between the time the form is loaded and the time its displayed. A hidden label control on the Calculator_Dialog (Action) indicates whether the user chose the OK or Cancel button to exit the dialog. Rather than unload the Calculator_Dialog when the user presses the OK or Cancel button, the form hides until the calling sub (CalculatorDialog_Show) processes the value of Calculator_Dialog.lblReadout. The form is then unloaded, and the Set-to-Nothing statement is executed to purge memory of the forms controls and procedures. This technique works with any version of VB. Starting with VB4, you can add properties and methods to forms, which is a preferable method to relying on hidden labels for interobject communication. Rob Parsons, Dee Why, New South Wales, Australia
http://www.windx.com
13
1 01 TECH TIPS
For VB Developers
In this example, I used two multiline text boxes with scrollbars, but TreeView and ListView controls work just as well. David Grantier, Atlanta, Georgia
VB5
Level: Intermediate
Because the condition is False, Visual Basic ignores this statement. However, the Setup Wizard interprets this line as a function declaration, locates the file (in this case, VIDEO.AVI), and includes it in the setup list. Setup Wizard will default to placing these files in your App folder, so change it accordingly. Miguel Santos, Aveiro, Portugal
In the labels Click event, you can change the value assigned to sText to specify what action ShellExecute performs. If you specify a URL, ShellExecute launches your Web browser and points it to the specified Web site. You can also use the mailto syntax (mailto:yourname@youraddress.com) to instruct ShellExecute to launch your e-mail program. You can even specify a file name, and ShellExecute automatically loads the file into the program registered to use it. For example, specifying a file with the DOC extension loads Microsoft Word on systems that have Word installed. Jos Rodrguez Alvira, San Juan, Puerto Rico
14
http://www.windx.com
1 01 TECH TIPS
For VB Developers
RunningInIDE = False 'Trap errors On Error GoTo RunningInIDEErr 'Divide by zero (fails within IDE) Debug.Print 1 / 0 'Exit if no error Exit Function RunningInIDEErr: 'We get error if Debug.Print was 'evaluated (i.e. running in the VB IDE) RunningInIDE = True End Function
RunningInIDE performs a division by zero in a Debug.Print statement. Within the IDE, this causes a divide overflow, which the function traps in an error handler. When the program is run as a standalone EXE, Debug.Print statements are not evaluated and no error occurs. Jeffrey Sahol, Greensboro, North Carolina
You can speed up this routine significantly by taking advantage of the fact that the LB_SETSEL message sets the state of all items in the list box at once if the index argument is -1. Because this approach uses a single call to SendMessage, you dont need to worry about setting the list boxs Visible property to False to prevent multiple redraws:
Sub ToggleSelectAll (lst As ListBox, _ ByVal bState As Integer) Dim nRet As Long nRet = SendMessage(lst.hWnd, LB_SETSEL, bState, -1) End Sub
This routine sets the list boxs Visible property to False to prevent the list box from repainting itself after each item is selected. This makes the routine more efficient. However, you can speed
http://www.windx.com
15
1 01 TECH TIPS
For VB Developers
'Traverse left branch If Not LeftBranch Is Nothing Then LeftBranch.TraverseTree End If 'Display this node MsgBox NodeData 'Traverse right branch If Not RightBranch Is Nothing Then RightBranch.TraverseTree End If End Sub
Test this class by creating a new CBinarySearchTree object, calling AddNode a few times to store data, and then calling TraverseTree to see the results. Binary search trees dont get much simpler than this. David Doknjas, Surrey, British Columbia, Canada
16
1 01 TECH TIPS
For VB Developers
server, you never want to hard-code drive letters. Not all software vendors take advantage of the Uniform Naming Convention (UNC) (for example, \\SERVER\VOLUME\ ) technology. Use these API declarations:
Public Declare Function GetVolumeInformation _ Lib "kernel32" Alias "GetVolumeInformationA" ( _ ByVal lpRootPathName As String, _ ByVal lpVolumeNameBuffer As String, _ ByVal nVolumeNameSize As Long, _ lpVolumeSerialNumber As Long, _ lpMaximumComponentLength As Long, _ lpFileSystemFlags As Long, _ ByVal lpFileSystemNameBuffer As String, _ ByVal nFileSystemNameSize As Long) As Long Public Function GetNetworkDrive(FileSystem _ As String, VolumeName As String) As String 'Returns the first mapped drive letter 'if successful or "NODRIVE" if fails. 'FileSystem and SysName refer to the 'Network file system type: 'NWCOMPA => Novell 'NTFS => Microsoft 'FAT => Local\Microsoft Dim Dim Dim Dim Dim SerialNum As Long, SysFlags As Long retVal As Long, Complength As Long VolBuff As String * 255, SysName As String * 255 DrivePath As String i As Integer
Vol1Drive = GetNetworkDrive("NWCOMPA","VOL1") If Vol1Drive = "NODRIVE" Then MsgBox "Unable to open database. " & _ "The user does not have a " & _ "drive letter mapped to VOL1" Else filespec = Vol1Drive & _ "\PUBLIC\APPS\BTRIEVE\MYDB.RDB" 'Some third-party control that opens 'the database file. ... ... ... End If End Sub
GetNetworkDrive = "NODRIVE"
VB4 32
Level: Advanced
http://www.windx.com
1 01 TECH TIPS
For VB Developers
wParam, which, in the case of the MouseMove event, VB converts to the Button, Shift, X, and Y arguments. If the user clicks on the icon in the system tray, Windows passes 513 and 514 (WM_LBUTTONDOWN and WM_LBUTTONUP) to VB, and VB performs a conversion that leaves the original mouse message in X. If ScaleMode of the invisible form, frmOmni in the example, is left as Twips, this tip wont work for every system. To make this tip work on every system, set ScaleMode of the invisible form to Pixels. Goran Stijacic, San Diego, California
' *** Return our nicely formatted GUID CreateGUIDKey = strFormattedGUID End Function
As As As As
Public Function CreateGUIDKey() As String '*** Possible max length for buffer Const GUID_LENGTH As Long = 38 Dim udtGUID As GUID 'User Defined Type Dim strFormattedGUID As String 'The formatted string Dim lngResult As Long 'Useless result flag '*** Create a 'raw' GUID lngResult = CoCreateGuid(udtGUID) If lngResult = GUID_OK Then '*** Pre-allocate space for the ID strFormattedGUID = String$(GUID_LENGTH, 0) '*** Convert the 'raw' GUID to a 'formatted string StringFromGUID2 udtGUID, _ StrPtr(strFormattedGUID), GUID_LENGTH + 1 Else '*** Return nothing or handle error strFormattedGUID = "" End If
Function SendToWinPopUp(PopFrom As String, _ PopTo As String, MsgText As String) As Long ' parms: PopFrom: user or computer that ' sends the message ' PopTo: computer that receives the ' message ' MsgText: the text of the message ' to send Dim rc As Long Dim mshandle As Long Dim msgtxt As String Dim byteswritten As Long Dim mailslotname As String ' name of the mailslot mailslotname = "\\" + PopTo + _ "\mailslot\messngr" msgtxt = PopFrom + Chr(0) + PopTo + Chr(0) + _ MsgText + Chr(0) mshandle = CreateFile(mailslotname, _
18
http://www.windx.com
1 01 TECH TIPS
For VB Developers
GENERIC_WRITE, FILE_SHARE_READ, 0, _ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) rc = WriteFile(mshandle, msgtxt, _ Len(msgtxt), byteswritten, 0) rc = CloseHandle(mshandle) End Function
http://www.windx.com
19
1 01 TECH TIPS
For VB Developers
'previous code may have stripped text to nothing 'if it was just spaces, so test If Size <> "" Then 'strip off inch character (double 'quotes) if it's there If Right(Size, 1) = Chr$(34) Then _ Size = Left(Size, Len(Size) - 1) iGap = InStr(Size, "-") If iGap = 0 Then iGap = InStr(Size, " ") If iGap Then sWhole = CSng(Left(Size, iGap - 1)) strSize = Right(Size, Len(Size) - iGap) iSlash = InStr(strSize, "/") 'user may have input backward slash 'in fraction instead of forward slash; 'verify If iSlash = 0 Then iSlash = InStr(strSize, "\") 'convert result to decimal form for 'saving in database If iSlash Then Size = CStr(sWhole + _ (CSng(Left(strSize, iSlash - 1)) / _ CSng(Right(strSize, Len(strSize) - iSlash)))) End If ReturnDecimalValue = Size End Function
For example, the Caption statement in this code sets the caption on the automatically created instance. When the instance FRM appears, its caption is not set:
Dim frm As New MyForm MyForm.Caption = "This is the single instance" frm.Show
Even more confusing problems can arise if you use MyForm within the MyForm code module, when an instance such as FRM might accidentally set properties on the automatically created form rather than itself. For this reason, never use MyForm within the MyForm code module. Rod Stephens, Boulder, Colorado
BETTER AUTO-PROPERCASE
The Auto-Propercase Text Box at Entry tip [VBPJ May 1997, page 63] has a simpler solution. The StrConv function can propercase any string. You can achieve the same effect with this code in the KeyUp event of a text box:
Private Sub Text1_KeyUp(KeyCode As Integer, _ Shift As Integer) Dim iCurPos As Integer iCurPos = Text1.SelStart Text1.Text = StrConv(Text1, vbProperCase) Text1.SelStart = iCurPos End Sub
http://www.windx.com
1 01 TECH TIPS
For VB Developers
Private ThisControl As Control Private Sub Command1_MouseUp(Button As _ Integer, Shift As Integer, X As Single, Y As Single) If Button = vbRightButton Then Set ThisControl = Command1 PopupMenu mnuBtnContextMenu End If Set ThisControl = Nothing End Sub Private Sub mnuBtnWhatsThis_Click() ThisControl.ShowWhatsThis End Sub
VB5
Level: Beginning
VB5
Level: Beginning
http://www.windx.com
1 01 TECH TIPS
For VB Developers
use an array instead of a combo-box or a list-box control, there is no API call you can use. Use this code for an array:
'In: 'Array to search Dim rasArray() As String 'String to search for Dim vsName As String 'Out: 'Index in the array of the string if found Dim rlIndex As Long 'Local variables: 'Index in the array Dim lnIdx As Long 'Lower bound of the search interval Dim lnMin As Long 'Upper bound of the search interval Dim lnMax As Long 'Return an invalid index, if string is not found rlIndex = LBound(rasArray) - 1 lnMax = UBound(rasArray) lnMin = LBound(rasArray) 'lookup vsName in rasArray() Do While lnMin <= lnMax lnIdx = (lnMax + lnMin) \ 2 If vsName = rasArray(lnIdx) Then rlIndex = lnIdx Exit Do ElseIf vsName < rasArray(lnIdx) Then lnMax = lnIdx - 1 Else lnMin = lnIdx + 1 End If Loop Loop
You can easily modify this code for a combo-box control to use with list-box controls as well:
'In: 'Combo to search ' (change into As ListBox for listbox controls ' or use As Controls to use with both types ' of controls) Dim rcboCombo As ComboBox 'String to search for Dim vsName As String 'Out: 'Index in the combo if the string is found Dim rlIndex As Long 'Local variables 'Index in the array Dim lnIdx As Long 'Lower bound of the search interval Dim lnMin As Long 'Upper bound of the search interval Dim lnMax As Long 'Return an invalid index, if string is not found rlIndex = -1 lnMin = 0 lnMax = rcboCombo.ListCount - 1 lnIdx = lnMax \ 2 'lookup name in the combo Do While rlIndex = -1 And lnMin <= lnMax If vsName = rcboCombo.List(lnIdx) Then rlIndex = lnIdx ElseIf vsName < rcboCombo.List(lnIdx) Then lnMax = lnIdx - 1 lnIdx = (lnMax + lnMin) \ 2
This routine is unable to deal with strings whose first character is greater than Chr$(127). Matthew B. Butler and Steve Hochreiter, San Angelo, Texas
22
http://www.windx.com
1 01 TECH TIPS
For VB Developers
VB5
Level: Intermediate
Else 'change the color less frequently iIncrement = 1 iCheckpoint = iIterations \ 510 + 1 End If sAddIncrement = "&H0000" & _ Format$(iIncrement, "00") & "00" sSubIncrement = "&H0000" & _ Format$(iIncrement, "0000") SSPanel1.FloodColor = &HFF 'start the panel at Red 'At your preference show the 'percentage. However, the tighter 'the loop, the less valuable this is. SSPanel1.FloodShowPct = True For i = 0 To iIterations - 1 'do your real processing here If i / iCheckpoint = i \ iCheckpoint Then With SSPanel1 If i <= iMidPoint Then .FloodColor = _ .FloodColor + sAddIncrement Else .FloodColor = _ .FloodColor - sSubIncrement End If .FloodPercent = (i + 1) / iIterations * 100 End With End If 'if the loop is tight, be sure to 'release the processor 'occasionally - also, some flood 'controls (other than SSPanel) 'may require this to get the 'color updated in the control DoEvents Next MsgBox "All done!", vbOKOnly + vbInformation SSPanel1.FloodPercent = 0 SSPanel1.FloodShowPct = False End Sub
VB4 16/32
Level: Intermediate
The effect works best when your video is set to at least 16-bit (High Color). Because there are exactly 510 progressive gradients between red and green, the number of iterations you enter will influence what shade of green you end up with. As the iterations increase (>900), youll end up with bright green. Jim Poland, Cedar Rapids, Iowa
http://www.windx.com
23
1 01 TECH TIPS
For VB Developers
Else Text1 = Text End If If Text1 <> "" Then Text1 = Text1 & ";" End If AddParam = Text1 & Param & "=" & (Value) End Function Function DelParam (Text As String, _ Param As String) As String Dim i As Integer Dim j As Integer Dim s1 As String Dim s2 As String Dim Text1 As String Text1 = Text i = InStr(UCase(Text), UCase(Param) & "=") If i > 0 Then If i = 1 Then s1 = "" Else s1 = Left(Text, i - 2) End If j = InStr(i, Text, ";") If j > 0 Then s2 = Mid(Text, j + 1) Else s2 = "" End If If s1 = "" Or s2 = "" Then Text1 = s1 & s2 Else Text1 = s1 & ";" & s2 End If End If DelParam = Text1 End Function Function GetParam (Text, Param) Dim i As Integer Dim j As Integer Dim Text1 As String If Len(Text) Then If Left(Text, 1) <> "'" Then Text1 = ";" & Text & ";" i = InStr(LCase(Text1), ";" _ & LCase(Param) & "=") + 1 If i > 1 Then j = InStr(i + Len(Param), Text1, ";") GetParam = Mid(Text1, i + Len(Param) + 1, _ j - i - Len(Param) - 1) Else GetParam = Null End If Else GetParam = Null End If Else GetParam = Null End If End Function
For 16-bit versions of VB, replace the GetSysColor declaration with this code:
Declare Function GetSysColor Lib "User" ( _ ByVal nIndex As Integer) As Long
1 01 TECH TIPS
For VB Developers
'iTimes sets the number of flashes Call FlashWindow(hFlash, True) Dim Start As Single Start = Timer ' Set start time. ' sInterval sets the time between flashes Do While Timer < Start + sInterval DoEvents ' Yield to other processes Loop Next i ' Puts everything back to normal Call FlashWindow(hFlash, False) End Sub
VB5
Level: Beginning
VB5
Level: Intermediate
http://www.windx.com
1 01 TECH TIPS
For VB Developers
the printer. This code uses the Windows API AbortDoc to prevent this. Put a button named cCancel on the form and caption it Abort Printing. Add this declaration to your program:
Declare Function AbortDoc% Lib "GDI" ( _ ByVal hDC As Integer)
VB5
Level: Beginning
CODE-COMMENTING SHORTCUTS
Instead of going to the Edit menu to comment out a section of code, you can add the comment command to the shortcut menu you access by right-clicking in a code window. Select View/ Toolbars/Customize. On the Toolbars tab of the Customize dialog, click on the Shortcut Menus check box. On the toolbar that pops up, click on Code Windows... Code Window. On the Commands tab of the Customize dialog, select Edit in the categories list box. Drag and drop Comment Block and Uncomment Block from the Commands list box to the code window menu. Hit the Close button on the Customize dialog. Now go to a code window, drag the mouse over a section of code, right-click, and select Comment code. Greg Ellis, St. Louis, Missouri
IS MY OBJECT VALID?
Have you ever needed to determine if an object variable is holding a valid reference? TypeName( ) returns a class name if the object holds a valid reference. It returns the word Nothing if it does not:
Public Function IsObjValid(objTest As Object) As Boolean Dim vntResult As Variant vntResult = TypeName(objTest) If vntResult <> "Nothing" Then _ IsObjValid = TrueEnd Function
VB3, VB4 16
Level: Advanced
http://www.windx.com
1 01 TECH TIPS
For VB Developers
For iLoop = 0 To snpExport.Fields.Count - 1 sFieldText = "" & (snpExport.Fields(iLoop)) Write #1, sFieldText; Next Write #1, snpExport.MoveNext Loop CSVExport = True Exit Function Err_Handler MSGBOX("Error: " & Err.Description) CSVExport=False End Function
http://www.windx.com
27
1 01 TECH TIPS
For VB Developers
iListTabs(0) = 96 ' 96/4 = 24 characters iListTabs(1) = 192 ' 192/4 = 48 characters Ret = SendMessage(iListHandle, _ LB_SETTABSTOPS, iNumColumns, iListTabs(0)) End Sub
In your form, create a list box called lstMyListBox. Call this routine in the form load to set your tab stops:
Call SetListTabStops(lstMyListBox.hwnd)
This technique only works if you dont have another object variable pointing to the same collection. In this case, setting the children variable to Nothing doesnt destroy the collection; instead, it decreases its internal reference counter. The only way to remove all the items of the collection is with a loop of Remove methods:
Do While children.Count children.Remove 1 Loop
28
http://www.windx.com