Opened 16 years ago
Closed 16 years ago
#1028 closed Bug (Fixed)
_ClipBoard_GetData does not work properly
Reported by: | Ascend4nt | Owned by: | Jpm |
---|---|---|---|
Milestone: | 3.3.1.2 | Component: | AutoIt |
Version: | 3.3.0.0 | Severity: | None |
Keywords: | Cc: |
Description
In working with _ClipBoard_GetData() and looking at the code (in Clipboard.au3), I've noticed some major flaws with it (AutoIT version 3.3.0.0):
- Unicode text will not be returned (at all)
- An arbitrary limit is placed on the ANSI/OEM text to be returned (8192 chars)
- The Clipboard is closed before the data is transferred. (From the source code I've reviewed, this is not good form)
- The Global memory isn't locked for anything but ANSI/OEM text
- Returning any other data types then the 3 it handles will result in a Global memory handle being returned (*not* locked)
With my code, I went ahead and fixed all of the above, and used the _MemMoveMemory() function to transfer memory to an AutoIT structure for only the 'unknown' data types. (The rest can be obtained quite easily).
Also: one enhancement: The size of the data is returned in @extended, and is in chars for CF_TEXT, CF_OEMTEXT, and CF_UNICODETEXT, or in bytes for any other data type.
I don't know the method for submitting the fixed code or extra documentation (regarding @extended), so please let me know what else I should do.
Fixed code is attached.
Attachments (2)
Change History (14)
Changed 16 years ago by Ascendant
comment:1 Changed 16 years ago by Valik
This code is wrong:
$tData = DllStructCreate("ubyte[" & $iDataSize & "]",$pMemoryBlock) $pMemoryDest = DllStructGetPtr($tData) ; Copy the memory over to our newly created structure so that we can unlock the memory _MemMoveMemory($pMemoryBlock, $pMemoryDest , $iDataSize) $vReturn = DllStructGetPtr($tData)
You initialized the structure with the pointer to the memory block. That means nothing was allocated. You are copying the data onto itself.
comment:2 Changed 16 years ago by Ascend4nt
Wow, you're totally right. I actually had messed around with a few ways of doing that, one of which was trying to copy between two DLLStructs using _MemMoveMemory(), but I wound up leaving a piece of that code in when reverting back to a regular memory move.
Here's the problem now: when changing the above back to this, I get a missing-data problem (memory isn't transferred):
$tData = DllStructCreate("ubyte[" & $iDataSize & "]") $pMemoryDest = DllStructGetPtr($tData) ; Copy the memory over to our newly created structure so that we can unlock the memory _MemMoveMemory($pMemoryBlock, $pMemoryDest , $iDataSize) $vReturn = DllStructGetPtr($tData)
For example, try modifying that code, and doing this (with a small amount of HTML text copied from a browser):
Local $pPointer=_ClipBoard_GetDataFixed(49342) Local $iDataSize=@extended Local $stStruct=DllStructCreate("char["&$iDataSize&"]",$pPointer) MsgBox(0,"HTML",DllStructGetData($stStruct,1))
It works only when I put that part I screwed up back into place. Hmm.. I wonder what's going on. I'll have to dig deeper. Thanks for catching that.
comment:3 Changed 16 years ago by Ascend4nt
From further testing, it appears that the actual _MemMoveMemory() copy does work, I've tested the data *inside* the function (after unlocking, closing the clipboard, and invalidating pointers) and it is perfectly fine. However, once the program exits, the DLLStructPtr that is returned becomes invalid.
I've resorted to returning the entire DLLStruct that was created for now, which works - but makes it a little more difficult for users to understand.
Is there a way to keep the DLLStruct memory active without resorting to Global variables? I thought perhaps you kept an internal reference count before you would destroy that memory.
Thanks
comment:4 Changed 16 years ago by Valik
A pointer is just a number. There is nothing special about it. You must return the DllStruct itself. You can't return the pointer and hope that does something because it can't and shouldn't.
comment:5 Changed 16 years ago by Ascend4nt
So do you recommend this method of returning a DLLStruct for non-text Clipboard types? This may break existing code, which I'd hate to do - but I already pointed out that the function is barely working as it is, and not doing the 'Get' properly. The change in return value would also confuse users, plus the Help info would need to be adjusted. Should I discuss this with GaFrost, since he appears to be the one handling UDF's? Or should I just post the modified code?
thanks
comment:6 Changed 16 years ago by Valik
Shouldn't the data be returned? Why does a pointer or a structure have to be returned at all? AutoIt supports binary data so the data returned will either be a string or a binary string.
comment:7 Changed 16 years ago by Ascen4nt
That would make sense, except I don't know an efficient way to grab the data and put it into a binary form. I might be not seeing something obvious though, because I have only gotten data into DLLStructs where you can only grab 1 byte at a time (for binary/unknown data) using DLLStructGetData, so it would require a type of For..Next loop to get each and every byte, which can be a long process for large amounts of data. Is there another way that I'm not seeing though?
comment:8 Changed 16 years ago by Valik
Case Else $tData = DllStructCreate("ubyte[" & $iDataSize & "]",$pMemoryBlock) $vReturn = DllStructGetData($tData)
comment:9 Changed 16 years ago by Ascend4nt
Dang, what the heck was I doing before that I was only getting one byte of data back at a time? I had that happen like last year or something, and have avoided trying to work with DLLStruct's with binary data as much as possible since then. Now that I just tested it however, it's fine. Live and learn! I'll attach a new version right away ('Fix2').
By the way, the HTML 'get' example I had above can now be changed to:
Local $vClipData=_ClipBoard_GetDataFixed(49342) MsgBox(0,"HTML",BinaryToString($vClipData))
The other versions test fine as well:
MsgBox(0,"ANSI Text",_ClipBoard_GetDataFixed($CF_TEXT)) MsgBox(0,"OEM Text",_ClipBoard_GetDataFixed($CF_OEMTEXT)) MsgBox(0,"Unicode",_ClipBoard_GetDataFixed($CF_UNICODETEXT))
Thanks, Valik
comment:10 follow-up: ↓ 11 Changed 16 years ago by anonymous
Darn, I forgot to remove one piece of code. Is it possible for someone to just pull this piece out:
; Reset Global structure, releast memory $_stClipGetStruct = 0
comment:11 in reply to: ↑ 10 Changed 16 years ago by Jpm
Replying to anonymous:
Darn, I forgot to remove one piece of code. Is it possible for someone to just pull this piece out:
; Reset Global structure, releast memory $_stClipGetStruct = 0
Done
comment:12 Changed 16 years ago by Jpm
- Milestone set to 3.3.1.2
- Owner set to Jpm
- Resolution set to Fixed
- Status changed from new to closed
Fixed in version: 3.3.1.2
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.
_ClipBoard_GetData (fixed) function