Jump to content

Recommended Posts

Posted

Hi everyone!

Please tell me why the functions for getting/restoring the clipboard are unstable?

Over time the error appears:

!>12:03:17 AutoIt3.exe ended.rc:-1073740940

The error also appears when using functions from Nine.

sorry for my english..

#include <WindowsConstants.au3>
#include <WinApi.au3>
#include <GDIPlus.au3>
#include <ColorConstants.au3>
#include <GUIConstantsEx.au3>
#include <Misc.au3>
#include <Array.au3>
#include <WinAPISysWin.au3>
#include <ColorConstants.au3>
#include <GUIConstantsEx.au3>
#include <Color.au3>
#include <SCreencapture.au3>
#include <GUIConstants.au3>
#include <ScreenCapture.au3>
#include <WindowsConstants.au3>
#include <SendMessage.au3>
#include <Clipboard.au3>

OnAutoItExitRegister("__AutoItExit_ClipAll")

Global $__bMemFree = False
Global $avClip
Global $aClip

;result - error
For $x=1 to 1000
    ConsoleWrite('Attemp ' & $x & @CRLF)
    ;_ScreenshotSendToClipBoard()
    Send('{PRINTSCREEN}') ;!important
    _ClipBoard_GetAll($avClip)
    ClipPut('test string..')
    _ClipBoard_PutAll($avClip)
Next


;by wraithdu
;https://www.autoitscript.com/forum/topic/81267-_clipboard_getall-_clipboard_putall-_clipboard_wait/

Func _ClipBoard_GetAll(ByRef $avClip)

    Local $i = 0, $iFormat = 0, $hMem, $hMemNew, $pSource, $pDest, $iSize, $iErr = 0, $iErrEx = 0

    If $__bMemFree = True Then
        __MemFree($avClip)
    Else
        Dim $avClip[1][2]
    EndIf

    If Not _ClipBoard_Open(0) Then Return SetError(1, 1, 0)

    Do
        $iFormat = _ClipBoard_EnumFormats($iFormat)
        If $iFormat = 0 Then ExitLoop
        $hMem = _ClipBoard_GetDataEx($iFormat) ; this can/will fail for some formats - don't know why yet, so let's continue without retutning an error
        If $hMem = 0 Then ContinueLoop

        ; copy the memory
        $pSource = _MemGlobalLock($hMem)
        If $pSource = 0 Then
            $iErr = 3
            $iErrEx += 1
            ExitLoop
        EndIf
        $iSize = _MemGlobalSize($hMem)
        $hMemNew = _MemGlobalAlloc($iSize, $GHND)
        If $hMemNew = 0 Then
            _MemGlobalUnlock($hMemNew)
            $iErr = 4
            $iErrEx += 1
            ExitLoop
        EndIf
        $pDest = _MemGlobalLock($hMemNew)
        If $pDest = 0 Then
            _MemGlobalFree($hMemNew)
            $iErr = 5
            $iErrEx += 1
            ExitLoop
        EndIf
        DllCall("msvcrt.dll", "int:cdecl", "memcpy_s", "ptr", $pDest, "ulong_ptr", $iSize, "ptr", $pSource, "ulong_ptr", $iSize)
        If @error Then
            $iErr = 6
            $iErrEx += 1
        EndIf
        _MemGlobalUnlock($hMem)
        _MemGlobalUnlock($hMemNew)
        $__bMemFree = True
        If $iErr = 6 Then
            __MemFree($avClip)
            ExitLoop
        EndIf

        ; add handle and format to array
        $i += 1
        ReDim $avClip[$i + 1][2]
        $avClip[0][0] = $i
        $avClip[$i][0] = $hMemNew
        $avClip[$i][1] = $iFormat
    Until $iFormat = 0

    If Not _ClipBoard_Close() Then $iErr = 5

    If $iErr Then Return SetError($iErr, $iErrEx, 0)
    Return 1

EndFunc   ;==>_ClipBoard_GetAll


