From: "Berger, Daniel" Date: 2006-02-15T01:13:26+09:00 Subject: Win32API, clipboard, unicode issue Hi all, I'm trying to resolve a unicode issue that I'm having some trouble dealing with. The problem, in short, is that some unicode values contain embedded nulls (e.g. the Tibetan 0x0F00), and that's causing data truncation in the call to GetClipboardData(), even when UNICODETEXT is used as a format specifier. Note that *setting* data works fine. It's *getting* data that's failing. Below is the relevant code, along with a sample program at the end. If you run the program and paste the results (via Ctrl-V) into a modern text editor (MS Word, OOO, whatever), you should see 3 characters. However, if you try to pull that data back out via Clipboard.get_data, you'll end up with a length two string. Any ideas? Regards, Dan require "Win32API" module Win32 class ClipboardError < StandardError; end class Clipboard # Clipboard data types TEXT = 1 OEMTEXT = 7 UNICODETEXT = 13 # Alloc constants GMEM_MOVEABLE = 0x0002 GMEM_ZEROINIT = 0x0040 GHND = GMEM_MOVEABLE | GMEM_ZEROINIT # Clipboard specific functions @@OpenClipboard = Win32API.new( 'user32', 'OpenClipboard', ['L'], 'I' ) @@CloseClipboard = Win32API.new( 'user32', 'CloseClipboard', [], 'I' ) @@GetClipboardData = Win32API.new( 'user32', 'GetClipboardData', ['I'], 'P' ) @@SetClipboardData = Win32API.new( 'user32', 'SetClipboardData', ['I', 'I'], 'I' ) @@EmptyClipboard = Win32API.new( 'user32', 'EmptyClipboard', [], 'I' ) # Generic Win32 functions @@GlobalAlloc = Win32API.new('kernel32','GlobalAlloc',['I','I'],'I') @@GlobalLock = Win32API.new('kernel32','GlobalLock',['I'],'I') @@GlobalFree = Win32API.new('kernel32','GlobalFree',['I'],'I') @@memcpy = Win32API.new('msvcrt', 'memcpy', ['I', 'P', 'I'], 'I') def self.open if 0 == @@OpenClipboard.call(0) raise ClipboardError, "OpenClipboard() failed" end end def self.close @@CloseClipboard.call end # Sets the clipboard contents to the data that you specify. You may # optionally specify a clipboard format. The default is Clipboard::TEXT. def self.set_data(clip_data, format = TEXT) self.open @@EmptyClipboard.call # NULL terminate text case format when TEXT, OEMTEXT, UNICODETEXT clip_data << "\0" end # Global Allocate a movable piece of memory. hmem = @@GlobalAlloc.call(GHND, clip_data.length + 4) mem = @@GlobalLock.call(hmem) @@memcpy.call(mem, clip_data, clip_data.length) # Set the new data if @@SetClipboardData.call(format, hmem) == 0 @@GlobalFree.call(hmem) self.close raise ClipboardError, "SetClipboardData() failed" end @@GlobalFree.call(hmem) self.close self end # Returns the data currently in the clipboard. If 'format' is # specified, it will attempt to retrieve the data in that format. The # default is Clipboard::TEXT. def self.data(format = TEXT) clipdata = "" self.open begin clipdata = @@GetClipboardData.call(format) rescue ArgumentError # Assume failure is caused by no data in clipboard end self.close clipdata end # An alias for Clipboard.data. def self.get_data(format = TEXT) self.data(format) end # Empties the contents of the clipboard. def self.empty self.open @@EmptyClipboard.call self.close self end end end require 'win32/clipboard' include Win32 def unicopy(hex_name_array) Clipboard.set_data(win32unicode(hex_name_array),Clipboard::UNICODETEXT) true end def extract_flipped_bytes(unicode_char_string) unicode_char_string[0,2].to_i(16) end def win32unicode(unicode_char_strings) flipped_bytes = unicode_char_strings.collect do |str| extract_flipped_bytes(str) end flipped_bytes.flatten.pack('C*') end puts unicopy(%w{ 0401 0400 0402 }) p Clipboard.get_data