# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  Preventing certain Listview columns from sizing...

## Aaron Young

Took a little while, but figured it out.  
You can do it by subclassing the Listview and intercepting the 
*HDN_BEGINTRACK* Header Notification Message.  
In this example, I've set it up so that any column with a width of 0 _(Zero)_ is deemed not sizable.

*In a Standard Module:*
VB Code:
Option Explicit
 ' GetWindowsLong Constants
Private Const GWL_WNDPROC = (-4)
 ' Windows Message Constants
Private Const WM_NOTIFY = &H4E
Private Const WM_DESTROY = &H2
 ' Column Header Notification Meassage Constants
Private Const HDN_FIRST = -300&
Private Const HDN_BEGINTRACK = (HDN_FIRST - 6)
 ' Column Header Item Info Message Constants
Private Const HDI_WIDTH = &H1
 ' Notify Message Header Type
Private Type NMHDR
   hWndFrom As Long
   idFrom As Long
   code As Long
End Type
 ' Notify Message Header for Listview
Private Type NMHEADER
     hdr As NMHDR
     iItem As Long
     iButton As Long
     lPtrHDItem As Long ' HDITEM FAR* pItem
End Type
 ' Header Item Type
Private Type HDITEM
    mask As Long
    cxy As Long
    pszText As Long
    hbm As Long
    cchTextMax As Long
    fmt As Long
    lParam As Long
    iImage As Long
    iOrder As Long
End Type
 Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
 Private mlPrevWndProc As Long
 Private Function WindowProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim tNMH As NMHDR
    Dim tNMHEADER As NMHEADER
    Dim tITEM As HDITEM
    
    Select Case Msg
    Case WM_NOTIFY
        ' Copy the Notify Message Header to a Header Structure
        CopyMemory tNMH, ByVal lParam, Len(tNMH)
       
        Select Case tNMH.code
        Case HDN_BEGINTRACK
            ' If the user is trying to Size a Column Header...
            
            ' Extract Information about the Header being Sized
            CopyMemory tNMHEADER, ByVal lParam, Len(tNMHEADER)
            
            ' Get Item Info. about the header (i.e. Width)
            CopyMemory tITEM, ByVal tNMHEADER.lPtrHDItem, Len(tITEM)
            
            ' Don't allow Zero Width Columns to be Sized.
            If (tITEM.mask And HDI_WIDTH) = HDI_WIDTH And tITEM.cxy = 0 Then
                WindowProc = 1
                Exit Function
            End If
        End Select
       
    Case WM_DESTROY
        ' Remove Subclassing when Listview is Destroyed (Form unloaded.)
        WindowProc = CallWindowProc(mlPrevWndProc, hWnd, Msg, wParam, lParam)
        Call SetWindowLong(hWnd, GWL_WNDPROC, mlPrevWndProc)
        Exit Function
         
    End Select
     ' Call Default Window Handler
    WindowProc = CallWindowProc(mlPrevWndProc, hWnd, Msg, wParam, lParam)
End Function
 Public Sub SubClassHwnd(ByVal hWnd As Long)
    mlPrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub
*In Form with ListView:*
VB Code:
Option Explicit
 Private Sub Form_Load()
    Dim lIndex As Long
    
    SubClassHwnd ListView1.hWnd
    
    With ListView1
        .View = lvwReport
        For lIndex = 1 To 5
            .ColumnHeaders.Add , "COL" & lIndex, "Column " & lIndex, IIf(lIndex = 3, 0, (.Width - 200) / 4)
        Next
    End With
 End Sub

----------


## crptcblade

Holy crap that's cool!

Thanks a lot Aaron.

 :Smilie:

----------


## rjlohan

Nice one!
:thumbsup:

 :Smilie:

----------


## MartinLiss

Amen to the above compliments. Can the code be modified so that the cursor doesn't change to the double-bar form?

----------


## crptcblade

I would imagine that catching WM_SETCURSOR, or something similar, would accomplish that.  Never really looked into it though.

 :Smilie:

----------


