Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation since 08/16/2025 in Posts

  1. Jon

    AutoIt v3.3.18.0 Released

    AutoIt v3.3.18.0 has been released - mainly a UDF release. Thanks to @jpm and the MVPs who were responsible for the majority of code in this version. Download it here. Complete list of changes: History
    15 points
  2. Try this: ;Coded by UEZ build 2025-09-06 #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPIConstants.au3> #include <WinAPISysWin.au3> _GDIPlus_Startup() Global Const $STM_SETIMAGE = 0x0172, $SC_DRAGMOVE = 0xF012 Global Const $iW = 300, $iH = $iW Global $hGUI = GUICreate("GDI+ Ring Progressbar", $iW, $iH, -1, -1, $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_LAYERED)) GUISetState() Global $aInterpolations[4][2] ;define the interpolated colors and positions $aInterpolations[0][0] = 3 $aInterpolations[1][0] = 0xFF800000 ;Red $aInterpolations[1][1] = 0 $aInterpolations[2][0] = 0xFFFF6700 ;Orange $aInterpolations[2][1] = 0.5 $aInterpolations[3][0] = 0xFFFFFF00 ;Yellow $aInterpolations[3][1] = 1.0 Global $fPerc = 0, $iSleep = 30 GUIRegisterMsg($WM_TIMER, "PlayAnim") DllCall("user32.dll", "int", "SetTimer", "hwnd", $hGUI, "int", 0, "int", $iSleep, "int", 0) GUIRegisterMsg($WM_LBUTTONDOWN, "WM_LBUTTONDOWN") Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE GUIRegisterMsg($WM_TIMER, "") GUIRegisterMsg($WM_LBUTTONDOWN, "") _GDIPlus_Shutdown() GUIDelete() Exit EndSwitch Until False Func PlayAnim() _GDIPlus_RingProgressbar($fPerc, $iW) $fPerc += 0.33333 If $fPerc > 100 Then $fPerc = 0 EndFunc ;==>PlayAnim Func _GDIPlus_RingProgressbar($fPerc, $iSize = 300, $sText = "Please wait...") Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize) Local Const $hCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetPixelOffsetMode($hCtxt, $GDIP_PIXELOFFSETMODE_HIGHQUALITY) _GDIPlus_GraphicsSetSmoothingMode($hCtxt, 2) If $fPerc < 0 Then $fPerc = 0 If $fPerc > 100 Then $fPerc = 100 Local Const $hPath = _GDIPlus_PathCreate(), _ $fRadius = $iSize / 1.5, $iX = ($iSize - $fRadius) / 2, $iY = ($iSize - $fRadius) / 2, _ $fDX = $iSize / 10, $fAngel = $fPerc * 3.6, $fSize = $iSize / 15 Local Const $hBrush = _GDIPlus_LineBrushCreate($iX, $fDX + $iY, $fRadius, $fRadius, 0, 0, 1) Local Const $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix, $fRadius, $fRadius) _GDIPlus_MatrixRotate($hMatrix, -35, False) _GDIPlus_LineBrushMultiplyTransform($hBrush, $hMatrix, False) _GDIPlus_LineBrushSetPresetBlend($hBrush, $aInterpolations) _GDIPlus_MatrixDispose($hMatrix) Local Const $hPen = _GDIPlus_PenCreate2($hBrush, $fSize) _GDIPlus_PathAddArc($hPath, $iX, $fDX + $iY, $fRadius, $fRadius, -90, $fAngel) _GDIPlus_GraphicsDrawPath($hCtxt, $hPath, $hPen) _GDIPlus_PathReset($hPath) Local Const $hFamily = _GDIPlus_FontFamilyCreate("Verdana") Local Const $hFormat = _GDIPlus_StringFormatCreate() Local Const $tLayout = _GDIPlus_RectFCreate(0, $iSize / 12, $iSize, 0) Local Const $tLayout2 = _GDIPlus_RectFCreate(0, ($iSize + $iSize / 18) / 2, $iSize, 0) _GDIPlus_StringFormatSetAlign($hFormat, 1) Local Const $hBrush2 = _GDIPlus_BrushCreateSolid(0xF0FFFFFF) _GDIPlus_PenSetColor($hPen, 0xF0404040) _GDIPlus_PenSetWidth($hPen, $iSize / 100) _GDIPlus_PenSetLineJoin($hPen, 2) _GDIPlus_PathAddString($hPath, $sText, $tLayout, $hFamily, 0, $iSize / 12, $hFormat) _GDIPlus_PathAddString($hPath, StringFormat("%02d%", $fPerc), $tLayout2, $hFamily, 0, $iSize / 9, $hFormat) _GDIPlus_GraphicsDrawPath($hCtxt, $hPath, $hPen) _GDIPlus_GraphicsFillPath($hCtxt, $hPath, $hBrush2) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_PenDispose($hPen) _GDIPlus_BrushDispose($hBrush) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_PathDispose($hPath) Local $hHBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _WinAPI_BitmapDisplayTransparentInGUI($hHBmp, $hGUI) _GDIPlus_BitmapDispose($hBitmap) _WinAPI_DeleteObject($hHBmp) EndFunc ;==>_GDIPlus_RingProgressbar Func _WinAPI_BitmapDisplayTransparentInGUI(ByRef $hHBitmap, ByRef $hGUI, $iOpacity = 0xFF, $iFlags = $ULW_ALPHA, $bReleaseGDI = True, $tDest = Null, $iBGR = 0) If Not BitAND(GUIGetStyle($hGUI)[1], $WS_EX_LAYERED) = $WS_EX_LAYERED Then Return SetError(1, 0, 0) Local $tDim = DllStructCreate($tagBITMAP) If Not _WinAPI_GetObject($hHBitmap, DllStructGetSize($tDim), DllStructGetPtr($tDim)) Then Return SetError(2, 0, 0) Local $tSize = DllStructCreate($tagSIZE), $tSource = DllStructCreate($tagPOINT), $tBlend = DllStructCreate($tagBLENDFUNCTION) Local Const $hScrDC = _WinAPI_GetDC(0), $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC), $hOld = _WinAPI_SelectObject($hMemDC, $hHBitmap) $tSize.X = $tDim.bmWidth $tSize.Y = $tDim.bmHeight $tBlend.Alpha = $iOpacity $tBlend.Format = 1 _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, $tDest, $tSize, $hMemDC, $tSource, $iBGR, $tBlend, $iFlags) _WinAPI_ReleaseDC(0, $hScrDC) _WinAPI_SelectObject($hMemDC, $hOld) _WinAPI_DeleteDC($hMemDC) If $bReleaseGDI Then _WinAPI_DeleteObject($hHBitmap) Return True EndFunc ;==>_WinAPI_BitmapDisplayTransparentInGUI Func WM_LBUTTONDOWN($hWnd, $iMsg, $wParam, $lParam) _SendMessage($hGUI, $WM_SYSCOMMAND, $SC_DRAGMOVE, 0) EndFunc ;==>WM_LBUTTONDOWN
    7 points
  3. ioa747

    Click & fun

    The work speaks for itself. ; https://www.autoitscript.com/forum/topic/213089-click-fun/#findComment-1545452 ;---------------------------------------------------------------------------------------- ; Title...........: _Explosion.au3 ; Description.....: Simulates an explosion effect on a series of popup windows. ; AutoIt Version..: 3.3.16.1 Author: ioa747 Script Version: 0.3 ; Note............: Testet in Win10 22H2 Date:28/08/2025 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <WindowsConstants.au3> #include <Math.au3> #include <GUIConstantsEx.au3> #include <WinAPIConstants.au3> _Example() Func _Example() Local $hGUI = GUICreate('Fireworks Example', 500, 300) Local $idBtn_Click = GUICtrlCreateButton("Click", 400, 270, 85, 25) Local $idBtn_Close = GUICtrlCreateButton("Close", 300, 270, 85, 25) GUISetState(@SW_SHOW) Local $msg, $aPos While True $msg = GUIGetMsg() Switch $msg Case $GUI_EVENT_CLOSE ; standard window close GUIDelete($hGUI) Sleep(50) $aPos = MouseGetPos() _Explosion($aPos[0] - 250, $aPos[1] + 150, 20) ExitLoop Case $idBtn_Close ; The window will shrink and then explode. $aPos = _Shrink($hGUI) _Explosion($aPos[0], $aPos[1]) ExitLoop Case $idBtn_Click ; explosion at the mouse cursor position. $aPos = MouseGetPos() _Explosion($aPos[0], $aPos[1]) EndSwitch WEnd EndFunc Func _Shrink($hWin, $iSteps = 10) Local $aWPos = WinGetPos($hWin) Local $iCenterX = $aWPos[0] + ($aWPos[2] / 2) Local $iCenterY = $aWPos[1] + ($aWPos[3] / 2) Local $iNewW, $iNewH, $iNewX, $iNewY For $i = 1 To $iSteps $iNewW = $aWPos[2] - ($i * $aWPos[2] / $iSteps) $iNewH = $aWPos[3] - ($i * $aWPos[3] / $iSteps) $iNewX = $aWPos[0] + (($aWPos[2] - $iNewW) / 2) $iNewY = $aWPos[1] + (($aWPos[3] - $iNewH) / 2) WinMove($hWin, '', $iNewX, $iNewY, $iNewW, $iNewH) Sleep(10) Next GUIDelete($hWin) Local $aPos[] = [$iCenterX, $iCenterY] Return $aPos EndFunc Func _Explosion($iX, $iY, $iFragments = 10) Local Const $aColors[5] = [0xFFD800, 0xFFFFFF, 0xD59262, 0x808141, 0x3B3C23] Local $aGUI[$iFragments][7] ; GUICreate For $i = 0 To $iFragments - 1 $aGUI[$i][1] = $iX ; x $aGUI[$i][2] = $iY ; y $aGUI[$i][3] = Random(5, 15, 1) ; w $aGUI[$i][4] = $aGUI[$i][3] ; h $aGUI[$i][5] = Random(15, 25, 1) ; speed $aGUI[$i][6] = $i * (360 / $iFragments); direction (circular) $aGUI[$i][0] = GUICreate('', $aGUI[$i][3], $aGUI[$i][4], $aGUI[$i][1], $aGUI[$i][2], $WS_POPUP, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) GUISetBkColor($aColors[Random(0, UBound($aColors) - 1, 1)]) GUISetState(@SW_SHOWNOACTIVATE) Next While 1 Local $bActive = False For $i = 0 To $iFragments - 1 If WinExists($aGUI[$i][0]) Then $bActive = True Local $fRad = _Radian($aGUI[$i][6]) $aGUI[$i][1] += ($aGUI[$i][5] * Cos($fRad)) $aGUI[$i][2] += ($aGUI[$i][5] * Sin($fRad)) $aGUI[$i][3] -= 1 $aGUI[$i][4] -= 1 $aGUI[$i][5] *= 0.95 WinMove($aGUI[$i][0], '', $aGUI[$i][1], $aGUI[$i][2], $aGUI[$i][3], $aGUI[$i][4]) If $aGUI[$i][3] <= 1 Or $aGUI[$i][4] <= 1 Then GUIDelete($aGUI[$i][0]) EndIf Next If Not $bActive Then ExitLoop Sleep(10) WEnd EndFunc have fun Thank you very much
    7 points
  4. Latest update just released. See below for change log.
    6 points
  5. To break down the performance behavior in more detail: It depends on whether the condition is met or not. The following test script: Global Const $N = 1e7 Global $iT, $f_Overhead ConsoleWrite(@CRLF & " name time" & @CRLF & "--------------------------------------" & @CRLF) ; determine the overhead of loop [and optional other stuff] $iT = TimerInit() For $i = 1 To $N Next $f_Overhead = TimerDiff($iT) $iVariable = 1 $iT = TimerInit() For $i = 1 To $N If $iVariable Then $iVariable = 1 EndIf Next $iT = TimerDiff($iT) ConsoleWrite(StringFormat("% 20s:\t%10.6f ms\n", "If-EndIf True", ($iT-$f_Overhead) / $N)) $iVariable = 0 $iT = TimerInit() For $i = 1 To $N If $iVariable Then $iVariable = 1 EndIf Next $iT = TimerDiff($iT) ConsoleWrite(StringFormat("% 20s:\t%10.6f ms\n", "If-EndIf False", ($iT-$f_Overhead) / $N)) $iVariable = 1 $iT = TimerInit() For $i = 1 To $N If $iVariable Then $iVariable = 1 Next $iT = TimerDiff($iT) ConsoleWrite(StringFormat("% 20s:\t%10.6f ms\n", "If-OneLiner True", ($iT-$f_Overhead) / $N)) $iVariable = 0 $iT = TimerInit() For $i = 1 To $N If $iVariable Then $iVariable = 1 Next $iT = TimerDiff($iT) ConsoleWrite(StringFormat("% 20s:\t%10.6f ms\n", "If-OneLiner False", ($iT-$f_Overhead) / $N)) produces for me: name time -------------------------------------- If-EndIf True: 0.000260 ms If-EndIf False: 0.000161 ms If-OneLiner True: 0.000481 ms If-OneLiner False: 0.000088 ms So it depends on whether the condition is met or not. If it is met, then the classic If-EndIf is faster. If it is not met, the one-liner is faster. When conditions are balanced, their times will be roughly the same. If you can estimate whether the vast majority of conditions are true or false, then you could certainly optimize on that basis. The relative differences are quite significant. But in absolute terms, they are completely subordinated. To put the measured numbers into perspective: we are talking about a difference between 160 nanoseconds and 88 nanoseconds – not milliseconds, not even microseconds! No, nanoseconds! These are therefore overshadowed by any other parts of the code. (unless the script consists purely of millions of consecutive if queries). This decision therefore makes no relevant difference to the overall script. However, this makes the answer for this thread quite straightforward (as the others have already said): which of the two is used is independent of any performance considerations. The decision should be based solely on readability and clarity at the specific code location.
    5 points
  6. If every ounce of performance is really needed, then there are a few areas where optimization can be carried out to squeeze out a little more: #include <WinAPIProc.au3> Global $hUser32 = DllOpen('user32.dll') Global $hKernel32 = DllOpen('kernel32.dll') Global $hpsapi = DllOpen('psapi.dll') ; Run Notepad Run("notepad.exe") ; Wait up to 10 seconds for the Notepad window to appear. WinWait("[CLASS:Notepad]", "", 10) ; Retrieve the handle of the Notepad window using the classname of Notepad. Global $hWnd = WinGetHandle("[CLASS:Notepad]") ConsoleWrite("Notepad handle: " & $hWnd & @CRLF) ConsoleWrite("Notepad process: " & _WinAPI_GetWindowFileName3($hWnd) & @CRLF) ; time comparison Global Const $N = 1e4 Global $iT ConsoleWrite(@CRLF & " name time" & @CRLF & "---------------------------------------------" & @CRLF) ; the first measurement $iT = TimerInit() For $i = 1 To $N _WinAPI_GetWindowFileName($hWnd) Next $iT = TimerDiff($iT) ConsoleWrite(StringFormat("% 30s:\t%10.6f ms\n", "_WinAPI_GetWindowFileName ", ($iT) / $N)) ; the second measurement $iT = TimerInit() For $i = 1 To $N _WinAPI_GetWindowFileName2($hWnd) Next $iT = TimerDiff($iT) ConsoleWrite(StringFormat("% 30s:\t%10.6f ms\n", "_WinAPI_GetWindowFileName2", ($iT) / $N)) ; the third measurement $iT = TimerInit() For $i = 1 To $N _WinAPI_GetWindowFileName3($hWnd) Next $iT = TimerDiff($iT) ConsoleWrite(StringFormat("% 30s:\t%10.6f ms\n", "_WinAPI_GetWindowFileName3", ($iT) / $N)) ; close notepad WinKill($hWnd) Func _WinAPI_GetWindowFileName2($hWnd) Local Static $iNumChars = 512, $tBuff = DllStructCreate(StringFormat("wchar[%d]", $iNumChars)) Local $aCall = DllCall($hUser32, "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0) Local $iPID = $aCall[2] $aCall = DllCall($hKernel32, 'handle', 'OpenProcess', 'dword', 0x00001010, 'bool', 0, 'dword', $iPID) Local $hProc = $aCall[0] DllCall($hpsapi, 'dword', 'GetModuleBaseNameW', 'handle', $hProc, 'handle', 0, 'struct*', $tBuff, 'int', $iNumChars) $aCall = DllCall($hKernel32, "bool", "CloseHandle", "handle", $hProc) Return DllStructGetData($tBuff, 1) EndFunc Func _WinAPI_GetWindowFileName3($hWnd) Local $aCall = DllCall($hKernel32, 'HANDLE', 'OpenProcess', 'DWORD', 0x410, 'BOOL', 0, 'DWORD', WinGetProcess($hWnd)), _ $hProc = $aCall[0] $aCall = DllCall($hpsapi, 'DWORD', 'GetModuleBaseNameW', 'HANDLE', $hProc, 'HANDLE', 0, 'WSTR', '', 'INT', 65536) DllCall($hKernel32, "BOOL", "CloseHandle", "HANDLE", $hProc) Return $aCall[3] EndFunc Otherwise, the solutions presented so far completely lack reasonable error management. And if only this function needs the DLL handles, then the global variables could be bypassed by defining them directly in the function as local static variables instead.
    5 points
  7. I had a dissatisfaction with IsNumber so this function was born: ; ========================================================================================= ; UDF: DataTypeChecker.au3 (strict-hex + numeric formats + IEEE754 + self-test: _RunSelfTest() ) ; Author: Dao Van Trong - TRONG.PRO ; Notes: ; - Type codes start at 1 (String = 1). IEEE-754 subtypes continue up to 24. ; - Unknown returns 0 (no numeric code assigned). ; - String detection order: Hex (0x... or bare even-length [0-9A-Fa-f]) → ; Numeric (US/EU/Thousands/Simple-EU) → Boolean-like → fallback String. ; - HWND is checked before Ptr to avoid misclassification. ; ========================================================================================= ; -------- Global Type Codes (1..24) -------- Global Const $TYPE_STRING = 1 Global Const $TYPE_INT32 = 2 Global Const $TYPE_INT64 = 3 Global Const $TYPE_DOUBLE = 4 Global Const $TYPE_BINARY = 5 Global Const $TYPE_BOOLEAN = 6 Global Const $TYPE_ARRAY = 7 Global Const $TYPE_MAP = 8 Global Const $TYPE_PTR = 9 Global Const $TYPE_STRUCT = 10 Global Const $TYPE_HWND = 11 Global Const $TYPE_OBJECT = 12 Global Const $TYPE_KEYWORD = 13 Global Const $TYPE_FUNCTION = 14 Global Const $TYPE_USERFUNCTION = 15 ; IEEE-754 sub-categories for Double Global Const $TYPE_POS_ZERO = 16 Global Const $TYPE_NEG_ZERO = 17 Global Const $TYPE_DENORMAL_POS = 18 Global Const $TYPE_DENORMAL_NEG = 19 Global Const $TYPE_NORMAL_POS = 20 Global Const $TYPE_NORMAL_NEG = 21 Global Const $TYPE_POS_INFINITY = 22 Global Const $TYPE_NEG_INFINITY = 23 Global Const $TYPE_NAN = 24 ; Unknown uses 0 (no constant) ; -------- Code → Name -------- Func _GetDataTypeName($i) Select Case $i = $TYPE_STRING Return "String" Case $i = $TYPE_INT32 Return "Int32" Case $i = $TYPE_INT64 Return "Int64" Case $i = $TYPE_DOUBLE Return "Double/Float" Case $i = $TYPE_BINARY Return "Binary/Hex" Case $i = $TYPE_BOOLEAN Return "Boolean" Case $i = $TYPE_ARRAY Return "Array" Case $i = $TYPE_MAP Return "Map" Case $i = $TYPE_PTR Return "Pointer" Case $i = $TYPE_STRUCT Return "DLL Struct" Case $i = $TYPE_HWND Return "Window Handle" Case $i = $TYPE_OBJECT Return "Object" Case $i = $TYPE_KEYWORD Return "Keyword" Case $i = $TYPE_FUNCTION Return "Function" Case $i = $TYPE_USERFUNCTION Return "UserFunction" Case $i = $TYPE_POS_ZERO Return "+Zero" Case $i = $TYPE_NEG_ZERO Return "-Zero" Case $i = $TYPE_DENORMAL_POS Return "deNormal (+)" Case $i = $TYPE_DENORMAL_NEG Return "deNormal (−)" Case $i = $TYPE_NORMAL_POS Return "Normal (+)" Case $i = $TYPE_NORMAL_NEG Return "Normal (−)" Case $i = $TYPE_POS_INFINITY Return "+Infinity" Case $i = $TYPE_NEG_INFINITY Return "-Infinity" Case $i = $TYPE_NAN Return "NaN" Case Else Return "Unknown" EndSelect EndFunc ;==>_GetDataTypeName ; -------- IEEE-754 classifier for Double (robust for 64-bit via hi/low dwords) -------- Func _CheckIEEE754Category($dVal) ; Overlay: write the double, then read two dwords at the same address Local $tDouble = DllStructCreate("double") DllStructSetData($tDouble, 1, $dVal) Local $p = DllStructGetPtr($tDouble) Local $tWords = DllStructCreate("dword;dword", $p) ; [1]=low, [2]=high on little-endian Local $low = DllStructGetData($tWords, 1) Local $high = DllStructGetData($tWords, 2) Local $sign = BitAND(BitShift($high, 31), 1) Local $exp = BitAND(BitShift($high, 20), 0x7FF) Local $fracHigh = BitAND($high, 0x000FFFFF) Local $fracLow = $low Local $fracIsZero = ($fracHigh = 0 And $fracLow = 0) If $exp = 0 Then If $fracIsZero Then Return ($sign ? $TYPE_NEG_ZERO : $TYPE_POS_ZERO) Else Return ($sign ? $TYPE_DENORMAL_NEG : $TYPE_DENORMAL_POS) EndIf ElseIf $exp = 0x7FF Then If $fracIsZero Then Return ($sign ? $TYPE_NEG_INFINITY : $TYPE_POS_INFINITY) Else Return $TYPE_NAN EndIf Else Return ($sign ? $TYPE_NORMAL_NEG : $TYPE_NORMAL_POS) EndIf EndFunc ;==>_CheckIEEE754Category ; -------- Decide Int32 vs Int64 by range -------- Func _IntCodeFromNumber($n) If $n >= -2147483648 And $n <= 2147483647 Then Return $TYPE_INT32 Else Return $TYPE_INT64 EndIf EndFunc ;==>_IntCodeFromNumber ; -------- Normalize & classify numeric strings -------- ; Returns: type code (2/3 for ints OR IEEE-754 sub-codes 16..24 for doubles) Func _ParseNumericString($s) ; US: 1,234.56 → remove commas, parse with dot If StringRegExp($s, '^[+-]?\d{1,3}(,\d{3})*(\.\d+)?$') Then Local $u = StringReplace($s, ",", "") If StringInStr($u, ".") Then Return _CheckIEEE754Category(Number($u)) Else ; For grouped integers (US), we follow user's expectation: ; treat as Double category (Normal +/-) rather than Int32/Int64 Return _CheckIEEE754Category(Number($u)) EndIf EndIf ; EU: 1.234,56 → remove dots, replace comma with dot If StringRegExp($s, '^[+-]?\d{1,3}(\.\d{3})*(,\d+)?$') Then Local $e = StringReplace(StringReplace($s, ".", ""), ",", ".") If StringInStr($s, ",") Then Return _CheckIEEE754Category(Number($e)) Else ; Grouped integer (EU) → follow same rule: classify via IEEE-754 Return _CheckIEEE754Category(Number($e)) EndIf EndIf ; Thousands only: 1,234 or 1.234 → strip separators If StringRegExp($s, '^[+-]?\d{1,3}([,\.]\d{3})+$') Then Local $t = StringReplace(StringReplace($s, ",", ""), ".", "") ; Per user's expected results: treat grouped integer as Double category Return _CheckIEEE754Category(Number($t)) EndIf ; Simple EU decimals: 123,45 → replace comma with dot If StringRegExp($s, '^[+-]?\d+,\d+$') Then Local $d = StringReplace($s, ",", ".") Return _CheckIEEE754Category(Number($d)) EndIf ; Plain ints/floats (no separators) If StringIsInt($s) Then Return _IntCodeFromNumber(Number($s)) If StringIsFloat($s) Then Return _CheckIEEE754Category(Number($s)) ; Not numeric Return 0 EndFunc ;==>_ParseNumericString ; -------- Parse strings: Hex → Numeric → Boolean-like → String -------- Func _ParseStringValue($s) $s = StringStripWS($s, 8) ; Hex with prefix 0x, body must have even length If StringRegExp($s, "^0[xX][0-9A-Fa-f]+$") Then Local $hexBody = StringMid($s, 3) If Mod(StringLen($hexBody), 2) = 0 Then Return $TYPE_BINARY EndIf ; Bare hex (0-9 A-F), even length accepted as hex (as requested) If StringRegExp($s, "^[0-9A-Fa-f]+$") Then If Mod(StringLen($s), 2) = 0 Then Return $TYPE_BINARY EndIf ; Numeric formats Local $numCode = _ParseNumericString($s) If $numCode <> 0 Then Return $numCode ; Boolean-like strings Switch StringLower($s) Case "true", "false" Return $TYPE_BOOLEAN EndSwitch ; Fallback string Return $TYPE_STRING EndFunc ;==>_ParseStringValue ; -------- Public: get type code for any value -------- Func _GetDataType($v) ; AutoIt-specific first (order matters) If IsArray($v) Then Return $TYPE_ARRAY If IsMap($v) Then Return $TYPE_MAP If IsHWnd($v) Then Return $TYPE_HWND If IsPtr($v) Then Return $TYPE_PTR If IsDllStruct($v) Then Return $TYPE_STRUCT If IsObj($v) Then Return $TYPE_OBJECT If IsKeyword($v) Then Return $TYPE_KEYWORD Local $sType = VarGetType($v) If IsFunc($v) Then If $sType = "UserFunction" Then Return $TYPE_USERFUNCTION Else Return $TYPE_FUNCTION EndIf EndIf ; Native primitives If $sType = "Int32" Then Return $TYPE_INT32 If $sType = "Int64" Then Return $TYPE_INT64 If $sType = "Double" Then Return _CheckIEEE754Category($v) If IsBinary($v) Then Return $TYPE_BINARY If IsBool($v) Then Return $TYPE_BOOLEAN ; Strings If IsString($v) Then Return _ParseStringValue($v) ; Unknown Return 0 EndFunc ;==>_GetDataType ; -------- Helper: is any numeric type? (native or string-based) -------- Func _IsNumber($v) Local $c = _GetDataType($v) Return ($c = $TYPE_INT32 Or $c = $TYPE_INT64 Or $c = $TYPE_DOUBLE Or _ $c = $TYPE_POS_ZERO Or $c = $TYPE_NEG_ZERO Or _ $c = $TYPE_DENORMAL_POS Or $c = $TYPE_DENORMAL_NEG Or _ $c = $TYPE_NORMAL_POS Or $c = $TYPE_NORMAL_NEG Or _ $c = $TYPE_POS_INFINITY Or $c = $TYPE_NEG_INFINITY Or _ $c = $TYPE_NAN) EndFunc ;==>_IsNumber ; ========================================================================================= ; SELF-TEST (English logs, prefixes: '+' OK, '!' ERROR, '-' INFO) ; ========================================================================================= Func _AddTest(ByRef $arr, $val, $expectedName, $label) ReDim $arr[UBound($arr) + 1][3] $arr[UBound($arr) - 1][0] = $val $arr[UBound($arr) - 1][1] = $expectedName $arr[UBound($arr) - 1][2] = $label EndFunc ;==>_AddTest Func __TestFunc() Return 1 EndFunc ;==>__TestFunc Func _RunSelfTest() ConsoleWrite("- Starting self-test..." & @CRLF) Local $tests[0][3] ; --- String fallback --- _AddTest($tests, "Hello", "String", "Plain string") ; Per requirement: bare [0-9A-F] with even length is HEX _AddTest($tests, "123ABC", "Binary/Hex", "Bare hex (even)") ; --- Int32 / Int64 --- _AddTest($tests, 42, "Int32", "Integer") _AddTest($tests, -999, "Int32", "Negative int") _AddTest($tests, 9223372036854775807, "Int64", "Max Int64") _AddTest($tests, -9223372036854775808, "Int64", "Min Int64") ; --- Double / IEEE754 normal --- _AddTest($tests, 3.14159, "Normal (+)", "Positive double") _AddTest($tests, -2.71828, "Normal (−)", "Negative double") ; --- Binary/Hex --- _AddTest($tests, "0x1A2B", "Binary/Hex", "Prefixed hex string") _AddTest($tests, "DEADBEEF", "Binary/Hex", "Bare hex string") ; --- Boolean --- _AddTest($tests, True, "Boolean", "True literal") _AddTest($tests, "false", "Boolean", "Boolean-like string") ; --- Array --- Local $arr[2] = [1, 2] _AddTest($tests, $arr, "Array", "Simple array") ; --- Map (correct syntax) --- Local $mMap[] $mMap["Key"] = "Value" _AddTest($tests, $mMap, "Map", "Map object") ; --- Ptr --- Local $p = Ptr(0x123456) _AddTest($tests, $p, "Pointer", "Pointer value") ; --- DllStruct --- Local $st = DllStructCreate("int;char[4]") _AddTest($tests, $st, "DLL Struct", "DllStruct sample") ; --- HWND (create GUI to ensure valid handle) --- Local $hGUI = GUICreate("DT Test", 1, 1, -100, -100) GUISetState(@SW_SHOW, $hGUI) _AddTest($tests, $hGUI, "Window Handle", "GUI handle") ; --- Object --- Local $o = ObjCreate("Scripting.Dictionary") _AddTest($tests, $o, "Object", "COM object") ; --- Keyword --- _AddTest($tests, Default, "Keyword", "Keyword Default") _AddTest($tests, Null, "Keyword", "Keyword Null") ; --- Function & UserFunction --- _AddTest($tests, Eval, "Function", "Builtin function") _AddTest($tests, __TestFunc, "UserFunction", "User-defined function") ; --- IEEE754 specials --- _AddTest($tests, +0.0, "+Zero", "Positive zero") _AddTest($tests, -0.0, "-Zero", "Negative zero") _AddTest($tests, (1.0 / 0.0), "+Infinity", "Positive infinity") _AddTest($tests, (-1.0 / 0.0), "-Infinity", "Negative infinity") _AddTest($tests, (0.0 / 0.0), "NaN", "Not-a-Number") ; --- Numeric strings: US/EU/Thousands/Simple-EU --- _AddTest($tests, "1,234.56", "Normal (+)", "US numeric string") _AddTest($tests, "1.234,56", "Normal (+)", "EU numeric string") _AddTest($tests, "1,234", "Normal (+)", "Thousand separator comma") _AddTest($tests, "1.234", "Normal (+)", "Thousand separator dot") _AddTest($tests, "123,45", "Normal (+)", "EU decimal comma") ; --- Run all --- For $i = 0 To UBound($tests) - 1 Local $input = $tests[$i][0] Local $expected = $tests[$i][1] Local $label = $tests[$i][2] Local $code = _GetDataType($input) Local $got = _GetDataTypeName($code) If $got = $expected Then ConsoleWrite("- " & '_IsNumber(' & $input & ") -> " & _IsNumber($input) & @CRLF) ConsoleWrite("+ " & $label & ' "' & $input & '" -> (' & $code & ') ' & $got & @CRLF) Else ConsoleWrite("! " & $label & ' "' & $input & '" -> (' & $code & ') ' & $got & " | Expected: " & $expected & @CRLF) EndIf Next ConsoleWrite("- Self-test complete." & @CRLF) ; Clean up GUI created for HWND test GUIDelete($hGUI) EndFunc ;==>_RunSelfTest ; ========================================================================================= ; Self-test routine: kiểm tra các giá trị mẫu và in PASS/FAIL ; ========================================================================================= Func _RunSelfTest2() Local $tests = [ _ ["String literal", "Hello", $TYPE_STRING], _ ["Int32 literal", 123, $TYPE_INT32], _ ["Int64 literal", 5000000000, $TYPE_INT64], _ ["Double normal +", 3.14, $TYPE_NORMAL_POS], _ ["Double normal −", -2.5, $TYPE_NORMAL_NEG], _ ["+Zero (double)", 0.0, $TYPE_POS_ZERO], _ ["-Zero (double)", -0.0, $TYPE_NEG_ZERO], _ ["Subnormal", Number("1e-320"), $TYPE_DENORMAL_POS], _ ["+Infinity", 1 / 0, $TYPE_POS_INFINITY], _ ["-Infinity", -1 / 0, $TYPE_NEG_INFINITY], _ ["NaN", 0 / 0, $TYPE_NAN], _ ["Hex 0x…", "0x1A2B", $TYPE_BINARY], _ ["Bare hex", "FACE", $TYPE_BINARY], _ ["US number", "1,234.56", $TYPE_NORMAL_POS], _ ["EU number", "1.234,56", $TYPE_NORMAL_POS], _ ["Thou only", "1,234", $TYPE_NORMAL_POS], _ ["Simple EU dec", "123,45", $TYPE_NORMAL_POS], _ ["Bool-like true", "true", $TYPE_BOOLEAN], _ ["Bool-like false", "false", $TYPE_BOOLEAN] _ ] Local $allOK = True ConsoleWrite(@CRLF & "---- Running DataTypeChecker Self-Test ----" & @CRLF) For $i = 0 To UBound($tests) - 1 Local $desc = $tests[$i][0] Local $val = $tests[$i][1] Local $exp = $tests[$i][2] Local $got = _GetDataType($val) Local $name = _GetDataTypeName($got) If $got = $exp Then ConsoleWrite("- _IsNumber(" & $val & ') -> ' & _IsNumber($val) & @CRLF) ConsoleWrite("+ PASS: " & $desc & ' "' & $val & '" -> ' & $name & " (" & $got & ")" & @CRLF) Else ConsoleWrite("! FAIL: " & $desc & ' "' & $val & '" -> Expected ' & _ _GetDataTypeName($exp) & " (" & $exp & "), Got " & _ $name & " (" & $got & ")" & @CRLF) $allOK = False EndIf Next ConsoleWrite("---- Self-Test " & ($allOK ? "+ PASSED" : "! FAILED") & " ----" & @CRLF & @CRLF) Return $allOK EndFunc ;==>_RunSelfTest2 ; Uncomment to run self-test on execute ; _RunSelfTest() ; _RunSelfTest2()
    5 points
  8. I compiled Zint v2.15.09 source and it has 30 functions! ZBarcode_BarcodeName|0x0001CBA0 ZBarcode_Buffer|0x0001CC20 ZBarcode_Buffer_Vector|0x0001CC60 ZBarcode_Cap|0x0001CCA0 ZBarcode_Clear|0x0001D270 ZBarcode_Create|0x0001D390 ZBarcode_Default_Xdim|0x0001D3C0 ZBarcode_Delete|0x0001D5D0 ZBarcode_Dest_Len_ECI|0x0001D630 ZBarcode_Encode|0x0001D6D0 ZBarcode_Encode_File|0x0001D710 ZBarcode_Encode_File_and_Buffer|0x0001DB00 ZBarcode_Encode_File_and_Buffer_Vector|0x0001DB50 ZBarcode_Encode_File_and_Print|0x0001DBA0 ZBarcode_Encode_Segs|0x0001DBE0 ZBarcode_Encode_Segs_and_Buffer|0x0001E890 ZBarcode_Encode_Segs_and_Buffer_Vector|0x0001E8F0 ZBarcode_Encode_Segs_and_Print|0x0001E950 ZBarcode_Encode_and_Buffer|0x0001E990 ZBarcode_Encode_and_Buffer_Vector|0x0001EA10 ZBarcode_Encode_and_Print|0x0001EA90 ZBarcode_HaveGS1SyntaxEngine|0x0001EAF0 ZBarcode_NoPng|0x0001EB00 ZBarcode_Print|0x0001EB10 ZBarcode_Reset|0x0001EC30 ZBarcode_Scale_From_XdimDp|0x0001ECA0 ZBarcode_UTF8_To_ECI|0x0001EE80 ZBarcode_ValidID|0x0001EF40 ZBarcode_Version|0x0001EF80 ZBarcode_XdimDp_From_Scale|0x0001EF90 I will update the code in the next days. I compiled also a x64 Zint DLL but I don't know if it is working yet...
    4 points
  9. You may have a look here: Or here (old):
    4 points
  10. Hey mate, Yeah so there's a bit you can do.. _WinAPI_GetWindowFileName calls a few things, which we can streamline if we're planning to call it 10000 times,. Func _WinAPI_GetWindowFileName($hWnd) Local $iPID = 0 Local $aCall = DllCall("user32.dll", "bool", "IsWindow", "hwnd", $hWnd) If $aCall[0] Then $aCall = DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0) $iPID = $aCall[2] EndIf If Not $iPID Then Return SetError(1, 0, '') Local $sResult = _WinAPI_GetProcessFileName($iPID) If @error Then Return SetError(@error, @extended, '') Return $sResult EndFunc Func _WinAPI_GetProcessFileName($iPID = 0) If Not $iPID Then $iPID = @AutoItPID Local $hProcess = DllCall('kernel32.dll', 'handle', 'OpenProcess', 'dword', ((_WinAPI_GetVersion() < 6.0) ? 0x00000410 : 0x00001010), _ 'bool', 0, 'dword', $iPID) If @error Or Not $hProcess[0] Then Return SetError(@error + 20, @extended, '') Local $sPath = _WinAPI_GetModuleFileNameEx($hProcess[0]) Local $iError = @error DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hProcess[0]) If $iError Then Return SetError(@error, 0, '') Return $sPath EndFunc Func _WinAPI_GetModuleFileNameEx($hProcess, $hModule = 0) Local $aCall = DllCall(@SystemDir & '\psapi.dll', 'dword', 'GetModuleFileNameExW', 'handle', $hProcess, 'handle', $hModule, _ 'wstr', '', 'int', 4096) If @error Or Not $aCall[0] Then Return SetError(@error + 10, @extended, '') Return $aCall[3] EndFunc Firstly I'd be using dll handles with DllOpen instead of using file names in DllCall, this should save open/closing Dlls all the time! That IsWindow call in GetWindowFilename is there as a sanity check. So if you're reasonably happy that you won't sent it rubbish, that can go. GetVersion doesn't need to be called 10000 times. 6.0 is Vista, so we probably don't really care about this anymore... but if you do - just call GetVersion once before your loop, or store it as a static or something. Use GetModuleBaseNameW instead of GetModuleFileNameExW - that will get you just the "notepad.exe" part of the process name We don't need to allocate the string buffer and free it 10000 times either (assuming the func returns a null-terminated string). Create a buffer once beforehand and just reuse it. #include <WinAPISysWin.au3> #include <WinAPIProc.au3> #include <Array.au3> #include <WinAPISys.au3> #include <File.au3> Global $maxruns = 10000 Global $hUser32 = DllOpen('user32.dll') Global $hKernel32 = DllOpen('kernel32.dll') Global $hpsapi = DllOpen('psapi.dll') ; Run Notepad Run("notepad.exe") ; Wait 10 seconds for the Notepad window to appear. WinWait("[CLASS:Notepad]", "", 10) Global $iPID = ProcessExists("notepad.exe") ; Retrieve the handle of the Notepad window using the classname of Notepad. Global $hWnd = WinGetHandle("[CLASS:Notepad]") ConsoleWrite("Notepad handle: " & $hWnd & @CRLF) Example3() Func Example3() Local $hTimer = TimerInit() For $i = 1 To $maxruns Local $test = _WinAPI_GetWindowFileName2($hWnd) Next Local $fDiff = TimerDiff($hTimer) ConsoleWrite("Timer: " & $fDiff & @CRLF) ConsoleWrite("_WinAPI_GetWindowFileName: " & $test & @CRLF) EndFunc Func _WinAPI_GetWindowFileName2($hWnd) Local Static $iNumChars = 512, $tBuff = DllStructCreate(StringFormat("wchar[%d]", $iNumChars)) Local $aCall = DllCall($hUser32, "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0) Local $iPID = $aCall[2] $aCall = DllCall($hKernel32, 'handle', 'OpenProcess', 'dword', 0x00001010, 'bool', 0, 'dword', $iPID) Local $hProc = $aCall[0] DllCall($hpsapi, 'dword', 'GetModuleBaseNameW', 'handle', $hProc, 'handle', 0, 'struct*', $tBuff, 'int', $iNumChars) $aCall = DllCall($hKernel32, "bool", "CloseHandle", "handle", $hProc) Return DllStructGetData($tBuff, 1) EndFunc Obviously you'll want to put some error checks back in, and clean up when you're done.. but you get the idea Edit: and the time comparison.. Notepad handle: 0x00000000005B0D40 Timer: 548.97 _WinAPI_GetWindowFileName2: Notepad.exe Timer: 1794.9062 _WinAPI_GetWindowFileName: C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2507.26.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe
    4 points
  11. 💡 Did You Know AutoIt’s Truthiness Rules Can Surprise You? Or that empty strings are False but "0" (as a string) is True? Or that Not $variable doesn’t work the way you might think? 🔍 Understanding Logical Expression Evaluation in AutoIt When working with AutoIt, one of the subtle but important differences compared to languages like C, JavaScript, or Python is how logical expressions are evaluated. 👉 AutoIt does not have a dedicated Boolean type. Instead, it uses other values (strings, numbers, etc.) and interprets them as True or False. This article breaks down AutoIt’s “truthiness rules” and explains what Not $variable really means. 1️⃣ No Boolean Type in AutoIt Unlike many languages, AutoIt does not define a bool type. Instead: Strings and numbers are interpreted as logical values. A function or expression that “returns True/False” is really returning an integer (1 or 0). 2️⃣ Truthiness Rules When AutoIt evaluates a value in a conditional (If, While, etc.): "" (empty string) → False 0 (number) → False Any non-empty string → True Any non-zero number → True ✅ Examples: If "" Then MsgBox(0, "Test", "This will NOT show") ; False If "hello" Then MsgBox(0, "Test", "This WILL show") ; True If 0 Then MsgBox(0, "Test", "This will NOT show") ; False If -1 Then MsgBox(0, "Test", "This WILL show") ; True 3️⃣ What Does Not $variable Do? The Not operator simply inverts the truthiness of a value. ConsoleWrite(Not "" & @CRLF) ; 1 (True) ConsoleWrite(Not "abc" & @CRLF) ; 0 (False) ConsoleWrite(Not 0 & @CRLF) ; 1 (True) ConsoleWrite(Not 123 & @CRLF) ; 0 (False) 👉 In plain: Not $variable is like asking “is this variable empty or zero?” 4️⃣ Real Example: _PathFull UDF In the standard UDF File.au3, the function _PathFull has this line: If Not $sRelativePath Or $sRelativePath = "." Then Return $sBasePath This handles two cases: $sRelativePath is "" → return the base path. $sRelativePath is "." → return the base path (current directory). 💡 This works because AutoIt treats an empty string as False. 5️⃣ Common Pitfalls ❌ Pitfall 1: Expecting False to exist Local $x = False If $x Then MsgBox(0, "Result", "Will this show?") ; False is just 0, there’s no real Boolean type. ❌ Pitfall 2: Forgetting that "0" (string) is True If "0" Then MsgBox(0, "Result", "This WILL show!") ; Non-empty string = True ; But numeric 0 would be False. ❌ Pitfall 3: Misunderstanding Not Local $val = "hello" If Not $val Then MsgBox(0, "Result", "Will this show?") ; Never runs because "hello" = True EndIf ✅ Key Takeaways AutoIt has no Boolean type — just numbers and strings used as truth values. "" (empty string) and 0 (numeric) = False. Everything else = True. "0" (string) = True, but 0 (number) = False. Not $var = “is this variable empty or zero?”. 📝 Conclusion Understanding AutoIt’s truthiness rules is essential for writing reliable conditions. They make scripts concise, but can be surprising if you expect strict Boolean behavior. 👉 Pro Tip: Use AutoIt’s implicit truthiness for quick checks, but when clarity matters, be explicit: Use StringLen() to check if a string is empty. Don't use IsNumber() if you don't understand it, read more here. Use comparisons (=, <>) for precise logic. That way, your intent is clear, and you avoid bugs caused by AutoIt’s flexible but tricky truth rules. 💬 Final Note: If I’ve misunderstood or explained something incorrectly, please share your thoughts — I’d be happy to update and improve this article!
    3 points
  12. What exactly leads you to this conclusion? This cannot be deduced from your following text. All of this can be explained perfectly by the fact that there are specific rules for converting other data types to the Boolean data type. There is nothing explicitly against the existence of a corresponding dedicated Boolean data type. Nope - if that were the case, they would behave exactly the same way - but they don't: ConsoleWrite("compare with int type: " & ("0" = retInt() ? True : False) & @CRLF) ConsoleWrite("compare with bool type: " & ("0" = retBool() ? True : False) & @CRLF) Func retInt() Return 1 EndFunc Func retBool() Return True EndFunc The following are also converted to False during conversion to Boolean: Global $aArray[1] Global $mMap[] If $aArray Then MsgBox(0, "", "Array = True") If $mMap Then MsgBox(0, "", "Map = True") If ObjCreate("Scripting.Dictionary") Then MsgBox(0, "", "Object = True") If Default Then MsgBox(0, "", "Default = True") If Ptr(0x0) Then MsgBox(0, "", "Ptr(0) = True") If DllStructCreate("CHAR[1]") Then MsgBox(0, "", "DllStruct = True") If ConsoleWrite Then MsgBox(0, "", "Function pointer = True") Basically, this discussion only touches superficially on logical expressions in AutoIt. In fact, the behavior is only a consequence of the real topic: Implicit data type conversions in AutoIt: AutoIt (like many other languages) is a dynamically typed language. In other words, variables do not have a fixed data type; instead, this can be changed at will during the lifetime of the variable. Nevertheless, variables can be linked together as desired using operators. But internally, at the machine level, only identical data types can be linked together. For example, addition is only possible between two Int32s and not between a Double and an Int32, etc. Therefore, one task of the AutoIt interpreter in operations with multiple operands or when the operation requires a specific target data type is to align the different data types with each other. AutoIt defines fixed rules for how certain data types are converted into others. Integers, for example, are converted to floats by considering the value as the integer part of the resulting float. How exactly certain data types are converted to the Boolean data type (yes, Boolean is explicitly listed as a separate data type) is described in part in the >>AutoIt help<<. Specifically, it says the following, for example: This explains exactly the behavior you described above. And we're not even talking about logical expressions yet - it's just about implicit data type conversion. If you keep in mind that logical operators and the if branch must have the expression as a Boolean, it quickly becomes clear that this is not actually about the behavior of logical expressions, but rather that they are only a consequence of the implicit data type conversion of other data types to the Boolean data type. In summary: The behavior described above describes the effects of implicit conversion of other data types to the Boolean data type. Everything described can be explained completely by this. However, I do not see the slightest indication in the description that AutoIt should not have a dedicated boolean data type.
    3 points
  13. Trong

    Windows Version Detector

    UDF: #include-once ; #INDEX# ======================================================================================================================= ; Title ..........: Windows Version Detector UDF v5 ; AutoIt Version .: 3.3.16.1+ ; Language .......: English ; Description ...: This User Defined Function (UDF) detects Windows versions for both live (running) and offline (mounted or extracted) Windows installations. ; It uses a dual-database approach: an exact build database for precise matches and a range-based inference database for broader version identification. ; The UDF supports Windows from version 1.0 up to Windows Server 2025, including client and server editions, Insider previews, and various builds. ; Key features include registry reading for live systems, offline hive loading for mounted images, and file-based fallback detection. ; Author(s) ......: Dao Van Trong - TRONG.PRO ; Version ........: 3.8.1 (Updated for consistent official version names like 2004; Enhanced with full UDF headers and inline comments) ; Dll(s) .........: kernel32.dll, advapi32.dll, ole32.dll ; =============================================================================================================================== ; #INCLUDES# ==================================================================================================================== #include <FileConstants.au3> ; For file operations like $OPEN_EXISTING, $FILE_SHARE_READ, $GENERIC_READ #include <APIRegConstants.au3> ; For registry constants like $HKEY_LOCAL_MACHINE #include <APIErrorsConstants.au3> ; For error codes like $ERROR_SUCCESS #include <StringConstants.au3> ; For string manipulation constants like $STR_STRIPLEADING, $STR_STRIPTRAILING, $STR_NOCOUNT #include <Array.au3> ; For array functions like _ArrayToString (though custom implementation used here for compatibility) ; =============================================================================================================================== ; #CONSTANTS# ==================================================================================================================== ; Registry paths and system constants Global Const $REG_KEY_VERSION = "SOFTWARE\Microsoft\Windows NT\CurrentVersion" ; Main registry key for Windows version info Global Const $REG_KEY_INSIDER = "SOFTWARE\Microsoft\WindowsSelfHost\Applicability" ; Registry key for Insider preview detection Global Const $HIVE_SOFTWARE = "\System32\Config\SOFTWARE" ; Path to SOFTWARE hive file for offline detection Global Const $MAX_PATH = 32767 ; Maximum path length for Windows API calls Global Const $SE_BACKUP_PRIVILEGE = "SeBackupPrivilege" ; Privilege required to load/unload registry hives ; Static version databases (initialized at compile time) ; Range DB structure: [MinBuild, MaxBuild, ProductName] - Used for inferring versions when exact match fails Global Const $_g_aWinVerRangeDB = __WinVerDetect_InitWindowsVersionDB() ; Exact DB structure: [ProductName, Codename, ReleaseDate, DisplayVersion, Build, UBR] - For precise version matching Global Const $_g_aWinVerExactDB = __WinVerDetect_InitExactWindowsVersionDB() ; Edition mappings array Global Const $g_aEditionMap = __WinVerDetect_InitEditionMap() ; =============================================================================================================================== ; #ENUMS# ======================================================================================================================= ; Enum for return array indices from _WinVerDetect_GetVersion (when $iReturn = -1) Global Enum $WINVER_STATE, _ ; 0: "Live" or "Offline" indicating if the system is running or not $WINVER_SHORTNAME, _ ; 1: Short OS identifier (e.g., "WIN_10", "WIN_11", "WIN_SRV") $WINVER_PRODUCTNAME, _ ; 2: Full product name (e.g., "Windows 10", "Windows Server 2022") $WINVER_FULLNAME, _ ; 3: Full version name (e.g., "Windows 10 Version 22H2 (Build 19045)") $WINVER_BUILD, _ ; 4: Major build number (e.g., "19045") $WINVER_UBR, _ ; 5: Update Build Revision (e.g., "4567") $WINVER_DISPLAYVERSION, _ ; 6: Display version string (e.g., "22H2", "2004") $WINVER_EDITIONID, _ ; 7: Edition ID (e.g., "Professional", "Enterprise", "Server") $WINVER_EDITIONTYPE, _ ; 8: Inferred edition type (e.g., "Professional") $WINVER_ISINSIDER ; 9: Boolean (True if Insider Preview) ; Enum for error codes returned by @error in _WinVerDetect_GetVersion Global Enum $WINVER_ERROR_SUCCESS, _ ; 0: No error $WINVER_ERROR_INVALID_PATH, _ ; 1: Invalid or non-existent Windows path $WINVER_ERROR_REGISTRY_FAILED, _ ; 2: Failed to read registry (live or offline) $WINVER_ERROR_FILE_ACCESS, _ ; 3: File access denied or files not found $WINVER_ERROR_NO_ADMIN, _ ; 4: Admin privileges required for live/offline operations $WINVER_ERROR_INVALID_BUILD ; 5: Invalid or unrecognized build number ; =============================================================================================================================== ; #VARIABLES# ==================================================================================================================== ; No global variables beyond constants; all data is in static arrays for efficiency ; =============================================================================================================================== ; #FUNCTIONS# ==================================================================================================================== ; Public Functions ; _WinVerDetect_GetVersion ; _RegReadMulti ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name ..........: _WinVerDetect_GetVersion ; Description ...: Detects detailed Windows version information from a live or offline Windows installation path. ; Supports both running systems (live) and mounted/extracted images (offline). For live systems, requires admin privileges. ; Returns an array with version details or a specific index if requested. Uses registry for precise info, falls back to file versions. ; Syntax ........: _WinVerDetect_GetVersion([$sWindowsPath = @WindowsDir[, $iReturn = -1]]) ; Parameters ....: $sWindowsPath - String: Path to Windows directory (default: @WindowsDir for live system) ; $iReturn - Integer: Index of array element to return (default: -1 for full array) ; Return values .: Success - If $iReturn = -1: Array[10] with version info as per $WINVER_* enums ; | If $iReturn >= 0: String value from the specified array index ; Failure - Sets @error to one of $WINVER_ERROR_* codes, returns empty array/string ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Enhanced documentation and error handling ; Remarks .......: - For offline detection without admin: Falls back to file-based inference (less accurate). ; | - Builds and UBR are integers as strings for consistency. ; | - IsInsider detection checks for Insider Preview rings. ; Related .......: _RegReadMulti, __WinVerDetect_LiveVersion, __WinVerDetect_OfflineVersion, __WinVerDetect_FromFiles ; Example .......: #include "Windows Version Detector v5.au3" ; Local $aInfo = _WinVerDetect_GetVersion() ; If Not @error Then ConsoleWrite("OS: " & $aInfo[$WINVER_PRODUCTNAME] & @CRLF) ; =============================================================================================================================== Func _WinVerDetect_GetVersion($sWindowsPath = @WindowsDir, $iReturn = -1) ; Initialize result array with defaults (empty strings and False for boolean) Local $aResult[10] = ["", "", "", "", "", "", "", "", "", False] ; Normalize the input path to handle long paths and ensure consistency Local $sPath = __WinVerDetect_NormalizePath($sWindowsPath) ; Validate if the path points to a valid Windows installation If Not __WinVerDetect_IsValidWindowsPath($sPath) Then Return SetError($WINVER_ERROR_INVALID_PATH, 0, ($iReturn = -1) ? $aResult : $aResult[$iReturn]) EndIf ; Determine if this is a live (running) system or offline installation $aResult[$WINVER_STATE] = __WinVerDetect_IsSystemLive($sPath) ? "Live" : "Offline" ; Process based on live/offline status If $aResult[$WINVER_STATE] = "Live" Then ; For live systems, require admin privileges If Not IsAdmin() Then Return SetError($WINVER_ERROR_NO_ADMIN, 0, ($iReturn = -1) ? $aResult : $aResult[$iReturn]) EndIf ; Read from live registry $aResult = __WinVerDetect_LiveVersion($sPath) Else ; For offline, attempt registry hive load if admin, else fallback to files If IsAdmin() Then $aResult = __WinVerDetect_OfflineVersion($sPath) Else $aResult = __WinVerDetect_FromFiles($sPath) EndIf EndIf ; Propagate errors from internal functions If @error Then Return SetError(@error, @extended, ($iReturn = -1) ? $aResult : $aResult[$iReturn]) EndIf ; Fill in any missing information using the version databases $aResult = __WinVerDetect_FillMissingInfo($aResult) ; Return full array or specific index Return ($iReturn = -1) ? $aResult : $aResult[$iReturn] EndFunc ;==>_WinVerDetect_GetVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: _RegReadMulti ; Description ...: Reads multiple registry values from a single key, supporting array input, delimited strings, or single values. ; Handles errors gracefully, returning defaults for missing values. Useful for batch registry reads in version detection. ; Syntax ........: _RegReadMulti($sKey, $vFields[, $sDefault = ""[, $sSplitChar = "|"[, $sJoinChar = "|"[, $bReturnArray = False]]]]) ; Parameters ....: $sKey - String: Registry key path (e.g., "HKLM\SOFTWARE\...") ; $vFields - Variant: Array of value names, delimited string (e.g., "Value1|Value2"), or single string ; $sDefault - String: Default value if read fails (default: "") ; $sSplitChar - String: Delimiter for splitting $vFields if string (default: "|") ; $sJoinChar - String: Delimiter for joining results if not returning array (default: "|") ; $bReturnArray- Boolean: True to return array, False to return joined string (default: True) ; Return values .: Success - Array if $bReturnArray=True, joined string otherwise ; Failure - Sets @error: 1=Invalid key, 2=Empty fields, 3=Parse error; @extended=Number of values processed ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added comprehensive error handling and documentation ; Remarks .......: - Strips whitespace from field names. ; | - Tracks the highest error code for partial failures. ; Related .......: RegRead (built-in) ; Example .......: Local $aValues = _RegReadMulti("HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion", ["ProductName", "BuildLab"], "", "|", True) ; =============================================================================================================================== Func _RegReadMulti($sKey, $vFields, $sDefault = "", $sSplitChar = "|", $sJoinChar = "|", $bReturnArray = True) Local $aNames, $iErrorCode = 0, $iExtended = 0 ; Track errors Local $aDefaultResult[1] = [$sDefault] ; Fallback for empty fields ; Parse $vFields: Handle array, delimited string, or single value If IsArray($vFields) Then If UBound($vFields) > 0 Then $aNames = $vFields ; Direct array Else $aNames = $aDefaultResult $iErrorCode = 3 ; Empty array $iExtended = 1 EndIf Else If $vFields = "" Then $aNames = $aDefaultResult $iErrorCode = 2 ; Empty string $iExtended = 1 ElseIf $sSplitChar <> "" And StringInStr($vFields, $sSplitChar) Then ; Split delimited string $aNames = StringSplit($vFields, $sSplitChar, $STR_NOCOUNT) If UBound($aNames) > 0 Then ; Strip whitespace from each name For $i = 0 To UBound($aNames) - 1 $aNames[$i] = StringStripWS($aNames[$i], $STR_STRIPLEADING + $STR_STRIPTRAILING) Next Else $aNames = $aDefaultResult $iErrorCode = 3 $iExtended = 1 EndIf Else ; Single value as array Local $aTmp[1] = [StringStripWS($vFields, $STR_STRIPLEADING + $STR_STRIPTRAILING)] $aNames = $aTmp EndIf EndIf ; Initialize result array Local $aResult[UBound($aNames)] If $sKey = "" Then ; No key: Fill with defaults For $i = 0 To UBound($aResult) - 1 $aResult[$i] = $sDefault Next If $iErrorCode = 0 Then $iErrorCode = 1 ; Invalid key $iExtended = UBound($aResult) Else ; Read each value from registry For $i = 0 To UBound($aNames) - 1 Local $sValue = RegRead($sKey, $aNames[$i]) If @error Then $sValue = $sDefault ; Track highest error $iErrorCode = (@error > $iErrorCode) ? @error : $iErrorCode $iExtended = (@extended > $iExtended) ? @extended : $iExtended EndIf $aResult[$i] = $sValue Next EndIf ; Return array or joined string Return SetError($iErrorCode, $iExtended, $bReturnArray ? $aResult : __WinVerDetect_ArrayToString($aResult, $sJoinChar)) EndFunc ;==>_RegReadMulti ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name...........: Internal Functions ; Description ...: These functions are for internal use by the UDF and should not be called directly. ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetShortName ; Description ...: Infers a short OS identifier (e.g., "WIN_10") from the full product name. Used for standardized OS classification. ; Syntax ........: __WinVerDetect_GetShortName($sProductName) ; Parameters ....: $sProductName - String: Full product name (e.g., "Windows 10", "Windows Server 2022") ; Return values .: Success - String: Short identifier (e.g., "WIN_10", "WIN_SRV") ; Failure - "UNKNOWN" if no match ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added inline comments for priority matching ; Remarks .......: - Prioritizes server versions first, then client. ; | - Case-insensitive matching using StringLower. ; Related .......: _WinVerDetect_GetVersion ; =============================================================================================================================== Func __WinVerDetect_GetShortName($sProductName) Local $sLower = StringLower($sProductName) ; Convert to lowercase for case-insensitive matching ; Prioritize server versions (check for "server" keyword first) If StringInStr($sLower, "server") Then If StringInStr($sLower, "2025") Then Return "WIN_2025" ; Windows Server 2025 If StringInStr($sLower, "2022") Then Return "WIN_2022" ; Windows Server 2022 If StringInStr($sLower, "2019") Then Return "WIN_2019" ; Windows Server 2019 If StringInStr($sLower, "2016") Then Return "WIN_2016" ; Windows Server 2016 If StringInStr($sLower, "2012 r2") Then Return "WIN_2012R2" ; Windows Server 2012 R2 If StringInStr($sLower, "2012") Then Return "WIN_2012" ; Windows Server 2012 If StringInStr($sLower, "2008 r2") Then Return "WIN_2008R2" ; Windows Server 2008 R2 If StringInStr($sLower, "2008") Then Return "WIN_2008" ; Windows Server 2008 If StringInStr($sLower, "2003 r2") Then Return "WIN_2003R2" ; Windows Server 2003 R2 If StringInStr($sLower, "2003") Then Return "WIN_2003" ; Windows Server 2003 Return "WIN_SRV" ; Generic server fallback EndIf ; Client versions (check in descending order for accuracy) If StringInStr($sLower, "windows 11") Then Return "WIN_11" If StringInStr($sLower, "windows 10") Then Return "WIN_10" If StringInStr($sLower, "windows 8.1") Then Return "WIN_81" If StringInStr($sLower, "windows 8") Then Return "WIN_8" If StringInStr($sLower, "windows 7") Then Return "WIN_7" If StringInStr($sLower, "vista") Then Return "WIN_VISTA" If StringInStr($sLower, "xp") Then Return "WIN_XP" If StringInStr($sLower, "2000") Then Return "WIN_2000" If StringInStr($sLower, "nt 4.0") Then Return "WIN_NT4" If StringInStr($sLower, "nt 3.51") Then Return "WIN_NT351" If StringInStr($sLower, "nt 3.5") Then Return "WIN_NT35" If StringInStr($sLower, "nt 3.1") Then Return "WIN_NT31" Return "UNKNOWN" ; No match found EndFunc ;==>__WinVerDetect_GetShortName ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_LiveVersion ; Description ...: Retrieves version info from the live system's registry. Requires admin privileges. ; Syntax ........: __WinVerDetect_LiveVersion($sPath) ; Parameters ....: $sPath - String: Path to Windows directory (must be live system) ; Return values .: Success - Array[10] with populated version fields ; Failure - Calls __WinVerDetect_FromFiles as fallback; logs error ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Integrated error logging and fallback ; Remarks .......: - Uses _RegReadMulti for efficient batch reading. ; | - Sets EditionType via inference if needed. ; Related .......: _RegReadMulti, __WinVerDetect_IsInsiderPreview, __WinVerDetect_FromFiles ; =============================================================================================================================== Func __WinVerDetect_LiveVersion($sPath) ; Initialize result array for live system Local $aResult[10] = ["Live", "", "", "", "", "", "", "", "", False] ; Registry key for version info Local $sKey = "HKLM\" & $REG_KEY_VERSION ; Read multiple values: ProductName, CurrentBuildNumber, DisplayVersion, UBR, EditionID Local $aRegValues = _RegReadMulti($sKey, "ProductName|CurrentBuildNumber|DisplayVersion|UBR|EditionID", "", "|", "|", True) ; Check if read succeeded (array of 5 elements) If Not @error And IsArray($aRegValues) And UBound($aRegValues) = 5 Then ; Populate result from registry values $aResult[$WINVER_PRODUCTNAME] = $aRegValues[0] ; ProductName $aResult[$WINVER_BUILD] = $aRegValues[1] ; Build $aResult[$WINVER_DISPLAYVERSION] = $aRegValues[2] ; DisplayVersion $aResult[$WINVER_UBR] = $aRegValues[3] ; UBR $aResult[$WINVER_EDITIONID] = $aRegValues[4] ; EditionID ; Infer EditionType from ProductName or EditionID $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aRegValues[0], $aRegValues[4]) ; Check for Insider Preview $aResult[$WINVER_ISINSIDER] = __WinVerDetect_IsInsiderPreview() Return $aResult Else ; Log error details for debugging __WinVerDetect_LogError("Registry read failed in __WinVerDetect_LiveVersion: Error=" & @error & ", Extended=" & @extended & ", aRegValues=" & (IsArray($aRegValues) ? __WinVerDetect_ArrayToString($aRegValues) : $aRegValues)) ; Fallback to file-based detection Return __WinVerDetect_FromFiles($sPath) EndIf EndFunc ;==>__WinVerDetect_LiveVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_OfflineVersion ; Description ...: Loads offline registry hive and reads version info. Requires admin privileges and SeBackupPrivilege. ; Syntax ........: __WinVerDetect_OfflineVersion($sPath) ; Parameters ....: $sPath - String: Path to offline Windows directory ; Return values .: Success - Array[10] with populated version fields ; Failure - Falls back to __WinVerDetect_FromFiles; unloads hive on exit ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added hive unloading and Insider check for offline ; Remarks .......: - Uses temporary key for hive loading to avoid conflicts. ; | - Ensures hive is unloaded after reading to free resources. ; Related .......: __WinVerDetect_LoadOfflineHive, __WinVerDetect_UnloadOfflineHive, __WinVerDetect_IsOfflineInsiderPreview ; =============================================================================================================================== Func __WinVerDetect_OfflineVersion($sPath) ; Initialize result array for offline system Local $aResult[10] = ["Offline", "", "", "", "", "", "", "", "", False] ; Path to SOFTWARE hive Local $sHiveFile = $sPath & $HIVE_SOFTWARE ; Check if hive file exists If Not FileExists($sHiveFile) Then Return __WinVerDetect_FromFiles($sPath) EndIf ; Generate unique temporary key for hive loading Local $sTempKey = __WinVerDetect_GenerateUniqueKey() ; Load the hive (requires backup privilege) If Not __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) Then Return __WinVerDetect_FromFiles($sPath) EndIf ; Read from loaded hive Local $sKey = "HKLM\" & $sTempKey & "\" & $REG_KEY_VERSION Local $aRegValues = _RegReadMulti($sKey, "ProductName|CurrentBuildNumber|DisplayVersion|UBR|EditionID", "", "|", "|", True) ; Populate result (assume success; errors handled in _RegReadMulti) $aResult[$WINVER_PRODUCTNAME] = $aRegValues[0] ; ProductName $aResult[$WINVER_BUILD] = $aRegValues[1] ; Build $aResult[$WINVER_DISPLAYVERSION] = $aRegValues[2] ; DisplayVersion $aResult[$WINVER_UBR] = $aRegValues[3] ; UBR $aResult[$WINVER_EDITIONID] = $aRegValues[4] ; EditionID ; Infer EditionType $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aRegValues[0], $aRegValues[4]) ; Check for offline Insider $aResult[$WINVER_ISINSIDER] = __WinVerDetect_IsOfflineInsiderPreview($sPath) ; Unload the hive to clean up __WinVerDetect_UnloadOfflineHive($sTempKey) Return $aResult EndFunc ;==>__WinVerDetect_OfflineVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_FromFiles ; Description ...: Fallback detection using file versions (kernel32.dll or ntdll.dll) and edition-specific files. No admin required. ; Syntax ........: __WinVerDetect_FromFiles($sPath) ; Parameters ....: $sPath - String: Path to Windows directory ; Return values .: Success - Array[10] with build, UBR, and inferred product/edition ; Failure - Sets @error=3 if no build found ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Enhanced edition detection logic ; Remarks .......: - Extracts build and UBR from file version info (format: Major.Minor.Build.UBR). ; | - Infers edition by presence of specific files (e.g., ServerManager.exe for Server). ; Related .......: FileGetVersion (built-in) ; =============================================================================================================================== Func __WinVerDetect_FromFiles($sPath) ; Initialize result array for offline/file-based detection Local $aResult[10] = ["Offline", "", "", "", "", "", "", "", "", False] ; Key system files for build detection Local $aSystemFiles[2] = [$sPath & "\System32\kernel32.dll", $sPath & "\System32\ntdll.dll"] ; Try each file for version info For $sFile In $aSystemFiles If FileExists($sFile) Then Local $sFileVersion = FileGetVersion($sFile) If $sFileVersion <> "" Then Local $aVersionParts = StringSplit($sFileVersion, ".") If $aVersionParts[0] >= 4 Then ; File version format: Major.Minor.Build.UBR (e.g., 10.0.19045.4567) $aResult[$WINVER_BUILD] = $aVersionParts[3] ; Build (last but one) $aResult[$WINVER_UBR] = $aVersionParts[4] ; UBR (private build) $aResult[$WINVER_DISPLAYVERSION] = "" ; To be inferred later ExitLoop ; Success, stop checking EndIf EndIf EndIf Next ; Error if no build found If $aResult[$WINVER_BUILD] = "" Then Return SetError($WINVER_ERROR_FILE_ACCESS, 0, $aResult) EndIf ; Infer product and edition based on edition-specific files If FileExists($sPath & "\System32\ServerManager.exe") Then ; Server edition $aResult[$WINVER_PRODUCTNAME] = "Windows Server" $aResult[$WINVER_EDITIONID] = "Server" $aResult[$WINVER_EDITIONTYPE] = "Server" ElseIf FileExists($sPath & "\System32\ProfSvc.dll") Then ; Professional edition $aResult[$WINVER_PRODUCTNAME] = "Windows Professional" $aResult[$WINVER_EDITIONID] = "Professional" $aResult[$WINVER_EDITIONTYPE] = "Professional" Else ; Default to Home $aResult[$WINVER_PRODUCTNAME] = "Windows Home" $aResult[$WINVER_EDITIONID] = "Home" $aResult[$WINVER_EDITIONTYPE] = "Home" EndIf Return $aResult EndFunc ;==>__WinVerDetect_FromFiles ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_FillMissingInfo ; Description ...: Populates missing fields in the result array using the static version databases or inference functions. ; Syntax ........: __WinVerDetect_FillMissingInfo(ByRef $aResult) ; Parameters ....: $aResult - Array: Reference to the result array[10] to fill ; Return values .: Modified $aResult with filled fields; Sets @error=5 if invalid build ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Prioritized DB lookup before inference ; Remarks .......: - Uses exact DB first, then range DB. ; | - Only overrides empty fields to preserve registry data. ; Related .......: __WinVerDetect_GetVersionFromDB, __WinVerDetect_InferDisplayVersion ; =============================================================================================================================== Func __WinVerDetect_FillMissingInfo(ByRef $aResult) ; Parse build and UBR as integers for comparison Local $iBuild = Int($aResult[$WINVER_BUILD]) Local $iUBR = Int($aResult[$WINVER_UBR]) If $iBuild < 1 Then Return SetError($WINVER_ERROR_INVALID_BUILD, 0, $aResult) EndIf ; Attempt to get full info from databases Local $aVersionInfo = __WinVerDetect_GetVersionFromDB($iBuild, $iUBR) If IsArray($aVersionInfo) Then ; Use DB info if available, but only fill empty fields If $aResult[$WINVER_SHORTNAME] = "" Then $aResult[$WINVER_SHORTNAME] = $aVersionInfo[1] ; ShortOS If $aResult[$WINVER_PRODUCTNAME] = "" Then $aResult[$WINVER_PRODUCTNAME] = $aVersionInfo[2] ; ProductName If $aResult[$WINVER_FULLNAME] = "" Then $aResult[$WINVER_FULLNAME] = $aVersionInfo[3] ; VersionFullName If $aResult[$WINVER_DISPLAYVERSION] = "" Then $aResult[$WINVER_DISPLAYVERSION] = $aVersionInfo[6] ; DisplayVersion ; Only set edition if not already from registry If $aResult[$WINVER_EDITIONID] = "" Then $aResult[$WINVER_EDITIONID] = $aVersionInfo[7] If $aResult[$WINVER_EDITIONTYPE] = "" Then $aResult[$WINVER_EDITIONTYPE] = $aVersionInfo[8] Else ; Fallback to inference functions for missing fields If $aResult[$WINVER_SHORTNAME] = "" Then $aResult[$WINVER_SHORTNAME] = __WinVerDetect_GetShortName($aResult[$WINVER_PRODUCTNAME]) If $aResult[$WINVER_PRODUCTNAME] = "" Then $aResult[$WINVER_PRODUCTNAME] = "Windows" ; Default If $aResult[$WINVER_FULLNAME] = "" Then $aResult[$WINVER_FULLNAME] = __WinVerDetect_GetVersionNameByBuild($iBuild, $aResult[$WINVER_DISPLAYVERSION], $aResult[$WINVER_PRODUCTNAME], $iUBR) If $aResult[$WINVER_DISPLAYVERSION] = "" Then $aResult[$WINVER_DISPLAYVERSION] = __WinVerDetect_InferDisplayVersion($iBuild) If $aResult[$WINVER_EDITIONID] = "" Then $aResult[$WINVER_EDITIONID] = __WinVerDetect_InferEditionType($aResult[$WINVER_PRODUCTNAME], "") If $aResult[$WINVER_EDITIONTYPE] = "" Then $aResult[$WINVER_EDITIONTYPE] = __WinVerDetect_InferEditionType($aResult[$WINVER_PRODUCTNAME], $aResult[$WINVER_EDITIONID]) EndIf Return $aResult EndFunc ;==>__WinVerDetect_FillMissingInfo ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetVersionFromDB ; Description ...: Looks up version info in exact and range databases based on build and UBR. ; Syntax ........: __WinVerDetect_GetVersionFromDB($iBuild[, $iUBR = 0]) ; Parameters ....: $iBuild - Integer: Major build number ; $iUBR - Integer: Update Build Revision (optional) ; Return values .: Success - Array[10] with version details ; Failure - 0 (no match) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Structured array return for consistency ; Remarks .......: - Exact DB checked first for precise matches (including UBR). ; | - Range DB for broader inference (ignores UBR). ; Related .......: __WinVerDetect_InitExactWindowsVersionDB, __WinVerDetect_InitWindowsVersionDB ; =============================================================================================================================== Func __WinVerDetect_GetVersionFromDB($iBuild, $iUBR = 0) ; Check exact build database first (precise matches) For $i = 0 To UBound($_g_aWinVerExactDB) - 1 ; Match build and UBR (UBR=-1 means any) If $iBuild = $_g_aWinVerExactDB[$i][4] And ($iUBR = $_g_aWinVerExactDB[$i][5] Or $_g_aWinVerExactDB[$i][5] = -1) Then ; Construct result array Local $aResult[10] $aResult[0] = "" ; State (not used here) $aResult[1] = __WinVerDetect_GetShortName($_g_aWinVerExactDB[$i][0]) ; ShortOS $aResult[2] = $_g_aWinVerExactDB[$i][0] ; ProductName ; Full name with version, build, and codename if available $aResult[3] = $_g_aWinVerExactDB[$i][0] & " Version " & $_g_aWinVerExactDB[$i][3] & " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" & ($_g_aWinVerExactDB[$i][2] <> "" ? " (" & $_g_aWinVerExactDB[$i][2] & ")" : "") $aResult[4] = String($iBuild) ; Build as string $aResult[5] = String($iUBR) ; UBR as string $aResult[6] = $_g_aWinVerExactDB[$i][3] ; DisplayVersion $aResult[7] = $_g_aWinVerExactDB[$i][0] ; EditionID fallback to product $aResult[8] = $_g_aWinVerExactDB[$i][0] ; EditionType fallback $aResult[9] = False ; Not Insider (DB is for stable releases) Return $aResult EndIf Next ; Fallback to range database (build range match) For $i = 0 To UBound($_g_aWinVerRangeDB) - 1 ; Check if build falls in range (MaxBuild=-1 means up to current) If $iBuild >= $_g_aWinVerRangeDB[$i][0] And ($iBuild <= $_g_aWinVerRangeDB[$i][1] Or $_g_aWinVerRangeDB[$i][1] = -1) Then Local $aResult[10] $aResult[0] = "" ; State $aResult[1] = __WinVerDetect_GetShortName($_g_aWinVerRangeDB[$i][2]) ; ShortOS $aResult[2] = $_g_aWinVerRangeDB[$i][2] ; ProductName ; Full name with inferred display version $aResult[3] = $_g_aWinVerRangeDB[$i][2] & " Version " & __WinVerDetect_InferDisplayVersion($iBuild) & " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" $aResult[4] = String($iBuild) $aResult[5] = String($iUBR) $aResult[6] = __WinVerDetect_InferDisplayVersion($iBuild) ; DisplayVersion $aResult[7] = $_g_aWinVerRangeDB[$i][2] ; EditionID fallback $aResult[8] = $_g_aWinVerRangeDB[$i][2] ; EditionType fallback $aResult[9] = False Return $aResult EndIf Next Return 0 ; No match EndFunc ;==>__WinVerDetect_GetVersionFromDB ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InitExactWindowsVersionDB ; Description ...: Initializes the exact version database with historical and current Windows builds. Called at compile time. ; Syntax ........: __WinVerDetect_InitExactWindowsVersionDB() ; Parameters ....: None ; Return values .: 2D Array: [57][6] with [ProductName, Codename, ReleaseDate, DisplayVersion, Build, UBR] ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Updated entries for Windows 11 24H2 and Server 2025; added comments ; Remarks .......: - UBR = -1 means any UBR for that build. ; | - Covers Windows 1.0 to Windows Server 2025. ; | - Duplicate entries for SP/service packs where applicable. ; Related .......: __WinVerDetect_GetVersionFromDB ; =============================================================================================================================== Func __WinVerDetect_InitExactWindowsVersionDB() ; Define 2D array structure: [ProductName, Codename, ReleaseDate, Version, DisplayVersion, Build, UBR] Local $aDB[53][7] ; Source data entries (historical to modern) Local $aEntries[53][7] = [ _ ["Windows 95", "Chicago", "August 1995", "4.0", "4.0", 950, -1], _ ["Windows 98", "Memphis", "June 1998", "4.1", "4.1", 1998, -1], _ ["Windows 98", "Memphis", "May 1999", "4.1", "SE", 2222, -1], _ ["Windows Me", "Millennium", "September 2000", "4.9", "4.9", 3000, -1], _ ["Windows NT 3.1", "Razzle", "July 1993", "3.1", "3.1", 528, -1], _ ["Windows NT 3.5", "Daytona", "September 1994", "3.5", "3.5", 807, -1], _ ["Windows NT 3.51", "Daytona", "May 1995", "3.51", "3.51", 1057, -1], _ ["Windows NT 4.0", "Cairo", "August 1996", "4.0", "4.0", 1381, -1], _ ["Windows 2000", "NT 5.0", "February 2000", "5.0", "5.0", 2195, -1], _ ["Windows XP", "Whistler", "October 2001", "5.1", "5.1", 2600, 0], _ ["Windows XP", "Whistler", "September 9, 2002", "5.1", "SP1", 2600, 1106], _ ["Windows XP", "Whistler", "August 25, 2004", "5.1", "SP2", 2600, 2180], _ ["Windows XP", "Whistler", "April 21, 2008", "5.1", "SP3", 2600, 5512], _ ["Windows Server 2003", "Whistler Server", "April 2003", "5.2", "5.2", 3790, 0], _ ["Windows Server 2003", "Whistler Server R2", "December 2005", "5.2", "R2", 3790, 3959], _ ["Windows Vista", "Longhorn", "January 2007", "6.0", "6.0", 6000, 0], _ ["Windows Vista", "Longhorn", "January 2007", "6.0", "SP2", 6002, 18005], _ ["Windows Server 2008", "Longhorn Server", "February 2008", "6.0", "6.0", 6001, 0], _ ["Windows 7", "Blackcomb", "October 2009", "6.1", "6.1", 7600, 0], _ ["Windows 7", "Blackcomb", "February 22, 2011", "6.1", "SP1", 7601, 17514], _ ["Windows Server 2008", "Windows 7 Server", "October 2009", "6.1", "R2", 7601, 0], _ ["Windows 8", "Metro", "October 2012", "6.2", "6.2", 9200, 0], _ ["Windows Server 2012", "Windows Server 8", "September 2012", "6.2", "6.2", 9200, 0], _ ["Windows 8.1", "Blue", "October 2013", "6.3", "6.3", 9600, 0], _ ["Windows 8.1", "Blue", "April 8, 2014", "6.3", "Update 1", 9600, 17031], _ ["Windows Server 2012", "Windows Server Blue", "October 2013", "6.3", "R2", 9600, 0], _ ["Windows 10", "Threshold 1", "July 29, 2015", "10.0", "1507", 10240, 16384], _ ["Windows 10", "Threshold 2", "November 12, 2015", "10.0", "1511", 10586, 17], _ ["Windows 10", "Redstone 1", "August 2, 2016", "10.0", "1607", 14393, 10], _ ["Windows 10", "Redstone 2", "April 11, 2017", "10.0", "1703", 15063, 14], _ ["Windows 10", "Redstone 3", "October 17, 2017", "10.0", "1709", 16299, 19], _ ["Windows 10", "Redstone 4", "April 30, 2018", "10.0", "1803", 17134, 1], _ ["Windows 10", "Redstone 5", "October 2, 2018", "10.0", "1809", 17763, 1], _ ["Windows 10", "19H1", "May 21, 2019", "10.0", "1903", 18362, 30], _ ["Windows 10", "19H2", "November 12, 2019", "10.0", "1909", 18363, 418], _ ["Windows 10", "20H1", "May 27, 2020", "10.0", "2004", 19041, 264], _ ["Windows 10", "20H2", "October 20, 2020", "10.0", "20H2", 19042, 508], _ ["Windows 10", "21H1", "May 18, 2021", "10.0", "21H1", 19043, 928], _ ["Windows 10", "21H2", "November 16, 2021", "10.0", "21H2", 19044, 1288], _ ["Windows 10", "22H2", "August 9, 2022", "10.0", "22H2", 19045, 2006], _ ["Windows 11", "Sun Valley", "October 5, 2021", "10.0", "21H2", 22000, 194], _ ["Windows 11", "Sun Valley 2", "May 24, 2022", "10.0", "22H2", 22621, 1], _ ["Windows 11", "Sun Valley 3", "September 20, 2022", "10.0", "23H2", 22631, 2428], _ ["Windows 11", "Sun Valley 4", "September 26, 2023", "10.0", "23H2", 22641, 1], _ ["Windows 11", "Sun Valley 5", "June 26, 2024", "10.0", "24H2", 22651, 1], _ ["Windows Server 2008", "Longhorn Server", "February 2008", "6.0", "6.0", 6001, 0], _ ["Windows Server 2008", "Windows 7 Server", "October 2009", "6.1", "R2", 7601, 0], _ ["Windows Server 2012", "Windows Server 8", "September 2012", "6.2", "6.2", 9200, 0], _ ["Windows Server 2012", "Windows Server Blue", "October 2013", "6.3", "R2", 9600, 0], _ ["Windows Server 2016", "Windows Server vNext", "October 2016", "10.0", "1607", 14393, 0], _ ["Windows Server 2019", "Windows Server vNext", "October 2018", "10.0", "1809", 17763, 0], _ ["Windows Server 2022", "Windows Server vNext", "August 2021", "10.0", "21H2", 20348, 169], _ ["Windows Server 2025", "Windows Server vNext", "November 2024", "10.0", "24H2", 26100, 1] _ ] ; Copy entries to DB array For $i = 0 To UBound($aEntries) - 1 For $j = 0 To 6 $aDB[$i][$j] = $aEntries[$i][$j] Next Next Return $aDB EndFunc ;==>__WinVerDetect_InitExactWindowsVersionDB ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InitWindowsVersionDB ; Description ...: Initializes the range-based version database for broad version inference. Called at compile time. ; Syntax ........: __WinVerDetect_InitWindowsVersionDB() ; Parameters ....: None ; Return values .: 2D Array: [22][3] with [MinBuild, MaxBuild, ProductName] ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Extended ranges for Windows 11 and Server 2025 ; Remarks .......: - MaxBuild = -1 indicates open-ended range (future builds). ; | - Used when exact DB fails. ; Related .......: __WinVerDetect_GetVersionFromDB ; =============================================================================================================================== Func __WinVerDetect_InitWindowsVersionDB() ; Define 2D array structure: [MinBuild, MaxBuild, ProductName] Local $aDB[19][3] ; Source data entries (ranges for inference) Local $aEntries[19][3] = [ _ [511, 528, "Windows NT 3.1"], _ [807, 807, "Windows NT 3.5"], _ [950, 950, "Windows 95"], _ [1057, 1057, "Windows NT 3.51"], _ [1381, 1381, "Windows NT 4.0"], _ [1998, 2222, "Windows 98"], _ [2195, 2195, "Windows 2000"], _ [2600, 2600, "Windows XP"], _ [3000, 3000, "Windows Me"], _ [3790, 3790, "Windows Server 2003"], _ [6000, 6001, "Windows Vista"], _ [7600, 7601, "Windows 7"], _ [9200, 9200, "Windows 8"], _ [9600, 9600, "Windows 8.1"], _ [10240, 19045, "Windows 10"], _ [22000, 22651, "Windows 11"], _ [20348, 20348, "Windows Server 2022"], _ [26100, 26100, "Windows Server 2025"] _ ] ; Copy entries to DB array For $i = 0 To UBound($aEntries) - 1 For $j = 0 To 2 $aDB[$i][$j] = $aEntries[$i][$j] Next Next Return $aDB EndFunc ;==>__WinVerDetect_InitWindowsVersionDB Func __WinVerDetect_InitEditionMap() Dim $l_aEditionMap[20][3] Local $iIndex = 0 $l_aEditionMap[$iIndex][0] = "corecountryspecific" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Home China" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professionalcountryspecific" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro China" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "coren" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Home N" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professionaln" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro N" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "corekn" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Home KN" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professionalkn" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro KN" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "enterprises" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Enterprise LTSC" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "iotenterprise" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "IoT Enterprise" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "professional" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Pro" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "education" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Education" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "serverstandard" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Server Standard" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "serverdatacenter" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Server Datacenter" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "enterpriseg" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Enterprise G" $iIndex += 1 $l_aEditionMap[$iIndex][0] = "enterprise" $l_aEditionMap[$iIndex][1] = "" $l_aEditionMap[$iIndex][2] = "Enterprise" $iIndex += 1 ReDim $l_aEditionMap[$iIndex][3] Return $l_aEditionMap EndFunc ;==>__WinVerDetect_InitEditionMap ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetVersionNameByBuild ; Description ...: Constructs a full version name string based on build, using DB or inference. Used as fallback. ; Syntax ........: __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName[, $iUBR = 0]) ; Parameters ....: $iBuild - Integer: Build number ; $sDisplayVersion- String: Known display version (fallback to inference) ; $sProductName - String: Known product name ; $iUBR - Integer: UBR (optional) ; Return values .: String: Full version name (e.g., "Windows 10 Version 22H2 (Build 19045)") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added server-specific formatting (no build in name for servers) ; Related .......: __WinVerDetect_GetVersionFromDB, __WinVerDetect_GetFallbackVersionName ; =============================================================================================================================== Func __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName, $iUBR = 0) Local $bIsServer = (StringInStr($sProductName, "Server") > 0) ; Check if server edition ; ==== Check exact DB ==== For $i = 0 To UBound($_g_aWinVerExactDB) - 1 Local $dbProduct = $_g_aWinVerExactDB[$i][0] Local $dbCodename = $_g_aWinVerExactDB[$i][1] Local $dbDate = $_g_aWinVerExactDB[$i][2] Local $dbVersion = $_g_aWinVerExactDB[$i][3] Local $dbDispVer = $_g_aWinVerExactDB[$i][4] Local $dbBuild = $_g_aWinVerExactDB[$i][5] Local $dbUBR = $_g_aWinVerExactDB[$i][6] If $iBuild = $dbBuild And ($iUBR = $dbUBR Or $dbUBR = -1) Then ; Ưu tiên ProductName đầu vào, fallback DB Local $sTemplate = $sProductName <> "" ? $sProductName : $dbProduct ; --- Thêm DisplayVersion/Version --- If $dbDispVer <> "" Then ; Nếu ProductName đã chứa rồi thì bỏ qua If StringInStr($sTemplate, $dbDispVer) = 0 Then ; Nếu DisplayVersion = Version và là số → "Version X" If $dbDispVer = $dbVersion And StringIsDigit(StringReplace($dbDispVer, ".", "")) Then $sTemplate &= " Version " & $dbVersion Else $sTemplate &= " " & $dbDispVer EndIf EndIf ElseIf $dbVersion <> "" Then If StringInStr($sTemplate, $dbVersion) = 0 Then $sTemplate &= " Version " & $dbVersion EndIf EndIf ; --- Build --- Local $sBuild = "(Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" $sTemplate &= " " & $sBuild ; --- Date --- If $dbDate <> "" Then $sTemplate &= " (" & $dbDate & ")" ; --- Codename --- If $dbCodename <> "" Then $sTemplate &= " (" & $dbCodename & ")" Return $sTemplate EndIf Next ; ==== Fallback to range DB ==== For $i = 0 To UBound($_g_aWinVerRangeDB) - 1 If $iBuild >= $_g_aWinVerRangeDB[$i][0] And ($iBuild <= $_g_aWinVerRangeDB[$i][1] Or $_g_aWinVerRangeDB[$i][1] = -1) Then Local $sTemplate = $sProductName <> "" ? $sProductName : $_g_aWinVerRangeDB[$i][2] If StringInStr($sTemplate, "Future") Then $sTemplate = $bIsServer ? "Windows Server" : "Windows" EndIf ; Ưu tiên DisplayVersion đầu vào, fallback infer Local $sDisplay = $sDisplayVersion <> "" ? $sDisplayVersion : __WinVerDetect_InferDisplayVersion($iBuild) If $sDisplay <> "" And StringInStr($sTemplate, $sDisplay) = 0 Then $sTemplate &= " " & $sDisplay EndIf $sTemplate &= " (Build " & $iBuild & ($iUBR > 0 ? "." & $iUBR : "") & ")" Return $sTemplate EndIf Next ; ==== Ultimate fallback ==== Return __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer) EndFunc ;==>__WinVerDetect_GetVersionNameByBuild ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InferEditionType ; Description ...: Infers edition type (e.g., "Professional") from ProductName or EditionID. ; Syntax ........: __WinVerDetect_InferEditionType($sProductName, $sEditionID) ; Parameters ....: $sProductName - String: Full product name ; $sEditionID - String: Registry EditionID (takes precedence) ; Return values .: String: Inferred edition type ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added EnterpriseS handling ; Remarks .......: - Prioritizes EditionID if provided. ; | - Case-insensitive keyword matching. ; Related .......: _WinVerDetect_GetVersion ; =============================================================================================================================== Func __WinVerDetect_InferEditionType($sProductName, $sEditionID = '') Local $sLowerID = StringLower($sEditionID) If $sLowerID <> '' Then For $i = 0 To UBound($g_aEditionMap) - 1 If StringInStr($sLowerID, $g_aEditionMap[$i][0]) > 0 Then Return $g_aEditionMap[$i][2] EndIf Next EndIf Local $sLower = StringLower($sProductName) If StringInStr($sLower, "server") Then If StringInStr($sLower, "2022") Or StringInStr($sLower, "2025") Then If StringInStr($sLower, "azure") Then Return "Server Datacenter: Azure Edition" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" If StringInStr($sLower, "essentials") Then Return "Server Essentials" Return "Server" EndIf If StringInStr($sLower, "2019") Then If StringInStr($sLower, "essentials") Then Return "Server Essentials" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" Return "Server 2019" EndIf If StringInStr($sLower, "2016") Then If StringInStr($sLower, "essentials") Then Return "Server Essentials" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" If StringInStr($sLower, "foundation") Then Return "Server Foundation" Return "Server 2016" EndIf If StringInStr($sLower, "essentials") Then Return "Server Essentials" If StringInStr($sLower, "datacenter") Then Return "Server Datacenter" If StringInStr($sLower, "standard") Then Return "Server Standard" Return "Server" EndIf If StringInStr($sLower, "windows 11") Then If StringInStr($sLower, "mixed reality") Then Return "Mixed Reality" If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise" If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "education") Then Return "Education" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "home") Then Return "Home" Return "Windows 11" EndIf If StringInStr($sLower, "windows 10") Then If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise" If StringInStr($sLower, "mobile") Then Return "Mobile" If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise" If StringInStr($sLower, "iot core") Then Return "IoT Core" If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "education") Then Return "Education" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "home") Then Return "Home" Return "Windows 10" EndIf If StringInStr($sLower, "windows 8.1") Or StringInStr($sLower, "8.1") Then If StringInStr($sLower, "rt") Then Return "RT" If StringInStr($sLower, "single language") Then Return "Single Language" If StringInStr($sLower, "pro") And StringInStr($sLower, "media center") Then Return "Pro with Media Center" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "core") Or StringInStr($sLower, "windows 8.1") Then Return "Core" Return "Windows 8.1" EndIf If StringInStr($sLower, "windows 8") Then If StringInStr($sLower, "rt") Then Return "RT" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then Return "Pro" If StringInStr($sLower, "core") Or StringInStr($sLower, "windows 8") Then Return "Core" Return "Windows 8" EndIf If StringInStr($sLower, "windows 7") Or StringInStr($sLower, "7") Then If StringInStr($sLower, "starter") Then Return "Starter" If StringInStr($sLower, "home basic") Then Return "Home Basic" If StringInStr($sLower, "home premium") Then Return "Home Premium" If StringInStr($sLower, "ultimate") Then Return "Ultimate" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Then Return "Professional" Return "Windows 7" EndIf If StringInStr($sLower, "embedded") Then Return "Embedded" If StringInStr($sLower, "starter") Then Return "Starter" If StringInStr($sLower, "ultimate") Then Return "Ultimate" If StringInStr($sLower, "mixed reality") Then Return "Mixed Reality" If StringInStr($sLower, "iot enterprise") Then Return "IoT Enterprise" If StringInStr($sLower, "iot core") Then Return "IoT Core" If StringInStr($sLower, "iot") Then Return "IoT" If StringInStr($sLower, "mobile enterprise") Then Return "Mobile Enterprise" If StringInStr($sLower, "mobile") Then Return "Mobile" If StringInStr($sLower, "rt") Then Return "RT" If StringInStr($sLower, "pro for workstations") Then Return "Pro for Workstations" If StringInStr($sLower, "workstation") Then Return "Workstation" If StringInStr($sLower, "pro education") Then Return "Pro Education" If StringInStr($sLower, "education") Then Return "Education" If StringInStr($sLower, "enterprise") Then Return "Enterprise" If StringInStr($sLower, "professional") Or StringInStr($sLower, "pro") Then If StringInStr($sLower, "media center") Then Return "Pro with Media Center" Return "Professional" EndIf If StringInStr($sLower, "home premium") Then Return "Home Premium" If StringInStr($sLower, "home basic") Then Return "Home Basic" If StringInStr($sLower, "home") Then Return "Home" If StringInStr($sLower, "core") Then Return "Core" If StringInStr($sLower, "single language") Then Return "Single Language" If StringInStr($sLower, "millennium") Then Return "Millennium Edition" If StringInStr($sLower, "second edition") Then Return "Second Edition" If $sProductName <> "" Then Return "Standard" Return "Unknown" EndFunc ;==>__WinVerDetect_InferEditionType ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_InferDisplayVersion ; Description ...: Infers the display version (e.g., "22H2") from the build number using known thresholds. ; Syntax ........: __WinVerDetect_InferDisplayVersion($iBuild) ; Parameters ....: $iBuild - Integer: Build number ; Return values .: String: Display version (e.g., "22H2"); Empty string if unknown ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added support for builds >=26100 (Server 2025/Win11 24H2) ; Remarks .......: - Uses descending thresholds for accurate inference. ; | - Covers from Windows 1.0 to future builds. ; Related .......: __WinVerDetect_FillMissingInfo ; =============================================================================================================================== Func __WinVerDetect_InferDisplayVersion($iBuild) ; Legacy NT-based If $iBuild = 9600 Then Return "6.3" If $iBuild = 9200 Then Return "6.2" If $iBuild = 7600 Or $iBuild = 7601 Then Return "6.1" If $iBuild = 6000 Or $iBuild = 6001 Then Return "6.0" If $iBuild = 3790 Then Return "5.2" If $iBuild = 2600 Then Return "5.1" If $iBuild = 2195 Then Return "5.0" If $iBuild = 1381 Then Return "4.0" If $iBuild = 1057 Then Return "3.51" If $iBuild = 807 Then Return "3.5" ; 9x/ME If $iBuild = 3000 Then Return "4.9" If $iBuild = 1998 Then Return "4.1" If $iBuild = 950 Then Return "4.0" If $iBuild = 528 Then Return "3.1" ; Modern Windows 11/Server 2025 If $iBuild >= 26100 Then Return "24H2" If $iBuild >= 22631 Then Return "23H2" If $iBuild >= 22621 Then Return "22H2" If $iBuild >= 22000 Then Return "21H2" ; Windows 10 If $iBuild >= 19045 Then Return "22H2" If $iBuild >= 19044 Then Return "21H2" If $iBuild >= 19043 Then Return "21H1" If $iBuild >= 19042 Then Return "20H2" If $iBuild >= 19041 Then Return "2004" If $iBuild >= 18363 Then Return "1909" If $iBuild >= 18362 Then Return "1903" If $iBuild >= 17134 Then Return "1803" If $iBuild >= 16299 Then Return "1709" If $iBuild >= 15063 Then Return "1703" If $iBuild >= 14393 Then Return "1607" If $iBuild >= 10586 Then Return "1511" If $iBuild >= 10240 Then Return "1507" Return "" ; Unknown build EndFunc ;==>__WinVerDetect_InferDisplayVersion ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GetFallbackVersionName ; Description ...: Generates a basic fallback version name when DB lookup fails. ; Syntax ........: __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer) ; Parameters ....: $iBuild - Integer: Build number ; $sDisplayVersion- String: Optional display version ; $bIsServer - Boolean: True if server edition ; Return values .: String: Basic name (e.g., "Windows (Build 12345)") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Simplified for server/client distinction ; Remarks .......: - Used as last resort. ; Related .......: __WinVerDetect_GetVersionNameByBuild ; =============================================================================================================================== Func __WinVerDetect_GetFallbackVersionName($iBuild, $sDisplayVersion, $bIsServer) Local $sFallback = $bIsServer ? "Windows Server" : "Windows" If $sDisplayVersion <> "" Then $sFallback &= " Version " & $sDisplayVersion EndIf If Not $bIsServer Then $sFallback &= " (Build " & $iBuild & ")" EndIf Return $sFallback EndFunc ;==>__WinVerDetect_GetFallbackVersionName ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsInsiderPreview ; Description ...: Checks live registry for Insider Preview indicators. ; Syntax ........: __WinVerDetect_IsInsiderPreview() ; Parameters ....: None ; Return values .: Boolean: True if Insider (ContentType or ReleaseType contains "Insider") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Checks both ContentType and ReleaseType ; Remarks .......: - Only for live systems. ; Related .......: __WinVerDetect_IsOfflineInsiderPreview ; =============================================================================================================================== Func __WinVerDetect_IsInsiderPreview() Local $sKey = "HKLM\" & $REG_KEY_INSIDER Local $sType = RegRead($sKey, "ContentType") If @error Or $sType = "" Then $sType = RegRead($sKey, "ReleaseType") ; Fallback key EndIf Return (Not @error And StringInStr($sType, "Insider") > 0) EndFunc ;==>__WinVerDetect_IsInsiderPreview ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_NormalizePath ; Description ...: Normalizes a file path, handling long paths (>240 chars) with \\?\ prefix and resolving full path via API. ; Syntax ........: __WinVerDetect_NormalizePath($sPath) ; Parameters ....: $sPath - String: Input path ; Return values .: String: Normalized full path without trailing slashes ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses DllCall for GetFullPathNameW ; Remarks .......: - Ensures compatibility with long paths in Windows. ; Related .......: DllCall("kernel32.dll", "GetFullPathNameW") ; =============================================================================================================================== Func __WinVerDetect_NormalizePath($sPath) ; Add \\?\ prefix for long paths If StringLeft($sPath, 4) <> "\\?\" And StringLen($sPath) > 240 Then $sPath = "\\?\" & $sPath EndIf ; Use Windows API to get full path Local $tBuf = DllStructCreate("wchar[" & $MAX_PATH & "]") Local $aRet = DllCall("kernel32.dll", "dword", "GetFullPathNameW", "wstr", $sPath, "dword", $MAX_PATH, "ptr", DllStructGetPtr($tBuf), "ptr", 0) If @error Or $aRet[0] = 0 Then ; Fallback: Simple replace Return StringReplace($sPath, "/", "\") EndIf ; Remove trailing backslashes Return StringRegExpReplace(DllStructGetData($tBuf, 1), "\\+$", "") EndFunc ;==>__WinVerDetect_NormalizePath ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsValidWindowsPath ; Description ...: Validates if a path is a valid Windows installation by checking key directories and files. ; Syntax ........: __WinVerDetect_IsValidWindowsPath($sPath) ; Parameters ....: $sPath - String: Path to check ; Return values .: Boolean: True if valid Windows dir ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added kernel32/ntdll existence check ; Remarks .......: - Requires System32, Config, and at least one core DLL. ; Related .......: FileExists (built-in) ; =============================================================================================================================== Func __WinVerDetect_IsValidWindowsPath($sPath) If Not FileExists($sPath) Then Return False EndIf ; Check essential directories If Not FileExists($sPath & "\System32") Or Not FileExists($sPath & "\System32\Config") Then Return False EndIf ; Count core files Local $iCount = 0 If FileExists($sPath & "\System32\kernel32.dll") Then $iCount += 1 If FileExists($sPath & "\System32\ntdll.dll") Then $iCount += 1 Return $iCount > 0 ; At least one core file EndFunc ;==>__WinVerDetect_IsValidWindowsPath ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsSystemLive ; Description ...: Determines if the path is a live (running) Windows system by checking file locks on key files. ; Syntax ........: __WinVerDetect_IsSystemLive($sPath) ; Parameters ....: $sPath - String: Path to check ; Return values .: Boolean: True if live (files locked by kernel) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Added ntoskrnl.exe check ; Remarks .......: - Compares to @WindowsDir first for quick live check. ; | - Uses CreateFile to test locks. ; Related .......: __WinVerDetect_IsFileLocked ; =============================================================================================================================== Func __WinVerDetect_IsSystemLive($sPath) ; Quick check: If matches current Windows dir, it's live If __WinVerDetect_NormalizePath(@WindowsDir) = $sPath Then Return True EndIf ; Check locks on key files (in-use by running system) Local $aCheck[3] = [$sPath & "\System32\Config\SYSTEM", $sPath & "\System32\Config\SOFTWARE", $sPath & "\System32\ntoskrnl.exe"] For $sFile In $aCheck If __WinVerDetect_IsFileLocked($sFile) Then Return True ; Locked = in use by live system EndIf Next Return False EndFunc ;==>__WinVerDetect_IsSystemLive ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsFileLocked ; Description ...: Tests if a file is locked (in use) using CreateFile API. ; Syntax ........: __WinVerDetect_IsFileLocked($sFile) ; Parameters ....: $sFile - String: File path to test ; Return values .: Boolean: True if locked (cannot open) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses wide char (W) for Unicode support ; Remarks .......: - INVALID_HANDLE_VALUE (-1) indicates lock. ; Related .......: DllCall("kernel32.dll", "CreateFileW") ; =============================================================================================================================== Func __WinVerDetect_IsFileLocked($sFile) If Not FileExists($sFile) Then Return False EndIf ; Attempt to open file with read share Local $h = DllCall("kernel32.dll", "handle", "CreateFileW", "wstr", $sFile, "dword", $GENERIC_READ, "dword", $FILE_SHARE_READ, "ptr", 0, "dword", $OPEN_EXISTING, "dword", 0, "handle", 0) If @error Or $h[0] = -1 Then ; -1 = INVALID_HANDLE_VALUE Return True ; Cannot open = locked EndIf ; Close handle if opened successfully DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $h[0]) Return False EndFunc ;==>__WinVerDetect_IsFileLocked ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_LoadOfflineHive ; Description ...: Loads an offline registry hive into HKLM using RegLoadKeyW. Requires SeBackupPrivilege. ; Syntax ........: __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) ; Parameters ....: $sHiveFile - String: Path to hive file (e.g., SOFTWARE) ; $sTempKey - String: Temporary subkey name under HKLM ; Return values .: Boolean: True if loaded successfully ($ERROR_SUCCESS) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Integrated privilege enablement ; Remarks .......: - Enables backup privilege before loading. ; Related .......: __WinVerDetect_EnableBackupPrivilege, RegLoadKeyW ; =============================================================================================================================== Func __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) ; Enable required privilege If Not __WinVerDetect_EnableBackupPrivilege() Then Return False EndIf ; Load hive via API Local $aRet = DllCall("advapi32.dll", "long", "RegLoadKeyW", "handle", $HKEY_LOCAL_MACHINE, "wstr", $sTempKey, "wstr", $sHiveFile) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__WinVerDetect_LoadOfflineHive ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_UnloadOfflineHive ; Description ...: Unloads a temporarily loaded registry hive from HKLM. ; Syntax ........: __WinVerDetect_UnloadOfflineHive($sTempKey) ; Parameters ....: $sTempKey - String: Temporary subkey to unload ; Return values .: Boolean: True if unloaded successfully ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses RegUnloadKeyW for Unicode ; Remarks .......: - Always call after loading to avoid leaks. ; Related .......: RegUnloadKeyW ; =============================================================================================================================== Func __WinVerDetect_UnloadOfflineHive($sTempKey) Local $aRet = DllCall("advapi32.dll", "long", "RegUnloadKeyW", "handle", $HKEY_LOCAL_MACHINE, "wstr", $sTempKey) Return (IsArray($aRet) And $aRet[0] = $ERROR_SUCCESS) EndFunc ;==>__WinVerDetect_UnloadOfflineHive ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_EnableBackupPrivilege ; Description ...: Enables SeBackupPrivilege on the current process token for hive operations. ; Syntax ........: __WinVerDetect_EnableBackupPrivilege() ; Parameters ....: None ; Return values .: Boolean: True if privilege enabled ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Full token privilege adjustment ; Remarks .......: - Uses AdjustTokenPrivileges API. ; | - Closes token handle on exit. ; Related .......: LookupPrivilegeValueW, AdjustTokenPrivileges ; =============================================================================================================================== Func __WinVerDetect_EnableBackupPrivilege() ; Get current process handle Local $hProc = DllCall("kernel32.dll", "handle", "GetCurrentProcess")[0] ; Open process token Local $a = DllCall("advapi32.dll", "bool", "OpenProcessToken", "handle", $hProc, "dword", 0x00000020, "handle*", 0) ; TOKEN_ADJUST_PRIVILEGES If @error Or Not $a[0] Then Return False EndIf Local $hToken = $a[3] ; Token handle ; Lookup LUID for SeBackupPrivilege Local $tLUID = DllStructCreate("int64") DllCall("advapi32.dll", "bool", "LookupPrivilegeValueW", "ptr", 0, "wstr", $SE_BACKUP_PRIVILEGE, "ptr", DllStructGetPtr($tLUID)) ; Prepare privilege structure: Enabled, LUID, Attributes=SE_PRIVILEGE_ENABLED Local $tPriv = DllStructCreate("dword;int64;dword") DllStructSetData($tPriv, 1, 1) ; PrivilegeCount DllStructSetData($tPriv, 2, DllStructGetData($tLUID, 1)) ; LUID DllStructSetData($tPriv, 3, 0x00000002) ; SE_PRIVILEGE_ENABLED ; Adjust token privileges Local $aAdjust = DllCall("advapi32.dll", "bool", "AdjustTokenPrivileges", "handle", $hToken, "bool", False, "ptr", DllStructGetPtr($tPriv), "dword", 0, "ptr", 0, "ptr", 0) Local $bSuccess = (IsArray($aAdjust) And $aAdjust[0]) ; Close token DllCall("kernel32.dll", "bool", "CloseHandle", "handle", $hToken) Return $bSuccess EndFunc ;==>__WinVerDetect_EnableBackupPrivilege ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_GenerateUniqueKey ; Description ...: Generates a unique temporary registry key name using GUID. ; Syntax ........: __WinVerDetect_GenerateUniqueKey() ; Parameters ....: None ; Return values .: String: Unique key (e.g., "TEMP_A1B2C3D4") ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Uses CoCreateGuid for randomness ; Remarks .......: - Prefix "TEMP_" for identification. ; Related .......: CoCreateGuid ; =============================================================================================================================== Func __WinVerDetect_GenerateUniqueKey() ; Create GUID structure Local $tGUID = DllStructCreate("byte[16]") DllCall("ole32.dll", "int", "CoCreateGuid", "ptr", DllStructGetPtr($tGUID)) ; Convert to hex string (first 8 chars for simplicity) Local $sHex = "" For $i = 1 To 16 $sHex &= StringFormat("%02X", DllStructGetData($tGUID, 1, $i)) Next Return "TEMP_" & StringLeft($sHex, 16) EndFunc ;==>__WinVerDetect_GenerateUniqueKey ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_IsOfflineInsiderPreview ; Description ...: Checks offline hive for Insider Preview, similar to live but loads hive temporarily. ; Syntax ........: __WinVerDetect_IsOfflineInsiderPreview($sPath) ; Parameters ....: $sPath - String: Offline Windows path ; Return values .: Boolean: True if Insider detected ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Mirrors live check with hive load/unload ; Remarks .......: - Requires admin; unloads hive after check. ; Related .......: __WinVerDetect_LoadOfflineHive, __WinVerDetect_UnloadOfflineHive ; =============================================================================================================================== Func __WinVerDetect_IsOfflineInsiderPreview($sPath) Local $sHiveFile = $sPath & $HIVE_SOFTWARE If Not FileExists($sHiveFile) Then Return False EndIf Local $sTempKey = __WinVerDetect_GenerateUniqueKey() If Not __WinVerDetect_LoadOfflineHive($sHiveFile, $sTempKey) Then Return False EndIf ; Check Insider keys in loaded hive Local $sInsiderKey = "HKLM\" & $sTempKey & "\" & $REG_KEY_INSIDER Local $sType = RegRead($sInsiderKey, "ContentType") If @error Or $sType = "" Then $sType = RegRead($sInsiderKey, "ReleaseType") EndIf Local $bResult = (Not @error And StringInStr($sType, "Insider") > 0) ; Cleanup __WinVerDetect_UnloadOfflineHive($sTempKey) Return $bResult EndFunc ;==>__WinVerDetect_IsOfflineInsiderPreview ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_ArrayToString ; Description ...: Converts an array to a delimited string, starting from optional index. ; Syntax ........: __WinVerDetect_ArrayToString($aArray[, $sDelimiter = "|"[, $iStart = 0]]) ; Parameters ....: $aArray - Array: Input array ; $sDelimiter- String: Delimiter (default: "|") ; $iStart - Integer: Starting index (default: 0) ; Return values .: String: Joined array elements ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Handles empty arrays ; Remarks .......: - Similar to _ArrayToString but custom for UDF compatibility. ; Related .......: _RegReadMulti ; =============================================================================================================================== Func __WinVerDetect_ArrayToString($aArray, $sDelimiter = "|", $iStart = 0) If Not IsArray($aArray) Or UBound($aArray) <= $iStart Then Return "" EndIf Local $sResult = $aArray[$iStart] For $i = $iStart + 1 To UBound($aArray) - 1 $sResult &= $sDelimiter & $aArray[$i] Next Return $sResult EndFunc ;==>__WinVerDetect_ArrayToString ; #FUNCTION# ==================================================================================================================== ; Name ..........: __WinVerDetect_LogError ; Description ...: Logs error messages to console for debugging (internal use). ; Syntax ........: __WinVerDetect_LogError($sMsg) ; Parameters ....: $sMsg - String: Error message ; Return values .: None (outputs to console) ; Author ........: Dao Van Trong - TRONG.PRO ; Modified ......: Simple console output ; Remarks .......: - Prefix with "!" for visibility. ; Related .......: ConsoleWrite (built-in) ; =============================================================================================================================== Func __WinVerDetect_LogError($sMsg) ConsoleWrite("! " & $sMsg & @CRLF) EndFunc ;==>__WinVerDetect_LogError : TEST : #Region TEST_SUITE ; #EXAMPLE# ===================================================================================================================== ; To run the test suite, call the function: _RunTestSuite() _RunTestSuite() ; =============================================================================================================================== ;======================================================================================================= ; Function: _RunTestSuite() ; Description: Runs the comprehensive test suite for the UDF and prints the results to the console. ; Return Value: True if all tests passed, False otherwise. ;======================================================================================================= Func _RunTestSuite() Local $iPassed = 0, $iFailed = 0, $iSkipped = 0, $iTotal = 0 ; List of test functions to execute Local $aTestsToRun[] = [ _ "_TestDatabaseInitialization", _ "_TestLiveSystemDetection", _ "_TestUtilityFunctions", _ "_TestErrorHandling", _ "_TestVersionInference", _ "_TestPathValidation", _ "_TestIndividualFieldAccess", _ "_TestSpecificBuildsAndNames", _ "_TestShortNameEdgeCases", _ "_TestLiveSystemDetails", _ "_TestSpecialEditionDetection", _ ; New Test Case 10 "_TestComprehensiveVersionNames" _ ; New Test Case 11 ] $iTotal = UBound($aTestsToRun) _PrintTestResult("STARTING COMPREHENSIVE TEST SUITE", 3) ConsoleWrite("> UDF Library: Windows Version Detector" & @CRLF) ConsoleWrite("=====================================================================================" & @CRLF) For $sTestFunc In $aTestsToRun Local $aResult = Call($sTestFunc) ; Prettify the function name for display Local $sTestName = StringRegExpReplace($sTestFunc, "^_Test", "") $sTestName = StringRegExpReplace($sTestName, "([A-Z])", " $1") $sTestName = StringStripWS($sTestName, 1) _PrintTestResult($sTestName, $aResult[0], $aResult[1]) Switch $aResult[0] Case 1 ; PASSED $iPassed += 1 Case 0 ; FAILED $iFailed += 1 Case 2 ; SKIPPED $iSkipped += 1 EndSwitch Next ConsoleWrite("=====================================================================================" & @CRLF) _PrintTestResult("TEST SUITE SUMMARY", 3) ConsoleWrite("+ Passed : " & $iPassed & @CRLF) ConsoleWrite("! Failed : " & $iFailed & @CRLF) ConsoleWrite("- Skipped : " & $iSkipped & @CRLF) ConsoleWrite("> Total : " & $iTotal & @CRLF) Local $fSuccessRate = ($iTotal > 0 And $iTotal > $iSkipped) ? ($iPassed / ($iTotal - $iSkipped)) * 100 : 0 ConsoleWrite(StringFormat("> Success Rate (excluding skipped): %.1f%%", $fSuccessRate) & @CRLF & @CRLF) Return $iFailed = 0 EndFunc ;==>_RunTestSuite ;=============================================================================== ; Function: _PrintTestResult($sTestName, $iResult, $sDetails = "") ; Description: Internal helper function to print a formatted and colored test result. ; Parameters: $sTestName - The name of the test. ; $iResult - The result code: 1 (PASSED), 0 (FAILED), 2 (SKIPPED), 3 (INFO). ; $sDetails - [optional] Additional details to print. ;=============================================================================== Func _PrintTestResult($sTestName, $iResult, $sDetails = "") Local $sStatus, $sColorChar Local Const $iNameWidth = 35 ; Column width for the test name Switch $iResult Case 1 ; PASSED $sColorChar = "+ " $sStatus = "[ PASSED ] " Case 0 ; FAILED $sColorChar = "! " $sStatus = "[ FAILED ] " Case 2 ; SKIPPED $sColorChar = "- " $sStatus = "[ SKIPPED ] " Case Else ; INFO $sColorChar = "> " $sStatus = "[ INFO ] " $sDetails = $sTestName $sTestName = "" EndSwitch Local $sPaddedName = StringFormat("%-" & $iNameWidth & "s", $sTestName) ConsoleWrite($sColorChar & $sStatus & " " & $sPaddedName & $sDetails & @CRLF) EndFunc ;==>_PrintTestResult ; ------ INDIVIDUAL TEST CASE FUNCTIONS ------ ;=============================================================================== ; Test Case: _TestDatabaseInitialization ; Description: Verifies that the global database arrays are initialized correctly. ;=============================================================================== Func _TestDatabaseInitialization() Local $aReturn[2] If Not IsArray($_g_aWinVerRangeDB) Or UBound($_g_aWinVerRangeDB, 2) <> 3 Then $aReturn[0] = 0 $aReturn[1] = "RangeDB database is invalid or has wrong structure." Return $aReturn EndIf If Not IsArray($_g_aWinVerExactDB) Or UBound($_g_aWinVerExactDB, 2) <> 7 Then $aReturn[0] = 0 $aReturn[1] = "ExactDB database is invalid or has wrong structure." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestDatabaseInitialization ;=============================================================================== ; Test Case: _TestLiveSystemDetection ; Description: Performs a basic check on the currently running OS. ;=============================================================================== Func _TestLiveSystemDetection() Local $aReturn[2] If Not IsAdmin() Then $aReturn[0] = 2 $aReturn[1] = "No administrator rights, skipping live system test." Return $aReturn EndIf Local $aResult = _WinVerDetect_GetVersion() If @error Then $aReturn[0] = 0 $aReturn[1] = "An error occurred during detection. Error code: " & @error Return $aReturn EndIf If Not IsArray($aResult) Or UBound($aResult) <> 10 Then $aReturn[0] = 0 $aReturn[1] = "The returned result is not a valid array." Return $aReturn EndIf If $aResult[$WINVER_STATE] <> "Live" Then $aReturn[0] = 0 $aReturn[1] = "System state was not detected as 'Live'." Return $aReturn EndIf If $aResult[$WINVER_BUILD] = "" Or Int($aResult[$WINVER_BUILD]) < 1000 Then $aReturn[0] = 0 $aReturn[1] = "Could not retrieve a valid build number (Build: " & $aResult[$WINVER_BUILD] & ")." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "Current OS: " & $aResult[$WINVER_PRODUCTNAME] Return $aReturn EndFunc ;==>_TestLiveSystemDetection ;=============================================================================== ; Test Case: _TestUtilityFunctions ; Description: Tests helper functions like GetShortName and InferDisplayVersion. ;=============================================================================== Func _TestUtilityFunctions() Local $aReturn[2] Local $sShort = __WinVerDetect_GetShortName("Windows 11 Pro") If $sShort <> "WIN_11" Then $aReturn[0] = 0 $aReturn[1] = "GetShortName failed. Expected 'WIN_11', got '" & $sShort & "'." Return $aReturn EndIf Local $sDisplay = __WinVerDetect_InferDisplayVersion(22631) If $sDisplay <> "23H2" Then $aReturn[0] = 0 $aReturn[1] = "InferDisplayVersion failed. Expected '23H2', got '" & $sDisplay & "'." Return $aReturn EndIf Local $sVersionName = __WinVerDetect_GetVersionNameByBuild(19045, "22H2", "Windows 10 Enterprise") If Not StringInStr($sVersionName, "Windows 10 Enterprise") Or Not StringInStr($sVersionName, "22H2") Then $aReturn[0] = 0 $aReturn[1] = "GetVersionName failed. Result: " & $sVersionName Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestUtilityFunctions ;=============================================================================== ; Test Case: _TestErrorHandling ; Description: Ensures the main function correctly handles invalid inputs. ;=============================================================================== Func _TestErrorHandling() Local $aReturn[2] _WinVerDetect_GetVersion("C:\NonExistent\Path\For\Sure") If @error <> $WINVER_ERROR_INVALID_PATH Then $aReturn[0] = 0 $aReturn[1] = "Did not catch invalid path error. Error code: " & @error Return $aReturn EndIf _WinVerDetect_GetVersion("") If @error <> $WINVER_ERROR_INVALID_PATH Then $aReturn[0] = 0 $aReturn[1] = "Did not catch empty path error. Error code: " & @error Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestErrorHandling ;=============================================================================== ; Test Case: _TestVersionInference ; Description: Checks display version inference for specific build numbers. ;=============================================================================== Func _TestVersionInference() Local $aReturn[2] Local $aTestBuilds[3][2] = [[19041, "2004"], [22000, "21H2"], [26100, "24H2"]] For $i = 0 To UBound($aTestBuilds) - 1 Local $sInferred = __WinVerDetect_InferDisplayVersion($aTestBuilds[$i][0]) If $sInferred <> $aTestBuilds[$i][1] Then $aReturn[0] = 0 $aReturn[1] = "Inference failed for Build " & $aTestBuilds[$i][0] & ". Expected '" & $aTestBuilds[$i][1] & "', got '" & $sInferred & "'." Return $aReturn EndIf Next $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestVersionInference ;=============================================================================== ; Test Case: _TestPathValidation ; Description: Tests the __WinVerDetect_IsValidWindowsPath helper function. ;=============================================================================== Func _TestPathValidation() Local $aReturn[2] If Not __WinVerDetect_IsValidWindowsPath(@WindowsDir) Then $aReturn[0] = 0 $aReturn[1] = "Failed to validate current Windows directory (" & @WindowsDir & ")." Return $aReturn EndIf If __WinVerDetect_IsValidWindowsPath(@TempDir) Then $aReturn[0] = 0 $aReturn[1] = "Incorrectly validated Temp directory (" & @TempDir & ") as a Windows path." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestPathValidation ;=============================================================================== ; Test Case: _TestIndividualFieldAccess ; Description: Tests retrieving a single field using the $iReturnIndex parameter. ;=============================================================================== Func _TestIndividualFieldAccess() Local $aReturn[2] If Not IsAdmin() Then $aReturn[0] = 2 $aReturn[1] = "Admin rights required." Return $aReturn EndIf Local $sBuild = _WinVerDetect_GetVersion(@WindowsDir, $WINVER_BUILD) If @error Or $sBuild = "" Or Int($sBuild) < 1000 Then $aReturn[0] = 0 $aReturn[1] = "Failed to retrieve individual Build Number. Error: " & @error Return $aReturn EndIf Local $sProductName = _WinVerDetect_GetVersion(@WindowsDir, $WINVER_PRODUCTNAME) If @error Or $sProductName = "" Then $aReturn[0] = 0 $aReturn[1] = "Failed to retrieve individual ProductName. Error: " & @error Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "Build: " & $sBuild & ", Product: " & $sProductName Return $aReturn EndFunc ;==>_TestIndividualFieldAccess ;=============================================================================== ; Test Case: _TestSpecificBuildsAndNames ; Description: Tests version name generation against known data points. ;=============================================================================== Func _TestSpecificBuildsAndNames() Local $aReturn[2] ; Test Data Format: [Build, Expected Product Name, Expected Display Version] Local $aTestCases[4][3] = [ _ [19045, "Windows 10", "22H2"], _ [22000, "Windows 11", "21H2"], _ [26100, "Windows Server 2025", "24H2"], _ [20348, "Windows Server 2022", "21H2"] _ ] For $aCase In $aTestCases Local $iBuild = $aCase[0] Local $sExpectedProduct = $aCase[1] Local $sExpectedDisplay = $aCase[2] Local $sFullName = __WinVerDetect_GetVersionNameByBuild($iBuild, "", $sExpectedProduct) If Not StringInStr($sFullName, $sExpectedProduct) Or Not StringInStr($sFullName, $sExpectedDisplay) Then $aReturn[0] = 0 $aReturn[1] = StringFormat("Build %d failed. Expected '%s %s', got '%s'", $iBuild, $sExpectedProduct, $sExpectedDisplay, $sFullName) Return $aReturn EndIf Next $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestSpecificBuildsAndNames ;=============================================================================== ; Test Case: _TestShortNameEdgeCases ; Description: Tests the GetShortName function with server and unknown values. ;=============================================================================== Func _TestShortNameEdgeCases() Local $aReturn[2] If __WinVerDetect_GetShortName("Windows Server 2022") <> "WIN_2022" Then $aReturn[0] = 0 $aReturn[1] = "Failed to get short name for Server 2022." Return $aReturn EndIf Local $sReturn = __WinVerDetect_GetShortName("Some Unknown OS") If $sReturn <> "UNKNOWN" Then $aReturn[0] = 0 $aReturn[1] = "Failed to return '" & $sReturn & "' for an unrecognized OS name." Return $aReturn EndIf $aReturn[0] = 1 $aReturn[1] = "" Return $aReturn EndFunc ;==>_TestShortNameEdgeCases ;=============================================================================== ; Test Case: _TestLiveSystemDetails ; Description: Displays detailed information about the live operating system. ;=============================================================================== Func _TestLiveSystemDetails() Local $aReturn[2] If Not IsAdmin() Then $aReturn[0] = 2 $aReturn[1] = "Admin rights required." Return $aReturn EndIf Local $aResult = _WinVerDetect_GetVersion() If @error Then $aReturn[0] = 0 $aReturn[1] = "Could not retrieve system details. Error: " & @error Return $aReturn EndIf Local $sDetails = @CRLF $sDetails &= "> State: " & $aResult[$WINVER_STATE] & @CRLF $sDetails &= "> Short Name: " & $aResult[$WINVER_SHORTNAME] & @CRLF $sDetails &= "> ProductName: " & $aResult[$WINVER_PRODUCTNAME] & @CRLF $sDetails &= "> Full Name: " & $aResult[$WINVER_FULLNAME] & @CRLF $sDetails &= "> Build: " & $aResult[$WINVER_BUILD] & @CRLF $sDetails &= "> UBR: " & $aResult[$WINVER_UBR] & @CRLF $sDetails &= "> DisplayVersion: " & $aResult[$WINVER_DISPLAYVERSION] & @CRLF $sDetails &= "> EditionID: " & $aResult[$WINVER_EDITIONID] & @CRLF $sDetails &= "> EditionType: " & $aResult[$WINVER_EDITIONTYPE] & @CRLF $sDetails &= "> IsInsider: " & ($aResult[$WINVER_ISINSIDER] ? "Yes" : "No") & @CRLF $aReturn[0] = 1 $aReturn[1] = $sDetails Return $aReturn EndFunc ;==>_TestLiveSystemDetails ;=============================================================================== ; Test Case: _TestSpecialEditionDetection ; Description: Tests the __WinVerDetect_InferEditionType function for special edition detection. ;=============================================================================== Func _TestSpecialEditionDetection() Local $aReturn[2] Local $iPassEdition = 0 ; Test Data Format: [ProductName, EditionID, Expected EditionType] Local $aTestCases[14][3] = [ _ ["Windows 10 Home", "CoreCountrySpecific", "Home China"], _ ["Windows 11 Home", "CoreCountrySpecific", "Home China"], _ ["Windows 10 Pro", "ProfessionalCountrySpecific", "Pro China"], _ ["Windows 10 Home N", "CoreN", "Home N"], _ ["Windows 11 Pro N", "ProfessionalN", "Pro N"], _ ["Windows 10 Home KN", "CoreKN", "Home KN"], _ ["Windows 10 Enterprise G", "EnterpriseG", "Enterprise G"], _ ["Windows 10 Enterprise LTSC", "EnterpriseS", "Enterprise LTSC"], _ ["Windows 10 IoT Enterprise", "IoTEnterprise", "IoT Enterprise"], _ ["Windows Server 2019", "ServerStandard", "Server Standard"], _ ["Windows Server 2022", "ServerDatacenter", "Server Datacenter"], _ ["Windows Server 2022", "ServerStandardCore", "Server Standard"], _ ["Windows 11 Enterprise", "Enterprise", "Enterprise"], _ ["Windows 10 Education", "Education", "Education"] _ ] ConsoleWrite("> Testing special edition detection capabilities:" & @CRLF) For $i = 0 To UBound($aTestCases) - 1 Local $sProductName = $aTestCases[$i][0] Local $sEditionID = $aTestCases[$i][1] Local $sExpected = $aTestCases[$i][2] Local $sResult = __WinVerDetect_InferEditionType($sProductName, $sEditionID) Local $sStatus = ($sResult = $sExpected) ? "+ ✓ PASS" : "! ✗ FAIL" ConsoleWrite($sStatus & " | ProductName: " & StringFormat("%-28s", $sProductName) & " | EditionID: " & StringFormat("%-27s", $sEditionID) & " | Result: " & $sResult & @CRLF) If $sResult = $sExpected Then $iPassEdition += 1 Next Local $sSummary = "Result: " & $iPassEdition & "/" & UBound($aTestCases) & " passed" If $iPassEdition = UBound($aTestCases) Then $aReturn[0] = 1 $aReturn[1] = $sSummary Else $aReturn[0] = 0 $aReturn[1] = $sSummary EndIf ConsoleWrite("> " & $sSummary & @CRLF & @CRLF) Return $aReturn EndFunc ;==>_TestSpecialEditionDetection ;=============================================================================== ; Test Case: _TestComprehensiveVersionNames ; Description: Tests __WinVerDetect_GetVersionNameByBuild with various build numbers and product names. ;=============================================================================== Func _TestComprehensiveVersionNames() Local $aReturn[2] Local $iPassVersion = 0 ; Test Data Format: [Build, DisplayVersion, ProductName, Expected Full Name] Local $aTestCases[32][4] = [ _ [528, "", "", "Windows NT 3.1 (Build 528) (July 1993) (Razzle)"], _ [807, "", "", "Windows NT 3.5 (Build 807) (September 1994) (Daytona)"], _ [1057, "", "", "Windows NT 3.51 (Build 1057) (May 1995) (Daytona)"], _ [1381, "", "", "Windows NT 4.0 (Build 1381) (August 1996) (Cairo)"], _ [1381, "", "Windows NT Server 4.0", "Windows NT Server 4.0 (Build 1381) (August 1996) (Cairo)"], _ [950, "", "", "Windows 95 Version 4.0 (Build 950) (August 1995) (Chicago)"], _ [1998, "", "", "Windows 98 Version 4.1 (Build 1998) (June 1998) (Memphis)"], _ [2222, "", "", "Windows 98 SE (Build 2222) (May 1999) (Memphis)"], _ [3000, "", "", "Windows Me Version 4.9 (Build 3000) (September 2000) (Millennium)"], _ [2195, "", "", "Windows 2000 Version 5.0 (Build 2195) (February 2000) (NT 5.0)"], _ [2195, "", "Windows 2000 Server", "Windows 2000 Server Version 5.0 (Build 2195) (February 2000) (NT 5.0)"], _ [2600, "", "", "Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)"], _ [2600, "5.1", "", "Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler)"], _ [2600, "5.1", "Windows XP Professional", "Windows XP Professional Version 5.1 (Build 2600) (October 2001) (Whistler)"], _ [3790, "", "", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _ [3790, "5.2", "", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _ [3790, "", "Windows Server 2003", "Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server)"], _ [6000, "", "", "Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)"], _ [6000, "6.0", "", "Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn)"], _ [7600, "", "", "Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)"], _ [7600, "6.1", "", "Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb)"], _ [9200, "", "", "Windows 8 Version 6.2 (Build 9200) (October 2012) (Metro)"], _ [9600, "", "", "Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)"], _ [9600, "Update1", "", "Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue)"], _ [10240, "", "", "Windows 10 1507 (Build 10240)"], _ [10240, "1507", "Windows 10", "Windows 10 1507 (Build 10240)"], _ [19045, "", "", "Windows 10 22H2 (Build 19045)"], _ [19045, "22H2", "Windows 10", "Windows 10 22H2 (Build 19045)"], _ [22000, "", "", "Windows 11 21H2 (Build 22000)"], _ [22000, "21H2", "Windows 11", "Windows 11 21H2 (Build 22000)"], _ [20348, "", "Windows Server 2022", "Windows Server 2022 22H2 (Build 20348)"], _ [26100, "", "Windows Server 2025", "Windows Server 2025 24H2 (Build 26100)"] _ ] ConsoleWrite("> Testing comprehensive version name generation for __WinVerDetect_GetVersionNameByBuild:" & @CRLF) For $i = 0 To UBound($aTestCases) - 1 Local $iBuild = $aTestCases[$i][0] Local $sDisplayVersion = $aTestCases[$i][1] Local $sProductName = $aTestCases[$i][2] Local $sExpected = $aTestCases[$i][3] Local $sActual = __WinVerDetect_GetVersionNameByBuild($iBuild, $sDisplayVersion, $sProductName) ;~ ConsoleWrite('['&$iBuild&', "'&$sDisplayVersion&'", "'&$sProductName&'", "'&$sActual&'"], _' & @CRLF) Local $sStatus = ($sActual = $sExpected) ? "+ ✓ PASS" : "! ✗ FAIL" ConsoleWrite($sStatus & " | Build: " & StringFormat("%-6s", $iBuild) & " | DisplayVersion: " & StringFormat("%-10s", $sDisplayVersion) & " | ProductName: " & StringFormat("%-30s", $sProductName) & " | Result: " & $sActual & @CRLF) If $sActual <> $sExpected Then ConsoleWrite(" -> Expected: " & $sExpected & @CRLF) ConsoleWrite(" -> Actual: " & $sActual & @CRLF) EndIf If $sActual = $sExpected Then $iPassVersion += 1 Next Local $sSummary = "Result: " & $iPassVersion & "/" & UBound($aTestCases) & " passed" If $iPassVersion = UBound($aTestCases) Then $aReturn[0] = 1 $aReturn[1] = $sSummary Else $aReturn[0] = 0 $aReturn[1] = $sSummary EndIf ConsoleWrite("> " & $sSummary & @CRLF & @CRLF) Return $aReturn EndFunc ;==>_TestComprehensiveVersionNames #EndRegion TEST_SUITE > Result test: > [ INFO ] STARTING COMPREHENSIVE TEST SUITE > UDF Library: Windows Version Detector ===================================================================================== + [ PASSED ] Database Initialization + [ PASSED ] Live System Detection Current OS: Windows 10 Enterprise LTSC 2021 + [ PASSED ] Utility Functions + [ PASSED ] Error Handling + [ PASSED ] Version Inference + [ PASSED ] Path Validation + [ PASSED ] Individual Field Access Build: 19045, Product: Windows 10 Enterprise LTSC 2021 + [ PASSED ] Specific Builds And Names + [ PASSED ] Short Name Edge Cases + [ PASSED ] Live System Details > State: Live > Short Name: WIN_10 > ProductName: Windows 10 Enterprise LTSC 2021 > Full Name: Windows 10 Version 22H2 (Build 19045.6216) > Build: 19045 > UBR: 6216 > DisplayVersion: 22H2 > EditionID: EnterpriseS > EditionType: Enterprise LTSC > IsInsider: No > Testing special edition detection capabilities: + ✓ PASS | ProductName: Windows 10 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 11 Home | EditionID: CoreCountrySpecific | Result: Home China + ✓ PASS | ProductName: Windows 10 Pro | EditionID: ProfessionalCountrySpecific | Result: Pro China + ✓ PASS | ProductName: Windows 10 Home N | EditionID: CoreN | Result: Home N + ✓ PASS | ProductName: Windows 11 Pro N | EditionID: ProfessionalN | Result: Pro N + ✓ PASS | ProductName: Windows 10 Home KN | EditionID: CoreKN | Result: Home KN + ✓ PASS | ProductName: Windows 10 Enterprise G | EditionID: EnterpriseG | Result: Enterprise G + ✓ PASS | ProductName: Windows 10 Enterprise LTSC | EditionID: EnterpriseS | Result: Enterprise LTSC + ✓ PASS | ProductName: Windows 10 IoT Enterprise | EditionID: IoTEnterprise | Result: IoT Enterprise + ✓ PASS | ProductName: Windows Server 2019 | EditionID: ServerStandard | Result: Server Standard + ✓ PASS | ProductName: Windows Server 2022 | EditionID: ServerDatacenter | Result: Server Datacenter + ✓ PASS | ProductName: Windows Server 2022 | EditionID: ServerStandardCore | Result: Server Standard + ✓ PASS | ProductName: Windows 11 Enterprise | EditionID: Enterprise | Result: Enterprise + ✓ PASS | ProductName: Windows 10 Education | EditionID: Education | Result: Education > Result: 14/14 passed + [ PASSED ] Special Edition Detection Result: 14/14 passed > Testing comprehensive version name generation for __WinVerDetect_GetVersionNameByBuild: + ✓ PASS | Build: 528 | DisplayVersion: | ProductName: | Result: Windows NT 3.1 (Build 528) (July 1993) (Razzle) + ✓ PASS | Build: 807 | DisplayVersion: | ProductName: | Result: Windows NT 3.5 (Build 807) (September 1994) (Daytona) + ✓ PASS | Build: 1057 | DisplayVersion: | ProductName: | Result: Windows NT 3.51 (Build 1057) (May 1995) (Daytona) + ✓ PASS | Build: 1381 | DisplayVersion: | ProductName: | Result: Windows NT 4.0 (Build 1381) (August 1996) (Cairo) + ✓ PASS | Build: 1381 | DisplayVersion: | ProductName: Windows NT Server 4.0 | Result: Windows NT Server 4.0 (Build 1381) (August 1996) (Cairo) + ✓ PASS | Build: 950 | DisplayVersion: | ProductName: | Result: Windows 95 Version 4.0 (Build 950) (August 1995) (Chicago) + ✓ PASS | Build: 1998 | DisplayVersion: | ProductName: | Result: Windows 98 Version 4.1 (Build 1998) (June 1998) (Memphis) + ✓ PASS | Build: 2222 | DisplayVersion: | ProductName: | Result: Windows 98 SE (Build 2222) (May 1999) (Memphis) + ✓ PASS | Build: 3000 | DisplayVersion: | ProductName: | Result: Windows Me Version 4.9 (Build 3000) (September 2000) (Millennium) + ✓ PASS | Build: 2195 | DisplayVersion: | ProductName: | Result: Windows 2000 Version 5.0 (Build 2195) (February 2000) (NT 5.0) + ✓ PASS | Build: 2195 | DisplayVersion: | ProductName: Windows 2000 Server | Result: Windows 2000 Server Version 5.0 (Build 2195) (February 2000) (NT 5.0) + ✓ PASS | Build: 2600 | DisplayVersion: | ProductName: | Result: Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler) + ✓ PASS | Build: 2600 | DisplayVersion: 5.1 | ProductName: | Result: Windows XP Version 5.1 (Build 2600) (October 2001) (Whistler) + ✓ PASS | Build: 2600 | DisplayVersion: 5.1 | ProductName: Windows XP Professional | Result: Windows XP Professional Version 5.1 (Build 2600) (October 2001) (Whistler) + ✓ PASS | Build: 3790 | DisplayVersion: | ProductName: | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server) + ✓ PASS | Build: 3790 | DisplayVersion: 5.2 | ProductName: | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server) + ✓ PASS | Build: 3790 | DisplayVersion: | ProductName: Windows Server 2003 | Result: Windows Server 2003 Version 5.2 (Build 3790) (April 2003) (Whistler Server) + ✓ PASS | Build: 6000 | DisplayVersion: | ProductName: | Result: Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn) + ✓ PASS | Build: 6000 | DisplayVersion: 6.0 | ProductName: | Result: Windows Vista Version 6.0 (Build 6000) (January 2007) (Longhorn) + ✓ PASS | Build: 7600 | DisplayVersion: | ProductName: | Result: Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb) + ✓ PASS | Build: 7600 | DisplayVersion: 6.1 | ProductName: | Result: Windows 7 Version 6.1 (Build 7600) (October 2009) (Blackcomb) + ✓ PASS | Build: 9200 | DisplayVersion: | ProductName: | Result: Windows 8 Version 6.2 (Build 9200) (October 2012) (Metro) + ✓ PASS | Build: 9600 | DisplayVersion: | ProductName: | Result: Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue) + ✓ PASS | Build: 9600 | DisplayVersion: Update1 | ProductName: | Result: Windows 8.1 Version 6.3 (Build 9600) (October 2013) (Blue) + ✓ PASS | Build: 10240 | DisplayVersion: | ProductName: | Result: Windows 10 1507 (Build 10240) + ✓ PASS | Build: 10240 | DisplayVersion: 1507 | ProductName: Windows 10 | Result: Windows 10 1507 (Build 10240) + ✓ PASS | Build: 19045 | DisplayVersion: | ProductName: | Result: Windows 10 22H2 (Build 19045) + ✓ PASS | Build: 19045 | DisplayVersion: 22H2 | ProductName: Windows 10 | Result: Windows 10 22H2 (Build 19045) + ✓ PASS | Build: 22000 | DisplayVersion: | ProductName: | Result: Windows 11 21H2 (Build 22000) + ✓ PASS | Build: 22000 | DisplayVersion: 21H2 | ProductName: Windows 11 | Result: Windows 11 21H2 (Build 22000) + ✓ PASS | Build: 20348 | DisplayVersion: | ProductName: Windows Server 2022 | Result: Windows Server 2022 22H2 (Build 20348) + ✓ PASS | Build: 26100 | DisplayVersion: | ProductName: Windows Server 2025 | Result: Windows Server 2025 24H2 (Build 26100) > Result: 32/32 passed + [ PASSED ] Comprehensive Version Names Result: 32/32 passed ===================================================================================== > [ INFO ] TEST SUITE SUMMARY + Passed : 12 ! Failed : 0 - Skipped : 0 > Total : 12 > Success Rate (excluding skipped): 100.0%
    3 points
  14. ioa747

    _CircularProgress

    I created _CircularProgress , with the idea of calling it as a single function. ; https://www.autoitscript.com/forum/topic/213118-_circularprogress/ ;---------------------------------------------------------------------------------------- ; Title...........: _CircularProgress.au3 ; Description.....: Creates a customizable circular progress bar using GDI+ graphics. ; AutoIt Version..: 3.3.16.1 Author: ioa747 Script Version: 0.8 ; Note............: Testet in Win10 22H2 Date:11/09/2025 ; Based on post ..: https://www.autoitscript.com/forum/topic/213118-_circularprogress/#findComment-1545797 ;---------------------------------------------------------------------------------------- #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WinAPISysWin.au3> #include <WinAPIConstants.au3> #include <WindowsConstants.au3> _Example() ; as demo ;~ _Example2() ; as demo ;~ _Example3() ; as demo Func _Example() Local $aList[2000] Local $iCnt = UBound($aList) ConsoleWrite("$iCnt=" & $iCnt & @CRLF) Local $nProgress For $i = 1 To UBound($aList) $nProgress = Int($i / $iCnt * 100) ConsoleWrite($i & ") $nProgress=" & $nProgress & @CRLF) _CircularProgress($nProgress) Next Sleep(200) ; Give it some time to see the 100%. _CircularProgress(101) ; Clean up the progress bar window EndFunc ;==>_Example Func _Example2() Local $aList[2000] Local $iCnt = UBound($aList) Local $nProgress _CircularProgress(0, 300, @DesktopWidth * 0.8, @DesktopHeight * 0.3) For $i = 1 To UBound($aList) $nProgress = Int($i / $iCnt * 100) _CircularProgress($nProgress) Next For $i = 1 To 2 _CircularProgress($nProgress, Default, Default, Default, Default, 0xFFFFFFFF, 0xFF4CFF00, 0xFFF6FF00) Sleep(500) _CircularProgress($nProgress, Default, Default, Default, Default, 0xFFFFFFFF, 0xFFF6FF00, 0xFF4CFF00) Sleep(500) Next _CircularProgress(101) ; Clean up the progress bar window EndFunc ;==>_Example Func _Example3() Local $aList[2000] Local $iCnt = UBound($aList) ConsoleWrite("$iCnt=" & $iCnt & @CRLF) Local $nProgress _CircularProgress($nProgress, 300, -1, -1, 20, Default, Default, Default, 150) For $i = 1 To UBound($aList) $nProgress = Int($i / $iCnt * 100) _CircularProgress($nProgress) Next Sleep(500) ; Give it some time to show the 100%. _CircularProgress(101) ; Clean up the progress bar window EndFunc ;==>_Example ; #FUNCTION# ==================================================================================================================== ; Name...........: _CircularProgress ; Description....: Creates a customizable circular progress bar using GDI+ graphics. ; Syntax.........: _CircularProgress($iPercent [, $iSize = 300 [, $iLeft = -1 [, $iTop = -1 [, $iThickness = 20 [, $TextCol = 0xFFBFBFBF [, $StartCol = 0xFFFFFF00, $EndCol = 0xFFFF0000 [, $iBgTrans = 0]]]]]]]) ; Parameters.....: $iPercent - The percentage complete for the progress bar (0 to 100). ; $iSize - [optional] width and height of the circular progress bar. (Default is 300) ; $iLeft - [optional] X-coordinate of the top-left corner. (Default is -1 for center) ; $iTop - [optional] Y-coordinate of the top-left corner. (Default is -1 for center) ; $iThickness - [optional] Thickness of the progress arc. (Default is 20) ; $TextCol - [optional] Color of the text within the progress bar. (Default is Silver) ; $StartCol - [optional] Start color of the progress arc gradient. (Default is Yellow) ; $EndCol - [optional] End color of the progress arc gradient. (Default is Red) ; $iBgTrans - [optional] The transparency of background, a number in the range 0 - 255. (Default is 0) ; Return values .: Success: create the progress bar GUI ; Author ........: ioa747 , Thank to UEZ ; Modified ......: 11/09/2025 - v0.8 ; Remarks .......: Cleanup is handled automatically by passing an $iPercent > 100. ; Avoid using 0x050505 Color for $TextCol, $StartCol, or $EndCol, as it is used as a transparency color for the background. ; Related .......: _GDIPlus_Startup, _GDIPlus_GraphicsCreateFromHWND, etc. ; Link ..........: https://www.autoitscript.com/forum/topic/213113-simple-circular-progressbar-with-smooth-edges-gradient-color/#findComment-1545755 ; Example .......: _CircularProgress(50, 300, -1, -1, 23, 0xFFBFBFBF, 0xFFFFFF00, 0xFFFF0000) ; =============================================================================================================================== Func _CircularProgress($iPercent, $iSize = 300, $iLeft = -1, $iTop = -1, $iThickness = 23, $TextCol = 0xFFDCDCDC, $StartCol = 0xFFFFFF00, $EndCol = 0xFFFF0000, $iBgTrans = 0) Local Static $hGUI, $inSize, $inThickness, $iRadius, $iX, $iY, $BackCol, $bInit = False If Not $bInit Then _GDIPlus_Startup() $BackCol = "0x" & Hex($iBgTrans, 2) & "000000" $inSize = ($iSize < 40 ? 300 : $iSize) $inThickness = ($iThickness > ($inSize * 0.5) ? $inSize * 0.5 : ($iThickness < 2 ? 20 : $iThickness) ) $iRadius = ($inSize - 4) / 2 $iX = $inSize / 2 $iY = $iX $hGUI = GUICreate("RingProgressBar", $inSize, $inSize, $iLeft, $iTop, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) GUISetState(@SW_SHOWNOACTIVATE) $bInit = True EndIf If $iPercent > 100 Then _GDIPlus_Shutdown() GUIDelete($hGUI) $bInit = False Return EndIf ; Create an off-screen bitmap for double-buffering Local Const $hBmp = _GDIPlus_BitmapCreateFromScan0($inSize, $inSize) Local Const $hBmpGraphics = _GDIPlus_ImageGetGraphicsContext($hBmp) _GDIPlus_GraphicsSetSmoothingMode($hBmpGraphics, 4) _GDIPlus_GraphicsSetTextRenderingHint($hBmpGraphics, 4) ; Draw arc backround Local Const $hbackround = _GDIPlus_BrushCreateSolid($BackCol) _GDIPlus_GraphicsFillEllipse($hBmpGraphics, $iX - $iRadius + 1, $iY - $iRadius + 1, ($iRadius * 2) - 2, ($iRadius * 2) - 2, $hbackround) _GDIPlus_BrushDispose($hbackround) ; Draw progress arc as pie Local $angle = ($iPercent / 100) * 360 Local Const $hBrushProg = _GDIPlus_LineBrushCreate($iX - $iRadius, $iY, $iX + $iRadius, $iY, $EndCol, $StartCol, 1) Local Const $hPen = _GDIPlus_PenCreate2($hBrushProg, $inThickness) _GDIPlus_GraphicsDrawArc($hBmpGraphics, $iX - $iRadius + $inThickness / 2, $iY - $iRadius + $inThickness / 2, _ $iRadius * 2 - $inThickness, $iRadius * 2 - $inThickness, -90, $angle, $hPen) _GDIPlus_BrushDispose($hBrushProg) ; Draw percentage text Local Const $hPath = _GDIPlus_PathCreate() Local Const $iFontSize = Int($iRadius * 0.33) Local Const $hFamily = _GDIPlus_FontFamilyCreate("Times New Roman") Local Const $hFormat = _GDIPlus_StringFormatCreate() Local Const $tLayout = _GDIPlus_RectFCreate($iX - $iFontSize * 1.5, $iY - $iFontSize * 0.5, $iFontSize * 3, $iFontSize) _GDIPlus_StringFormatSetAlign($hFormat, 2) Local Const $hBrushText = _GDIPlus_BrushCreateSolid($TextCol) _GDIPlus_PenSetColor($hPen, 0xF0404040) _GDIPlus_PenSetWidth($hPen, $iFontSize * 0.0381) _GDIPlus_PenSetLineJoin($hPen, 2) _GDIPlus_PathAddString($hPath, StringFormat("%d%", $iPercent), $tLayout, $hFamily, 1, $iFontSize, $hFormat) _GDIPlus_GraphicsDrawPath($hBmpGraphics, $hPath, $hPen) _GDIPlus_GraphicsFillPath($hBmpGraphics, $hPath, $hBrushText) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_PenDispose($hPen) _GDIPlus_BrushDispose($hBrushText) _GDIPlus_PathDispose($hPath) ; Create HBITMAP and display Local $hHBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp) ;_WinAPI_BitmapDisplayTransparentInGUI($hHBmp, $hGUI) Local $iOpacity = 0xFF, $iFlags = $ULW_ALPHA, $bReleaseGDI = True, $tDest = Null, $iBGR = 0 If Not BitAND(GUIGetStyle($hGUI)[1], $WS_EX_LAYERED) = $WS_EX_LAYERED Then Return SetError(1, 0, 0) Local $tDim = DllStructCreate($tagBITMAP) If Not _WinAPI_GetObject($hHBmp, DllStructGetSize($tDim), DllStructGetPtr($tDim)) Then Return SetError(2, 0, 0) Local $tSize = DllStructCreate($tagSIZE), $tSource = DllStructCreate($tagPOINT), $tBlend = DllStructCreate($tagBLENDFUNCTION) Local Const $hScrDC = _WinAPI_GetDC(0), $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC), $hOld = _WinAPI_SelectObject($hMemDC, $hHBmp) $tSize.X = $tDim.bmWidth $tSize.Y = $tDim.bmHeight $tBlend.Alpha = $iOpacity $tBlend.Format = 1 _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, $tDest, $tSize, $hMemDC, $tSource, $iBGR, $tBlend, $iFlags) _WinAPI_ReleaseDC(0, $hScrDC) _WinAPI_SelectObject($hMemDC, $hOld) _WinAPI_DeleteDC($hMemDC) If $bReleaseGDI Then _WinAPI_DeleteObject($hHBmp) ;Return True _GDIPlus_BitmapDispose($hBmp) _GDIPlus_GraphicsDispose($hBmpGraphics) EndFunc ;==>_CircularProgress Please, every comment is appreciated! leave your comments and experiences here! Thank you very much
    3 points
  15. argumentum

    EndIf "overhead"

    Global $iTimer, $iVariable = 1 For $tryNo = 1 To 3 Sleep(1000) $iTimer1 = TimerInit() For $A = 1 To 10000 If $iVariable Then $iVariable = 1 Next $iTimer1 = Round(TimerDiff($iTimer1), 1) ConsoleWrite("10,000 runs (single line If statement): " & @TAB & $iTimer1 & "ms" & @CRLF) $iTimer2 = TimerInit() For $A = 1 To 10000 If $iVariable Then $iVariable = 1 EndIf Next $iTimer2 = Round(TimerDiff($iTimer2), 1) ConsoleWrite("10,000 runs (If statement with EndIf): " & @TAB & @TAB & $iTimer2 & "ms" & @CRLF) $iDifference = Round(($iTimer1 - $iTimer2) / $iTimer2, 2) ConsoleWrite("Percentage Difference: " & @TAB & @TAB & @TAB & @TAB & @TAB & @TAB & $iDifference * 100 & "%" & @CRLF & @CRLF) Next Exit 10,000 runs (single line If statement): 40.5ms 10,000 runs (If statement with EndIf): 3.1ms Percentage Difference: 1206% 10,000 runs (single line If statement): 5.7ms 10,000 runs (If statement with EndIf): 3ms Percentage Difference: 90% 10,000 runs (single line If statement): 5.8ms 10,000 runs (If statement with EndIf): 3ms Percentage Difference: 93% I'll write what makes the code more readable. Anyone having to depend on this, needs to rethink their code. My 2 cents
    3 points
  16. UEZ

    _CircularProgress

    It looks ugly on my Notebook: You may use: Func _WinAPI_BitmapDisplayTransparentInGUI(ByRef $hHBitmap, ByRef $hGUI, $iOpacity = 0xFF, $iFlags = $ULW_ALPHA, $bReleaseGDI = True, $tDest = Null, $iBGR = 0) If Not BitAND(GUIGetStyle($hGUI)[1], $WS_EX_LAYERED) = $WS_EX_LAYERED Then Return SetError(1, 0, 0) Local $tDim = DllStructCreate($tagBITMAP) If Not _WinAPI_GetObject($hHBitmap, DllStructGetSize($tDim), DllStructGetPtr($tDim)) Then Return SetError(2, 0, 0) Local $tSize = DllStructCreate($tagSIZE), $tSource = DllStructCreate($tagPOINT), $tBlend = DllStructCreate($tagBLENDFUNCTION) Local Const $hScrDC = _WinAPI_GetDC(0), $hMemDC = _WinAPI_CreateCompatibleDC($hScrDC), $hOld = _WinAPI_SelectObject($hMemDC, $hHBitmap) $tSize.X = $tDim.bmWidth $tSize.Y = $tDim.bmHeight $tBlend.Alpha = $iOpacity $tBlend.Format = 1 _WinAPI_UpdateLayeredWindow($hGUI, $hScrDC, $tDest, $tSize, $hMemDC, $tSource, $iBGR, $tBlend, $iFlags) _WinAPI_ReleaseDC(0, $hScrDC) _WinAPI_SelectObject($hMemDC, $hOld) _WinAPI_DeleteDC($hMemDC) If $bReleaseGDI Then _WinAPI_DeleteObject($hHBitmap) Return True EndFunc ;==>_WinAPI_BitmapDisplayTransparentInGUI to get a proper display. See for an example. _WinAPI_SetLayeredWindowAttributes() only makes is ugly!
    3 points
  17. Play with the colors, angle and translations: ;AutoIt v3.3.9.21 or higher needed! ;coded by UEZ build 2013-10-13 #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> _GDIPlus_Startup() Global Const $STM_SETIMAGE = 0x0172 Global Const $iW = 300, $iH = 300 Global Const $hGUI = GUICreate("GDI+ Ring Progressbar", $iW, $iH, -1, -1, $WS_POPUPWINDOW, $WS_EX_TOPMOST) GUISetBkColor(0) Global Const $iPic = GUICtrlCreatePic("", 0, 0, $iW, $iH) ;~ GUICtrlSetState(-1, $GUI_DISABLE) GUISetState() Global $hHBmp_BG, $hB, $fPerc, $iSleep = 60 GUIRegisterMsg($WM_TIMER, "PlayAnim") DllCall("user32.dll", "int", "SetTimer", "hwnd", $hGUI, "int", 0, "int", $iSleep, "int", 0) Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE GUIRegisterMsg($WM_TIMER, "") _WinAPI_DeleteObject($hHBmp_BG) _GDIPlus_Shutdown() GUIDelete() Exit EndSwitch Until False Func PlayAnim() $hHBmp_BG = _GDIPlus_RingProgressbar($fPerc) $hB = GUICtrlSendMsg($iPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBmp_BG) If $hB Then _WinAPI_DeleteObject($hB) _WinAPI_DeleteObject($hHBmp_BG) $fPerc += 0.33333 If $fPerc > 100 Then $fPerc = 0 EndFunc ;==>PlayAnim Func _GDIPlus_RingProgressbar($fPerc, $iSize = 300, $sText = "Please wait...") Local Const $hBmp = _GDIPlus_BitmapCreateFromMemory(_Background_Texture()) Local Const $hTexture = _GDIPlus_TextureCreate($hBmp) _GDIPlus_BitmapDispose($hBmp) Local Const $hBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize) Local Const $hCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetPixelOffsetMode($hCtxt, $GDIP_PIXELOFFSETMODE_HIGHQUALITY) _GDIPlus_GraphicsSetSmoothingMode($hCtxt, 2) _GDIPlus_GraphicsFillRect($hCtxt, 0, 0, $iSize, $iSize, $hTexture) If $fPerc < 0 Then $fPerc = 0 If $fPerc > 100 Then $fPerc = 100 Local Const $hPath = _GDIPlus_PathCreate(), $hPath2 = _GDIPlus_PathCreate(), _ $fRadius = $iSize / 1.5, $iX = ($iSize - $fRadius) / 2, $iY = ($iSize - $fRadius) / 2, _ $fDX = $iSize / 10, $fAngel = $fPerc * 360 / 100, $fSize = $iSize / 15 _GDIPlus_PathAddEllipse($hPath, $iX, $fDX + $iY, $fRadius, $fRadius) Local $hBrush = _GDIPlus_LineBrushCreate($iX, $fDX + $iY, $fRadius, $fRadius, 0, 0, 1) Local $aInterpolations[4][2] ;define the interpolated colors and positions $aInterpolations[0][0] = 3 $aInterpolations[1][0] = 0xFF800000 ;Red $aInterpolations[1][1] = 0 $aInterpolations[2][0] = 0xFFFF6700 ;Orange $aInterpolations[2][1] = 0.5 $aInterpolations[3][0] = 0xFFFFFF00 ;Yellow $aInterpolations[3][1] = 1.0 $hMatrix = _GDIPlus_MatrixCreate() _GDIPlus_MatrixTranslate($hMatrix, $fRadius, $fRadius) _GDIPlus_MatrixRotate($hMatrix, -35, False) _GDIPlus_LineBrushMultiplyTransform($hBrush, $hMatrix, False) _GDIPlus_LineBrushSetPresetBlend($hBrush, $aInterpolations) _GDIPlus_MatrixDispose($hMatrix) Local Const $hPen = _GDIPlus_PenCreate2($hBrush, $fSize) _GDIPlus_GraphicsDrawPath($hCtxt, $hPath, $hPen) _GDIPlus_PathReset($hPath) Local Const $hPen2 = _GDIPlus_PenCreate2($hTexture, $fSize + 4) _GDIPlus_PathAddArc($hPath, $iX, $fDX + $iY, $fRadius, $fRadius, -90, $fAngel) _GDIPlus_GraphicsDrawPath($hCtxt, $hPath, $hPen2) _GDIPlus_PathReset($hPath) Local Const $hFamily = _GDIPlus_FontFamilyCreate("Verdana") Local Const $hFormat = _GDIPlus_StringFormatCreate() Local Const $tLayout = _GDIPlus_RectFCreate(0, $iSize / 12, $iSize, 0) Local Const $tLayout2 = _GDIPlus_RectFCreate(0, ($iSize + $iSize / 18) / 2, $iSize, 0) _GDIPlus_StringFormatSetAlign($hFormat, 1) Local Const $hBrush2 = _GDIPlus_BrushCreateSolid(0xE0FFFFFF) _GDIPlus_PenSetColor($hPen, 0x80000000) _GDIPlus_PenSetWidth($hPen, 4) _GDIPlus_PathAddString($hPath, $sText, $tLayout, $hFamily, 0, $iSize / 12, $hFormat) _GDIPlus_PathAddString($hPath, StringFormat("%02d%", $fPerc), $tLayout2, $hFamily, 0, $iSize / 9, $hFormat) _GDIPlus_GraphicsDrawPath($hCtxt, $hPath, $hPen) _GDIPlus_GraphicsFillPath($hCtxt, $hPath, $hBrush2) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_PenDispose($hPen) _GDIPlus_PenDispose($hPen2) _GDIPlus_BrushDispose($hBrush) _GDIPlus_BrushDispose($hBrush2) _GDIPlus_BrushDispose($hTexture) _GDIPlus_PathDispose($hPath) _GDIPlus_PathDispose($hPath2) _GDIPlus_GraphicsDispose($hCtxt) Local Const $hHBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) _GDIPlus_BitmapDispose($hBitmap) Return $hHBmp EndFunc ;Code below was generated by: 'File to Base64 String' Code Generator v1.12 Build 2013-05-17 Func _Background_Texture($bSaveBinary = False, $sSavePath = @ScriptDir) Local $Background_Texture $Background_Texture &= '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' $Background_Texture &= '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' $Background_Texture &= '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' $Background_Texture &= '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' $Background_Texture &= '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' $Background_Texture &= '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' $Background_Texture &= 'LDtyT0/mXl/5NOLjdHdfuZrUd46l0feIgZuiLJ89Qb51eMRqmGGruU5O9yhvUKrEpXe63MNc5bmK037iLdxC+dvMA8yir0Mo4v7l2l8icq5RyzfLAUVy7lXdNoHR3FLbHcTJj8xC+YOdfn+pyYf98QbtraVYVydwr52wOzANnUwsKh48QC8GMo9H+4lHwf7iDN8DnxKVMZEt2lr0/UpvT9SsUvXEprN66lZcOonQ/UD1x15mJ95ue7fUVW3wTTznxMlls49wnfjNTFb4Sr3Xcep2fuBaBecTqu5tQcssFX+Iq+94lafklLtV9TkZs8QqlXvVQz23yQPJMwdYuIplY3yd6iW4WJStWZay1+pVZvHqBhWMv6iZ5q4VWenmNGm/XqGRd7ceIE4zviU8moJZX8zbnT+CYsPGczQwUYOeY88/5l1M3p0Rb1cMmBgdGY7b3UwMXPC4c7C55t2cSlv4JR33EKp317hYr0lH3EtyOWX4/ECnszBo14l28My8Smhy5mHkSoZCu5Xl+5k/NxS/LzGqMc4zMXj+YUtMRWLvUKcL28+o4ZvcWM6Gs/1FpSOtXCrOxz49Rl86efEoOmqggmHB3/U326P4g0FLqGWFH3FbL9y17ddxRmrw/cFQoXG43bDqLjNxY1TK9j5hjRhqGuZisjv/ALCYdiCVqa9hMmWy9TutIgpd76lUeXUT/wAJWhXMq+W5w9yt+WDBfc05d9R8lmm37mO37Rd5+43q/wAoIwCy1c7OGJ/Z/UHHJl59RVHZf+4izjrrx7l5d64g5tvA/wAQBvo/xFLv/FQwLG5i5qkBT0/uD1f3LKVeu5Yu2eV1j7i8zrqXlWj/AHMXG31F5/z5gY3ALq9zJ/qXvn6m/O4yfZxBJnGepSHflU5bc8RmR4fzB15eJeOHLHGj8zw6/wCoa18TxO+GXejbuWdjuDODuZGn7hnEdkSuJ6PuJdY2gJz9oBeb3AvNwCu67Qe7s4iCn0HxEA3eq3AbZ2/iFLldPEo96/UA7Sl4vSyUo3qUfzzBvlqXfx/U87/zB2Hj9xyi3USjbU9n3AKq31Ck53APqUOrgC5xBh7JgHGY/wApW3u3mVxdOZi7HMHJvD3FuFH+HMESWYOe/wCpZVN/cWsJndx6wtvcMtO5Yc8p+5zpmlKe5R4m3Nza7gAvvqL4XFfPD3BTd1uNlpOINbO1fUHZyNTXMEDcbbYT9QKKvLDGVTs4RrK8VjPiDhF8xcNhSOWXjdRpNygV0g0Z/ma7tcGOVr3CpeZQS7+5QrvD3HDl+Zk/3L3FucZhYN4e41eTJDLbvuFptw6l5ydxO0queeo5b/MKrKuYYCunME3lwwwxbX/uYtOx8TTC8xsjgthZkv3FLhYg0orS4zLTpKDamY/5cDPGnnxAyImu4jWq13GxqjHZF4X8iYC3Tsl7y2rp17lqeDw8xxb/AAQMmtdyimVn45nHe4FM+eZWC7jk4lW8biYXUSuNX3ALo3/uZRS0XFTYNwSs1cE8b3UsMK3EGzwxLyrW9RYbrcd8bi5++ai8PqZPzLVmoiEK3Loa5HHuDbZ9RtM1vqO8Vm4tjJuO8xhxx8kqgXHm/Crn/9k=' Local $bString = Binary(_Base64Decode($Background_Texture)) If $bSaveBinary Then Local $hFile = FileOpen($sSavePath & "\Dark Texture 300x300.jpg", 18) FileWrite($hFile, $bString) FileClose($hFile) EndIf Return $bString EndFunc ;==>_Background_Texture Func _Base64Decode($sB64String) Local $a_Call = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "ptr", 0, "dword*", 0, "ptr", 0, "ptr", 0) If @error Or Not $a_Call[0] Then Return SetError(1, 0, "") Local $a = DllStructCreate("byte[" & $a_Call[5] & "]") $a_Call = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "struct*", $a, "dword*", $a_Call[5], "ptr", 0, "ptr", 0) If @error Or Not $a_Call[0] Then Return SetError(2, 0, "") Return DllStructGetData($a, 1) EndFunc ;==>_Base64Decode
    3 points
  18. pixelsearch, analytical and comprehensive as always, thank you very much The solution proposed by Danyfirex 🏆, in this particular post is completely functional #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <GuiTab.au3> ;>> Target: C:\Program Files (x86)\AutoIt3\Examples\Helpfile\GUICtrlCreateTab.au3 If Not WinExists("My GUI Tab") Then Exit Local $hWnd = WinWait("My GUI Tab", "", 1) ConsoleWrite("$hWnd=" & $hWnd & @CRLF) Local $hCtrl = ControlGetHandle($hWnd, "", "SysTabControl321") ConsoleWrite("$hCtrl=" & $hCtrl & @CRLF) Local $hParentWnd = _WinAPI_GetParent($hCtrl) ConsoleWrite("$hParentWnd=" & $hParentWnd & @CRLF) ; Show number of tabs Local $iTabCnt = _GUICtrlTab_GetItemCount($hCtrl) ConsoleWrite("Number of tabs: " & $iTabCnt & @CRLF & @CRLF) Local $sItemText, $aItem ; Now is working !! For $x = 0 To $iTabCnt - 1 $aItem = _GUICtrlTab_GetItemEx($hCtrl, $x) $sItemText = $aItem[1] ConsoleWrite("$sItemText=" & $sItemText & @CRLF) Next Func _GUICtrlTab_GetItemEx($hWnd, $iIndex) If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd) Local $tagTCITEMEx = $tagTCITEM & ";ptr Filler" ; strange the Filler is erased by TCM_GETITEM : MS Bug!!! If Not _WinAPI_InProcess($hWnd, $__g_hGUICtrl_LastWnd) Then ;x86 read remote x64 If (Not @AutoItX64) And (Not _WinAPI_IsWow64Process(DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0)[2])) Then $tagTCITEMEx = StringReplace($tagTCITEMEx, "ptr", "INT64") EndIf ;x64 read remote x86 If (@AutoItX64) And (_WinAPI_IsWow64Process(DllCall("user32.dll", "dword", "GetWindowThreadProcessId", "hwnd", $hWnd, "dword*", 0)[2])) Then $tagTCITEMEx = StringReplace($tagTCITEMEx, "ptr", "ULONG") EndIf EndIf Local $tItem = DllStructCreate($tagTCITEMEx) DllStructSetData($tItem, "Mask", $TCIF_ALLDATA) DllStructSetData($tItem, "StateMask", BitOR($TCIS_HIGHLIGHTED, $TCIS_BUTTONPRESSED)) Local $tBuffer, $iMsg If _GUICtrlTab_GetUnicodeFormat($hWnd) Then $tBuffer = $__g_tTabBuffer $iMsg = $TCM_GETITEMW Else $tBuffer = $__g_tTabBufferANSI $iMsg = $TCM_GETITEMA EndIf Local $iRet = __GUICtrl_SendMsg($hWnd, $iMsg, $iIndex, $tItem, $tBuffer, True, 4, True) Local $aItem[4] $aItem[0] = DllStructGetData($tItem, "State") $aItem[1] = DllStructGetData($tBuffer, "Text") $aItem[2] = DllStructGetData($tItem, "Image") $aItem[3] = DllStructGetData($tItem, "Param") Return SetError($iRet = 0, 0, $aItem) EndFunc ;==>_GUICtrlTab_GetItem This way, I avoid having to make a helper script like a bridge, I just add the function. Mission accomplished. Thank you very much
    3 points
  19. @ioa747 Hi When you call _GUICtrlTab_GetItemText, then _GUICtrlTab_GetItem is called And _GuiCtrlTab_GetItem had issues as seen on Trac Ticket 3903 and in this post. In the post, @Danyfirex worked on this x86-x64 issue and maybe he could give an advice here if he got time ? Also I notice code in _GUICtrlTab_GetItem has been updated in new release 3.3.17.1 (beta) . Did you check your script with 3.3.17.1 , maybe it's solved with the new release ? Fingers crossed & good luck
    3 points
  20. MattyD

    WinRT - WinUI3

    To flesh this out a bit more - I attempted to recreate this example.. The XML looks like this... <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="3*"/> <ColumnDefinition Width="5*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="2*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Border Background="#2f5cb6"/> <Border Grid.Column ="1" Background="#1f3d7a"/> <Border Grid.Row="1" Grid.ColumnSpan="2" Background="#152951"/> <StackPanel Grid.Column="1" Margin="40,0,0,0" VerticalAlignment="Center"> <TextBlock Foreground="White" FontSize="25" Text="Today - 64° F"/> <TextBlock Foreground="White" FontSize="25" Text="Partially Cloudy"/> <TextBlock Foreground="White" FontSize="25" Text="Precipitation: 25%"/> </StackPanel> <StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock Foreground="White" FontSize="25" Text="High: 66°" Margin="0,0,20,0"/> <TextBlock Foreground="White" FontSize="25" Text="Low: 43°" Margin="0,0,20,0"/> <TextBlock Foreground="White" FontSize="25" Text="Feels like: 63°"/> </StackPanel> <Image Margin="20" Source="Assets/partially-cloudy.png"/> </Grid> Now last time out we were specifying our Row/Column definitions like this.. Local $tGridLen = DllStructCreate("align 1;double Value;ulong GridUnitType") $tGridLen.GridUnitType = $mGridUnitType["Star"] $pRowDef = _WinRT_ActivateInstance("Microsoft.UI.Xaml.Controls.RowDefinition") $tGridLen.Value = 2 IRowDefinition_SetHeight($pRowDef, $tGridLen) IVector_Append($pRowDefs, $pRowDef) The default interface for a "RowDefinition" is IRowDefinition - but it seems ActivateInstance doesn't put us there. So appending the object to the collection worked OK- the cells obviously appeared. But setting the height property was actually failing. So the learning is: If you're instantiating via ActivateInstance, you should always follow up with a _WinRT_SwitchInterface. Local $tGridLen = DllStructCreate("align 1;double Value;ulong GridUnitType") $tGridLen.GridUnitType = $mGridUnitType["Star"] $pRowDef = _WinRT_ActivateInstance("Microsoft.UI.Xaml.Controls.RowDefinition") _WinRT_SwitchInterface($pRowDef, $sIID_IRowDefinition) ;ADD THIS! $tGridLen.Value = 2 IRowDefinition_SetHeight($pRowDef, $tGridLen) IVector_Append($pRowDefs, $pRowDef) In this example, we have a few new controls: stackpanels - these work like grids, but the're 1-dimentional. (Edit: Well they have a width and height, but its just one row or one column of panels!) You don't need to assign a "grid spot" for the controls of a stackpanel though - they seem to appear in the order they were added in the IPanel::Children collection. Vectors do assign indexes to child items by memory - so I'd imagine if we shuffled items around via IVector, the GUI would probably follow suit (untested). textblocks - not much to be said about these. But at this point, I'll quickly mention that IFrameworkElement interface seems to look after most of the spatial things for a control (its margins, vertical and horizontal alignment, min/max sizing etc). And this is common across everything we've seen so far. Then we have an image - this one is a bit more interesting. You load it in with a URI, so for local storage we'll need to specify something like file:///C:/path/to/file.blah. Once you have yourself an uri object - we can bring the file in via a BitmapImage object. And finally we associate that with the UI object "controls.Image" Local $pURI_Fact = _WinRT_GetActivationFactory("Windows.Foundation.Uri", $sIID_IUriRuntimeClassFactory) Local $pImageURI = IUriRuntimeClassFactory_CreateWithRelativeUri($pURI_Fact, "file:///C:/FilePath/", "image.png") Local $pBitmap = _WinRT_ActivateInstance("Microsoft.UI.Xaml.Media.Imaging.BitmapImage") _WinRT_SwitchInterface($pBitmap, $sIID_IBitmapImage) IBitmapImage_SetUriSource($pBitmap, $pImageURI) Local $pImage = _WinRT_ActivateInstance("Microsoft.UI.Xaml.Controls.Image") _WinRT_SwitchInterface($pImage, $sIID_IImage) IImage_SetSource($pImage, $pBitmap) The loading is asynchronous, so if you need the dimensions of the source for example - those details are only available once the image is ready. If those properties are important we can register a delegate that will fire once the image is loded. Also, if the image fails to load, there's a delegate for that too... Local $pImgFailedDgte = _WinRT_CreateDelegate("ImageLoadFail") Local $iImgFailedDgteTkn = IBitmapImage_AddHdlrImageFailed($pBitmap, $pImgFailedDgte) ;Attempt to load image IBitmapImage_SetUriSource($pBitmap, $pImageURI) Func ImageLoadFail($pThis, $pSource, $pArgs) #forceref $pThis, $pSource, $pArgs ConsoleWrite("Image failed to load!" & @CRLF) EndFunc Final point on this example, I've tied the content bridge's size (the container encompassing the xaml controls) to the Windows WM_SIZE message. Case $WM_SIZE $tRect.Width = BitAND(0xFFFF, $lParam) $tRect.Height = BitShift($lParam, 16) IDesktopSiteBridge_MoveAndResize($pBridge, $tRect) $iReturn = _WinAPI_DefWindowProcW($hWnd, $iMsg, $wParam, $lParam) And resizing the window actually works remarkably well. I guess I was expecting some flicker or something- so that was a pleasant surprise! WindowTest Grid.zip
    3 points
  21. UDF: #include-once #cs ---------------------------------------------------------------------------- ; LZNT1 Compression ; AutoIt Version: 3.3.16.1+ ; Description: Supports compression and decompression of binary data and strings using the Windows LZNT1 algorithm. ; Author: trancexx + rewritten & extended by Dao Van Trong - TRONG.PRO ; ; Functions: ; _LZNT_Compress($bInput, $iEngine = 2, $bBase64 = False, $iLineLen = 1024) ; _LZNT_Decompress($vInput, $iOrigSize = 0, $iEngine = 2, $bBase64 = False) ; _LZNT_CompressString($sInput, $iEncoding = 4, $iEngine = 2, $bBase64 = False, $iLineLen = 1024) ; _LZNT_DecompressString($vInput, $iOrigSize = 0, $iEncoding = 4, $iEngine = 2, $bBase64 = False) ; #ce ---------------------------------------------------------------------------- ; =============================================================================================================================== ; Public Function: Compress Binary ; =============================================================================================================================== ; Description: Compresses binary data using the LZNT1 algorithm. ; Parameters: ; $bInput - Binary data to be compressed. ; $iEngine - Compression engine. ; 2 (default) = COMPRESSION_FORMAT_LZNT1 | $COMPRESSION_ENGINE_STANDARD ; 258 = COMPRESSION_ENGINE_MAXIMUM ; $bBase64 - True to return a Base64 string, False to return binary data. ; $iLineLen - Line length when returning a Base64 string (default is 1024 characters). ; Return Value: Returns the compressed data (binary or Base64). ; On Failure: Returns an empty string (""), @error is set to: ; 1 = Error calling RtlGetCompressionWorkSpaceSize. ; 2 = Error calling RtlCompressBuffer. ; 3 = Error converting to Base64 in __Base64Encode. ; @extended is set to the original length of the binary data. ; Author: Dao Van Trong - TRONG.PRO ; =============================================================================================================================== Func _LZNT_Compress($bInput, $iEngine = 2, $bBase64 = False, $iLineLen = 1024) If Not IsBinary($bInput) Then $bInput = Binary($bInput) If $iEngine <> 2 And $iEngine <> 258 Then $iEngine = 2 Local $tInput = DllStructCreate("byte[" & BinaryLen($bInput) & "]") DllStructSetData($tInput, 1, $bInput) Local $aCall = DllCall("ntdll.dll", "int", "RtlGetCompressionWorkSpaceSize", _ "ushort", $iEngine, "dword*", 0, "dword*", 0) If @error Or $aCall[0] Then Return SetError(1, 0, "") Local $tWork = DllStructCreate("byte[" & $aCall[2] & "]") Local $tBuffer = DllStructCreate("byte[" & 16 * DllStructGetSize($tInput) & "]") $aCall = DllCall("ntdll.dll", "int", "RtlCompressBuffer", _ "ushort", $iEngine, _ "ptr", DllStructGetPtr($tInput), "dword", DllStructGetSize($tInput), _ "ptr", DllStructGetPtr($tBuffer), "dword", DllStructGetSize($tBuffer), _ "dword", 4096, "dword*", 0, "ptr", DllStructGetPtr($tWork)) If @error Or $aCall[0] Then Return SetError(2, 0, "") Local $tOut = DllStructCreate("byte[" & $aCall[7] & "]", DllStructGetPtr($tBuffer)) Local $bOut = DllStructGetData($tOut, 1) If $bBase64 Then Return SetError(0, DllStructGetSize($tInput), __Base64Encode($bOut, $iLineLen)) Return SetError(0, DllStructGetSize($tInput), $bOut) EndFunc ;==>_LZNT_Compress ; =============================================================================================================================== ; Public Function: Decompress Binary ; =============================================================================================================================== ; Description: Decompresses LZNT1-compressed binary data. ; Parameters: ; $vInput - Compressed data, can be binary or a Base64 string. ; $iOrigSize - Estimated original size of the uncompressed data. If < 1, it will be estimated automatically. ; $iEngine - Compression engine used. ; 2 (default) = COMPRESSION_FORMAT_LZNT1 | $COMPRESSION_ENGINE_STANDARD ; 258 = COMPRESSION_ENGINE_MAXIMUM ; $bBase64 - True if $vInput is a Base64 string, False if it is binary data. ; Return Value: Returns the decompressed binary data. ; On Failure: Returns an empty string (""), @error is set to: ; 1 = Decompression error, or $vInput is not Base64 when $bBase64 is True. ; @extended is set to 0. ; Author: Dao Van Trong - TRONG.PRO ; =============================================================================================================================== Func _LZNT_Decompress($vInput, $iOrigSize = 0, $iEngine = 2, $bBase64 = False) Local $bInput If $bBase64 Then $bInput = __Base64Decode($vInput) Else $bInput = $vInput EndIf If Not IsBinary($bInput) Then $bInput = Binary($bInput) If $iEngine <> 2 And $iEngine <> 258 Then $iEngine = 2 Local $tInput = DllStructCreate("byte[" & BinaryLen($bInput) & "]") DllStructSetData($tInput, 1, $bInput) If $iOrigSize < 1 Then $iOrigSize = 16 * DllStructGetSize($tInput) Local $tBuffer = DllStructCreate("byte[" & $iOrigSize & "]") Local $aCall = DllCall("ntdll.dll", "int", "RtlDecompressBuffer", _ "ushort", $iEngine, _ "ptr", DllStructGetPtr($tBuffer), "dword", DllStructGetSize($tBuffer), _ "ptr", DllStructGetPtr($tInput), "dword", DllStructGetSize($tInput), _ "dword*", 0) If @error Or $aCall[0] Then Return SetError(1, 0, "") Local $tOut = DllStructCreate("byte[" & $aCall[6] & "]", DllStructGetPtr($tBuffer)) Return SetError(0, $aCall[6], DllStructGetData($tOut, 1)) EndFunc ;==>_LZNT_Decompress ; =============================================================================================================================== ; Public Function: Compress String ; =============================================================================================================================== ; Description: Compresses a string and returns the compressed data. ; Parameters: ; $sInput - String to be compressed. ; $iEncoding - String encoding. (1=ANSI, 2=UTF16LE, 3=UTF16BE, 4=UTF8) ; $iEngine - Compression engine (same as _LZNT_Compress).(2 or 258) ; $bBase64 - True to return a Base64 string, False to return binary. ; $iLineLen - Line length when returning a Base64 string. ; Return Value: Returns the compressed data (binary or Base64). ; On Failure: Returns an empty string (""), @error is set to: ; 1, 2, 3 (same as _LZNT_Compress). ; @extended is set to the original length of the string data. ; Author: Dao Van Trong - TRONG.PRO ; =============================================================================================================================== Func _LZNT_CompressString($sInput, $iEncoding = 4, $iEngine = 2, $bBase64 = False, $iLineLen = 1024) Local $bData = StringToBinary($sInput, $iEncoding) Return _LZNT_Compress($bData, $iEngine, $bBase64, $iLineLen) EndFunc ;==>_LZNT_CompressString ; =============================================================================================================================== ; Public Function: Decompress String ; =============================================================================================================================== ; Description: Decompresses data and returns a string. ; Parameters: ; $vInput - Compressed data. ; $iOrigSize - Estimated original size of the uncompressed data. ; $iEncoding - Encoding to convert the decompressed binary to a string. (1=ANSI, 2=UTF16LE, 3=UTF16BE, 4=UTF8) ; $iEngine - Compression engine used (same as _LZNT_Decompress).(2 or 258) ; $bBase64 - True if $vInput is a Base64 string, False if it is binary. ; Return Value: Returns the decompressed string. ; On Failure: Returns an empty string (""), @error is set to: ; 1 = Decompression error (same as _LZNT_Decompress). ; @extended is set to 0. ; Author: Dao Van Trong - TRONG.PRO ; =============================================================================================================================== Func _LZNT_DecompressString($vInput, $iOrigSize = 0, $iEncoding = 4, $iEngine = 2, $bBase64 = False) Local $bData = _LZNT_Decompress($vInput, $iOrigSize, $iEngine, $bBase64) If @error Then Return SetError(1, 0, "") Return BinaryToString($bData, $iEncoding) EndFunc ;==>_LZNT_DecompressString ; =============================================================================================================================== ; Internal helper: Base64 Encode ; =============================================================================================================================== Func __Base64Encode($bData, $iLineLen = 1024) If Not IsBinary($bData) Then Return SetError(1, 0, "") Local $pInput = DllStructCreate("byte[" & BinaryLen($bData) & "]") DllStructSetData($pInput, 1, $bData) ; 1st call to get required length Local $aCall = DllCall("Crypt32.dll", "bool", "CryptBinaryToStringW", _ "ptr", DllStructGetPtr($pInput), _ "dword", DllStructGetSize($pInput), _ "dword", 0x1, _ ; CRYPT_STRING_BASE64 "ptr", 0, _ "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(2, 0, "") Local $iLen = $aCall[5] Local $tOut = DllStructCreate("wchar[" & $iLen & "]") ; 2nd call to actually encode $aCall = DllCall("Crypt32.dll", "bool", "CryptBinaryToStringW", _ "ptr", DllStructGetPtr($pInput), _ "dword", DllStructGetSize($pInput), _ "dword", 0x1, _ "ptr", DllStructGetPtr($tOut), _ "dword*", $iLen) If @error Or Not $aCall[0] Then Return SetError(3, 0, "") Local $sOut = DllStructGetData($tOut, 1) ; Remove CRLF inserted by Crypt32 $sOut = StringReplace($sOut, @CRLF, "") ; Manual wrap for embedding in AutoIt source If $iLineLen > 0 And StringLen($sOut) > $iLineLen Then Local $sWrapped = "" For $i = 1 To StringLen($sOut) Step $iLineLen $sWrapped &= StringMid($sOut, $i, $iLineLen) & @CRLF Next $sOut = StringTrimRight($sWrapped, 2) EndIf Return $sOut EndFunc ;==>__Base64Encode ; =============================================================================================================================== ; Internal helper: Base64 Decode ; =============================================================================================================================== Func __Base64Decode($sBase64) If Not IsString($sBase64) Then Return SetError(1, 0, "") ; strip whitespace / CRLF $sBase64 = StringStripWS($sBase64, 8) ; 1st call to get required length Local $aCall = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryW", _ "wstr", $sBase64, _ "dword", 0, _ "dword", 0x1, _ ; CRYPT_STRING_BASE64 "ptr", 0, _ "dword*", 0, _ "dword*", 0, _ "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(2, 0, "") Local $iLen = $aCall[5] Local $tOut = DllStructCreate("byte[" & $iLen & "]") ; 2nd call to decode $aCall = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryW", _ "wstr", $sBase64, _ "dword", 0, _ "dword", 0x1, _ "ptr", DllStructGetPtr($tOut), _ "dword*", $iLen, _ "dword*", 0, _ "dword*", 0) If @error Or Not $aCall[0] Then Return SetError(3, 0, "") Return DllStructGetData($tOut, 1) EndFunc ;==>__Base64Decode #cs ; =============================================================================================================================== ; SELF-TEST FOR LZNT + BASE64 UDF ; =============================================================================================================================== ; Test string with 10 languages Global Const $sTest = "Hello 你好 नमस्ते Hola Bonjour مرحبا হ্যালো Привет Olá Xin chào 🚀" ConsoleWrite("!===== SELF TEST START =====" & @CRLF) ConsoleWrite("+ Original String: " & $sTest & @CRLF) ConsoleWrite("- Original Length: " & StringLen($sTest) & " chars" & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 1) Compress binary ; ------------------------------------------------------------------------------------------------------------------------------- Local $bInput = StringToBinary($sTest, 4) ; UTF-8 Local $bCompressed = _LZNT_Compress($bInput, 2, False) Local $iOrigSize = @extended ConsoleWrite(@CRLF & "- [1] Compress Binary (HEX)" & @CRLF) ConsoleWrite("+ OrigSize: " & $iOrigSize & " CompressedSize: " & BinaryLen($bCompressed) & @CRLF) ; Decompress binary Local $bDecompressed = _LZNT_Decompress($bCompressed, $iOrigSize, 2, False) ConsoleWrite("" & (BinaryToString($bDecompressed, 4) = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 2) Compress binary + Base64 ; ------------------------------------------------------------------------------------------------------------------------------- Local $sCompressedB64 = _LZNT_Compress($bInput, 2, True, 32) $iOrigSize = @extended ConsoleWrite(@CRLF & "- [2] Compress Binary (Base64)" & @CRLF) ConsoleWrite("+ Compressed (B64): " & @CRLF & $sCompressedB64 & @CRLF) ; Decompress binary from Base64 $bDecompressed = _LZNT_Decompress($sCompressedB64, $iOrigSize, 2, True) ConsoleWrite("" & (BinaryToString($bDecompressed, 4) = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 3) Compress String (HEX) ; ------------------------------------------------------------------------------------------------------------------------------- Local $sCompressedStr = _LZNT_CompressString($sTest, 4, 2, False) $iOrigSize = @extended ConsoleWrite(@CRLF & "- [3] Compress String (HEX)" & @CRLF) ConsoleWrite("+ CompressedSize: " & BinaryLen($sCompressedStr) & @CRLF) ; Decompress String Local $sDecompressed = _LZNT_DecompressString($sCompressedStr, $iOrigSize, 4, 2, False) ConsoleWrite("- Decompressed String: " & $sDecompressed & @CRLF) ConsoleWrite("" & ($sDecompressed = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 4) Compress String (Base64) ; ------------------------------------------------------------------------------------------------------------------------------- Local $sCompressedStrB64 = _LZNT_CompressString($sTest, 4, 2, True, 40) $iOrigSize = @extended ConsoleWrite(@CRLF & "- [4] Compress String (Base64)" & @CRLF) ConsoleWrite("+ Compressed (B64): " & @CRLF & $sCompressedStrB64 & @CRLF) ; Decompress String $sDecompressed = _LZNT_DecompressString($sCompressedStrB64, $iOrigSize, 4, 2, True) ConsoleWrite("- Decompressed String: " & $sDecompressed & @CRLF) ConsoleWrite("" & ($sDecompressed = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ConsoleWrite("!===== SELF TEST END =====" & @CRLF) #ce EG: ;#include "LZNT_Compress_Engine.AU3" ; =============================================================================================================================== ; SELF-TEST FOR LZNT + BASE64 UDF ; =============================================================================================================================== ; Test string with 10 languages Global Const $sTest = "Hello 你好 नमस्ते Hola Bonjour مرحبا হ্যালো Привет Olá Xin chào 🚀" ConsoleWrite("!===== SELF TEST START =====" & @CRLF) ConsoleWrite("+ Original String: " & $sTest & @CRLF) ConsoleWrite("- Original Length: " & StringLen($sTest) & " chars" & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 1) Compress binary ; ------------------------------------------------------------------------------------------------------------------------------- Local $bInput = StringToBinary($sTest, 4) ; UTF-8 Local $bCompressed = _LZNT_Compress($bInput, 2, False) Local $iOrigSize = @extended ConsoleWrite(@CRLF & "- [1] Compress Binary (HEX)" & @CRLF) ConsoleWrite("+ OrigSize: " & $iOrigSize & " CompressedSize: " & BinaryLen($bCompressed) & @CRLF) ; Decompress binary Local $bDecompressed = _LZNT_Decompress($bCompressed, $iOrigSize, 2, False) ConsoleWrite("" & (BinaryToString($bDecompressed, 4) = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 2) Compress binary + Base64 ; ------------------------------------------------------------------------------------------------------------------------------- Local $sCompressedB64 = _LZNT_Compress($bInput, 2, True, 32) $iOrigSize = @extended ConsoleWrite(@CRLF & "- [2] Compress Binary (Base64)" & @CRLF) ConsoleWrite("+ Compressed (B64): " & @CRLF & $sCompressedB64 & @CRLF) ; Decompress binary from Base64 $bDecompressed = _LZNT_Decompress($sCompressedB64, $iOrigSize, 2, True) ConsoleWrite("" & (BinaryToString($bDecompressed, 4) = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 3) Compress String (HEX) ; ------------------------------------------------------------------------------------------------------------------------------- Local $sCompressedStr = _LZNT_CompressString($sTest, 4, 2, False) $iOrigSize = @extended ConsoleWrite(@CRLF & "- [3] Compress String (HEX)" & @CRLF) ConsoleWrite("+ CompressedSize: " & BinaryLen($sCompressedStr) & @CRLF) ; Decompress String Local $sDecompressed = _LZNT_DecompressString($sCompressedStr, $iOrigSize, 4, 2, False) ConsoleWrite("- Decompressed String: " & $sDecompressed & @CRLF) ConsoleWrite("" & ($sDecompressed = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ; ------------------------------------------------------------------------------------------------------------------------------- ; 4) Compress String (Base64) ; ------------------------------------------------------------------------------------------------------------------------------- Local $sCompressedStrB64 = _LZNT_CompressString($sTest, 4, 2, True, 40) $iOrigSize = @extended ConsoleWrite(@CRLF & "- [4] Compress String (Base64)" & @CRLF) ConsoleWrite("+ Compressed (B64): " & @CRLF & $sCompressedStrB64 & @CRLF) ; Decompress String $sDecompressed = _LZNT_DecompressString($sCompressedStrB64, $iOrigSize, 4, 2, True) ConsoleWrite("- Decompressed String: " & $sDecompressed & @CRLF) ConsoleWrite("" & ($sDecompressed = $sTest ? '- Decompressed OK' : '! Decompressed NG') & @CRLF) ConsoleWrite("!===== SELF TEST END =====" & @CRLF) #ce !
    3 points
  22. WildByDesign

    WinRT - WinUI3

    I personally really appreciate these longer blog-like posts. You are learning this WinUI3 stuff as you go and we are learning along with you (thanks to you). I think that this teaching style of posts is the only way to go, honestly. I also think that this has a lot of great potential for any of us who use AutoIt for making GUI programs. This has the potential to create more opportunities for designing modern looking GUI apps in AutoIt and that is definitely a bonus. Therefore, for any of us that have an interest in that area and who are following along with you, I personally am very thankful for the amount of detail that you share in your posts. You have a good teaching style.
    3 points
  23. I have to use passwords in a lot of my scripts. I have an SQL server where each script has it's own database where I store passwords as an encrypted string along with any other config/test/log data. I also only allow specific users access to that database via AD. The decryption keys are also unique to each script. This lets me keep passwords secure and lets me control who can access my apps as if the database connection fails then the app closes with a message to contact me for access.
    3 points
  24. Are you aware that you can escape the respective quote characters in AutoIt string definitions by simply doubling them? So to create an AutoIt-compliant string definition for the AutoIt code itself from a string, you do not need to split it into individual strings and reassemble them, but simply double the quotes. This would be shorter, probably clearer and also better performing. In concrete terms, the following should also achieve your actual goal $result = '"' & StringReplace($raw, '"', '""', 0, 1) & '"' ; or equally: $result = "'" & StringReplace($raw, "'", "''", 0, 1) & "'"
    3 points
  25. Jugador From a place of kindness and introspection, there is a general principle and lesson for anyone, that surpasses this topic, but still related to the genesis of this topic. That principle is "unit testing". If we unit test our code, we are never surprised or blindsided by results we didn't expect. And trust me, in my early days I was blind sided many many times. Unit testing also implies "never assuming" your own code is perfect. Build "test code" to test your "production code". But not only your own code, but supplied Autoit UDFs, members UDF, DLLs, COM objects, APIs etc. And not everything Microsoft publishes works as expected. We see this every single day in our MSP business. And if timing is important to a set of code, build in tests for timing. That way there are no surprises. You can build code with certainty. Code Complete 2, is one of the many great books on coding standards. I was recommended to read it by my seasoned genius programmer who has programmed in a dozen different languages with a reputation for error free code. I've read it half a dozen times, the last four taking extensive notes, and deriving and creating standards to use with AutoIT, and programming in general. Not the only book, but a good start. I've got 20+ years on mLipok, but he has insights I don't have, and is definitely not childish. Like him I have a business and staff, and yes, I program, purely out of necessity, in AutoIT. I/we program purely because what we need doesn't exist. My business is IT and Technology, not software. The heavy lifting is done in C# or Delphi, by my genius programmer(s). Full blown applications written by them, plus upgrades, are still running after 18 years of 24/7/365 continuous running without any bugs or errors. I know when to bow down to programming gods. Although I started programming in the late 80's, it was purely on a needs basis, not a full time occupation. I still regard myself as a novice, and am very grateful to the people on here like mLipok, Jos, Jon, Argumentum and many many others who provide valuable insights. 🙂
    3 points
  26. New version available.
    2 points
  27. UDF and DLL updated! See post#1. The DLLs are too big to post it here. You can find it on my 1Drv! Feel free to post examples here!
    2 points
  28. GUICtrlSendMsg($idComboBox, $WM_CHANGEUISTATE, 65537, 0) Try this.
    2 points
  29. I just came across some odd behavior when automating a third party software app. On this third party app, there's a dialog with an edit control where you can enter an ID number that's 9 digits long. As soon as you enter the 9th digit the app immediately checks to see if it recognizes the ID as being an existing customer and if it does, it pops up a modal Yes/No window asking if you want to autofill the customer's information on the rest of the dialog. This popup correctly occurs whether my AutoIt app fills the edit control with 9 digits using ControlSetText or ControlSend. My AutoIt app needs to know whether the popup happens in order to determine its next action, so I follow the ControlSetText or ControlSend with a WinWait call looking for the popup, with a 2 second timeout. Here's where the odd behavior comes. If I fill the edit control using ControlSetText and the popup window appears, my WinWait doesn't start looking for the popup window until after the user has clicked Yes or No on it (and thereby dismissed the window). The AutoIt app just sits there idle the entire time that the Yes/No window is visible. Then as soon as the user clicks Yes or No (and dismisses the modal window), the WinWait immediately begins looking for that (now dismissed) window and of course never finds it. If I instead fill the edit control with ControlSend, AutoIt doesn't hang while the Yes/No window is visible, and WinWait immediately finds the window as expected. My guess is that the 3rd party app is popping up the modal Yes/No window before the original dialog can provide the return code from ControlSetText's underlying SendMessage command (probably due to some improper subclassing in the 3rd party app that shows the popup dialog before allowing the WndProc function to complete its operation and return a value). As a result, AutoIt is left sitting there waiting for that message before the ControlSetText function completes and it can move on to the next line of the script. Once the user dismisses the modal Yes/No window and the original dialog can continue, the return code gets received by AutoIt, the ControlSetText command finishes, and the script continues. With the ControlSend command, AutoIt apparently doesn't get stuck waiting for a return message, and can proceed with finding the window and acting accordingly. So I'm not looking for a solution, since using ControlSend is the workaround. Just posting here in case someone else comes across something similar and is banging their head on the keyboard as I was.
    2 points
  30. May you release it on github.com ? Then we be able to look over enttire udf and have a better look
    2 points
  31. argumentum

    MustReturnArray()

    #include <WinAPIProc.au3> ; for the example Func MustReturnArray($aArray, $iColumns = 0, $iErr = @error, $iExt = @extended) If UBound($aArray) Then Return SetError($iErr, $iExt, $aArray) If $iColumns Then Dim $aArray[1][$iColumns] = [[0]] Else Dim $aArray[1] = [0] EndIf Return SetError($iErr, $iExt, $aArray) EndFunc ;==>MustReturnArray Exit MustReturnArray_Example() Func MustReturnArray_Example() ; worry free return Local $aWinList = WinList("nah, is not there") For $n = 1 To $aWinList[0][0] ConsoleWrite($aWinList[$n][1] & @TAB & $aWinList[$n][0] & @CRLF) Next ; worry free return Local $aProcessList = ProcessList("nah, is not there") For $n = 1 To $aProcessList[0][0] ConsoleWrite($aProcessList[$n][1] & @TAB & $aProcessList[$n][0] & @CRLF) Next ; solution ; create a "worry free return" Local $aArray = MustReturnArray(_WinAPI_EnumProcessWindows(4), 2) For $n = 1 To $aArray[0][0] ConsoleWrite($aArray[$n][1] & @TAB & $aArray[$n][0] & @CRLF) Next ; problem ; not a "worry free return" Local $aArray = _WinAPI_EnumProcessWindows(4) For $n = 1 To $aArray[0][0] ConsoleWrite($aArray[$n][1] & @TAB & $aArray[$n][0] & @CRLF) Next EndFunc ;==>MustReturnArray_Example Before I start with my problem ( and solution ), a big thank you to everyone coding these UDFs. AutoIt would not be what it is without them. ... a coder should always check @error, but is a pain, or not. In any case, the internal AutoIt functions return an array even if nothing there when an array is what it returns on success. Am so used to it, that when I use a UDF function I have to RTFM and I don't like reading ( nor writing but here we are 🤷‍♂️ ) How should I solve this problem given my coding style that does not include a failing function returning a zero stead of the array I was expecting. AutoIt does it, why does the UDFs not do it ?, ... must be a professional coders thing but, am a scripter. I write scripts. So, if it should return an array, then MustReturnArray() !. I hope this idea/function helps you avoid the " ==> Subscript used on non-accessible variable. " and/or simplify your code
    2 points
  32. @donnyh13 Hi When we discussed this with @jchd and @jpm in Trac Ticket #3945 then the last table at the end of the web page showed the results with a better alignment, I'm pasting it below : Row Unicode CharacterName \h \v \s [[:space:]] [[:blank:]] -------------------------------------------------------------------------------- # 1 0x0009 HT xX xX xX xX # 2 0x000A LF xX xX xX # 3 0x000B VT xX xX xX # 4 0x000C FF xX xX xX # 5 0x000D CR xX xX xX # 6 0x0020 SPACE xX xX xX xX # 7 0x0085 NEL xX X X # 8 0x00A0 NO-BREAK SPACE xX X X X # 9 0x1680 OGHAM SPACE MARK xX X X X # 10 0x180E MONGOLIAN VOWEL SEPARATOR xX X X X # 11 0x2000 EN QUAD xX X X X # 12 0x2001 EM QUAD xX X X X # 13 0x2002 EN SPACE xX X X X # 14 0x2003 EM SPACE xX X X X # 15 0x2004 THREE-PER-EM SPACE xX X X X # 16 0x2005 FOUR-PER-EM SPACE xX X X X # 17 0x2006 SIX-PER-EM SPACE xX X X X # 18 0x2007 FIGURE SPACE xX X X X # 19 0x2008 PUNCTUATION SPACE xX X X X # 20 0x2009 THIN SPACE xX X X X # 21 0x200A HAIR SPACE xX X X X # 22 0x2028 LINE SEPARATOR xX X X # 23 0x2029 PARAGRAPH SEPARATOR xX X X # 24 0x202F NARROW NO-BREAK SPACE xX X X X # 25 0x205F MEDIUM MATHEMATICAL SPACE xX X X X # 26 0x3000 IDEOGRAPHIC SPACE xX X X X Legend : xX will match with or without (*UCP) in the pattern X alone will match ONLY if (*UCP) is present at the start of the pattern For example let's create a subject starting with "abc" followed by a no-break space (0x00A0) and ending with "def" , so the subject looks like this "abc def" (make sure there is a no-break space in the middle of the subject between abc and def) . Now let's test different patterns : ======================= 2 patterns searching for \h abc\hdef => 1 match (*UCP)abc\hdef => 1 match Both patterns match because xX is indicated for \h (concerning the no-break space) ======================= 2 patterns searching for \s abc\sdef => NO match (*UCP)abc\sdef => 1 match Only the pattern starting with (*UCP) matches because X is indicated for \s (concerning the no-break space) This example could be applied to any of the 26 characters found in the table above Hope it helps
    2 points
  33. Then, as already mentioned, the most relevant starting point for reducing the load is to write FileReadToArray before the while loop – not within! And at the same time, increase the sleep time slightly. That alone should make a big difference. If there is still a need for further optimization, then a different approach would be required: Currently, your script queries the current status of the process list at regular intervals and processes it. This is commonly referred to as "polling". A better option would be to tell Windows: You know when new processes are created anyway, so just let me know when that happens. This way, the script can go to sleep and will be actively woken up by Windows when a new process appears. This approach is called event registration, for example. There are events for file system operations or window creation and so on. However, I am not aware of any event-based approach for process creation that does not require administrator privileges. But we can still find a workaround. WMI offers the option of periodically querying its tables internally and automatically reporting new records when changes are made. Technically speaking, this is still polling, but in WMI it is more cost-effective than implementing it directly in AutoIt. In addition, you can also specify which processes you are interested in and specify from the outset that only processes with a name from your list should be reported, e.g. This further reduces the effort required for the script. And yes, your concern is correct: this does make the script more complicated. But if further optimization is really necessary, there is no real way around it: HotKeySet("{F9}", "goout") ; Create WMI object and sink for events Global $oWMI = ObjGet("winmgmts:\\") Global $oSink = ObjCreate("WbemScripting.SWbemSink") ; say WMI that the script should be informed of new processes as they appear in test.dat. (See function definition) _registerProcessCreation() ; endless loop for keeping the script running Do Sleep(100) Until False ; Function that is automatically called when the __InstanceCreationEvent occurs Func SINK_OnObjectReady($oProcess) ProcessClose($oProcess.TargetInstance.ProcessID) EndFunc Func goout() Exit EndFunc ; Creates the query string that defines exactly which process settings should be responded to. ; This query is then linked to the user's own function as an event handler. Func _registerProcessCreation() Local $mProcNames[] ; build the query-string out of the "Test.dat" file ; Queries the __InstanceCreationEvent events on the WMI class Win32_Process every 100 ms. ; Also limit the query to the processes listed in Test.dat. Local $sQuery = "SELECT * FROM __InstanceCreationEvent WITHIN 0.1 WHERE TargetInstance ISA 'Win32_Process' AND (" For $sProcessName In FileReadToArray("Test.dat") If Not MapExists($mProcNames, $sProcessName) Then ; Prevent duplicate process names $sQuery &= "TargetInstance.name = '" & $sProcessName & "' OR " $mProcNames[$sProcessName] = "" EndIf Next $sQuery = StringTrimRight($sQuery, 4) & ")" ; Events with the prefix “SINK_” are linked to corresponding AutoIt functions (we only need SINK_OnObjectReady). ObjEvent($oSink, "SINK_") ; Queries the __InstanceCreationEvent events on the WMI class Win32_Process every 100 ms. $oWMI.ExecNotificationQueryAsync($oSink, $sQuery) EndFunc
    2 points
  34. argumentum

    EndIf "overhead"

    ..perhaps.. . Perhaps is good. Not because one of your questions did not bring the house down, or you were right or not about making a big deal out of, something. Is good, is all good. So keep asking if there is a question. I enjoy the threads even if I don't have either time, or anything to contribute to it. This if-then-else thing, ...I had no idea, nor ever came up in my brain. Thinking about it, at times I use Switch as an If when is practical ( I don't care much about speed or memory with today's hardware )
    2 points
  35. I got a chance to test myLogin (3.6) on Windows 11 and I just wanted to confirm that your existing blur method worked perfectly. I did not end up having to add anything to your code.
    2 points
  36. Yes just hide the window, or do not show them at all.
    2 points
  37. To be fair, Libraries like "user32.dll" would already be loaded by autoit for its own purposes, so I'd imagine doing a DllCall("user32.dll", blah) would probably just result in adding/removing a reference to the already loaded dll. So the time saving would be much less than say "wlanapi.dll" for example, which I assume fully loads/unloads the dll during the call.. #include <WinAPISys.au3> Local $hOrigUser32Handle = _WinAPI_GetModuleHandle("user32.dll") ConsoleWrite("user32 before load: " & $hOrigUser32Handle & @CRLF) $hUser32Dll = _WinAPI_LoadLibrary("user32.dll") ConsoleWrite("user32 after load: " & _WinAPI_GetModuleHandle("user32.dll") & @CRLF) ConsoleWrite("Same Handle = " & ($hUser32Dll = $hOrigUser32Handle) & @CRLF) _WinAPI_FreeLibrary($hUser32Dll) ConsoleWrite("user32 after free: " & _WinAPI_GetModuleHandle("user32.dll") & @CRLF & @CRLF) ConsoleWrite("wlanapi before load: " & _WinAPI_GetModuleHandle("wlanapi.dll") & @CRLF) $hWlanapiDll = _WinAPI_LoadLibrary("wlanapi.dll") ConsoleWrite("wlanapi after load: " & _WinAPI_GetModuleHandle("wlanapi.dll") & @CRLF) _WinAPI_FreeLibrary($hWlanapiDll) ConsoleWrite("wlanapi after free: " & _WinAPI_GetModuleHandle("wlanapi.dll") & @CRLF)
    2 points
  38. Indeed, yes. My jaw is still on the floor. If this forum has any kind of Solution of the Year, Matty nailed it. As soon as I pick my jaw up from the floor I’m going to respond in more detail.
    2 points
  39. Wow @MattyD, that is impressive. I also played around with some variants but what really did the trick is mentioned by you: My timer result was 980.0433, but you version is way better! I guess this will help @WildByDesign a lot, Best regards Sven
    2 points
  40. MattyD

    WinRT - WinUI3

    Alrighty, here's a couple of general notes around this attachment, then there will be a follow up post with more detail around the Grid stuff. (last one for the weekend I promise!) We can now include "Include\WinRT_WinUI3.au3" which exposes _WinUI3_Startup and _WinUI3_Shutdown. This is basically those boostrapper calls to spin up and down the runtime. In WinRT.au3, I've popped _WinRT_SwitchInterface in as a standard func so we don't have to do multi-step calls through IUnknown to jump between interfaces. I've also added a _WinRT_CreateDelegate() and _WinRT_DestroyDelegate() in WinRT.au3 to do the heavy lifting for creating delegates. So the syntax now looks like this: ; Creation $pBtnClickDelegate = _WinRT_CreateDelegate("BtnClick") $iBtnClickHandlerTkn = IButtonBase_AddHdlrClick($pButton, $pBtnClickDelegate) ; Teardown IButtonBase_RemoveHdlrClick($pButton, $iBtnClickHandlerTkn) _WinRT_DestroyDelegate($pBtnClickDelegate) Func BtnClick($pThis, $pSender, $pArgs) ;Do stuff EndFunc I'll still need to fix up a few more things before popping this all up on sourceforge - but just thought I'd get these quality of life things out the door while I'm feeling energetic! WindowTest - Grid.zip
    2 points
  41. ermar, Certainly - how about this: #include <GuiConstantsEx.au3> #include <WindowsConstants.au3> #include "GUIListViewEx.au3" Opt("GUIOnEventMode", 1) ; Create GUI $hGUI = GUICreate("LVEx Example", 320, 320) ; Create ListView $cListView = GUICtrlCreateListView("Tom|Dick|Harry", 10, 10, 300, 300, $LVS_SHOWSELALWAYS) _GUICtrlListView_SetExtendedListViewStyle($cListView, $LVS_EX_FULLROWSELECT) _GUICtrlListView_SetColumnWidth($cListView, 0, 93) _GUICtrlListView_SetColumnWidth($cListView, 1, 93) _GUICtrlListView_SetColumnWidth($cListView, 2, 93) ; Set font GUICtrlSetFont($cListView, 12, Default, Default, "Courier New") ; Note edit control will use same font ; Create array and fill listview Global $aLV_List[20] For $i = 0 To UBound($aLV_List) - 1 If Mod($i, 5) Then $aLV_List[$i] = "Tom " & $i & "|Dick " & $i & "|Harry " & $i Else $aLV_List[$i] = "Tom " & $i & "||Harry " & $i EndIf GUICtrlCreateListViewItem($aLV_List[$i], $cListView) Next ; Initiate LVEx $iLV_Left_Index = _GUIListViewEx_Init($cListView, $aLV_List) ; Column 1 & 2 editable - simple text _GUIListViewEx_SetEditStatus($iLV_Left_Index, "1;2") ; Register for sorting, dragging and editing - but do NOT register WM_Notify _GUIListViewEx_MsgRegister(Default) ; Now register the user WM_NOTIFY handler GUIRegisterMsg(0x004E, "_User_WM_NOTIFY_Handler") GUISetState() GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit_Ex") While 1 Sleep(10) $vRet = _GUIListViewEx_EventMonitor(0) If @error Then MsgBox($MB_SYSTEMMODAL, "Error", "Event error: " & @error) EndIf Switch @extended Case 1 If $vRet = "" Then MsgBox($MB_SYSTEMMODAL, "Edit", "Edit aborted" & @CRLF) Else _ArrayDisplay($vRet, "ListView " & _GUIListViewEx_GetActive() & " content edited", Default, 8) EndIf EndSwitch WEnd Func _Exit_Ex() Exit EndFunc Func _User_WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam) ; Do whatever the user handler is supposed to do here ; Must be LAST line of the handler Return(_GUIListViewEx_WM_NOTIFY_Handler($hWnd, $iMsg, $wParam, $lParam)) EndFunc Please ask if you have any questions. M23
    2 points
  42. Looks like I've been beaten to to the punch! Anyway FWIW - heres one that'll work any which way... (without the processing the '=' delimiter) #AutoIt3Wrapper_UseX64=Y #include <WinAPIMisc.au3> #include <array.au3> Local $aStr = _WinAPI_GetEnvironmentStrings(True) _ArrayDisplay($aStr) Func _WinAPI_GetEnvironmentStrings($bUnicode = True) Local $sFunc, $sType, $pBuff, $pStr, $iCharLen, $iStrLen, $tStr, $aStr[10], $iIdx If $bUnicode Then $sFunc = "GetEnvironmentStringsW" $sType = "wchar" $iCharLen = 2 Else $sFunc = "GetEnvironmentStringsA" $sType = "char" $iCharLen = 1 EndIf Local $aCall = DllCall("Kernel32.dll", "ptr", $sFunc) If @error Then Return SetError(@error, @extended, "") $pBuff = $aCall[0] $pStr = $pBuff While 1 $iStrLen = _WinAPI_StrLen($pStr, $bUnicode) + 1 If $iStrLen = 1 Then ExitLoop If $iIdx = UBound($aStr) Then ReDim $aStr[int(1.5 * $iIdx)] $tStr = DllStructCreate(StringFormat("%s[%d]", $sType, $iStrLen), $pStr) $aStr[$iIdx] = DllStructGetData($tStr, 1) $pStr = Ptr($pStr + ($iCharLen * $iStrLen)) $iIdx += 1 WEnd ReDim $aStr[$iIdx] _WinAPI_FreeEnvironmentStrings($pBuff, $bUnicode) Return $aStr EndFunc Func _WinAPI_FreeEnvironmentStrings($pStrings, $bUnicode = True) Local $aCall = DllCall("Kernel32.dll", "bool", $bUnicode ? "FreeEnvironmentStringsW" : "FreeEnvironmentStringsA", "ptr", $pStrings) If @error Then Return SetError(@error, @extended, False) Return $aCall[0] EndFunc
    2 points
  43. I slightly modified something I had ready, and here are the results #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #include <AutoItConstants.au3> #include <MsgBoxConstants.au3> Opt("TrayAutoPause", 0) HotKeySet("{END}", "main") ; <- HotKeySet -<< While 1 Sleep(50) WEnd Exit ;--------------------------------------------------------------------------------------- Func main() Local $sDomain = GetDomain() MsgBox(4096, "Domain:", $sDomain) EndFunc ;==>main ;--------------------------------------------------------------------------------------- Func GetDomain($sFullUrl = "") Local $sDomain = "", $iError = 0 If $sFullUrl = "" Then $sFullUrl = _ExtractLink() If Not @error Then ; Regex pattern to match the domain. Local $aMatch = StringRegExp($sFullUrl, '(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)', 3) If Not @error Then $sDomain = $aMatch[0] Else $iError = @error $sDomain = "Could not extract domain." EndIf Else ; I can't recognize the Url $iError = @error $sDomain = "I can't recognize the Url" EndIf Return SetError($iError, 0, $sDomain) EndFunc ;==>GetDomain ;--------------------------------------------------------------------------------------- Func _ExtractLink() ; Extract Link Local $hWnd = WinGetHandle("[ACTIVE]") Local $sTitle = WinGetTitle($hWnd) Local $sResult If StringRegExp($sTitle, "(?i)(.* — Mozilla Firefox.*|.* - Google Chrome.*)") Then Local $ClipBak = ClipGet() ; backUp ClipData WinActivate($hWnd) Send("{F6}") ; go in adresse bar Sleep(10) Send("{CTRLDOWN}") ; copy the link Send("c") Send("{CTRLUP}") Send("{F6}") ; deselect the link Sleep(100) Local $sLnk = ClipGet() Sleep(100) $sResult = $sLnk ClipPut($ClipBak) ; Restore backUp ClipData Return $sResult EndIf Return SetError(1, 0, "") EndFunc ;==>_ExtractLink
    2 points
  44. Its all in this thread and I can see I updated all in post 1.
    2 points
  45. Sorry, but I have to disagree: Encrypting passwords in a script together with the information required for decryption is obfuscation, not security. Suggestion: Use the keepass CLI (kpscript), there is an UDF by @seadoggie01 available, never worked with it, just as a start:
    2 points
  46. Just to be clear: Whatever you do, the shell command requires the clear text password, so by definition no solution will be safe! 🙂
    2 points
  47. You're welcome. And thank you for the sharing your example as well with the buttons. Your example makes more sense for being able to play around with the example. I've never been very good with examples. I was working on another example earlier today using a slider to automatically change the color transparency in real-time and it's working well. So I think what I will do is combine my slider example with your example and should make for a good example in the end. Also, I was thinking of adding an input box (likely a color picker too) to change color. And with that, maybe a "Random Color" button as well.
    2 points
  48. UEZ

    DLL Call Problems

    Made a quick test with 3.3.12.0 by replacing AutoIt3.exe only - same result.
    2 points
  49. MattyD

    WinRT - WinUI3

    OK I've managed to get this working for the most part... bear with me. say we want to resolve: "Windows.Foundation.Collections.IVector`1<Microsoft.UI.Xaml.Controls.ColumnDefinition>" broadly speaking, this is what needs to happen. Create a MetaDataLocator - this is similar to how we're creating our delegates. It doesn't inherit from IUnknown, and has 1 method called "Locate"... but more on this in a bit! Call RoParseTypeName. This gives us an array of name elements i.e.: ["Windows.Foundation.Collections.IVector`1", "Microsoft.UI.Xaml.Controls.ColumnDefinition"] Use this info to call RoGetParameterizedTypeInstanceIID. As RoGetParameterizedTypeInstanceIID does its thing, it'll pump us for information - by you guessed it! calling our "Locate" function. we are provided with: a name of a typedef and a pointer to an IRoSimpleMetaDataBuilder interface. (I've written an interface library for this one). We need to dig in the metadata for that info, then call the correct method of the builder to send it on. A call to RoGetMetaDataFile will get us an pointer to a IMetadataImport2 interface. This is what we should use to find stuff. In our scenario, the first time "Locate" is called we're asked to resolve "Windows.Foundation.Collections.IVector`1" So we need to determine what this is.. (a paramatised interface). Therefore we should call builder.SetParameterizedInterface(PIID, NumParams). Next time around we get "Microsoft.UI.Xaml.Controls.RowDefinition". This is a class. So this time we should call builder.SetRuntimeClassSimpleDefault(ClassName, DefaultInterface, DefaultInterfaceIID). DefaultInterfaceIID is optional though can be left null. In this case Locate() would be called a third time asking us to resolve the default interface (Microsoft.UI.Xaml.Controls.IRowDefinition). Because this is a non-paramatised interface, we'd then call builder.SetWinRtInterface(IID). Once RoGetParameterizedTypeInstanceIID is satisfied it'll spit out what it thinks the IID is. If we call the wrong method on IRoSimpleMetaDataBuilder or provide bad info, then unsurprisingly we get an incorrect IID as a result! I'll do a bit of a tidy up, and pop some code up in a day or two
    2 points
  50. Working example: #include <MsgBoxConstants.au3> #include "wd_helper.au3" _Example() Func _Example() Run('"C:\Program Files\Mozilla Firefox\firefox.exe" --marionette -profile C:\FirefoxTEMP') _WD_Option('Driver', 'geckodriver.exe') _WD_Option('DriverParams', '--log trace --connect-existing --marionette-port 2828') _WD_Option('Port', 4444) _WD_Startup() Local $sSession = _WD_CreateSession() _WD_Navigate($sSession, "https://www.autoitscript.com/forum") MsgBox($MB_OK + $MB_TOPMOST + $MB_ICONINFORMATION, @ScriptName, "After attaching") _WD_Shutdown() EndFunc ;==>_Example
    2 points
×
×
  • Create New...