Visual Basic Common Control API Routines
SendMessage: Determine Positions of Re-Ordered ListView Columns
Posted:   Friday August 14, 1997
Updated:   Monday December 26, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB4-32, Windows 95
OS restrictions:   None
Author:   VBnet - Randy Birch
This method is intended for Visual Basic 5 or Visual Basic 6 where the Common Control library used is the MSComCtl 5 version (comctl32.ocx). Because the VB6-specific mscomctl.ocx (Common Controls 6) is a complete implementation of comctl32.dll and not reliant on the version of comctl32.dll installed, this routine may not work when applied to a listview created from the VB6-specific mscomctl.ocx.

Enhanced Comctl32 functionality is only available to users with comctl32.dll version 4.70 or greater installed. This dll is typically installed with IE3.x or greater.

Sending the listview extended style message LVS_EX_HEADERDRAGDROP enables repositioning/reordering of a Listview's main and sub item columns.

However, this does not alter the index of the columns to match their new physical locations. VB remains unaware that repositioning has taken place (since it was done via APIs "outside" of VB's native control handling methods), so performing an indexed loop through the ColumnHeaders collection will always return the columns in the order they were created. This maintains the validity of the code used in adding items and sub items to the listview as the indexes continue to point to the original columns.

There are times, however, when it is desirable to know what the current column arrangement is. LVM_GETCOLUMNORDERARRAY, LVM_GETCOLUMN and the LVCOLUMN Type, together with SendMessage, will return the order of the columns that the user may have changed.

This example does not contain all code required to construct the illustration shown. The routine provided here is designed to be applied to an existing project utilizing a Listview control with sub items.

It also assumes that you have implemented the code necessary to provide the column-rearrangement functionality.

 BAS Module Code

 Form Code
Add a command button to the project (Command1), and add the following code to the Command1_Click sub:

Option Explicit
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
Private Declare Function SendMessage Lib "user32" _
    Alias "SendMessageA" _ 
   (ByVal hwnd As Long, _
    ByVal msg As Long, _ 
    ByVal wParam As Long, _
    lParam As Any) As Long

Private Const LVM_FIRST = &H1000
Private Const LVS_EX_GRIDLINES = &H1
Private Const LVS_EX_CHECKBOXES = &H4
Private Const LVM_GETCOLUMN = (LVM_FIRST + 25)
Private Const LVCF_TEXT = &H4

Private Type LVCOLUMN
    mask As Long
    fmt As Long
    cx As Long
    pszText  As String
    cchTextMax As Long
    iSubItem As Long
    iImage As Long
    iOrder As Long
End Type

Private Sub Command1_Click()
  'working variables   
   Dim i As Long
   Dim firstCol As Long
   Dim lastCol As Long
   Dim totalCols As Long
  'used for the message box  
   Dim msg As String
  'the return value from the API   
   Dim tmp As String
  'the Listview Column structure   
  'initialize the variables needed. totalCols is the 1-based 
  'total required for the API. lastCol is the 0-based 
  'number of columns in the listview.  
   totalCols = ListView1.ColumnHeaders.Count
   firstCol = 0
   lastCol = totalCols - 1
  'to get the column order, we have to pass an array to the API.  
  'On return, it will be filled with the index of the column in 
  'incrementing positions.  For example, if column 2 was moved 
  'to position 0, the return array would hold 2, 1, 0, 3.   
  'And because this will be used directly in the API calls, it 
  'is declared As Long.
   ReDim posArray(firstCol To lastCol) As Long

   Call SendMessage(ListView1.hwnd, _
                    LVM_GETCOLUMNORDERARRAY, _
                    totalCols, _
  'with the array filled, it's now a matter of looping through the 
  'array, and passing each item as the position (wParam).  The 
  'LVCOLUMN type (LVC) will be filled with the data for the   
  'passed index (LVCF_TEXT in this example).   
   For i = firstCol To lastCol
    'get the string associated with the position. The string to fill
    'must be padded with sufficient room to hold the ColumnHeader
     tmp = Space$(32)
      With LVC
         .mask = LVCF_TEXT
         .pszText = tmp
         .cchTextMax = Len(tmp)
      End With
      Call SendMessage(ListView1.hwnd, LVM_GETCOLUMN, posArray(i), LVC)
     'strip the trailing null   
      tmp = Left$(LVC.pszText, InStr(LVC.pszText, Chr$(0)) - 1)
     'add the returned value to the msg for display 
      List1.AddItem tmp
      msg = msg & vbTab & tmp & vbTab & _
            vbTab & posArray(i) & vbTab & vbCrLf
   MsgBox "    Current column order / Original index: " & vbCrLf & vbCrLf & msg
End Sub
Run your project, and populate your Listview as usual. Enable the Allow Repositioning checkbox, and click and drag the column headers to new positions. Test the routine by hitting the Get Columns button.


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy



Hit Counter