## baja_yu

Can this be modified to prevent resize of non zero width columns? Like some other fixed value...

----------


## DiGiTaIErRoR

Nice code, I can already see uses for it in one appliacation of mine.

One thing, shouldn't those len()'s be LenB()'s, just to be safe.

----------


## crptcblade

> _Originally posted by baja_yu_ 
> *Can this be modified to prevent resize of non zero width columns? Like some other fixed value...*


Yes

VB Code:
' Don't allow Zero Width Columns to be Sized.
            If (tITEM.mask And HDI_WIDTH) = HDI_WIDTH And tITEM.cxy = 0 Then

Change that from 0 to whatever you want.

----------


## baja_yu

> _Originally posted by crptcblade_ 
> *Yes
> 
> VB Code:
> ' Don't allow Zero Width Columns to be Sized.
            If (tITEM.mask And HDI_WIDTH) = HDI_WIDTH And tITEM.cxy = 0 Then
> 
> Change that from 0 to whatever you want.*


No....that didnt work... The first column is 350...so I tried that... nothing.....then I noticed that it made it's size 349.79....tried that...nothing..... then I made a messagebox write the width....and it said 349.7953...... tried that and nothing...

----------


## MartinLiss

How about < 350 instead of = 0?

----------


## baja_yu

Tired that too.... then all columns get locked for resizing and I cant resize any of them....
And I dont understand this because all of them, except the first one, are way wider than 350....

----------


## MartinLiss

I don't have the code in front of me so it's hard to tell from here waht's going on but when you try to resize the column, does this line execute?

If (tITEM.mask And HDI_WIDTH) = HDI_WIDTH And tITEM.cxy = 0 Then

If so then set a breakpoint on that line and see what each of the variables contain and let me know.

----------


## baja_yu

Martin, I followed your idea and found that 

tITEM.mask = 1
HDI_WIDTH = 1

but 

tITEM.cxy = 23

even if the width is 350 .... so I set the limit to 23...
and now it works like I want it to...

But the readings are kinda odd... maybe it is in twips and not in pixels..

----------


## RobDog888

I was surprised to see this old thread back on top.

Here is Aaron's code that I had modified a while ago to prevent 
the resizing of certain columns and prevents the double-click auto-
resize column width when the user tries to position the mouse 
between column headers for a resize.
Also, I added code to keep certain columns a certain fixed width.
The "tITEM.cxy = 60" is a different measurement unit - twips I believe.
If you were to double-click a column with aarons code on a zero 
width column, you would be able to open it up if it had anything 
in it.

VB Code:
Private Function WindowProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Dim tNMH As NMHDR
    Dim tNMHEADER As NMHEADER
    Dim tITEM As HDITEM
    
    Select Case Msg
        Case WM_NOTIFY
            ' COPY THE NOTIFY MESSAGE HEADER TO A HEADER STRUCTURE
            CopyMemory tNMH, ByVal lParam, Len(tNMH)
            Select Case tNMH.code
                Case HDN_DIVIDERDBLCLICKA
                    'IF THE USER IS TRYING TO DOUBLECLICK A COLUMN HEADER...
                    'EXTRACT INFORMATION ABOUT THE HEADER BEING SIZED
                    CopyMemory tNMHEADER, ByVal lParam, Len(tNMHEADER)
                    'GET THE INFO ABOUT THE HEADER (IE. INDEX#)
                    'DONT ALLOW COLUMNS 1 OR 2 TO BE DOUBLECLICKED
                    If (tNMHEADER.iItem < 3) = True Then
                        WindowProc = 1
                        Exit Function
                    ElseIf (tNMHEADER.iItem = 5) = True Then 'DURATION
                        WindowProc = 1
                        Exit Function
                    End If
                Case HDN_BEGINTRACK
                    'IF THE USER IS TRYING TO SIZE A COLUMN HEADER...
                    'EXTRACT INFORMATION ABOUT THE HEADER BEING SIZED
                    CopyMemory tNMHEADER, ByVal lParam, Len(tNMHEADER)
                    'GET THE INFO ABOUT THE HEADER (IE. WIDTH)
                    CopyMemory tITEM, ByVal tNMHEADER.lPtrHDItem, Len(tITEM)
                    'DONT ALLOW ZERO OR COLUMNS 1 OR 2 TO BE SIZED
                    If (tNMHEADER.iItem < 3) = True Then 'TYPE & STATUS
                        WindowProc = 1
                        Exit Function
                    ElseIf (tNMHEADER.iItem = 5) = True Then 'DURATION
                        'If (tITEM.mask And HDI_WIDTH) = HDI_WIDTH And tITEM.cxy = 27 Then
                            WindowProc = 1
                            Exit Function
                        'End If
                    End If
            End Select
        Case WM_DESTROY
            'REMOVE SUBCLASSING WHEN LISTVIEW IS DESTROYED (FORM UNLOADED)
            WindowProc = CallWindowProc(mlPrevWndProc, hWnd, Msg, wParam, lParam)
            Call SetWindowLong(hWnd, GWL_WNDPROC, mlPrevWndProc)
            Exit Function
    End Select
    'CALL DEFAULT WINDOW HANDLER
    WindowProc = CallWindowProc(mlPrevWndProc, hWnd, Msg, wParam, lParam)
    
