PDA

Click to See Complete Forum and Search --> : Preventing certain Listview columns from sizing...


Aaron Young
Feb 21st, 2002, 10:17 PM
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: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: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
Feb 21st, 2002, 10:21 PM
Holy crap that's cool!

Thanks a lot Aaron.

:)

rjlohan
May 3rd, 2002, 12:03 AM
Nice one!
:thumbsup:

:)

MartinLiss
Nov 4th, 2002, 04:37 PM
Amen to the above compliments. Can the code be modified so that the cursor doesn't change to the double-bar form?

crptcblade
Nov 4th, 2002, 04:38 PM
I would imagine that catching WM_SETCURSOR, or something similar, would accomplish that. Never really looked into it though.

:)

baja_yu
Jun 9th, 2004, 05:08 PM
Can this be modified to prevent resize of non zero width columns? Like some other fixed value...

DiGiTaIErRoR
Jun 9th, 2004, 05:10 PM
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
Jun 9th, 2004, 05:25 PM
Originally posted by baja_yu
Can this be modified to prevent resize of non zero width columns? Like some other fixed value...

Yes

' 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
Jun 10th, 2004, 02:56 PM
Originally posted by crptcblade
Yes

' 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
Jun 10th, 2004, 04:17 PM
How about < 350 instead of = 0?

baja_yu
Jun 10th, 2004, 04:23 PM
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
Jun 10th, 2004, 04:29 PM
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
Jun 10th, 2004, 04:37 PM
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
Jun 10th, 2004, 06:32 PM
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.
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
Jun 11th, 2004, 03:06 AM
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
Jun 11th, 2004, 11:14 AM
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.
Private Const HDN_DIVIDERDBLCLICKA As Long = (HDN_FIRST-5)

baja_yu
Jun 11th, 2004, 12:56 PM
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
Jun 11th, 2004, 01:00 PM
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.
'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
Jun 11th, 2004, 01:21 PM
Didn't see that, sorry :blush:

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

Thanks for the help. :wave:

RobDog888
Jun 11th, 2004, 01:24 PM
Glad to hear its working for you now.

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

InvisibleDuncan
Nov 12th, 2004, 12:04 PM
Now all we need is a VB.Net version. :p

Rodik
Jan 4th, 2006, 06:04 PM
Hey, how do we make this code "IDE-friendly"? So IDE doesn't crash every time one exits the program..

RobDog888
Jan 4th, 2006, 06:09 PM
You need to close your app instead of stopping the code from the IDE. :)

WarrenW
Sep 20th, 2006, 09:22 AM
I tried Aaron's code above and I get an error saying "Invalid use of AddressOf operator". Has anyone seen this before?

Thanks!

MartinLiss
Sep 20th, 2006, 11:57 AM
I believe that that code needs to be in a code module rather than a form. How are you using it?

WarrenW
Sep 20th, 2006, 11:58 AM
Yes, I stuck it in my main form. I'll try it in a module instead and will reply back.

Thanks!

Warren

wittekat01
Apr 17th, 2008, 01:44 PM
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
Apr 17th, 2008, 02:11 PM
I can't reproduce that problem. Can you zip up and attach your project?

wittekat01
Apr 17th, 2008, 02:17 PM
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
Apr 17th, 2008, 04:35 PM
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
Apr 17th, 2008, 04:56 PM
Please create a zip file from your project and attach it using the Manage Attachments function that you'll find below this window.

Chris001
Mar 25th, 2010, 07:58 PM
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.

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
May 11th, 2010, 08:04 AM
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