windowsdelphiwinapiclipboard

How can I copy something to the Clipboard without it showing up in the history?


When I copy something onto the clipboard, it shows up in the Clipboard history (Win+V). And with Windows 10 and Windows 11, it also syncs the clipboard with the cloud and other devices.

When I copy sensitive data onto the clipboard (like a password), I don't want it to show up in the history, and I don't want Windows to sync it to other devices.

How can I manage to do that?


Solution

  • You can not only put Text on the clipboard, but all kind of different types of data. It's like a Multi-Part-Message in an EMail, where you can have the mail in plain text and in HTML format.

    There are many default Clipboard types that are known to Delphi. And on Windows 10 and later, the Cloud Clipboard has 3 new Clipboard types that are not represented by ID but per Name, such as "ExcludeClipboardContentFromMonitorProcessing":

    https://learn.microsoft.com/en-us/windows/win32/dataxchg/clipboard-formats

    You have to declare these 3 new types yourself and set them if you copy sensitive data.

    I wrote a TClipboard helper so it is easier to handle. It adds a SetTextWithoutHistory() method.

    Here is the helper:

    unit vcl.Clipbrd.sec;
    
    interface
    
    uses
      Windows, Clipbrd, SysUtils;
    
    
    type
      TClipboardSec = class helper for TClipboard
      public
        procedure SetTextWithoutHistory(const Value: string);
        property AsTextWithoutHistory : string write SetTextWithoutHistory;
      end;
    
    
    implementation
    
    var
      dwNo : DWORD;
      dwYes: DWORD;
      CF_ExcludeClipboardContentFromMonitorProcessing : UINT;
      CF_CanIncludeInClipboardHistory: UINT;
      CF_CanUploadToCloudClipboard: UINT;
    
    procedure TClipboardSec.SetTextWithoutHistory(const Value: string);
    begin
      Open;
      try
        Adding;
    
        SetBuffer(CF_ExcludeClipboardContentFromMonitorProcessing, dwYes, sizeOf(DWORD) );
        SetBuffer(CF_CanIncludeInClipboardHistory, dwNo, sizeOf(DWORD) );
        SetBuffer(CF_CanUploadToCloudClipboard, dwNo, sizeOf(DWORD));
    
        SetBuffer(CF_UNICODETEXT, PChar(Value)^, ByteLength(Value) + SizeOf(Char));
      finally
        Close;
      end;
    
    end;
    
    
    initialization
      dwNo  := 0;
      dwYes := 1;
    
      CF_ExcludeClipboardContentFromMonitorProcessing := RegisterClipboardFormat('ExcludeClipboardContentFromMonitorProcessing');
      if CF_ExcludeClipboardContentFromMonitorProcessing = 0
        then RaiseLastOSError;
    
      CF_CanIncludeInClipboardHistory := RegisterClipboardFormat('CanIncludeInClipboardHistory');
      if CF_CanIncludeInClipboardHistory = 0
        then RaiseLastOSError;
    
      CF_CanUploadToCloudClipboard := RegisterClipboardFormat('CanUploadToCloudClipboard');
      if CF_CanUploadToCloudClipboard = 0
        then RaiseLastOSError;
    finalization
    end.
    

    I hope it helps someone.

    I needed a long time to figure it out.