Jump to content

Clipboard save and retrieve


Clear
 Share

Recommended Posts

Hey, First, I am really sorry for this question. I have searched for the answer for several minutes, in Help File and via Google, but can't answer it by myself.

I am new to AutoIt. Before I have used AutoHotkey for simple improvements of my work station. Unfortunately, IT decided to update OS to Windows 10, and with that, AutoHotkey was removed and instead AutoIt has been given.

Unfortunately, I need to learn syntax, and as for me, it's more weird syntax for simple tasks (however I must admit, GUI is easier). What is my problem is that Send and ControlSend commands are not as effective as in case of SendInput. I want to create some templates with hotkeys and gui. Unfortunately, Send is too slow for bigger templates (text is pasted in SunAwtFrame class (program created in Java) with no ControlId.

That's why I wanted to use Clipboard to make it work faster.

In AutoHotkey it would be something like:

ClipCopy := ClipboardAll
Clipboard = Template to send
Send, ^v
Clipboard := ClipCopy
ClipCopy =

Unfortunately, something similar doesn't work in AutoIt:
 

Local $ClipCopy = _Clipboard_GetData()
ClipPut("Template to Send")
Send("^v")
_Clipboard_SetData($ClipCopy)

It works only for text.  I know that's because it need additional parameter for storing other type of content, but how am i supposed to know, what will be stored in clipboard? Is there any other way to achieve what I am trying to do?

Link to comment
Share on other sites

Hi @Clear, and welcome to the AutoIt forums :)

If you look closely in the Help file about _Clipboard_GetData(), you'll see that you can specify the format of its content, so, if you want to get a previous copied bitmap, you can (and have to) specify the $iFormat parameter as $CF_BITMAP.

And, the same is for _Clipboard_SetData() :)

Edited by FrancescoDiMuro

Click here to see my signature:

Spoiler

ALWAYS GOOD TO READ:

 

Link to comment
Share on other sites

Próbowałem, ale po wybraniu tej opcji, w ogóle nie działa, chyba że coś źle robię. Nie działa wtedy ani dla tekstu, ani obrazków, ani niczego innego.

W przypadku obrazków, przy próbie wklejenia, pojawia się komunikat (do innych programów oczywiście tez nie działa)

 

I tried, but after choosing this option, it doesn't work at all or I'm not doing it properly. It doesn't work for text, nor images, neither anything else.
In case of images, when trying to paste, there is error:

Quote

---------------------------
Paint
---------------------------
Clipboard cannot be pasted into Paint
---------------------------
OK   
---------------------------

 

Kod:

Func Text($Text)
   Local $Clip = _ClipBoard_GetData($CF_BITMAP)
   ClipPut($Text)
   Send("^v")
   _ClipBoard_SetData($Clip, $CF_BITMAP)
EndFunc

 

Edited by Clear
Link to comment
Share on other sites

It seems like _Clipboard_GetData, _Clipboard_SetData and ...Ex functions are not working with $iFormat set to $CF_BITMAP in my workstation (Windows 10 64-bit) or I am doing it in wrong way.

