开发者

TBPF_INDETERMINATE status has no effect in .NET 2.0 on Windows 7 taskbar

I have a very weird problem. I have a VB.NET 2.0 application that takes advantage of Windows 7 taskbar button progress features, i.e. displaying certain progress and application state in the Win7 taskbar button.

Everything works just fine - I can set and update progress, I can set the button to paused or ewrror state, I can set it to No progress. Everything works, except MARQUE (Indeterminate) mode. This is a total mistery, whenever I set state to TBPF_INDETERMINATE (value of 0x1), it simply changes back to NOPROGRESS type, i.e. it removes all progress inidcation from the taskbar button and sets it back to its default state - no animated marque is ever displayed!

I have read documentation on MSDN - http://msdn.microsoft.com/en-us/library/dd391697(v=vs.85).aspx ; tried various combinations like setting progress to 0 and then calling set state to indeterminate; or like setting it to normal first and then to indeterminate - nothing works. It's a total mistery - and there is no clue in the documentation as to why it is failing...

Here's the code: The API implementation:

    <StructLayout(LayoutKind.Sequential)> _
Public Structure RECT
    Public left As Integer
    Public top As Integer
    Public right As Integer
    Public bottom As Integer

    Public Sub New(left As Integer, top As Integer, right As Integer, bottom As Integer)
        Me.left = left
        Me.top = top
        Me.right = right
        Me.bottom = bottom
    End Sub
End Structure

Public Enum TBPFLAG
    TBPF_NOPROGRESS = 0
    TBPF_INDETERMINATE = &H1
    TBPF_NORMAL = &H2
    TBPF_ERROR = &H4
    TBPF_PAUSED = &H8
End Enum

Public Enum TBATFLAG
    TBATF_USEMDITHUMBNAIL = &H1
    TBATF_USEMDILIVEPREVIEW = &H2
End Enum

Public Enum THBMASK
    THB_BITMAP = &H1
    THB_ICON = &H2
    THB_TOOLTIP = &H4
    THB_FLAGS = &H8
E开发者_JAVA技巧nd Enum

Public Enum THBFLAGS
    THBF_ENABLED = 0
    THBF_DISABLED = &H1
    THBF_DISMISSONCLICK = &H2
    THBF_NOBACKGROUND = &H4
    THBF_HIDDEN = &H8
End Enum

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Structure THUMBBUTTON
    <MarshalAs(UnmanagedType.U4)> _
    Public dwMask As THBMASK
    Public iId As UInteger
    Public iBitmap As UInteger
    Public hIcon As IntPtr
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> _
    Public szTip As String
    <MarshalAs(UnmanagedType.U4)> _
    Public dwFlags As THBFLAGS
End Structure

<ComImportAttribute()> _
<GuidAttribute("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")> _
<InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface ITaskbarList3
    ' ITaskbarList
    <PreserveSig()> _
    Sub HrInit()
    <PreserveSig()> _
    Sub AddTab(hwnd As IntPtr)
    <PreserveSig()> _
    Sub DeleteTab(hwnd As IntPtr)
    <PreserveSig()> _
    Sub ActivateTab(hwnd As IntPtr)
    <PreserveSig()> _
    Sub SetActiveAlt(hwnd As IntPtr)

    ' ITaskbarList2
    <PreserveSig()> _
    Sub MarkFullscreenWindow(hwnd As IntPtr, <MarshalAs(UnmanagedType.Bool)> fFullscreen As Boolean)

    ' ITaskbarList3
    Sub SetProgressValue(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByVal ullCompleted As UInt64, <[In]()> ByVal ullTotal As UInt64) 'hwnd As IntPtr, ullCompleted As UInt64, ullTotal As UInt64)
    Sub SetProgressState(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByVal tbpFlags As TBPFLAG) 'hwnd As IntPtr, tbpFlags As TBPFLAG) 'As Integer
    Sub RegisterTab(hwndTab As IntPtr, hwndMDI As IntPtr)
    Sub UnregisterTab(hwndTab As IntPtr)
    Sub SetTabOrder(hwndTab As IntPtr, hwndInsertBefore As IntPtr)
    Sub SetTabActive(hwndTab As IntPtr, hwndMDI As IntPtr, tbatFlags As TBATFLAG)
    Sub ThumbBarAddButtons(hwnd As IntPtr, cButtons As UInteger, <MarshalAs(UnmanagedType.LPArray)> pButtons As THUMBBUTTON())
    Sub ThumbBarUpdateButtons(hwnd As IntPtr, cButtons As UInteger, <MarshalAs(UnmanagedType.LPArray)> pButtons As THUMBBUTTON())
    Sub ThumbBarSetImageList(hwnd As IntPtr, himl As IntPtr)
    Sub SetOverlayIcon(hwnd As IntPtr, hIcon As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> pszDescription As String)
    Sub SetThumbnailTooltip(hwnd As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> pszTip As String)
    '[MarshalAs(UnmanagedType.LPStruct)]
    Sub SetThumbnailClip(hwnd As IntPtr, ByRef prcClip As RECT)
