views:

194

answers:

1

I am not sure if anyone can help with this, but I inhertied this code and I have no idea what the issue is nor am I familiar with the WndProc method. The area that is not running is the "' check for custom draw message" section. I need it to run the ProcessListCustomDraw(m) method so some thumbnails are generated. I beleive the origianl application was wirtten for .Net 1.1, so I may be SOL. Any ideas or thoughts would be greatly appreciated.

<SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
    Protected Overrides Sub WndProc(ByRef m As Message)
        Try

            If m.Msg = Win32.Consts.WM_NCPAINT Then
                ' always repaint background if get wm_ncpaint
                _backgroundDirty = True
            End If

            If m.Msg = Win32.Consts.WM_ERASEBKGND Then
                ' see if should repaint the background or not
                If ProcessBackground() = False Then Return
            End If

            ' look for messages to owner draw the listview items
            If m.Msg = Win32.Consts.OCM_NOTIFY Then
                ' get the notification info
                Dim notifyHeader As Win32.NMHDR = _
                 CType(m.GetLParam(GetType(Win32.NMHDR)), Win32.NMHDR)

                ' turn off background painting when get the item changed message
                If notifyHeader.code = Win32.Consts.LVN_ITEMCHANGED Then
                    _paintBackground = False
                End If

                ' check for custom draw message
                If notifyHeader.hwndFrom.Equals(Me.Handle) And _
                 notifyHeader.code = Win32.Consts.NM_CUSTOMDRAW Then
                    _paintBackground = True

                    ' process the message, returns true if performed custom
                    ' drawing, otherwise false
                    If ProcessListCustomDraw(m) Then
                        Return
                    End If
                End If
            End If

            MyBase.WndProc(m)

        Catch ex As Exception

            Log.WriteLog(Log.SZ_LOG_EXCEPTION & MethodBase.GetCurrentMethod().Name & " " & ex.Message)

        End Try

    End Sub

' one step closer to detecting if a listview item should be drawn
    ' return true if the listview item was drawn
    Private Function ProcessListCustomDraw(ByRef m As Message) As Boolean
        Try
            ' return true if performed custom drawing
            Dim drawSelf As Boolean = False

            ' get custom draw information
            Dim customDraw As Win32.NMCUSTOMDRAW = _
             CType(m.GetLParam(GetType(Win32.NMCUSTOMDRAW)), Win32.NMCUSTOMDRAW)

            ' return different values in the message depending on the draw stage
            Select Case customDraw.dwDrawStage
                Case Win32.Consts.CDDS_PREPAINT
                    m.Result = New System.IntPtr(Win32.Consts.CDRF_NOTIFYITEMDRAW)

                Case Win32.Consts.CDDS_ITEMPREPAINT
                    m.Result = New System.IntPtr(Win32.Consts.CDRF_SKIPDEFAULT)

                    If IsItemVisible(customDraw.dwItemSpec) Then
                        ' finally, draw the listview item
                        Dim g As Graphics = Graphics.FromHdc(customDraw.hdc)
                        Try
                            DrawItemEg(g, CInt(customDraw.dwItemSpec))
                            drawSelf = True
                        Finally
                            g.Dispose()
                        End Try
                    Else
                        drawSelf = True
                    End If

                Case Else
                    m.Result = New System.IntPtr(Win32.Consts.CDRF_DODEFAULT)
            End Select


            Return drawSelf

        Catch ex As Exception

            Log.WriteLog(Log.SZ_LOG_EXCEPTION & MethodBase.GetCurrentMethod().Name & " " & ex.Message)

        End Try

    End Function

Update: Here is the Win32 Class:

' win32 values
Private Class Win32
    Public Enum Consts
        ' messages
        WM_NCPAINT = &H85
        WM_ERASEBKGND = &H14
        WM_NOTIFY = &H4E
        OCM_BASE = &H2000
        OCM_NOTIFY = OCM_BASE + WM_NOTIFY
        NM_CUSTOMDRAW = -12
        NM_SETFOCUS = -7
        LVN_ITEMCHANGED = -101

        ' custom draw return flags
        CDRF_DODEFAULT = &H0
        CDRF_SKIPDEFAULT = &H4
        CDRF_NOTIFYITEMDRAW = &H20

        ' custom draw state flags
        CDDS_PREPAINT = &H1
        CDDS_ITEM = &H10000
        CDDS_ITEMPREPAINT = CDDS_ITEM Or CDDS_PREPAINT
    End Enum

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure NMHDR
        Public hwndFrom As IntPtr
        Public idFrom As Integer
        Public code As Integer
    End Structure

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

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure NMCUSTOMDRAW
        Public hdr As NMHDR
        Public dwDrawStage As Integer
        Public hdc As IntPtr
        Public rc As RECT
        Public dwItemSpec As Integer
        Public uItemState As Integer
        Public lItemlParam As IntPtr
    End Structure
End Class
+1  A: 

If it works on x86 then your P/Invoke declarations are probably wrong. Using Integer where IntPtr is required, something like that. You didn't post them, I can't tell. Visit pinvoke.net to get the right ones.


After seeing your edit: yes, your NMHDR declaration is wrong. It must look like this:

<StructLayout(LayoutKind.Sequential)> _
Public Structure NMHDR
    Public hwndFrom As IntPtr
    Public idFrom As IntPtr              ' NOT INTEGER!!!
    Public code As Integer
End Structure
Hans Passant
What do you mean? See, the ProcessListCustomDraw never gets called. the lines: "If notifyHeader.hwndFrom.Equals(Me.Handle) And _ notifyHeader.code = Win32.Consts.NM_CUSTOMDRAW Then".. the notifyHeader.code is always 0 and the Win32.Consts.NM_CUSTOMDRAW is -12.
DDiVita
Yes, your NMHDR declaration is probably wrong. The idFrom field is IntPtr, not Integer.
Hans Passant
I updated the post so you could see the Win32 Class.
DDiVita
Just as I guessed, your NMHDR.idFrom field is not IntPtr.
Hans Passant
That fixed that issue (Thanks!!!!!), but now, the Select Case customDraw.dwDrawStage is always 1. And the strange thing is I can't see the value of dwDrawStage until I pass the Select statement when debugging. So, when the object gets instantiated all the values are 0 in the customDraw object until I pass the breakpoint I have at the Select Case customDraw.dwDrawStage. The dwDrawStage value never is the same as Win32.Consts.CDDS_ITEMPREPAINT value
DDiVita
I dunno, I can't see what you see. If you want me to take a look at it you'll need to put a repro project on a file sharing service.
Hans Passant