Setting the clipboard

I want to realize the function of setting the clipboard,However, after using the following operations, the SketchUp will crash.I can’t find the reason.

          @openClipboard = Win32API.new("user32", "OpenClipboard", ["I"], "I")
          @setClipboard = Win32API.new("user32", 'SetClipboardData', ["I", "P"], "V")
          @emptyClipboard = Win32API.new("user32", "EmptyClipboard", [], "I")
          @closeClipboard = Win32API.new("user32", "CloseClipboard", [], "I")
          @openClipboard.call(0)
          @emptyClipboard.call()
          @setClipboard.call(1, "set clipboard data")
          @closeClipboard.call()

I have not debugged why your attempt crashes, … however the following which uses the "clip.exe" utility supplied with Windows since Win7 will work …

module SomeAuthor # <---<<< replace with YOUR toplevel namespace

  require 'win32ole'

  module Clip

    extend self

    def set_text(text)
      unless text.respond_to?(:to_s)
        fail(TypeError, "String or coercible argument expected.", caller)
      end
      begin
        text = text.to_s unless text.is_a?(String)
      rescue => err
        puts 'Error with clipboard text argument:'
        puts err.inspect
        raise
      else
        # Put text into the clipboard:
        shell = WIN32OLE.new('WScript.Shell')
        clip  = shell.Exec('clip')
        clip_input = clip.stdIn()
        clip_input.WriteLine(text)
        clip_input.Close()
        clip.Terminate()
      end
    end

  end # Clip library module

end # author toplevel namespace

FYI: "clip.exe" is in the File.join(ENV['WINDIR'], 'System32') directory so it should already be in the ENV['PATH'] search list.

REF:

NOTE: I am reading online that "clip.exe" expects input text to be
encoded as UTF-16 LE (with Bit Order Mark if the input is a file.)
So if using any other characters than the low set of ASCII characters
then the text may need to be transcoded. See Ruby’s Encoding class.

Here is another Ruby solution that may work for both Windows and Mac:

  require "open3"

  def clipboard(text)
    cmd =( Sketchup.platform == :platform_win ? 'clip' : 'pbcopy' )
    Open3.popen2(cmd) { |input, output, waiter|
      begin
        input.write( text )
      rescue Errno::EPIPE => err
        puts err.inspect
      ensure
        input.close
      end
    }
  end
1 Like

Thank you very much for your answer. I will try your method.

I’m sorry that I didn’t describe the clearing problem, SketchUp will crash in a few minutes, not immediately.

I have used this method before, but there will be a black window flashing. I didn’t find a solution, so I gave up. Do you have any good ways to hide the black window

I do not know of any easy way to prevent shell windows from showing on Windows platform.
On my machine it must happen so fast that I do not notice it.

Yes, I also noticed this when testing the Windows API C calls paradigm.

By the way, the clipboard expects the text data to be terminated with a NULL character …

text << "\0"

I will guess that the crash may be an issue where Ruby attempts to release the memory used by the text data, but the system really owns it after it is pushed onto the clipboard.


Note: The "Win32API.rb" wrapper class file will be going away in Ruby 3.x, so you should migrate to using the Fiddle class for making C calls.

@thomthom has already posted an example using Fiddle that creates a globally allocated string object which Ruby should not fight over …

See: ruby-fiddle-examples/clipboard.rb at master · thomthom/ruby-fiddle-examples · GitHub

1 Like

Indeed, as the documentation for SetClipboardData says, the system takes ownership of the object identified by hMem: SetClipboardData function (winuser.h) - Win32 apps | Microsoft Learn

Therefore passing in data owned by Ruby won’t work, you need to allocate memory that Ruby doesn’t try to fight for ownership. (As in my example Dan linked to.)

For these Win32 APIs it often useful to look at examples in C/C++ before porting to Ruby. In particular when dealing with passing data around like this.

1 Like

Thank you for your help. This method is very useful

I encountered some problems when using this method. After I changed the parameters (as shown below), I put them into Chinese, and pasted them with shortcut keys instead of interfaces

User32::SetClipboardData(13, mem)

This code is in line 220,in the link

For general readership information, the ID integer 13 is the value of the constant CF_UNICODETEXT in the Windows API. (See Standard Clipboard Formats.)

Unicode on Windows platform expects the encoding to be UTF-16LE.

But Ruby in SketchUp uses UTF-8 encoded strings, so I would think that you will need to transcode the string from UTF-8 to UTF-16LE before sending it to the clipboard.

Clipboard.text= utf8_string.encode(Encoding::UTF_16LE)

Or … you could insert a statement at line 195 such as:

clipboard_text = clipboard_text.encode(Encoding::UTF_16LE)

This must be done before the buffer size is set.

Oh,I see. Thank you very much for your help