End Interface

<GuidAttribute("56FDF344-FD6D-11d0-958A-006097C9A090")> _
<ClassInterfaceAttribute(ClassInterfaceType.None)> _
<ComImportAttribute()> _
Public Class CTaskbarList
End Class

And here are the actual procedures that use the code:

 Friend Sub SetWindows7Progress(ByVal aValue As Integer)
        If Not IsWin7orLater Then Exit Sub
            If w7tb Is Nothing Then
                w7tb = CType(New CTaskbarList, ITaskbarList3)
            End If
            CType(w7tb, ITaskbarList3).SetProgressValue(My.Forms.Form1.Handle, Math.Min(Math.Max(1, aValue), 1000), 1000)
 End Sub

    Friend Sub ResetWindows7Progress()
        If Not IsWin7orLater Then Exit Sub
            If w7tb Is Nothing Then
                w7tb = CType(New CTaskbarList, ITaskbarList3)
            End If
            CType(w7tb, ITaskbarList3).SetProgressState(My.Forms.Form1.Handle, TBPFLAG.TBPF_NOPROGRESS)
    End Sub

    Friend Sub SetWindows7ProgressMon()
        If Not IsWin7orLater Then Exit Sub
            If w7tb Is Nothing Then
                w7tb = CType(New CTaskbarList, ITaskbarList3)
            End If
            CType(w7tb, ITaskbarList3).SetProgressState(My.Forms.Form1.Handle, TBPF_INDETERMINATE)
    End Sub

I even tried getting the HRESULT code from SetProgressState and checking to make sure no exception is thrown to no avail: SetProgressState always returns 0 (everything is fine); and no exceptions are thrown!

Any help in resolving the matter would be greatly appreciated! I just can't believe that everything works except the MARQUE/INDETERMINATE state!

Thanks.


First, it's very strange that your worker functions are accessing your form's instance using this code:

 My.Forms.Form1.Handle

That implies that those functions are not defined in the same class as your form (because if they were, the compiler would prompt you to use Me, instead). And if that's the case, you really should be passing the handle to the form into the function as a parameter.

(The reason for this is so that your functions are reusable. If you hardcode a reference to a particular form, what happens when you rename that form, or display two instances of it on the screen at a time, or just want to show a progress indicator in the taskbar for a different form? Things break. Passing the form instance as a parameter is a much cleaner, more reusable approach.)

Second, there seems like an unnecessary amount of casting going on. Why not just declare the w7tb variable as type ITaskbarList3 in the first place, rather than casting back and forth between that and CTaskbarList?

Third, I'm not sure if this is a typo or the actual problem, but your SetWindows7ProgressMon function does not actually reference the correct value for TBPF_INDETERMINATE. You use an unqualified reference to that identifier, when it's actually defined in the TBPFLAG enumeration.

So, considering all of the above, I would rewrite the second block of code that you posted as follows:

Private w7tb As ITaskbarList3

Friend Sub SetWindows7Progress(ByVal frm As Form, ByVal aValue As Integer)
    If (Not IsWin7orLater()) OrElse (frm Is Nothing) Then
        Exit Sub
    End If

    If w7tb Is Nothing Then
        w7tb = CType(New CTaskbarList, ITaskbarList3)
    End If
    w7tb.SetProgressValue(frm.Handle, Math.Min(Math.Max(1, aValue), 1000), 1000)
End Sub

Friend Sub ResetWindows7Progress(ByVal frm As Form)
    If (Not IsWin7orLater()) OrElse (frm Is Nothing) Then
        Exit Sub
    End If

    If w7tb Is Nothing Then
        w7tb = CType(New CTaskbarList, ITaskbarList3)
    End If
    w7tb.SetProgressState(frm.Handle, TBPFLAG.TBPF_NOPROGRESS)
End Sub

Friend Sub SetWindows7ProgressMon(ByVal frm As Form)
    If (Not IsWin7orLater()) OrElse (frm Is Nothing) Then
       Exit Sub
    End If

    If w7tb Is Nothing Then
        w7tb = CType(New CTaskbarList, ITaskbarList3)
    End If
    w7tb.SetProgressState(frm.Handle, TBPFLAG.TBPF_INDETERMINATE)
End Sub

This is tested to work perfectly on Windows 7 32-bit. Note that you can call the functions from code inside of your form class by simply specifying Me for the frm parameter.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