tags:

views:

82

answers:

1

I support a .Net 2.0 Windows application that has a custom listview control to allow for greater flexibility. I am not allowed to bring this to a newer version of the gramework until next year. We are moving from XP to Windows 7, and we have identified an issue with how the column sort image (up/down arrow) is drawn to the listview. Currently in XP, the image is drawn to the right of the column's text. However, in Windows 7, I am getting Access Violation Exceptions. Now, I know that the error is with the improper handling of memory using the unmanaged code as shown below. I am looking for a method to mimic what we have below in a safe manner using managed code.

Public Shared Sub ColumnImageToRight(ByVal view As ListView, ByVal index As Integer)
        Dim LVM_GETCOLUMNW As Integer = &H1000 + 95
        Dim LVM_SETCOLUMNW As Integer = &H1000 + 96
        If Not view.IsHandleCreated Then
            Throw New InvalidOperationException("ListView not yet created, wait...")
        End If
        If index >= view.Columns.Count Then
            Throw New ArgumentOutOfRangeException("Column index out of range")
        End If
        Dim buf As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(GetType(LVCOLUMN)))
        Dim lvc As New LVCOLUMN()
        lvc.mask = &HFFFF
        Marshal.StructureToPtr(lvc, buf, False)
        Dim retval As IntPtr = SendMessageW(view.Handle, LVM_GETCOLUMNW, CType(index, IntPtr), buf)
        lvc = CType(Marshal.PtrToStructure(buf, GetType(LVCOLUMN)), LVCOLUMN)
        lvc.fmt = lvc.fmt Or &H1000
        Marshal.StructureToPtr(lvc, buf, False)
        retval = SendMessageW(view.Handle, LVM_SETCOLUMNW, CType(index, IntPtr), buf)
        Marshal.FreeHGlobal(lvc.pszText)
        Marshal.FreeHGlobal(buf)
    End Sub
A: 

I was able to migrate from the unmanaged code to managed code with the methods below:

Private Sub ListViewEx_DrawColumnHeader(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewColumnHeaderEventArgs) Handles Me.DrawColumnHeader
    Dim lcIcon As Drawing.Image = Nothing
    If miSelectedColumn = e.ColumnIndex Then
        Select Case Me.Sorting
            Case SortOrder.Ascending
                lcIcon = Me.SmallImageList.Images(EnumSortImageKeys.Ascending)
            Case SortOrder.Descending
                lcIcon = Me.SmallImageList.Images(EnumSortImageKeys.Descending)
            Case SortOrder.None
                'Don't Do Anything
        End Select
    End If
    If lcIcon IsNot Nothing Then
        Dim liMargin As Integer = 4
        Dim x, y As Integer
        e.DrawBackground()

        Dim lcFontSize As Drawing.SizeF = e.Graphics.MeasureString(e.Header.Text, e.Font)
        x = CInt(lcFontSize.Width + e.Bounds.Left + (liMargin * 2))
        y = CInt((e.Bounds.Height / 2) - (lcIcon.Height / 2))

        Dim lsText As String = e.Header.Text
        If lcFontSize.Width + lcIcon.Width + liMargin > e.Bounds.Width Then
            Dim liCharWidth As Integer = CInt(lcFontSize.Width / lsText.Length)
            Dim liLength As Integer = CInt((e.Bounds.Width - (liMargin + lcIcon.Width)) / liCharWidth)

            lsText = lsText.Substring(0, liLength)

            lcFontSize = e.Graphics.MeasureString(lsText, e.Font)
            x = CInt(lcFontSize.Width + e.Bounds.Left + liMargin)
            y = CInt((e.Bounds.Height / 2) - (lcIcon.Height / 2))
            liMargin = CInt(liMargin / 2)
        End If

        e.Graphics.DrawString(lsText, e.Font, Drawing.Brushes.Black, e.Bounds.Left + liMargin, CSng((e.Bounds.Height / 2) - (lcFontSize.Height / 2)))
        e.Graphics.DrawImageUnscaled(lcIcon, x, y)
    Else
        e.DrawDefault = True
    End If
End Sub

Private Sub lv_DrawItem(ByVal view As Object, ByVal e As System.Windows.Forms.DrawListViewItemEventArgs) Handles Me.DrawItem
    e.DrawDefault = True
End Sub
websch01ar