argumentum Posted September 12 Posted September 12 ..where did I put that code I had... somewhere 🤷♂️ Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
Solution argumentum Posted September 12 Author Solution Posted September 12 (edited) It's here in this thread. Don't go losing the code again, ..you hear ! 01) I use SciTE portable but don't have the context menus as when properly installed. 02) Have a bunch of RDP windows open and when they close ( some error ) I don't know from what PC it was from. 03) I use Dark reader and makes html copy/paste a mess for those not using it 🤷♂️ 04) Want to download torrents sequentially by default, but there is no default that I can find in qBittorrent 😭 05) _WinAPI_ShellGetKnownFolderPath() has a bunch of GUIDs and I'd like to know what paths work/return something 🤔 06) star trek stardate generator. 07) highlighting of icons on the desktop. 08) How can I draft and preview formatted posts elsewhere to copy and paste into the forum ? 09) How to format AutoIt source code by aligning assignment operators and inline comments. 10) Need to make a function for a small file on disk or clipboard that I can edit in a function, to include/customize said file in the script. 11) Script to upload images ( from file or clipboard image ) to GitHub. 12) Create a shortcut to your script to run it uncompiled ( using your icon if there ). 13) Disable downloaded files from being blocked. 14) Wake-on-LAN (WoL) a PC. 15) WoL receiver ( to start VMs in a Hyper-V from another PC ) 16) Volume Shadow Copy Management from CLI ( AutoIt translation of vssown.vbs ). 17) Set the help file to handle HiDPI better. 18) Registry entry to set high DPI compatibility on an executable. 19) FileGetTimeAmPm() - and an exercise on AI prompt engineering. 20) MDReader — Pure AutoIt Dark-Mode .md Viewer 21) IconMaker (v0.2026.1029.3) - make icons 🤪 List of libraries of user defined functions (UDF) in the WiKi. MAP display - Display the contents of a MAP-type variable in a TreeView. SciTE_OverlayTab. Searching specific content in Text file or AU3. File to Base64 String Code Generator (embed your files easily). I rather not have conversations in this thread. If you would like to chat about a post in this thread, open one in the help area, mentioning me and the post, and we'll chat there. Edited October 29 by argumentum added list of posts WildByDesign 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted September 12 Author Posted September 12 (edited) Problem I use SciTE portable but don't have the context menus as when properly installed Solution Add the registry entries to show a context menu for .au3 in SystemFileAssociations for the current user Spoiler expandcollapse popupGlobal $g_AutoIt3root = StringLeft(@AutoItExe, StringInStr(@AutoItExe, '\', 0, -1) - 1) Global $g_sSysAssoc = "HKCU\Software\Classes\SystemFileAssociations\.au3\shell" Global $g_sTemplate = $g_AutoIt3root & "\SciTE\Template\Script.au3" AutoIt_Portable_ContextMenu_Remove(0) AutoIt_Portable_ContextMenu_Add() Func AutoIt_Portable_ContextMenu_Add($iShowMsgbox = 1) RegWrite("HKCU\Software\Classes\.au3", "PerceivedType", "REG_SZ", "text") RegWrite("HKCU\Software\Classes\.au3", "Content Type", "REG_SZ", "text/plain") RegWrite("HKCU\Software\Classes\.au3", "", "REG_SZ", "AutoIt3Script.Portable") RegWrite("HKCU\Software\Classes\AutoIt3Script.Portable", "", "REG_SZ", "AutoIt v3 Script Portable") ScriptTemplateWrite() If FileExists($g_sTemplate) Then RegWrite("HKCU\Software\Classes\.au3\ShellNew", "FileName", "REG_SZ", $g_sTemplate) Else RegWrite("HKCU\Software\Classes\.au3\ShellNew", "NullFile", "REG_SZ", "") EndIf RegWriteContextMenuCommand("RunX86", "Run Script (x86 Portable)", '"' & $g_AutoIt3root & '\AutoIt3.exe" "%1" %*') RegWriteContextMenuCommand("RunX64", "Run Script (x64 Portable)", '"' & $g_AutoIt3root & '\AutoIt3_x64.exe" "%1" %*') RegWriteContextMenuCommand("EditWSciTE", "Edit Script (SciTE Portable)", '"' & $g_AutoIt3root & '\SciTE\SciTE.exe" "%1"') RegWriteContextMenuCommand("Compile with Options", "Compile with Options (Portable)", '"' & $g_AutoIt3root & '\AutoIt3.exe" "' & $g_AutoIt3root & '\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.au3" /ShowGui /in "%l"') RegWriteContextMenuCommand("CompileX86", "Compile Script (x86 Portable)", '"' & $g_AutoIt3root & '\Aut2Exe\Aut2Exe.exe" /in "%1" /x86') RegWriteContextMenuCommand("CompileX64", "Compile Script (x64 Portable)", '"' & $g_AutoIt3root & '\Aut2Exe\Aut2Exe.exe" /in "%1" /x64') RegWriteContextMenuCommand("Tidy", "Tidy (Portable)", '"' & $g_AutoIt3root & '\SciTE\Tidy\Tidy.exe" "%1"') RefreshWindowsExplorerShellCache() If $iShowMsgbox Then MsgBox(64, "Registration Complete", "SystemFileAssociations context menu entries registered.") EndFunc ;==>AutoIt_Portable_ContextMenu_Add Func RegWriteContextMenuCommand($sEntry, $sDesc, $sCommand) RegWrite($g_sSysAssoc & "\" & $sEntry, "", "REG_SZ", $sDesc) RegWrite($g_sSysAssoc & "\" & $sEntry & "\command", "", "REG_SZ", $sCommand) EndFunc ;==>RegWriteContextMenuCommand Func RefreshWindowsExplorerShellCache() DllCall("shell32.dll", "none", "SHChangeNotify", "long", 0x08000000, "uint", 0, "ptr", 0, "ptr", 0) EndFunc ;==>RefreshWindowsExplorerShellCache Func AutoIt_Portable_ContextMenu_Remove($iShowMsgbox = 1) ; Delete SystemFileAssociations extension key and all associated verbs RegDelete("HKCU\Software\Classes\SystemFileAssociations\.au3") RefreshWindowsExplorerShellCache() If $iShowMsgbox Then MsgBox(64, "Unregister Complete", "SystemFileAssociations and portable AutoIt registry entries removed.") EndFunc ;==>AutoIt_Portable_ContextMenu_Remove Func ScriptTemplateWrite($iOverwrite = 0) If Not $iOverwrite And FileGetSize($g_sTemplate) Then Return Local $hFileOpen = FileOpen($g_sTemplate, 138) ; $FO_OVERWRITE (2) + $FO_CREATEPATH (8) + $FO_UTF8 (128) FileWrite($hFileOpen, ScriptTemplateStr()) FileClose($hFileOpen) EndFunc ;==>ScriptTemplateWrite Func ScriptTemplateStr() Local $sStr = "" $sStr &= '#Region ;**** Directives created by AutoIt3Wrapper_GUI ****' $sStr &= @CRLF & '#AutoIt3Wrapper_UseX64=y' $sStr &= @CRLF & '#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7' $sStr &= @CRLF & '#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****' $sStr &= @CRLF & '' $sStr &= @CRLF & '#cs ----------------------------------------------------------------------------' $sStr &= @CRLF & '' $sStr &= @CRLF & ' AutoIt Version: ' & @AutoItVersion $sStr &= @CRLF & ' Author: myName' $sStr &= @CRLF & '' $sStr &= @CRLF & ' Script Function:' $sStr &= @CRLF & ' Template AutoIt script.' $sStr &= @CRLF & '' $sStr &= @CRLF & '#ce ----------------------------------------------------------------------------' $sStr &= @CRLF & '' $sStr &= @CRLF & '; Script Start - Add your code below here' $sStr &= @CRLF & '' $sStr &= @CRLF & '' Return $sStr EndFunc ;==>ScriptTemplateStr Edited September 23 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted September 12 Author Posted September 12 Problem Have a bunch of RDP windows open and when they close ( some error ) I don't know from what PC it was from. Solution Keep this script running in the tray and it will find the name of the connection and place it in the MsgBox's error title. Spoiler WhatRdpWasIt.au3 expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Icon=WhatRdpWasIt.ico #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Res_ProductName=WhatRdpWasIt.exe #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <WinAPISys.au3> #include <WinAPIProc.au3> #include <WinAPISysWin.au3> Global Enum $eRdpFromPID_32770, $eRdpFromPID_TscShellContainer, $eRdpFromPID_TscPopupParentWND, $eRdpFromPID_UBound If WinExists(StringTrimRight(@ScriptName, 4) & "_STUB") Then Exit 4 AutoItWinSetTitle(StringTrimRight(@ScriptName, 4) & "_STUB") Opt("TrayAutoPause", 0) Opt("TrayOnEventMode", 1) Opt("TrayMenuMode", 2) ;0=append, 1=no default menu, 2=no automatic check, 4=menuitemID not return If FileGetSize(StringTrimRight(@ScriptFullPath, 4) & ".ico") Then TraySetIcon(StringTrimRight(@ScriptFullPath, 4) & ".ico") EndIf TrayCreateItem("Open this folder") TrayItemSetOnEvent(-1, "Open_this_folder") Global $g_hWinHook = DllCallbackRegister('_WinEventProc', 'none', 'ptr;dword;hwnd;long;long;dword;dword') Global $g_hEventProc = _WinAPI_SetWinEventHook($EVENT_OBJECT_STATECHANGE, $EVENT_OBJECT_STATECHANGE, DllCallbackGetPtr($g_hWinHook)) If $g_hEventProc Then OnAutoItExitRegister('WinUnHook') Else Exit 5 EndIf While Sleep(100) WEnd Func Open_this_folder() ShellExecute(@WindowsDir & "\explorer.exe", '/n,/select,"' & @ScriptFullPath & '"', "") EndFunc ;==>Open_this_folder Func WinUnHook() If $g_hWinHook Then _WinAPI_UnhookWinEvent($g_hWinHook) If $g_hEventProc Then DllCallbackFree($g_hEventProc) $g_hWinHook = 0 $g_hEventProc = 0 EndFunc ;==>WinUnHook Func _WinEventProc($hEventHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iThreadId, $iEventTime) #forceref $hEventHook, $iEvent, $iObjectID, $iChildID, $iThreadId, $iEventTime If Not $hWnd Then Return Local $sTitle = WinGetTitle($hWnd) If Not StringInStr($sTitle, "Remote Desktop Connection") Then Return Local $sProcessName = "", $iPid = WinGetProcess($hWnd) If $iPid < 4 Then Return If $iPid > 1 Then $sProcessName = _WinAPI_GetProcessName($iPid) If $sProcessName <> "mstsc.exe" Then Return WinListRdpFromPID($iPid) EndFunc ;==>_WinEventProc Func WinListRdpFromPID($iPid, $sWinTitle = "Remote Desktop Connection") Local $aFound[$eRdpFromPID_UBound][2], $iEcho = 0 If $iPid < 2 Then Return SetError(2, 0, $aFound) Local Static $hTimer = TimerInit(), $aWinList = WinList($sWinTitle) Local $iOpt_WinTitleMatchMode = Opt("WinTitleMatchMode", 2) If TimerDiff($hTimer) > 1000 Then $hTimer = TimerInit() $aWinList = WinList($sWinTitle) EndIf If $iEcho Then ConsoleWrite('$aWinList[0][0] = ' & $aWinList[0][0] & @CRLF) For $i = 1 To $aWinList[0][0] If WinGetProcess($aWinList[$i][1]) = $iPid Then Switch _WinAPI_GetClassName($aWinList[$i][1]) Case "TSC_POPUP_PARENT_WNDCLASS" $aFound[$eRdpFromPID_TscPopupParentWND][0] = $aWinList[$i][1] ; "" $aFound[$eRdpFromPID_TscPopupParentWND][1] = $aWinList[$i][0] Case "TscShellContainerClass" $aFound[$eRdpFromPID_TscShellContainer][0] = $aWinList[$i][1] ; XPS8700K - Remote Desktop Connection $aFound[$eRdpFromPID_TscShellContainer][1] = $aWinList[$i][0] Case "#32770" If StringInStr(WinGetText($aWinList[$i][1]), @LF & @LF & "OK" & @LF) And $aWinList[$i][0] = "Remote Desktop Connection" Then $aFound[$eRdpFromPID_32770][0] = $aWinList[$i][1] ; Remote Desktop Connection $aFound[$eRdpFromPID_32770][1] = $aWinList[$i][0] If $iEcho Then ConsoleWrite('!' & $aWinList[$i][1] & @TAB & '[' & _WinAPI_GetClassName($aWinList[$i][1]) & ']' & @TAB & '[' & StringReplace(StringReplace(WinGetText($aWinList[$i][1]), @CR, "@CR"), @LF, "@LF") & ']' & @TAB & $aWinList[$i][0] & @CRLF) EndIf EndSwitch If $iEcho Then ConsoleWrite('+' & $aWinList[$i][1] & @TAB & '[' & _WinAPI_GetClassName($aWinList[$i][1]) & ']' & @TAB & '[' & StringReplace(StringReplace(WinGetText($aWinList[$i][1]), @CR, ">"), @LF, "~") & ']' & @TAB & $aWinList[$i][0] & @CRLF) Else If $iEcho Then ConsoleWrite('-' & $aWinList[$i][1] & @TAB & '[' & _WinAPI_GetClassName($aWinList[$i][1]) & ']' & @TAB & '[' & StringReplace(StringReplace(WinGetText($aWinList[$i][1]), @CR, ">"), @LF, "~") & ']' & @TAB & $aWinList[$i][0] & @CRLF) EndIf Next Opt("WinTitleMatchMode", $iOpt_WinTitleMatchMode) If $aFound[$eRdpFromPID_32770][0] Then _WinAPI_DwmSetWindowAttribute__($aFound[$eRdpFromPID_32770][0], 34, _WinAPI_SwitchColor(0x00AA00)) WinSetOnTop($aFound[$eRdpFromPID_32770][0], "", 1) WinSetTitle($aFound[$eRdpFromPID_32770][0], "", $aFound[$eRdpFromPID_TscShellContainer][1]) EndIf Return SetError(Not $aWinList[0][0], Int($aFound[$eRdpFromPID_32770][0]), $aFound) EndFunc ;==>WinListRdpFromPID Func _WinAPI_DwmSetWindowAttribute__($hWnd, $attribute = 34, $value = 0x00FF00, $valLen = 4) Local $aCall = DllCall('dwmapi.dll', 'long', 'DwmSetWindowAttribute', 'hwnd', $hWnd, 'dword', $attribute, 'dword*', $value, 'dword', $valLen) If @error Then Return SetError(@error, @extended, 0) If $aCall[0] Then Return SetError(10, $aCall[0], 0) Return 1 EndFunc ;==>_WinAPI_DwmSetWindowAttribute__ WhatRdpWasIt-icon-gen.au3 expandcollapse popup#NoTrayIcon #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Global $g_hGraphics = 0 Global $g_hBitmap = 0 WhatRdpWasIt_IcoGen() Func WhatRdpWasIt_IcoGen() _GDIPlus_Startup() Local Const $iWidth = 600 Local Const $iHeight = 600 Local $hGUI = GUICreate("GDI+ WhatRdpWasIt icon/png generator", $iWidth, $iHeight) $g_hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI) $g_hBitmap = _GDIPlus_BitmapCreateFromGraphics($iWidth, $iHeight, $g_hGraphics) Local $hBuffer = _GDIPlus_ImageGetGraphicsContext($g_hBitmap) _GDIPlus_GraphicsSetSmoothingMode($hBuffer, 4) ; Palette Colors (ARGB: 0xAA RRGGBB) Local Const $iBgColor = 0x00000000 ; Fully transparent background Local Const $iCircleColor = 0xFFC48A20 ; Golden-ochre Local Const $iArrowColor = 0xFFECECEC ; Off-white / light grey Local $hBrushCircle = _GDIPlus_BrushCreateSolid($iCircleColor) Local Const $fPenWidth = 75.0 Local $hPenArrow = _GDIPlus_PenCreate($iArrowColor, $fPenWidth) _GDIPlus_PenSetLineJoin($hPenArrow, 2) _GDIPlus_PenSetStartCap($hPenArrow, 2) _GDIPlus_PenSetEndCap($hPenArrow, 2) ; Clear Canvas to Transparent ARGB _GDIPlus_GraphicsClear($hBuffer, $iBgColor) ; Main Circle _GDIPlus_GraphicsFillEllipse($hBuffer, 50, 50, 500, 500, $hBrushCircle) ; Upper Chevron Lines _GDIPlus_GraphicsDrawLine($hBuffer, 415, 155, 330, 240, $hPenArrow) _GDIPlus_GraphicsDrawLine($hBuffer, 330, 240, 395 + 20, 305 + 20, $hPenArrow) ; Lower Chevron Lines _GDIPlus_GraphicsDrawLine($hBuffer, 185, 445, 270, 360, $hPenArrow) _GDIPlus_GraphicsDrawLine($hBuffer, 270, 360, 205 - 20, 295 - 20, $hPenArrow) ; --- SAVE TRANSPARENT PNG AND ICO --- _GDIPlus_ImageSaveToFile($g_hBitmap, @ScriptDir & "\WhatRdpWasIt.png") _SaveBitmapToIco($g_hBitmap, @ScriptDir & "\WhatRdpWasIt.ico", 256) GUIRegisterMsg(0x000F, "_WM_PAINT") GUISetState(@SW_SHOW, $hGUI) _GDIPlus_GraphicsDrawImage($g_hGraphics, $g_hBitmap, 0, 0) While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd _GDIPlus_PenDispose($hPenArrow) _GDIPlus_BrushDispose($hBrushCircle) _GDIPlus_GraphicsDispose($hBuffer) _GDIPlus_BitmapDispose($g_hBitmap) _GDIPlus_GraphicsDispose($g_hGraphics) _GDIPlus_Shutdown() GUIDelete() EndFunc ;==>WhatRdpWasIt_IcoGen Func _WM_PAINT($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam If $g_hGraphics And $g_hBitmap Then _GDIPlus_GraphicsDrawImage($g_hGraphics, $g_hBitmap, 0, 0) EndIf Return $GUI_RUNDEFMSG EndFunc ;==>_WM_PAINT Func _SaveBitmapToIco($hSrcBitmap, $sIcoPath, $iIconSize = 256) Local $hBitmap256 = _GDIPlus_BitmapCreateFromScan0($iIconSize, $iIconSize) Local $hCtx256 = _GDIPlus_ImageGetGraphicsContext($hBitmap256) _GDIPlus_GraphicsClear($hCtx256, 0x00000000) _GDIPlus_GraphicsSetSmoothingMode($hCtx256, 4) _GDIPlus_GraphicsSetInterpolationMode($hCtx256, 7) _GDIPlus_GraphicsDrawImageRect($hCtx256, $hSrcBitmap, 0, 0, $iIconSize, $iIconSize) Local $sTempPNG = @TempDir & "\~tmpIcon_" & Random(1000, 9999, 1) & ".png" _GDIPlus_ImageSaveToFile($hBitmap256, $sTempPNG) _GDIPlus_GraphicsDispose($hCtx256) _GDIPlus_BitmapDispose($hBitmap256) Local $hFile = FileOpen($sTempPNG, 16) Local $bPngData = FileRead($hFile) FileClose($hFile) FileDelete($sTempPNG) Local $iPngSize = BinaryLen($bPngData) If $iPngSize = 0 Then Return False Local $tHeader = DllStructCreate("align 1; word; word; word; byte; byte; byte; byte; word; word; dword; dword") DllStructSetData($tHeader, 1, 0) DllStructSetData($tHeader, 2, 1) DllStructSetData($tHeader, 3, 1) DllStructSetData($tHeader, 4, ($iIconSize >= 256) ? 0 : $iIconSize) DllStructSetData($tHeader, 5, ($iIconSize >= 256) ? 0 : $iIconSize) DllStructSetData($tHeader, 6, 0) DllStructSetData($tHeader, 7, 0) DllStructSetData($tHeader, 8, 1) DllStructSetData($tHeader, 9, 32) DllStructSetData($tHeader, 10, $iPngSize) DllStructSetData($tHeader, 11, 22) Local $tBytes = DllStructCreate("byte[22]", DllStructGetPtr($tHeader)) Local $bHeader = DllStructGetData($tBytes, 1) Local $hIcoFile = FileOpen($sIcoPath, 18) FileWrite($hIcoFile, $bHeader) FileWrite($hIcoFile, $bPngData) FileClose($hIcoFile) Return True EndFunc ;==>_SaveBitmapToIco Add it to shell:startup to run on login. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted September 14 Author Posted September 14 (edited) Problem I use Dark reader and makes html copy/paste a mess for those not using it 🤷♂️ Solution Run this function to remove the background coloring from the clipboard Spoiler expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <Clipboard.au3> #include <Memory.au3> #include <String.au3> Exit _PasteCleanRichText(0) ; Bind to a hotkey: Ctrl + Alt + Shift + V HotKeySet("^!+v", "_HotKey_PasteCleanRichText") While 1 Sleep(100) WEnd Func _HotKey_PasteCleanRichText() _PasteCleanRichText() EndFunc Func _PasteCleanRichText($iSendCtrlV = 1) ; https://www.autoitscript.com/forum/topic/213874-solved-help-for-argumentum/#findComment-1554648 _ClipBoard_Open(0) Local $iFormat = _ClipBoard_RegisterFormat("HTML Format") If Not _ClipBoard_IsFormatAvailable($iFormat) Then _ClipBoard_Close() If $iSendCtrlV Then Send("^v") Return EndIf ; 1. Get binary data and convert to UTF-8 string Local $vBinData = _ClipBoard_GetData($iFormat) _ClipBoard_Close() If @error Or Not IsBinary($vBinData) Then If $iSendCtrlV Then Send("^v") Return EndIf Local $sRawHTML = BinaryToString($vBinData, 4) ; 4 = UTF-8 ; 2. Extract the fragment part between <!--StartFragment--> and <!--EndFragment--> Local $aMatch = StringRegExp($sRawHTML, "(?s)<!--StartFragment-->(.*?)<!--EndFragment-->", 3) Local $sFragment = "" If @error Then ; Fallback if tags aren't found: use the whole raw string $sFragment = $sRawHTML Else $sFragment = $aMatch[0] EndIf ; 3. Strip out forced dark-mode styles from the fragment $sFragment = StringRegExpReplace($sFragment, "color:\s*[^;]+;", "") $sFragment = StringRegExpReplace($sFragment, "background-color:\s*[^;]+;", "") $sFragment = StringRegExpReplace($sFragment, "background:\s*[^;]+;", "") $sFragment = StringRegExpReplace($sFragment, 'style="\s*"', "") ; 4. Build a brand-new, perfectly calculated CF_HTML payload Local $sPrefix = "Version:0.9" & @CRLF & _ "StartHTML:00000097" & @CRLF & _ "EndHTML:" & StringFormat("%010d", 135 + StringLen($sFragment) + 55) & @CRLF & _ "StartFragment:00000135" & @CRLF & _ "EndFragment:" & StringFormat("%010d", 135 + StringLen($sFragment)) & @CRLF & _ "<html><body><!--StartFragment-->" Local $sSuffix = "<!--EndFragment--></body></html>" Local $sFinalHTML = $sPrefix & $sFragment & $sSuffix ; 5. Allocate global memory and push to clipboard Local $vUtf8Bin = StringToBinary($sFinalHTML, 4) Local $iLen = BinaryLen($vUtf8Bin) + 1 Local $hMem = _MemGlobalAlloc($iLen, 0x0002) ; $GMEM_MOVEABLE If Not $hMem Then If $iSendCtrlV Then Send("^v") Return EndIf Local $pMem = _MemGlobalLock($hMem) DllStructSetData(DllStructCreate("byte[" & $iLen & "]", $pMem), 1, $vUtf8Bin) _MemGlobalUnlock($hMem) _ClipBoard_Open(0) _ClipBoard_Empty() _ClipBoard_SetDataEx($hMem, $iFormat) _ClipBoard_Close() ; 6. Send paste command If $iSendCtrlV Then Send("^v") EndFunc making this background formatted clipboard: Spoiler While traditional WebDriver acts like a remote-control robot interacting with a web page from the outside (clicking buttons, typing text as a user would), the Chrome DevTools Protocol (CDP) plugs directly into the browser's engine. Because of this deep access, CDP can do several low-level tasks that standard WebDriver cannot easily do: Browserbase+ 1 1. Advanced Network Interception & Mocking What CDP can do: You can intercept, modify, mock, or drop network requests and responses on the fly. For example, you can intercept an API call returning user data and change the JSON payload mid-flight to test how your app handles specific data without altering the backend database. Testplane Why WebDriver struggles: Standard WebDriver has very limited network control; it mostly just tells the browser to navigate and lets whatever happens on the network happen passively. 2. Device, Geolocation, and Sensor Emulation What CDP can do: It allows you to deeply mock physical device metrics. You can dynamically override geolocation coordinates, timezones, CPU throttling (simulate a slow phone processor), network offline/online states, and even device orientation or touch events. Why WebDriver struggles: While modern WebDriver implementations have added basic geolocation or mobile emulation hooks, they are often rigid and restricted compared to the granular parameters you can pass directly through CDP's emulation domains. 3. Real-Time Event Streaming & Console Logging What CDP can do: It streams browser events natively over WebSockets. You can instantly capture unhandled JavaScript exceptions, browser console logs, performance metrics, and storage/cookie updates the exact millisecond they happen. Obsidian Publish+ 1 Why WebDriver struggles: WebDriver historically relies on a request-response polling model. To get console logs or errors, WebDriver usually has to ask the browser for them after the fact rather than streaming them live. 4. Performance Tracing and Profiling What CDP can do: You can record deep performance traces, generate CPU profiles, and measure memory heaps. This lets developers programmatic check for memory leaks or find out exactly why a page load is lagging down to the millisecond. Why WebDriver struggles: WebDriver has no native capability to inspect memory consumption, JavaScript execution timelines, or deep rendering metrics. 5. Managing Browser Contexts and Service Workers What CDP can do: It gives you granular control over background processes like Service Workers, Web Workers, out-of-process iframes, and isolated incognito storage partitions (Browser Contexts) without needing to spin up separate browser windows. Browserbase Summary: Think of WebDriver as a user sitting in front of a monitor using a mouse and keyboard. Think of CDP as an engineer plugged directly into the browser's electrical wiring with a diagnostic kit. look better: Spoiler While traditional WebDriver acts like a remote-control robot interacting with a web page from the outside (clicking buttons, typing text as a user would), the Chrome DevTools Protocol (CDP) plugs directly into the browser's engine. Because of this deep access, CDP can do several low-level tasks that standard WebDriver cannot easily do: Browserbase+ 1 1. Advanced Network Interception & Mocking What CDP can do: You can intercept, modify, mock, or drop network requests and responses on the fly. For example, you can intercept an API call returning user data and change the JSON payload mid-flight to test how your app handles specific data without altering the backend database. Testplane Why WebDriver struggles: Standard WebDriver has very limited network control; it mostly just tells the browser to navigate and lets whatever happens on the network happen passively. 2. Device, Geolocation, and Sensor Emulation What CDP can do: It allows you to deeply mock physical device metrics. You can dynamically override geolocation coordinates, timezones, CPU throttling (simulate a slow phone processor), network offline/online states, and even device orientation or touch events. Why WebDriver struggles: While modern WebDriver implementations have added basic geolocation or mobile emulation hooks, they are often rigid and restricted compared to the granular parameters you can pass directly through CDP's emulation domains. 3. Real-Time Event Streaming & Console Logging What CDP can do: It streams browser events natively over WebSockets. You can instantly capture unhandled JavaScript exceptions, browser console logs, performance metrics, and storage/cookie updates the exact millisecond they happen. Obsidian Publish+ 1 Why WebDriver struggles: WebDriver historically relies on a request-response polling model. To get console logs or errors, WebDriver usually has to ask the browser for them after the fact rather than streaming them live. 4. Performance Tracing and Profiling What CDP can do: You can record deep performance traces, generate CPU profiles, and measure memory heaps. This lets developers programmatic check for memory leaks or find out exactly why a page load is lagging down to the millisecond. Why WebDriver struggles: WebDriver has no native capability to inspect memory consumption, JavaScript execution timelines, or deep rendering metrics. 5. Managing Browser Contexts and Service Workers What CDP can do: It gives you granular control over background processes like Service Workers, Web Workers, out-of-process iframes, and isolated incognito storage partitions (Browser Contexts) without needing to spin up separate browser windows. Browserbase Summary: Think of WebDriver as a user sitting in front of a monitor using a mouse and keyboard. Think of CDP as an engineer plugged directly into the browser's electrical wiring with a diagnostic kit. Edited September 28 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted September 15 Author Posted September 15 (edited) Problem Want to download torrents sequentially by default, but there is no default that I can find in qBittorrent 😭 The reason for "the problem" ...that works against the swarm and spirit of the protocol. So it will never have a default sequential setting. Solution #1 If you must have it then register your own handler to do it via WebUI. Go to: Tools > Options > WebUI and enable it. Then compile and register the script below with your user, password and port. Spoiler expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Icon=qBittorrAdd.ico #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Res_Comment=qBittorrAdd #AutoIt3Wrapper_Res_Description=qBittorrAdd #AutoIt3Wrapper_Res_Fileversion=0.2608.6.7 #AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y #AutoIt3Wrapper_Res_ProductName=qBittorrAdd.exe #AutoIt3Wrapper_Res_ProductVersion=0.2608.6.0 #AutoIt3Wrapper_Res_CompanyName=. #AutoIt3Wrapper_Res_LegalCopyright=. #AutoIt3Wrapper_Res_LegalTradeMarks=. #AutoIt3Wrapper_Run_Au3Stripper=y #Au3Stripper_Parameters=/mo #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <MsgBoxConstants.au3> #include <FileConstants.au3> ;~ #RequireAdmin ; Run this once as Administrator to register magnet links ;~ Exit _RegisterMagnetProtocol() ; Prevent AutoIt hard crashes on COM errors Global $oCOMError = ObjEvent("AutoIt.Error", "_COMErrHandler") ; --- Configuration --- Local $sWebUiUrl = "https://127.0.0.1:8080" Local $sUsername = "YOUR_USERNAME_HERE" Local $sPassword = "YOUR_PASSWORD_HERE" ; Set to your active Web UI password ; Check if a magnet link, URL, or file path was passed via command line Local $sTarget = "" If $CmdLine[0] > 0 Then $sTarget = $CmdLine[1] Else $sTarget = InputBox("qBittorrent Sequential Add", "Enter Torrent URL, Magnet Link, or File Path:") If @error Or $sTarget = "" Then Exit EndIf ; Strip surrounding quotes if dragged & dropped or passed via CMD $sTarget = StringRegExpReplace($sTarget, '^"|"$', '') ; Create HTTP Object Local $oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1") ; Configure SSL (Ignore self-signed errors & Force TLS 1.2) Const $WinHttpRequestOption_SslErrorIgnoreFlags = 4 Const $WinHttpRequestOption_SecureProtocols = 9 $oHTTP.Option($WinHttpRequestOption_SslErrorIgnoreFlags) = 13056 $oHTTP.Option($WinHttpRequestOption_SecureProtocols) = 2048 ; --- Step 1: Login --- Local $sLoginBody = "username=" & _URLEncode($sUsername) & "&password=" & _URLEncode($sPassword) $oHTTP.Open("POST", $sWebUiUrl & "/api/v2/auth/login", False) $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") $oHTTP.SetRequestHeader("Referer", $sWebUiUrl) $oHTTP.Send($sLoginBody) ; Validate status code (200 or 204 indicates success) If $oHTTP.Status <> 200 And $oHTTP.Status <> 204 Then MsgBox($MB_ICONERROR, "Auth Error", "Login failed! HTTP Status: " & $oHTTP.Status & @CRLF & "Response: " & $oHTTP.ResponseText, 5) Exit EndIf ; --- Step 2: Add Torrent with Sequential Download Enabled --- $oHTTP.Open("POST", $sWebUiUrl & "/api/v2/torrents/add", False) $oHTTP.SetRequestHeader("Referer", $sWebUiUrl) If FileExists($sTarget) Then ; --- Handle Local .torrent File (multipart/form-data) --- Local $sBoundary = "----AutoItBoundary" & Hex(Random(100000, 999999, 1)) Local $sFileName = StringRegExpReplace($sTarget, "^.*[\\/]", "") ; Read file as binary Local $hFile = FileOpen($sTarget, $FO_BINARY) Local $bFileContent = FileRead($hFile) FileClose($hFile) ; 1. Build options header FIRST before the file bytes Local $sParamsPart = "" $sParamsPart &= "--" & $sBoundary & @CRLF $sParamsPart &= 'Content-Disposition: form-data; name="sequentialDownload"' & @CRLF & @CRLF $sParamsPart &= "true" & @CRLF $sParamsPart &= "--" & $sBoundary & @CRLF $sParamsPart &= 'Content-Disposition: form-data; name="firstLastPiecePrio"' & @CRLF & @CRLF $sParamsPart &= "false" & @CRLF $sParamsPart &= "--" & $sBoundary & @CRLF $sParamsPart &= 'Content-Disposition: form-data; name="torrents"; filename="' & $sFileName & '"' & @CRLF $sParamsPart &= "Content-Type: application/x-bittorrent" & @CRLF & @CRLF ; 2. Closing boundary after binary file content Local $sEndPart = @CRLF & "--" & $sBoundary & "--" & @CRLF ; 3. Combine header/parameters, file bytes, and closing boundary Local $bPayload = Binary($sParamsPart) & $bFileContent & Binary($sEndPart) $oHTTP.SetRequestHeader("Content-Type", "multipart/form-data; boundary=" & $sBoundary) $oHTTP.Send($bPayload) Else ; --- Handle Magnet Link or Web URL (application/x-www-form-urlencoded) --- Local $sAddBody = "urls=" & _URLEncode($sTarget) & "&sequentialDownload=true&firstLastPiecePrio=false" $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") $oHTTP.Send($sAddBody) EndIf Func _RegisterMagnetProtocol() Local $sExePath = StringTrimRight(@ScriptFullPath, 4) & ".exe" Local $sAppProgID = StringTrimRight(@ScriptName, 4) If IsAdmin() Then ; Register 'magnet:' protocol in Windows Registry RegWrite("HKCR\magnet", "", "REG_SZ", "URL:Magnet link") RegWrite("HKCR\magnet", "URL Protocol", "REG_SZ", "") RegWrite("HKCR\magnet\shell\open\command", "", "REG_SZ", '"' & $sExePath & '" "%1"') If Not @error Then MsgBox($MB_ICONINFORMATION, "Success", "Registered magnet links to:" & @CRLF & $sExePath, 10) Else MsgBox($MB_ICONERROR, "Error", "Failed to write registry keys.", 10) EndIf EndIf ; 1. Define Protocol Class RegWrite("HKCU\Software\Classes\" & $sAppProgID, "", "REG_SZ", "URL:Magnet link") RegWrite("HKCU\Software\Classes\" & $sAppProgID, "URL Protocol", "REG_SZ", "") RegWrite("HKCU\Software\Classes\" & $sAppProgID & "\shell\open\command", "", "REG_SZ", '"' & $sExePath & '" "%1"') ; 2. Register as Windows Capability (makes it show up in Default Apps) RegWrite("HKCU\Software\" & $sAppProgID & "\Capabilities", "ApplicationName", "REG_SZ", "qBittorrent Sequential Handler") RegWrite("HKCU\Software\" & $sAppProgID & "\Capabilities\URLAssociations", "magnet", "REG_SZ", $sAppProgID) RegWrite("HKCU\Software\RegisteredApplications", $sAppProgID, "REG_SZ", "Software\" & $sAppProgID & "\Capabilities") MsgBox($MB_ICONINFORMATION, "Done", "App registered in Windows Default Apps menu!", 10) EndFunc ;==>_RegisterMagnetProtocol ; Check response If $oHTTP.Status = 200 Or $oHTTP.Status = 204 Then ToolTip("Torrent added sequentially via HTTPS!", 10, 10, "qBittorrent", 1) Sleep(2000) Else MsgBox($MB_ICONERROR, "qBittorrent Error", "Failed to add torrent. HTTP Status: " & $oHTTP.Status & @CRLF & "Response: " & $oHTTP.ResponseText, 3) EndIf ; --- Helper Function to URL-Encode Form Data --- Func _URLEncode($sData) Local $aArray = StringSplit($sData, ""), $sEncoded = "", $iAsc For $i = 1 To $aArray[0] $iAsc = Asc($aArray[$i]) Select Case ($iAsc >= 48 And $iAsc <= 57) Or ($iAsc >= 65 And $iAsc <= 90) Or ($iAsc >= 97 And $iAsc <= 122) $sEncoded &= $aArray[$i] Case $aArray[$i] = " " $sEncoded &= "+" Case Else $sEncoded &= "%" & Hex($iAsc, 2) EndSelect Next Return $sEncoded EndFunc ;==>_URLEncode Func _COMErrHandler($oError) EndFunc ;==>_COMErrHandler Solution #2 ( simpler but i didn't think of it before ) Go to Tools > Options > Downloads, then on Run external program, Run on torrent added: "C:\Utilities\qBittorrAddSeq.exe" "/I:%I" "/J:%J" Spoiler expandcollapse popup#NoTrayIcon #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <MsgBoxConstants.au3> ; "C:\Utilities\qBittorrAddSeq.exe" "/I:%I" "/J:%J" ; Prevent AutoIt hard crashes on COM errors Global $oCOMError = ObjEvent("AutoIt.Error", "_COMErrHandler") qTorr_AddSequentialViaWebUI() Func qTorr_AddSequentialViaWebUI($sWebUiUrl = "https://127.0.0.1:8080", $sUsername = "YOUR_USERNAME_HERE", $sPassword = "YOUR_PASSWORD_HERE") ; --- Parameter Parsing --- Local $sHash = "" Local $sHashV1 = "" Local $sHashV2 = "" ; Loop through all arguments looking for /I: or /J: If $CmdLine[0] > 0 Then For $i = 1 To $CmdLine[0] If StringLeft($CmdLine[$i], 3) = "/I:" Then $sHashV1 = StringMid($CmdLine[$i], 4) ElseIf StringLeft($CmdLine[$i], 3) = "/J:" Then $sHashV2 = StringMid($CmdLine[$i], 4) EndIf Next EndIf ; Combine them if both exist, otherwise use whichever is populated If $sHashV1 <> "" And $sHashV2 <> "" Then $sHash = $sHashV1 & "|" & $sHashV2 ElseIf $sHashV1 <> "" Then $sHash = $sHashV1 Else $sHash = $sHashV2 EndIf ; Exit silently if no valid hash was passed If $sHash = "" Then Exit 4 ; --- HTTP Web API Transmission --- Local $oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1") ; Configure SSL (Ignore self-signed errors & Force TLS 1.2) Const $WinHttpRequestOption_SslErrorIgnoreFlags = 4 Const $WinHttpRequestOption_SecureProtocols = 9 $oHTTP.Option($WinHttpRequestOption_SslErrorIgnoreFlags) = 13056 $oHTTP.Option($WinHttpRequestOption_SecureProtocols) = 2048 ; Step 1: Login to get session cookie Local $sLoginBody = "username=" & _URLEncode($sUsername) & "&password=" & _URLEncode($sPassword) $oHTTP.Open("POST", $sWebUiUrl & "/api/v2/auth/login", False) $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") $oHTTP.SetRequestHeader("Referer", $sWebUiUrl) $oHTTP.Send($sLoginBody) ; Validate status code (200 or 204 indicates success) If $oHTTP.Status <> 200 And $oHTTP.Status <> 204 Then MsgBox($MB_ICONERROR, StringTrimRight(@ScriptName, 4) & " Error", "Login failed!" & @CRLF & " HTTP Status: " & $oHTTP.Status & @CRLF & "Response: " & $oHTTP.ResponseText, 60) Exit 5 EndIf ; Step 2: Toggle Sequential Download Using the Extracted Hash $oHTTP.Open("POST", $sWebUiUrl & "/api/v2/torrents/toggleSequentialDownload", False) $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") $oHTTP.SetRequestHeader("Referer", $sWebUiUrl) $oHTTP.Send("hashes=" & $sHash) ; Validate status code (200 or 204 indicates success) If $oHTTP.Status <> 200 And $oHTTP.Status <> 204 Then MsgBox($MB_ICONERROR, StringTrimRight(@ScriptName, 4) & " Error", "toggleSequentialDownload failed!" & @CRLF & " HTTP Status: " & $oHTTP.Status & @CRLF & "Response: " & $oHTTP.ResponseText, 60) Exit 6 EndIf ;~ ; Step 3: Automatically prioritize the first and last pieces ;~ $oHTTP.Open("POST", $sWebUiUrl & "/api/v2/torrents/toggleFirstLastPiecePrio", False) ;~ $oHTTP.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") ;~ $oHTTP.SetRequestHeader("Referer", $sWebUiUrl) ;~ $oHTTP.Send("hashes=" & $sHash) ;~ ; Validate status code (200 or 204 indicates success) ;~ If $oHTTP.Status <> 200 And $oHTTP.Status <> 204 Then ;~ MsgBox($MB_ICONERROR, StringTrimRight(@ScriptName, 4) & " Error", "toggleFirstLastPiecePrio failed!" & @CRLF & " HTTP Status: " & $oHTTP.Status & @CRLF & "Response: " & $oHTTP.ResponseText, 60) ;~ Exit 7 ;~ EndIf Exit 0 ; all good. EndFunc ;==>qTorr_AddSequentialViaWebUI ; --- Helper Function to URL-Encode Form Data --- Func _URLEncode($sData) Local $aArray = StringSplit($sData, ""), $sEncoded = "", $iAsc For $i = 1 To $aArray[0] $iAsc = Asc($aArray[$i]) Select Case ($iAsc >= 48 And $iAsc <= 57) Or ($iAsc >= 65 And $iAsc <= 90) Or ($iAsc >= 97 And $iAsc <= 122) $sEncoded &= $aArray[$i] Case $aArray[$i] = " " $sEncoded &= "+" Case Else $sEncoded &= "%" & Hex($iAsc, 2) EndSelect Next Return $sEncoded EndFunc ;==>_URLEncode Func _COMErrHandler($oError) EndFunc ;==>_COMErrHandler Edited September 15 by argumentum more Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted September 19 Author Posted September 19 (edited) Problem _WinAPI_ShellGetKnownFolderPath() has a bunch of GUIDs and I'd like to know what paths work/return something 🤔 Solution Get the table from MSDN and try each 🤷♂️ Do read the help file regarding $iFlags and $hToken. Spoiler expandcollapse popup#AutoIt3Wrapper_UseX64=y #include <WinAPIShellEx.au3> #include <NetShare.au3> #include <Debug.au3> Exit _knownfolderid2array() Func _knownfolderid2array() If Not FileGetSize("knownfolderid.htm") Then Local $sSource = InetRead("https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid") $sSource = BinaryToString($sSource) FileWrite("knownfolderid.htm", $sSource) EndIf Local $sHTML = FileRead("knownfolderid.htm") Local $oHTML = ObjCreate("HTMLFile") ; Parse HTML using the MSXML HTMLFile COM object If Not IsObj($oHTML) Then MsgBox(16, "oops", "Failed to create HTMLFile object.") Exit EndIf $oHTML.Open() $oHTML.Write($sHTML) $oHTML.Close() Local $oTargetTable, $oTables = $oHTML.getElementsByTagName("table") ; Locate target Constants table For $i = 0 To $oTables.length - 1 Local $sTableText = $oTables.item($i).innerText If StringInStr($sTableText, "FOLDERID_") Or StringInStr($sTableText, "Constant") Then $oTargetTable = $oTables.item($i) ExitLoop EndIf Next If Not IsObj($oTargetTable) Then Exit MsgBox(48, "oops", "Could not locate the Constants table.") Local $sCleanText, $oCells, $oRows = $oTargetTable.rows Local $sCellHTML, $iRowCount = $oRows.length Local $aConstantsData[$iRowCount][9] $aConstantsData[0][0] = "Constant Name" $aConstantsData[0][1] = "Path" $aConstantsData[0][2] = "GUID" $aConstantsData[0][3] = "Display Name" $aConstantsData[0][4] = "Folder Type" $aConstantsData[0][5] = "Default Path" $aConstantsData[0][6] = "CSIDL Equivalent" $aConstantsData[0][7] = "Legacy Display Name" $aConstantsData[0][8] = "Legacy Default Path" For $r = 1 To $iRowCount - 1 ; Populate Array and Subdivide Description Fields $oCells = $oRows.item($r).cells If $oCells.length < 2 Then ContinueLoop $aConstantsData[$r][0] = StringStripWS($oCells.item(0).innerText, 3) $sCellHTML = $oCells.item(1).innerHTML $sCellHTML = StringRegExpReplace($sCellHTML, "(?i)</?(?:p|div|tr|td|br|dt|dd)[^>]*>", @CRLF) $sCleanText = StringRegExpReplace($sCellHTML, "<[^>]+>", "") $sCleanText = StringReplace($sCleanText, " ", " ") $sCleanText = StringReplace($sCleanText, "&", "&") $sCleanText = StringReplace($sCleanText, "<", "<") $sCleanText = StringReplace($sCleanText, ">", ">") $sCleanText = StringRegExpReplace($sCleanText, "(?i)\bLegacy Display Name\b", "KEY_LEGACY_DISPLAY_NAME:") $sCleanText = StringRegExpReplace($sCleanText, "(?i)\bLegacy Default Path\b", "KEY_LEGACY_DEFAULT_PATH:") $sCleanText = StringRegExpReplace($sCleanText, "(?i)\bDisplay Name\b", "KEY_DISPLAY_NAME:") $sCleanText = StringRegExpReplace($sCleanText, "(?i)\bDefault Path\b", "KEY_DEFAULT_PATH:") $sCleanText = StringRegExpReplace($sCleanText, "(?i)\bFolder Type\b", "KEY_FOLDER_TYPE:") $sCleanText = StringRegExpReplace($sCleanText, "(?i)\bCSIDL Equivalent[s]?\b", "KEY_CSIDL:") $sCleanText = StringRegExpReplace($sCleanText, "(?i)\bGUID\b", "KEY_GUID:") $aConstantsData[$r][2] = _ExtractTagValue($sCleanText, "KEY_GUID") $aConstantsData[$r][3] = _ExtractTagValue($sCleanText, "KEY_DISPLAY_NAME") $aConstantsData[$r][4] = _ExtractTagValue($sCleanText, "KEY_FOLDER_TYPE") $aConstantsData[$r][5] = _ExtractTagValue($sCleanText, "KEY_DEFAULT_PATH") $aConstantsData[$r][6] = _ExtractTagValue($sCleanText, "KEY_CSIDL") $aConstantsData[$r][7] = _ExtractTagValue($sCleanText, "KEY_LEGACY_DISPLAY_NAME") $aConstantsData[$r][8] = _ExtractTagValue($sCleanText, "KEY_LEGACY_DEFAULT_PATH") Next For $r = 1 To UBound($aConstantsData) - 1 If $aConstantsData[$r][2] = "" Then ContinueLoop $aConstantsData[$r][1] = _WinAPI_ShellGetKnownFolderPath($aConstantsData[$r][2]) If $aConstantsData[$r][1] <> "" Then ConsoleWrite('- ' & $aConstantsData[$r][2] & @TAB & $aConstantsData[$r][1] & @CRLF) EndIf Next ;~ _DebugArrayDisplay($aConstantsData, "KnownFolderID Table", "", 0, Default, _ ;~ "Constant Name|Path|GUID|Display Name|Folder Type|Default Path|CSIDL Equivalent|Legacy Display Name|Legacy Default Path") Return $aConstantsData EndFunc ;==>_knownfolderid2array Func _ExtractTagValue($sText, $sTag) Local $sPattern = "(?is)" & $sTag & ":\s*(.*?)(?=\s*KEY_[A-Z_]+:|\z)" Local $aMatch = StringRegExp($sText, $sPattern, 1) If @error Or UBound($aMatch) = 0 Then Return "" Return StringStripWS($aMatch[0], 3) EndFunc ;==>_ExtractTagValue Edited September 23 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted September 29 Author Posted September 29 (edited) Problem 23 hours ago, TheSaint said: Take for instance, highlighting of an icon on the desktop. You can barely tell if the icon is highlighted, and quite often cannot really. Solution 23 hours ago, argumentum said: ..the icons on the desktop are in a Listview. It'd be a good project to get the selected entry and draw a frame around it 🤔 or Spoiler expandcollapse popup#AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #AutoIt3Wrapper_UseX64=y #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <GuiListView.au3> #include <WinAPI.au3> ; 1. Enable Per-Monitor V2 DPI Awareness for accurate physical pixel reporting _EnableDPIAwareness() ; WinEvent Hook Constants ;~ Global Const $EVENT_OBJECT_SELECTION = 0x8006 ;~ Global Const $EVENT_OBJECT_LOCATIONCHANGE = 0x800B ;~ Global Const $WINEVENT_OUTOFCONTEXT = 0x0000 Global $g_hWndLV = _GetDesktopListViewHandle() If Not $g_hWndLV Then MsgBox(16, 'Error', 'Cannot obtain Desktop ListView handle.', 60) Exit 4 EndIf Global $g_hEventCallback = 0, $g_pEventCallback = 0 Global $g_aBorderGUIs[1] = [0] Global $g_sLastSelectedState = "", $g_RoundCorners = True Global $g_hHook = _SetWinEventHook() If Not $g_hHook Then MsgBox(16, 'Error', 'Failed to install WinEvent hook.', 60) DllCallbackFree($g_hEventCallback) Exit 5 EndIf OnAutoItExitRegister("_OnExit") HotKeySet("{ESC}", "_ExitScript") _UpdateDesktopIconHighlights() While 1 Sleep(100) WEnd Func _ExitScript() Exit EndFunc ;==>_ExitScript Func _OnExit() If $g_hHook Then DllCall("user32.dll", "bool", "UnhookWinEvent", "handle", $g_hHook) If $g_hEventCallback Then DllCallbackFree($g_hEventCallback) _ClearBorderGUIs() EndFunc ;==>_OnExit Func _SetWinEventHook() ; Retrieve Process ID and Thread ID of Desktop Explorer Local $iPID = 0, $iThreadID = _WinAPI_GetWindowThreadProcessId($g_hWndLV, $iPID) ; Register C-style callback for WinEvents $g_hEventCallback = DllCallbackRegister("_WinEventProc", "none", "ptr;uint;hwnd;long;long;dword;dword") $g_pEventCallback = DllCallbackGetPtr($g_hEventCallback) ; Install WinEventHook targeting Explorer process Local $aHookCall = DllCall("user32.dll", "handle", "SetWinEventHook", _ "uint", $EVENT_OBJECT_SELECTION, _ "uint", $EVENT_OBJECT_LOCATIONCHANGE, _ "ptr", 0, _ "ptr", $g_pEventCallback, _ "dword", $iPID, _ "dword", $iThreadID, _ "uint", $WINEVENT_OUTOFCONTEXT) Return $aHookCall[0] EndFunc ;==>_SetWinEventHook Func _WinEventProc($hWinEventHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iEventThread, $iEventTime) #forceref $hWinEventHook, $iEvent, $hWnd, $iObjectID, $iChildID, $iEventThread, $iEventTime _UpdateDesktopIconHighlights() EndFunc ;==>_WinEventProc Func _UpdateDesktopIconHighlights() Local $iCount = _GUICtrlListView_GetItemCount($g_hWndLV) If $iCount = 0 Then Return Local $sCurrentState = "" Local $aSelectedIndices[1] = [0] For $i = 0 To $iCount - 1 If _GUICtrlListView_GetItemSelected($g_hWndLV, $i) Then $aSelectedIndices[0] += 1 ReDim $aSelectedIndices[$aSelectedIndices[0] + 1] $aSelectedIndices[$aSelectedIndices[0]] = $i $sCurrentState &= $i & "|" EndIf Next If $sCurrentState == $g_sLastSelectedState Then Return $g_sLastSelectedState = $sCurrentState _ClearBorderGUIs() If $aSelectedIndices[0] = 0 Then Return ReDim $g_aBorderGUIs[$aSelectedIndices[0] + 1] $g_aBorderGUIs[0] = $aSelectedIndices[0] ; Retrieve Desktop DPI scale factor ;~ Local $fDPIScale = _GetWindowDPIScale($g_hWndLV) Local $fDPIScale = _WinAPI_GetDpiForMonitor_FromMousePos() Local $iX, $iY, $iW, $iH, $iBaseBorderThickness = 2 Local $iScaledThickness = Ceiling($iBaseBorderThickness * $fDPIScale) Local $aRect, $hBorderGUI For $k = 1 To $aSelectedIndices[0] #cs ; Highlight ONLY the icon graphic (1 = $LVIR_ICON) $aRect = _GUICtrlListView_GetItemRect($g_hWndLV, $aSelectedIndices[$k], 1) ; Highlight ONLY the text label (2 = $LVIR_LABEL) $aRect = _GUICtrlListView_GetItemRect($g_hWndLV, $aSelectedIndices[$k], 2) ; Highlight full item - icon + text combined (0 = $LVIR_BOUNDS - Default) $aRect = _GUICtrlListView_GetItemRect($g_hWndLV, $aSelectedIndices[$k], 0) This is useful if you want a subtle highlight around just the desktop shortcut image itself rather than extending all the way down around long multi-line file names #ce $aRect = _GUICtrlListView_GetItemRect($g_hWndLV, $aSelectedIndices[$k]) $iX = $aRect[0] $iY = $aRect[1] $iW = $aRect[2] - $aRect[0] $iH = $aRect[3] - $aRect[1] If $iW > 0 And $iH > 0 Then Switch $g_RoundCorners Case 1, True $hBorderGUI = _CreateBorderOverlay_v2($iX, $iY, $iW, $iH, 0xFF0000, $iScaledThickness, $fDPIScale) Case Else $hBorderGUI = _CreateBorderOverlay_v1($iX, $iY, $iW, $iH, 0xFF0000, $iScaledThickness, $fDPIScale) EndSwitch $g_aBorderGUIs[$k] = $hBorderGUI EndIf Next EndFunc ;==>_UpdateDesktopIconHighlights ; Creates a hollow rounded border overlay with corner rounding. Or use v1 Func _CreateBorderOverlay_v2($iX, $iY, $iW, $iH, $iColor = 0xFF0000, $iThickness = 1, $fDPIScale = 1.0, $iBaseRadius = 4) Local $hGUI = GUICreate("", $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE), BitOR($WS_EX_LAYERED, $WS_EX_TRANSPARENT), $g_hWndLV) GUISetBkColor($iColor, $hGUI) ; Set layered window opacity (255 = 100% opaque) DllCall("user32.dll", "bool", "SetLayeredWindowAttributes", "hwnd", $hGUI, "dword", 0, "byte", 255, "dword", 2) ; Subtle corner radius (3-4px base) eliminates jagged stair-stepping Local $iRadius = Round($iBaseRadius * $fDPIScale, 0) ;~ ToolTip('$fDPIScale: ' & $fDPIScale & @LF & _ ;~ '$iThickness: ' & $iThickness & @LF & _ ;~ '$iRadius: ' & $iRadius & @LF & _ ;~ '') If $iRadius > 0 Then Local $iInnerRadius = ($iRadius > $iThickness) ? ($iRadius - $iThickness) : 0 ; 1. Outer rounded boundary Local $aRgnOuter = DllCall("gdi32.dll", "handle", "CreateRoundRectRgn", "int", 0, "int", 0, "int", $iW + 1, "int", $iH + 1, "int", $iRadius * 2, "int", $iRadius * 2) Local $hRgnOuter = $aRgnOuter[0] ; 2. Inner rounded boundary (inset by $iThickness) Local $aRgnInner = DllCall("gdi32.dll", "handle", "CreateRoundRectRgn", "int", $iThickness, "int", $iThickness, "int", $iW - $iThickness + 1, "int", $iH - $iThickness + 1, "int", $iInnerRadius * 2, "int", $iInnerRadius * 2) Local $hRgnInner = $aRgnInner[0] ; 3. Subtract inner region from outer (3 = RGN_DIFF) DllCall("gdi32.dll", "int", "CombineRgn", "handle", $hRgnOuter, "handle", $hRgnOuter, "handle", $hRgnInner, "int", 3) ; 4. Apply region to window DllCall("user32.dll", "int", "SetWindowRgn", "hwnd", $hGUI, "handle", $hRgnOuter, "bool", True) _WinAPI_DeleteObject($hRgnInner) EndIf _WinAPI_SetParent($hGUI, $g_hWndLV) GUISetState(@SW_SHOWNOACTIVATE, $hGUI) Return $hGUI EndFunc ;==>_CreateBorderOverlay_v2 ; Creates a transparent border GUI scaled to DPI settings Func _CreateBorderOverlay_v1($iX, $iY, $iW, $iH, $iColor = 0xFF0000, $iThickness = 3, $fDPIScale = 1.0) #forceref $fDPIScale Local $hGUI = GUICreate("", $iW, $iH, $iX, $iY, BitOR($WS_CHILD, $WS_VISIBLE), BitOR($WS_EX_LAYERED, $WS_EX_TRANSPARENT), $g_hWndLV) Local $iTransColor = 0x00FF00FF GUISetBkColor($iTransColor, $hGUI) _WinAPI_SetLayeredWindowAttributes($hGUI, $iTransColor, 255, $LWA_COLORKEY) ; Border Edges GUICtrlCreateLabel("", 0, 0, $iW, $iThickness) GUICtrlSetBkColor(-1, $iColor) GUICtrlCreateLabel("", 0, $iH - $iThickness, $iW, $iThickness) GUICtrlSetBkColor(-1, $iColor) GUICtrlCreateLabel("", 0, 0, $iThickness, $iH) GUICtrlSetBkColor(-1, $iColor) GUICtrlCreateLabel("", $iW - $iThickness, 0, $iThickness, $iH) GUICtrlSetBkColor(-1, $iColor) _WinAPI_SetParent($hGUI, $g_hWndLV) GUISetState(@SW_SHOWNOACTIVATE, $hGUI) Return $hGUI EndFunc ;==>_CreateBorderOverlay_v1 Func _ClearBorderGUIs() If $g_aBorderGUIs[0] > 0 Then For $i = 1 To $g_aBorderGUIs[0] If IsHWnd($g_aBorderGUIs[$i]) Then GUIDelete($g_aBorderGUIs[$i]) Next $g_aBorderGUIs[0] = 0 EndIf EndFunc ;==>_ClearBorderGUIs ;~ ; Calculates screen DPI scaling ratio (100% = 1.0, 225% = 2.25) ;~ Func _GetWindowDPIScale($hWnd) ;~ Local $aRet = DllCall("User32.dll", "uint", "GetDpiForWindow", "hwnd", $hWnd) ;~ If Not @error And $aRet[0] > 0 Then Return $aRet[0] / 96.0 ;~ ; Fallback for Windows builds without GetDpiForWindow ;~ Local $hDC = _WinAPI_GetDC($hWnd) ;~ Local $iDPI = _WinAPI_GetDeviceCaps($hDC, 88) ; LOGPIXELSX = 88 ;~ _WinAPI_ReleaseDC($hWnd, $hDC) ;~ Return Round((($iDPI > 0) ? ($iDPI / 96.0) : 1.0), 0) ;~ EndFunc ;==>_GetWindowDPIScale ; Sets Per-Monitor V2 DPI awareness context (-4 = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) Func _EnableDPIAwareness() DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "ptr", -4) EndFunc ;==>_EnableDPIAwareness Func _GetDesktopListViewHandle() Local $hDesktop = WinGetHandle('[CLASS:Progman]') ; https://www.autoitscript.com/forum/topic/139260-autoit-snippets/page/29/#comment-1554812 Local $hLV = ControlGetHandle($hDesktop, '', '[CLASS:SysListView32;Instance:1]') If Not $hLV Then Local $hWorkerW = _WinAPI_FindWindowEx(0, 0, 'WorkerW', '') While $hWorkerW $hLV = ControlGetHandle($hWorkerW, '', '[CLASS:SysListView32;Instance:1]') If $hLV Then ExitLoop $hWorkerW = _WinAPI_FindWindowEx(0, $hWorkerW, 'WorkerW', '') WEnd EndIf Return $hLV EndFunc ;==>_GetDesktopListViewHandle Func _WinAPI_FindWindowEx($hWndParent, $hWndChildAfter, $sClass = '', $sWindow = '') Local $sTypeClass = ($sClass = '' Or $sClass = 0) ? 'ptr' : 'wstr' Local $vClass = ($sTypeClass = 'ptr') ? 0 : $sClass Local $sTypeWindow = ($sWindow = '' Or $sWindow = 0) ? 'ptr' : 'wstr' Local $vWindow = ($sTypeWindow = 'ptr') ? 0 : $sWindow Local $aRet = DllCall('user32.dll', 'hwnd', 'FindWindowExW', _ 'hwnd', $hWndParent, 'hwnd', $hWndChildAfter, _ $sTypeClass, $vClass, $sTypeWindow, $vWindow) If @error Then Return SetError(@error, @extended, 0) Return $aRet[0] EndFunc ;==>_WinAPI_FindWindowEx Func _WinAPI_GetDpiForMonitor_FromMousePos() Local $tPos = _WinAPI_GetMousePos() Local $hMonitor = _WinAPI_MonitorFromPoint($tPos) Local $aDPI = _WinAPI_GetDpiForMonitor($hMonitor) Return $aDPI[0] / 96 EndFunc ;==>_WinAPI_GetDpiForMonitor_FromMousePos Func _WinAPI_GetDpiForMonitor($hMonitor, $dpiType = 0) Local $X, $Y, $aDPI[2] = [96, 96] ; https://www.autoitscript.com/forum/topic/205087-pixelgetcolor-return-value-is-not-correct-when-xy-reported-by-au3info-moved/#comment-1474583 Local $aRet = DllCall("Shcore.dll", "long", "GetDpiForMonitor", "long", $hMonitor, "int", $dpiType, "uint*", $X, "uint*", $Y) If @error Or Not IsArray($aRet) Then Return SetError(1, 0, $aDPI) Dim $aDPI[2] = [$aRet[3], $aRet[4]] Return $aDPI EndFunc ;==>_WinAPI_GetDpiForMonitor ..example only. You'd make a tray icon and menus, etc. Edited September 30 by argumentum added rounded corners donnyh13 and TheDcoder 2 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 2 Author Posted October 2 (edited) Problem This forum has a limited set of formatting. What can I do. Solution Write it elsewhere and paste the preview here. Out of the top of my head you can use https://html5-editor.net/ or https://html-online.com/html-editor/ or even https://www.w3schools.com/html/ Spoiler Welcome To The Best Online HTML Web Editor! You can type your text directly in the editor or paste it from a Word Doc, PDF, Excel etc. The visual editor on the right and the source editor on the left are linked together and the changes are reflected in the other one as you type! Name City Age John Chicago 23 Lucy Wisconsin 19 Amanda Madison 22 This is a table you can experiment with. ..be creative Edited October 2 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 6 Author Posted October 6 (edited) Problem I code something looking like Global $thisThing = "ok" ; yes, important Global $thisOtherThing = 2 ; also important run tidy and Global $thisThing = "ok" ; yes, important Global $thisOtherThing = 2 ; also important And I love tidy but ... I'd like to keep those alignments as such Solution Run the tidy up script on this "au3align.au3" and it'll format AutoIt source code and align assignment operators and inline comments for you. Spoiler expandcollapse popup#include-once #NoTrayIcon #NoComplainIfYouDontLikeIt ; 😜 #Region ; **** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64 = y #AutoIt3Wrapper_AU3Check_Parameters = -q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ; **** Directives created by AutoIt3Wrapper_GUI **** #include <File.au3> ; #INDEX# ======================================================================================================================= ; Title .........: Au3Align ; AutoIt Version : 3.3.14.5+ ; Language ......: English ; Description ...: Formats AutoIt source code by aligning assignment operators and inline comments. ; Author(s) .....: argumentum ; =============================================================================================================================== Global Const $g_au3align_VERSION = "2026.10.08" ; #CURRENT# ===================================================================================================================== ; _au3align_Version ; _au3align_CmdLine ; _au3align_align ; _au3align_BackupSourceFile ; =============================================================================================================================== ; #INTERNAL_USE_ONLY# =========================================================================================================== ; __au3align_FlushAssignBlock ; __au3align_ParseAssignmentLine ; __au3align_FormatTokens ; __au3align_IsBlockCommentStart ; __au3align_IsBlockCommentEnd ; __au3align_GetLineEnding ; =============================================================================================================================== ; #FUNCTION# ==================================================================================================================== ; Name...........: _au3align_CmdLine ; Description ...: Main entry point when executed via command line parameters or standalone. ; Syntax.........: _au3align_CmdLine() ; Parameters ....: None ; Return values .: None ; Author ........: argumentum ; Remarks .......: Aligns file specified in $CmdLine[1] or prints formatted current script to console if run manually. ; Related .......: _au3align_align ; =============================================================================================================================== _au3align_CmdLine() Func _au3align_CmdLine() Local $sSource If $CmdLine[0] > 0 Then Local $sFilePath = $CmdLine[1] If FileExists($sFilePath) Then Local $hTimer = TimerInit() ConsoleWrite('- au3align start >' & $CmdLine[1] & '<' & @CRLF) ; Create backup prior to alignment modification ; added on v2026.10.08 Local $sBackup = _au3align_BackupSourceFile($sFilePath) If @error Then ConsoleWrite("! Backup failed with @error = " & @error & @CRLF) ConsoleWrite('! au3align aborted (' & Round(TimerDiff($hTimer), 4) & ' ms.)' & @CRLF) Return SetError(4, 0, 4) Else ConsoleWrite("+ Backup created: " & $sBackup & @CRLF) EndIf Local $iFileGetEncoding = FileGetEncoding($sSource) $iFileGetEncoding = ($iFileGetEncoding = -1 ? 0 : $iFileGetEncoding) $sSource = FileRead($sFilePath) Local $sFormatted = _au3align_align($sSource) Local $hFile = FileOpen($sFilePath, 2 + $iFileGetEncoding) ; 2 = Overwrite mode + FileGetEncoding FileWrite($hFile, $sFormatted) FileClose($hFile) Local $hWnd = WinGetHandle("[CLASS:SciTEWindow]") ; reload file trigger for SciTE4AutoIt3 If $hWnd Then ControlSend($hWnd, "", "Scintilla1", "^r") ; ..then again, is all I use. ; added on v2026.10.08 ConsoleWrite('- au3align finished (' & Round(TimerDiff($hTimer), 4) & ' ms.)' & @CRLF) EndIf Else ; Standalone testing mode if run manually $sSource = FileRead(@ScriptFullPath) ConsoleWrite(_au3align_align($sSource)) EndIf EndFunc ; ==>_au3align_CmdLine ; #FUNCTION# ==================================================================================================================== ; Name...........: _au3align_align ; Description ...: Formats AutoIt source code and aligns assignment operators and inline comments. ; Syntax.........: _au3align_align(Const $sAu3Source) ; Parameters ....: $sAu3Source - Const string containing raw AutoIt source code. ; Return values .: Success - Aligned and formatted AutoIt source string. ; Author ........: argumentum ; Related .......: __au3align_FlushAssignBlock, __au3align_ParseAssignmentLine ; =============================================================================================================================== Func _au3align_align(Const $sAu3Source) Local $sCleanSource = StringReplace($sAu3Source, @CRLF, @LF) $sCleanSource = StringReplace($sCleanSource, @CR, @LF) Local $aLines = StringSplit($sCleanSource, @LF) Local $sFormatted = "" Local $bInBlockComment = False ; Assignment block buffers Local $aBlock_Indent[1000] Local $aBlock_LHS[1000] Local $aBlock_Op[1000] Local $aBlock_RHS[1000] Local $aBlock_Comment[1000] Local $iBlockCount = 0 Local $iMaxLHSLen = 0 For $k = 1 To $aLines[0] Local $sLine = $aLines[$k] ; 1. Handle Multiline Comments (#cs / #comments-start) If $bInBlockComment Then __au3align_FlushAssignBlock($sFormatted, $aBlock_Indent, $aBlock_LHS, $aBlock_Op, $aBlock_RHS, $aBlock_Comment, $iBlockCount, $iMaxLHSLen) $sFormatted &= $sLine & __au3align_GetLineEnding($k, $aLines[0]) If __au3align_IsBlockCommentEnd($sLine) Then $bInBlockComment = False ContinueLoop EndIf If __au3align_IsBlockCommentStart($sLine) Then __au3align_FlushAssignBlock($sFormatted, $aBlock_Indent, $aBlock_LHS, $aBlock_Op, $aBlock_RHS, $aBlock_Comment, $iBlockCount, $iMaxLHSLen) $bInBlockComment = True $sFormatted &= $sLine & __au3align_GetLineEnding($k, $aLines[0]) ContinueLoop EndIf Local $sTrimmed = StringStripWS($sLine, 3) ; 2. SciTE Toggle Comments (;~) - Pass through completely untouched If StringLeft($sTrimmed, 2) = ";~" Then __au3align_FlushAssignBlock($sFormatted, $aBlock_Indent, $aBlock_LHS, $aBlock_Op, $aBlock_RHS, $aBlock_Comment, $iBlockCount, $iMaxLHSLen) $sFormatted &= $sLine & __au3align_GetLineEnding($k, $aLines[0]) ContinueLoop EndIf ; 3. Standard comment-only or empty lines break assignment blocks and stay untouched If $sTrimmed = "" Or StringLeft($sTrimmed, 1) = ";" Then __au3align_FlushAssignBlock($sFormatted, $aBlock_Indent, $aBlock_LHS, $aBlock_Op, $aBlock_RHS, $aBlock_Comment, $iBlockCount, $iMaxLHSLen) $sFormatted &= $sLine & __au3align_GetLineEnding($k, $aLines[0]) ContinueLoop EndIf ; 4. Check for Assignment Line ($LHS = $RHS ; $Comment) Local $sIndent = "", $sLHS = "", $sOp = "", $sRHS = "", $sComment = "" If __au3align_ParseAssignmentLine($sLine, $sIndent, $sLHS, $sOp, $sRHS, $sComment) Then ; Flush block if indentation level changes If $iBlockCount > 0 And $aBlock_Indent[0] <> $sIndent Then __au3align_FlushAssignBlock($sFormatted, $aBlock_Indent, $aBlock_LHS, $aBlock_Op, $aBlock_RHS, $aBlock_Comment, $iBlockCount, $iMaxLHSLen) EndIf $aBlock_Indent[$iBlockCount] = $sIndent ; a comment $aBlock_LHS[$iBlockCount] = $sLHS ; another comment $aBlock_Op[$iBlockCount] = $sOp ; more comments $aBlock_RHS[$iBlockCount] = $sRHS $aBlock_Comment[$iBlockCount] = $sComment ; comment $iBlockCount += 1 Local $iLHSLen = StringLen($sLHS) If $iLHSLen > $iMaxLHSLen Then $iMaxLHSLen = $iLHSLen Else ; Non-assignment line -> Flush assignment block __au3align_FlushAssignBlock($sFormatted, $aBlock_Indent, $aBlock_LHS, $aBlock_Op, $aBlock_RHS, $aBlock_Comment, $iBlockCount, $iMaxLHSLen) ; Directives starting with '#' pass through without token formatting If StringLeft($sTrimmed, 1) = "#" Then $sFormatted &= $sLine & __au3align_GetLineEnding($k, $aLines[0]) Else $sFormatted &= __au3align_FormatTokens($sLine) & __au3align_GetLineEnding($k, $aLines[0]) EndIf EndIf Next __au3align_FlushAssignBlock($sFormatted, $aBlock_Indent, $aBlock_LHS, $aBlock_Op, $aBlock_RHS, $aBlock_Comment, $iBlockCount, $iMaxLHSLen) Return $sFormatted EndFunc ; ==>_au3align_align ; #FUNCTION# ==================================================================================================================== ; Name...........: _au3align_BackupSourceFile ; Description ...: Creates a numbered backup (_oldN.au3) in a 'BackUp' subfolder relative to the source file. ; Syntax.........: _au3align_BackupSourceFile($sFilePath) ; Parameters ....: $sFilePath - Full path to the source file to back up. ; Return values .: Success - Returns the full path of the newly created backup file. ; Failure - Returns "" and sets @error: ; |1 - Source file does not exist. ; |2 - Failed to create 'BackUp' directory. ; |3 - FileCopy failed. ; Author ........: argumentum ; =============================================================================================================================== Func _au3align_BackupSourceFile($sFilePath) If Not FileExists($sFilePath) Then Return SetError(1, 0, "") ; Split path into drive, directory, filename, and extension Local $sDrive = "", $sDir = "", $sFileName = "", $sExt = "" _PathSplit($sFilePath, $sDrive, $sDir, $sFileName, $sExt) ; Target backup directory relative to the source file Local $sBackupDir = $sDrive & $sDir & "BackUp" ; Ensure BackUp directory exists If Not FileExists($sBackupDir) Then If Not DirCreate($sBackupDir) Then Return SetError(2, 0, "") EndIf ; Find the next available _oldN sequence index Local $iIndex = 0 Local $sBackupPath = "" Do $iIndex += 1 $sBackupPath = $sBackupDir & "\" & $sFileName & "_old" & $iIndex & $sExt Until Not FileExists($sBackupPath) If FileCopy($sFilePath, $sBackupPath, 0) Then Return $sBackupPath EndIf Return SetError(3, 0, "") EndFunc ; ==>_au3align_BackupSourceFile ; #FUNCTION# ==================================================================================================================== ; Name...........: _au3align_Version ; Description ...: Returns the current version string of Au3Align. ; Syntax.........: _au3align_Version() ; Parameters ....: None ; Return values .: String containing current version. ; Author ........: argumentum ; Related .......: _au3align_CmdLine ; =============================================================================================================================== Func _au3align_Version() Return $g_au3align_VERSION EndFunc ; ==>_au3align_Version ; #INTERNAL_FUNCTION# ==================================================================================================== ; Name...........: __au3align_FlushAssignBlock ; Description ...: Flushes buffered assignment statements and aligns their operators and comments. ; Syntax.........: __au3align_FlushAssignBlock(ByRef $sOut, ByRef $aIndent, ByRef $aLHS, ByRef $aOp, ByRef $aRHS, ByRef $aComment, ByRef $iCount, ByRef $iMaxLen) ; Parameters ....: $sOut - ByRef string to append formatted lines to. ; $aIndent - ByRef array of line indentation strings. ; $aLHS - ByRef array of left-hand side expressions. ; $aOp - ByRef array of assignment operators. ; $aRHS - ByRef array of right-hand side expressions. ; $aComment - ByRef array of inline comments. ; $iCount - ByRef integer count of stored statements. ; $iMaxLen - ByRef integer tracking max LHS length. ; Return values .: None ; Author ........: argumentum ; Remarks .......: Resets $iCount and $iMaxLen to 0 upon completion. ; =============================================================================================================================== Func __au3align_FlushAssignBlock(ByRef $sOut, ByRef $aIndent, ByRef $aLHS, ByRef $aOp, ByRef $aRHS, ByRef $aComment, ByRef $iCount, ByRef $iMaxLen) If $iCount = 0 Then Return Local $sCodeLine, $aCodeParts[$iCount] Local $iMaxCodeLen = 0 ; Pass 1: Align LHS / Op / RHS and compute maximum code length for comment positioning For $idx = 0 To $iCount - 1 Local $sL = $aLHS[$idx] Local $sR = $aRHS[$idx] Local $sOp = $aOp[$idx] Local $sInd = $aIndent[$idx] Local $iPad = $iMaxLen - StringLen($sL) Local $sPad = "" For $p = 1 To $iPad $sPad &= " " Next $sCodeLine = "" If $sR <> "" Then $sCodeLine = $sInd & $sL & $sPad & " " & $sOp & " " & $sR Else $sCodeLine = $sInd & $sL & $sPad & " " & $sOp EndIf $aCodeParts[$idx] = $sCodeLine If $aComment[$idx] <> "" Then Local $iCodeLen = StringLen($sCodeLine) If $iCodeLen > $iMaxCodeLen Then $iMaxCodeLen = $iCodeLen EndIf Next ; Pass 2: Append comments aligned to the maximum code length column For $idx = 0 To $iCount - 1 $sCodeLine = $aCodeParts[$idx] Local $sCmt = $aComment[$idx] If $sCmt <> "" Then Local $iPadComment = $iMaxCodeLen - StringLen($sCodeLine) Local $sCommentPad = "" For $p = 1 To $iPadComment $sCommentPad &= " " Next $sOut &= $sCodeLine & $sCommentPad & " " & $sCmt & @CRLF Else $sOut &= $sCodeLine & @CRLF EndIf Next $iCount = 0 $iMaxLen = 0 EndFunc ; ==>__au3align_FlushAssignBlock ; #INTERNAL_FUNCTION# ==================================================================================================== ; Name...........: __au3align_ParseAssignmentLine ; Description ...: Parses a line to determine if it is a valid assignment statement and extracts components. ; Syntax.........: __au3align_ParseAssignmentLine($sLine, ByRef $sIndent, ByRef $sLHS, ByRef $sOp, ByRef $sRHS, ByRef $sComment) ; Parameters ....: $sLine - Raw source line string. ; $sIndent - ByRef string receiving indentation. ; $sLHS - ByRef string receiving formatted left-hand side. ; $sOp - ByRef string receiving assignment operator. ; $sRHS - ByRef string receiving formatted right-hand side. ; $sComment - ByRef string receiving inline comment. ; Return values .: True if line is a valid top-level assignment or contains comment, False otherwise. ; Author ........: AutoIt Community ; =============================================================================================================================== Func __au3align_ParseAssignmentLine($sLine, ByRef $sIndent, ByRef $sLHS, ByRef $sOp, ByRef $sRHS, ByRef $sComment) Local $c, $iLen = StringLen($sLine) Local $iNonWS = 1 While $iNonWS <= $iLen And (StringMid($sLine, $iNonWS, 1) = " " Or StringMid($sLine, $iNonWS, 1) = @TAB) $iNonWS += 1 WEnd $sIndent = StringLeft($sLine, $iNonWS - 1) Local $sTrimmed = StringMid($sLine, $iNonWS) ; Ignore lines starting with control-flow keywords Local $aReserved[21] = ["if", "elseif", "else", "while", "wend", "until", "do", "for", "next", "select", "case", "switch", "endswitch", "return", "func", "endfunc", "with", "endwith", "exitloop", "continueloop", "redim"] Local $sFirstWord = StringLower(StringRegExpReplace($sTrimmed, "[\s\(].*", "")) For $r In $aReserved If $sFirstWord = $r Then Return False Next Local $bInSQ = False, $bInDQ = False Local $iCommentPos = 0 ; Separate code from inline comment (first ';' outside quotes) Local $iTrimLen = StringLen($sTrimmed) For $i = 1 To $iTrimLen $c = StringMid($sTrimmed, $i, 1) If $c = '"' And Not $bInSQ Then $bInDQ = Not $bInDQ ContinueLoop ElseIf $c = "'" And Not $bInDQ Then $bInSQ = Not $bInSQ ContinueLoop EndIf If Not $bInSQ And Not $bInDQ And $c = ";" Then $iCommentPos = $i ExitLoop EndIf Next Local $sCodePart = $sTrimmed $sComment = "" If $iCommentPos > 0 Then $sCodePart = StringLeft($sTrimmed, $iCommentPos - 1) Local $sRawComment = StringMid($sTrimmed, $iCommentPos) $sComment = StringStripWS($sRawComment, 2) ; Preserve exact comment string (including ;~) EndIf Local $bIsDirective = (StringLeft($sTrimmed, 1) = "#") ; --- Check for multi-variable lines (containing top-level commas) --- Local $iParenDepth = 0, $iBracketDepth = 0 Local $iCodeLen = StringLen($sCodePart) Local $bHasTopLevelComma = False $bInSQ = False $bInDQ = False For $i = 1 To $iCodeLen $c = StringMid($sCodePart, $i, 1) If $c = '"' And Not $bInSQ Then $bInDQ = Not $bInDQ ElseIf $c = "'" And Not $bInDQ Then $bInSQ = Not $bInSQ ElseIf Not $bInSQ And Not $bInDQ Then If $c = "(" Then $iParenDepth += 1 ElseIf $c = ")" Then If $iParenDepth > 0 Then $iParenDepth -= 1 ElseIf $c = "[" Then $iBracketDepth += 1 ElseIf $c = "]" Then If $iBracketDepth > 0 Then $iBracketDepth -= 1 ElseIf $iParenDepth = 0 And $iBracketDepth = 0 And $c = "," Then $bHasTopLevelComma = True ExitLoop EndIf EndIf Next ; If multi-variable declaration, skip '=' alignment but keep in block for comment alignment If $bHasTopLevelComma Then If $bIsDirective Then $sLHS = $sCodePart Else $sLHS = __au3align_FormatTokens($sCodePart) EndIf $sOp = "" $sRHS = "" Return True EndIf ; Parse $sCodePart for assignment operator Local $iOpPos = 0, $iOpLen = 1 Local $sFoundOp = "" $iParenDepth = 0 $iBracketDepth = 0 $bInSQ = False $bInDQ = False For $i = 1 To $iCodeLen $c = StringMid($sCodePart, $i, 1) If $c = '"' And Not $bInSQ Then $bInDQ = Not $bInDQ ContinueLoop ElseIf $c = "'" And Not $bInDQ Then $bInSQ = Not $bInSQ ContinueLoop EndIf If $bInSQ Or $bInDQ Then ContinueLoop If $c = "(" Then $iParenDepth += 1 ElseIf $c = ")" Then If $iParenDepth > 0 Then $iParenDepth -= 1 ElseIf $c = "[" Then $iBracketDepth += 1 ElseIf $c = "]" Then If $iBracketDepth > 0 Then $iBracketDepth -= 1 EndIf If $iParenDepth = 0 And $iBracketDepth = 0 Then Local $two = StringMid($sCodePart, $i, 2) If $two = "+=" Or $two = "-=" Or $two = "*=" Or $two = "/=" Or $two = "&=" Or $two = "^=" Then $iOpPos = $i $iOpLen = 2 $sFoundOp = $two ExitLoop ElseIf $two = "==" Or $two = "<=" Or $two = ">=" Or $two = "<>" Then $i += 1 ContinueLoop ElseIf $c = "=" Then $iOpPos = $i $iOpLen = 1 $sFoundOp = "=" ExitLoop EndIf EndIf Next If $iOpPos = 0 Then Return False If $bIsDirective Then $sLHS = StringStripWS(StringLeft($sCodePart, $iOpPos - 1), 3) $sOp = $sFoundOp $sRHS = StringStripWS(StringMid($sCodePart, $iOpPos + $iOpLen), 3) Else $sLHS = __au3align_FormatTokens(StringStripWS(StringLeft($sCodePart, $iOpPos - 1), 3)) $sOp = $sFoundOp $sRHS = __au3align_FormatTokens(StringStripWS(StringMid($sCodePart, $iOpPos + $iOpLen), 3)) EndIf Return True EndFunc ; ==>__au3align_ParseAssignmentLine ; #INTERNAL_FUNCTION# ==================================================================================================== ; Name...........: __au3align_FormatTokens ; Description ...: Formats expression tokens with standardized spacing around operators, commas, and comments. ; Syntax.........: __au3align_FormatTokens($sCode) ; Parameters ....: $sCode - Raw expression code string. ; Return values .: Formatted expression string. ; Author ........: argumentum ; =============================================================================================================================== Func __au3align_FormatTokens($sCode) If $sCode = "" Then Return "" Local $sPrev, $iLen = StringLen($sCode) Local $sOut = "" Local $bInSQ = False, $bInDQ = False Local $i = 1 While $i <= $iLen Local $c = StringMid($sCode, $i, 1) If $c = '"' And Not $bInSQ Then $bInDQ = Not $bInDQ $sOut &= $c $i += 1 ContinueLoop ElseIf $c = "'" And Not $bInDQ Then $bInSQ = Not $bInSQ $sOut &= $c $i += 1 ContinueLoop EndIf If $bInSQ Or $bInDQ Then $sOut &= $c $i += 1 ContinueLoop EndIf If $c = ";" Then ; If inline comment starts with ;~, keep it intact If StringMid($sCode, $i, 2) = ";~" Then $sOut &= StringMid($sCode, $i) ExitLoop EndIf $sPrev = StringRight($sOut, 1) If $sPrev <> "" And $sPrev <> " " And $sPrev <> @TAB Then $sOut &= " " $sOut &= ";" $i += 1 While $i <= $iLen And StringMid($sCode, $i, 1) = " " $i += 1 WEnd If $i <= $iLen Then $sOut &= " " While $i <= $iLen $sOut &= StringMid($sCode, $i, 1) $i += 1 WEnd ExitLoop EndIf If $c = "," Then While StringRight($sOut, 1) = " " $sOut = StringTrimRight($sOut, 1) WEnd $sOut &= ", " $i += 1 While $i <= $iLen And StringMid($sCode, $i, 1) = " " $i += 1 WEnd ContinueLoop EndIf If StringInStr("+-*/^&?:", $c) > 0 Then Local $two = StringMid($sCode, $i, 2) If $two = "==" Or $two = "<=" Or $two = ">=" Or $two = "<>" Or _ $two = "+=" Or $two = "-=" Or $two = "*=" Or $two = "/=" Or $two = "&=" Or $two = "^=" Then $sPrev = StringRight($sOut, 1) If $sPrev <> "" And $sPrev <> " " And $sPrev <> "(" And $sPrev <> "[" Then $sOut &= " " $sOut &= $two & " " $i += 2 While $i <= $iLen And StringMid($sCode, $i, 1) = " " $i += 1 WEnd ContinueLoop EndIf Local $bIsUnary = False If $c = "-" Or $c = "+" Then Local $sTrimmedPrev = StringStripWS($sOut, 2) Local $sLast = StringRight($sTrimmedPrev, 1) If $sLast = "" Or StringInStr("(=+-*/^&<>,:?[", $sLast) > 0 Then $bIsUnary = True Else Local $sLastWord = StringLower(StringRegExpReplace($sTrimmedPrev, "^.*?\b(\w+)$", "$1")) If StringInStr("|return|to|step|and|or|not|then|else|case|with|in|by|", "|" & $sLastWord & "|") > 0 Then $bIsUnary = True EndIf EndIf EndIf If $bIsUnary Then $sOut &= $c $i += 1 ContinueLoop EndIf $sPrev = StringRight($sOut, 1) If $sPrev <> "" And $sPrev <> " " Then $sOut &= " " $sOut &= $c & " " $i += 1 While $i <= $iLen And StringMid($sCode, $i, 1) = " " $i += 1 WEnd ContinueLoop EndIf If $c = "(" Or $c = "[" Then $sOut &= $c $i += 1 While $i <= $iLen And StringMid($sCode, $i, 1) = " " $i += 1 WEnd ContinueLoop ElseIf $c = ")" Or $c = "]" Then While StringRight($sOut, 1) = " " $sOut = StringTrimRight($sOut, 1) WEnd $sOut &= $c $i += 1 ContinueLoop EndIf If $c = " " Then If StringRight($sOut, 1) <> " " And StringRight($sOut, 1) <> "" Then $sOut &= " " EndIf $i += 1 ContinueLoop EndIf $sOut &= $c $i += 1 WEnd Return $sOut EndFunc ; ==>__au3align_FormatTokens ; #INTERNAL_FUNCTION# ==================================================================================================== ; Name...........: __au3align_IsBlockCommentStart ; Description ...: Checks if a line initiates a multi-line block comment (#cs / #comments-start). ; Syntax.........: __au3align_IsBlockCommentStart($sLine) ; Parameters ....: $sLine - Line string to evaluate. ; Return values .: True if line starts a block comment, False otherwise. ; Author ........: argumentum ; =============================================================================================================================== Func __au3align_IsBlockCommentStart($sLine) Local $sT = StringStripWS($sLine, 3) Return (StringLeft($sT, 3) = "#cs" Or StringLeft($sT, 15) = "#comments-start") EndFunc ; ==>__au3align_IsBlockCommentStart ; #INTERNAL_FUNCTION# ==================================================================================================== ; Name...........: __au3align_IsBlockCommentEnd ; Description ...: Checks if a line terminates a multi-line block comment (#ce / #comments-end). ; Syntax.........: __au3align_IsBlockCommentEnd($sLine) ; Parameters ....: $sLine - Line string to evaluate. ; Return values .: True if line ends a block comment, False otherwise. ; Author ........: argumentum ; =============================================================================================================================== Func __au3align_IsBlockCommentEnd($sLine) Local $sT = StringStripWS($sLine, 3) Return (StringLeft($sT, 3) = "#ce" Or StringLeft($sT, 13) = "#comments-end") EndFunc ; ==>__au3align_IsBlockCommentEnd ; #INTERNAL_FUNCTION# ==================================================================================================== ; Name...........: __au3align_GetLineEnding ; Description ...: Determines line termination character based on current position in total lines. ; Syntax.........: __au3align_GetLineEnding($iCurrentIndex, $iTotalLines) ; Parameters ....: $iCurrentIndex - 1-based index of current line. ; $iTotalLines - Total number of lines. ; Return values .: @CRLF if not on last line, empty string otherwise. ; Author ........: argumentum ; =============================================================================================================================== Func __au3align_GetLineEnding($iCurrentIndex, $iTotalLines) If $iCurrentIndex < $iTotalLines Then Return @CRLF Return "" EndFunc ; ==>__au3align_GetLineEnding ..could also be added to SciTE Spoiler 1.Open SciTEUser.properties:Access your personal SciTE configuration. In SciTE, open your user settings file by navigating to: Options $\rightarrow$ Open SciTEUser.properties (or press Ctrl+Shift+U). 2.Add the Tool Configuration:Define the menu item, path, and shortcut key. Paste the following configuration at the end of your SciTEUser.properties file. Replace C:\Path\To\Au3Align.au3 with the actual full path to where you saved the AutoIt aligner script: Properties # Custom Tool: AutoIt Code Aligner # Use an unused slot number (slots 36–50 are typically free for user tools) command.name.36.$(au3)=Align Code command.36.$(au3)="$(AutoIt3Dir)\AutoIt3.exe" "C:\Path\To\Au3Align.au3" "$(FilePath)" command.shortcut.36.$(au3)=Ctrl+Shift+A command.mode.36.$(au3)=subsystem:4,savebefore:yes 3.Save and Test the Shortcut:Run the tool on an open AutoIt file. Save SciTEUser.properties (Ctrl+S). Open any .au3 script in SciTE. Press Ctrl+Shift+A (or select Tools $\rightarrow$ Align Code from the top menu). SciTE will automatically save the active file, run Au3Align.au3 against it, and reload the newly aligned code on disk. Configuration Breakdown command.name.36.$(au3): Registers the tool under SciTE's Tools menu for .au3 files. command.36.$(au3): Executes AutoIt3.exe using SciTE's internal variable $(AutoIt3Dir), passing the target script path and $(FilePath) as $CmdLine[1]. command.shortcut.36.$(au3): Sets the keybinding (Ctrl+Shift+A). You can change this to any preferred key combination. command.mode.36.$(au3)=subsystem:4,savebefore:yes: Saves open edits to disk prior to running the script so the aligner reads the latest changes. Note: ..testing in SciTE v5.5.6 ( Jun 5 2025 10:01:05 ) the block that worked ( on \AutoIt3\SciTE\Properties\au3.properties ) was: # Custom Tool: AutoIt Code Aligner # Use an unused slot number (slots 36–50 are typically free for user tools) command.36.$(au3)=$(SciteDefaultHome)\..\Autoit3_x64.exe "$(SciteDefaultHome)\Au3Align\Au3Align.au3" "$(FilePath)" command.name.36.$(au3)=Align Code command.subsystem.36.$(au3)=0 command.save.before.36.$(au3)=1 command.shortcut.36.$(au3)=Ctrl+Shift+A so be careful with what you do ..or other tweaks Edited October 8 by argumentum new version "2026.10.08" ioa747 and WildByDesign 2 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 8 Author Posted October 8 (edited) Problem Need to make a function for a small file on disk or clipboard that I can edit in a function, to include/customize said file in the script. Solution Use this code. Ain't much but should be sufficient for common small files . Spoiler ;~ clip2Str2Func() Func clip2Str2Func() ;~ Local $sStr = Str2Func(FileRead( @ScriptFullPath )) Local $sStr = Str2Func(ClipGet()) ConsoleWrite(@CRLF & $sStr & @CRLF) ClipPut($sStr) EndFunc ;==>clip2Str2Func Func Str2Func($sStr) Local $sRet = 'Func _TODO_ChangeFuncName()' & @CRLF & @TAB & 'Local $sStr = "" & @CRLF' & @CRLF Local $aArray = StringSplit($sStr, @CRLF, 1) For $n = 1 To $aArray[0] $sRet &= @TAB & '$sStr &= "' & StringReplace($aArray[$n], '"', '""') & '" & @CRLF' & @CRLF Next $sRet &= @TAB & "Return $sStr" & @CRLF & "EndFunc" & @CRLF Return $sRet EndFunc ;==>Str2Func Edited October 16 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 9 Author Posted October 9 (edited) Problem Am using a GitHub repo as an image holder. But is a pain to do by hand as the count of images in that path increase 😱 Solution Use this code to upload the image and get the "raw" link to use in the forum. Version 1 ( only file upload ) Spoiler expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <Constants.au3> #include <MsgBoxConstants.au3> ; --- CONFIGURATION --- Global Const $sToken = "YOUR_GITHUB_PAT_HERE" ; GitHub Personal Access Token (repo scope) Global Const $sOwner = "YourGitHubUsername" ; Your GitHub username or organization Global Const $sRepo = "YourRepositoryName" ; Your repository name Global Const $sBranch = "main" ; Branch name (main or master) Global Const $sTargetDir = "images/" ; Folder path inside your repo (trailing slash required) ; --------------------- Exit main() Func main() ; 1. Select image file via standard File Open Dialog Local $sFilePath = FileOpenDialog("Select Image to Upload", @ScriptDir, "Images (*.png;*.jpg;*.jpeg;*.gif;*.webp)", $FD_FILEMUSTEXIST) If @error Then Exit ; Extract filename and construct repository path Local $sFileName = StringRegExpReplace($sFilePath, "^.*\\", "") Local $sRepoPath = $sTargetDir & $sFileName ; 2. Read file as binary and encode to Base64 Local $sBase64 = _FileToBase64($sFilePath) If $sBase64 = "" Then MsgBox($MB_SYSTEMMODAL, "Error", "Failed to read or encode the image file.") Exit EndIf ; 3. Construct JSON Payload ; Note: If the file already exists in the repo, the GitHub API requires the existing file's "sha" key ; to update it. For simple write-once uploads, this payload is sufficient. Local $sJson = '{"message": "Upload ' & $sFileName & ' via AutoIt automation", "content": "' & $sBase64 & '", "branch": "' & $sBranch & '"}' ; 4. Send PUT request to GitHub Contents API Local $sUrl = "https://api.github.com/repos/" & $sOwner & "/" & $sRepo & "/contents/" & $sRepoPath Local $oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1") $oHTTP.Open("PUT", $sUrl, False) $oHTTP.SetRequestHeader("Authorization", "Bearer " & $sToken) $oHTTP.SetRequestHeader("Accept", "application/vnd.github+json") $oHTTP.SetRequestHeader("User-Agent", "AutoIt-GitHubUploader") $oHTTP.SetRequestHeader("Content-Type", "application/json") $oHTTP.Send($sJson) ; 5. Handle Response & Copy Raw Link If $oHTTP.Status = 201 Or $oHTTP.Status = 200 Then ; Construct raw content URL Local $sRawUrl = "https://raw.githubusercontent.com/" & $sOwner & "/" & $sRepo & "/" & $sBranch & "/" & $sRepoPath ClipPut($sRawUrl) ConsoleWrite(@CRLF & $sRawUrl & @CRLF & @CRLF) MsgBox($MB_SYSTEMMODAL, "Success!", "Image uploaded successfully!" & @CRLF & @CRLF & "Raw URL copied to clipboard:" & @CRLF & $sRawUrl) Else MsgBox($MB_SYSTEMMODAL, "Upload Failed (HTTP " & $oHTTP.Status & ")", $oHTTP.ResponseText) EndIf EndFunc ;==>main ; --- Helper Function: Base64 Encoding via MSXML --- Func _FileToBase64($sPath) Local $hFile = FileOpen($sPath, $FO_BINARY) If $hFile = -1 Then Return "" Local $bData = FileRead($hFile) FileClose($hFile) Local $oXML = ObjCreate("MSXML2.DOMDocument") If Not IsObj($oXML) Then Return "" Local $oNode = $oXML.createElement("b64") $oNode.dataType = "bin.base64" $oNode.nodeTypedValue = $bData ; Strip all whitespace / line breaks inserted by MSXML Return StringRegExpReplace($oNode.text, "\s+", "") EndFunc v2026.10.09 Version 2 ( If there's an image in the clipboard will upload that, else, will ask to select a file ) Spoiler expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64 = y #AutoIt3Wrapper_AU3Check_Parameters = -q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <Constants.au3> #include <MsgBoxConstants.au3> #include <Clipboard.au3> #include <GDIPlus.au3> #include <WinAPI.au3> ; --- CONFIGURATION --- Global Const $sToken = "YOUR_GITHUB_PAT_HERE" ; GitHub Personal Access Token Global Const $sOwner = "YourGitHubUsername" ; Your GitHub username Global Const $sRepo = "YourRepositoryName" ; Your repository name Global Const $sBranch = "main" ; Branch name (main or master) Global Const $sTargetDir = "images/" ; Folder path inside your repo ; --------------------- Exit main() Func main() ; 1. Check if an image/bitmap is in the clipboard Local $sFileName, $sFilePath = "" _ClipBoard_Open(0) Local $hBitmap = _ClipBoard_GetDataEx($CF_BITMAP) _ClipBoard_Close() If $hBitmap Then ; Extract clipboard bitmap using GDI+ and save to a temporary PNG file _GDIPlus_Startup() Local $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap) $sFileName = "snap_" & @YEAR & @MON & @MDAY & "_" & @HOUR & @MIN & @SEC & ".png" $sFilePath = @TempDir & "\" & $sFileName _GDIPlus_ImageSaveToFile($hImage, $sFilePath) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() _WinAPI_DeleteObject($hBitmap) Else ; Fallback: Open File Dialog if no image is in the clipboard $sFilePath = FileOpenDialog("Select Image to Upload", @ScriptDir, "Images (*.png;*.jpg;*.jpeg;*.gif;*.webp)", $FD_FILEMUSTEXIST) If @error Then Exit $sFileName = StringRegExpReplace($sFilePath, "^.*\\", "") EndIf ; Extract filename and construct repository path $sFileName = StringRegExpReplace($sFilePath, "^.*\\", "") Local $sRepoPath = $sTargetDir & $sFileName ; 2. Read file as binary and encode to Base64 Local $sBase64 = _FileToBase64($sFilePath) If $sBase64 = "" Then MsgBox($MB_SYSTEMMODAL, "Error", "Failed to read or encode the image file.") Exit EndIf ; 3. Construct JSON Payload Local $sJson = '{"message": "Upload ' & $sFileName & ' via AutoIt automation", "content": "' & $sBase64 & '", "branch": "' & $sBranch & '"}' ; 4. Send PUT request to GitHub Contents API Local $sUrl = "https://api.github.com/repos/" & $sOwner & "/" & $sRepo & "/contents/" & $sRepoPath Local $oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1") $oHTTP.Open("PUT", $sUrl, False) $oHTTP.SetRequestHeader("Authorization", "Bearer " & $sToken) $oHTTP.SetRequestHeader("Accept", "application/vnd.github+json") $oHTTP.SetRequestHeader("User-Agent", "AutoIt-GitHubUploader") $oHTTP.SetRequestHeader("Content-Type", "application/json") $oHTTP.Send($sJson) ; 5. Handle Response & Copy Raw Link If $oHTTP.Status = 201 Or $oHTTP.Status = 200 Then Local $sRawUrl = "https://raw.githubusercontent.com/" & $sOwner & "/" & $sRepo & "/" & $sBranch & "/" & $sRepoPath ClipPut($sRawUrl) MsgBox($MB_SYSTEMMODAL, "Success!", "Image uploaded successfully!" & @CRLF & @CRLF & "Raw URL copied to clipboard:" & @CRLF & $sRawUrl) Else MsgBox($MB_SYSTEMMODAL, "Upload Failed (HTTP " & $oHTTP.Status & ")", $oHTTP.ResponseText) EndIf EndFunc ;==>main ; --- Helper Function: Base64 Encoding via MSXML --- Func _FileToBase64($sPath) Local $hFile = FileOpen($sPath, $FO_BINARY) If $hFile = -1 Then Return "" Local $bData = FileRead($hFile) FileClose($hFile) Local $oXML = ObjCreate("MSXML2.DOMDocument") If Not IsObj($oXML) Then Return "" Local $oNode = $oXML.createElement("b64") $oNode.dataType = "bin.base64" $oNode.nodeTypedValue = $bData Return StringRegExpReplace($oNode.text, "\s+", "") EndFunc ;==>_FileToBase64 Version 3 ( same as version 2 but with a preview GUI to accept or cancel the image upload ) ..and an icon for it: Spoiler expandcollapse popup#NoTrayIcon #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64 = y #AutoIt3Wrapper_AU3Check_Parameters = -q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <Constants.au3> #include <MsgBoxConstants.au3> #include <Clipboard.au3> #include <GDIPlus.au3> #include <WinAPI.au3> #include <GUIConstantsEx.au3> #include <SendMessage.au3> ; version 2026.10.11 ; --- CONFIGURATION --- Global Const $g_sToken = "YOUR_GITHUB_PAT_HERE" ; GitHub Personal Access Token Global Const $g_sOwner = "YourGitHubUsername" ; Your GitHub username Global Const $g_sRepo = "YourRepositoryName" ; Your repository name Global Const $g_sBranch = "main" ; Branch name (main or master) Global Const $g_sTargetDir = "images/" & @YEAR & "/" & @MON & "/" ; Folder path inside your repo ; --------------------- Global $g_bComError = False Global $g_oMyError = ObjEvent("AutoIt.Error", "_ComErrorHandler") ; --- PREVIEW WINDOW DIMENSIONS --- Global Const $g_iMaxPreviewW = 640 Global Const $g_iMaxPreviewH = 480 ;~ Exit _Get_AuthenticationTokenExpiration() ; if you don't use it often you can check every so often ( Task Schedule, etc. ) Exit main() Func main() ; https://www.autoitscript.com/forum/topic/213874-solved-help-for-argumentum/#findComment-1555185 ; 1. Check if an image/bitmap is in the clipboard Local $sFilePath = "", $sFileName = "", $sTimestamp = @YEAR & @MON & @MDAY & "_" & @HOUR & @MIN & @SEC _ClipBoard_Open(0) Local $hBitmap = _ClipBoard_GetDataEx($CF_BITMAP) _ClipBoard_Close() If $hBitmap Then ; Extract clipboard bitmap using GDI+ and save to a temporary PNG file _GDIPlus_Startup() Local $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap) $sFileName = "snap_" & $sTimestamp & ".png" $sFilePath = @TempDir & "\" & $sFileName _GDIPlus_ImageSaveToFile($hImage, $sFilePath) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() _WinAPI_DeleteObject($hBitmap) Else ; Fallback: Open File Dialog if no image is in the clipboard $sFilePath = FileOpenDialog("GitHub Image Uploader - Select Image to Upload", "{374DE290-123F-4565-9164-39C4925E467B}", _ "Images (*.png;*.jpg;*.jpeg;*.gif;*.webp;*.ico;*.bmp)", $FD_FILEMUSTEXIST) If @error Then Exit 5 $sFileName = StringRegExpReplace($sFilePath, "^.*\\", "") EndIf ; 2. Show Preview GUI & Ask for Confirmation If Not _ConfirmImageUpload($sFilePath, $sFileName) Then ; Clean up temp file if canceled If StringInStr($sFilePath, @TempDir) And FileExists($sFilePath) Then FileDelete($sFilePath) Exit 4 EndIf ; 3. Construct repository path Local $g_sRepoPath = $g_sTargetDir & $sFileName ; 4. Read file as binary and encode to Base64 Local $sBase64 = _FileToBase64($sFilePath) ; Clean up temp file after reading If StringInStr($sFilePath, @TempDir) And FileExists($sFilePath) Then FileDelete($sFilePath) If $sBase64 = "" Then MsgBox($MB_SYSTEMMODAL, "Error", "Failed to read or encode the image file.", 120) Exit 6 EndIf ; 5. Construct JSON Payload Local $sJson = '{"message": "Upload ' & $sFileName & ' via AutoIt automation", "content": "' & $sBase64 & '", "branch": "' & $g_sBranch & '"}' ; 6. Send PUT request to GitHub Contents API Local $sUrl = "https://api.github.com/repos/" & $g_sOwner & "/" & $g_sRepo & "/contents/" & $g_sRepoPath Local $sExpirationHeader, $oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1") $oHTTP.Open("PUT", $sUrl, False) $oHTTP.SetRequestHeader("Authorization", "Bearer " & $g_sToken) $oHTTP.SetRequestHeader("Accept", "application/vnd.github+json") $oHTTP.SetRequestHeader("User-Agent", "AutoIt-GitHubUploader") $oHTTP.SetRequestHeader("Content-Type", "application/json") $oHTTP.Send($sJson) ; 7. Handle Response & Copy Raw Link If $oHTTP.Status = 201 Or $oHTTP.Status = 200 Then Local $sRawUrl = "https://raw.githubusercontent.com/" & $g_sOwner & "/" & $g_sRepo & "/" & $g_sBranch & "/" & _LocalPathToUrl($g_sRepoPath) ClipPut($sRawUrl) $sExpirationHeader = $oHTTP.GetResponseHeader("GitHub-Authentication-Token-Expiration") FileWriteLine(StringTrimRight(@ScriptFullPath, 4) & ".log", $sTimestamp & ' | ' & $sExpirationHeader & ' | ' & $sFilePath & ' | ' & $sRawUrl & @CRLF) Local $sMsgBox = "Image uploaded successfully!" & @CRLF & @CRLF & "Raw URL copied to clipboard:" & @CRLF & $sRawUrl If $sExpirationHeader <> "" Then $sMsgBox &= @CRLF & @CRLF & 'PAT token expiration:' & @CRLF & $sExpirationHeader & ' (' & _ExpirationInDays($sExpirationHeader) & ' days)' MsgBox($MB_SYSTEMMODAL, "GitHub Image Uploader", $sMsgBox, 120) Else FileWriteLine(StringTrimRight(@ScriptFullPath, 4) & ".log", $sTimestamp & ' | ' & $sExpirationHeader & ' | ' & $sFilePath & ' | ' & "Upload Failed (HTTP " & $oHTTP.Status & ")" & ' | ' & $oHTTP.ResponseText & @CRLF) MsgBox($MB_SYSTEMMODAL, "GitHub Image Uploader", "Upload Failed (HTTP " & $oHTTP.Status & ")" & @CRLF & $oHTTP.ResponseText, 120) EndIf EndFunc ;==>main ; --- GUI Preview Function --- Func _ConfirmImageUpload($sImagePath, $sName, $iMaxWidth = $g_iMaxPreviewW, $iMaxHeight = $g_iMaxPreviewH, $iMinWidth = 300) _GDIPlus_Startup() Local $hImage = _GDIPlus_ImageLoadFromFile($sImagePath) Local $iOriginalW = _GDIPlus_ImageGetWidth($hImage) Local $iOriginalH = _GDIPlus_ImageGetHeight($hImage) ; Calculate aspect ratio Local $fRatio = $iOriginalW / $iOriginalH Local $iNewW = $iOriginalW Local $iNewH = $iOriginalH ; Resize logic: Determine which dimension exceeds limits If $iOriginalW > $iMaxWidth Or $iOriginalH > $iMaxHeight Then If $fRatio > 1 Then ; Wide image $iNewW = $iMaxWidth $iNewH = $iMaxWidth / $fRatio Else ; Tall or square image $iNewH = $iMaxHeight $iNewW = $iMaxHeight * $fRatio EndIf EndIf ; Create scaled HBITMAP in memory Local $hResizedBmp = _GDIPlus_BitmapCreateFromGraphics($iNewW, $iNewH, _GDIPlus_GraphicsCreateFromHWND(0)) Local $hGfx = _GDIPlus_ImageGetGraphicsContext($hResizedBmp) _GDIPlus_GraphicsSetInterpolationMode($hGfx, 7) ; HighQualityBicubic _GDIPlus_GraphicsDrawImageRect($hGfx, $hImage, 0, 0, $iNewW, $iNewH) Local $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hResizedBmp) ; Clean up GDI+ objects _GDIPlus_GraphicsDispose($hGfx) _GDIPlus_BitmapDispose($hResizedBmp) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() ; Create GUI (Centered, slightly larger than max preview for padding) Local $iGuiW = $iNewW + 40 Local $iGuiH = $iNewH + 100 Local $hGUI = GUICreate("GitHub Image Uploader - Confirm Image (Preview)", ($iGuiW < $iMinWidth ? $iMinWidth : $iGuiW), $iGuiH, -1, -1) GUISetIcon(StringTrimRight(@ScriptFullPath, 4) & ".ico") GUISetBkColor(0x333333) ; Create picture control using the scaled HBITMAP Local $idPic = GUICtrlCreatePic("", 20, 20, $iNewW, $iNewH) _SendMessage(GUICtrlGetHandle($idPic), 0x0172, 0, $hHBitmap) ; STM_SETIMAGE _WinAPI_DeleteObject($hHBitmap) $iNewW = ($iNewW < $iMinWidth ? $iMinWidth - 40 : $iNewW) ; UI Elements GUICtrlCreateLabel("File: " & $sName, 20, $iNewH + 30, $iNewW, 20) GUICtrlSetColor(-1, 0xEEEEEE) Local $idBtnCancel = GUICtrlCreateButton("&Cancel", ($iNewW / 2) + 30, $iNewH + 60, ($iNewW / 2) - 5, 35) GUICtrlSetColor(-1, 0xEEEEEE) GUICtrlSetBkColor(-1, 0x222222) Local $idBtnUpload = GUICtrlCreateButton("&Upload to GitHub", 20, $iNewH + 60, ($iNewW / 2) - 5, 35) GUICtrlSetColor(-1, 0xEEEEEE) GUICtrlSetBkColor(-1, 0x222222) GUISetState(@SW_SHOW, $hGUI) Local $bConfirmed = False While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idBtnCancel ExitLoop Case $idBtnUpload $bConfirmed = True ExitLoop EndSwitch WEnd GUIDelete($hGUI) Return $bConfirmed EndFunc ;==>_ConfirmImageUpload ; --- Helper Function: Base64 Encoding via MSXML --- Func _FileToBase64($sPath) Local $hFile = FileOpen($sPath, $FO_BINARY) If $hFile = -1 Then Return "" Local $bData = FileRead($hFile) FileClose($hFile) Local $oXML = ObjCreate("MSXML2.DOMDocument") If Not IsObj($oXML) Then Return "" Local $oNode = $oXML.createElement("b64") $oNode.dataType = "bin.base64" $oNode.nodeTypedValue = $bData Return StringRegExpReplace($oNode.text, "\s+", "") EndFunc ;==>_FileToBase64 ; #FUNCTION# ==================================================================================================== ; Name...........: _Get_AuthenticationTokenExpiration ; Description ...: Checks the expiration date of a GitHub API authentication token. ; Syntax.........: _Get_AuthenticationTokenExpiration([$iSilent = 0]) ; Parameters ....: $iSilent - [optional] Flag to suppress UI message boxes. ; |0 - (Default) Displays modal message boxes for status and errors. ; |1 - Silent mode; suppresses UI, returns expiration string, and sets @extended to calculated days remaining via _ExpirationInDays(). ; Return Value ..: Success - Returns the expiration date string from the header (or "" if non-expiring/classic token). Sets @extended to expiration days (or 0) when $iSilent is 1. ; Failure - Returns "" and sets @error: ; |1 - HTTP error status (HTTP status code stored in @extended). ; |2 - Network connectivity failure or COM error. ; Author ........: argumentum ; Remarks .......: Relies on global variables $g_sToken and $g_bComError. Calls _ExpirationInDays() when running in silent mode. ; =============================================================================================================== Func _Get_AuthenticationTokenExpiration($iSilent = 0) Local $oHTTP = ObjCreate("WinHttp.WinHttpRequest.5.1") $oHTTP.Open("GET", "https://api.github.com/user", False) $oHTTP.SetRequestHeader("Authorization", "Bearer " & $g_sToken) $oHTTP.SetRequestHeader("Accept", "application/vnd.github+json") $oHTTP.SetRequestHeader("User-Agent", "AutoIt-TokenChecker") $oHTTP.Send() If $g_bComError Then If $iSilent Then Return SetError(2, 0, "") MsgBox(16, "GitHub Token Check", "Failed to connect to GitHub (DNS or Network failure).", 120) ElseIf $oHTTP.Status = 200 Then Local $sExpiration = $oHTTP.GetResponseHeader("GitHub-Authentication-Token-Expiration") Local $sDays = ($sExpiration = "" ? "" : _ExpirationInDays($sExpiration) & ' days') ConsoleWrite('>' & $sExpiration & '< ' & $sDays & @CRLF) If $iSilent Then Return SetError(0, Int($sDays), $sExpiration) If $sExpiration <> "" Then MsgBox($MB_SYSTEMMODAL, "GitHub Token Check", "Token is valid!" & @CRLF & @CRLF & "Expiration Date: " & $sExpiration & @CRLF & $sDays, 120) Else MsgBox($MB_SYSTEMMODAL, "GitHub Token Check", "Token is valid, but no expiration header was returned (this can happen with Classic tokens or non-expiring tokens).", 120) EndIf Else If $iSilent Then Return SetError(1, $oHTTP.Status, "") MsgBox($MB_SYSTEMMODAL, "GitHub Token Check Failed (HTTP " & $oHTTP.Status & ")", "Could not verify token. It may have already expired or your network is down.", 120) EndIf EndFunc ;==>_Get_AuthenticationTokenExpiration Func _ExpirationInDays($sExpirationHeader) Return _DateDiff("D", _NowCalc(), $sExpirationHeader) EndFunc ;==>_ExpirationInDays Func _LocalPathToUrl($sFilePath) Local $sUrl = StringReplace($sFilePath, "\", "/") Local $sResult = "" ; Replace Windows backslashes with forward slashes Local $iLen = StringLen($sUrl) For $i = 1 To $iLen Local $sChar = StringMid($sUrl, $i, 1) Local $iAsc = Asc($sChar) If ($iAsc >= 65 And $iAsc <= 90) Or _ ; A-Z ; RFC 3986 unreserved characters (A-Z, a-z, 0-9, -, _, ., ~) ($iAsc >= 97 And $iAsc <= 122) Or _ ; a-z ; Plus URI structural delimiters commonly kept in paths (/ and :) ($iAsc >= 48 And $iAsc <= 57) Or _ ; 0-9 $iAsc = 45 Or $iAsc = 95 Or $iAsc = 46 Or $iAsc = 126 Or _ ; - _ . ~ $iAsc = 47 Or $iAsc = 58 Then ; / : $sResult &= $sChar Else ; Convert special characters and spaces to %XX hex encoding $sResult &= "%" & Hex($iAsc, 2) EndIf Next Return $sResult EndFunc ;==>_LocalPathToUrl ; --- COM Error Handler Function --- Func _ComErrorHandler() $g_bComError = True ; this flag prevents the script from crashing on "oops" EndFunc ;==>_ComErrorHandler update: 2026.10.11 (fixes) To get the GitHub PAT ( Personal Access Token ): Go to Settings > Developer Settings > Personal Access Tokens. Get a "Fine-Grained Token". Set the Repository access to "Only select repositories" and select the repo to use. In Repository permissions > Contents: Set to "Read and write" (this gives the API permission to create and push new image files to your repo). Once you set that, scroll down, click Generate token, and paste the string into the script at YOUR_GITHUB_PAT_HERE. Enjoy Edited October 10 by argumentum update: 2026.10.11 (fixes) ioa747, TheDcoder and TheSaint 3 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 9 Author Posted October 9 (edited) Problem To add a script to the Start menu, I need a shortcut link to my script. Solution Run this script. It'll copy it's own shortcut to the SendTo folder. When you want to make a shortcut for your script, select it and SendTo > "AutoIt3ScriptCreateLink - shortcut" ( or however you name it ) in explorer, and that will create a shortcut to your script and using your icon if the name is the same that of the script. Spoiler #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <WinAPIShellEx.au3> #include <WinAPISys.au3> Exit main() Func main() Local $sAutoItExe = _GetPath(@AutoItExe) & '\autoit3_x64.exe' ; choose the exe Local $sAutoItIcon = _GetPath(@AutoItExe) & '\Icons\au3.ico' ; choose the default icon Local $sIco, $sSelfLnk = StringTrimRight(@ScriptFullPath, 4) & " - Shortcut.lnk" If Not FileGetSize($sSelfLnk) Then FileCreateShortcut($sAutoItExe, $sSelfLnk, "", '/AutoIt3ExecuteScript "' & @ScriptFullPath & '"', "Create AutoIt script shortcuts", $sAutoItIcon) FileCopy($sSelfLnk, _WinAPI_ShellGetKnownFolderPath($FOLDERID_SendTo), 1) ; right click > SendTo > thisScript to create the shortcut for your script EndIf If $CmdLine[0] = 1 Then ; if there's an icon wiht the same name as the script, use that, else, use $sAutoItIcon $sIco = StringTrimRight($CmdLine[1], 4) & ".ico" If Not FileGetSize($sIco) Then $sIco = $sAutoItIcon FileCreateShortcut($sAutoItExe, StringTrimRight($CmdLine[1], 4) & " - Shortcut.lnk", "", '/AutoIt3ExecuteScript "' & $CmdLine[1] & '"', "AutoIt script", $sIco) EndIf EndFunc ;==>main Func _GetPath($sFullpath) Return StringLeft($sFullpath, StringInStr($sFullpath, "\", 0, -1) - 1) EndFunc ;==>_GetPath To "Pin to start" successfully, you'll need to Pin it, then unpin it, then pin it again ( thank you M$ for the bug 🤷♂️ ) Edited October 9 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 10 Author Posted October 10 Problem Each time I download a file I have to "Unblock" the file 💢 Warning Only unblock a file if you completely trust its source. Unblocking malicious files can expose your computer to malware or security breaches ⚠️ Solution Set in registry to leave you alone if you know what you're doing. Spoiler Disable_block_downloaded_files.reg Windows Registry Editor Version 5.00 ; Created by: Shawn Brink ; Created on: May 26th 2017 ; Tutorial: https://www.tenforums.com/tutorials/85418-disable-downloaded-files-being-blocked-windows.html [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Attachments] "SaveZoneInformation"=dword:00000001 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Attachments] "SaveZoneInformation"=dword:00000001 ReEnable_block_downloaded_files.reg Windows Registry Editor Version 5.00 ; Created by: Shawn Brink ; Created on: May 26th 2017 ; Tutorial: https://www.tenforums.com/tutorials/85418-disable-downloaded-files-being-blocked-windows.html [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Attachments] "SaveZoneInformation"=- [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Attachments] "SaveZoneInformation"=- Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 18 Author Posted October 18 (edited) Problem I need to Wake-on-LAN (WoL) a PC Solution Run this script with the MAC of the PC in your network Spoiler expandcollapse popup#cs Title: Wake-on-LAN (WoL) Magic Packet Sender Language: AutoIt v3.3.14+ #ce ;~ Exit WoL_PC("AA:BB:CC:DD:EE:FF") ; <-- your target PC's actual MAC address Func WoL_PC($sTargetMAC) ; detect the local broadcast IP from active physical NICs Local $sBroadcast = _GetActiveBroadcastIP() ;~ $sBroadcast = "255.255.255.255" ; to broadcast everywhere ConsoleWrite("Detected Subnet Broadcast IP: " & $sBroadcast & @CRLF) If _WakeOnLAN($sTargetMAC, $sBroadcast) Then MsgBox(262144 + 64, "Wake-on-LAN", "Magic packet sent to MAC: " & $sTargetMAC & @CRLF & "Broadcast mask used: " & $sBroadcast, 10) Else MsgBox(262144 + 16, "Wake-on-LAN", "Failed to send magic packet." & @CRLF & _ "Error Stage (@error): " & @error & @CRLF & _ "Error Details (@extended): " & @extended, 60) EndIf EndFunc ;==>WoL_PC ; #FUNCTION# ==================================================================================================================== ; Name...........: _GetActiveBroadcastIP ; Description....: Automatically queries active physical NICs, reads IP and Subnet Mask, and computes the broadcast IP. ; =============================================================================================================================== Func _GetActiveBroadcastIP() Local $aAdapters = _GetAdaptersInfo_API() ;~ _DebugArrayDisplay($aAdapters, "$aAdapters") Local $iRows = UBound($aAdapters, 1) If Not $iRows Then Return SetError(1, 0, "255.255.255.255") For $i = 0 To $iRows - 1 ; Look for the adapter flagged as Primary ($sIsMain = 1) If $aAdapters[$i][0] = 1 Then Return _CalculateBroadcast($aAdapters[$i][2], $aAdapters[$i][4]) EndIf Next Return SetError(2, 0, "255.255.255.255") ; fallback. Should work. EndFunc ;==>_GetActiveBroadcastIP ; #FUNCTION# ==================================================================================================================== ; Name...........: _CalculateBroadcast ; Description....: Computes Broadcast IP given an IPv4 address and Subnet Mask. ; =============================================================================================================================== Func _CalculateBroadcast($sIP, $sMask) Local $aIP = StringSplit($sIP, ".") Local $aMask = StringSplit($sMask, ".") If $aIP[0] <> 4 Or $aMask[0] <> 4 Then Return "255.255.255.255" Local $sBroadcast = "", $iSubnetBit, $iIPBit, $iBroadBit For $i = 1 To 4 $iSubnetBit = Number($aMask[$i]) $iIPBit = Number($aIP[$i]) ; Formula: IP OR (NOT SubnetMask restricted to 8-bit byte) $iBroadBit = BitOR($iIPBit, BitAND(BitNOT($iSubnetBit), 0xFF)) $sBroadcast &= $iBroadBit & ($i < 4 ? "." : "") Next Return $sBroadcast EndFunc ;==>_CalculateBroadcast ; #FUNCTION# ==================================================================================================================== ; Name...........: _WakeOnLAN ; Description....: Sends a Wake-on-LAN magic packet via WinSock UDP broadcast. ; =============================================================================================================================== Func _WakeOnLAN($sMacAddress, $sBroadcastIP = "255.255.255.255", $iPort = 9) ; $iPort = 9 ; Standard WoL port (7 or 9) ; any random number realy, and the PC would still wake up just fine, as long as a firewall or router isn't explicitly blocking that port. Local $aErr, $sCleanMAC = StringRegExpReplace($sMacAddress, "[^A-Fa-f0-9]", "") If StringLen($sCleanMAC) <> 12 Then Return SetError(1, StringLen($sCleanMAC), 0) Local $bPacket = Binary("0xFFFFFFFFFFFF") For $i = 1 To 16 $bPacket &= Binary("0x" & $sCleanMAC) Next Local $iPacketLen = BinaryLen($bPacket) Local $tPacket = DllStructCreate("byte[" & $iPacketLen & "]") DllStructSetData($tPacket, 1, $bPacket) Local $tWSAData = DllStructCreate("byte[400]") Local $aRet = DllCall("ws2_32.dll", "int", "WSAStartup", "short", 0x0202, "struct*", $tWSAData) If @error Or $aRet[0] <> 0 Then Return SetError(2, @error, 0) $aRet = DllCall("ws2_32.dll", "handle", "socket", "int", 2, "int", 2, "int", 17) If @error Or $aRet[0] = -1 Then $aErr = DllCall("ws2_32.dll", "int", "WSAGetLastError") DllCall("ws2_32.dll", "int", "WSACleanup") Return SetError(3, $aErr[0], 0) EndIf Local $hSocket = $aRet[0] Local $tOptVal = DllStructCreate("int") DllStructSetData($tOptVal, 1, 1) DllCall("ws2_32.dll", "int", "setsockopt", "handle", $hSocket, "int", 0xFFFF, "int", 0x0020, "struct*", $tOptVal, "int", 4) Local $tSockAddr = DllStructCreate("short;ushort;uint;byte[8]") DllStructSetData($tSockAddr, 1, 2) Local $iNetworkPort = BitOR(BitShift($iPort, -8), BitAND(BitShift($iPort, 8), 0xFF)) DllStructSetData($tSockAddr, 2, $iNetworkPort) $aRet = DllCall("ws2_32.dll", "uint", "inet_addr", "str", $sBroadcastIP) Local $uIP = $aRet[0] DllStructSetData($tSockAddr, 3, $uIP) $aRet = DllCall("ws2_32.dll", "int", "sendto", _ "handle", $hSocket, _ "ptr", DllStructGetPtr($tPacket), _ "int", $iPacketLen, _ "int", 0, _ "ptr", DllStructGetPtr($tSockAddr), _ "int", DllStructGetSize($tSockAddr)) Local $iBytesSent = $aRet[0] Local $iWSAErr = 0 If $iBytesSent = -1 Then $aErr = DllCall("ws2_32.dll", "int", "WSAGetLastError") $iWSAErr = $aErr[0] EndIf DllCall("ws2_32.dll", "int", "closesocket", "handle", $hSocket) DllCall("ws2_32.dll", "int", "WSACleanup") If $iBytesSent = -1 Then Return SetError(4, $iWSAErr, 0) Return 1 EndFunc ;==>_WakeOnLAN Func _GetAdaptersInfo_API() ; Array format: [ [IsMain, Description, IP, Gateway, SubnetMask, MAC] ] Local $aResult[0][6] ; 1. Query Windows for the active Primary Interface Index (routes to 8.8.8.8 because is reliable) Local $iBestInterfaceIndex = _GetBestInterfaceIndex() ; 2. Query required buffer size for GetAdaptersInfo Local $aCall = DllCall("iphlpapi.dll", "ulong", "GetAdaptersInfo", "ptr", 0, "ulong*", 0) If @error Or $aCall[0] <> 111 Then Return $aResult ; 111 = ERROR_BUFFER_OVERFLOW Local $iBufSize = $aCall[2] Local $tBuffer = DllStructCreate("byte[" & $iBufSize & "]") Local $pBuffer = DllStructGetPtr($tBuffer) ; 3. Fetch adapter details $aCall = DllCall("iphlpapi.dll", "ulong", "GetAdaptersInfo", "ptr", $pBuffer, "ulong*", $iBufSize) If @error Or $aCall[0] <> 0 Then Return $aResult ; 0 = ERROR_SUCCESS ; 4. Structure definition including GatewayList (x86 & x64 compliant) Local $sAdapterStruct = "ptr Next; dword ComboIndex; char AdapterName[260]; char Description[132]; " & _ "uint AddressLength; byte Address[8]; dword Index; uint Type; uint DhcpEnabled; " & _ "ptr CurrentIpAddress; " & _ "ptr IpListNext; char IpAddress[16]; char IpMask[16]; dword IpContext; " & _ "ptr GwListNext; char Gateway[16]; char GwMask[16]; dword GwContext" Local $sIpListStruct = "ptr Next; char IpAddress[16]; char IpMask[16]; dword Context" Local $pCurrentAdapter = $pBuffer ; 5. Traverse linked list of adapters While $pCurrentAdapter <> 0 Local $tAdapter = DllStructCreate($sAdapterStruct, $pCurrentAdapter) Local $iAdapterIndex = DllStructGetData($tAdapter, "Index") Local $sDesc = DllStructGetData($tAdapter, "Description") Local $sGateway = DllStructGetData($tAdapter, "Gateway") ; Clean up empty gateway values If $sGateway = "0.0.0.0" Then $sGateway = "" ; "None" ; Check if Windows considers this adapter its main active interface Local $sIsMain = ($iAdapterIndex = $iBestInterfaceIndex) ? 1 : 0 ; Format MAC Address Local $iMacLen = DllStructGetData($tAdapter, "AddressLength") Local $sMAC = "" For $i = 1 To $iMacLen $sMAC &= Hex(DllStructGetData($tAdapter, "Address", $i), 2) If $i < $iMacLen Then $sMAC &= "-" Next ; Parse Primary IP Local $sIP = DllStructGetData($tAdapter, "IpAddress") Local $sMask = DllStructGetData($tAdapter, "IpMask") If $sIP <> "" And $sIP <> "0.0.0.0" Then _AddRow($aResult, $sIsMain, $sDesc, $sIP, $sGateway, $sMask, $sMAC) EndIf ; Parse Additional IPs bound to the same adapter (if any) Local $pNextIP = DllStructGetData($tAdapter, "IpListNext") While $pNextIP <> 0 Local $tIPNode = DllStructCreate($sIpListStruct, $pNextIP) $sIP = DllStructGetData($tIPNode, "IpAddress") $sMask = DllStructGetData($tIPNode, "IpMask") If $sIP <> "" And $sIP <> "0.0.0.0" Then _AddRow($aResult, $sIsMain, $sDesc, $sIP, $sGateway, $sMask, $sMAC) EndIf $pNextIP = DllStructGetData($tIPNode, "Next") WEnd ; Move to next adapter in list $pCurrentAdapter = DllStructGetData($tAdapter, "Next") WEnd Return $aResult EndFunc ;==>_GetAdaptersInfo_API ; Helper function: Asks Windows routing table which Interface Index reaches external IP 8.8.8.8 Func _GetBestInterfaceIndex() ; Google Public DNS (8.8.8.8 and 8.8.4.4) and Cloudflare DNS (1.1.1.1 and 1.0.0.1) are the most reliable and ; widely trusted public DNS resolvers that stay up everywhere with massive global anycast networks. ; 0x08080808 is 8.8.8.8 in DWORD format ; trusting that Google Public DNS is up and accessible. Local $aCall = DllCall("iphlpapi.dll", "dword", "GetBestInterface", "dword", 0x08080808, "dword*", 0) If Not @error And $aCall[0] = 0 Then Return $aCall[2] Return 0 EndFunc ;==>_GetBestInterfaceIndex Func _AddRow(ByRef $aArray, $sIsMain, $sDesc, $sIP, $sGateway, $sMask, $sMAC) Local $iRows = UBound($aArray, 1) ReDim $aArray[$iRows + 1][6] $aArray[$iRows][0] = $sIsMain $aArray[$iRows][1] = $sDesc $aArray[$iRows][2] = $sIP $aArray[$iRows][3] = $sGateway $aArray[$iRows][4] = $sMask $aArray[$iRows][5] = $sMAC EndFunc ;==>_AddRow F.A.Q. Q: Why won't the PC wake up A: Make sure that the BIOS is setup to do so. Also, remove the power savings from the adaptor in case the PC is sleeping, so that the network device get to listen to incoming packets. This "How to enable Wake-on-LAN in Windows" may help too. Edited October 19 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 18 Author Posted October 18 (edited) Problem I used that Wake-on-LAN code but my VMs don't load/start 😤 Solution Code something like this to receive the "Magic Packet" and act on it. This script is made for Hyper-V but you can adapt it to work on any hypervisor. Spoiler expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #RequireAdmin ; Required to interact with Hyper-V WMI objects Opt("TrayAutoPause", 0) ; Keep script running even if tray is clicked Global Const $g_port = 9 ; Standard Wake-on-LAN Port Global Const $g_IPAddr = "0.0.0.0" ; Listen on all network interfaces Global $g_hSocket = 0 Exit Main() Func Main() UDPStartup() $g_hSocket = UDPBind($g_IPAddr, $g_port) If @error Then Exit 5 OnAutoItExitRegister("_Cleanup") Local $sVMName, $sTargetMac, $aData While 1 ; Check for incoming UDP packets (Max size for a WoL packet is 102 bytes) + "password" if any ( old stuff ) $aData = UDPRecv($g_hSocket, 102, 3) ; $aData[1] holds the "IP from" if you care for a white-list security thing If UBound($aData) And $aData[0] <> "" Then ConsoleWrite('-- ' & $aData[0] & @CRLF) ; Parse the packet to see if it contains a valid WoL Magic Packet $sTargetMac = _ParseWoLMagicPacket($aData[0]) ConsoleWrite('- $sTargetMac: ' & $sTargetMac & @CRLF) If $sTargetMac <> "" Then $sVMName = _HyperV_MAC_info($sTargetMac) ; find VM with that MAC ConsoleWrite('- $sTargetMac state: ' & @extended & ', $sVMName: ' & $sVMName & @CRLF) If $sVMName <> "" Then ConsoleWrite('- ' & _HyperV_StartVM($sVMName) & ' (' & @error & ',' & @extended & ')' & @CRLF) EndIf EndIf EndIf Sleep(50) ; Prevent high CPU usage WEnd EndFunc ;==>Main ; ========================================================================================== ; _HyperV_StartVM ; Description: Uses native WMI to command Hyper-V to start a VM by its ElementName GUID ; Note: I use it to start the VM but you can use it to, anything. ; https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/requeststatechange-msvm-plannedcomputersystem ; ========================================================================================== ;~ _HyperV_StartVM("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX") Func _HyperV_StartVM($sVMName, $iRequestStateChange = 2) Local $oWMIService = ObjGet("winmgmts:\\.\root\virtualization\v2") If @error Then Return SetError(1, 0, 0) Local $oVMs = $oWMIService.ExecQuery("SELECT * FROM Msvm_ComputerSystem WHERE Name = '" & $sVMName & "'") If Not IsObj($oVMs) Then Return SetError(2, 0, 0) ; don't ask me why is not ElementName 💢 For $oVM In $oVMs Local $iResult = $oVM.RequestStateChange($iRequestStateChange) ; 2 = Power On If $iResult = 0 Or $iResult = 4096 Then Return 1 Next Return SetError(3, $iResult, 0) EndFunc ;==>_HyperV_StartVM ; ========================================================================================== ; _ParseWoLMagicPacket ; Description: Identifies if hex payload contains a valid WoL layout. ; Returns: Cleaned target MAC string (e.g. "001122334455") or empty string if invalid. ; ========================================================================================== Func _ParseWoLMagicPacket($sHexData) Local $sFound = StringMid($sHexData, 15, 12) If StringInStr($sHexData, $sFound, 0, 16) = 195 Then Return SetError(0, 1, $sFound) Return SetError(0, 0, "") EndFunc ;==>_ParseWoLMagicPacket Func _Cleanup() UDPCloseSocket($g_hSocket) UDPShutdown() EndFunc ;==>_Cleanup ;~ ConsoleWrite('--- FirewallRule: ' & _SetupWindowsFirewallRule() & @CRLF) Func _SetupWindowsFirewallRule($iUDP = 9) If Not IsAdmin() Then Return SetError(1, 0, "Must be admin to run this") Local $sRuleName = "Hyper-V WoL Receiver (UDP " & $iUDP & ")" ; Check if the firewall rule already exists to avoid duplication errors Local $iPID = Run(@ComSpec & ' /c netsh advfirewall firewall show rule name="' & $sRuleName & '"', "", @SW_HIDE, 2) ProcessWaitClose($iPID) Local $sOutput = StdoutRead($iPID) ;~ ConsoleWrite($sOutput & @CRLF) ; debug ; If the rule isn't found, create it using netsh (universally compatible across Windows versions) If StringInStr($sOutput, "no rules match") Or $sOutput == "" Then RunWait(@ComSpec & ' /c netsh advfirewall firewall add rule name="' & $sRuleName & '" dir=in action=allow protocol=UDP localport=' & $iUDP, "", @SW_HIDE) Return SetError(0, 1, "added") EndIf Return SetError(0, 2, "existing") EndFunc ;==>_SetupWindowsFirewallRule ;~ _HyperV_MAC_info() Func _HyperV_MAC_info($sHexMAC = "MAC_or_empty_to_get_the_array") Local $iStateInteger = 0, $sStateName, $sVMName, $sVmElementName Local $iExt, $iErr, $vRet = _HyperV_MAC_infoEx($sHexMAC, $iStateInteger, $sStateName, $sVMName, $sVmElementName) $iExt = @extended $iErr = @error ConsoleWrite('+ $vRet: ' & $vRet & ' (' & $iErr & ',' & $iExt & '), $iStateInteger: ' & $iStateInteger & ', $sStateName: ' & $sStateName & _ ', $sVmName: ' & $sVMName & ', $sVmElementName: ' & $sVmElementName & @CRLF) ;~ If $iExt Then _DebugArrayDisplay($sStateName, "$sStateName ""array""") ; meh, have a list of VMs found Return SetError($iErr, $iStateInteger, $sVmElementName) EndFunc ;==>_HyperV_MAC_info Func _HyperV_MAC_infoEx(ByRef $sHexMAC, ByRef $iStateInteger, ByRef $sStateName, ByRef $sVMName, ByRef $sVmElementName) #forceref $sHexMAC, $iStateInteger, $sStateName, $sVMName, $sVmElementName ;~ Local $hTimer = TimerInit() Local $sPowerState, $oWMIService = ObjGet("winmgmts:\\.\root\virtualization\v2") If @error Then Return SetError(1, 0, 0) Local $oVMs = $oWMIService.ExecQuery("SELECT Name, ElementName, EnabledState FROM Msvm_ComputerSystem WHERE Caption = 'Virtual Machine'") If Not IsObj($oVMs) Then Return SetError(2, 0, 0) Local $mVmName[], $mStateInteger[], $mStateName[], $aRet[1][5] = [[0]] For $oVM In $oVMs ;~ ConsoleWrite('-- $oVM.Name: ' & $oVM.Name & ' - $oVM.ElementName: ' & $oVM.ElementName & @CRLF) ; debug $mVmName[$oVM.Name] = $oVM.ElementName $mStateInteger[$oVM.Name] = $oVM.EnabledState Switch $oVM.EnabledState Case 2 $sPowerState = "ON" Case 3 $sPowerState = "OFF" Case 6 $sPowerState = "SAVED" Case 9 $sPowerState = "PAUSED" Case 32768, 32769 $sPowerState = "SAVED/PAUSED" Case 32770 $sPowerState = "BOOTING..." Case 32774 $sPowerState = "SHUTTING DOWN..." Case Else $sPowerState = "UNKNOWN " & $oVM.EnabledState EndSwitch $mStateName[$oVM.Name] = $sPowerState Next Local $aMacMatch, $sMac, $sInstanceID, $sNativeInstanceID, $sNativeMac, $aSplat, $sVMGuid Local $oAdapters = $oWMIService.ExecQuery("SELECT Address, InstanceID, VirtualSystemIdentifiers FROM Msvm_SyntheticEthernetPortSettingData") If Not IsObj($oAdapters) Then Return SetError(3, 0, 0) For $oAdapter In $oAdapters $sMac = $oAdapter.Address $sInstanceID = $oAdapter.InstanceID If ($sMac == "" Or $sMac == "000000000000") And IsArray($oAdapter.VirtualSystemIdentifiers) Then For $sIdentifier In $oAdapter.VirtualSystemIdentifiers $aMacMatch = StringRegExp($sIdentifier, "(?i)\b([0-9A-F]{12}|(?:[0-9A-F]{2}[:\-]){5}[0-9A-F]{2})\b", 1) If Not @error Then $sMac = $aMacMatch[0] ExitLoop EndIf Next EndIf $sNativeInstanceID = String($sInstanceID) $sNativeMac = String($sMac) If StringLen($sNativeMac) And $sNativeMac <> "000000000000" And $sNativeInstanceID <> "" Then $aSplat = StringRegExp($sNativeInstanceID, "Microsoft:(?:\{)?([A-Fa-f0-9\-]+)(?:\}|\b)", 1) If Not @error Then $sVMGuid = $aSplat[0] If MapExists($mVmName, $sVMGuid) Then Local $sCleanMac = StringUpper(StringRegExpReplace($sNativeMac, "[:\-\s]", "")) $aRet[0][0] += 1 If UBound($aRet) = $aRet[0][0] Then ReDim $aRet[UBound($aRet) + 100][5] $aRet[$aRet[0][0]][0] = $sCleanMac $aRet[$aRet[0][0]][1] = $mStateInteger[$sVMGuid] $aRet[$aRet[0][0]][2] = $mStateName[$sVMGuid] $aRet[$aRet[0][0]][3] = $mVmName[$sVMGuid] $aRet[$aRet[0][0]][4] = $sVMGuid ;~ ConsoleWrite('[+] Writing Map: ' & $sCleanMac & @TAB & $sVMGuid & @TAB & $mStateName[$sVMGuid] & @TAB & $mVmName[$sVMGuid] & @CRLF) ; debug If $sCleanMac = $sHexMAC Then $iStateInteger = $mStateInteger[$sVMGuid] $sStateName = $mStateName[$sVMGuid] $sVMName = $mVmName[$sVMGuid] $sVmElementName = $sVMGuid Return 1 EndIf Else ;~ ConsoleWrite('[-] GUID Found (' & $sVMGuid & ') but missing from inventory map dictionary.' & @CRLF) ; debug EndIf Else ;~ ConsoleWrite('[-] Regular Expression parsing failed to isolate structural VM GUID from: ' & $sNativeInstanceID & @CRLF) ; debug EndIf EndIf Next ;~ ConsoleWrite('- Execution Time: ' & TimerDiff($hTimer) & ' ms' & @CRLF) ; debug ReDim $aRet[$aRet[0][0] + 1][5] $sStateName = $aRet Return SetError(0, 1, "") EndFunc ;==>_HyperV_MAC_infoEx F.A.Q. Q: Why won't it receive ? A: Is the firewall. Run _SetupWindowsFirewallRule() ( in the script ) to add the rule. Q: It don't start the Hyper-V VM for that MAC address. A: Make sure it runs as Admin. Other than that, I have limited experience with this code I just finished. Q: How do I get a list of VMs and their MACs A: Use _HyperV_MAC_info() without a valid MAC. ( read the code and uncomment the _DebugArrayDisplay() line ) Q: Are you going to make a full app with tray icon, load on boot, IPC, etc. A: If I ever go that far, then it will go on the Example Scripts section. Edited October 19 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 19 Author Posted October 19 (edited) Problem I use vssown.vbs to create Volume Shadow copies, and VBS is going away soon. What am I gonna do 🥲 Solution Here is a literal translation to AutoIt. Spoiler expandcollapse popup#NoTrayIcon #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_Change2CUI=y #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ; ============================================================================== ; Volume Shadow Copy Management from CLI (AutoIt Translation) ; Original Part of the presentation "Lurking in the Shadows" by Mark Baggett and Tim "LaNMaSteR53" Tomes ; ============================================================================== If $CmdLine[0] < 1 Then ConsoleWrite("Usage: vssown.exe [option]" & @CRLF & @CRLF) ConsoleWrite(" Options:" & @CRLF & @CRLF) ConsoleWrite(" /list - List current volume shadow copies." & @CRLF) ConsoleWrite(" /start - Start the shadow copy service." & @CRLF) ConsoleWrite(" /stop - Halt the shadow copy service." & @CRLF) ConsoleWrite(" /status - Show status of shadow copy service." & @CRLF) ConsoleWrite(" /mode - Display the shadow copy service start mode." & @CRLF) ConsoleWrite(" /mode [Manual|Automatic|Disabled] - Change the shadow copy service start mode." & @CRLF) ConsoleWrite(" /create [drive_letter] - Create a shadow copy." & @CRLF) ConsoleWrite(" /delete [id|*] - Delete a specified or all shadow copies." & @CRLF) ConsoleWrite(" /mount [path] [device_object] - Mount a shadow copy to the given path." & @CRLF) ConsoleWrite(" /execute [\path\to\file] - Launch executable from within an unmounted shadow copy." & @CRLF) ConsoleWrite(" /store - Display storage statistics." & @CRLF) ConsoleWrite(" /size [bytes] - Set drive space reserved for shadow copies." & @CRLF) Exit (0) EndIf Global $strComputer = "." Global $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2") If @error Then ConsoleWrite("[!] Error connecting to WMI service." & @CRLF) Exit (1) EndIf Exit Main() Func Main() Local $colItems, $errResult, $colListOfServices, $option = StringLower($CmdLine[1]) Switch $option Case "/list" ConsoleWrite("SHADOW COPIES" & @CRLF) ConsoleWrite("=============" & @CRLF & @CRLF) $colItems = $objWMIService.ExecQuery("Select * from Win32_ShadowCopy") For $objItem In $colItems ConsoleWrite("[*] ID: " & $objItem.ID & @CRLF) ConsoleWrite("[*] InstallDate: " & $objItem.InstallDate & @CRLF) ConsoleWrite("[*] Description: " & $objItem.Description & @CRLF) ConsoleWrite("[*] Caption: " & $objItem.Caption & @CRLF) ConsoleWrite("[*] Client accessible: " & $objItem.ClientAccessible & @CRLF) ConsoleWrite("[*] Count: " & $objItem.Count & @CRLF) ConsoleWrite("[*] Device object: " & $objItem.DeviceObject & @CRLF) ConsoleWrite("[*] Differential: " & $objItem.Differential & @CRLF) ConsoleWrite("[*] Exposed locally: " & $objItem.ExposedLocally & @CRLF) ConsoleWrite("[*] Exposed name: " & $objItem.ExposedName & @CRLF) ConsoleWrite("[*] Exposed remotely: " & $objItem.ExposedRemotely & @CRLF) ConsoleWrite("[*] Hardware assisted: " & $objItem.HardwareAssisted & @CRLF) ConsoleWrite("[*] Imported: " & $objItem.Imported & @CRLF) ConsoleWrite("[*] No auto release: " & $objItem.NoAutoRelease & @CRLF) ConsoleWrite("[*] Not surfaced: " & $objItem.NotSurfaced & @CRLF) ConsoleWrite("[*] No writers: " & $objItem.NoWriters & @CRLF) ConsoleWrite("[*] Originating machine: " & $objItem.OriginatingMachine & @CRLF) ConsoleWrite("[*] Persistent: " & $objItem.Persistent & @CRLF) ConsoleWrite("[*] Plex: " & $objItem.Plex & @CRLF) ConsoleWrite("[*] Provider ID: " & $objItem.ProviderID & @CRLF) ConsoleWrite("[*] Service machine: " & $objItem.ServiceMachine & @CRLF) ConsoleWrite("[*] Set ID: " & $objItem.SetID & @CRLF) ConsoleWrite("[*] State: " & $objItem.State & @CRLF) ConsoleWrite("[*] Transportable: " & $objItem.Transportable & @CRLF) ConsoleWrite("[*] Volume name: " & $objItem.VolumeName & @CRLF) ConsoleWrite("[*] Name: " & $objItem.Name & @CRLF & @CRLF) Next Exit (0) Case "/start" $colListOfServices = $objWMIService.ExecQuery("Select * from Win32_Service Where Name ='VSS'") For $objService In $colListOfServices $objService.StartService() ConsoleWrite("[*] Signal sent to start the " & $objService.Name & " service." & @CRLF) Next Exit (0) Case "/stop" $colListOfServices = $objWMIService.ExecQuery("Select * from Win32_Service Where Name ='VSS'") For $objService In $colListOfServices $objService.StopService() ConsoleWrite("[*] Signal sent to stop the " & $objService.Name & " service." & @CRLF) Next Exit (0) Case "/status" $colListOfServices = $objWMIService.ExecQuery("Select * from Win32_Service Where Name ='VSS'") For $objService In $colListOfServices ConsoleWrite("[*] " & $objService.State & @CRLF) Next Exit (0) Case "/mode" $colListOfServices = $objWMIService.ExecQuery("Select * from Win32_Service Where Name ='VSS'") $errResult = 0 For $objService In $colListOfServices If $CmdLine[0] < 2 Then ConsoleWrite("[*] " & $objService.Name & " service set to '" & $objService.StartMode & "' start mode." & @CRLF) Else Local $mode = StringLower($CmdLine[2]) If $mode = "manual" Or $mode = "automatic" Or $mode = "disabled" Then $errResult = $objService.ChangeStartMode($mode) ConsoleWrite("[*] " & $objService.Name & " service set to '" & $mode & "' start mode." & @CRLF) Else ConsoleWrite("[*] '" & $mode & "' is not a valid start mode." & @CRLF) EndIf EndIf Next Exit ($errResult) Case "/create" If $CmdLine[0] < 2 Then ConsoleWrite("[!] Error: Missing drive letter." & @CRLF) Exit (1) EndIf Local $VOLUME = $CmdLine[2] & ":\" Local $CONTEXT = "ClientAccessible" Local $objShadowStorage = $objWMIService.Get("Win32_ShadowCopy") ConsoleWrite("[*] Attempting to create a shadow copy." & @CRLF) Local $strShadowID = "" $errResult = $objShadowStorage.Create($VOLUME, $CONTEXT, $strShadowID) Exit ($errResult) Case "/delete" If $CmdLine[0] < 2 Then ConsoleWrite("[!] Error: Missing ID or wildcard." & @CRLF) Exit (1) EndIf Local $id = $CmdLine[2] $colItems = $objWMIService.ExecQuery("Select * From Win32_ShadowCopy") $errResult = 0 For $objItem In $colItems If $objItem.ID = $id Then ConsoleWrite("[*] Attempting to delete shadow copy with ID: " & $id & @CRLF) $errResult = $objItem.Delete_() ElseIf $id = "*" Then ConsoleWrite("[*] Attempting to delete shadow copy " & $objItem.DeviceObject & "." & @CRLF) $errResult = $objItem.Delete_() EndIf Next Exit ($errResult) Case "/mount" If $CmdLine[0] < 3 Then ConsoleWrite("[!] Error: Missing mount path or device object." & @CRLF) Exit (1) EndIf Local $link = $CmdLine[2] Local $sc = $CmdLine[3] & "\" Local $cmd = "cmd /C mklink /D " & $link & " " & $sc RunWait($cmd, "", @SW_HIDE) ConsoleWrite("[*] " & $sc & " has been mounted to " & $link & "." & @CRLF) Exit (0) Case "/execute" If $CmdLine[0] < 2 Then ConsoleWrite("[!] Error: Missing file path." & @CRLF) Exit (1) EndIf Local $file = $CmdLine[2] $colItems = $objWMIService.ExecQuery("Select * From Win32_ShadowCopy") Local $objProcess = $objWMIService.Get("Win32_Process") For $objItem In $colItems Local $path = StringReplace($objItem.DeviceObject, "?", ".") & $file Local $intReturn = $objProcess.Create($path) If $intReturn <> 0 Then ConsoleWrite("[*] Process could not be created from " & $path & "." & @CRLF) ConsoleWrite("[*] ReturnValue = " & $intReturn & @CRLF) Else ConsoleWrite("[!] Process created from " & $path & "." & @CRLF) Exit (0) EndIf Next Exit (0) Case "/store" ConsoleWrite("SHADOW STORAGE" & @CRLF) ConsoleWrite("==============" & @CRLF & @CRLF) $colItems = $objWMIService.ExecQuery("Select * from Win32_ShadowStorage") For $objItem In $colItems ConsoleWrite("[*] Allocated space: " & StringFormat("%0.0f", $objItem.AllocatedSpace / 1000000) & "MB" & @CRLF) ConsoleWrite("[*] Maximum size: " & StringFormat("%0.0f", $objItem.MaxSpace / 1000000) & "MB" & @CRLF) ConsoleWrite("[*] Used space: " & StringFormat("%0.0f", $objItem.UsedSpace / 1000000) & "MB" & @CRLF & @CRLF) Next Exit (0) Case "/size" If $CmdLine[0] < 2 Then ConsoleWrite("[!] Error: Missing size value." & @CRLF) Exit (1) EndIf Local $storagesize = Number($CmdLine[2]) $colItems = $objWMIService.ExecQuery("Select * from Win32_ShadowStorage") For $objItem In $colItems $objItem.MaxSpace = $storagesize $objItem.Put_() Next ConsoleWrite("[*] Shadow storage space has been set to " & StringFormat("%0.0f", $storagesize / 1000000) & "MB." & @CRLF) Exit (0) Case Else ConsoleWrite("[!] Unknown option specified." & @CRLF) Exit (1) EndSwitch EndFunc ;==>Main Compile as CUI and run elevated. ( My limited testing was "/create c" ) Note: AutoIt has its own independent interpreter and talks directly to the Windows WMI through core system components rather than the VBScript engine, so scripts will keep working regardless. Edited October 19 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 22 Author Posted October 22 (edited) Problem The help file looks too blurry on my high DPI monitor Solution Right click AutoIt3Help.exe, open Properties and select the Compatibility tab. Click Change high DPI settings. Do as in the pic bellow: Edited October 22 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
argumentum Posted October 22 Author Posted October 22 (edited) Problem hh.exe don't have that compatibility tab. Why ! Solution ..don't know. But you can patch the registry to set the values. Spoiler expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=y #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #cs ---------------------------------------------------------------------------- ; Script: CHM High-DPI Fixer for Windows ; Description: Adds the registry compatibility flag to force hh.exe to scale correctly on High-DPI displays. #ce ---------------------------------------------------------------------------- #RequireAdmin ; if possible Global $g_sAutoItDir = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1) - 1) ;~ main($g_sAutoItDir & "\AutoIt3Help.exe") ; might as well use it on this too main(@WindowsDir & "\hh.exe") Func main($sValueName) Local $sKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" If Not IsAdmin() Then $sKey = StringReplace($sKey, "HKEY_LOCAL_MACHINE\", "HKEY_CURRENT_USER\") Local $sValueData = "~ GDIDPISCALING DPIUNAWARE" If Not FileExists($sValueName) Then Exit 5 ; Prompt the user for confirmation before making system modifications Local $iMsgBox = MsgBox(36 + 256, "CHM High-DPI Fixer", _ "This script will configure Windows to fix the high-DPI scaling issue for the Microsoft HTML Help Viewer (hh.exe)." & @CRLF & @CRLF & _ "Do you want to apply this fix now?") If $iMsgBox <> 6 Then Exit 6 ; Ensure the AppCompatFlags\Layers key exists If Not RegWrite($sKey) Then MsgBox(16, "Error", "Failed to access or create the registry key." & @CRLF & "Please check your permissions.") Exit 7 EndIf ; Write the compatibility string value Local $iResult = RegWrite($sKey, $sValueName, "REG_SZ", $sValueData) If $iResult Then MsgBox(64, "Success", "The high-DPI fix has been successfully applied to C:\Windows\hh.exe!" & @CRLF & _ "Any program launching CHM files should now display properly.") Else MsgBox(16, "Error", "Failed to write to the registry. Please check your permissions.") EndIf EndFunc ;==>main Edited October 23 by argumentum ioa747 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now