From: Luis Lavena Date: 2010-01-19T12:15:06+09:00 Subject: Re: ffi: How to use wchar_t strings? On Jan 18, 2:06 pm, Marvin Gülker wrote: > Hello, > > I'm trying to use the ffi gem to work with some WinAPI functions. Till > now, I've used the win32-api gem which worked quite well, but I'd like > to try out something new (and maybe easier ;-) ). So, here's my > question: How do I send a Unicode string (encoded in UTF-16LE) to a > WinAPI function? > > This my code: > ------------------------------------- > #Encoding: UTF-8 > require "ffi" > > module Test >   extend FFI::Library > >   ffi_lib "user32" >   ffi_convention :stdcall > >   attach_function :message_box, :MessageBoxW, [:long, :string, :string, > :int], :int > end > > module Test2 >   extend FFI::Library > >   CP_UTF8 = 65001 >   MB_PRECOMPOSED = 0x00000001 > >   ffi_lib "kernel32" >   ffi_convention :stdcall > >   attach_function :get_last_error, :GetLastError, [], :long >   attach_function :multi_byte_to_wide_char, :MultiByteToWideChar, > [:uint, :int, :string, :int, :buffer_out, :int], :int > end > > buffer = "\0" * 100_000 > > #I know, I could use Rubies built-in encoding functions > #and I WILL do so, but for now this is to ensure > #everything is 100% correct as MS it expects. > ret = Test2.multi_byte_to_wide_char(Test2::CP_UTF8, 0, "Test", > "Test".length, buffer, buffer.length) > > buffer.force_encoding("UTF-16LE") > puts buffer.encode("ISO-8859-1").rstrip #Everything correct > > #The following line causes the error: > Test.message_box(0, buffer, buffer, 0) > ------------------------------------- > > This is the error message: > ------------------------------------- > t2.rb:32:in `message_box': string contains null byte (ArgumentError) >   from t2.rb:32:in `
' > ------------------------------------- > > An UTF-16LE encoded string *contains* NUL bytes, I know--but I want to > use Unicode functions, so: How to do that? > I think because :string definition is expecting a Ruby string, not a memory buffer as you're trying to send. wchar_t should be defined as a new type and a proper memory pointer and buffer should be used to marshal the string from Ruby to the C realm :-) I suggest also bring this topic to FFI group: http://groups.google.com/group/ruby-ffi Where you could get better pointers than my vague description. Cheers, -- Luis Lavena