Modify

Opened 10 years ago

Closed 6 years ago

#1368 closed Bug (Rejected)

_ClipBoard_GetData($CF_BITMAP) not working on 3.3.2.0

Reported by: eukalyptus Owned by: Valik
Milestone: Component: Standard UDFs
Version: 3.3.2.0 Severity: None
Keywords: _ClipBoard_GetData $CF_BITMAP Cc:

Description

this code workes fine on AutoIt 3.3.0.0, but returns zero (no hbitmap-handle) on Autoit 3.3.2.0!

#Include <Clipboard.au3>
Send("{PRINTSCREEN}")
Sleep(1000)
$hBitmap=_ClipBoard_GetData($CF_BITMAP)
ConsoleWrite("hBitmap: " & $hBitmap & @LF)

Attachments (0)

Change History (8)

comment:1 Changed 10 years ago by Valik

I've just spent awhile debugging this. Here's what I've concluded:

  • The reason the function fails is due to the call to _MemGlobalLock() returning error 6 (Invalid handle) when used on the handle returned for $CF_BITMAP.
  • I think the reason _MemGlobalLock() is failing is because rather than a handle to global memory I believe the handle is actually an HBITMAP.

The difference's between 3.3.0.0 and 3.3.2.0 are:

  • In 3.3.0.0 _Clipboard_GetData() returned the handle that GetClipboardData() returned. This is not safe. Once the clipboard data changes that handle becomes invalid or points to different data entirely. This could actually lead to an application crash.
  • In 3.3.2.0 _Clipboard_GetData() tries to copy the data and returns the copy. However, not all of the data is stored in the same way so the generic code fails on certain data formats.

The key problem is: _Clipboard_GetData() is doing too much. It was designed to handle opening and closing the clipboard for the user and was supposed to do the right thing. Except it's pretty much a failure since it doesn't know what the right thing is. _Clipboard_GetData() needs to be a thin wrapper around GetClipboardData() and not try anything fancy. Right now the thin wrapper is actually at _Clipboard_GetDataEx(). These functions should have been swapped from the beginning to match the API and the standard convention of "Ex" functions doing more.

As it stands the solution is to make _Clipboard_GetData() a thin wrapper meaning to use it you will have to manually call _Clipboard_Open() and _Clipboard_Close(). Then _Clipboard_GetDataEx() can be modified to provide custom handling for specific formats (for example, it's trivial to open the clipboard, retrieve text into a buffer and close the clipboard returning the text).

In short, the fix for this is likely to be swapping _Clipboard_GetData() and _Clipboard_GetDataEx() and _Clipboard_GetDataEx() will only work with a few clipboard formats that have common actions (like the above text example).

comment:2 Changed 9 years ago by Jpm

as swapping the function will be a script breaking, I don't think we will swap them.
in this specifice report we can just document that _Clipboard_GetDataEx($CF_BITMAP)
is the right thing to do if you really want to use the HBITMAP handle

comment:3 Changed 9 years ago by Valik

So let me get this straight, you don't want to fix a fundamentally broken function because it will break scripts (that are already broken)? Your logic continues to astound and amaze me.

comment:4 Changed 9 years ago by Jpm

What your suggestion to fix it

comment:5 follow-up: Changed 9 years ago by Jpm

  • Owner set to Valik
  • Status changed from new to assigned

comment:6 in reply to: ↑ 5 Changed 9 years ago by len.vaz@…

Replying to Jpm:

I am using GetClip() in 3.3.6.1 and it always returns empty. Under the covers it is probably calling _Clipboard_GetData(), maybe... I have seen people doing some pretty wild stuff to get it working. This is what i did and i get the data back immediately. Seems like a particular windows message activates it. Here is the code I am using that works for me and hopefully it helps fix this issue. Moving the mouse off the active window seems to do the trick.

def getTextFromActiveWindow(self, titleOfBrowser):

self.myauto.ClipPut("")
url = ""
counter = 0


while counter < 10:

self.runWaitAuto("activateWindow.exe " + titleOfBrowser)
self.myauto.Sleep(250)
self.myauto.Send("!d")
self.myauto.Sleep(250)
self.myauto.Send("c")
self.myauto.Sleep(250)
if self.myauto.ClipGet() <> "":

url = self.myauto.ClipGet()
return( url )


self.myauto.MouseMove(700, 500, 5)
self.myauto.Sleep(1000)
self.myauto.MouseMove(0, 0, 5)
self.myauto.Sleep(1000)
counter = counter + 1

comment:7 Changed 8 years ago by Jon

  • Component changed from AutoIt to Standard UDFs

comment:8 Changed 6 years ago by Jon

  • Resolution set to Rejected
  • Status changed from assigned to closed

Guidelines for posting comments:

  • You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
  • In-depth discussions should take place on the forum.

For more information see the full version of the ticket guidelines here.

Add Comment

Modify Ticket

Action
as closed The owner will remain Valik.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.