Func _ClipBoard_PutAll(ByRef $avClip)

    ; DO NOT free the memory handles after a call to this function - the system now owns the memory
    Local $iErr = 0, $iErrEx = 0 ; , $bOpen, $iTime

    $__bMemFree = False

    If Not IsArray($avClip) Or UBound($avClip, 0) <> 2 Or $avClip[0][0] < 1 Then
        Dim $avClip[1][2]
        Return SetError(1, 1, 0)
    EndIf

    ; test if clipboard can be opened
    ; if _ClipBoard_Open failes, the clipboard is likely still being updated, so we keep trying until it succeeds
    ;Local $hTimer = TimerInit()
    ;Do
    ;    $bOpen = _ClipBoard_Open(0)
    ;    Sleep(50)
    ;    $iTime = TimerDiff($hTimer)
    ;Until $bOpen = 1 Or $iTime >= 2000
    ;If $bOpen = 0 Then
    ;    Return SetError(2, 1, 0)
    ;EndIf

    ; empty clipboard
    If Not _ClipBoard_Open(0) Then Return SetError(2, 1, 0) ; comment out if using the code above
    If Not _ClipBoard_Empty() Then
        _ClipBoard_Close()
        Return SetError(3, 1, 0)
    EndIf
    If Not _ClipBoard_Close() Then Return SetError(4, 1, 0)

    ; re-open clipboard and put data
    If Not _ClipBoard_Open(0) Then Return SetError(5, 1, 0)
    For $i = 1 To $avClip[0][0]
        If Not _ClipBoard_SetDataEx($avClip[$i][0], $avClip[$i][1]) Then
            $iErr = 6
            $iErrEx += 1
        EndIf
    Next
    If Not _ClipBoard_Close() Then
        $iErr = 7
        $iErrEx += 1
    EndIf

    If $iErr Then Return SetError($iErr, $iErrEx, 0)
    Return 1

EndFunc   ;==>_ClipBoard_PutAll


Func __MemFree(ByRef $avClip)

    Local $iErr = 0, $iErrEx = 0

    If $__bMemFree = False Then
        Return
    ElseIf Not IsArray($avClip) Or UBound($avClip, 0) <> 2 Or $avClip[0][0] < 1 Then
        Dim $avClip[1][2]
        $__bMemFree = False
        Return SetError(1, 1, 0)
    EndIf

    For $i = 1 To $avClip[0][0]
        If Not _MemGlobalFree($avClip[$i][1]) Then
            $iErr = 2
            $iErrEx += 1
        EndIf
    Next

    $__bMemFree = False
    Dim $avClip[1][2]

    If $iErr Then Return SetError($iErr, $iErrEx, 0)
    Return 1

EndFunc   ;==>__MemFree


Func __AutoItExit_ClipAll()
    #forcedef $avClip
    __MemFree($avClip)
EndFunc   ;==>__AutoItExit_ClipAll


;func by Nine

Func _Clipboard_GetAll_byNine(ByRef $avClip)
    Local $iFormat = 0, $iNum

    If Not _ClipBoard_Open(0) Then Return SetError(-1, 0, 0)
    $iNum = _ClipBoard_CountFormats()
    Dim $avClip[$iNum + 1][2]
    $avClip[0][0] = $iNum

    For $i = 1 To $iNum
        $iFormat = _ClipBoard_EnumFormats($iFormat)
        $avClip[$i][0] = $iFormat
    Next

    _ClipBoard_Close()

    For $i = 1 To $iNum
        $avClip[$i][1] = _ClipBoard_GetData($avClip[$i][0])
    Next
EndFunc   ;==>_Clipboard_GetAll_byNine

Func _ClipBoard_PutAll_byNine(ByRef $avClip)
    Local $bEmpty, $iErr = 0

    If Not _ClipBoard_Open(0) Then Return SetError(-2, 0, 0)
    $bEmpty = _ClipBoard_Empty()
    _ClipBoard_Close()

    If Not $bEmpty Then Return SetError(-3, 0, 0)

    For $i = 1 To $avClip[0][0]
        If _ClipBoard_SetData($avClip[$i][1], $avClip[$i][0]) = 0 Then $iErr += 1
    Next

    If $iErr Then
        Return SetError(-4, $iErr, 0)
    Else
        Return 1
    EndIf
