1

I'm creating a custom progress bar with a property

Public Class CustomProgressBar : Inherits ProgressBar

    Private _State As ProgressStates

    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As Int32
    End Function

    <Category("Appearance")> _
    <DefaultValue(ProgressStates.Normal)> _
    <Description("The progress state, Red=Error, Yellow=Warning, Green=Normal")> _
    Public Property State As ProgressStates
        Get
            Return _State
        End Get
        Set(value As ProgressStates)
            _State = value
            SendMessage(MyBase.Handle, 1040, value, 0)
        End Set
    End Property

End Class

ProgressStates

Public Enum ProgressStates

    Normal = 1
    [Error] = 2
    Warning = 3

End Enum

In the designer I set my custom property to Error and it works fine (in the designer), but when I run my application, progress value sets automatically to 0 and property is not applied

Designer and executable

Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • The way in which you are using `SendMessage` is unnecessarily confusing. You should better rely on the constant name which is expected to be used here, that is: `PBM_SETSTATE` (https://msdn.microsoft.com/en-us/library/windows/desktop/bb760850(v=vs.85).aspx). Also, it would be clearer to use the usual format for `IntPtr`, that is: rather than `1040`, `&H400 + 16`. – varocarbas Oct 30 '15 at 08:56

1 Answers1

2

It has nothing to do with the Property exactly, but the PInvoke is imperfect either in the source or your conversion. I suspect you started with this old C# answer.

Imports System.Runtime.InteropServices
Class NativeMethods
    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=False)>
    Private Shared Function SendMessage(hWnd As IntPtr,
                                        Msg As UInt32,
                                        w As IntPtr,
                                        l As IntPtr) As IntPtr
    End Function

    Private Const PBM_SETSTATE = &H400 + 16
    Friend Enum PBMStates
        Normal = 1
        [Error] = 2
        Paused = 3
    End Enum

    Friend Shared Sub SetProgressState(ctl As ProgressBar, state As PBMStates)
        SendMessage(ctl.Handle, PBM_SETSTATE, New IntPtr(state), IntPtr.Zero)
    End Sub
End Class

According to the MSDN docs, PBM_SETSTATE returns the previous state. I've ignored that and made it a Sub. Since it only is supposed to be used with a ProgressBar I it to accept only a ProgressBar control rather than a control handle (which could be from any control). Finally, the code is Shared and in a NativeMethods class so CA will not complain. Usage:

NativeMethods.SetProgressState(ProgressBar1, NativeMethods.PBMStates.Error)

Result:

enter image description here

Community
  • 1
  • 1
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • I believe the trouble is calling to sendmessage before load the form, because I tried to use the snippet on `Load` event of form and it worked correctly, but when I send the message in my custom control, it is applied before load, Is there some override sub like `onCreateControl()`, but after form load? –  Nov 15 '15 at 20:44
  • You cant call it before the form loads - there is no handle for it before that. Is it a UserControl? *In* the load event should work – Ňɏssa Pøngjǣrdenlarp Nov 15 '15 at 20:58
  • I just tested it in Form Load and after it has been shown and it works fine both places. More info would be needed on what the control is etc – Ňɏssa Pøngjǣrdenlarp Nov 15 '15 at 21:05
  • ----------------ENDING COMMENT CONVERSATION AND START ANOTHER ONE--------------------------------------- –  Nov 19 '15 at 18:33
  • The problem is not the property, the problem is the moment that sendmessage is invoked because progress animation has to end before send a message SETSTATE –  Nov 19 '15 at 18:34
  • The color wont change until it stops animating (and only Green animates), but once it finishes, the state changes - windows stacks up messages, it doesnt throw them away. The *original* problem - the value being goofed up - was a result of the bad PInvoke. Are you calling this in very rapid succession, constantly changing the state? – Ňɏssa Pøngjǣrdenlarp Nov 19 '15 at 19:29
  • Is there some overrides sub like this "onAnimationEnd()"? If I set the progress value before calling to my property, it not works –  Nov 19 '15 at 19:38
  • I just did that in a loop and the color wont change until it is done (too many paints too often), but when it is done, the state is set. Again, `Are you calling this in very rapid succession`? and what does "it not works" mean? is it throwing away the value like originally? – Ňɏssa Pøngjǣrdenlarp Nov 19 '15 at 19:45