home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-08-04 | 32.2 KB | 1,078 lines |
- VB Tips
-
- Compiled by Nelson Ford, 71355,470
- For distribution on the MSLANG Forum only.
-
- This is a compilation of information about VB that has flowed through the
- Forum here (plus my own input). The hope is that new users can refer to this
- file rather than having to ask the same questions on the forum all the time.
- Experienced users whose memory is bad as mine might benefit from this as well.
-
- Main contributors are:
- Jonathan Zuck
- Keith Funk
- Mark Novisoff
- Ted Young
- Dennis Harrington
- the Microsoft Section Leaders
-
- Note: There are a number of very valuable free DLL's and VB routines on DL1
- ("New Uploads") and DL6 ("VB"). It is highly recommended that you Browse these
- two DL's. A few are mentioned in this file, but many more are available.
-
- Uploading: If you would like to share your coding with others, upload to DL1,
- not DL6. All new uploads go to DL1 for 30 days and then are moved to the
- appropriate DL (6, for VB). Do NOT put VBRUN100.DLL in your archive, nor any
- of the other DLLs that are available on here. All that does is increase the
- download time for everyone who already has those files. Instead, in your
- upload description, just tell people that they need to download those files
- too, if they don't already have them.
-
-
- CONTENTS: [Names in brackets are files in the MSLANG DL's 1 or 6.]
-
- General:
- Button Colors
- .EXE Size
- Far Pointers
- Help Files
- Icon - Get Rid Of
- Networks & VB
- Saving Your Work
- Screen type
- Sound.DLL (Need TPW)
- Type...End Type
-
- Arrays:
- Dynamic Arrays
- [VBSORT]
-
- Combo Boxes:
- Changing Text
- Color
- Pseudo Combo Dropdown List Box
-
- DOS Functions:
- File Copying
- [VBDOS]
-
- Form & Control Placement, Sizing:
- Controlling Form Size
- "Floating" Window
- Form Size and Granularity
- Grouped Controls
- Mouse Pointer, Position
- Placing Forms, Controls
-
- File I/O:
- Btrieve
- Deleting Data in Sequential File
- MKI$ & CVI in VB
-
- Fonts:
- Using Different Fonts, Colors in a Box
- System Font
-
- Forms: (Also see "Form & Control Placement, Sizing", above)
- Focus & Order of Execution
- Focus on StartUp
- SetFocus
-
- Keyboard & Mouse:
- Trapping Double-Click before Click
- Using "Enter" in Place of "Tab"
-
- List Boxes:
- Finding an Item Added to a Sorted List Box
- Inhibiting Screen Updating
- Linking Sorted and Unsorted List Boxes
- Searching For An Item
- [VBSORT]
-
- Picture Boxes:
- Copying a Drawing to Clipboard
- Drawing - Scale
- Saving Picture Files
-
- Printer:
- Printer Setup
- Printer Control Codes
- Printing Forms
-
- System:
- Calling the Windows 3 Calculator
- hWnd for a Control
- .INI Files
- Multi-Instance App Prevention
- SendMessage
- Windows Termination
-
- Text Boxes:
- Cursor (text), Position
- Data Entry Masking
- Data Entry Routine
- Data Entry Text Limit
- Flicker
- Flashing Text
-
- Timer
- Using the Timer
-
-
-
-
-
-
- Button Colors:
-
- Button colors are controlled by WIN.INI. See the 6/11/91 issue of PC Mag
- for details. Of course, changes you make there apply globally.
- ---------------
-
-
- .EXE Size:
-
- 1. Long variable names increase EXE size.
- 2. Comments add a couple of bytes per line to EXE size.
- 3. A Global DIM of an array adds to EXE size.
- For example:
- Global sample as string*20000
- will add about 20k to the size of the EXE file, but the same DIM
- in a Form will not.
- ---------------
-
-
-
- Far Pointers:
-
- Here's a question regarding direct calls to the Windows API from a Visual Basic
- procedure. In trying to set up a call to the API entry "Polygon", I discovered
- that one of the arguments is a far pointer to an array of structures. I've
- searched the VB documentation, but can't find a method that will return the
- run-time address of a variable (or an array element) as a far pointer.
-
- Is there a VB technique for passing a far pointer as an argument -- if so, how?
- Also, how would such an argument be specified in the corresponding DECLARE
- statement? Many thanks to anyone who can supply this information.
-
- (Fm: Mark Novisoff (TA) 73047,3706)
-
- If the structures themselves don't require pointers (which is the case with
- Polygon), then it's a piece of cake. Use TYPE...END TYPE to declare a model
- structure, and then DIM an array of the structures.
-
- In your Global module Declare statement, use the "As" syntax:
-
- Type Points
- ' Define the structure
- X As Integer
- Y As Integer
- End Type
- Declare Function Polygon Lib "Gdi" (hDC%, MyStruc As Points, nCount%)
-
- In your code:
-
- ReDim MyStrucArray(0 To 10) As Points
- ' Set the variables in the array here
- Result = Polygon(hDC%, MyStrucArray(0), nCount%)
-
- Note that this results in passing a far pointer to the zeroth element of the
- array. Because the length of the structure is known to the DLL routine, it
- will figure out where the rest of the elements are.
- ---------------
-
-
- Help Files:
-
- 1. You can create Help files more easily and cheaply than with the SDK: use
- the help compiler (HC.EXE) that comes with Turbo Pascal for Windows and
- Borland C++.
-
- 2. A shareware program named Xantippe is a good front-end for making help
- files.
- ---------------
-
-
- Icon - Get Rid Of:
-
- 1. Click on the form
- 2. Select the Icon property from the properties bar.
- 3. Click on the middle portion of the properties bar, where (icon) shows.
- 4. Press the Del key
- ---------------
-
-
- Networks & VB:
-
- VBRUN100.DLL and VB apps (EXE's) should be placed on each machine's hard disk
- to avoid significant performance degradation.
- ---------------
-
-
- Saving Your Work:
-
- Several users have reported losing their work in different ways. If you always
- save before test-running your code, you can prevent most losses. If you get
- any kind of warnings or other indications that something might be wrong with
- your system, try to get into DOS (or use File Manager) and copy your project
- files to a backup directory. Many people have had their project files
- "trashed" when the system went screwy. There is a utility on the DLs here for
- copying all the files in a Project - very handy to have, although a better
- idea, generally, is to keep each project in its own subdirectory.
- ---------------
-
-
- Screen type:
-
- z = Screen.Height
- If z = 6000 Then
- Type$="CGA"
- ElseIf z = 7000 Then
- Type$ = "EGA"
- ElseIf z > 7000 Then
- Type$ = "VGA or Better"
- End if
-
- There's another way to do this, calling GetDeviceCaps to find out the vertical
- resolution; but this method is a lot easier... BTW, if you want to know if it
- is exactly VGA, not "or better" (i.e., better than 640x480), the number for
- that 7200 if memory serves...
- ---------------
-
-
- Sound.DLL (Need TPW):
-
- Here's my DLL written in TPW. I had no documentation besides the Windows
- Programmer's Reference so maybe someone here can tell me if I'm on the right
- track. Some questions come to mind such as: how large shoule I make the voice
- queue? Is it unecessary to open and close the sound device every time I want to
- set a note?
-
- library SoundDLL;
-
- uses WinTypes, WinProcs;
-
- procedure PlayNote(Note, nLength, Cdots: Integer);export; begin
- OpenSound;
- SetVoiceAccent(1,100,255,S_NORMAL,0);
- SetVoiceQueueSize(1,1000);
- SetVoiceNote(1,Note,nLength,Cdots);
- StartSound;
- WaitSoundState(S_QueueEmpty);
- CloseSound;
- StopSound; end;
-
- exports PlayNote index 1;
-
- begin end.
-
- The declaration in VB (general):
-
- Declare Sub PlayNote Lib "e:\tpw\output\soundll.dll" (ByVal note%, ByVal
- Length%, ByVal Cdots%)
-
- (Mark N.):
- The size of the voice queue is one of those numbers that you simply "Pull
- out of thin air". It depends on what you're going to do. For example, in
- VBTools, we set the queue to 8K because we include several large pieces of
- music.
-
- OTOH, if you're going to play single notes on an occasional basis, then 1K
- should be plenty.
-
- It is not necessary to open and close the sound device every time. In fact,
- if you close it while there are notes in the queue, they'll be lost!
- I suggest that you do what we've done in VBTools:
-
- 1. Open the sound device when the user first calls your proc.
- 2. If the device is open, then close it when your DLL unloads.
- 3. Give the user a method to close it so that sound can be generated by
- other apps.
- ---------------
-
-
- Type...End Type:
-
- Be sure when using arrays with Type variables to put the variable number
- AFTER the type name and BEFORE the element name.
- Example:
- Type Test
- a1 as string*1
- a2 as string*2
- End Type
-
- Dim TypeName as Test
- TypeName(i).a1 = "xyz" NOT TypeName.a1(i) = "xyz"
- ---------------
-
-
- Dynamic Arrays:
-
- In order to use a dynamic array, you must REDIM it in a module or form:
- (Mark N.)
-
- Global:
- Type SomeType
- X As Integer
- etc
- End Type
- Global ArrayName() As SomeType
-
- Module or Form:
- Redim ArrayName(x) As SomeType ' x can be a number or a variable
- ---------------
-
-
- Combo Boxes: Changing Text
-
- Text is read-only, but you can accomplish the same thing with:
- Combo1.ListIndex = 3. This would select and display the 4th item in the list.
- ---------------
-
-
- Combo Boxes: Color
-
- BackColor does not apply to the list portion of the combo box, only the 'edit'
- part.
- ---------------
-
-
- Pseudo Combo Dropdown List Box:
-
- To implement a pseudo Combo DropDown List Box like the one used in the VB
- Help/Index/Search Window: As you type text in a Text Box, VB hilights the
- first entry in the List Box that matches what you have typed. This can be
- implemented in VB by using a Text Box, a List Box and the API message
- LB_FINDSTRING.
- ---------------
-
-
- File Copying:
-
- Open "FileIn" for Binary as #1
- whole = Lof(1) \ 32000 'numer of whole 32768 byte chunks
- part = Lof(1) MOD 32000 'remaining bytes at end of file
- buffer$ = string$(32000,0)
- start& = 1
- Open "FileOut" for Binary as #2
- for x=1 to whole 'this for-next loop will copy 32,000
- get #1, start&, buffer$ 'byte chunks at a time. If there is
- Put #2, start&, buffer$ 'less than 32,000 bytes in the file,
- start&= start& + 32000 'whole = 0 and the loop is bypassed.
- next x
- buffer$ = string$(part, 0) 'this part of the routine will copy
- get #1, start&, buffer$ 'the remaining bytes at the end of the
- put #2, start&, buffer$ 'file.
- close
- ---------------
-
-
- Controlling Form Size:
-
- Set MaxButton to False so the user can't maximize the form.
-
- General_Declarations:
- Dim OldWidth As Single '-- width before resizing.
- Dim OldHeight As Single '-- height before resizing.
- Const MinWidth = 6000!, MaxWidth = 9000! '-- change these values to...
- Const MinHeight = 3000!, MaxHeight = 6000! '-- the ones you want.
-
- Sub Form_Load ()
- OldWidth = Width
- OldHeight = Height
- End Sub
-
- Sub Form_Resize ()
- If WindowState <> 1 then '-- allows user to minimize window.
- If Width < MinWidth Or Width > MaxWidth Then
- Width = OldWidth
- Else
- OldWidth = Width
- End If
- If Height < MinHeight Or Height > MaxHeight Then
- Height = OldHeight
- Else
- OldHeight = Height
- End If
- End If
- End Sub
- ---------------
-
-
- "Floating" Window:
-
- Sometimes you may want a small window to show above the current window, but VB
- does not offer this feature. Here is how to force it (courtesy of Ted Young):
-
- Global.Bas:
- Declare Sub SetWindowPos Lib "User" (ByVal hWnd As Integer,
- ByVal hWndInsertAfter as Integer,
- ByVal X as Integer,
- (put this all on --> ByVal Y as Integer,
- one line) ByVal cx as Integer,
- ByVal cy as Integer,
- ByVal wFlags as Integer)
- Declare Function GetWindow Lib "User" (ByVal hWnd as Integer,
- ByVal wCmd as Integer) As Integer
- ' Set WindowPos Flags:
- Global Const SWP_Nosize = &H1
- Global Const SWP_NoMove = &H2
- Global Const SWP_NoActivate = &H10
- Global Const SWP_ShowWindow = &H40
-
- Form1, Load:
- Form2.Show ' this is the "Floating" window
- End Sub
-
- Form1, Timer1 (set Interval to 50 in Properties)
- Sub Timer1_Timer
- If GetWindow(Form2.hwnd,0) <> Form2.hWnd Then
- wFlags = SWP_Nomove or Swp_Nosize or Swp_ShowWindow or Swp_NoActivate
- SetWindowPos Form2.hWnd, 0, 0, 0, 0, 0, wFlags
- End If
- End Sub
- ---------------
-
-
- Form Size and Granularity
-
- Check the "Granularity" under the Desktop settings in the Control Panel. If
- this number is anything but zero, you'll get the effect of all windows only
- being able to be sized and placed by increments of 16 pixels multiplied by the
- Granularity number. Set it to zero and this should fix things.
- ---------------
-
-
- Grouped Controls:
-
- If you want to group a set of controls within another control, such as a
- Frame, you cannot do so by double-clicking the control and moving it into the
- Frame. You must single-click the control and then click-and-drag INSIDE the
- frame (or other control) to draw the added control.
- ---------------
-
-
- Mouse Pointer, Position:
-
- Sometimes it nice to be able to place the user's mouse cursor for him. One
- example is when the user has to click on a button to continue, you can put the
- cursor on the box for him.
-
- Declare Sub SetCursorPos Lib "User" (ByVal x%, ByVal y%)
- example: Call SetCursorPos(100,200)
-
- The above code will do a rudimentary job of positioning the cursor.
- Here is some more information about positioning:
-
- Using the Windows API call SetCursorPos, you can move the mouse to any
- location on the screen. Note that the x & y coordinates are *screen*
- coordinates. You'll need to translate the coordinates in your VB
- program to screen coordinates. One way is to get the current coordinates of
- the mouse using GetCursorPos, and then moving the mouse in relation to those
- coordinates. Note that GetCursorPos returns the coordinates in a Type
- structure (see below). You can also use the API functions ClientToScreen
- and ScreenToClient to convert the coordinates from the Client (your Form) to
- the Screen, and back. Experiment with the functions to see which suits your
- purpose, and holler if you have any questions. Also, I'd recommend
- downloading WINAPI.ZIP which has all the Declares necessary for calling the
- API functions.
-
- Declare Sub SetCursorPos Lib "User" (byval x as integer, byval y as integer)
- Declare Sub GetCursorPos Lib "User" (lpPoint as PointAPI)
- Declare Sub ClientToScreen Lib "User" (ByVal hWnd As Integer,
- lpPoint As PointAPI)
- Declare Sub ScreenToClient Lib "User" (ByVal hWnd As Integer,
- lpPoint As PointAPI)
- Type PointAPI
- x As Integer
- y As Integer
- End Type
-
- Note: Type the declares on one line, not two as shown above.
- ---------------
-
-
- Placing Forms, Controls:
-
- Sub InitializeWindow
- Height = Screen.Height * .75
- Width = Screen.Width * .75
- Top = (Screen.Height - Height) / 2
- Left = (Screen.Width - Width) / 2 '
- *** Then place and size your controls.
- End Sub
-
- If you want to make the form a specific size, then Scale it in inches,
- centimeters, points, or twips (a twip is 1/20th of a point), and don't bother
- making references to Screen.Height or .Width.
- ---------------
-
-
- Btrieve:
-
- There are the DLL-Declarations for Btrieve. The requestor must be loaded
- before Windows:
-
- Declare Function wbtrvinit Lib "wbtrcall.dll" (ByVal init$) As Integer
- Declare Sub wbtrvstop Lib "wbtrcall.dll" ()
- Declare Function btrcall Lib "wbtrcall.dll" (ByVal a%, ByVal b$, ByVal c$,
- d%, ByVal e$, ByVal f%, ByVal g%) As Integer
-
- FIELD and VARPTR are definitely not necessary. You'll need to set up a
- user-defined type to work with Btrieve (instead of FIELD). The call syntax for
- Win Btrieve takes care of pointing to the record (instead of VARPTR). Just be
- sure to pass any variable-length strings (i.e, A$) BYVAL.
- ---------------
-
-
- Deleting Data in Sequential File:
-
- Here's an idea for deleting text in the middle of a sequential file that might
- work. Haven't tried it, but it seems like it would work and wouldn't be
- difficult to implement. First, you'll have to save file pointers to the
- beginning of each message (e.g., in a Long Int array during message load using
- the SEEK function) in MsgPtr&(). Now, if you want to delete message 50 and
- there are a total of 200, you'd do the following:
-
- MsgToDelete = 50
- TotMsgs = 200
- BlockSize& = 32768&'-- make this larger or smaller to find optimum size
- Temp$ = Space$(BlockSize&)
- Open "MESSAGE.MSG" For Binary As #1
-
- SizeOfFile& = LOF(1)
- SizeToMove& = SizeOfFile& - MsgPtr&(MsgToDelete + 1)
- NumBlocks = SizeToMove \ BlockSize&
- LeftOver = SizeToMove& - Num32KBlocks * BlockSize&
- FromLoc& = MsgPtr&(MsgToDelete + 1)
- ToLoc& = MsgPtr&(MsgToDelete)
-
- For i = 1 To NumBlocks
- Seek #1, FromLoc& + BlockSize& * (i - 1)
- Get #1, Temp$
- Seek #1, ToLoc& + BlockSize& * (i - 1)
- Put #1, Temp$
- Next
- Temp$ = Space$(LeftOver)
- Seek #1, FromLoc& + BlockSize& * NumBlocks
- Get #1, Temp$
- Seek #1, ToLoc& + BlockSize& * NumBlocks
- Put #1, Temp$
- '-- Now adjust the MsgPtr& array
- TotMsgs = TotMsgs - 1
- Adjust = MsgPtr&(MsgToDelete + 1) - MsgPtr&(MsgToDelete)
- For i = MsgToDelete To TotMsgs
- MsgPtr&(i) = MsgPtr&(i + 1) - Adjust
- Next
- ---------------
-
-
- MKI$ & CVI in VB:
-
- function MKI$ (Work%)
- MKI$ = Chr$ (Work% MOD 256) + Chr$ (Work% \ 256)
- end function
-
- function CVI% (Work$)
- CVI% = (ASC (Left$ (Work$, 1)) * 256) + ASC (Right$ (Work$, 1))
- end function
- ---------------
-
-
- Using Different Fonts, Colors in a Box:
-
- You can use different colors and fonts with the .Print method in a Picture Box
- (during run-time) to get different fonts and colors in a box. You can also use
- different fonts and colors in the form itself.
- ---------------
-
-
- System Font
-
- In a List box using the System font, 9 pitch is non-proportional, 9.75 is
- proportional.
- ---------------
-
-
- Focus & Order of Execution:
-
- Some times VB will delaying doing something while it executes more code. For
- example, if you write a lot of stuff to a List box in a tight loop, the List
- box display on the screen will not be shown updated until the code comes to a
- "resting point" (ie: waiting for user input).
-
- Focus on StartUp
-
- If you try to display a form on startup that has your logo, copyright notice,
- etc, you may find that the form displays, but the detail on it does not. You
- have to force VB to wait until the detail is displayed. One way to do that is
- do define a Global variable and when you are finished with the Title box, set
- the variable ("Continue", in the example below) to true (-1).
-
- Form1_Load:
- TitleForm.Show
- Do
- x = DoEvents() 'allow control to the system
- Loop Until Continue = -1
-
- Another way is to "Loop Until Len(Label1.Caption) > 0" (You can omit the >0.)
- This assumes you have a Label1 box, of course.
-
-
- Another problem is trying to get some other form to load and to transfer focus
- to it during start-up, and then continuing the start-up. What happens is that
- you can do a Form2.Show, for example, but after the Form2_Load code (if any)
- is run, focus will immediately return to the original form. Users don't get a
- chance to interact with Form2. If Form2 is an installation form, for example,
- the installation will never get done.
-
- The solution is to use Show Modal (eg: Form2.Show 1), with the possible
- drawback being that you have to Unload the form to return to the calling form.
- ---------------
-
-
- SetFocus:
-
- You cannot do a SetFocus until a form is visible. Use Show instead.
- ---------------
-
-
- Trapping Double-Click before Click:
-
- If you have code assigned to both the Click event AND the Double-Click,
- when you double-click, VB will execute the Click code on the first click of
- the double and the D-C code on the second click.
-
- Here's how to avoid executing the Click when double clicking (J. Zuck):
-
- On the first Click, setup a timer event to process the click in the "near"
- future. If a DblClick occurs within the timer.interval it disables the timer
- and processes the DblClick instead.
- ---------------
-
- Using "Enter" in Place of "Tab":
-
- Sub Text1_KeyPress(KeyAscii As Integer)
- If KeyAscii = 13 Then
- KeyAscii = 0 ' Avoid the beep
- SendKeys "{Tab}" ' Simulate pressing the Tab key
- End If
- End Sub
- ---------------
-
-
- Finding An Item Added to a Sorted List Box:
-
- Instead of using List.AddItem, use
- SendMessage(hWnd, LB_ADDSTRING, wParam, lParam).
-
- This adds the item to the list and returns the ListIndex of the newly added
- item.
- ---------------
-
-
- Inhibiting Screen Updating:
-
- If you are adding a whole bunch of items to a list box all at once like
- assigning items from an array from within a loop, you might want to use the API
- WM_SETREDRAW message to prevent the list box from being continually updated on
- the screen as each item is added. Not only does this stop the flickering, but
- it makes adding the items much faster.
- ---------------
-
-
- Linking Sorted and Unsorted List Boxes:
-
- You can append a 4 byte value to an item in a List Box by using the
- LB_SETITEMDATA message and you can retrieve the value using the LB_GETITEMDATA
- message. You can use the ItemData to store the location of the item in the
- unsorted array.
- ---------------
-
-
- List Box: Searching For An Item:
-
- Object: (general) Proc: FindItem
- Sub FindItem (Lst as Control, a$)
- U = Lst.ListCount
- L = 0
- Do
- IF U < L Then
- Lst.Index = I
- MsgBox "Not Found"
- Exit Sub
- I = (L + U) / 2
- IF P = X(I) Then
- Lst.Index = I 'Found. Set ".Index" accordingly
- Exit Sub
- ElseIf P > X(I) Then
- L = I + 1
- Else
- U = I - 1
- End If
- Loop
-
- Note: If a match is not found, we still set ".Index" to "I" so that you can
- do an alphabetical insert, if you wish.
- ---------------
-
-
- Copying a Drawing to Clipboard
-
- The following will work, IF Picture1.AutoRedraw is True. (J. Zuck)
-
- Sub Picture1_Click ()
- ClipBoard.Clear
- Picture1.Circle (1000, 1000), 500
- ClipBoard.SetData (Picture1.Image) 'Picture1.Picture won't work.
- End Sub
-
- Sub Picture2_Click ()
- Picture2.Picture = ClipBoard.GetData() 'Picture2.Image is illegal.
- End Sub
- ---------------
-
-
- Drawing - Scale
-
- You can change the scale for pictures from twips to virtually anything you
- want (100 allows you to do easy percent drawing), but you still have to draw
- by using pixel measurements. I found this out by trying to set DrawWidth to
- draw a line covering the middle 20% of a small picture.
- ---------------
-
-
- Saving Picture Files:
-
- It seems that SavePicture saves everything when the property is a Picture on a
- Form, but it saves only the original loaded file when the property is a
- Picture on a PictureBox, and it saves only the new drawn lines when the
- property is an Image in a PictureBox.
-
- The following should fix it:
-
- 'BMP or WMF loaded into Picture1
- 'Redlines added with Line, Pset, etc., then
- Form1.Picture = Picture1.Image
- PictureSave Form1.Image, "TEST1.BMP"
-
- This works with WMFs but they cannot be changed and saved as WMFs, they get
- saved as BMPs, which may or may not be ok with you.
- ---------------
-
-
- Printer Setup:
-
- Declare Function LoadLibrary Lib "kernel" (Byval LibName$) As Integer
- Declare Function FreeLibrary Lib "kernel" (hLib%) As Integer
- Declare Function DeviceMode Lib "HPPCL.DRV" (hWnd%, hLib%, Dev$, Port$)
-
- SUB Command1_Click ()
- hLib% = LoadLib% ("HPPCL.DRV")
- Result% = DeviceMode (hWnd, hLib%,"HP / PCL LaserJet","LPT1:")
- Result% = FreeLibrary (hLib%)
- END SUB
-
- Declare Function LoadLibrary Lib "KERNEL" (ByVal lpLibFileName$) As Integer
- Declare Sub FreeLibrary Lib "KERNEL" (ByVal hLibModule%)
-
- Then change PSetupMNU_Click to read:
-
- Sub PSetupMNU_Click ()
- RetStr$ = String$(256, 0)
- RetStrSize% = Len(RetStr$)
- x% = GetProfileString("windows", "device", "", RetStr$, RetStrSize%)
-
- i% = InStr(RetStr$, ",")
- If i% > 0 Then
- a$ = Left$(RetStr$, i% - 1)
- b$ = Right$(RetStr$, Len(RetStr$) - i%)
- j% = InStr(b$, ",")
- If j% > 0 Then
- DriverName$ = Left$(b$, j% - 1)
- PortName$ = Right$(b$, Len(b$) - j%)
- End If
- End If
-
- If Len(DriverName$) > 0 And Len(PortName$) > 0 Then
- LibHandle% = LoadLibrary("PSETUP.DLL")
- If LibHandle% >= 32 Then
- r% = DoPrinterSetup(Form1.hwnd, DriverName$, PortName$)
- FreeLibrary LibHandle%
- If Not r% Then MsgBox "Can't run Printer Setup", 64, "Printer Setup"
- End If
- Else
- MsgBox "No default printer selected", 64, "Printer Setup"
- End If
- End Sub
- ---------------
-
-
- Printer Control Codes:
-
- The normal Print command in VB will not properly send printer control codes
- through to the printer. Here is how to get around VB:
-
- Open "LPT1" For Binary As #1 'note: no colon on LPT1
- Put #1,,<put your control codes here>
- Close #1
- ---------------
-
-
- Printing Forms:
-
- In VB's File menu, there is a Print option for printing forms and code. On an
- HPLJ, the top of forms will be cut off because VB/Windows tries to print in
- the top-most part of the page, which is, of course, unusable on an HPLJ.
- ---------------
-
-
- Calling the Windows 3 Calculator:
-
- Declare Function isapploaded Lib "kernel"(name$) As Integer Alias
- "GetModuleHandle" 'All one line
-
- Sub MAIN
- If isapploaded("calc") = 0 Then
- Shell("calc.exe", 1)
- Else
- AppActivate "Calculator", 0
- SendKeys "% r"
- End If
- End Sub
- ---------------
-
-
- hWnd for a Control:
-
- All you have to do is use the Windows API GetFocus call after setting the
- focus to the desired control:
-
- General Section
- Declare Function GetFocus% Lib "User" ()
-
- In your code
- Command1.SetFocus
- ButtonHwnd = GetFocus()
- ---------------
-
-
- .INI Files:
-
- The calls to read/write private ini file are:
-
- GetPrivateProfileInt - returns int value
- WORD GetPrivateProfileInt( LPSTR lpApplicationName
- , LPSTR lpKeyName
- , int nDefault
- , LPSTR lpFileName )
-
- GetPrivateProfileString - returns string
- WritePriviteProfileString
-
- The calls to read/write the WIN.ini file are almost the same -- just remove
- the Private.
- ---------------
-
-
- Multi-Instance App Prevention:
-
- Here's an example of the Multi-Instance App prevention, as well as an example
- of calling DLL functions. You simply "Declare" them at the beginning (taking
- them from a provided .DEFs file) then use them! (See the "Dummy" returning
- functions lower down.)
-
- Dim PassString$ ' declare a local string to hold user's password
-
- Const SW_SHOWNORMAL = 1
- Declare Function GetActiveWindow Lib "User" () As Integer
- Declare Function ShowWindow Lib "User" (ByVal hWnd As Integer, ByVal nCmdShow As
-
- Form_Load() ' this executes when the PassWord form loads
-
- On Error GoTo NoLink ' setup our no-link error handler
- SystemLink.LinkMode = 1 ' try to establish a hot link with a server
- On Error GoTo 0 ' disable error trapping
-
- MsgBox "A DDE LINK HAS BEEN ESTABLISHED WITH A SERVER!!!"
-
- AppActivate "SalHist" ' activate the "other" SalHist
- hActive = GetActiveWindow() ' pickup it's hWnd handle
- Dummy = SetFocusAPI(hActive) ' give it the system focus
- Dummy = ShowWindow(hActive, SW_SHOWNORMAL) ' and restore its size
- End ' finally, terminate this app!
-
- On Error GoTo 0 ' disable our temporary error trapping
- SystemLink.LinkMode = 0 ' abandon our local DDE connection attempt
- LinkMode = 1 ' and establish ourselves as a DDE server...
-
- CenterForm PassWord ' (My standard.lib form-centering routine)
- PassString$ = "" ' init the
- PassWord.Show 1 ' present the PassWord form for user data
- ' entry. The "1" makes it "modal" (stickier)
- End Sub ' end of the Form_Load subroutine.
- ---------------
-
-
- SendMessage:
-
- In the Global module:
- 'type the declaration on one line
- Declare Function Sendmessage Lib "user" (ByVal Hwnd%,
- ByVal Msg%,
- ByVal wParam%,
- ByVal lparam As Any) As Long
-
- Global Const wm_WinIniChange = &H1A
-
- Then, for example:
- Sub Command1_Click
- x& = Sendmessage(&HFFFF, wm_WinIniChange, 0, ByVal "")
- End Sub
- ---------------
-
-
- Windows Termination:
-
- If Windows is about to terminate, it will invoke your Form_Unload procedure. In
- that proc, you can do whatever you want, including telling Windows to *cancel*
- the shutdown!
-
- To cancel the Form_Unload, use: Cancel=True.
- ---------------
-
-
- Cursor (text), Position:
-
- You can get the cursor position in a text box as follows:
-
- CursPos = Text1.SelStart
- ---------------
-
-
- Data Entry Masking:
-
- General - Declarations:
- Dim Txt as String
- Text1_GotFocus ():
- Text1.Text = "01/23"
- Txt$ = Text1.Text 'Txt$ = "01/23". This intitialization keeps KeyUp
- ' from kicking in until a key has been pressed.
- Text1_KeyPress: 'Assume cursor is on the "/" and "X" is pressed.
- Txt$ = Text1.Text 'Note: Text1.Text is still "01/23" at this point.
- Text1_KeyUp
- If Txt$ <> Text1.Text Then 'now Text1.Text is "01X/23"
- Call CursPos(Text1) 'and Txt$ is still "01/23"
- End If
- CursPos(Ctl as Control)
- i = 0
- Do While Len(Txt$) > i
- i = i + 1
- If Mid$(Txt$, i, 1) <> mid$(Ctl.Text, i, 1) Then
- pos = i
- Exit Do
- End If
- Loop
- if pos = 3 then 'Example of preventing an unwanted change:
- Ctl.Text = Txt$ 'Reset Text1.Text and
- Ctl.SelStart = pos - 1 'put the cursor back where it was.
- end if
- ---------------
-
-
- Data Entry Routine:
-
- .FRM Code:
- Sub Form_Load ()
- SomeForm.Show
- InitStdControl AcctNo1 'Initialize standard edit controls
- InitStdControl AcctNo2
- .. etc
- End Sub
-
- Sub AcctNo1_KeyPress (KeyAscii As Integer)
- StdEdit AcctNo1, KeyAscii 'Use standard editing procedure
- End Sub
-
- Module (.BAS) Code:
- DefInt A-Z
- Declare Function GetFocus% Lib "USER" ()
- Declare Function SendMessage& Lib "USER" (ByVal hWnd%, ByVal wMsg%
- ByVal wParm%, ByVal lParm&)
- Const WM_USER = &H400 'Define the message number for
- Const EM_LIMITTEXT = WM_USER + 21 ' limiting the length of an edit
- ' Control
- Sub InitStdControl (Ctrl As Control)
- Ctrl.Width = 500 'Make field some standard length
- Ctrl.SetFocus 'Allow maximum of 14 characters
- Ok& = SendMessage(GetFocus(), EM_LIMITTEXT, 14, 0)
- .. more setup
- End Sub
-
- Sub StdEdit (Ctrl As Control, KeyAscii%)
- If KeyAscii >= 48 And KeyAscii <= 57 Then
- Ctrl.SelLength = 1 'This produces overstrike mode
- Else
- KeyAscii = 0 'Ignore non-numeric keys
- End if
- End Sub
- ---------------
-
-
-
- Data Entry Text Limit:
-
- Declare Function GetFocus% Lib "USER" ()
- Declare Function SendMessage& Lib "USER" (ByVal hWnd%, ByVal wMsg%,
- ByVal wParm%, Byval lParm&)
- Const WM_USER = &H400
- Const EM_LIMITTEXT = WM_USER + 21
-
- In your Form_Load procedure:
- MaxLen% = Whatever
- Text1.SetFocus
- Ok& = SendMessage(GetFocus(), EM_LIMITTEXT, MaxLen%, 0)
- ---------------
-
-
-
- Text Box - Flicker:
-
- Concatenating text in a Text Box can cause screen flicker. Instead use
- SelStart and SelLength - no flicker.
- ---------------
-
-
- Flashing Text:
-
- Sub FlashColor ()
- If FlashState = True Then
- Label1.BackColor = RGB(255, 0, 0)
- Label1.ForeColor = RGB(255, 255, 255)
- Else
- Label1.BackColor = RGB(255, 255, 255)
- Label1.ForeColor = RGB(0, 0, 0)
- End If
- If FlashState = True Then
- FlashState = False
- Else
- FlashState = True
- End If
- End Sub
- --------
-
-
- Flashing Text:
-
- You can use the .SelLength and .SelStart to highlight and unhighlight a
- section of the text.
- ---------------
-
-
- Timer:
-
- If you use a Timer with a small interval (eg: 1) and another application is
- active, Windows may not be able to respond at the specified duration and
- execution of the related code will be postponed until Windows can get to it.
- ---------------