Visual Basic Online

Questions & Answers May 1997

General Visual Basic.

Q: I'm using VB5 Enterprise Edition to write a calculator as a programming project. All's well, except that I want to use the Enter key to act as the equals key and display a result, as it does with the standard Windows 95 Calc app. I've written a frmCalc_keypress event routine that intercepts all keypresses to the main calculator form and reroutes them to the appropriate click event for the other buttons, using KeyPreview=True on the form. This works fine. The problem is this. The Enter key isn't recognised at all by the Keypress event when the focus is on a command button, as is the case here. (The focus is always on the last-pressed button, of course.) According to the Knowledge Base, this is because "command buttons are subclassed Windows push button controls and the Enter key is an accelerator key that is passed to the superclass; Visual Basic never receives it." For the life of me I can't find a way round this problem, and so can't use Enter as equals. It's trivial, but it's annoying me. Do you know of any work-around?
Ed Ricketts
lynchmob@dircon.co.uk
A: The key is that when a command button has the focus the Enter key gets translated to a click event. Since you want to intercept it you need to prevent any command button from having the focus. There are two ways I can think of that might accomplish this:

  1. Put another control (picturebox, textbox, ?) and set it's properties so that it has Visible=True but the border and backstyle are defined to make it blend in with the form background or place it under another control using the Zorder method. After responding to a click or keypress set the focus to this control. That will allow you to catch the Enter key in the KeyPress event or you can set Default=True for the command button that represents the = sign.
  2. Replace all your command buttons with labels and use the Click events on the labels and the KeyPress event on the form to handle entry.

Q: Is there any easy way to get my own MousePointer to my program, made with VB 3.0 Pro ? If not, is there any way at all ?
Markku Lahti
Markku_Lahti@online.tietokone.fi
A: The Windows API can be used to change the mouse pointer, but VB3 will change it right back as soon as almost anything happens, including a mouse move. I have not yet seen a method to make a change stick. VB4 and VB5 support this with the .MousePointer=99 and the .MouseIcon properties.