End Function

----------


## baja_yu

I am getting a variable not defined for: HDN_DIVIDERDBLCLICKA
And I think same will happen for HDN_BEGINTRACK
Also, I am guessing these are constants... what are their values?

----------


## RobDog888

I had only posted the change to the procedure from Aaron's 
code. You will need all his code from above and replace his 
WindowProc with mine. Also, here is the declaration for the const.

VB Code:
Private Const HDN_DIVIDERDBLCLICKA As Long = (HDN_FIRST-5)

----------


## baja_yu

Yeah, I know. And I still got the error...

Anyway, I added the definition, and it does prevent doubleclikc, but it also prevents resizing of all columns, not just the one I set the widt to 23 (I am using that width)...

Aarons code works, but I can do the doubleclick...

----------


## RobDog888

Thats because you needed to modify it for whatever columns you 
want to prevent the resize for. My example works and it works 
for columns 1,2, & 5. Not by width only column index number - 
base 1.

This could be part of the issue. I forgot to take it out from testing.
Comment like I have it.

VB Code:
'If (tITEM.mask And HDI_WIDTH) = HDI_WIDTH And tITEM.cxy = 27 Then
    WindowProc = 1
    Exit Function
'End If
Post your procedure so I can see whats wrong.

----------


## baja_yu

Didn't see that, sorry  :Blush:  

Anyway, it works more than great. Thumbs up to all  :Thumb:  

Thanks for the help.  :wave:

----------


## RobDog888

Glad to hear its working for you now.

I commented my code on my original post with the fix too.

----------


## InvisibleDuncan

Now all we need is a VB.Net version.  :Stick Out Tongue:

----------


## Rodik

Hey, how do we make this code "IDE-friendly"? So IDE doesn't crash every time one exits the program..

----------


## RobDog888

You need to close your app instead of stopping the code from the IDE.  :Smilie:

----------


## WarrenW

I tried Aaron's code above and I get an error saying "Invalid use of AddressOf operator".  Has anyone seen this before?

Thanks!

----------


## MartinLiss

I believe that that code needs to be in a code module rather than a form. How are you using it?

----------


## WarrenW

Yes, I stuck it in my main form.  I'll try it in a module instead and will reply back.

Thanks!

Warren

----------


## wittekat01

Hello to you all


A little late, I know, but I was just now looking for a way to prevent column on a listview from sizing. SO I found these messages. Thanks for it, but I noticed that it is still possible to resize the column after double-cllicking. Has anyone found this also and how did you fix that??

Thanks
Catharinus van der Werf
Leeuwarden, Holland

----------


## MartinLiss

I can't reproduce that problem. Can you zip up and attach your project?

----------


## wittekat01

Hier is de code:

