In message "[ruby-list:19218] Re: Clipbord を Ruby で使うには?",
TADA Tadashi <sho / spc.gr.jp> wrote:
>  でも、元の質問だと、Rubyでいじった文字列を、またクリップボードに
> 戻したいようなんですが、これってできるのでしょうか。GlobalAllocで
> 確保した領域に、RubyのStringの内容をコピーするところがわからない。
> ハンドルをGlobalLockしてみても、戻ってきた値は長さが8しかないし(謎)。
> 拡張モジュールを書かないとダメなのかな。

できてるみたいです。私はこんなんで二台のマシンでクリップボード内容の
やりとりをしています。

(clipbrd.rb)
#!/usr/local/bin/ruby

require 'Win32API'

module Clipboard

# Clipboard API
$OpenClipboard = Win32API.new('user32', 'OpenClipboard', ['I'], 'I');
$CloseClipboard = Win32API.new('user32', 'CloseClipboard', [], 'I');
$EmptyClipboard = Win32API.new('user32', 'EmptyClipboard', [], 'I');
$IsClipboardFormatAvailable = Win32API.new('user32', 'IsClipboardFormatAvailable', ['I'], 'I');
$GetClipboardData = Win32API.new('user32', 'GetClipboardData', ['I'], 'I');
$SetClipboardData = Win32API.new('user32', 'SetClipboardData', ['I', 'I'], 'I');
# Predefined Clipboard Formats
CF_TEXT = 1;
CF_BITMAP = 2;
CF_METAFILEPICT = 3;
CF_SYLK = 4;
CF_DIF = 5;
CF_TIFF = 6;
CF_OEMTEXT = 7;
CF_DIB = 8;
CF_PALETTE = 9;
CF_PENDATA = 10;
CF_RIFF = 11;
CF_WAVE = 12;
CF_UNICODETEXT = 13;
CF_ENHMETAFILE = 14;
CF_HDROP = 15;
CF_LOCALE = $10;
CF_MAX = 17;


# memory manager API
$GlobalAlloc = Win32API.new('kernel32', 'GlobalAlloc', ['I','I'], 'I');
$GlobalSize = Win32API.new('kernel32', 'GlobalSize', ['I'], 'I');
$GlobalLock = Win32API.new('kernel32', 'GlobalLock', ['I'], 'P');
$GlobalUnlock = Win32API.new('kernel32', 'GlobalUnlock', ['I'], 'I');
$GlobalFree = Win32API.new('kernel32', 'GlobalFree', ['I'], 'I');

# Global Memory Flags
GMEM_FIXED = 0;
GMEM_MOVEABLE = 2;
GMEM_NOCOMPACT = 0x10;
GMEM_NODISCARD = 0x20;
GMEM_ZEROINIT = 0x40;
GMEM_MODIFY = 0x80;
GMEM_DISCARDABLE = 0x100;
GMEM_NOT_BANKED = 0x1000;
GMEM_SHARE = 0x2000;
GMEM_DDESHARE = 0x2000;
GMEM_NOTIFY = 0x4000;
GMEM_LOWER = GMEM_NOT_BANKED;
GMEM_VALID_FLAGS = 32626;
GMEM_INVALID_HANDLE = 0x8000;

GHND = GMEM_MOVEABLE + GMEM_ZEROINIT;
GPTR = GMEM_FIXED + GMEM_ZEROINIT;

$lstrcpy = Win32API.new('kernel32', 'lstrcpyA', ['P', 'P'], 'P');
$lstrlen = Win32API.new('kernel32', 'lstrlenA', ['P'], 'I');

$lstrcpyIP = Win32API.new('kernel32', 'lstrcpyA', ['I', 'P'], 'P');
$lstrcpyPI = Win32API.new('kernel32', 'lstrcpyA', ['P', 'I'], 'P');
$GlobalLockI = Win32API.new('kernel32', 'GlobalLock', ['I'], 'I');


  def GetText
    result = ""
    if $OpenClipboard.Call(0) != 0
      if (h = $GetClipboardData.Call(CF_TEXT)) != 0
        if (p = $GlobalLock.Call(h)) != 0
          result = p;
          $GlobalUnlock.Call(h);
        end
      end
      $CloseClipboard.Call;
    end
    return result;
  end
  
  def SetText(text)
    if (text == nil) || (text == "")
      return
    end
    if $OpenClipboard.Call(0) != 0
      $EmptyClipboard.Call();
      len = $lstrlen.Call(text);
      hmem = $GlobalAlloc.Call(GMEM_DDESHARE, len+1);
      pmem = $GlobalLockI.Call(hmem);
      $lstrcpyIP.Call(pmem, text);
      $SetClipboardData.Call(CF_TEXT, hmem);
      $GlobalUnlock.Call(hmem);
      $CloseClipboard.Call;
    end
  end
end

include Clipboard;

# sample:
#   require 'clipbrd';
#   print Clipboard.GetText;
#   Clipboard.SetText("aaaaa\nbbbbb\n");

(clipserver.rb)
#!/usr/local/bin/ruby

require 'socket'
require 'clipbrd'
Port = 4445

gs = TCPserver.open(Port)
addr = gs.addr
addr.shift
printf("server is on %d\n", addr.join(":"))

# for ^C trap
Thread.start do
  while TRUE
    print "|\b"; STDOUT.flush
    sleep 1
    print "-\b"; STDOUT.flush
    sleep 1
  end
end

# server thread
while TRUE
  newsc = gs.accept
  #print(newsc, " is accepted\n")
  print(newsc.peeraddr.join(":"), " is accepted\n")
  Thread.start do
    sc = newsc
    #sc.gets
    #print $_; STDOUT.flush
    str = Clipboard.GetText
    #print str; STDOUT.flush
    sc.write(str + "\n")
    sc.close
  end
end

(clipclient.rb)
#!/usr/local/bin/ruby

require 'socket'
require 'clipbrd'
Port = 4445

host=(if ARGV.length == 1; ARGV.shift; else "localhost"; end)
STDERR.print("Trying ", host, " ..."); STDERR.flush
sc = TCPsocket.open(host, Port)
STDERR.print("connect."); STDERR.flush
str = ""
#sc.write("HELLO\n")
while sc.gets
  str = str + $_
end
sc.close
print str
Clipboard.SetText("[#{host}]\n"+str)