Win32API, clipboard, unicode issue


#1

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