Zet onderstaande in een module:


' GetWindowsLong Constants
Private Const GWL_WNDPROC = (-4)

' Windows Message Constants
Private Const WM_NOTIFY = &H4E
Private Const WM_DESTROY = &H2

' Column Header Notification Meassage Constants
Private Const HDN_FIRST = -300&
Private Const HDN_BEGINTRACK = (HDN_FIRST - 6)

' Column Header Item Info Message Constants
Private Const HDI_WIDTH = &H1

' Notify Message Header Type
Private Type NMHDR
hWndFrom As Long
idFrom As Long
code As Long
End Type

' Notify Message Header for Listview
Private Type NMHEADER
hdr As NMHDR
iItem As Long
iButton As Long
lPtrHDItem As Long ' HDITEM FAR* pItem
End Type

' Header Item Type
Private Type HDITEM
mask As Long
cxy As Long
pszText As Long
hbm As Long
cchTextMax As Long
fmt As Long
lParam As Long
iImage As Long
iOrder As Long
End Type

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private mlPrevWndProc As Long

Private Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Dim tNMH As NMHDR
Dim tNMHEADER As NMHEADER
Dim tITEM As HDITEM

Select Case Msg
Case WM_NOTIFY
' COPY THE NOTIFY MESSAGE HEADER TO A HEADER STRUCTURE
CopyMemory tNMH, ByVal lParam, Len(tNMH)
Select Case tNMH.code
Case HDN_DIVIDERDBLCLICKA
'IF THE USER IS TRYING TO DOUBLECLICK A COLUMN HEADER...
'EXTRACT INFORMATION ABOUT THE HEADER BEING SIZED
CopyMemory tNMHEADER, ByVal lParam, Len(tNMHEADER)
'GET THE INFO ABOUT THE HEADER (IE. INDEX#)
'DONT ALLOW COLUMNS 1 OR 2 TO BE DOUBLECLICKED
If (tNMHEADER.iItem < 9) = True Then '9 heb ik zelf ingevoerd als maximum kolom
WindowProc = 1
'Exit Function
'ElseIf (tNMHEADER.iItem = 5) = True Then 'DURATION
'WindowProc = 1
'Exit Function
End If
Case HDN_BEGINTRACK
'IF THE USER IS TRYING TO SIZE A COLUMN HEADER...
'EXTRACT INFORMATION ABOUT THE HEADER BEING SIZED
CopyMemory tNMHEADER, ByVal lParam, Len(tNMHEADER)
'GET THE INFO ABOUT THE HEADER (IE. WIDTH)
CopyMemory tITEM, ByVal tNMHEADER.lPtrHDItem, Len(tITEM)
'DONT ALLOW ZERO OR COLUMNS 1 OR 2 TO BE SIZED
If (tNMHEADER.iItem < 9) = True Then 'TYPE & STATUS'9 heb ik zelf ingevoerd als maximum kolom
WindowProc = 1
Exit Function
'ElseIf (tNMHEADER.iItem = 5) = True Then 'DURATION
''If (tITEM.mask And HDI_WIDTH) = HDI_WIDTH And tITEM.cxy = 27 Then
'WindowProc = 1
'Exit Function
'End If
End If
End Select
Case WM_DESTROY
'REMOVE SUBCLASSING WHEN LISTVIEW IS DESTROYED (FORM UNLOADED)
WindowProc = CallWindowProc(mlPrevWndProc, hwnd, Msg, wParam, lParam)
Call SetWindowLong(hwnd, GWL_WNDPROC, mlPrevWndProc)
Exit Function
End Select
'CALL DEFAULT WINDOW HANDLER
WindowProc = CallWindowProc(mlPrevWndProc, hwnd, Msg, wParam, lParam)

End Function

'-------------------------------------------------------------------------------

Public Sub SubClassHwnd(ByVal hwnd As Long)
mlPrevWndProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub



En zet onderstaande in de form_load:

   SubClassHwnd ListView1.hwnd

----------


## wittekat01

