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