Q: how can I read a diskette volume label in vb4? I think that it is possible to do a call API, but I don't know what function to use.
barlas@ucfma.univ-bpclermont.fr
A: No API needed for the volume label. Try: MsgBox "Volume label: " & Dir$("A:\",8)


Q: I am VB beginner and I have got some questions about MDI. The question is: In an MDI application a single empty child document window is auto instantiated and shown in the MDI form's load event. However, when the application is run the MDI form initially appears containing two empty child documents windows, so can you suggest what is going wrong? Another one is--In the context of terminating an MDI application, do you know the differences and similarities between a child document window's QueryUnload event and its Unload event?
Huang Bai Lin
huang@yoyo.cc.monash.edu.au
A: One of the properties of the project is the "Startup Form". This can be any form in the project or a special case "Sub Main" which causes VB to load no forms by default but instead looks for a BAS module with a MAIN subroutine. In most projects the Startup Form is the plain form that VB creates by default when you start a new project. It is not an MDI form nor is it an MDIChild form. When you run the project this form is loaded and off you go. If you set your project so that the Startup Form is the MDIForm then VB will load the MDI parent form by default but will not load any child forms. The MDIForm_Load event can do that if you want or you can wait for the user to select menu options before creating child forms. If you set things so that the Startup Form IS an MDIChild form then VB will load the MDI parent form AND an instance of the child form by default. This is because you have asked for the child to be the startup but the child can not exist without the parent being there first. It sounds to me like you have the Startup Form set as the MDIChild and your MDIForm_Load is also loading an instance of the child. Check the MDIForm_Load and/or other events and see if that is your problem. QueryUnload vs Unload is another confusing area to the new VB programmer (and even to a lot of the "old-timers"). When you Unload a form from your code, or the user clicks the Close option on the title bar, or Windows needs to shutdown or restart the first thing that happens is that a QueryUnload message is sent to all affected forms. This is in effect asking 'Is it OK to unload you now?' and gives you the chance to save data and otherwise clean up what is happening. Typically if you have unsaved data you either save without asking or give the user a 'Do you want to save changes? Yes/No/Cancel' message box. If the user selects Cancel or for any other reason you can not terminate at this time you let CANCEL=TRUE and exit the QueryUnload event. This tells Windows to abort the Unload/Shutdown process. After every window has processed the QueryUnload message, and assuming none of them requested cancellation, every window is sent the Unload message which triggers the Unload event in VB. This is a last chance to save data, close files, etc. You can let CANCEL=TRUE here as well but it is not polite to do so. The reason is that some other windows may have already gotten the Unload messages and terminated and now you are cancelling so they shut down for no reason. You should have said you were going to cancel when you werre first asked in QueryUnload so that they could stay running. The order in which windows get the messages is not definable, but everybody gets the QueryUnload before anybody gets the Unload. In summary:

  1. QueryUnload occurs: make sure it is OK to exit at this point - if not set the CANCEL flag. If it is OK you can save if you want or wait for the Unload event. Note that the Unload may never come as some other window might Cancel the process so you should leave files open and be prepared to continue.
  2. Unload occurs: save anything you need to save, close files and clean up anything else you are using and exit

Q: When I first got VB4 Pro, I created a tutorial program in the VB directory. All of the forms, database files, and bmp images used by the program are in the VB directory. I decided that this was messy, so I moved all of these files to a subdirectory \VB\Tutorial. Whenever the program is run (from within VB) it cannot find the darn bmp files. It keeps looking in the VB directory even though it is started from within the \VB\Tutorial directory. None of the commands that bring the bmp images to the screen have path names in them. What am I missing here?
Ed VineYard
vineyard@enid.com
A: Take a look at APP.PATH which returns the path to the directory the EXE was run from. This may or may not be the current directory and it sounds like that is what is happening to you. The biggest problem is that if you are running in design mode the APP.PATH property returns the path to your VB directory and after compiling it becomes the actual production directory.


	Dim strPath As String

	strPath=App.Path

	If Right$(strPath,1)"\" then strPath=strPath & "\"

	' previous line needed because root returns C:\, subs have no trailing slash

	Open strPath & "Tutorial\filename" For Input As #1

Usually I end up having to kludge something for testing by adding something like:


	If Instr(strPath,"\PROGRAM~1\VB\") then strPath="C:\VB\"

This way I can hack around the problem of design vs compiled.


Q: How can I display a form at run time if the form name is stored in a variable. The version of VB I am using is 4.0.
Claude @asiaonline.net
A: There is no way to parse a variable at run-time. The best method is probably:


Select Case strFormName

Case "Form1": Form1.Show

Case "Form2": Form2.Show



End Select


Q: For some reason vb says "input past end of file" for this code:



Open "war.twn" for input as #1

     while not eof(1)

          input #1,bozo

          list1.additem bozo

     wend

I don't get it, it doesn't do the while wend part. I have VB 4.0 for Win 95.
Nick Puleo
puleo@concentric.net
A: The INPUT statement reads up to a comma or the end of a line from a text file. If you file contains binary data (e.g. if you look at it in Notepad you see garbage characters) then INPUT won't work - you would need to OPEN "WAR.TWN" FOR BINARY AS #1 and then use GET instead of INPUT. If the file is really plain text but each line can contain embedded commas or quotes then you should use LINE INPUT #1,BOZO to read it one line at a time regardless of what is on the line. The only other reasons I can think of for an error like this are:

  1. the last line of the file does not have the carriage return and newline characters at the end
  2. there is a ^Z (Control-Z) character in the file somewhere - DOS always used a ^Z as an end-of-file marker and files (especially those created with the DOS command COPY CON: ) had one at the end. The VB EOF function does return TRUE because it sees more data in the file (the ^Z character) but then INPUT trips over 'End of file'. Use NotePad or WordPad to view the file. If it looks OK, check the last line to be sure it is complete and that there is no ^Z after it.

Q: Can you tell me where I can found all the .dll files that must be loaded in to a pc with Windows 95 or Windows 3.xx to run a VB4.0 32 bits application.
Roberto Flores
ave@entelchile.net
A: You can't run a 32-bit application under Windows 3.x so there are no DLLs to look for in that case. The answer under Win95 depends on what the program uses. All programs will need VB40032.DLL plus several other standard DLL files most of which you probably already have. If you are developing a VB application then run the Setup Wizard which will analyze your code and come up with a list of what you need to distribute. If you are copying an existing application from another machine then it sounds to me like you should get the setup disks that were used originally or compare your windows\system directory to the original and copy what you are missing.


Q: I'm writing a procedure in Visual Basic 4.0 32 bit having five text boxes in a control array. We want the text boxes only to accept numbers or backspace. In the keypress event of the control we typed the following:



 If KeyAscii >= 48 And KeyAscii <= Or KeyAscii="8" Then char="Chr(KeyAscii)" KeyAscii="Asc(char)" Else char="Chr(8)" KeyAscii="Asc(char)" End If pre>

It works fine but when I press two or three numbers and after that a letter, I 

miss the last number. E.g. if I enter "1234a" the resault of the text box is 

"123".


Andrew Ladis


ADVISOR@ATH.FORTHNET.GR


A: The KeyPress event allows you to replace a keystroke by changing the value 

of the KeyAscii parameter or to eliminate it by setting it to zero.  Your 

problem is because you are replacing it instead of eliminating it.  What the 

textbox is receiving is "1234" so it dutifully removes the "4" and 

leaves you with "123".  What you are looking for is this:


If KeyAscii=8 Then Exit Sub ' Allow backspace with no intervention 

If KeyAscii>=Asc("0") And KeyAscii<=Asc("9") Then Exit Sub pre>Allow numbers 

KeyAscii=0 ' eliminate anything else 

Beep ' let the user know something wasn't right 

Note that I changed the constants 48 and 57 to Asc("0") and Asc("9") 

respectively.  This is to make the functionality of the line immediately 

obvious so that a maintenance programmer six months from know doesn't have to 

look up the ascii chart to figure out what you did.  You can also define 

constants or, in VB4 or above, use vbKey0 and vbKey9 instead as that would be 

faster executing.


Q: I'm trying to scan a picture(b/w)(bitmap) in an image box, the reason for using the imagebox is that it has stretch property which the picturebox doesn't. The problem is that I can't find the properties/functions to do that, seems that they are not supported for an imagebox. I want to know if the pixel is white or black and the current position of the marker. Can this be done in an imagebox? I am using VB 3.0
Hobil
96110287@student.napier.ac.uk
A: With a PictureBox you can use the Point method to get the RGB color of the selected pixel. Your best bet may be to put the image in the Image control to stretch it and then copy it to a PictureBox to query the pixel colors. If by the marker you mean the cursor then both controls have MouseMove and MouseDown events that tell you where the mouse is currently.


Q: I'm new to VB4 programming. I've read a several of the beginner books on the subject i.e "Learn Visual Basic 4 Today", "Teach Yourself Visual Basic in 21 day". I'm looking for a good intermiate book, that emphasizes the actual code more than how to make a command button. Any suggestions?
Bill.Nelson@anadigi.com
A: I'll leave this to the other readers - the only VB books I've ever read are the manuals.


Q: I'm taking a intro to VB class. My instructor suggested I use the following code in the click event of the control array. It errors out at the select case line. The code follows. Can you tell me what is wrong with it? I've worked three weeks on this and I'm falling behind. Thanks for any help you can give me.



Assign text to numbers

    sgNum1 = Val(txtNum1.Text)

    sgNum2 = Val(txtNum2.Text)

'Switch depending on which button was clicked

    Select Case cmdOpButton.Index  It errors at this point

        Case 0  'Add Button

            sgAnswer = sgNum1 + sgNum2

        Case 1  'Subtract Button

            sgAnswer = sgNum1 - sgNum2

	

Judy Thompson


DJThomp@aol.com


A: Since this code is in the click event of a control array named 

'cmdOpButton' then the opening line for the routine should be:


Sub cmdOpButton_Click (Index As Integer)

As you can see, VB is passing you the Index as an argument to the routine.  

You are trying to reference it as a property, which can be done, but you don't 

have a single button named cmdOpButton - you have an array of them.  To 

reference the property of any element in an array you have to specify the 

position in the array.  To do that here, you have to use the Index property 

that VB is providing you which tells you which command button to use.  You 

could, for example:


	Select Case cmdOpButton(Index).Index ' get index of currently active 

cmdOpButton

The Index property for the currently selected button will, of course, be the 

number of the button which is what VB told you in the first place.  In other 

words, what you want is:


	Select Case Index


Q: I am trying to get a Wizard-Made setup.exe to create a program group for my icons. I am developing a series of applications that will function similar to microsoft office - with a buttonbar to launch the different modules. I need the installation to create a program group so users can use only what modules they want.
Joel Lansden
digitalparadise@worldnet.att.net
A: Run the setup wizard to create the basic installation package. That will modify the source for the SETUP1 program under the SETUPKIT of your VB directory. You can then load that project and modify it. You should copy all of the files to a new directory and edit the .MAK or .VBP file or use FILE / SAVE AS for all modules to ensure that you custom copy is distinct from the one under VB. The code has lots of comments in it showing where to make changes. You can make it create whatever groups and icons you want and you can add or remove dialog questions as desired to get exactly the install you need.


Q: I have heard that you can write a dll file in VB¤. How do you go about it?
Isaac Kumalo
etxs.etxkumo@mesmtpse.ericsson.se
A: You can't do it in VB3 at all. In VB4 you create your project with Class modules and Public procedures and use the MAKE DLL option instead of MAKE EXE on the FILE menu. In VB5 an ActiveX DLL is one of the new project templates. In either case the DLL is not directly usable with Declare statements like one created by C++. VB puts an OLE wrapper around your code and you "Dim oMyDLL As " and then use oMyDLL. to access it. For VB5 you can get an add-on from Desaware that will export your functions so that they can be used like a standard DLL file.


Q: I was wondering if you knew of anyway to get a file's attributes, such as date stamp and file size. I know that you can open up a file and determine its size but this method is impractical when you're dealing with hundreds or thousands of files.
Jim Pragit
jpragit@niu.edu
A: Within VB you have the GetAttr, FileDateTime and FileLen functions without opening the file.


Q: I can't get this program working the way I want. I am using VB3. I want to have when you click a button it will look through a text1 box and change all the A's to X's and all the B's to Y's. I have been trying for a wile and i can't get it to work. I get it so it will change the first letter to what i want but it will not look past the first letter. This is the code I have so far that will do what I said.



Sub mnuEncode_Click ()

    Dim userinput

    Dim A

    userinput = Text1.Text

        On Error Resume Next

        Select Case Asc(userinput)

            Case 65

                A = text2.Text & "X"

                text2.Text = A

            Case 66

                A = text2.Text & "Y"

                text2.Text = A

    End Select

End Sub

Dave


AngerBuRn@worldnet.att.net


Sub mnuEncode_Click()

Dim x As Integer ' Note: you should always specify the variable type 

explicitly

Text2.Text="" ' Clear Text2

For x=1 To Len(Text1.Text) ' Loop through text

  Select Case Mid$(Text1.Text,x,1) ' get this character - could use 

Asc(Mid$(Text1.Text,1))

    Case "A": Text2.Text=Text2.Text & "X" ' Use "Case 65:" if you use the ASC 

function

    Case "B": Text2.Text=Text2.Text & "Y"

    Case Else: Text2.Text=Text2.Text & Mid$(Text1.Text,1)

  End Select

Next x

End Sub


Q: I'm trying to know whats the use of the VB40016.DLL?
Antonio Lorvao
antonio.lorvao@imperio.pt
A: VB40016.DLL is the run-time environment for 16bit VB 4.0 - it replaces VBRUN300.DLL which was for VB3. There is also VB40032.DLL for 32bit VB 4.0. When you "compile" a VB3 or VB4 program it does not actually become executable code. Instead, VB creates P-Code (PseudoCode) which is essentially just a condensed version of your source. The EXE file that is created is a small "stub" program followed by this compacted version of your code. The stub loads VB40016.DLL and calls routines in there to run your program. Those routines read the p-code data and perform the instructions requested there. This is why VB4 (and earlier revs) is more appropriately called an 'interpreter' and not a 'compiler'. VB40016.DLL interprets your instructions line by line and executes them for you - the CPU only executes code in the runtime library (except for the little startup routine VB puts in the EXE). In VB5 you have the option of compiling to true machine code which is directly executed by the CPU. Note that VB5 still needs a runtime library but only because your EXE will call routines from it. For example, the code to create and draw a form is in the MSVBVM50.DLL file and not in your EXE. When your code needs to create a form it calls a subroutine in the runtime library to do it and just passes the parameters for size, location, etc. The advantage is that common routines needed by all VB5 applications is in one shared file and not duplicated in every EXE so it can keep the EXE files smaller.


Q: I have been working slowly but surely on my VB word processor. I've figured out how to put a tool bar on a MDI form and also the problem with my find and replace subroutines. But a few things still baffle me -- For example, how do I do pages in RTF box? Like in Word 97, you can only type so much stuff on a page before you go to page 2. And how do you control the Top, Bottom, Left and Right margins Both on screen and on printer?
Xin Li
x_li@colby.edu
A: The RichTextBox does not support page breaks. While you can probably work around this by using a special sequence in your code, creating RTF files that other apps can read will mean parsing the .TextRTF data and inserting the proper codes when saving the file and doing the reverse on opening in your application since any page breaks in the RTF file will be ignored. The ScaleHeight, ScaleWidth, TextHeight and TextWidth methods can all be used to determine where you are on a page and the CurrentX and CurrrentY properties can be used to position output appropriately.


Q: I'm trying to make an app (it puts an icon in the systray) to press the 'No' button when Internet Explorer pops out the cookie 'Security Alert' message. The problem I have is that my app doesn't always work if the focus is elswhere. Here's my code:



Dim x As Long

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _

        (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private Sub tmrCookie_Timer()        'tmrCookie.interval = 100

Dim Cookie As Long

    Cookie = FindWindow(vbNullString, "Security Alert")

    If Cookie = 0 Then

        Exit Sub

    Else

        SendKeys "%{N}"

    End If

End Sub

Should I use loop instead of a timer?


Clarence Chau


clarence@cadvision.com


A: I like it!  I refuse all 'cookies' myself and am tired of clicking NO every 

time.  I would really like to see a way to disable them entirely like you can 

do with ActiveX controls.  Using either a loop or a timer should work equally 

well for this, except that a loop may make the system seem more sluggish as it 

will be executing the code continuously.  If you are writing in a 32-bit 

version of VB you can add a call to the API SLEEP function to slow it down.  

If this is 16-bit, I'd probably stay with a timer.  You may need to make it 

get the focus using App.Activate though:


Sub main ()

Dim x As Integer

Do

  x = FindWindow(0, "Security Alert")

  If x Then

    On Error Resume Next

    AppActivate "Security Alert"

    If Err = 0 Then SendKeys "N", True

  End If

  DoEvents

Loop

End Sub


Visual Basic 5.0

Q: Just finished reading your introduction on VB5 - and I agree having to mail 

in for the manuals to be a drag. In any event, are you familiar with the 

installation issues for VB5? For example, VB4 and VB5 can't exist on the same 

machine. And that VB5 installs in a different directory thus I thought VB4 

would go away yet now I still have it on the machine and I'm a little bit 

scared to uninstall it based on the above. Any thoughts?


Steve Fredrickson


fredrisg@sce.com


A: Well, I did not know about the issues before I loaded VB4 but I uninstalled 

VB4 before loading VB5 anyway.  This was mainly because I have spent the last 

few months fighting issues with Office 97 installs screwing up every system 

they touch by loading incompatible DLL files.  I also thought about all the 

glitches involved in loading VB3, VB4-16 and VB4-32 on the same system and all 

the aggravation that loading VB5CCE caused for developers.  My assumption was 

that if Microsoft could screw those up that badly that they probably did the 

same with VB5.  Evidently VB4 and VB5 share some DLL names, but the versions 

are not compatible and the line I am hearing through the newsgroups is that 

the recommended approach to running both is to create a dual-boot system with 

different Windows & Windows\System directories to keep them totally separate.  

I find that totally unacceptable, but I also have no use for VB4 any more.  If 

I need to support 16-bit systems with an application it will be VB3 and will 

stay VB3 until all users can be upgraded even if that limits it under Win95 & 

NT.  New applications will be VB5 and not available to 16-bit users.  This is 

how MS is forcing everybody to go and while I'm not thrilled with the tactics, 

I tend to agree with the goal so….  In your particular case I would back up 

the registry and the Windows & Windows\System directories and un-install VB4.  

If it asks about removing shared components don't let it remove them (or at 

least note what they are).  I would then re-install VB5 (even if it appears to 

work) and keep my fingers crossed.  


Q: I am currently using VB4 (Pro), and I feel that the time it takes to start VB4 programs (I mean .exe programs made by VB4) is too long. I heard that it takes a lot of time to load vb40032.dll and other necessary .dll files, and that's why it takes so much time to start VB4 programs. Now I heard that VB5 improved its speed. But I don't know if it improved the time it takes for a program to start. Can you tell me whether or not .exe programs made by VB5 starts faster than those made by VB4?
Kazushi Oenoki
97kaoeno@amersol.edu.pe
A: I think you will find an improvement but it is hard to give any unqualified numbers. VB 5.0 does handles forms faster than VB 4.0 did so that part of the startup is faster. With VB4 you had to load your EXE and then wait while that loaded VB40032.DLL which was needed to run the pseudocode that was "compiled" into your EXE. Assuming that you have compiled your VB5 application to native code then at least some of it can get started right away. Of course, VB5 apps still need the code in MSVBVM50.DLL (Microsoft VB Virtual Machine 5.0) so that will be loading before anything gets very far. Since all that is out of the hands of the VB developer you need to look at how you start your code. If you do a lot of initializing or time-consuming actions like opening databases in your Form_Load then you should consider adding code to display your form first:


	Sub Form_Load()

	Me.Show

	Me.Refresh

	

	End Sub

I would also consider adding a splash screen to your applications.  What I do 

is have the spalsh screen set as the startup form so that it gets loaded 

first.  Since it has virtually no code or data the load is fast and the form 

is displayed.  The load event has just:


	Sub Form_Load()

	Me.Show

	Me.Refresh

	Load frmMain ' load "real" startup form

	End Sub


The Form_Load event for the 'frmMain' form ends with:


	Me.Show

	Me.Refresh

	Unload frmSplash

	Set frmSplash=Nothing

This way I get the splash screen quickly and it stays up until the main form 

is initialized and displayed.  It doesn't make loading any faster, but the 

distraction provided by the splash screen makes it less bothersome.


Q: Well, I went ahead a purchased VB4.0 Enterprise Addition. I am leaping to my death for sure. I am a programmer familiar with older languages like DbaseV and FoxPro, however my skills at Vb4 are surely in the needy category. This offset has me looking to the internet for help and examples. I am somewhat familiar with the basic design of Vb programs and can do some cool things, yet I strive for the ultimate, which is to go interactive over the net. Meaning non-static natured webpages, user controls for order_entry at remote ftp sites, and Inventory controls at remote sites. I have searched for help for days now and am in need of your talent in this area. Can you tell me a great Vb web site that helps with internet connectivity? Can you suggest a book or two?
oldc1@stlnet.com
A: Well, if you really purchased VB 4.0 EE then my first suggestion is that you call Microsoft and get the price for the upgrade to VB 5.0 EE. It should be very reasonable since they have a lot of deals for recent VB4 buyers. VB 5 allows creation of ActiveX controls and documents and sounds like the arena you are interested in (although I wouldn't consider that the "ultimate" myself). There is quite a bit of stuff on Microsoft's website about this sort of thing and, after you weed through what their sales and marketing hyped up about it, there's even quite a bit of substance in it. I would also check their "Personal Web Server" (Win95) or "Peer Web Services" (WinNT) as it supports ASP (Active Server Pages) which can theoretically be used to write complete database applications using only a web browser on the client side.

Using the API

Q: Using VB4 or VB5 (32-bit) on Win 95 I'm creating an HTML editor and would 

like to add colored HTML tags in a rich text box.  What I mean is, if a tag 

(such as TITLE) is written I want that text to be a different color than 

black.  I've tried using the SelColor property with limited success, but my 

problem is searching through a file that is loaded into the rich text box.  

Also, when the user is editing a file, I want to check just the line they 

completed rather than check the whole file.  I can't even figure out what line 

the user is on.


Steve


bravhaart@relia.net


A: The INSTR function will let you search the text to find the starting 

position.  As for determining where you are, try these functions:


Const EM_GETLINE = &HC4

Const EM_GETLINECOUNT = &HBA

Const EM_LINEINDEX = &HBB

Const EM_LINELENGTH = &HC1

Const EM_LINEFROMCHAR = &HC9

Declare Function SendMessage Lib "user32" Alias "SendMessageA" _

(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _

lParam As Any) As Long

Dim lngCount As Long ' number of lines in textbox

Dim lngLine As Long ' current line number (0 through lngCount-1)

Dim strLine As String ' text of current line

Dim lngStart As Long ' starting byte (0 though .Len-1)

Dim lngLen As Long ' length of current line

Dim x As Long

lngCount = SendMessage(RichTextBox1.hwnd, EM_GETLINECOUNT, 0, ByVal 0&)

lngLine = SendMessage(RichTextBox1.hwnd, EM_LINEFROMCHAR, _

RichTextBox1.SelStart, ByVal 0&)

lngStart = SendMessage(RichTextBox1.hwnd, EM_LINEINDEX, lngLine, ByVal 0&)

lngLen = SendMessage(RichTextBox1.hwnd, EM_LINELENGTH, _

RichTextBox1.SelStart, ByVal 0&)

x = lngLen + 3 ' allow for CRLF & NULL at end of string

strLine = Chr$(x And 255) & Chr$(x \ 256) & Space$(x) ' put max size into 

buffer!

x = SendMessage(RichTextBox1.hwnd, EM_GETLINE, lngLine, ByVal strLine)

MsgBox "Line " & Format$(lngLine) & " of " & Format$(lngCount) & _

  "; Start=" & Format$(lngStart) & _

  "; Length=" & Format$(lngLen) & ":" & Format$(x) & _

  "; line='" & Left$(strLine, lngLen) & "'"


Q: I'm using two Rich Text Boxes side by side and I want them to scroll together. If one scrolls I want the other to scroll too. If one reaches the end of course it will not move further, but basically what I need is two simultaneous scrolling Text Boxes. If there is any other control that I should be using, please advise me.
Diego
el-loft@shadow.net
A: There isn't an event that I know of to tell you when a RichTextBox scrolls. This makes doing what you are trying to accomplish awkward. The solution I have seen work is to use a timer with a fairly brief interval (under 1 second) and manipulate the .SelStart property of the second box to make it match the first. The code above should help get you started and you can probably also use the following:


Const EM_GETFIRSTVISIBLELINE = &HCE

Dim lngTop As Long

lngTop = SendMessage(RichTextBox1.hwnd, EM_GETFIRSTVISIBLELINE, 0, ByVal 0&)


Q: I 'm using VB4.0 Pro and I like to let the user read a very boring text before he can run the program. My idee was to put a button on the form where the user can push on ONLY if he reached the end of the text. How can I let the PC know that the scroll-bar (aside the text) as reached the end ? Is there something like RichTextBox.VerticalScrollbar.Value ?
GeertVer@DMA.be
A: See the previous two questions – you can check what is visible on the screen easily enough. Determining if they actually read it or not isn't possible unless you want to give them a little quiz!


Q: I'm developer in VB 4.0 , C++ and J++, in healthcare company. I need to use the tray icon's bar of windows 95. I've called Api functions to add or remove icons and tooltips into the tray, but how can I receive the click event of the user on my icon in the Windows's tray, for exemple for starting a pop-up menu from my application ? I need to check to mouse click event from the user on the tray; not on my application !
Philippe B.
Pboutrem@skynet.be
A: In VB5 you have new options to help with doing this sort of operation, but it is possible in VB4. What I have done is to add a control or form to my project to use solely for getting tray icon events. The .Visible property is set False so the user can not see or access it in any way. In the call to create the icon I pass the hWnd of this special object and the WM_MOUSEMOVE value for the callback message. When the user moves over the tray icon or clicks on it my hidden object gets a MouseMove event which I know had to come from the tray icon. The X value in the MouseMove event can be divided by the Screen.TwipsPerPixelX value to get a number that indicates what really happened.


Q: I need some conversion functions in my Visual Basic programs (like functions CVx or MKx$) that converts n-byte strings to number and vice-versa. I have found help about using API call "Declare Sub hmemcpy Lib "Kernel" ..." but there is no library kernel.dll in Windows95. There is kernel32.dll in which I have not found procedure hmemcpy. So my question is, where can I find an API function which is equivalent to hmemcpy?
Roman Antol
dcsoft@netlab.sk
A: This one took me quite a while to track down when I first got VB 4. The function exists in Kernel32 but has been renamed. Try this (and be VERY careful using it):


Declare Sub hmemcopy Lib "Kernel32" Alias "RtlMoveMemory" _

(xdest As Any, xsource As Any, ByVal xsize As Long)


Q: I would like do create scrolling text in a program. The style that I would like is ether like IE 3 of down to up like the credits in a movie.
Stevie RG
stevierg@geocities.com
A: You have two choices: you can search for a marquee control that will do this for you or use the API to build it yourself from VB. My preference would be to use a timer and a picturebox or two along with the BitBlt and DrawText API calls to create the effect. Some sample code follows - to use it start a new project and add two picture boxes, one checkbox and one timer. Change the name of Picture2 to picMarquee, set the caption of Check1 to "Scroll Vertical" and disable the timer. Then paste in the following code:


Const SRCCOPY = &HCC0020

Const DT_CENTER = &H1

Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, _

ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, _

ByVal wFormat As Long) As Long

Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, _

ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, _

ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, _

ByVal dwRop As Long) As Long

Sub Form_Load()

Dim x As Long

Dim picRect As RECT

Picture1.AutoRedraw = True ' set required properties

Picture1.ScaleMode = vbPixels

Picture1.Visible = False ' Picture1 is just a scratch area

Picture1.Width = picMarquee.Width

Picture1.Height = picMarquee.Height

Me.Show: Me.Refresh ' get form visible on screen

picMarquee.AutoRedraw = True

picMarquee.ScaleMode = vbPixels

picRect.Top = 0 ' set area for drawing

picRect.Left = 0

picRect.Bottom = picMarquee.ScaleHeight

picRect.Right = picMarquee.ScaleWidth

x = DrawText(picMarquee.hdc, "Scrolling Text", -1, picRect, DT_CENTER)

picMarquee.Picture = picMarquee.Image ' update display

Timer1.Interval = 10 ' start timer: may need to play with this value

Timer1.Enabled = True

End Sub

Sub Timer1_Timer()

Dim x As Long

Const HORIZONTAL = 3 ' number of pixels to move each time

Const VERTICAL = 4 ' may need to play to reduce flicker

If Check1.Value Then ' scroll vertical

' first copy bottom portion of image up 

  x = BitBlt(Picture1.hdc, 0, 0, picMarquee.ScaleWidth, _

    picMarquee.ScaleHeight - VERTICAL, picMarquee.hdc, _

    0, VERTICAL, SRCCOPY)

' then copy top few pixels to bottom area

  x = BitBlt(Picture1.hdc, 0, picMarquee.ScaleHeight - VERTICAL, _

    picMarquee.ScaleWidth, VERTICAL, picMarquee.hdc, _

    0, 0, SRCCOPY)

Else ' scroll horizontal

' first copy right-hand side to the left

  x = BitBlt(Picture1.hdc, 0, 0, picMarquee.ScaleWidth - HORIZONTAL, _

    picMarquee.ScaleHeight, picMarquee.hdc, HORIZONTAL, 0, SRCCOPY)

' then copy leftmost columns of pixels to right-hand edge

  x = BitBlt(Picture1.hdc, picMarquee.ScaleWidth - HORIZONTAL, 0, _

    HORIZONTAL, picMarquee.ScaleHeight, picMarquee.hdc, _

    0, 0, SRCCOPY)

End If

picMarquee.Picture = Picture1.Image ' update display

End Sub


Q: I am trying put a bitmap in a menu. I have 2 picture controls and use the following code:

But the picture is not loaded in the menu.
Mabel Espinoza E.
mee@tci.net.pe
http://www.tci.net.pe
A: Your main problem is that the ModifyMenu call has a string for the last parameter and you are passing the handle to a bitmap. That is passing the wrong info to the API call and causing it to fail. You were also passing the wrong menu handle. Here is the revised code that is working for me in VB 5 and should work for VB 4 (be sure to set AutoRedraw=True for your pictureboxes):


Private Declare Function ModifyMenuPic Lib "user32" Alias "ModifyMenuA" _

(ByVal hmenu As Long, ByVal nPosition As Long, ByVal wFlags As Long, _

ByVal wIDNewItem As Long, ByVal lpString As Long) As Long

Private Declare Function GetMenu Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function GetSubMenu Lib "user32" (ByVal hmenu As Long, _

ByVal nPos As Long) As Long

Private Declare Function GetMenuItemID Lib "user32" (ByVal hmenu As Long, _

 ByVal nPos As Long) As Long

Const MF_BITMAP = 4

Const MF_BYCOMMAND = 0

Const MF_BYPOSITION = &H400&

Sub Form_Load()

Dim hmenu&, hSubmenu&, menuid&, result As Long ' Note the "&" characters

' the syntax "Dim hmenu,result As Long" creates hmenu as a variant

' the syntax above, or "Dim hmenu As Long,result As Long", is better

Me.Show ' I added the "Me." out of personal preference

hmenu = GetMenu(Form1.hwnd) ' get handle to form menu

hSubmenu = GetSubMenu(hmenu, 0) ' get handle to first submenu

menuid = GetMenuItemID(hSubmenu, 0) ' get ID of first submenu item

result = ModifyMenuPic(hSubmenu, menuid, MF_BYCOMMAND Or MF_BITMAP, _

menuid, Picture1.Picture) ' change first submenu item to bitmap

menuid = GetMenuItemID(hSubmenu, 1) ' get second item ID

result = ModifyMenuPic(hSubmenu, menuid, MF_BYCOMMAND Or MF_BITMAP, _

menuid, Picture2.Picture) ' change to bitmap

End Sub


Q: I am a new to Visual Basic4 programming and am trying to create an application to show the cpu load and have no idea where to start.
Scott Willson
boweeble@rapidcity.com
A: This is not something that is built-in to VB but there are several Windows API calls that can return information about the system status: GetFreeSpace, GetFreeSystemResources, GetSystemMetrics, GetVersion, GetWinFlags. Under Win95 you can also read the HKEY_DYN_DATA section of the system registry which records performance information and is probably your best source of data (this is not available under NT). It all depends on what OS you are using and what you define as 'CPU load'. If you don't have it, I strongly recommend getting Daniel Appleman's "Visual Basic Programmer's Guide to the Win32 API" if you are going to be doing system programming. I understand that a version for VB5 is also coming out which covers API calls that are now more accessible with the new features in VB 5.0.


Accessing DataBases

Q: I am new to VB 4.0 and trying to develop a client/server application but 

after some readings I found that I am confused about some items :



1.Rowset

2.Recordset

3.Resultset

What is difference between them? and when each of them is used?


Ahmed Abdel Aziz


R&D Engineer


ahmed@arabic.ie-eg.com


A: RecordSet and ResultSet are, as far as I know, effectively synonymous.  In 

VB you use OpenRecordSet to ask for information from an open database.  The 

RecordSet object that comes back holds the ResultSet which is the whole of the 

data that met the criteria you asked for in the OpenRecordSet request.  The 

ResultSet is the data, the RecordSet is the object that VB provides to let you 

look at it...  In many cases that number of records in the complete ResultSet 

may be very large so the server only sends part of the data.  Each block of 

rows is a RowSet and just indicates "the part of the ResultSet that is 

currently available in local memory".  When you are working with intelligent 

servers (e.g. SQL Server) and large databases you may want to look into the 

options of controlling the RowSet size to improve performance in your 

application.


Q: I don't know if you recall our email from 2 months ago, but I was having problems with CommitTrans telling me that I had not used BeginTrans when I had. I seem to have found some kind of strange workings of transaction processing, that solved my errors. I found it by looking at one form I had where the transaction processing was working fine and comparing it to a similar form where I got the error we spoke of. It seems that the differences were on the table type, i.e. some of the tables were defined as Dynasets and others were defined as Tables. On the form where the TxPro worked, the data controls were all defined as Tables, and on the form the had the errors, some of them were Dynasets. There was no need for them to be defined as Dynasets, so I changed them to tables and my TxPro worked!!! I couldn't find anything on this anomaly in the online books, except for a mention: "Dynaset-type Recordset objects based on tables created by other database products, however, may not support transactions. For example, you can't use transactions in a Recordset based on a Paradox table." Well these tables were all MDB tables!! I'm glad that I finally solved this problem, but wish that it was obviously documented somewhere. Also, I took a tip from the online mag that stated you could easily check for nulls in numeric fields by using the following code: anum = 0 & data1.recordset.fields("numfield") This didn't seem to work when there was a negative number involved. I ended up giving anum the value of "0-12.34" when to field val was -12.34.
Darryl Minsky
Calgary, Alberta, Canada
Stallion Software Systems
http://www.cadvision.com/minskyd/stallion.htm
A: Glad to hear you got it. I'll have to look into that one - it makes some sense as handling Dynasets is more complicated than handling Tables directly. You trade efficiency for flexibility as with most things. If I remember right you were using a data control and I can definitely understand it making use of BeginTrans and CommitTrans itself when using Dynasets - if anything I am surprised that it lets you get away with Tables in this manner. Regarding the Null test I hope it wasn't something I wrote... The '&' is a string concatenation so it would convert everything to a string and then the assignment would attempt to convert it back and that would be invalid for negatives. I've run into this one myself (although not with Nulls - just trying to avoid using VAL on an invalid string) and it has taught me to be careful about implementing tips without checking them carefully. You MIGHT be able to use '+' instead but that may not like adding a null value. The IsNull function is probably the best option for testing NULLness.


Q: Using Visual Basic 4.0 Pro I would like to create a DBGrid(displaying a list of data) which I can move/copy a record from one row to another row. The destination row must NOT have any data before I can do the move/copy process.
monasa@pc.jaring.my
A: I'm not sure I understand the question. The DBGrid is used to display fields from a recordset created by a data control. To add rows you would add a row to your database and refresh the grid… I may be missing something here as I never use bound controls because I always want more direct control over what is going on. I would have an unbound grid that I populated myself and would add a row whenever I added a record to the database.


Q: I am trying to insert a picture from an Access database into Word 6.0 using VB 4.0 (16-bit - after I get this to work I will also need it to work with 32-bit). I am converting the picture in the database to a bitmap file and then trying:



fh = FreeFile

Open "c:\temp\photo.bmp" For Binary As fh

bmpdat = datDB.Recordset!Photo

Put fh, , bmpdat

Close fh

objWord.InsertPicture

Whenever I do this Word comes back and wants to know how to convert it.  I 

used an example project called VISIBASE.  All of the pictures that are shipped 

in the example work fine, but whenever I put a picture in the database I can 

view it on the online form, but I can't insert it in a

Word document (the thing that I really need).   By using a Watch window I've 

noticed that bmpdat starts with "BM" in the picutres that come with the 

example, but mine start with "it". If I'm going about this completely wrong, I 

would appreciate some help about a better way to get an embedded picture into 

an Access DB and then from Access (using VB) to a Word 6.0 document.


Bryan Pollard


bsp@ols.net


A: Have you looked at the rest of what you have from the database to see if 

they really are bitmaps?  You are correct that standard bitmap format has BM 

as the first two so I suspect you have some other format there.  I would start 

with the way you select and add the bitmap to the database - you may be doing 

something there that corrupts it.  My only other selection would be to try 

using Clipboard.SetData and telling Word to do a Paste.


Operating System Quirks

Q: I used the SetupWizard provided with VB4 Professional Edition to create an 

install package for a project of mine.  I took this package and ran the setup 

on another machine (w/o VB on it).  After it copied the initialization files, 

it gave me an error saying "unexpected error; quitting".  I looked into the 

problem and found that setup132.exe failed when setup tried to spawn it.  It 

gave me the same exact error, "unexpected error; quitting".  But setup132 

executes fine on the machine I created the project on.  What does setup132 

need (besides command line arguments) to run on a machine without visual basic 

and will this solve my problem?


Kevin LeBlanc


kleblanc@eece.maine.edu


A: Check OLEPRO32.DLL and OLEAUT32.DLL - this error shows up if one of them is 

missing or out of rev.  It has become a common problem since VB 5 and Office 

97 released.


Miscellaneous

Q: I started a program with C++ and I got stuck...  A good friend told me that 

I could convert the C++ format over to the VB format.  Well, I decide since VB 

seems easier that I would get rid of C++ and get VB 4.0.  Now when I got home 

from the store I installed the VB 4.0 16 bit Profession Version.  My good 

friend told me that this version would convert the C++ source code to VB.  

After installing it I needed some more space so I deleted C++.  After reading 

the whole help file and book I couldn't translate the files.  So, I decided 

that I would contiune finishing my program with C++ and find help, but when I 

went to re-install the program it said it had a virus .  I stop right there 

and bought a Virus Scanning and cleaning program call McAfee.   But for some 

reason it didn't work...  So I trashed the disks...  Now can you please tell 

me where I can get a free or cheap translater so I can complete this project 

for work.  I already spent over $1,250 with this software and trying to get my 

project done.  I'm not very interested in buying another product, so if you 

can please try to tell me that I can get this translater for free or cheap...  

Tha Panther


tha_panther@hotmail.com


A: There is nothing I know of that will convert C++ to VB automatically.  You 

need to either re-write it in VB or get C++ re-installed.  I'm not sure what 

told you that you had a virus if you did not have a virus scanner active 

already.  I have had occurrences where after installing an application I tried 

to run it and got a message box that loading would stop because a virus was 

detected.  Rebooting the system cleared that and a virus scan found nothing.  

I don't use McAfee myself, but it should have a way to create a bootable 

floppy that can do a scan.  You should format the floppy on a known clean 

system and then boot your system with the floppy to be sure you have no 

memory-resident viruses.  You should also be able to scan the C++ diskettes 

before installing them.


Q: I have a question about the webbrowser control. Is there any way to control the scroll bar in the webbrowser control? I want my program to slowly scroll the screen downward.
Pin Tan
lonegunmen@worldnet.att.net
A: The only thing I can think of that might work would be to use AppActivate to set focus on the browser and use SendKeys "{Down}" to send a down-arrow periodically.


Q: I am a final year student of Bachelor of computer science at Swinburne University (Melbourne, Australia). Now I have a final year project which is about Visual Basic and I have some questions with that. Q1. Could you tell me the way to write the help topic title in a help topic file including its footnote marks and the footnotes themselves for a topic titled "Recovering after a power failure". include it as the third member in a browse sequence with the browse prefix "RECOVERY". add the topic title to the search engine's keyword list. Give the topic the jump label REC_POWER_FAILURE. Q2. with reference to the previous question, the words" power failure" in the topic title should be a hot spot that allows jumping to a pop up box containing a definition of a power failure. How can this be implemented?
Kenny WONG
082232@bud.cc.swin.edu.au
A: I'm not sure what any of this has to do with VB, except that a good VB app should have a decent help file along with it. The Help compiler takes RTF documents created by Word, or other processors, as input to create the files. Each page is a topic and footnotes, hidden text and 'strikeout' text are used to create jumps and popups. Offhand, I don't remember which is which and I am a bit hesitant about doing somebody else's homework anyway. I will suggest that you go to the Microsoft web site and search for information about WHAT6 or the Help Compiler. They have a free download that can be used to help format RTF documents and plenty of documentation on what the codes are.


Q: I'm a little confused here. I can create a telnet client , non-blocking on port 23 and connect, send-recv data, and then close. Now if I create a server I can do all that but, I would like it to be able to accept 40 connections at one time.. I can do this but keeping track of them is a little hard. Whether it be connecting or closing, sending or receiving its getting confusing.. Now if I create a array to handle them all thats fine but how can I find out when what does what? Create a timer and keep checking the sockets (HOW)...
Jason Ludwig
lludwig@neo.lrun.com
A: I just did an application last week that did exactly this. The approach I took was to create an MDIForm to act as the main server and an MDI child form to handle each connection. The MDIForm opens a socket on port 23, set non-blocking mode and waits for a connection. When one comes in, I accept it in the MDIForm's code and then create a new instance of the child form and pass the socket number to it. The child form then sends and receives as necessary. When the socket closes the child unloads itself. This made coding simple since I only had to code for a single socket. It also gave me a convenient way to interactively check the status since I made the child form show what was happening and I can then just click on the various forms to view them as they run. If I had to do it all without multiple forms I would probably set up an array of sockets as you mentioned and also an array of controls on a single form (probably all with Visible=True). When I put a socket into an array element I would use the WSAAsync call to send a mousemove event to the corresponding control in the control array. That way when control number 5 gets a mousemove I know that socket(5) is the one that has activity ready.