I hope you can read/understand my dutch remarks, otherwise:

Put the first piece of code in the module

Put the second piece of code (SubClassHwnd ListView1.hwnd) in
the form_load of a form.

Catharinus van der Werf
csvanderwerf@planet.nl
Leeuwarden, The Netherlands

----------


## MartinLiss

Please create a zip file from your project and attach it using the Manage Attachments function that you'll find below this window.

----------


## Chris001

Here's my version of the code for locking the columnheaders. HDN_BEGINTRACK used in the examples above didn't work for me, so I had to change it to HDN_BEGINTRACKA (MSCC 6.0) and HDN_BEGINTRACKW (MSCC 5.0).

Unfortunately I still haven't found a way to hide the double-arrow cursor when moving over a locked column divider. WM_SETCURSOR doesn't 'fire' when the cursor is moved over a column divider. 

::Edit::

An other 'problem' is that it's not possible to subclass more than one Listview at a time with the same code. You have to add multiple WindowProc with different names in order to do that. Although it's not a real problem, it would be easier to put the code in a Class and create a new instance for each Listview, but AddressOf only works for Modules and not Classes.


vb Code:
Option Explicit
 Private Type POINTAPI
  x             As Long
  y             As Long
End Type
 Private Type HD_HITTESTINFO
  PT            As POINTAPI
  flags         As Long
  iItem         As Long
End Type
 Private Const HHT_ONHEADER          As Long = &H2
Private Const HHT_ONDIVIDER         As Long = &H4
Private Const HDM_HITTEST           As Long = &H1206
 Private Const HDN_FIRST             As Long = (-300)
Private Const HDN_BEGINTRACKW       As Long = (HDN_FIRST - 26)
Private Const HDN_BEGINTRACKA       As Long = (HDN_FIRST - 6)
Private Const HDN_DIVIDERDBLCLICKW  As Long = (HDN_FIRST - 25)
Private Const HDN_DIVIDERDBLCLICKA  As Long = (HDN_FIRST - 5)
 ' GetWindowsLong Constants
Private Const GWL_WNDPROC = (-4)
 ' Windows Message Constants
Private Const WM_NOTIFY = &H4E
Private Const WM_DESTROY = &H2
Private Const WM_SETCURSOR = &H20
 ' Notify Message Header Type
Private Type NMHDR
   hWndFrom As Long
   idFrom As Long
   code As Long
End Type
 Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
 Private mlPrevWndProc As Long
 Private Function WindowProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim HitTestInfo     As HD_HITTESTINFO
    Dim PT              As POINTAPI
    
    Select Case Msg
    Case WM_NOTIFY
        Dim tNMH As NMHDR
        
        ' Copy the Notify Message Header to a Header Structure
        CopyMemory tNMH, ByVal lParam, Len(tNMH)
        
        Select Case tNMH.code
        Case HDN_BEGINTRACKW, HDN_BEGINTRACKA, HDN_DIVIDERDBLCLICKW, HDN_DIVIDERDBLCLICKA
            
            Call GetCursorPos(PT)
            Call ScreenToClient(tNMH.hWndFrom, PT)
            
            HitTestInfo.flags = HHT_ONHEADER Or HHT_ONDIVIDER
            HitTestInfo.PT = PT
             Call SendMessage(tNMH.hWndFrom, HDM_HITTEST, 0&, HitTestInfo)
             ' Lock column 1 (0) and column 2 (1)
            If HitTestInfo.iItem = 0 Or HitTestInfo.iItem = 1 Then
                Debug.Print "Sorry, I'm locked!"
                WindowProc = 1
                Exit Function
            End If
            
            Debug.Print "OK, you can move me."
        End Select
        
    Case WM_DESTROY
        ' Remove Subclassing when Listview is Destroyed (Form unloaded.)
        WindowProc = CallWindowProc(mlPrevWndProc, hwnd, Msg, wParam, lParam)
        Call SetWindowLong(hwnd, GWL_WNDPROC, mlPrevWndProc)
        Exit Function
         
    End Select
     ' Call Default Window Handler
    WindowProc = CallWindowProc(mlPrevWndProc, hwnd, Msg, wParam, lParam)