EndFunc   ;==>_ClipBoard_PutAll_byNine


Func _ScreenshotSendToClipBoard()
    _GDIPlus_Startup()
    Local $hBMP = _ScreenCapture_Capture()
    _ClipBoard_Open(0)
    Local $hBitmap = _WinAPI_CopyImage($hBMP, 0, 0, 0, BitOR($LR_COPYDELETEORG, $LR_COPYRETURNORG))
    _ClipBoard_Empty()
    _ClipBoard_SetDataEx($hBitmap, $CF_BITMAP)
    _ClipBoard_Close()
EndFunc   ;==>_ScreenshotSendToClipBoard
;========================================================

 

Posted

I do not get any error with both sets of functions.  So I can only guess what could be the problem.  My comp is recent and quite fast.  Maybe the problem comes from the send.  It might require some time to copy the screen to clipboard.  Try put a sleep after, see if that helps.

Posted (edited)
1 hour ago, Nine said:

I do not get any error with both sets of functions.  So I can only guess what could be the problem.  My comp is recent and quite fast.  Maybe the problem comes from the send.  It might require some time to copy the screen to clipboard.  Try put a sleep after, see if that helps.

tried on a virtual machine VMware Workstation

still an error.. clean Windows 11 LTSC installed..

Strange, what could this be connected with? The working machine is also Windows 11 LTSC 2024

Sorry the picture is big, I don't know how to make it smaller

image.jpg

Edited by SEKOMD
Posted (edited)
Posted (edited)
11 hours ago, Nine said:

You will need to debug and found the statement that creates the crash

 

_ClipBoard_PutAll_byNine - supports restoring a screenshot in the clipboard (which was before), but does not support restoring the "file to insert" that was before in the clipboard

_ClipBoard_PutAll - supports restoring the "file to insert" that was before in the clipboard, but does not support restoring a screenshot in the clipboard

Please tell me, if it's not difficult, is it possible to somehow solve this? so that all the features work..

Edited by SEKOMD
Posted

I managed to reproduce the problem, everything is clear from the code. There are no problems with reading/restoring text.

Maybe someone can tell me how to solve this - I will be very grateful.

#include <WindowsConstants.au3>
#include <WinApi.au3>
#include <GDIPlus.au3>
#include <ColorConstants.au3>
#include <GUIConstantsEx.au3>
#include <Misc.au3>
#include <Array.au3>
#include <WinAPISysWin.au3>
#include <ColorConstants.au3>
#include <GUIConstantsEx.au3>
#include <Color.au3>
#include <SCreencapture.au3>
#include <GUIConstants.au3>
#include <ScreenCapture.au3>
#include <WindowsConstants.au3>
#include <SendMessage.au3>
#include <Clipboard.au3>

OnAutoItExitRegister("__AutoItExit_ClipAll")

Global $__bMemFree = False
Global $avClip
Global $aClip


MsgBox(64, '', 'copy something')

;==== Its works only if the script is compiled!! ====
_ScreenshotSendToClipBoard()
Sleep(500)
;================================================

_ClipBoard_Open(0)
$iFormat = 0
$iCount = 0
$iIsBitmapData=0
Do
    $iFormat = _ClipBoard_EnumFormats($iFormat)
    If $iFormat <> 0 Then
        $iCount += 1
        if _ClipBoard_FormatStr($iFormat) = 'Bitmap' Then _
            $iIsBitmapData=1
    EndIf
Until $iFormat = 0
_ClipBoard_Close()

if $iIsBitmapData Then
    _Clipboard_GetAll_byNine($aClip)
    ClipPut('Test string for testing')
    MsgBox(64,'','New value clipboard: ' & ClipGet())
    _ClipBoard_PutAll_byNine($aClip)
    MsgBox(64, '_ClipBoard_PutAll_byNine', 'check that the buffer has been restored')
    Exit
