![]() |
Source Code |
![]() |
![]() |
3 | Code Libraries |   |
  |
Set the Show In Taskbar property at Run Time |
|
A technique for control freaks - making things happen like you want them to |
NOTE:
this code has been superceded by the version at the new site.
|
  |
![]()
VB provides a ShowInTask bar property for forms which allows you to choose whether a form is shown in the Alt-Tab sequence and the shell's task bar. However there are two limitations to this:
The technique demonstrated in this article sticks two fingers up at any attempt by VB to prevent you from appearing in the task bar. You get to set any flags you want well before VB has had the chance to create your window and therefore tell Windows of your true intentions before VB's form engine stuffs it up for you. Cool! ShowInTaskBar from a Windows Perspective The problem with affecting built-in behaviours in Windows is that they are not well documented and sometimes troubling to use. The logic to put a window into the task bar can be dug out from MSDN although you have to search the Knowledge Base to find the answer:
You can Take Control VB's interface into the window creation procedure is somewhat lacking. You get a Form_Initialise event when the first instance of your form object is created, followed by a Form_Load event when the form is about to be shown on screen. Form_Initialise is of no use here because it is in effect an event fired when the object is constructed, so although the object has just come into life, and hence you can use local variables, the associated UI elements have not yet been created. Therefore you may not refer to any windows or controls at this stage. Form_Load is no use either because this fires at the moment the window has been created and is about to be shown. It would have been nice to get some more intermediate events, but I suppose this is the price to pay for having an easy to use interface. So, given that there is no VB hook into the point when the window is created, how else might you detect this event? The Windows Hook to the rescue When all other things have failed, a Windows Hook is often a good thing to consider. Windows Hooks allow you to get into the message stream for your app before the messages get sent to it - and allows you to change or otherwise subvert the standard processing. By installing a hook of type WH_CALLWNDPROC during an _Initialise event, your app can be notified of any attempts by Windows to call a Window Procedure. This allows us to capture the crucial WM_CREATE notification which is sent when the window is first created. In Code - The Theory The first thing to do is to install a windows hook before any windows get created and start watching for WM_CREATE calls. The _Initialise event of Forms, UserControls and so on always fires before any windows have been created, whilst all other events fire after the windows have been created, so this is a good place as any to install the hook for window creation checking (note that the _Initialise event only fires once for a form object, so if you want this to work correctly you will always need a new instance of a form). Here is how to initiate the hook: Public Sub HookAttach() m_hHook = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf AppHook, App.hInstance, App.ThreadID) Debug.Assert m_hHook <> 0 End Sub Now whenever any window in your application has its Window Procedure called, the hook will fire your AppHook procedure. You can then check whether the call is a WM_CREATE message and also you can isolate the particular window being created: Private Function AppHook(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Dim CWP As CWPSTRUCT Dim k As Long, aClass As String If idHook >= 0 Then CopyMemory CWP, ByVal lParam, Len(CWP) Select Case CWP.message Case WM_CREATE aClass = Space$(128) k = GetClassName(CWP.hwnd, ByVal aClass, 128) aClass = Left$(aClass, k) If IsIn(aClass, C_MDIFORMCLASS_IDE, C_MDIFORMCLASS_EXE, C_MDIFORMCLASS5_IDE, _ C_MDIFORMCLASS5_EXE, C_FORMCLASS_IDE_DC, C_FORMCLASS_EXE_DC, C_FORMCLASS_IDE, _ C_FORMCLASS_EXE, C_FORMCLASS5_IDE, C_FORMCLASS5_EXE) Then m_lHookWndProc = SetWindowLong(CWP.hwnd, GWL_WNDPROC, AddressOf Form_WndProc) End If End Select End If AppHook = CallNextHookEx(m_hHook, idHook, wParam, ByVal lParam) End Function The constants listed above specify all the various class names that VB gives to a form for VB5 and VB6 - and there's a lot of them! (Thanks to Geoff Glaze for his assistance with this): Private Const C_MDIFORMCLASS_IDE = "ThunderMDIForm" Private Const C_MDIFORMCLASS_EXE = "ThunderRT6MDIForm" Private Const C_MDIFORMCLASS5_IDE = "ThunderMDIForm" Private Const C_MDIFORMCLASS5_EXE = "ThunderRT5MDIForm" Private Const C_FORMCLASS_IDE_DC = "ThunderFormDC" Private Const C_FORMCLASS_EXE_DC = "ThunderRT6FormDC" Private Const C_FORMCLASS_IDE = "ThunderForm" Private Const C_FORMCLASS_EXE = "ThunderRT6Form" Private Const C_FORMCLASS5_IDE = "ThunderForm" Private Const C_FORMCLASS5_EXE = "ThunderRT5Form" You will see that in the above function, I set a new Window Procedure to subclass the window in response to the WM_CREATE message. Why? Well, there is a problem with calling code in response to WH_CALLWNDPROC events. If you do anything during a WH_CALLWNDPROC hook notification which would call the window procedure of that window again, then VB crashes. This rules out a lot - for example, you can't change the style of the window, and so forth. To get around this problem, you can use the hook notification to install a temporary subclass on the window to capture exactly the same message again - and then you can make as many modifications as you wish. So finally I respond to the WM_CREATE message in a subclass procedure. As you will see, I just change the Extended Style of the form using SetWindowLong and by modifying the Window's creation data, plus I know I no longer need the subclass so I can reinstall the original version: Private Function Form_WndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Dim lSetStyleEX As Long ' SPM - specific wnd proc for a form. Only called once for the WM_CREATE message. Select Case Msg Case WM_CREATE Dim tCS As CREATESTRUCT CopyMemory tCS, ByVal lParam, Len(tCS) lSetStyleEX = GetWindowLong(hwnd, GWL_EXSTYLE) lSetStyleEX = lSetStyleEX Or WS_EX_APPWINDOW lSetStyleEX = lSetStyleEX And (Not WS_EX_TOOLWINDOW) tCS.ExStyle = lSetStyleEX CopyMemory ByVal lParam, tCS, Len(tCS) SetWindowLong hwnd, GWL_WNDPROC, m_lHookWndProc SetWindowLong hwnd, GWL_EXSTYLE, tCS.ExStyle End Select Form_WndProc = CallWindowProc(m_lHookWndProc, hwnd, Msg, wParam, lParam) End Function In Code - In Practice In the download sample the code is all wrapped up into a single module, modStyles. All you have to do to make this work is call HookAttach from the Form_Initialise event and then call HookDetach sometime later (I use the Form_Load event because I know this fires after the window has been created). There are a whole load of other possible uses of this code. Matt Hart has demonstrated how you can use this technique to modify the style of a VB control as it is created, for example, to create an Owner Draw Combo Box and an Owner Draw Tab. Have fun! Back to top Back to Source Code Overview |
  |
![]() |
|
About Contribute Send Feedback Privacy
|