LarsJ Posted October 28, 2018 Share Posted October 28, 2018 (edited) In Fast subclassing through compiled code a WM_NOTIFY message handler is implemented in C/C++. Is it possible to implement the entire window procedure (main message handler) in compiled code and thus avoid the overhead associated with the subclassing technique? AutoIt code This is a slightly modified version of _WinAPI_RegisterClassEx example, and a listview is created in the window (ListView0.au3): expandcollapse popup#include <WinAPIRes.au3> #include <WinAPISys.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> Global $bExit = False Global $iRows = 100, $iCols = 8 Example() Func Example() Local Const $sClass = "MyWindowClass" Local Const $sName = "Ordinary ListView" ; Get module handle for the current process Local $hInstance = _WinAPI_GetModuleHandle( 0 ) ; Create a class cursor Local $hCursor = _WinAPI_LoadCursor( 0, 32512 ) ; IDC_ARROW ; Create a class icons (large and small) Local $tIcons = DllStructCreate( "ptr;ptr" ) _WinAPI_ExtractIconEx( @SystemDir & "\shell32.dll", 130, DllStructGetPtr( $tIcons, 1 ), DllStructGetPtr( $tIcons, 2 ), 1 ) Local $hIcon = DllStructGetData( $tIcons, 1 ) Local $hIconSm = DllStructGetData( $tIcons, 2 ) ; Create DLL callback function (window procedure) Local $pWinProc = DllCallbackGetPtr( DllCallbackRegister( "WinProc", "lresult", "hwnd;uint;wparam;lparam" ) ) ; Create and fill $tagWNDCLASSEX structure Local $tWCEX = DllStructCreate( $tagWNDCLASSEX & ";wchar szClassName[" & ( StringLen( $sClass ) + 1 ) & "]" ) DllStructSetData( $tWCEX, "Size", DllStructGetPtr( $tWCEX, "szClassName" ) - DllStructGetPtr( $tWCEX ) ) DllStructSetData( $tWCEX, "Style", 0 ) DllStructSetData( $tWCEX, "hWndProc", $pWinProc ) DllStructSetData( $tWCEX, "ClsExtra", 0 ) DllStructSetData( $tWCEX, "WndExtra", 0 ) DllStructSetData( $tWCEX, "hInstance", $hInstance ) DllStructSetData( $tWCEX, "hIcon", $hIcon ) DllStructSetData( $tWCEX, "hCursor", $hCursor ) DllStructSetData( $tWCEX, "hBackground", _WinAPI_CreateSolidBrush( _WinAPI_GetSysColor( $COLOR_3DFACE ) ) ) DllStructSetData( $tWCEX, "MenuName", 0 ) DllStructSetData( $tWCEX, "ClassName", DllStructGetPtr( $tWCEX, "szClassName" ) ) DllStructSetData( $tWCEX, "hIconSm", $hIconSm ) DllStructSetData( $tWCEX, "szClassName", $sClass ) ; Register a window class _WinAPI_RegisterClassEx( $tWCEX ) ; Create a window Local $hWnd = _WinAPI_CreateWindowEx( 0, $sClass, $sName, BitOR( $WS_CAPTION, $WS_POPUPWINDOW, $WS_VISIBLE ), ( @DesktopWidth - 826 ) / 2, ( @DesktopHeight - 584 ) / 2, 826, 584, 0 ) ; Create listview Local $hListView = _GUICtrlListView_Create( $hWnd, "", 10, 10, 800, 538, $LVS_DEFAULT-$LVS_SINGLESEL, $WS_EX_CLIENTEDGE ) _GUICtrlListView_SetExtendedListViewStyle( $hListView, $LVS_EX_DOUBLEBUFFER+$LVS_EX_FULLROWSELECT ) ; Add columns For $i = 0 To $iCols - 1 _GUICtrlListView_AddColumn( $hListView, "Col " & $i, 96, 2 ) ; 2 = Centered text Next ; ListView items For $i = 0 To $iRows - 1 _GUICtrlListView_AddItem( $hListView, "Row " & $i ) For $j = 1 To $iCols - 1 _GUICtrlListView_AddSubItem( $hListView, $i, "Col " & $j, $j ) Next Next ; Main loop While Sleep(10) If $bExit Then ExitLoop WEnd ; Unregister window class and release unnecessary resources _WinAPI_UnregisterClass( $sClass, $hInstance ) _WinAPI_DestroyCursor( $hCursor ) _WinAPI_DestroyIcon( $hIcon ) _WinAPI_DestroyIcon( $hIconSm ) EndFunc Func WinProc( $hWnd, $iMsg, $wParam, $lParam ) Switch $iMsg Case $WM_CLOSE $bExit = True EndSwitch Return _WinAPI_DefWindowProcW( $hWnd, $iMsg, $wParam, $lParam ) EndFunc It's left for Windows to handle all listview messages. No new code is added to WinProc() function. In the next example the listview is replaced by a virtual and custom drawn listview. Now it's necessary to handle LVN_GETDISPINFO and NM_CUSTOMDRAW notifications in WinProc() function (ListView1.au3): ; Create listview $hListView = _GUICtrlListView_Create( $hWnd, "", 10, 10, 800, 538, $LVS_DEFAULT+$LVS_OWNERDATA-$LVS_SINGLESEL, $WS_EX_CLIENTEDGE ) _GUICtrlListView_SetExtendedListViewStyle( $hListView, $LVS_EX_DOUBLEBUFFER+$LVS_EX_FULLROWSELECT ) ; Add columns For $i = 0 To $iCols - 1 _GUICtrlListView_AddColumn( $hListView, "Col " & $i, 96, 2 ) ; 2 = Centered text Next ; ListView items For $i = 0 To $iRows - 1 For $j = 0 To $iCols - 1 $aItems[$i][$j] = $i & "/" & $j Next Next ; ListView colors Local $aLVColors = [ 0xCCCCFF, 0xCCFFFF, 0xCCFFCC, 0xFFFFCC, 0xFFCCCC, 0xFFCCFF ] ; BGR For $i = 0 To $iRows - 1 For $j = 0 To $iCols - 1 $aColors[$i][$j] = $aLVColors[Random( 0,5,1 )] Next Next ; Set number of rows in virtual ListView DllCall( "user32.dll", "lresult", "SendMessageW", "hwnd", $hListView, "uint", $LVM_SETITEMCOUNT, "wparam", $iRows, "lparam", 0 ) WinProc() function: expandcollapse popupFunc WinProc( $hWnd, $iMsg, $wParam, $lParam ) Local Static $tText = DllStructCreate( "wchar[100]" ), $pText = DllStructGetPtr( $tText ) Local Static $tRect = DllStructCreate( $tagRECT ), $pRect = DllStructGetPtr( $tRect ) Switch $iMsg Case $WM_NOTIFY Switch DllStructGetData( DllStructCreate( $tagNMHDR, $lParam ), "Code" ) Case $LVN_GETDISPINFOW ; Fill virtual listview Local $tNMLVDISPINFO = DllStructCreate( $tagNMLVDISPINFO, $lParam ) If Not BitAND( DllStructGetData( $tNMLVDISPINFO, "Mask" ), $LVIF_TEXT ) Then Return Local $sItem = $aItems[DllStructGetData($tNMLVDISPINFO,"Item")][DllStructGetData($tNMLVDISPINFO,"SubItem")] DllStructSetData( $tText, 1, $sItem ) DllStructSetData( $tNMLVDISPINFO, "TextMax", StringLen( $sItem ) ) DllStructSetData( $tNMLVDISPINFO, "Text", $pText ) Return Case $NM_CUSTOMDRAW ; Draw back colors Local $tNMLVCUSTOMDRAW = DllStructCreate( $tagNMLVCUSTOMDRAW, $lParam ) Local $dwDrawStage = DllStructGetData( $tNMLVCUSTOMDRAW, "dwDrawStage" ), $iItem Switch $dwDrawStage ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify the parent window of any item-related drawing operations Case $CDDS_ITEMPREPAINT ; Before painting an item Return $CDRF_NOTIFYSUBITEMDRAW ; Notify the parent window of any subitem-related drawing operations Case $CDDS_ITEMPREPAINT + $CDDS_SUBITEM ; Before painting a subitem $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) If DllCall( "user32.dll", "lresult", "SendMessageW", "hwnd", $hListView, "uint", $LVM_GETITEMSTATE, "wparam", $iItem, "lparam", $LVIS_SELECTED )[0] Then Return $CDRF_NOTIFYPOSTPAINT ; Selected item DllStructSetData( $tNMLVCUSTOMDRAW, "ClrTextBk", $aColors[$iItem][DllStructGetData($tNMLVCUSTOMDRAW,"iSubItem")] ) ; Normal item Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors Case $CDDS_ITEMPOSTPAINT + $CDDS_SUBITEM ; After painting a subitem Local $hDC = DllStructGetData( $tNMLVCUSTOMDRAW, "hdc" ) ; Subitem rectangle $iItem = DllStructGetData( $tNMLVCUSTOMDRAW, "dwItemSpec" ) Local $iSubItem = DllStructGetData( $tNMLVCUSTOMDRAW, "iSubItem" ) DllStructSetData( $tRect, "Left", $LVIR_LABEL ) DllStructSetData( $tRect, "Top", $iSubItem ) DllCall( "user32.dll", "lresult", "SendMessageW", "hwnd", $hListView, "uint", $LVM_GETSUBITEMRECT, "wparam", $iItem, "lparam", $pRect ) DllStructSetData( $tRect, "Left", DllStructGetData( $tRect, "Left" ) + 2 ) DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllStructSetData( $tRect, "Right", DllStructGetData( $tRect, "Right" ) - 2 ) DllStructSetData( $tRect, "Bottom", DllStructGetData( $tRect, "Bottom" ) - 1 ) ; Subitem back color Local $hBrush = DllCall( "gdi32.dll", "handle", "CreateSolidBrush", "int", $aColors[$iItem][$iSubItem] )[0] ; _WinAPI_CreateSolidBrush DllCall( "user32.dll", "int", "FillRect", "handle", $hDC, "struct*", $tRect, "handle", $hBrush ) ; _WinAPI_FillRect DllCall( "gdi32.dll", "bool", "DeleteObject", "handle", $hBrush ) ; _WinAPI_DeleteObject ; Draw subitem text DllStructSetData( $tRect, "Top", DllStructGetData( $tRect, "Top" ) + 1 ) DllCall( "gdi32.dll", "int", "SetTextColor", "handle", $hDC, "int", 0 ) ; _WinAPI_SetTextColor DllCall( "gdi32.dll", "int", "SetBkMode", "handle", $hDC, "int", $TRANSPARENT ) ; _WinAPI_SetBkMode DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aItems[$iItem][$iSubItem], "int", -1, "struct*", $tRect, "uint", $DT_CENTER ) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch EndSwitch Case $WM_CLOSE $bExit = True EndSwitch Return _WinAPI_DefWindowProcW( $hWnd, $iMsg, $wParam, $lParam ) EndFunc Also in this example there is a problem with the speed of the WM_NOTIFY code. You can provoke an error this way: Click a row in the listview (not one of the very top rows). Press Shift+Down arrow to select multiple rows. The problem will arise after just a few rows. Press Ctrl+Break in SciTE to stop the code. Note that since the window isn't created with GUICreate(), it's not possible to use any of the native functions in the GUI Management section of the help file. But all the UDFs in the GUI Reference section can be used. C/C++ code The window procedure above is defined this way: ; Create DLL callback function (window procedure) Local $pWinProc = DllCallbackGetPtr( DllCallbackRegister( "WinProc", "lresult", "hwnd;uint;wparam;lparam" ) ) DllStructSetData( $tWCEX, "hWndProc", $pWinProc ) The C/C++ definition of a window procedure in a dll-file looks like this: LRESULT CALLBACK __stdcall WinProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) We can get a pointer to the window procedure this way: Local $hModule = _WinAPI_LoadLibrary( "WinProc.dll" ) Local $pWinProc = _WinAPI_GetProcAddress( $hModule, "WinProc" ) Now we can use this pointer in $tWCEX struct. We also need to pass $aItems and $aColors arrays to the compiled code in the dll-file. But we already know how to do that. Note that because $pWinProc is used directly in $tWCEX struct, we can avoid both the DllCall and DllCallAddress commands. Thus, we avoid a severe overhead in relation to these commands (that the AutoIt code interpreter should interpret a code line for each message (for a huge number of messages), and that DllCall and DllCallAddress are complicated and time-consuming commands). AutoIt code in ListView2.au3: expandcollapse popup#include <WinAPIRes.au3> #include <WinAPISys.au3> #include <GuiListView.au3> #include <WindowsConstants.au3> #include "AccArrays.au3" Global $aData[3] ; $psaItems, $psaColors, $pExit Example() Func Example() Local Const $sClass = "MyWindowClass", $sName = "Virtual and Custom Drawn ListView" Local $iRows = 10000, $iCols = 8, $aItems[$iRows][$iCols], $aColors[$iRows][$iCols] ; Get module handle for the current process Local $hInstance = _WinAPI_GetModuleHandle( 0 ) ; Create a class cursor Local $hCursor = _WinAPI_LoadCursor( 0, 32512 ) ; IDC_ARROW ; Create a class icons (large and small) Local $tIcons = DllStructCreate( "ptr;ptr" ) _WinAPI_ExtractIconEx( @SystemDir & "\shell32.dll", 130, DllStructGetPtr( $tIcons, 1 ), DllStructGetPtr( $tIcons, 2 ), 1 ) Local $hIcon = DllStructGetData( $tIcons, 1 ) Local $hIconSm = DllStructGetData( $tIcons, 2 ) ; Create DLL callback function (window procedure) Local $hModule = _WinAPI_LoadLibrary( @AutoItX64 ? "WinProc_x64.dll" : "WinProc.dll" ) Local $pWinProc = _WinAPI_GetProcAddress( $hModule, "WinProc" ) ; Create and fill $tagWNDCLASSEX structure Local $tWCEX = DllStructCreate( $tagWNDCLASSEX & ";wchar szClassName[" & ( StringLen( $sClass ) + 1 ) & "]" ) DllStructSetData( $tWCEX, "Size", DllStructGetPtr( $tWCEX, "szClassName" ) - DllStructGetPtr( $tWCEX ) ) DllStructSetData( $tWCEX, "Style", 0 ) DllStructSetData( $tWCEX, "hWndProc", $pWinProc ) DllStructSetData( $tWCEX, "ClsExtra", 0 ) DllStructSetData( $tWCEX, "WndExtra", 0 ) DllStructSetData( $tWCEX, "hInstance", $hInstance ) DllStructSetData( $tWCEX, "hIcon", $hIcon ) DllStructSetData( $tWCEX, "hCursor", $hCursor ) DllStructSetData( $tWCEX, "hBackground", _WinAPI_CreateSolidBrush( _WinAPI_GetSysColor( $COLOR_3DFACE ) ) ) DllStructSetData( $tWCEX, "MenuName", 0 ) DllStructSetData( $tWCEX, "ClassName", DllStructGetPtr( $tWCEX, "szClassName" ) ) DllStructSetData( $tWCEX, "hIconSm", $hIconSm ) DllStructSetData( $tWCEX, "szClassName", $sClass ) ; Register a window class _WinAPI_RegisterClassEx( $tWCEX ) ; Create a window Local $hWnd = _WinAPI_CreateWindowEx( 0, $sClass, $sName, BitOR( $WS_CAPTION, $WS_POPUPWINDOW, $WS_VISIBLE ), ( @DesktopWidth - 826 ) / 2, ( @DesktopHeight - 584 ) / 2, 826, 584, 0 ) ; Create listview Local $hListView = _GUICtrlListView_Create( $hWnd, "", 10, 10, 800, 538, $LVS_DEFAULT+$LVS_OWNERDATA-$LVS_SINGLESEL, $WS_EX_CLIENTEDGE ) _GUICtrlListView_SetExtendedListViewStyle( $hListView, $LVS_EX_DOUBLEBUFFER+$LVS_EX_FULLROWSELECT ) ; Add columns For $i = 0 To $iCols - 1 _GUICtrlListView_AddColumn( $hListView, "Col " & $i, 96, 2 ) ; 2 = Centered text Next ; ListView items For $i = 0 To $iRows - 1 For $j = 0 To $iCols - 1 $aItems[$i][$j] = $i & "/" & $j Next Next ; ListView colors Local $aLVColors = [ 0xCCCCFF, 0xCCFFFF, 0xCCFFCC, 0xFFFFCC, 0xFFCCCC, 0xFFCCFF ] ; BGR For $i = 0 To $iRows - 1 For $j = 0 To $iCols - 1 $aColors[$i][$j] = $aLVColors[Random( 0,5,1 )] Next Next ; Load dll-file Local $hDll = DllOpen( @AutoItX64 ? "WinProc_x64.dll" : "WinProc.dll" ) ; $aItems, $aColors and $bExit Local $psaItemsData, $psaColorsData, $bExit = False $aData[2] = DllStructGetPtr( DllStructCreate( $tagVARIANT ) ) AccArrays03( Copy, $aItems, $aColors, $bExit ) SafeArrayAccessData( $aData[0], $psaItemsData ) SafeArrayAccessData( $aData[1], $psaColorsData ) ; Pass data to compiled code DllCall( $hDll, "none", "PassData", "hwnd", $hListView, "int", $iCols, "ptr", $psaItemsData, "ptr", $psaColorsData, "ptr", $aData[2] ) ; Set number of rows in virtual ListView DllCall( "user32.dll", "lresult", "SendMessageW", "hwnd", $hListView, "uint", $LVM_SETITEMCOUNT, "wparam", $iRows, "lparam", 0 ) ; Main loop While Sleep(10) If DllStructGetData( DllStructCreate( "short", $aData[2] + 8 ), 1 ) Then ExitLoop WEnd ; Unregister window class and release unnecessary resources _WinAPI_UnregisterClass( $sClass, $hInstance ) _WinAPI_DestroyCursor( $hCursor ) _WinAPI_DestroyIcon( $hIcon ) _WinAPI_DestroyIcon( $hIconSm ) SafeArrayUnaccessData( $aData[0] ) SafeArrayUnaccessData( $aData[1] ) _WinAPI_FreeLibrary( $hModule ) DllClose( $hDLL ) EndFunc ; Copy internal AutoIt variants (variables) to real Windows ; variants, that can be accessed from both AutoIt and C/C++. Func Copy( $pvItems, $pvColors, $pvExit ) SafeArrayCopy( DllStructGetData( DllStructCreate( "ptr", $pvItems + 8 ), 1 ), $aData[0] ) SafeArrayCopy( DllStructGetData( DllStructCreate( "ptr", $pvColors + 8 ), 1 ), $aData[1] ) VariantCopy( $aData[2], $pvExit ) EndFunc C/C++ code: expandcollapse popup#include <Windows.h> #include <CommCtrl.h> #include <OleAuto.h> // Globals HWND g_hListView; int g_iColumns; VARIANT* g_psaItems; VARIANT* g_psaColors; VARIANT* g_pExit; void __stdcall PassData( HWND hListView, int iColumns, VARIANT* psaItems, VARIANT* psaColors, VARIANT* pExit ) { g_hListView = hListView; g_iColumns = iColumns; g_psaItems = psaItems; g_psaColors = psaColors; g_pExit = pExit; } LRESULT CALLBACK __stdcall WinProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { NMLVDISPINFOW* plvdi; NMLVCUSTOMDRAW* plvcd; BSTR pBstr; DWORD_PTR iItem; RECT r; HBRUSH hBrush; switch ( uMsg ) { case WM_NOTIFY: switch ( ((LPNMHDR)lParam)->code ) { case LVN_GETDISPINFOW: // Fill virtual listview plvdi = (NMLVDISPINFOW*)lParam; if ( ( plvdi->item.mask & LVIF_TEXT ) == 0 ) return TRUE; pBstr = g_psaItems[plvdi->item.iItem*g_iColumns+plvdi->item.iSubItem].bstrVal; plvdi->item.pszText = pBstr; plvdi->item.cchTextMax = SysStringLen( pBstr ); return TRUE; case NM_CUSTOMDRAW: // Draw back colors plvcd = (NMLVCUSTOMDRAW*)lParam; switch ( plvcd->nmcd.dwDrawStage ) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: return CDRF_NOTIFYSUBITEMDRAW; case CDDS_ITEMPREPAINT | CDDS_SUBITEM: iItem = plvcd->nmcd.dwItemSpec; if ( SendMessageW( g_hListView, LVM_GETITEMSTATE, iItem, LVIS_SELECTED ) ) return CDRF_NOTIFYPOSTPAINT; plvcd->clrTextBk = g_psaColors[iItem*g_iColumns+plvcd->iSubItem].intVal; return CDRF_NEWFONT; case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: // Subitem rectangle iItem = plvcd->nmcd.dwItemSpec; r.left = LVIR_LABEL; r.top = plvcd->iSubItem; SendMessageW( g_hListView, LVM_GETSUBITEMRECT, iItem, (LPARAM)&r ); r.left += 2; r.right -= 2; r.top += 1; r.bottom -= 1; // Subitem back color hBrush = CreateSolidBrush( g_psaColors[iItem*g_iColumns+plvcd->iSubItem].intVal ); FillRect( plvcd->nmcd.hdc, &r, hBrush ); DeleteObject( hBrush ); // Draw subitem text SetTextColor( plvcd->nmcd.hdc, 0 ); SetBkMode( plvcd->nmcd.hdc, TRANSPARENT ); pBstr = g_psaItems[iItem*g_iColumns+plvcd->iSubItem].bstrVal; r.top += 1; DrawTextW( plvcd->nmcd.hdc, pBstr, SysStringLen( pBstr ), &r, DT_CENTER ); return CDRF_NEWFONT; } default: return DefWindowProcW( hWnd, uMsg, wParam, lParam ); } case WM_CLOSE: g_pExit->boolVal = 1; default: return DefWindowProcW( hWnd, uMsg, wParam, lParam ); } return 0; } Zip-file ListView0.au3 and ListView1.au3 is pure AutoIt code. In ListView2.au3 the window procedure is replaced with compiled code. Note that the zip-file contains two small dll-files. If you are using Microsoft SmartScreen or Microsoft Windows Defender, there is a likelihood of fake virus detection, even if the dll-files are created with Microsoft Visual Studio. Most other antivirus products will not detect fake viruses. You need AutoIt 3.3.12 or later. Tested on Windows 7 and Windows 10. Comments are welcome. Let me know if there are any issues. WinProc.7z Edited October 31, 2018 by LarsJ New zip-file with updated ListView2.au3 mLipok, Gianni and KaFu 3 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Danyfirex Posted October 29, 2018 Share Posted October 29, 2018 Hello really nice, You rock LarsJ!!! I was getting ListView2.au3 Ended without pressing close button. It was exiting from main loop because you forgot to check g_pExit value with 1. This fixed the issue. If DllStructGetData( DllStructCreate( "short", $aData[2] + 8 ), 1 )=1 Then ExitLoop You could wrap "DllStructGetData( DllStructCreate( "short", $aData[2] + 8 ), 1 )" in a easier way for not advanced users because the will get scared when they see that. Saludos LarsJ 1 Danysys.com AutoIt... UDFs: VirusTotal API 2.0 UDF - libZPlay UDF - Apps: Guitar Tab Tester - VirusTotal Hash Checker Examples: Text-to-Speech ISpVoice Interface - Get installed applications - Enable/Disable Network connection PrintHookProc - WINTRUST - Mute Microphone Level - Get Connected NetWorks - Create NetWork Connection ShortCut Link to comment Share on other sites More sharing options...
LarsJ Posted October 31, 2018 Author Share Posted October 31, 2018 Danyfirex, thank you very much. The variables used to close the program are $bExit and $aData[2]: ; $aItems, $aColors and $bExit Local $psaItemsData, $psaColorsData, $bExit = False $aData[2] = DllStructGetPtr( DllStructCreate( $tagVARIANT ) ) AccArrays03( Copy, $aItems, $aColors, $bExit ) The Copy() function that's executed by AccArrays03() copies $bExit to $aData[2] in this way: VariantCopy( $aData[2], $pvExit ) Now $aData[2] is a real windows variant that can be accessed from both AutoIt and C/C++. This means that $aData[2] is a pointer to a variant structure defined by $tagVARIANT. And since it's copied from $bExit which is a boolean (False/True or 0/1), $aData[2] is a variant of type $VT_BOOL: Global Const $tagVARIANT = _ "word vt;" & _ ; 2 bytes, contains the value $VT_BOOL (= 11 = 0x000B) for $aData[2] "word r1;" & _ ; 2 bytes, reserved for Windows "word r2;" & _ ; 2 bytes, reserved for Windows "word r3;" & _ ; 2 bytes, reserved for Windows "ptr data; ptr" ; 8 (32 bit) or 16 (64 bit) bytes data field Because $aData[2] is a boolean variant, only the first two bytes of the data field is used to store the boolean value (usually 0 or 1, but any non-zero value that fits into two bytes can be used instead of 1). And these two bytes are interpreted as a short. That's the Microsoft definition. Because $aData[2] is a pointer to the start of the variant structure, $aData[2] + 8 is a pointer directly to the data field. This means that the value of the data field (the boolean value) can be read this way: $tShort = DllStructCreate( "short", $aData[2] + 8 ) $bValue = DllStructGetData( $tShort, 1 ) Or simply: $bValue = DllStructGetData( DllStructCreate( "short", $aData[2] + 8 ), 1 ) And since $bValue is a boolean (True/False or 1/0 or non-zero/zero) it can simply be tested this way: If $bValue Then ... Or: If DllStructGetData( DllStructCreate( "short", $aData[2] + 8 ), 1 ) Then ... You can read more about variants (and safearrays) in Accessing AutoIt Variables. Now to the error. Replace this line in ListView2.au3: $aData[2] = DllStructGetPtr( DllStructCreate( $tagVARIANT ) ) With these two lines: Local $tVARIANT = DllStructCreate( $tagVARIANT ) $aData[2] = DllStructGetPtr( $tVARIANT ) A structure must be assigned to a variable to prevent the allocated memory to be used for something else. And that was exactly what was happening. When the two bytes given by $aData[2] + 8 were filled with a non-zero value in a very random way, the program immediately closed. If you were lucky. In worst case it would crash with some kind of memory access violation error. 0xC0000005 or something. New zip-file with updated ListView2.au3 in bottom of first post. Danyfirex 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now