EndIf
_Clipboard_GetAll($avClip)
ClipPut('Test string for testing')
MsgBox(64,'','New value clipboard: ' & ClipGet())
_ClipBoard_PutAll($avClip)
MsgBox(64, '_ClipBoard_PutAll', 'check that the buffer has been restored')









;by wraithdu
;https://www.autoitscript.com/forum/topic/81267-_clipboard_getall-_clipboard_putall-_clipboard_wait/

Func _ClipBoard_GetAll(ByRef $avClip)

    Local $i = 0, $iFormat = 0, $hMem, $hMemNew, $pSource, $pDest, $iSize, $iErr = 0, $iErrEx = 0

    If $__bMemFree = True Then
        __MemFree($avClip)
    Else
        Dim $avClip[1][2]
    EndIf

    If Not _ClipBoard_Open(0) Then Return SetError(1, 1, 0)

    Do
        $iFormat = _ClipBoard_EnumFormats($iFormat)
        If $iFormat = 0 Then ExitLoop
        $hMem = _ClipBoard_GetDataEx($iFormat) ; this can/will fail for some formats - don't know why yet, so let's continue without retutning an error
        If $hMem = 0 Then ContinueLoop

        ; copy the memory
        $pSource = _MemGlobalLock($hMem)
        If $pSource = 0 Then
            $iErr = 3
            $iErrEx += 1
            ExitLoop
        EndIf
        $iSize = _MemGlobalSize($hMem)
        $hMemNew = _MemGlobalAlloc($iSize, $GHND)
        If $hMemNew = 0 Then
            _MemGlobalUnlock($hMemNew)
            $iErr = 4
            $iErrEx += 1
            ExitLoop
        EndIf
        $pDest = _MemGlobalLock($hMemNew)
        If $pDest = 0 Then
            _MemGlobalFree($hMemNew)
            $iErr = 5
            $iErrEx += 1
            ExitLoop
        EndIf
        DllCall("msvcrt.dll", "int:cdecl", "memcpy_s", "ptr", $pDest, "ulong_ptr", $iSize, "ptr", $pSource, "ulong_ptr", $iSize)
        If @error Then
            $iErr = 6
            $iErrEx += 1
        EndIf
        _MemGlobalUnlock($hMem)
        _MemGlobalUnlock($hMemNew)
        $__bMemFree = True
        If $iErr = 6 Then
            __MemFree($avClip)
            ExitLoop
        EndIf

        ; add handle and format to array
        $i += 1
        ReDim $avClip[$i + 1][2]
        $avClip[0][0] = $i
        $avClip[$i][0] = $hMemNew
        $avClip[$i][1] = $iFormat
    Until $iFormat = 0

    If Not _ClipBoard_Close() Then $iErr = 5

    If $iErr Then Return SetError($iErr, $iErrEx, 0)
    Return 1

EndFunc   ;==>_ClipBoard_GetAll


Func _ClipBoard_PutAll(ByRef $avClip)

    ; DO NOT free the memory handles after a call to this function - the system now owns the memory
    Local $iErr = 0, $iErrEx = 0 ; , $bOpen, $iTime

    $__bMemFree = False

    If Not IsArray($avClip) Or UBound($avClip, 0) <> 2 Or $avClip[0][0] < 1 Then
        Dim $avClip[1][2]
        Return SetError(1, 1, 0)
    EndIf

    ; test if clipboard can be opened
    ; if _ClipBoard_Open failes, the clipboard is likely still being updated, so we keep trying until it succeeds
    ;Local $hTimer = TimerInit()
    ;Do
    ;    $bOpen = _ClipBoard_Open(0)
    ;    Sleep(50)
    ;    $iTime = TimerDiff($hTimer)
    ;Until $bOpen = 1 Or $iTime >= 2000
    ;If $bOpen = 0 Then
    ;    Return SetError(2, 1, 0)
    ;EndIf

    ; empty clipboard
    If Not _ClipBoard_Open(0) Then Return SetError(2, 1, 0) ; comment out if using the code above
    If Not _ClipBoard_Empty() Then
        _ClipBoard_Close()
        Return SetError(3, 1, 0)
    EndIf
    If Not _ClipBoard_Close() Then Return SetError(4, 1, 0)

    ; re-open clipboard and put data
    If Not _ClipBoard_Open(0) Then Return SetError(5, 1, 0)
    For $i = 1 To $avClip[0][0]
        If Not _ClipBoard_SetDataEx($avClip[$i][0], $avClip[$i][1]) Then
            $iErr = 6
            $iErrEx += 1
        EndIf
    Next
    If Not _ClipBoard_Close() Then
        $iErr = 7
        $iErrEx += 1
    EndIf

    If $iErr Then Return SetError($iErr, $iErrEx, 0)
    Return 1

