Jump to content

[Solved] Help for argumentum


Go to solution Solved by argumentum,

Recommended Posts

Posted (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
Global $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 by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted

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

#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

#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  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted (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

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 <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 by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted (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
#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
#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 by argumentum
more

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...