[Windows] SetClipboardTextPrivate()

Share your advanced PureBasic knowledge/code with the community.
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

[Windows] SetClipboardTextPrivate()

Post by Little John »

In my current project, I want to offer the user the possibility to copy text to the clipboard in a way, so that it does not appear in the clipboard history or in the cloud clipboard of Windows 10+. This code does the job.

Code: Select all

; Windows only
; tested with PB 5.73 (x64) on Windows 11
; https://www.purebasic.fr/english/viewtopic.php?t=79284

EnableExplicit

Global g_ClipboardHistoryFormat.i = RegisterClipboardFormat_("CanIncludeInClipboardHistory")
Global g_CloudClipboardFormat.i   = RegisterClipboardFormat_("CanUploadToCloudClipboard")


Procedure.i SetClipboardTextPrivate (text$)
   ; -- Copy text to the clipboard in a way, so that it does not appear in the clipboard history or in the cloud clipboard of Windows 10+
   ; in : string to copy
   ; out:  0 on success,
   ;     > 0 on error
   ;
   ; after
   ; - Charles Petzold:
   ;   Programming Windows,
   ;   5th ed. 1998.
   ;   Chapter 12: "The Clipboard"
   ; - https://stackoverflow.com/questions/53190273/bypass-clipboard-history-in-the-windows-10-october-2018-update
   Protected *str, hZeros.i, hString.i, ret.i=0
   
   If Asc(text$) =''
      ProcedureReturn 0  ; success
   EndIf   
   
   hZeros = GlobalAlloc_(#GHND|#GMEM_SHARE, 4)
   If hZeros = #Null
      ProcedureReturn 1
   EndIf   
   
   hString = GlobalAlloc_(#GHND|#GMEM_SHARE, (lstrlen_(text$)+1) * SizeOf(Character))
   If hString = #Null
      GlobalFree_(hZeros)
      ProcedureReturn 2
   EndIf   
   
   *str = GlobalLock_(hString)      ; translate the handle into a pointer
   CopyMemoryString(@text$, @*str)  ; copy the string into the global memory block
   GlobalUnlock_(hString)
   
   If OpenClipboard_(0) = #False
      ret = 3
   Else
      EmptyClipboard_()
      If SetClipboardData_(g_ClipboardHistoryFormat, hZeros) = #Null  ; This hides the text from the clipboard history!
         ret = 4
      EndIf
      If SetClipboardData_(g_CloudClipboardFormat, hZeros) = #Null    ; This prevents upload of the text to the cloud clipboard!
         ret = 5
      EndIf
      If SetClipboardData_(#CF_UNICODETEXT, hString) = #Null
         ret = 6
      EndIf   
      CloseClipboard_()
   EndIf
   
   If ret > 0
      GlobalFree_(hZeros)
      GlobalFree_(hString)
   EndIf
   
   ProcedureReturn ret
EndProcedure


CompilerIf #PB_Compiler_IsMainFile
   Define c$
   
   c$ = Str(Random(9999))
   
   Select SetClipboardTextPrivate(c$)
      Case 0
         MessageRequester("OK", ~"Copied:\n" + c$)
      Case 1
         MessageRequester("Error", "Can't allocate 4 zero bytes in global memory.")
      Case 2
         MessageRequester("Error", "Can't allocate global memory for the string.")
      Case 3
         MessageRequester("Error", "Can't open the clipboard.")
      Case 4
         MessageRequester("Error", "Can't write data in ClipboardHistory format.")
      Case 5
         MessageRequester("Error", "Can't write data in CloudClipboard format.")
      Case 6
         MessageRequester("Error", "Can't put the string into the clipboard.")
   EndSelect
CompilerEndIf
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5342
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: [Windows] SetClipboardTextPrivate()

Post by Kwai chang caine »

Works perfect here :D
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Windows] SetClipboardTextPrivate()

Post by Little John »

Hi KCC, thanks for the feedback! :)
Little John
Addict
Addict
Posts: 4519
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [Windows] SetClipboardTextPrivate()

Post by Little John »

Going one step further, we can remove our text from the clipboard after some seconds.
The following procedure CopyTemp() is useful e.g. for temporarily copying a password to the clipboard.

Code: Select all

; Windows only
; tested with PB 6.00 (x64) on Windows 11
; https://www.purebasic.fr/english/viewtopic.php?p=586400#p586400

EnableExplicit

Global g_ClipboardHistoryFormat.i = RegisterClipboardFormat_("CanIncludeInClipboardHistory")
Global g_CloudClipboardFormat.i   = RegisterClipboardFormat_("CanUploadToCloudClipboard")


Procedure.i SetClipboardTextPrivate (text$)
   ; -- Copy text to the clipboard in a way, so that it does not appear in the clipboard history or in the cloud clipboard of Windows 10+
   ; in : string to copy
   ; out:  0 on success,
   ;     > 0 on error
   ;
   ; after
   ; - Charles Petzold:
   ;   Programming Windows,
   ;   5th ed. 1998.
   ;   Chapter 12: "The Clipboard"
   ; - https://stackoverflow.com/questions/53190273/bypass-clipboard-history-in-the-windows-10-october-2018-update
   Protected *str, hZeros.i, hString.i, ret.i=0
   
   If Asc(text$) =''
      ProcedureReturn 0  ; success
   EndIf   
   
   hZeros = GlobalAlloc_(#GHND|#GMEM_SHARE, 4)
   If hZeros = #Null
      ProcedureReturn 1
   EndIf   
   
   hString = GlobalAlloc_(#GHND|#GMEM_SHARE, (lstrlen_(text$)+1) * SizeOf(Character))
   If hString = #Null
      GlobalFree_(hZeros)
      ProcedureReturn 2
   EndIf   
   
   *str = GlobalLock_(hString)      ; translate the handle into a pointer
   CopyMemoryString(@text$, @*str)  ; copy the string into the global memory block
   GlobalUnlock_(hString)
   
   If OpenClipboard_(0) = #False
      ret = 3
   Else
      EmptyClipboard_()
      If SetClipboardData_(g_ClipboardHistoryFormat, hZeros) = #Null  ; This hides the text from the clipboard history!
         ret = 4
      EndIf
      If SetClipboardData_(g_CloudClipboardFormat, hZeros) = #Null    ; This prevents upload of the text to the cloud clipboard!
         ret = 5
      EndIf
      If SetClipboardData_(#CF_UNICODETEXT, hString) = #Null
         ret = 6
      EndIf   
      CloseClipboard_()
   EndIf
   
   If ret > 0
      GlobalFree_(hZeros)
      GlobalFree_(hString)
   EndIf
   
   ProcedureReturn ret
EndProcedure



#WinMain = 0
#ClipboardTimer = 0

; Gadgets
Enumeration
   #Edit
   #BtnCopy
EndEnumeration

Define s_TempText$=""

Procedure.i CopyTemp (text$, timeout.i)
   ; -- Copy 'text$' privately and temporarily to the clipboard
   ; - The text does not appear in the clipboard history of Windows 10+.
   ; - The text does not appear in the cloud clipboard of Windows 10+.
   ; - The text will be removed from the clipboard after 'timeout' milliseconds.
   ; - The text will be removed from the clipboard when the program is terminated.
   ;
   ; return value:  0 on success,
   ;              > 0 on error
   Shared s_TempText$
   Protected ret.i
   
   If Asc(s_TempText$) <> ''
      RemoveWindowTimer(#WinMain, #ClipboardTimer)
   EndIf   
   ret = SetClipboardTextPrivate(text$)
   s_TempText$ = text$
   AddWindowTimer(#WinMain, #ClipboardTimer, timeout)
   
   ProcedureReturn ret
EndProcedure


Procedure ClearTemp ()
   Shared s_TempText$
   
   If GetClipboardText() = s_TempText$  ; Don't clear the clipboard if any other
      ClearClipboard()                  ; text was copied to it in the meantime.
   EndIf
   s_TempText$ = ""
   RemoveWindowTimer(#WinMain, #ClipboardTimer)
EndProcedure


Define Event.i

OpenWindow(#WinMain, 0, 0, 360, 200, "CopyTemp() example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
EditorGadget(#Edit, 10, 10, 340, 100)
SetGadgetText(#Edit, "Confidential text")
ButtonGadget(#BtnCopy, 10, 160, 200, 25, "Copy for 10 sec. to the clipboard")

Repeat
   Event = WaitWindowEvent()
   
   Select Event
      Case #PB_Event_Gadget
         If EventGadget() = #BtnCopy
            If CopyTemp(GetGadgetText(#Edit), 10000) > 0
               MessageRequester("CopyTemp()", "Error copying text to the clipboard.")
            EndIf   
         EndIf
         
      Case #PB_Event_Timer 
         If EventTimer() = #ClipboardTimer
            ClearTemp()
         EndIf   
   EndSelect
Until Event = #PB_Event_CloseWindow

If Asc(s_TempText$) <> ''
   ClearTemp()
EndIf
Post Reply