So something which I could acomplish with just few lines in AutoHotkey doesn't seem to work at all with AutoIt or I don't know how :(

Once again, I will write what I am trying to do:

  • Creating simple script that will bind hotkeys for quickly writing written templates (it's ok)
    #include <GUIConstantsEx.au3>
    #include <Clipboard.au3>
    
    HotKeySet("^{NUMPAD1}", TemplatesGreeting)
    HotKeySet("^{NUMPAD2}", TemplatesFarewell)
    HotkeySet("^{NUMPAD3}", TemplatesVerification)
    
    Opt("SendKeyDelay", 0)
    
    While 1
        Sleep(100)
    WEnd

     

  • While entering hotkey, GUI with templates' categories' buttons will appear.  Clicking buttons should send templates.
    Func TemplatesFarewell()
        Local $GUI1 = GUICreate("Farewell GUI", 275, 400)
        GUICtrlCreateLabel("Choose radio button", 10, 10)
        Local $FormRadio1 = GUICtrlCreateRadio("R1", 10, 40)
        Local $FormRadio2 = GUICtrlCreateRadio("R_2", 60, 40)
        GUICtrlCreateLabel("Choose Template to use:", 10, 100)
        Local $Button1 = GUICtrlCreateButton("Template #1", 10, 125, 250, 25)
        Local $Button2 = GUICtrlCreateButton("Template #2", 10, 160, 250, 25)
        Local $Button3 = GUICtrlCreateButton("Template #3", 10, 195, 250, 25)
        GUISetState(@SW_SHOW)
        
        ; HERE STARTS PROBLEM
        
        Local $FirstText = "Bye :)"
        While 1
            Switch GUIGetMsg()
            Case $FormRadio1
                $FirstText = "Bye :)"
            Case $FormRadio2
                $FirstText = "Goodbye :)"
            Case $Button1
                ; By using Send
                GUIDelete($GUI1)
                Send($FirstText & @CRLF & "Thanks for nothing! Here I will add some local chars like ąćęóńżź")
                ; Problem - it's slow. Otherwise, works fine
            Case $Button2
                ; By using ControlSend
                GUIDelete($GUI1)
                ControlSend("Active Conversations", "", "", $FirstText & ". Thanks for anything - Some local chars like ąćęóńźż")
                ; It seems it works faster, but Polish chars are not displayed :( That's why I need to use something else
                ; The program to send is SunAwtFrame class (Jp2Launcher - Java)
            Case $Button3
                ; By Using SendText (Clipboard)
                GUIDelete($GUI1)
                SendText($FirstText & ". This is some text. Blebleble." & @CRLF & "Have a nice day")
            Case $GUI_EVENT_CLOSE
                ExitLoop
            EndSwitch
        WEnd
        GUIDelete($GUI1)
    EndFunc
    
    Func SendText($Text)
        ; User can have something in Clipboard - we store it to retrieve it later to make sure nothing is lost.
        Local $Clip = _ClipBoard_GetData($CF_BITMAP)
        ; Once we have saved clipboard content, we change clipboard to our template and send it
        ClipPut($Text)
        Send("^v")
        ; Now it's time to retrieve our clipboard from memory
        _ClipBoard_SetData($Clip, $CF_BITMAP)
    EndFunc

     

EDIT: I am really sorry. I didn't notice till now, my previous post was written not in English. I edited it

Edited by Clear
Link to comment
Share on other sites

Hi Clear,
I just studied a bit UEZ's script to fill the Clipboard with an image, who knows, maybe it will help you one day, even if it seems simpler with AutoHotkey :)

Translating your 2nd polish post with google shows that you also want to put images in clipboard and it didn't work, so this script could be helpful :

; Based on UEZ's script
#include <Clipboard.au3>
#include <GDIPlus.au3>
#include <MsgBoxConstants.au3>

Local $sImageName = "G:\temp\cherry.jpg"

; Initialize GDI+ library
_GDIPlus_Startup()

; Create a bitmap object from file
$hClipboard_Bitmap = _GDIPlus_BitmapCreateFromFile($sImageName)

; Create a handle to a bitmap from a bitmap object
$hClipboard_BitmapGDI = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hClipboard_Bitmap)

; Release a bitmap object (not needed anymore)
_GDIPlus_BitmapDispose($hClipboard_Bitmap)

; Shut down GDI+ library
_GDIPlus_Shutdown()

; Create a new image (bitmap) and copy the attributes of the specified image to the new one
$hHBmp_Clipboard = _WinAPI_CopyImage($hClipboard_BitmapGDI, 0, 0, 0, _
    BitOR($LR_COPYDELETEORG, $LR_COPYRETURNORG))

; Open Clipboard, empty it, fill it with the image, close Clipboard
$iReturn = _WinAPI_Bitmap2Clipboard($hHBmp_Clipboard)

If $iReturn = 0 Then
    Msgbox($MB_TOPMOST, "Ok", "Clipboard contains the image")
Else
    Msgbox($MB_TOPMOST, "Error", $iReturn)
EndIf

; =========================================
Func _WinAPI_Bitmap2Clipboard($hHBitmap)
    If Not _ClipBoard_Open(0) Then Return 1
    If Not _ClipBoard_Empty() Then Return 2
    Local Const $hCP = _ClipBoard_SetDataEx($hHBitmap, $CF_BITMAP)
    If Not $hCP Or @error Then Return 3
    If Not _ClipBoard_Close() Then Return 4
    Return 0
EndFunc

Concerning _WinAPI_CopyImage(), i didn't understand immediately why it was necessary here, because we already had a functional bitmap handle, so why is it necessary to copy the image again ?

The answer is because in some cases, you will want to modify the image width/height (among other attributes).
Also, have a look at the 2 flags (uncommented in help file) $LR_COPYDELETEORG, $LR_COPYRETURNORG :

MSDN indicates this :
* LR_COPYDELETEORG : "Deletes the original image after creating the copy"
* LR_COPYRETURNORG : "Returns the original hImage if it satisfies the criteria for the copy—that is, correct dimensions and color depth—in which case the LR_COPYDELETEORG flag is ignored. If this flag is not specified, a new object is always created."

Which means _WinAPI_CopyImage() will not always create a copy of the image, reusing the original if all criterias are correct, that's the answer to my question :)

Thanks Francesco for UEZ's link, he always got great scripts !
A few weeks ago, I found another UEZ's link, very helpful, where he solved a tricky problem :
https://www.autoitscript.com/forum/topic/165083-question-on-_guiimagelist-usage/?do=findComment&comment=1205157

 

Link to comment
Share on other sites

35 minutes ago, pixelsearch said:

Concerning _WinAPI_CopyImage(), i didn't understand immediately why it was necessary here, because we already had a functional bitmap handle, so why is it necessary to copy the image again ?

The answer is because in some cases, you will want to modify the image width/height (among other attributes).
Also, have a look at the 2 flags (uncommented in help file) $LR_COPYDELETEORG, $LR_COPYRETURNORG :

MSDN indicates this :
* LR_COPYDELETEORG : "Deletes the original image after creating the copy"
* LR_COPYRETURNORG : "Returns the original hImage if it satisfies the criteria for the copy—that is, correct dimensions and color depth—in which case the LR_COPYDELETEORG flag is ignored. If this flag is not specified, a new object is always created."

Not quite, the answer comes from from @ProgAndy in

"The problems of the other Scripts were the differencies between GDI32-HBITMAP and GDIPlus-HBITMAP."  Image copy resolves that. 

If you don't do it, it will simply not work...

 

Link to comment
Share on other sites

Hi Nine :)
Thanks for your input, it allowed us to see what ProgAndy was able to do in 2008 and to get his UDF
If I read him well, he was able, first, to copy a bmp image to clipboard, here :
https://www.autoitscript.com/forum/topic/70184-screencapture-into-clipboard/?do=findComment&comment=514764

#include <ClipBoard.au3>
#include <WinAPIRes.au3>

$hBitmap = _WinAPI_LoadImage("","C:\windows\zapotec.bmp", $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE)
_ClipBoard_Open(0)
_ClipBoard_Empty()
_ClipBoard_SetDataEx($hBitmap, $CF_BITMAP)
_ClipBoard_Close()

Reduced to its shortest size, his script works nicely on my computer for .bmp images only (not for tif or jpg)
So without GDIPlus functions or _WinAPI_CopyImage() , he was able to copy a bmp to clipboard, great job !

After that, he created a UDF to allow other types of images to be copied to the clipboard, here :

https://www.autoitscript.com/forum/topic/70237-images-and-the-clipboard/

In his UDF, the 9 important functions he used are nearly the same as UEZ's (only 1 function will differ) :

_GDIPlus_Startup()
_GDIPlus_ImageLoadFromFile()   [UEZ uses _GDIPlus_BitmapCreateFromFile]
_GDIPlus_BitmapCreateHBITMAPFromBitmap()
_WinAPI_CopyImage()
_GDIPlus_Shutdown()

_ClipBoard_Open()
_ClipBoard_Empty()
_ClipBoard_SetDataEx()
_ClipBoard_Close()

I wish a function named _ClipPutImage() could be added in the next releases of AutoIt, to be able to copy the content of any image in the clipboard... with 1 line only, based on the script of these great guys :)

