Restore Tray Icons After Crashes
by Karl E. Peterson
Technology Toolbox: VB6, VB5, VB4/32
Q: Restore Tray Icon After
I've written a tray application and am happy with it in nearly all respects but one. When Explorer crashes and Windows restarts it, my icon is no longer in the tray. Does Windows offer some notification so I can handle this contingency?
A: Odds are, you're already hooking your app's main window to receive notification messages for your tray icon, right? This is a good case for using true subclassing, as opposed to the misguided WM_MOUSEMOVE hack popular in many VB tray app examples. If you have a window message hook installed, and if you're either running on Windows 98/Me or have Internet Explorer 4.0 or higher installed, all you need to do is monitor for one additional message.
Whenever IE starts the taskbar, it broadcasts a registered message to all top-level windows. You can retrieve this message's value, as your application starts up, by calling RegisterWindowMessage with the string "TaskbarCreated":
m_TaskbarCreated = RegisterWindowMessage( _ "TaskbarCreated")
Rather than creating your tray icon in Sub Main or Form_Load, design a standalone routine for this task and add it to your project. Add m_TaskbarCreated to the Select Case block in your message processing routine. Now you're only one call away from creating the tray icon whenever needed, both at startup and anytime IE re-creates the taskbar. —K.E.P.
Q: Allow User Graphical
A: At its simplest, this task requires you to maintain four module-level variables to track the X/Y coordinates of where the mouse button is depressed initially and where it's subsequently released. You also need a module-level flag value that indicates whether the user is dragging a selection area within your graphic (see Figure 1).
Set the flag variable and initial X/Y values on MouseDown. On MouseMove, check the flag, and if it's set, update the endpoint X/Y values and draw the selection rectangle. You need to first draw a rectangle that erases the last one you drew, then draw the new rectangle boundary. It's a bit of a dance, but not too bad when laid out logically. The key to erasing the previous rectangle is using a DrawMode of vbNotXorPen.
You can either have all this going on within your form, or you can assign all the drudge work to a single class. I prefer the latter option (though the sample code offers examples of both; download it here), because you can readily assign the functionality on the fly to any picture box.
Within the delegation class, declare an object variable of type PictureBox using the WithEvents keyword. Class consumers can then pass a picture box reference to the class's Client property, and the picture box's events are sunk within both the class and its parent. In return, the class can raise events such as Selecting and Selected to notify its consumers of user activity (see Listing 1). All in all, a tidy solution, which you can set up as simply as this:
Private WithEvents m_Lasso As CLasso Private Sub Form_Load() Set m_Lasso = New CLasso Set m_Lasso.Client = Picture1 m_Lasso.Enabled = True End Sub
You can then react to user selections in CLasso's Selected event:
Private Sub m_Lasso_Selected() With m_Lasso Debug.Print "Selected: "; _ .X1; .Y1, .X2; .Y2 End With End Sub
CLasso is designed to use whatever ScaleMode your picture box is using, so be sure not to change this property during a user selection. —K.E.P.
About the Author