EndFunc   ;==>_ClipBoard_PutAll


Func __MemFree(ByRef $avClip)

    Local $iErr = 0, $iErrEx = 0

    If $__bMemFree = False Then
        Return
    ElseIf Not IsArray($avClip) Or UBound($avClip, 0) <> 2 Or $avClip[0][0] < 1 Then
        Dim $avClip[1][2]
        $__bMemFree = False
        Return SetError(1, 1, 0)
    EndIf

    For $i = 1 To $avClip[0][0]
        If Not _MemGlobalFree($avClip[$i][1]) Then
            $iErr = 2
            $iErrEx += 1
        EndIf
    Next

    $__bMemFree = False
    Dim $avClip[1][2]

    If $iErr Then Return SetError($iErr, $iErrEx, 0)
    Return 1

EndFunc   ;==>__MemFree


Func __AutoItExit_ClipAll()
    #forcedef $avClip
    __MemFree($avClip)
EndFunc   ;==>__AutoItExit_ClipAll


;func by Nine
Func _Clipboard_GetAll_byNine(ByRef $aClip)
    Local $iFormat = 0, $iNum

    If Not _ClipBoard_Open(0) Then Return SetError(-1, 0, 0)
    $iNum = _ClipBoard_CountFormats()
    Dim $avClip[$iNum + 1][2]
    $avClip[0][0] = $iNum

    For $i = 1 To $iNum
        $iFormat = _ClipBoard_EnumFormats($iFormat)
        $avClip[$i][0] = $iFormat
    Next

    _ClipBoard_Close()

    For $i = 1 To $iNum
        $avClip[$i][1] = _ClipBoard_GetData($avClip[$i][0])
    Next
EndFunc   ;==>_Clipboard_GetAll_byNine


Func _ClipBoard_PutAll_byNine(ByRef $aClip)
    Local $bEmpty, $iErr = 0

    If Not _ClipBoard_Open(0) Then Return SetError(-2, 0, 0)
    $bEmpty = _ClipBoard_Empty()
    _ClipBoard_Close()

    If Not $bEmpty Then Return SetError(-3, 0, 0)

    For $i = 1 To $avClip[0][0]
        If _ClipBoard_SetData($avClip[$i][1], $avClip[$i][0]) = 0 Then $iErr += 1
    Next

    If $iErr Then
        Return SetError(-4, $iErr, 0)
    Else
        Return 1
    EndIf
EndFunc   ;==>_ClipBoard_PutAll_byNine


Func _ScreenshotSendToClipBoard()
    _GDIPlus_Startup()
    Local $hBMP = _ScreenCapture_Capture()
    _ClipBoard_Open(0)
    Local $hBitmap = _WinAPI_CopyImage($hBMP, 0, 0, 0, BitOR($LR_COPYDELETEORG, $LR_COPYRETURNORG))
    _ClipBoard_Empty()
    _ClipBoard_SetDataEx($hBitmap, $CF_BITMAP)
    _ClipBoard_Close()
EndFunc   ;==>_ScreenshotSendToClipBoard
;========================================================

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...