End Function
 Public Sub SubClassHwnd(ByVal hwnd As Long)
    mlPrevWndProc = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub

----------


## sergelac

there is a big problem with the column width version

if you resize a unlocked column to the specified size (0), it will become locked



i use a ParamArray to specify the column numbers so i can use it on all my forms


```
SubClassHwnd ListView1.hWnd, 7, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
```



```
Option Explicit
Option Base 0

' GetWindowsLong Constants
Private Const GWL_WNDPROC = (-4)

' Windows Message Constants
Private Const WM_NOTIFY = &H4E
Private Const WM_DESTROY = &H2

' Column Header Notification Meassage Constants
Private Const HDN_FIRST = -300&
Private Const HDN_DIVIDERDBLCLICKA = (HDN_FIRST - 5)
Private Const HDN_BEGINTRACK = (HDN_FIRST - 6)

' Column Header Item Info Message Constants
Private Const HDI_WIDTH = &H1

' Notify Message Header Type
Private Type NMHDR
   hWndFrom As Long
   idFrom As Long
   code As Long
End Type

' Notify Message Header for Listview
Private Type NMHEADER
     hdr As NMHDR
     iItem As Long
     iButton As Long
     lPtrHDItem As Long ' HDITEM FAR* pItem
End Type

' Header Item Type
Private Type HDITEM
    mask As Long
    cxy As Long
    pszText As Long
    hbm As Long
    cchTextMax As Long
    fmt As Long
    lParam As Long
    iImage As Long
    iOrder As Long
End Type

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Private mlPrevWndProc As Long, ColumnsBits As Long

Private Function WindowProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim tNMH As NMHDR
    Dim tNMHEADER As NMHEADER
    Dim tITEM As HDITEM
    
    Select Case Msg
    Case WM_NOTIFY
        ' Copy the Notify Message Header to a Header Structure
        CopyMemory tNMH, ByVal lParam, Len(tNMH)

        Select Case tNMH.code
        Case HDN_DIVIDERDBLCLICKA
            ' If the user is trying to DOUBLECLICK a Column Header
            ' Extract Information about the Header being Sized
            CopyMemory tNMHEADER, ByVal lParam, Len(tNMHEADER)

            ' Don't allow Columns to be Sized.
            If (ColumnsBits And (2 ^ tNMHEADER.iItem)) = (2 ^ tNMHEADER.iItem) Then
                WindowProc = 1
                Exit Function
            End If
        Case HDN_BEGINTRACK
            ' If the user is trying to Size a Column Header
            ' Extract Information about the Header being Sized
            CopyMemory tNMHEADER, ByVal lParam, Len(tNMHEADER)

            ' Don't allow Columns to be Sized.
            If (ColumnsBits And (2 ^ tNMHEADER.iItem)) = (2 ^ tNMHEADER.iItem) Then
                WindowProc = 1
                Exit Function
            End If
        End Select

    Case WM_DESTROY
        ' Remove Subclassing when Listview is Destroyed (Form unloaded)
        WindowProc = CallWindowProc(mlPrevWndProc, hWnd, Msg, wParam, lParam)
        Call SetWindowLong(hWnd, GWL_WNDPROC, mlPrevWndProc)
        Exit Function
    End Select

    ' Call Default Window Handler
    WindowProc = CallWindowProc(mlPrevWndProc, hWnd, Msg, wParam, lParam)
End Function

Public Sub SubClassHwnd(ByVal hWnd As Long, ParamArray ColumnsNums())
    Dim t As Integer
    ColumnsBits = 0
    For t = 0 To UBound(ColumnsNums)
      ColumnsBits = ColumnsBits + (2 ^ (ColumnsNums(t) - 1))
    Next t
    mlPrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
End Sub
```

optionaly you can move all the hidden column to the left


```
ListView1.ColumnHeaders(7).Position = 1
```

----------

