Jump to content
Burgaud

Need understanding the various cryptic DLL and API functions

Recommended Posts

Burgaud

I was looking for scripts/functions/methods to make a highlighted listview item remain highlighted even when mouse is removed from focus of the listview.

This is a script from a post (not mine) long ago that seems to work.

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>
#include <WinAPI.au3>

Global Const $ODT_LISTVIEW = 102

Global Const $ODA_DRAWENTIRE = 0x1
Global Const $ODA_SELECT = 0x2
Global Const $ODA_FOCUS = 0x4

Global Const $ODS_SELECTED = 0x0001

$hGUI = GUICreate("Test GUI", 410, 320)

$hListView = _GUICtrlListView_Create($hGUI, "Items|SubItems", 10, 10, 300, 200, BitOR($LVS_REPORT, $LVS_OWNERDRAWFIXED))
_GUICtrlListView_SetExtendedListViewStyle($hListView, $LVS_EX_FULLROWSELECT)
$XhListView = _GUICtrlListView_Create($hGUI, "Items|SubItems", 10, 210, 300, 100, BitOR($LVS_REPORT, $LVS_OWNERDRAWFIXED))

_GUICtrlListView_SetExtendedListViewStyle($XhListView, $LVS_EX_FULLROWSELECT)

For $i = 1 To 10
    _GUICtrlListView_AddItem($hListView, "Item " & $i)
    _GUICtrlListView_AddSubItem($hListView, $i - 1, "SubItem " & $i, 1)

    _GUICtrlListView_AddItem($XhListView, "Item " & $i)
    _GUICtrlListView_AddSubItem($XhListView, $i - 1, "SubItem " & $i, 1)
Next

GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

GUISetState()

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam)
    Local $tagDRAWITEMSTRUCT, $iBrushColor, $cID, $itmID, $itmAction, $itmState, $hItm, $hDC, $bSelected
    
    $tagDRAWITEMSTRUCT = DllStructCreate("uint cType;uint cID;uint itmID;uint itmAction;uint itmState;" & _
                                         "hwnd hItm;hwnd hDC;int itmRect[4];dword itmData", $lParam)
                                         
    If DllStructGetData($tagDRAWITEMSTRUCT, "cType") <> $ODT_LISTVIEW Then Return $GUI_RUNDEFMSG
    
    $cID = DllStructGetData($tagDRAWITEMSTRUCT, "cID")
    $itmID = DllStructGetData($tagDRAWITEMSTRUCT, "itmID")
    $itmAction = DllStructGetData($tagDRAWITEMSTRUCT, "itmAction")
    $itmState = DllStructGetData($tagDRAWITEMSTRUCT, "itmState")
    $hItm = DllStructGetData($tagDRAWITEMSTRUCT, "hItm")
    $hDC = DllStructGetData($tagDRAWITEMSTRUCT, "hDC")
    
    $bSelected = BitAND($itmState, $ODS_SELECTED)
    
    Switch $itmAction
        Case $ODA_DRAWENTIRE
            If $itmState = $bSelected Then
                $iBrushColor = 0xFFFFFF
            Else
                $iBrushColor = 0x0000FF
            EndIf
            
            Local $aBrush = DLLCall("gdi32.dll","hwnd","CreateSolidBrush", "int", $iBrushColor)
            
            Local $aBrushOld = _WinAPI_SelectObject($hDC, $aBrush[0])
            
            Local $iLeft = DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1)
            DllStructSetData($tagDRAWITEMSTRUCT, "itmRect", $iLeft + 5, 1)
            
            _WinAPI_FillRect($hDC, DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), $aBrush[0])
            
            _WinAPI_SelectObject($hDC, $aBrushOld)
            
            _WinAPI_DeleteObject($aBrush[0])
            
            Local $itmText = _GUICtrlListView_GetItemText($hListView, $itmID)

            DllStructSetData($tagDRAWITEMSTRUCT, "itmRect", DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1) + 2, 1)
            
            DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $itmText, "int", StringLen($itmText), _
                    "ptr", DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), "int", $DT_LEFT)
                    
            Local $iSubItmText = _GUICtrlListView_GetItemText($hListView, $itmID, 1)
            Local $aSubItmRect = _GUICtrlListView_GetSubItemRect($hListView, $itmID, 1)
            
            Local $iSubItmRect = DllStructCreate("int[4]")
            
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[0], 1)
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[1], 2)
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[2], 3)
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[3], 4)
            
            DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $iSubItmText, "int", StringLen($iSubItmText), _
                    "ptr", DllStructGetPtr($iSubItmRect), "int", $DT_LEFT)
    EndSwitch
    
    Return $GUI_RUNDEFMSG
EndFunc

 

Here is my question:

I read the documentations on:

DllStructCreate
DllStructGetData
DLLCall
.
.
.
every DLL therein

All were too cryptic to understand.

Can anyone please explain the WM_DRAWITEM function, if possible, line per line?
I really would like to understand Autoit in its innards.

Thanks!

 

 

Share this post


Link to post
Share on other sites
Melba23

Burgaud,

I suggest you start by reading the GUIRegisterMsg tutorial in the Wiki if you are not sure quite what Windows message handlers do. Then the following might make more sense:

; Tell AutoIt to intercept $WM_DRAWITEM messages

GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

