Win32APIパッケージからFiddleパッケージへの乗り換えようとして、Unicode文字列(WCHAR, LPWSTR, LPCWSTR, OLECHAR, LPOLESTR, LPCOLESTR)を扱う関数、特にAnsi版が存在しないOLE関数周りで文字化けが起きて困っていました。
文字コードについて色々と調べた結果、UTF-16LEへのエンコードが必要だったことが原因だったようです。標準の文字コードは同じUnicodeでもUTF-8形式であり、またUTF-16とだけ指定するとダミーエンコーディングとなるので注意が必要です。
以下、FiddleからMessageBoxA/Wを呼び出して文字化けを確かめるサンプルコードです。
require 'fiddle/import' require 'fiddle/types' module WinAPI extend Fiddle::Importer dlload 'user32.dll' include Fiddle::BasicTypes include Fiddle::Win32Types typealias 'LPCWSTR', 'wchar_t*' extern "int MessageBoxA(HWND, LPCSTR, LPCSTR, DWORD)" extern "int MessageBoxW(HWND, LPCWSTR, LPCWSTR, DWORD)" MB_OK = 0 end require 'pp' s_sjis = 'あいうえお'.encode!('Shift_JIS') s_uni = 'あいうえお'.encode!('UTF-16') s_unibe = 'あいうえお'.encode!('UTF-16BE') s_unile = 'あいうえお'.encode!('UTF-16LE') #エンコーディングの確認 pp [s_sjis, s_uni, s_unibe, s_unile].map {|x| x.encoding} #=>[#<Encoding:Shift_JIS>, # #<Encoding:UTF-16 (dummy)>, # #<Encoding:UTF-16BE>, # #<Encoding:UTF-16LE>] #ANSI版 WinAPI::MessageBoxA(0, s_sjis, 0, WinAPI::MB_OK) #=> OK WinAPI::MessageBoxA(0, s_uni, 0, WinAPI::MB_OK) #=> 文字化け WinAPI::MessageBoxA(0, s_unibe, 0, WinAPI::MB_OK) #=> 文字化け WinAPI::MessageBoxA(0, s_unile, 0, WinAPI::MB_OK) #=> 文字化け #Unicode版 WinAPI::MessageBoxW(0, s_sjis, 0, WinAPI::MB_OK) #=> 文字化け WinAPI::MessageBoxW(0, s_uni, 0, WinAPI::MB_OK) #=> 文字化け WinAPI::MessageBoxW(0, s_unibe, 0, WinAPI::MB_OK) #=> 文字化け WinAPI::MessageBoxW(0, s_unile, 0, WinAPI::MB_OK) #=> OK
確認部分を省くと以下の様なコードとなります。
require 'fiddle/import' require 'fiddle/types' module WinAPI extend Fiddle::Importer dlload 'user32.dll' include Fiddle::BasicTypes include Fiddle::Win32Types typealias 'LPCWSTR', 'wchar_t*' extern "int MessageBoxA(HWND, LPCSTR, LPCSTR, DWORD)" extern "int MessageBoxW(HWND, LPCWSTR, LPCWSTR, DWORD)" MB_OK = 0 end #ANSI版 WinAPI::MessageBoxA(0, 'あいうえお'.encode!('Shift_JIS'), 0, WinAPI::MB_OK) #Unicode版 WinAPI::MessageBoxW(0, 'あいうえお'.encode!('UTF-16LE'), 0, WinAPI::MB_OK)
Win32APIを使用する場合も引数の型を'P'、encode/encode!('UTF-16LE')を使えばUnicode版関数を呼び出すことができます。
require 'Win32API' MessageBoxW = Win32API::new('user32', 'MessageBoxW', 'PPPI', 'I') MessageBoxW.call 0, 'あいうえお'.encode!('UTF-16LE'), 0, 0