I stumbled over a very odd problem: In a Subsystem Windows app,
- call GetClipboardText (a Masm32 library function) to see what's there
- copy something else to the clipboard
- call GetClipboardText again
You will see strange things happen. Full example is attached - look for ShowTheProblem to see where it happens, and how it can be solved.
Needless to say that MSDN is kind of timid about this phenomenon :bg
the clipboard is very finicky
you might test to see if it is empty and what type of data is in it before GetClipBoardData
GetClipboardFormatName
IsClipboardFormatAvailable
QuoteOpenClipboard fails if another window has the clipboard open.
An application should call the CloseClipboard function after every successful call to OpenClipboard.
in the masm32 library function, i see no status test after OpenClipboard
EDIT
did not even see this line - lol
.if rv(IsClipboardFormatAvailable, CF_TEXT)
Dave doesn't do ".if .else .esleif .endif" very well :lol
still, there is no test of OpenClipboard return status
Like Dave recommended, there should be more error checking.
I did note that if an image was in the clipboard, your code opens up the debugger.
invoke OpenClipboard,NULL
.IF (eax)
invoke EmptyClipboard
invoke GlobalAlloc,GMEM_MOVEABLE,SIZEOF str1
.IF (eax)
mov hglb, eax
invoke GlobalLock,hglb
;---------------------
; Pointer now in eax.
;---------------------
invoke MemCopy,ADDR str1,eax,SIZEOF str1
invoke GlobalUnlock,hglb
invoke SetClipboardData,CF_TEXT,hglb
;--------------------------------------------
; System now owns object identified by hglb.
;--------------------------------------------
.IF (eax == 0)
print "SetClipboardData failed",13,10
.ENDIF
.ELSE
print "GlobalAlloc failed",13,10
.ENDIF
invoke CloseClipboard
.ELSE
print "OpenClipboard failed",13,10
.ENDIF
Quote from: Magnum on August 21, 2011, 02:37:14 AM
I did note that if an image was in the clipboard, your code opens up the debugger.
Thanks for spotting this; however that is not exactly
my code, as the thread title says :bg
Try ShowTheProblem = 0 to see correct behaviour, and see the culprit for the image problem below. My version works, and is also considerably shorter. I am working on its MasmBasic implementation (as Clip$());
edit: added 21.8.11, see here (http://www.masm32.com/board/index.php?topic=12460.msg144857#msg144857).
GetClipboardText proc
push ebx
push esi
push edi
; --------------------------------------------------------
; if the return value is not zero, deallocate the returned
; memory handle with GlobalFree() or the macro "free" when
; the data is no longer required.
; --------------------------------------------------------
invoke OpenClipboard,NULL ; open clipboard
.if rv(IsClipboardFormatAvailable,CF_TEXT) != 0 ; if text available
invoke GetClipboardData,CF_TEXT ; get pointer to text
mov ebx, eax
invoke StrLen,eax ; get text length
mov esi, eax
mov edi, alloc(esi) ; allocate that much memory
cst edi, ebx
invoke CloseClipboard ; close the clipboard
mov eax, edi ; return memory handle
jmp bye
.else ; else
xor eax, eax ; set return to zero <<<<<<<<<<<<<<< that comes a bit early ;-) ##########
invoke CloseClipboard ; close the clipboard
jmp bye
.endif
bye:
pop edi
pop esi
pop ebx
ret
GetClipboardText endp
O.K.
Will have to look up cst and see if there is a list of of library functions.
Quote from: Magnum on August 21, 2011, 01:11:30 PM
O.K.
Will have to look up cst and see if there is a list of of library functions.
\masm32\help\masmlib.chm is your friend. And \masm32\macros\macros.asm - there you can reveal the mysteries of cst:
cst MACRO arg1,arg2
invoke szCopy,reparg(arg2),tstarg(arg1)
ENDM
As to the problem mentioned above: GetClpboardText relies on GetClipboardData returning a
pointer. It does, it does... but only if the clipboard got its CF_TEXT content from a
different application. If you copy from the
current app, e.g. from an edit box, GetClipboardData returns a handle that needs GlobalLock. I guess this went unnoticed for a long time because the standard usage of the clipboard is to exchange data between apps. You can test this behaviour with the executable attached on top of thread.
MasmBasic Clip$() (http://www.masm32.com/board/index.php?topic=12460.msg144857#msg144857) uses GlobalLock, which works flawless also on those cases where GetClipboardData already returns a long pointer instead of a handle.
Thanks.