Link to comment
Share on other sites

Hi FrancescoDiMuro :)
In the link you provided in your post, before UEZ's answer, Water indicated something that could interest Clear (lots of nicknames in that sentence lol)

https://www.autoitscript.com/forum/topic/191946-how-to-copy-a-picture-to-the-clipboard【solved】/

OP wanted to copy an image into clipboard and Water answered him this :

_ClipPutFile("<your filename goes here>")

But this was not satisfying for OP because ctrl-v in his app pasted... the name of the file, not the image itself. Then Water suggested him to try this in Word and see the results. Then came UEZ...

According to the help file , _ClipPutFile() "copy Files to Clipboard Like Explorer does"
I just did this test :

#include <Misc.au3>
_ClipPutFile("G:\temp\cherry.jpg" & "|" & "C:\windows\zapotec.bmp")

Don't expect the clipboard to contain the images themselves, it will contain 2 lines only (path & filename) :

G:\temp\cherry.jpg
C:\windows\zapotec.bmp

Now is the important part : depending on the software where you are going to paste (ctrl-v), results will be totally different :

* If you open Word and paste, then the 2 images will appear (as Water suggested)
* If you open Worpad or Paint, nothing happens when you paste.

So each software reacts differently when you paste in it a list of filenames, a point to remember.

