Showing posts with label Tips and Triks Visual Basics (VB). Show all posts
Showing posts with label Tips and Triks Visual Basics (VB). Show all posts

Tip 110: Sending a Click Event to a Command Button Control

Abstract
In a Microsoft(r) Visual Basic(r) application, you can simulate a Click =
event to
a Command Button control. This article explains how to send a BN_CLICKED
notification message to a control.

Executing a BN_CLICKED Message
A user who wants to carry out a command in your Microsoft(r) Visual =
Basic(r)
application usually clicks a Command Button control. The code in the =
Command
Button's Click event is then executed.

There may be times, however, when you will want to initiate a Click =
event from
within your Visual Basic program. You can use the Microsoft Windows(r) =
application
programming interface (API) PostMessage function to send a BN_CLICKED =
notification
message to the parent of the Command Button control. This will call the =
button's
Click event.
As you can see from the example program below, the GetDlgCtrlID function
retrieves the Command Button's handle. Next, a call is made to the =
GetParent
function, which retrieves the handle of the window that the Command =
Button resides
on. (In other words, we must retrieve the parent window's handle.)

The last step is to execute a PostMessage function. PostMessage sends a =
BN_CLICKED
notification message to the parent window, which then processes the =
Click event
for the Command Button.
When you run the example program below, the second Command Button's =
Click event
is executed. However, the second Command Button does not receive the =
focusonly its
code is executed.

Example Program
This program shows how to send a Command Button click to the Windows =
operating
system.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add the following Constant and Declare statements to the General =
Declarations
section of Form1 (note that each Declare statement must be typed as =
a single
line of text):

Const BN_CLICKED =3D 0
Const WM_COMMAND =3D &H111
Private Declare Function GetDlgCtrlID Lib "User" (ByVal hWnd As Integer) =
As
Integer
Private Declare Function GetParent Lib "User" (ByVal hWnd As Integer) As =
Integer
Private Declare Function PostMessage Lib "User" (ByVal hWnd As Integer, =
ByVal
wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Long) As =
Integer

3. Add a Command Button control to Form1. Command1 is created by =
default. Set
its Caption property to "Send".
4. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
ClickButton Command2.hWnd
End Sub

5. Add a second Command Button control to Form1. Command2 is created by =
default.
Set its Caption property to "Receive".
6. Add the following code to the Click event for Command2:

Private Sub Command2_Click()
MsgBox "Command2 was CLICKED!"
End Sub

7. Create a new function called ClickButton. Add the following code to =
this
function:

Sub ClickButton(ByVal hWnd As Integer)
Dim Button As Integer
Dim ParentHwnd As Integer
Dim X As Integer
=20
Button =3D GetDlgCtrlID(hWnd)
ParentHwnd =3D GetParent(hWnd)

X =3D PostMessage(ParentHwnd, WM_COMMAND, Button, BN_CLICKED * =
&H10000 + hWnd)
End Sub

Run the example program by pressing F5. Click the Send Command Button. =
The Click
event for the second Command Button control is immediately executed (the =
message
box is displayed).

Additional References
"BN_CLICKED." (Development Library, Product Documentation, SDKs,
Windows 3.1 SDK, Programmer's Reference Volume 3: Messages, =
Structures)
"GetDlgCtrl." (Development Library, Product Documentation, SDKs,
Windows 3.1 SDK, Programmer's Reference Volume 2: Functions)
PostMessage." (Development Library, Product Documentation, SDKs,
Windows 3.1 SDK, Programmer's Reference Volume 2: Functions)

Tip 109: Modifying an MDI Form's Border Style

Abstract
This article explains how you can create a multiple-document interface =
(MDI) form
that has a fixed border in a Microsoft(r) Visual Basic(r) application.

Retrieving and Setting a Form's BorderStyle
Every form you create when designing a Microsoft(r) Visual Basic(r) =
application
can have one of four border styles. Just set the form's BorderStyle =
property to
one of the following styles:
0 - None
1 - Fixed Single
2 - Sizeable
3 - Fixed Double

An MDI child form, however, does not have a BorderStyle property. But by =
using the
Microsoft Windows(r) GetWindowLong and SetWindowLong application =
programming
interface (API) functions , you can change an MDI form's border style to =
a fixed
border style.
The GetWindowLong function retrieves information about the specified =
window's
style attributes and the SetWindowLong function modifies the specified =
window's
style attributes.

GetWindowLong requires only two arguments. The first argument is the =
target
window's handle. The second argument specifies the type of information =
you want
to retrieve, which is the style settings for the window.
After retrieving the window's current style settings, use the bitwise =
And Not
function to remove the WS_THICKFRAME attribute from the style settings =
value.
Next, issue a call to the SetWindowLong function to set the new style =
settings
for the specified window. This creates an MDI form that has a fixed =
border style.


Example Program
This program shows how to create an MDI form that has a fixed border. =
Run the
example program by pressing F5. The MDI form will be displayed with a =
fixed
border.

1. Create a new project in Visual Basic. Form1 is created by default.
2. From the Insert menu, select MDI Form to create an MDI form. =
MDIForm1 is
created by default.
3. Set Form1's MDIChild property to True. Modify the size of this form =
so that
it is smaller than the MDIForm1 form.
4. Add the following Constant and Declare statements to the General =
Declarations
section of Form1 (note that each Declare statement must be typed as =
a single
line of text):

Private Declare Function GetWindowLong Lib "User" (ByVal hWnd As =
Integer, ByVal
nIndex As Integer) As Long
Private Declare Function SetWindowLong Lib "User" (ByVal hWnd As =
Integer, ByVal
nIndex As Integer, ByVal dwNewLong As Long) As Long
Const GWL_STYLE =3D (-16)

Const WS_THICKFRAME =3D &H40000

5. Add the following code to the Load event for MDIForm1 (note that the =
NewStyle
line must be typed as a single line of code):

Private Sub MDIForm_Load()
Dim CurStyle As Long
Dim NewStyle As Long
CurStyle =3D GetWindowLong(MDIForm1.hWnd, GWL_STYLE)
NewStyle =3D SetWindowLong(MDIForm1.hWnd, GWL_STYLE, CurStyle And
Not (WS_THICKFRAME))
End Sub

Additional References

"GetSystemMenu." (Development Library, Product Documentation, SDKs,
Windows 3.1 SDK, Programmer's Reference, Volume 2: Functions)
Knowledge Base Q118376. "How to Lock a Form So It Cannot Be Moved."
Knowledge Base Q110393. "How to Remove Menu Items from a Form's =
Control-Menu Box."
Knowledge Base Q77930. "Modifying the System Menu of an MDI Child =
Window."
Knowledge Base Q71669. "Preventing an MDI Child Window from Changing =
Size."

Tip 108: Flashing Controls to Get the User's Attention

Abstract
When developing an application in Microsoft(r) Visual Basic(r), you can =
use the
BackColor property to change the background color of a control. This =
article
explains how you can temporarily flash a control's BackColor property to =
draw the
user's attention to a specific control.

Changing a Control's BackColor Property
When designing a Microsoft(r) Visual Basic(r) application , you place =
controls
such as List Boxes and Text Boxes on a form. At run time, you can move =
the focus
to one of these objects by using Visual Basic's SetFocus method. Users =
can then
see that that particular control needs to be addressed in some way. For =
example,
if a Text Box receives the focus, users know they must type some text =
into that
control.

However, users may not actually notice that the focus has been set to a =
specific
control because the "rubberband" (highlighting) around the inside of the =
control
is not that obvious. To alert the user, you could change the background =
color of
the control from white to, say, red, to draw the user's attention to =
that control.
When the control loses the focus, you could reset the control's =
background color
to white. This procedure, however, means that the control would be a =
different
color as long as that control retained the focus. In some situations, =
this would
not be appropriate.

A far better solution would be to change the control's background color =
for just
a few seconds. The example program below "flashes" a control by quickly =
changing
the control's background color three times in succession. The Timer =
function is
used to cause a short time delay in the program. Each time a 2-second =
interval
elapses, the control's color is changed from white to red, then back to =
white.
The For-Next loop dictates how many times the control is flashed. In =
this case,
a value of 3 was used to flash the color three times. This creates a =
very visual
clue to draw the user's attention to that specific control.

Example Program
This program shows how to highlight the control that has the focus. Run =
the
example program by pressing F5 . Then click the Flash Command Button. =
Note that
the background color of the List Box control is changed to red and =
flashed three
times.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add the following code to the Form_Load event for Form1:

Private Sub Form_Load()
List1.AddItem "Item #1"
List1.AddItem "Item #2"
List1.AddItem "Item #3"
End Sub

3. Add a Command Button control to Form1. Command1 is created by =
default. Set
its Caption property to "Flash".
4. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
FlashControl List1
End Sub

5. Add a List Box control to Form1. List1 is created by default.
6. Create a new function called FlashControl. Add the following code to =
this
function:

Sub FlashControl(C As Control)
Dim OldColor As Double
Dim Delay As Double
Dim X As Integer
=20
OldColor =3D C.BackColor
For X =3D 1 To 3
C.BackColor =3D QBColor(12)
Delay =3D Timer
While Timer - Delay < 0.2
DoEvents
Wend
C.BackColor =3D OldColor
Delay =3D Timer
While Timer - Delay < 0.2
DoEvents
Wend
Next X
C.SetFocus
End Sub

Tip 107: Detecting Double-Click Events in Combo Box Controls

Abstract
When developing an application in Microsoft(r) Visual Basic(r), you may =
want to
let the user double-click the edit portion of a Combo Box control. This =
article
explains how to process this double-click event by using the Message =
Blaster
custom control.

Using Message Blaster to Detect Double-Clicks on Combo Boxes
In a Microsoft(r) Visual Basic(r) application, you can use a Combo Box =
control to
allow your user to easily select an item. Unfortunately, the Combo Box =
control
only responds to single-click events, not to double-click events in the =
box's
edit portion.

You can, however, use a subclassing control such as Message Blaster to =
detect
when a user has double-clicked the combo box. Before you can do this, =
you need
to use two Microsoft Windows(r) application programming interface (API)
functions GetWindow and GetClassName.
The GetWindow function retrieves the handle of a window that has a =
specific
relationship to the source window. In other words, we need to determine =
the
Combo Box's handle. The Combo Box window is actually a sibling window of =
our
Visual Basic application's main form. Next, we need to call the =
GetClassName
function to make sure that the edit portion of the Combo Box is the =
window we are
dealing with.

If you are using a combo box with its Style property set to 0 - Drop =
Down Combo,
detecting a double-click message is relatively straightforward. Just =
retrieve the
handle of the Combo Box's edit window, and then tell Message Blaster to =
intercept
the Windows WM_LBUTTONDBLCLK message.
On the other hand, if you are using a Combo Box with its Style property =
set to
1 - Simple Combo, the procedure is a little different. Because the edit =
portion
of the Combo Box is already displayed, you need to call GetWindow to =
retrieve
the handle of the edit window.

After you have retrieved the edit window's handle, you must call the =
GetClassName
function. This function is called so that we can be certain we are =
processing a
double-click message for only the edit portion of the Combo Box.

Example Program
This program shows how your Visual Basic application can respond to a =
double-click event when such an event is detected in the edit portion of =
a Combo Box control.
1. Create a new project in Visual Basic. Form1 is created by default.
2. From the Insert menu, select Custom Control. Add the Message Blaster =
custom
control to this project.
3. Add a Message Blaster control to Form1. MsgBlast1 is created by =
default.
4. Add the following code to the Message event for MsgBlaster1 (note =
that the
first two lines of code must be typed as a single line of text):

Private Sub MsgBlaster1_Message(MsgVal As Integer, wParam As Integer,
lParam As Long, ReturnVal As Long)
MsgBox "Combo1 box double-clicked"
End Sub

5. Add a Combo Box control to Form1. Combo1 is created by default. Set =
its Style
property to 1-Simple Combo.
6. Add the following Constant and Declare statements to the General =
Declarations
section of Form1 (note that each Declare statement must be typed as =
a single
line of text):

Private Declare Function GetWindow Lib "User" (ByVal hWnd As Integer,
ByVal wCmd As Integer) As Integer
Private Declare Function GetClassName Lib "User" (ByVal hWnd As Integer,

ByVal lpClassName As String, ByVal nMaxCount As Integer) As Integer
Const WM_LBUTTONDBLCLK =3D &H203
Const GW_CHILD =3D 5
Const GW_HWNDNEXT =3D 2

7. Add the following code to the Form_Load event for Form1:

Private Sub Form_Load()
Dim hWndList As Integer
Dim hWndEdit As Integer
Dim Buf As String * 10
Dim X As Integer
=20
Combo1.AddItem "Item #1"
Combo1.AddItem "Item #2"
Combo1.AddItem "Item #3"
=20
hWndList =3D GetWindow(Combo1.hWnd, GW_CHILD)
Select Case Combo1.Style
Case 0
MsgBlaster1.hWndTarget =3D hWndList
MsgBlaster1.MsgList(0) =3D WM_LBUTTONDBLCLK
Case 1
hWndEdit =3D GetWindow(hWndList, GW_HWNDNEXT)
Buf =3D ""
X =3D GetClassName(hWndEdit, Buf, Len(Buf))
=20
If StrComp(Trim(Buf), "Edit" & Chr$(0)) =3D 0 Then

MsgBlaster1.hWndTarget =3D hWndEdit
MsgBlaster1.MsgList(0) =3D WM_LBUTTONDBLCLK
End If
End Select
End Sub

Run the example program by pressing F5. When you double-click the edit =
portion of
the Combo Box control, a message box will confirm this action. You can =
also change
the Style property of the Combo Box to 0 - Drop Down Combo to get the =
same effect.

Additional References

"GetClassName." (Development Library, Product Documentation, SDKs,
Windows 3.1 SDK, Programmer's Reference Volume 2: Functions)
"GetWindow." (Development Library, Product Documentation, SDKs,
Windows 3.1 SDK, Programmer's Reference Volume 2: Functions)
Knowledge Base Q110104. "Using MSGBLAST.VBX Control to Process Windows =
Messages
from VB."
"Processing Messages in Visual Basic." (Development Library, Technical =
Articles,
Visual Basic Articles)

Tip 106: Centering Text Vertically in a Text Box Control

Abstract
The Microsoft® Visual Basic® Text Box control lets your user enter text that can
later be used by your application. This article explains how you can center the
text that the user types vertically within the Text Box control.

Vertically Centering Text in Visual Basic
In your application, you may need to display the text typed by the user, centered
vertically within the Text Box control. The only way to accomplish this task is
to place the Text Box control within a larger Picture Box control. The Text Box
control allows you to type text that can later be used by your Microsoft® Visual
Basic® application. As the user types the text, the text wraps to the next line
(if the MultiLine property is set to True).

The example program below centers the text in the text box by first setting the
size of the Text Box control to the same as the size of the Picture Box control.
Whenever a Change event is detected by the Text Box control, the text is redrawn
in the control so that it appears vertically centered.

Example Program
This program shows how to center text vertically within a Text Box control.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add a Picture Box control to Form1. Picture1 is created by default. Set its
AutoRedraw property to True.
3. Add a Text Box control to Form1 over top of the Picture Box control. Text1 is
created by default. Set its MultiLine property to True.
4. Add the following Constant and Declare statements to the General Declarations
section of Form1 (note that the Declare statement must be typed as a single
line of text):

Private Declare Function SendMessage Lib "User" (ByVal hWnd As Integer,
ByVal wMsg As Integer, ByVal wParam As Integer, lParam As Any) As Long
Const WM_USER = &H400
Const EM_GETLINECOUNT = WM_USER + 10
Dim NumLines As Integer

5. Add the following code to the Form_Load event for Form1:

Private Sub Form_Load()
Dim HT As Integer
Text1.Left = 0
Text1.Width = Picture1.Width
Text1.Height = Picture1.TextHeight("A")
Text1.Top = (Picture1.Height = Text1.Height) / 2
Text1.Visible = True
NumLines = 1
End Sub

6. Add the following code to the Change event for Text1:

Private Sub Text1_Change()
Dim Ret As Long
Dim HT As Integer
Ret = SendMessage(Text1.hWnd, EM_GETLINECOUNT, 0, ByVal 0&)
If Ret <> NumLines Then
HT = Picture1.TextHeight("A")
Text1.Height = HT * Ret
Text1.Top = (Picture1.Height - Text1.Height) / 2
NumLines = Ret
SendKeys "{PGUP}", True
Text1.SelStart = Len(Text1)
End If
End Sub

Tip 105: Removing a Form's Title Bar

Abstract
This article explains how you can remove the title bar from a window or form from
within a Microsoft® Visual Basic® application.

Modifying the Style Attributes of a Window
You can use two Microsoft® Windows® application programming interface (API)
functions GetWindowLong and SetWindowLong to modify the appearance of a window
when your Visual Basic® application is running.

These functions allow you to programmatically change one or more style bits
associated with a specific window. For example, you can remove a window's
title bar by changing the following style bits at run time:

WS_SYSMENU The window has a control menu on the left side of its title bar
WS_MINIMIZEBOX The window has a minimize box on the right side of its title bar
WS_MAXMIZEBOX The window has a maximize box on the right side of its title bar
WS_DLGFRAME The window has a double border, but does not have a title bar

First, we must first call GetWindowLong. This function reports the window style
associated with a window, among other pieces of information.
To use GetWindowLong, you must include its Declare statement in your program as
follows (note that the Declare statement must be typed as a single line of text):

Private Declare Function GetWindowLong Lib "User" (ByVal hWnd As Integer,
ByVal nIndex As Integer) As Long

The GetWindowLong function requires two arguments. The first argument is the
window's handle; the second argument specifies the type of information you
want to retrieve. In this case, we want to retrieve the window's style settings.
The current window style is returned as a long value after GetWindowLong is
called.

After we have retrieved the current window style for the window, we need to save
the original style value that was just retrieved so that we can later restore the
window's title bar, if desired. This is done by testing for the individual title
bar attributes and saving each in turn to a new OriginalStyle variable. Next, we
need to remove the attributes associated with the window's title bar. These
attributes are the Minimize and Maximize buttons, the control menu, and the
dialog box frame. We can remove them from the original window style value that
was just retrieved by using the bitwise AND NOT function. Finally, we can call
SetWindowLong to send this information to Windows, which causes the title bar
to be removed from the window.

Example Program

This program shows how you can remove and later restore a window's title bar.
1. Create a new project in Visual Basic. Form1 is created by default.
2. Add a Command Button control to Form1. Command1 is created by default. Set
its Caption property to "Remove Title Bar".
3. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
RemoveTitleBar Form2
Form2.Show
End Sub

4. Add a second Command Button control to Form1. Command2 is created by default.
Set its Caption property to "Restore Title Bar".
5. Add the following code to the Click event for Command2:

Private Sub Command2_Click()
RestoreTitleBar Form2
Form2.Show
End Sub

6. From the Insert menu, select Form. Form2 is created by default. Adjust the
size of this form so that it is approximately half the size of Form1. Set
its AutoRedraw property to True and its Caption property to an empty (NULL)
string.
7. Add a Command Button control to Form2. Command1 is created by default. Set
its Caption property to "OK".
8. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
Form1.Show
Unload Form2
End Sub

9. From the Insert menu, select Module. Module1.Bas is created by default.
10. Add the following Constant and Declare statements to Module1.Bas (note that
each Declare statement must be typed as a single line of text):

Option Explicit
Private Declare Function GetWindowLong Lib "User" (ByVal hWnd As Integer,
ByVal nIndex As Integer) As Long
Private Declare Function SetWindowLong Lib "User" (ByVal hWnd As Integer,
ByVal nIndex As Integer, ByVal dwNewLong As Long) As Long
Const GWL_STYLE = (-16)
Const WS_DLGFRAME = &H400000
Const WS_SYSMENU = &H80000
Const WS_MINIMIZEBOX = &H20000
Const WS_MAXIMIZEBOX = &H10000

11. Create a new function called RemoveTitleBar to Module1.Bas. Add the following
code to this function:

Sub RemoveTitleBar(frm As Form)
Static OriginalStyle As Long
Dim CurrentStyle As Long
Dim X As Long
OriginalStyle = 0
CurrentStyle = GetWindowLong(frm.hWnd, GWL_STYLE)

OriginalStyle = OriginalStyle Or (CurrentStyle And WS_DLGFRAME)
OriginalStyle = OriginalStyle Or (CurrentStyle And WS_SYSMENU)
OriginalStyle = OriginalStyle Or (CurrentStyle And WS_MINIMIZEBOX)
OriginalStyle = OriginalStyle Or (CurrentStyle And WS_MAXIMIZEBOX)

CurrentStyle = CurrentStyle And Not WS_DLGFRAME
CurrentStyle = CurrentStyle And Not WS_SYSMENU
CurrentStyle = CurrentStyle And Not WS_MINIMIZEBOX
CurrentStyle = CurrentStyle And Not WS_MAXIMIZEBOX

X = SetWindowLong(frm.hWnd, GWL_STYLE, CurrentStyle)
frm.Refresh
End Sub

12. Create a new function called RestoreTitleBar to Module1.Bas. Add the
following code to this function:

Sub RestoreTitleBar(frm As Form)
Static OriginalStyle As Long
Dim CurrentStyle As Long
Dim X As Long

CurrentStyle = GetWindowLong(frm.hWnd, GWL_STYLE)
CurrentStyle = CurrentStyle Or OriginalStyle
X = SetWindowLong(frm.hWnd, GWL_STYLE, CurrentStyle)
frm.Refresh
End Sub

Run this example program by pressing F5. Click the "Remove Title Bar" command
button. Form2 is displayed. Notice that the title bar has been removed from
the form. Click the OK command button, then click the Restore Title Bar command
button. Form2 is displayed again, this time with its title bar intact.

Additional References
"GetWindowLong." (Development Library, Product Documentation, SDKs, Windows 3.1
SDK, Programmer's Reference, Volume 2: Functions)
Knowledge Base Q77316."How to Determine Display State of a VB Form, Modal or
Modeless."
Knowledge Base Q83915. "SAMPLE: Adding and Removing Caption of a Window."
"SetWindowLong." (Development Library, Product Documentation, SDKs, Windows 3.1
SDK, Programmer's Reference Volume 2: Functions)

Tip 104: Creating a Form with a Thin Title Bar

Abstract
Many Microsoft® Windows®-based applications include a Toolbox control. A toolbox
is a group of icons that the user can click to perform various operations within
a running application. These toolbox windows usually display a very small, thin
title bar instead of the normal-sized title bar. This article explains how you
can create forms with thin title bars in your Visual Basic® applications.

Using SendMessage and GetCursorPos to Create Title Bars

You can design a form that contains a thin title bar. This is most often used in
Toolbox controls from which the user can click on an icon to perform a program
operation.
In the example program below, we use a Label control, sized to fit at the top of
our form. This control, which will become the thin title bar, responds to both
the Click and MouseDown events. These two events allow the user to click on the
Label control (that is, the thin title bar) and drag the entire form to a new
location on the screen. This gives our Microsoft® Visual Basic® application the
same functionality as a toolbox window.

To enable our user to drag the form to a new location on the screen, we need to
determine the cursor's current X and Y coordinates on the screen. You can use the
Microsoft® Windows® application programming interface (API) GetCursorPos function
to retrieve the cursor's current location.
To call the GetCursorPos function, you must first add its Declare statement to
the General Declarations section of your Visual Basic application. Following is
the declaration for the GetCursorPos function:

Private Declare Sub GetCursorPos Lib "User" (lpPoint As POINTAPI)

The GetCursorPos function requires only one argument a POINTAPI structure. This
structure will hold the cursor's current position, which is reported in screen
coordinate values.
The cursor's horizontal position is stored in the X variable; the cursor's
vertical position is stored in the Y variable within the POINTAPI structure:

Type POINTAPI
X As Integer
Y As Integer
End Type

After the cursor's position has been retrieved, we issue the LSet statement to
convert the X and Y values to values that can be understood by the SendMessage
function. In other words, LSet converts the X and Y integers to a single long
value.
Next, we issue two SendMessage commands to Windows. The first SendMessage
statement tells Windows that, because a MouseDown event has just occurred,
it needs an equivalent MouseUp event. The second SendMessage statement tells
Windows that the user has clicked the title bar. Windows then processes our
thin title bar's Click and MouseDown events as it would for a normal window.

Example Program
This program shows how to create a form with a small title bar.
1. Create a new project in Visual Basic. Form1 is created by default.
2. Set the following properties for Form1:

ClipControls 0 'False
ControlBox 0 'False
MaxButton 0 'False
MinButton 0 'False

3. Add the following Constant and Declare statements to the General Declarations
section of Form1 (note that the Declare statements must be typed as single
lines of text):

Private Declare Function SendMessage Lib "User" (ByVal hWnd As Integer, ByVal
wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Any) As Long
Private Declare Sub GetCursorPos Lib "User" (lpPoint As POINTAPI)
Const WM_LBUTTONUP = &H202
Const WM_SYSCOMMAND = &H112
Const MOUSE_MOVE = &HF012

4. Add a Label control to Form1. Label1 is created by default. Set its Caption
property to "Thin Title Bar".
Note: For this example program, change the size of Form1 so that it
resembles the size and shape of a Toolbox window. Next, position
the Label control at the top of the form and adjust its size so
that it isthe same size as a thin title bar.
5. Add the following code to the Click event for Label1:

Private Sub Label1_Click()
Dim mpos As POINTAPI
Dim P As ConvertPOINTAPI
Dim Ret As Integer

Call GetCursorPos(mpos)
LSet P = mpos
Ret = SendMessage(Me.hWnd, WM_LBUTTONUP, 0, P.XY)
Ret = SendMessage(Me.hWnd, WM_SYSCOMMAND, MOUSE_MOVE, P.XY)
End Sub

6. Add the following code to the MouseDown event for Label1 (note that the first
two lines must be typed as a single line of code):

Private Sub Label1_MouseDown(Button As Integer, Shift As Integer,
X As Single, Y As Single)
Dim mpos As POINTAPI
Dim P As ConvertPOINTAPI
Dim Ret As Integer

Call GetCursorPos(mpos)
LSet P = mpos
Ret = SendMessage(Me.hWnd, WM_LBUTTONUP, 0, P.XY)
Ret = SendMessage(Me.hWnd, WM_SYSCOMMAND, MOUSE_MOVE, P.XY)
End Sub

7. From the Insert menu, select Module. Module1.Bas is created by default.
8. Add the following type declarations to Module1.Bas:

Type POINTAPI
X As Integer
Y As Integer
End Type

Type ConvertPOINTAPI
XY As Long
End Type

Run the example program by pressing F5. Form1 should be displayed on the screen
with the thin title bar appearing at the top of the form. You can drag the form
by clicking on the title bar, just as you would do with any other window that has
a title bar.

Additional References
"Dave's Top Ten List of Tricks, Hints, and Techniques for Programming in Windows."
(Development Library, Books and Periodicals, Microsoft Systems Journal,
October 1992, Volume 7, Number 6)
Knowledge Base Q83349. "How to Create a Form with No Title Bar in VB for Windows."
Knowledge Base Q71280. "How to Create a Flashing Title Bar on a Visual Basic Form."

Tip 103: Preventing the CTRL+TAB and CTRL+F6 Key Combinations from Activating

Abstract
A multiple-document interface (MDI) window can contain multiple child windows. A
user can switch between child windows by pressing the CTRL+TAB or CTRL+F6 key
combinations. This article explains how you can prevent the user from using these
keys to switch to another child window.

Using Message Blaster to Disable Keystrokes
Many Microsoft® Windows®-based applications use multiple-document interface (MDI)
windows to display several child windows to the user. For instance, Word for
Windows lets you work with several different documents at the same time. Each text
file is displayed in its own child window.

When users want to switch from one child window to another, they press either
CTRL+TAB or CTRL+F6. The next window in the list is then brought to the top of
the window list (that is, it becomes the currently active window).
In a Visual Basic® application, you can disable this window-switching by
intercepting the messages sent to Windows. The WM_SYSCOMMAND message triggers the
event that switches between child windows. The Message Blaster custom control can
be used to process this WM_SYSCOMMAND message in your Visual Basic program. You
can retrieve Message Blaster from the Microsoft Development Library. For
information on the Message Blaster custom control, see "Additional References" at
the end of this article.

The general idea, however, is to capture the WM_SYSCOMMAND that is sent to
Windows when the CTRL+F6 or CTRL+TAB combination is pressed. To do this, you must
register the Message Blaster control to the target controlin this case, the first
child window (Form1). To prevent a user from activating other child windows,
execute the following statement:

MsgBlaster1=MsgPassage(0)

After you have disabled a child window in this manner, the user will not be able
to minimize or maximize the target window. In addition, the resize and move
options are also disabled.

Example Program
This program shows how to disable the CTRL+F6 and CTRL+TAB key combinations so
that the user cannot move to the next MDI child window. Run the example program
by pressing F5. The program displays two child windows (Form1 and Form2) within
an MDI document window. Normally, you can press the CTRL+TAB or CTRL+F6 keys to
switch between the child windows. The Message Blaster control has been used to
disable these two key combinations if you try to use them in Form1. Click Form2
to bring that child window to the top. Unlike Form 1, the Form 2 child window
will process the CTRL+TAB and CTRL+F6 key combinations.

1. Create a new project in Visual Basic. Form1 is created by default.
2. From the Visual Basic Insert menu, select MDI Form. MDIForm1 is created by
default.
3. Set Form1's MDIChild property to True.
4. From the Visual Basic Insert menu, select Form. Form2 is created by default.
5. Set the Form 2 MDIChild property to True.
6. From the Visual Basic Tools menu, select Custom Controls. Add a Message
Blaster control to Form1. MsgBlaster1 is created by default.
7. Add the following code to the General Declarations section of Form1:

Option Explicit
Const WM_SYSCOMMAND = &H112

8. Add the following code to the Form_Load event for Form1:

Private Sub Form_Load()
MsgBlaster1.hWndTarget = Form1.hWnd
MsgBlaster1.MsgList(0) = WM_SYSCOMMAND
End Sub

9. Add the following code to the MsgBlaster1_Message event for Form1 (note that
the first two lines below must be typed as a single line of code):

Private Sub MsgBlaster1_Message(MsgVal As Integer, wParam As Integer,
lParam As Long, ReturnVal As Long)
MsgBlaster1.MsgPassage(0) = 0
End Sub

10. Add the following code to the Form_Load event for MDIForm1:

Private Sub MDIForm_Load()
Form1.Show
Form2.Show
End Sub

Additional References
"The Elements of MDI." (Development Library, Books and Periodicals,
"Programming Windows 3.1" by Charles Petzold, PART 5 Data Exchange and Links,
Chapter 18 The Multiple-Document Interface [MDI])
Knowledge Base Q110104. "Using MSGBLAST.VBX Control to Process Windows Messages."
"Message Blaster: Processing Messages in Visual Basic." (Development Library,
Technical Articles, Visual Basic Articles)
"Switching Between MDI Child Windows." (Development Library,
Product Documentation, SDKs, Windows Interface Guidelines for Software Design,
Chapter 9 Window Management, Multiple-Document Interface)

Tip 102: Modifying a Child Window's Caption

Abstract
This article explains how you can modify the caption displayed in a
multiple-document interface (MDI) child window.

Changing the Caption of Child Windows or Forms
The Microsoft® Word for Windows® application allows you to have several
documents loaded into memory at one time. These text files are displayed in
multiple-document interface (MDI) child windows.
An MDI child window automatically inherits the parent window's caption. This
caption is inserted before the child window's own caption. As an example, if
the parent window's caption is MDIForm1 and the child window's caption is Form1,
the child window's caption, at run time, will be set to MDIForm1 - [Form1].

In your Visual Basic® application, you can set the child form's caption to a
NULL string so that only the caption of the parent window is displayed. However,
the dash and bracket characters must also be deleted. Because the caption is
displayed in the non-client area of a window, you must use a subclassing control
to process the paint event yourself. The Message Blaster custom control can be
used to modify a child window's caption.
However, another solution can do the same thing without using a subclassing
control. Just use Visual Basic's string functions (Mid and InStr) to remove the
unwanted text from the child window's caption. This code, as shown below in the
example program, is placed in the child form's Resize event. Each time Windows
needs to repaint the window, the caption will be modified.

Example Program
This program shows how to modify a child window's caption text. Start this
program by pressing F5. The original caption is "MDIForm1 - [Form1]".
Start this program again after removing the Exit Sub statement from the Resize
event (at the beginning of the code listing). The caption for the MDIForm1
window now reads, "MDIForm1 - Form1". The dash and bracket characters have been
removed from the string. In addition, if you set Form1's caption to a NULL
string, MDIForm1 will simply display its own caption even when Form1 is
minimized.

1. Create a new project in Visual Basic. Form1 is created by default.
2. From the Visual Basic Insert menu, select MDI Form. MDIForm1 is created by
default.
3. Set Form1's MDIChild property to True. Modify the size of this form so that
it is smaller than the MDIForm1 form.
4. Add the following code to the Form_Load event for Form1:

Private Sub Form_Load()
Form1.Tag = Form1.Caption
MDIForm1.Tag = MDIForm1.Caption
Form1.WindowState = 2 'Maximize this form
End Sub

5. Add the following code to the Resize event for Form1:

Private Sub Form_Resize()
Dim Cap As String
Dim Postn As Integer

If (Form1.WindowState = 2) Then
Cap = MDIForm1.Caption

MDIForm1.Caption = ""
Postn = InStr(Cap, "[")
If (Postn) Then
Mid(Cap, Postn, 1) = " "
End If

Postn = InStr(Cap, "]")
If (Postn) Then
Mid(Cap, Postn, 1) = " "
End If

Postn = InStr(Cap, "-")
If (Postn) Then
Mid(Cap, Postn, 1) = " "
End If

Form1.Caption = ""
MDIForm1.Caption = Cap
End If

If (Form1.WindowState = 0) Then
Form1.Caption = Form1.Tag
MDIForm1.Caption = MDIForm1.Tag
End If
End Sub

Tip 101: Using the Built-In Windows Icons

Abstract
There are several icons built into the Windows® operating system that are used
by Windows when displaying message boxes. This article explains how to use the
built-in icons in your own Visual Basic® applications.

Displaying the Built-In Windows Icons
In a Visual Basic® application, you can use the icons built into the Windows®
operating system. These include the hand, exclamation point, question mark,
asterisk, and application icons. The CONSTANT.TXT file defines these as follows:

Const IDI_APPLICATION = 32512&
Const IDI_HAND = 32513&
Const IDI_QUESTION = 32514&
Const IDI_EXCLAMATION = 32515&
Const IDI_ASTERISK = 32516&

Before you can use one of these icons in your Visual Basic application, you must
load the icon using the Windows application programming interface (API) LoadIcon
function. This function loads a specified icon into the device context. In the
example program below, we want to display the icon in a Picture Box control.
Therefore, we must first retrieve a device context for the Picture Box control.

To retrieve a device context for a window, you use the Windows application
programming interface (API) GetWindowDC function, as follows:

Private Declare Function GetWindowDC Lib "User" (ByVal hWnd As Integer)
As Integer

(Note that this statement must be typed as a single line of code.)
This function requires only one argumentan integer value containing the window's
handle. The device context's handle is returned as an integer value or, if the
function was not successful, a value of zero is returned.

When you have finished using the device context you must remember to release the
device context. This can be done by calling the ReleaseDC function, passing it
the handle of the device context that you want to release.
After retrieving the device context, you can call the LoadIcon function to
display the specified icon in the device context. Because this is a built-in
Windows icon, we set the first argument to a value of zero. The second argument
to the LoadIcon function is a constant value telling the function which icon you
want to load.

Example Program
This program shows how to use the built-in icons used by the Windows operating
system. This program displays the exclamation icon in the Picture Box control.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add the following Constant and Declare statements to the General
Declarations section of Form1 (note that each Declare statement must be
typed as a single line of code):

Private Declare Function DrawIcon Lib "User" (ByVal hDC As Integer, ByVal X
As Integer, ByVal y As Integer, ByVal hIcon As Integer) As Integer
Private Declare Function LoadIcon Lib "User" (ByVal hInstance As Integer, ByVal
lpIconName As Any) As Integer
Private Declare Function GetWindowDC Lib "User" (ByVal hWnd As Integer) As
Integer
Private Declare Function ReleaseDC Lib "User" (ByVal hWnd As Integer, ByVal hDC
As Integer) As Integer
Const IDI_EXCLAMATION = 32515&

3. Add a Picture Box control to Form1. Picture1 is created by default. Set its
AutoRedraw property to True.
4. Add a Command Button control to Form1. Command1 is created by default.
5. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
Dim hDCCur As Long
Dim hIcon As Integer
Dim X As Integer

hDCCur = GetWindowDC(Picture1.hWnd)
hIcon = LoadIcon(0, IDI_EXCLAMATION)
X = DrawIcon(hDCCur, 0, 0, hIcon)
Call ReleaseDC(Picture1.hWnd, hDCCur)
End Sub

Additional References
Knowledge Base Q88944. How to Extract a Windows Program IconRunning or Not.
Specifying a Class Icon and Using Built-In Icons (Product Documentation, SDKs,
Windows 3.1 SDK, Guide to Programming)

Tip 100: Printing a Form Multiple Times on One Page

Abstract
This article explains how you can print a Visual Basic® form several
times on a single piece of paper.

Printing Forms on the Printer Device
You can use the Windows® application programming interface (API)
StretchBlt function to copy a form to another form multiple times. For
instance, the example program below uses the StretchBlt function to
copy a form to a new form. The original form is copied four times. The
destination form then contains a copy of the original form in its
upper left, lower left, upper right, and lower right corners.

The technique presented in this article is usefull for duplicating a
form several times. For example, if you designed a form to keep track
of telephone messages, you could print four messages per printed page,
instead of using one piece of paper per telephone message.
The StretchBlt function can be used to copy an image from one device
context to another. To use this function in your Visual Basic®
application, include the following Declare statement in the General
Declarations section of your form (note that it must be typed as a
single line of code):

Private Declare Function StretchBlt Lib "GDI" (ByVal hDC%, ByVal X%, ByVal y%,
ByVal nWidth%, ByVal nHeight%, ByVal hSrcDC%, ByVal XSrc%, ByVal YSrc%, ByVal
nSrcWidth%, ByVal nSrcHeight%, ByVal dwRop&) As Integer

The StretchBlt function requires the following arguments:

hDC An integer value containing the destination device context.
X,Y Integer values defining the rectangle's upper left corner
for the destination device context.
nWidth The width of the image.
nHeight The height of the image.
hSrcDC An integer value containing the source device context.
Xsrc, YSrc Integer values defining the rectangle's upper left corner
for the source device context.
nSrcWidth The width of the image.
nSrcHeight The height of the image.
dwRop The raster operation that is to be used.

In the example program below, the StretchBlt function is called four
times to copy the original Form1 to the destination Form2. Each time
the copy operation is performed, the destination is offset to the next
quarter section of Form2.

Example Program
Before running this program, make sure your printer is online and
ready to accept data. Press the F5 function key to run the example
program, which will print Form2 on the paper four times.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add a Command Button control to Form1. Command1 is created by
default.
3. Add the following code to the Click event for Command1 (note that
the X = lines must each be typed as a single line of code):

Private Sub Command1_Click()
Dim W As Integer
Dim H As Integer
Dim X As Integer

W = Form2.ScaleWidth / 2
H = Form2.ScaleHeight / 2
X = SetStretchBltMode(Form2.hDC, 3)

X = StretchBlt(Form2.hDC, 0, 0, W, H, Form1.hDC, 0, 0, Form1.ScaleWidth,
Form1.ScaleHeight, SRCCOPY)
X = StretchBlt(Form2.hDC, W, 0, W, H, Form1.hDC, 0, 0, Form1.ScaleWidth,
Form1.ScaleHeight, SRCCOPY)
X = StretchBlt(Form2.hDC, W, H, W, H, Form1.hDC, 0, 0, Form1.ScaleWidth,
Form1.ScaleHeight, SRCCOPY)
X = StretchBlt(Form2.hDC, 0, H, W, H, Form1.hDC, 0, 0, Form1.ScaleWidth,
Form1.ScaleHeight, SRCCOPY)

Form2.Refresh
Form2.PrintForm
End Sub

4. From Visual Basic's menu, select Insert. Select Form to create a new form.
Form2 is created by default. Add a Text Box control to Form2 or otherwise
put some type of material on the form so you can see it printed on the paper.
5. Add the following code to the General Declarations section of Form1 (note
that each Declare statement should be typed as a single line of code):

Private Declare Function SetStretchBltMode Lib "GDI" (ByVal hDC%, ByVal
nStretchMode%) As Integer
Private Declare Function StretchBlt Lib "GDI" (ByVal hDC%, ByVal X%, ByVal y%,
ByVal nWidth%, ByVal nHeight%, ByVal hSrcDC%, ByVal XSrc%, ByVal YSrc%, ByVal
nSrcWidth%, ByVal nSrcHeight%, ByVal dwRop&) As Integer
Const SRCCOPY = &HCC0020

Additional References
"Creating Bitmaps of Any Size with StretchBlt." (Books and Periodicals, Inside
Visual Basic Articles [Cobb])
Knowledge Base Q84066. "How to Print Entire VB Form and Control the Printed Size."
Knowledge Base Q77060. "How to Print a VB Picture Control Using Windows API
Functions."

Tip 99: Adding Three-Dimensional Effects to Visual Basic Forms

Abstract
You can use functions in the CTL3D.DLL dynamic-link library to add a
three-dimensional (3-D) look to any form. This article explains how to
use this .DLL to create a 3-D form in a Visual Basic® application.

Creating 3-D Forms
The CTL3D.DLL dynamic-link library contains Windows® application
programming interface (API) functions you can use to create
three-dimensional (3-D) message boxes and common dialog boxes in your
Visual Basic® applications. You can also use these functions to create
a 3-D form. The form must have a fixed-double-style border. In
addition, the form's MinButton and MaxButton properties must be set to
False.

As the example program below shows, the CTL3D.DLL functions can enable
your Visual Basic application to display 3-D forms, message boxes, and
common dialog boxes.

Example Program
1. Create a new project in Visual Basic. Form1 is created by default.
2. Add a Command Button control to Form1. Command1 is created by
default.
3. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
Form2.Show
End Sub

4. From the Insert menu, select Form to create a second form. Form2
is created by default. Set the form's BorderStyle property to
3-Fixed Double, the MinButton property to False, and the MaxButton
property to False.
5. Add the following code to the Form_Load event for Form2:

Private Sub Form_Load()
Call Ctl3DForm(Me)
End Sub

6. From the Insert menu, select Module to create a new module.
Module1.Bas is created by default.
7. Add the following code to Module1.Bas (note that the Private
lines must each be typed as a single line of code):

Const SWW_HPARENT = -8
Const GWW_HINSTANCE = -6
Const GWW_HPARENT = -8
Const BUTTON_FACE = &H8000000F
Const FIXED_DOUBLE = 3
Const DS_MODALFRAME = &H80&
Const GWL_STYLE = (-16)
Private Declare Function Ctl3DSubClassDlgEx Lib "CTL3D.DLL" (ByVal hWnd As
Integer, ByVal Flags As Long) As Integer
Private Declare Function GetWindowLong Lib "User" (ByVal hWnd As Integer, ByVal
nIndex As Integer) As Long
Private Declare Function SetWindowLong Lib "User" (ByVal hWnd As Integer, ByVal
nIndex As Integer, ByVal dwNewLong As Long) As Long
Sub Ctl3DForm(frm As Form)
Dim hWnd As Integer
Dim Result As Integer
Dim lStyle As Long
Dim Flag1 As Long

hWnd = frm.hWnd
Flag1 = 0

If frm.BorderStyle = FIXED_DOUBLE Then
frm.BackColor = BUTTON_FACE
lStyle = GetWindowLong(hWnd, GWL_STYLE)
lStyle = lStyle Or DS_MODALFRAME
lStyle = SetWindowLong(hWnd, GWL_STYLE, lStyle)
Result = Ctl3DSubClassDlgEx(hWnd, Flag1)
End If
End Sub

Run the example program by pressing the F5 function key. Click the
Command Button to display Form2. Form2 is modified so that it has a
three-dimensional look.

Additional References
Knowledge Base Q113898. "How to Use CTL3D.DLL in Your Visual Basic
Program."
"Seventeen Techniques for Preparing Your 16-Bit Applications for
Chicago." (Books and Periodicals, Microsoft Systems Journal,
1994 Volume 9, February 1994 Number 2)
"Windows Questions and Answers." (Books and Periodicals, Microsoft
Systems Journal, 1994 Volume 9, August 1994, Number 8)

Tip 98: Saving a Window's Client Area in Bitmap Format

Abstract
You may need to create a bitmap (.BMP) image file that contains a
window's client area. This article explains how to save a window's
client area to disk in a bitmap image file format.

Saving Bitmap Images to Disk
You can save the contents of a window to a disk file in bitmap format
by retrieving the target window's rectangle area and then using
several Windows® application programming interface (API) functions to
save that image to a device context such as a Picture Box control.

The GetWindowRect function can be used to retrieve the bounding
rectangle of a window or form. This rectangle includes the window's
borders, title bars, and other attributes associated with a window.
The Declare statement for the GetWindowRect function is as follows:

Private Declare Sub GetWindowRect Lib "User" (ByVal hWnd As Integer, lpRect
As RECT)

The GetWindowRect function takes two arguments: an integer value
containing the window's handle and a pointer to a RECT rectangle
structure. The RECT structure will contain the dimensions of the
window's rectangle area after the function is called.

The BitBlt function uses the rectangle that contains the image you
want to save to disk to copy the image from one device context to
another. In this case, BitBlt is used to copy the window's client
area to the Picture Box control. Then the Save As dialog box is used
to save the contents of the Picture Box to disk as a .BMP file.

Example Program
This program shows how to save the client area of a form or window
and save it as a .BMP file.

1. Create a new project in Visual Basic®. Form1 is created by default.
2. Add the following Constant and Declare statements to the General
Declarations section of Form1 (note that each Declare statement
must be typed as a single line of code):

Private Declare Function GetActiveWindow Lib "User" () As Integer
Private Declare Function GetWindowDC Lib "User" (ByVal hWnd As Integer)
As Integer
Private Declare Sub GetWindowRect Lib "User" (ByVal hWnd As Integer, lpRect
As RECT)
Private Declare Function ReleaseDC Lib "User" (ByVal hWnd As Integer, ByVal hDC
As Integer) As Integer
Private Declare Function BitBlt% Lib "GDI" (ByVal hDestDC%, ByVal X%, ByVal Y%,
ByVal nWidth%, ByVal nHeight%, ByVal hSrcDC%, ByVal XSrc%, ByVal YSrc%, ByVal
dwRop&)
Const SRCCOPY = &HCC0020

3. From the Insert menu, select Form to create a second form. Form2
is created by default. Set its Picture property to
"C:\WINDOWS\ARCHES.BMP".
4. From the Insert menu, select Module to create a BASIC module.
Module1.Bas is created by default.
5. Add the following Type structure to Module1.Bas:

Type RECT
Left As Integer
Top As Integer
Right As Integer
Bottom As Integer
End Type

6. Add a Timer control to Form1. Timer1 is created by default.
7. Add a Picture Box control to Form1. Picture1 is created by
default. Set its AutoRedraw property to True.
8. Add a Command Button control to Form1. Command1 is created by
default.
9. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
SaveToPicture
End Sub

10. Create a new function called SaveToPicture. Add the following code
to this function:

Sub SaveToPicture()
Dim hDCCur As Long
Dim hWndCur As Long
Dim HWndOld As Long
Dim Tim As Double
Dim ThisRect As RECT
Dim DX As Long
Dim DY As Long

HWndOld = GetActiveWindow()
Form2.Show
hWndCur = Form2.hWnd
Tim = Timer + 0.5
Do
DoEvents
Loop Until Timer >= Tim

hDCCur = GetWindowDC(hWndCur)
Call GetWindowRect(hWndCur, ThisRect)
DX = ThisRect.Right - ThisRect.Left + 2: DY = ThisRect.Bottom - ThisRect.Top + 2

With Picture1
.Width = Screen.TwipsPerPixelX * DX
.Height = Screen.TwipsPerPixelY * DY
Call BitBlt(.hDC, 0, 0, DX, DY, hDCCur, 0, 0, SRCCOPY)
.Picture = .Image
End With

Call ReleaseDC(hWndCur, hDCCur)
Form2.Hide

CommonDialog1.DefaultExt = "BMP"
CommonDialog1.DialogTitle = "Save Window As"
CommonDialog1.FileName = "*.BMP"
CommonDialog1.Action = 2

If CommonDialog1.FileName <> Empty Then
SavePicture Picture1.Picture, CommonDialog1.FileName
End If
End Sub

11. Add a Common Dialog control to Form1. CommonDialog1 is created by
default.

Run this program by pressing the F5 function key. Click once on the
command button. The ARCHES.BMP picture is displayed on Form2. Next,
the Save File As dialog box pops up on the screen. Type a filename
for the .BMP file and Visual Basic will save Form2's window (which
contains the ARCHES.BMP picture) to a new bitmap file.

Additional References
"Bitmaps." (Product Documentation, DDKs, Windows 3.1 DDK, Device
Driver Adaptation Guide)
"GetActiveWindow"; "GetWindowDC"; and "ReleaseDC." (Product
Documentation, SDKs, Windows 3.1 SDK, Programmer's Reference
Volume 2: Functions)
Knowledge Base Q71104. "How to Use Windows BitBlt Function in Visual
Basic Application."

Tip 97: Creating a Task List

Abstract
This article explains how you can determine what modules are currently
running under Microsoft® Windows® and create a task list based on that
information.

Determine What Modules Are Currently Running
The TOOLHELP.DLL dynamic-link library (.DLL) file contains two
Windows® application programming interface (API) functions that can be
used to create a list of modules currently loaded under Windows. These
are the ModuleFirst and ModuleNext functions. To declare these
functions within your program, include the following Declare
statements in the Global Module or General Declarations section of a
Visual Basic® form:

Private Declare Function ModuleFirst Lib "toolhelp.dll" (mdlentry As
ModuleEntry) As Integer
Private Declare Function ModuleNext Lib "toolhelp.dll" (mdlentry As ModuleEntry)
As Integer

Note that each Declare statement must be typed as a single line of text.
The ModuleFirst and ModuleNext functions are the key to traversing
the chain of loaded modules in Windows. The ModuleFirst function fills
the specified structure with information describing the first module
in the list of currently loaded modules. The ModuleNext function is
then called to find the next module in the list.

The MODULEENTRY structure required by these two functions must be
defined as follows:

dwSize The size of the structure in bytes.
szModule The module's name (a null-terminated string).
hModule The module's handle.
wcUsage Used by GetModuleUsage function.
szExePath The module.
wNext The window.

Before you can use these two functions, however, you must initialize
the dwSize field of the MODULEENTRY structure. This value should be
specified as the number of bytes needed to store the information
returned by ModuleFirst and ModuleNext.
These functions return a value indicating the status of the function.
The function was successful if the returned value is nonzero; the
function was not successful (or no more modules were found in memory)
if the value returned is zero.

Example Program
This program shows how to retrieve the module name and path for every
running task under Windows. The name of each module is displayed in
the first List Box control, while the full path of the module is
displayed in the second List Box control.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add the following code to the General Declarations section of
Form1 (note that each Declare statement should be typed as a
single line of text):

Private Declare Function ModuleFirst Lib "toolhelp.dll" (mdlentry As
ModuleEntry) As Integer
Private Declare Function ModuleNext Lib "toolhelp.dll" (mdlentry As ModuleEntry)
As Integer

3. Add a Command Button control to Form1. Add the following code to
the Click event for Command1:

Private Sub Command1_Click()
Dim Tmp As ModuleEntry
Dim Retn As Integer

Tmp.dwSize = Len(Tmp)
Retn = ModuleFirst(Tmp)
While Retn <> 0
If InStr(Tmp.szExepath, ".VBX") <> 0 Or InStr(Tmp.szExepath, ".DLL") <>
0 Or InStr(Tmp.szExepath, ">DRV") <> 0 Then
List1.AddItem Tmp.szModule
List2.AddItem Tmp.szExepath
End If
Tmp.szExepath = ""
Retn = ModuleNext(Tmp)
Wend
End Sub

4. Add a List Box control to Form1. List1 is created by default.
5. Add a second List Box control to Form1. List2 is created by
default.
6. From the Insert menu, select Module. Module1.Bas is created by
default.
7. Add the following user-defined Type to Module1.Bas:

Type ModuleEntry
dwSize As Long
szModule As String * 10
hModule As Integer
wcUsage As Integer
szExepath As String * 256
wNext As Integer
End Type

Additional References

Knowledge Base Q78001. "How to Get Windows Master (Task List) Using
Visual Basic."
Knowledge Base Q80124. "Retrieving the Names of Simultaneous Tasks
Under Windows."
"Windows Questions and Answers." (Books and Periodicals, Microsoft
Systems Journal, 1994 Volume 9, May 1994 Number 5)

Tip 96: Centering a Form over Another Form

Abstract
You can position a form so it appears centered within another form.
This article explains how to center a form within its parent form.
This same technique can be applied to centering controls such as
Picture Box controls over other controls.

Centering Forms in Visual Basic
When developing an application in Visual Basic®, you may need to
position a form so it is centered over another form. You can position
a form in this way by using Visual Basic's Left, Top, Height, and
Width properties.

The Left property defines the position of the form's left edge and the
Top property defines the position of the form's top edge. In the same
manner, the Width and Height properties define how wide and high the
form is. It is easy enough to center a form on a container by
calculating the width and height of the form and dividing that value
by two to center it within the control.
To center a form within a parent form, take the width of Form1 and
Form2, subtract these two values, and divide the result by two. Next,
add Form1's width to the result to determine the position of Form2's
left edge within Form1. This will center Form2 horizontally within
Form1.

In the same manner, you can center a form vertically within another
form by using the Top and Height properties of each form, dividing by
two, and setting Form2's Top property to the result.

Example Program
This program shows how to center a form over another form. After you
run this example program by pressing the F5 function key, click the
Command Button. The program displays Form2 centered over its "parent,"
Form1.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add a Command Button control to Form1. Command1 is created by
default.
3. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
Form2.Show
CentreFormWithParent Form2, Form1
End Sub

4. From the Insert menu, select Form to create a second form. Form2
is created by default. Change this form's size so it is smaller
than Form1.
5. Create a new function called CreateFormWithParent. Add the
following code to this function:

Sub CenterFormWithParent(aForm As Form, aParent As Form)
aForm.Left = aParent.Left + (aParent.Width - aForm.Width) / 2
aForm.Top = aParent.Top + (aParent.Height - aForm.Height) / 2
If (aForm.Left + aForm.Width) > Screen.Width Then
aForm.Left = Screen.Width - aForm.Width
Else
If aForm.Left < 0 Then aForm.Left = 0
End If
If (aForm.Top + aForm.Height) > Screen.Height Then
aForm.Top = Screen.Height - aForm.Height
Else
If aForm.Top < 0 Then aForm.Top = 0
End If
End Sub

Tip 87: Sending Output to the Printer in Any Order

* VB-CODE (1)

Abstract
You can use the Visual Basic® Print method to send text to the default
printer. This article explains how you can send data to the printer in
any order (that is, you can print a line of text in the middle of the
page and then print some other text at the top of page).

Outputting Data to the Printer
In a Visual Basic® application, you may need to create a hard copy of
some data. To send data to the default printer, you use Visual Basic's
Print method. For example, to send a line of text to the printer, you
would issue a statement such as:

Printer.Print "This is a test"

When this statement is executed, Visual Basic will print the text on
the printer. Note that the text is printed at the coordinates
specified by the CurrentX and CurrentY properties.
Each time you send data to the printer, Visual Basic automatically
updates the CurrentX and CurrentY properties. CurrentX is incremented
each time a new character is sent to the printer on the same line.
When a new line is needed, the value in CurrentX is reset to zero,
and CurrentY is incremented by one to account for the new line.

Therefore, as the example program below shows, you can print to any
specific physical location on the paper. You can print a line of text
in the center of the paper first and then, by simply changing the
CurrentX and CurrentY properties, print a line of text at the top of
the page.

Example Program
The example program below prints two lines of text on the default
printer. The first line is actually the second line to be physically
transferred to the printer.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add a Command Button control to Form1. Command1 is created by
default.
3. Add the following code to the Click event for Command1:

Private Sub Command1_Click()
Printer.ScaleMode = 2
Printer.FontSize = 42
Printer.CurrentX = 40
Printer.CurrentY = 40
Printer.Print "This is the first line to be printed"
Printer.CurrentX = 40
Printer.CurrentY = 12
Printer.FontSize = 14
Printer.Print "This is actually the second line to be printed"
Printer.EndDoc
End Sub

Additional References
Knowledge Base Q119673. "How to Print with Rotated Text."
"Managing Your Print Jobs." (Books and Periodicals, Inside Visual
Basic Articles [Cobb])

Tip 86: Allowing a Visual Basic Application to Accept Drag-and-Drop

* VB-CODE (4)

Abstract
Many Windows=AE-based applications can accept, or process, a file that
has been dragged from File Manager. This article explains how you can
add this feature to your own Visual Basic=AE application.

Using MSGBLAST.VBX to Accept Drag-and-Drop Files
Using File Manager, you can drag a file to another application and,
when you release the mouse button (drop the file), the target
application can process the file any way it wants to.

In order for a program to be able to accept drag-and-drop files,
however, the program must have a method of recognizing when a file has
been sent to it. In Visual Basic=AE, this can be done by using the
Message Blaster custom control and three Windows=AE application
programming interface (API) functions: DragAcceptFiles, DragQueryFile,
and DragFinish.
The DragAcceptFiles function tells Windows that a specific window
(that is, your Visual Basic application's form) can accept files
dropped from File Manager. The Declare statement for this function is:

Private Declare Sub DragAcceptFiles Lib "shell" (ByVal hWnd
As Integer, ByVal bool As Integer)

(Note that this Declare statement must be typed as a single line of
code.)
The DragAcceptFiles function takes only two arguments: the handle of
the window that will accept the dropped files, and an integer value
that specifies if the file can be accepted or ignored. If the Boolean
argument is set to True, the window can accept dropped files; if it is
set to zero, the window can no longer accept dropped files.

You can retrieve the name of the file that was dropped on the target
window by calling the DragQueryFile function. This function's
declaration statement is:

Private Declare Function DragQueryFile Lib "shell" (ByVal wParam
As Integer, ByVal Index As Integer, ByVal lpszFile
As Any, ByVal BufferSize As Integer) As Integer

(Note that this Declare statement must be typed as a single line of
code.)
DragQueryFile requires four arguments, as follows:

wParam An integer value that contains the internal data
structure's handle. This is provided by the WM_DROPFILES
message.
Index An integer value containing the number of the individual
file to be retrieved. If this value is -1, the number of
files listed in the wParam structure will be returned.
lpszFile A string buffer that contains the name of the dropped file.
BufferSize An integer value containing the maximum number of
characters in lpszFile.

After calling the DragQueryFile function, an integer value reports the
status of the function. This value contains the number of characters
copied to the lpszFile string or the number of files available if
Index was set to zero.
The third function needed to work with drag-and-drop files is the
DragFinish function. This function simply requires that the internal
data structure's handle be passed to it. DragFinish frees all
structures used when transferring the file to the target application.

The final step is to process the WM_DROPFILES message. This message is
sent by Windows each time it needs to send a drag-and-drop request to
a program. In your Visual Basic program you need only use the Message
Blaster custom control to intercept the WM_DROPFILES message before
Windows actually processes it itself. In the example program below,
we use the Message Blaster control to retrieve the name of the dropped
file and store that name in the List Box control.

Example Program
The example program below shows how to allow your Visual Basic
application to accept drag-and-drop files from File Manager. To use
this demonstration program, first execute the Windows Explorer or
File Manager application. Then run the DEMO.EXE program. When you drag
a file from File Manager to DEMO.EXE's window and release the mouse
button, the filename will be displayed in the List Box control.

1. Create a new project in Visual Basic. Form1 is created by default.
2. Add the following code to the General Declarations section of
Form1 (note that each Declare statement must be typed as a single
line of code):

Option Explicit

Private Declare Sub DragAcceptFiles Lib "shell" (ByVal hWnd
As Integer, ByVal bool As Integer)
Private Declare Function DragQueryFile Lib "shell" (ByVal wParam
As Integer, ByVal Index As Integer, ByVal lpszFile
As Any, ByVal BufferSize As Integer) As Integer
Private Declare Sub DragFinish Lib "shell" (ByVal hDrop As Integer)

Const WM_DROPFILES =3D &H233

3. Add the following code to the Form_Load event for Form1:

Private Sub Form_Load()
msgblaster1.MsgList(0) =3D WM_DROPFILES
msgblaster1.hWndTarget =3D Me.hWnd
msgblaster1.MsgPassage(0) =3D 1
DragAcceptFiles Me.hWnd, True
End Sub

4. Add a Message Blaster custom control to Form1. MsgBlaster1 is
created by default.
5. Add the following code to the MsgBlaster1_Message event for
MsgBlaster1:

Private Sub MsgBlaster1_Message(MsgVal As Integer, wParam As Integer,
lParam As Long, ReturnVal As Long)
Dim hFilesInfo As Integer
Dim szFileName As String
hFilesInfo =3D wParam
wTotalFiles =3D DragQueryFile(hFilesInfo, &amp;HFFFF, ByVal 0&, 0)
For wIndex =3D 0 To wTotalFiles
szFileName =3D Space$(50)
Retv% =3D DragQueryFile(hFilesInfo, wIndex, szFileName, 50)
list1.AddItem szFileName
Next wIndex
DragFinish (hFilesInfo)
End Sub

6. Compile the program. From Visual Basic's File menu, select Make
EXE File to create the executable file called DEMO.EXE.

Additional References
"DragAcceptFiles." (Product Documentation, SDKs, Windows 3.1 SDK,
Programmer's Reference, Volume 2, Functions)
"Drop Everything: How to Make Your Application Accept and Source
Drag-and-Drop Files." (Books and Periodicals, Microsoft Systems
Journal)
"Message Blaster: Processing Messages in Visual Basic." (Technical
Articles, Visual Basic Articles)
"Using Drag-Drop in an Edit Control or a Combo Box." (Knowledge
Base and Bug Lists, Windows SDK KBase, Related Information)
"Using MSGBLAST.VBX Control to Process Windows Messages from VB."
(Knowledge Base and Bug Lists, Visual Basic for Windows KBase,
Related Information)

Tip 85: Hiding MDI Child Forms at Run Time

* VB-CODE (3)

Abstract
There may be situations in which you do not want a multiple-document
interface (MDI) child form displayed while your program is executing.
This article explains how you can hide an MDI child form.

Making MDI Forms Invisible
A multiple-document interface (MDI) child form allows you to have
several windows open at the same time with different documents loaded
in each window. This is how Notepad and similar programs operate so
that you can switch between different text files. You cannot, however,
hide an MDI child form at run time.

So how can you temporarily hide an MDI child window from the user? By
moving the window to a nonexistent position on your screen.
In the example program below, the MDI child form is moved off the
current viewing area of the screen. Windows=AE itself doesn't care where
you place the window; and, to your user, it appears as if the window
has been hidden.

Example Program
This program shows how you can temporarily hide an MDI child form in
your Visual Basic=AE application. Run the program by pressing the F5
function key. The MDI child window is visible on the screen. Click the
mouse on the main form. The MDI child window disappears from view.
Double-click the main form and the MDI child form is again visible on
the screen.

1. Create a new project in Visual Basic. Form1 is created by default.
Set the following properties for Form1:
BorderStyle =3D 1-Fixed Single
Height =3D 1140
Left =3D 2220
Top =3D 3030
Width =3D 4605
2. From the Insert menu, select MDI Form. MDIForm1 is created by
default.
3. From the Insert menu, select Form. Form2 is created by default.
Set the form's MDIChild property to True.
4. Add the following code to the Click event for MDIForm:

Private Sub MDIForm_Click()
Form1.Move -(2 * Form1.Width), -(2 * Form1.Height)
End Sub

5. Add the following code to the DblClick event for MDIForm:

Private Sub MDIForm_DblClick()
Form1.Move 2220, 3030, 4605, 1140
End Sub

6. Add the following code to the Form_Load event for MDIForm:

Private Sub
MDIForm_Load()
Form1.Show
Form2.Show
End Sub

Additional References
Knowledge Base Q115781. "How to Create Hidden MDI Child Forms."
"Hide Method." (Product Documentation, Office Developer's Kit 1.0,
Visual Basic 3.0 Professional Edition, Language Reference)
"Run-Time Features of MDI Child Forms." (Product Documentation,
Office Developer's Kit 1.0, Visual Basic 3.0, Professional Edition,
Programmer's Guide)

Tip 84: Creating a Scrolling "Credits" Control

* VB-CODE (2)

Abstract
You can add visual appeal to your Visual Basic=AE applications by
including a routine that automatically scrolls text vertically within
a picture box. This article explains how you can add this
functionality to your programs.

Scrolling Text Vertically Within a Picture Box
The Windows=AE application programming interface (API) BitBlt function
can be used to copy a section of a Picture Box control to another
section of that same control. You must remember to set the ScaleMode
property of the Picture Box control to Pixel mode.

The example program below shows how to use the BitBlt function to
print scrolling text on a Picture Box control. A Timer control is
used to print a string of text on the Picture Box control at selected
time intervals.

Example Program
1. Create a new project in Visual Basic. Form1 is created by default.
2. Add the following code to the General Declarations section of
Form1 (note that the Declare statement must be typed as a single
line of code):

Const SRCCOPY =3D &HCC0020
Const ShowText$ =3D "This line of text scrolls vertically."

Private Declare Function BitBlt Lib "GDI" (ByVal hDestDC As Integer,
ByVal X As Integer, ByVal Y As Integer, ByVal nWidth As Integer,
ByVal nHeight As Integer, ByVal hSrcDC As Integer,
ByVal XSrc As Integer, ByVal YSrc As Integer,
ByVal dwRop As Long) As Integer

Dim ShowIt%

3. Add a Picture Box control to Form1. Picture1 is created by
default. Set its ScaleMode property to 3-Pixel.
4. Add a Timer control to Form1. Timer1 is created by default. Set
its Interval property to 25.
5. Add the following code to the Timer event for Timer1 (note that
the Ret =3D line must be typed as a single line of code):

Private Sub Timer1_Timer()
Dim Ret As Integer
If (ShowIt% =3D 30) Then
Picture1.CurrentX =3D 0
Picture1.CurrentY =3D Picture1.ScaleHeight - 30
Picture1.Print ShowText$
ShowIt% =3D 0
Else
Ret =3D BitBlt(Picture1.hDC, 0, 0, Picture1.ScaleWidth,
Picture1.ScaleHeight - 1, Picture1.hDC, 0, 1, SRCCOPY)
ShowIt% =3D ShowIt% + 1
End If
End Sub

Run the program by pressing the F5 function key. After a short time,
the text "This line of text scrolls vertically." will be displayed in
the Picture Box control. Each time the Timer control reaches 25, the
line of text will be scrolled upward in the Picture Box control.

Additional References
Tip 45: Using BitBlt to Display Bitmaps
"BITBLT: Tests the BitBlt Function." (Sample Code, Sample City,
Visual Basic Samples)
Knowledge Base Q71104. "How to Use Windows BitBlt Function in
Visual Basic Application."

Tip 83: Listing Fields and Associated Properties for an Attached

* VB-CODE (1)

Abstract
This article describes a sample user-defined Access Basic function
that you can use to retrieve all field names and their associated
properties for an attached Microsoft=AE Access=AE table.

More Information
This article assumes that you are familiar with Access Basic and with
creating Microsoft=AE Access=AE applications using the programming tools
provided with Microsoft Access. For more information on Access Basic,
please refer to the Building Applications manual for Access 2.0 and
the Introduction to Programming manual for Access 1.x.

The example program below uses tools in Visual Basic=AE to get
information from a Microsoft Access database.

Example Program
This program demonstrates how to create and use the sample
ListFieldProperties() function.

1. Open the sample database NWIND.MDB. (This database can usually be
found in the C:\ACCESS\SAMPAPPS directory.)
2. From the File menu, choose New, and select Module.
3. Enter the following code to create the ListFieldProperties()
function:

Function ListFieldProperties ()
Dim MyDB As Database
Dim MyTable As TableDef
Set MyDB =3D DBEngine(0)(0)
Set MyTable =3D MyDB.TableDefs("Categories")
For X =3D 0 To MyTable.Fields.Count - 1
Debug.Print MyTable.Fields(X).Name
For Y =3D 0 To MyTable.Fields(X).Properties.Count - 1
Debug.Print Chr(9) & MyTable.Fields(X).Properties(Y).Name
Next Y
Next X
End Function

4. From the View menu, choose Immediate Window.
5. In the Immediate window, type the following line and press the
ENTER key:

? ListFieldProperties()

The name of each field in the Categories table will be displayed along
with that field's properties.

Additional References
"Name Property." (Product Documentation, Office Developer's Kit 1.0,
Microsoft Access 2.0, Language Reference)
"Using Properties." (Product Documentation, Office Developer's Kit 1.0,
Microsoft Access 2.0, Advanced Topics)