Dec 222017
 
Info about Visual Basic -- Bugs, etc.
File VBTIPS.ZIP from The Programmer’s Corner in
Category BASIC Language
Info about Visual Basic — Bugs, etc.
File Name File Size Zip Size Zip Type
TPCREAD.ME 199 165 deflated
VB-TIPS.TXT 33023 11938 deflated

Download File VBTIPS.ZIP Here

Contents of the VB-TIPS.TXT file


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,,
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.
---------------


 December 22, 2017  Add comments

Leave a Reply