Hope it will be helpful :)

Edited by pixelsearch
Link to comment
Share on other sites

hey, guys, Thanks for your help. Unfortunately, I didn't want to copy image from file to clipboard, but rather to save and retrieve clipboard content - whichever it is - to retrieve it after template is send.

 

  1. User uses hotkey to activate gui
  2. User click button on gui to send corresponding template
  3. Program saves current clipboard content into memory (it can be anything - because, at the time, you don't know what user will be holding in clipboard)
  4. Program sets clipboard to template content (text)
  5. Program sends keystroke CTRL + V to send template
  6. Program retrieves clipboard content that was saved in 3. point

 

I have found this thread with user created function _Clipboard_GetAll() and it seems kinda good for now. Sometimes, unfortunately the Clipboard is not retrieved during test, but it may be because I am testing it too fast. Will try to check it slower to check if it work properly.

The current $Text function is:

Func Text($Text)
    ; Remove saved Clip Content in case it was not removed by any chance before
   $Clip = ""
   Local $Timer = TimerInit()
   While TimerDiff($Timer) < 1000
      _ClipBoard_Open(0)
      ; Copy current clipboard content by using wraithdu script
      _Clipboard_GetAll($Clip)
      _ClipBoard_Close()
      If $Clip Then
         ExitLoop
      Sleep(10)
      EndIf
   WEnd
   ; copying template content to clipboard
   ClipPut($Text)
   ; sending clipboard to other application
   Send("^v")
   ; releasing clipboard content
   _Clipboard_Open(0)
   _Clipboard_Empty()
   _Clipboard_Close()
   ; retrievieng clipboard content
   _ClipBoard_PutAll($Clip)
   $Clip = ""
EndFunc

EDIT: Unfortunately, it crashes or failing at random :'(

Edited by Clear
Link to comment
Share on other sites

Could you try this simple script ?  Seemed to be working fine with me...

#include <Constants.au3>
#include <GUIConstants.au3>
#include <Clipboard.au3>

Opt ("MustDeclareVars", 1)

Global $aClip
_Clipboard_GetAll($aClip)
_ClipBoard_Empty()
_ClipBoard_SetData ("Some text to set clipboard to",$CF_TEXT)
MsgBox (0,"test","Check if clipboard is OK")
_ClipBoard_PutAll($aClip)
Beep ()

Func _Clipboard_GetAll(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

Func _ClipBoard_PutAll(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

 

Link to comment
Share on other sites

1 hour ago, Clear said:

It works almost perfectly (formatted text is retrieved as plain, but it's still very good)

I don't know how to solve this one, glad you like it :)

Link to comment
Share on other sites

@Nine : that's a great function, it works fine, nicely written and fully understandable.
I like how you used the 2D array and the [$iNum+1] so you could store in [0][0] the total of different formats actually in clipboard, and all your future loops will start at 1, that's how I like loops, starting at 1 and not at 0 !

Then all formats/data you stored them in rows 1+  (col 0 for formats, col 1 for data)
Btw, there's still room in [0][1] in case you wanna add something in it (joke) :P
I guess I'm gonna have a look at your other functions, in case they are as nicely written as this one :)

Edited by pixelsearch
Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

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