GetClipboardData and problem with Masm32 GetClipboardText

Started by jj2007, August 20, 2011, 09:50:49 PM

Previous topic - Next topic

jj2007

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

dedndave

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

Magnum

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

Have a great day,
                         Andy

jj2007

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.

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

Magnum

O.K.

Will have to look up cst and see if there is a list of of library functions.

Have a great day,
                         Andy

jj2007

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$() uses GlobalLock, which works flawless also on those cases where GetClipboardData already returns a long pointer instead of a handle.

Magnum

Have a great day,
                         Andy