; This handler will run when a $WM_DRAWITEM message is ibntercepted
Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam)
    
    ; Create a struct - a type of variable with very closely defined sections, ech of which is given a name (optional) and a datatype
    Local $tagDRAWITEMSTRUCT, $iBrushColor, $cID, $itmID, $itmAction, $itmState, $hItm, $hDC, $bSelected
    $tagDRAWITEMSTRUCT = DllStructCreate("uint cType;uint cID;uint itmID;uint itmAction;uint itmState;" & _
                                         "hwnd hItm;hwnd hDC;int itmRect[4];dword itmData", $lParam)
    ; $lParam - one of the parameters received by the message handler - gives us a pointer
    ; This is the address of an area of memory filled when Windows gets a $WM_DRAWITEM message
    ; We map this area of memory using the struct we created
                                         
    ; Look at what is in the "cType" section of the struct
    If DllStructGetData($tagDRAWITEMSTRUCT, "cType") <> $ODT_LISTVIEW Then Return $GUI_RUNDEFMSG
    
    ; If that was valid then get other useful data from other sections ofthe struct
    $cID = DllStructGetData($tagDRAWITEMSTRUCT, "cID")
    $itmID = DllStructGetData($tagDRAWITEMSTRUCT, "itmID")
    $itmAction = DllStructGetData($tagDRAWITEMSTRUCT, "itmAction")
    $itmState = DllStructGetData($tagDRAWITEMSTRUCT, "itmState")
    $hItm = DllStructGetData($tagDRAWITEMSTRUCT, "hItm")
    $hDC = DllStructGetData($tagDRAWITEMSTRUCT, "hDC")
    
    $bSelected = BitAND($itmState, $ODS_SELECTED)
    
    ; Now determine whether the action that took place was the one we needed to intercept
    Switch $itmAction
        Case $ODA_DRAWENTIRE
            ; Determine the colour needed - wil depend if the ListView element is selected or not
            If $itmState = $bSelected Then
                $iBrushColor = 0xFFFFFF
            Else
                $iBrushColor = 0x0000FF
            EndIf
            ; Create a brush
            Local $aBrush = DLLCall("gdi32.dll","hwnd","CreateSolidBrush", "int", $iBrushColor)
            Local $aBrushOld = _WinAPI_SelectObject($hDC, $aBrush[0])
            ; Create a struct to show the position of the ListView element
            Local $iLeft = DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1)
            DllStructSetData($tagDRAWITEMSTRUCT, "itmRect", $iLeft + 5, 1)
            ; Paint the element
            _WinAPI_FillRect($hDC, DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), $aBrush[0])
            ; delete the bruch we created
            _WinAPI_SelectObject($hDC, $aBrushOld)
            _WinAPI_DeleteObject($aBrush[0])
            
            ; This next section write the text into the user drawn elements
            ; The item (left-most element)
            Local $itmText = _GUICtrlListView_GetItemText($hListView, $itmID)
            DllStructSetData($tagDRAWITEMSTRUCT, "itmRect", DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1) + 2, 1)
            
            DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $itmText, "int", StringLen($itmText), _
                    "ptr", DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), "int", $DT_LEFT)
            ; And now the subitem - I imagine this woudl be looped if there were mor ethan 2 columns            
            Local $iSubItmText = _GUICtrlListView_GetItemText($hListView, $itmID, 1)
            Local $aSubItmRect = _GUICtrlListView_GetSubItemRect($hListView, $itmID, 1)
            
            Local $iSubItmRect = DllStructCreate("int[4]")
            
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[0], 1)
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[1], 2)
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[2], 3)
            DllStructSetData($iSubItmRect, 1, $aSubItmRect[3], 4)
            
            DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $iSubItmText, "int", StringLen($iSubItmText), _
                    "ptr", DllStructGetPtr($iSubItmRect), "int", $DT_LEFT)
    EndSwitch
    
    ; Tell Autoit to do its normal actions when it receives the message
    Return $GUI_RUNDEFMSG
EndFunc

I hope this helps.

M23


Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind._______My UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Share this post


Link to post
Share on other sites
Burgaud

What is the difference between:

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") 

and

GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM")

Several sample scripts I saw them using WM_NOTIFY while some uses WM_DRAWITEM to perform the same result (ie, highlight/change color of a listview item).

THIS is very confusing.

Share this post


Link to post
Share on other sites
Earthshine

well, you start with Google and look up the messages.

WM_DRAWITEM message

WM_NOTIFY message


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
Burgaud

The last 3-4 weeks, I have been trying to port over my book keeping perl script into Autoit.

After weeks with this project, I barely made any progress. AutoIt's GUI module requires EXTENSIVE knowledge of Win32::GUI. It was steep learning curve. Documentations and examples were little help as these were cryptic at best. Simple GUI like buttons, labels and entry boxes were easy; but ListBoxes, ListViews and others was the high wall.

Little progress and huge amount of time and effort spent was NOT worth it. Sadly, in the end, I gave up on this Autoit port project.

Share this post


Link to post
Share on other sites
Zedna

When you do standard actions with ListView/ListBox then it's easy too.

It becomes complex only when you want to achieve non-standard behaviour.

So for you as AutoIt/Win32 API novice avoid non-standard behaviour and be happy with standards.

Share this post


Link to post
Share on other sites
jchd

I wonder how you can compare perl scripts and customized behavior Windows GUI, using AutoIt or whatever else.

You seem to be upset by Windows' GUI complexity when trying to achieve non-standard behavior and that isn't surprising: no GUI-ed OS is simple in this regard. You're drowning yourself in cosmetic details.
Rather focus on having the real job done first using a bare-bone interface (even console I/O will do) and when the core job is working fine, only then add a GUI harness, simple at first then make it prettier/sophisticated as you feel need.

  • Like 1

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites
Earthshine

Yes. Get it working first without Gui then add that later as stated above. Don’t blame Windows


My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×