2012年6月10日日曜日

FFIを利用してWindows上でメッセージボックスを表示する

FFI(Foreign Function Interface)を利用して、Windows上でメッセージボックスを表示してみます。

注意点
  • APIにはAscii用のMessageBoxAとUnicode用のMessageBoxWがある
  • Unicodeの符号化形式はUTF-16LE

Common Lisp

FFIは処理系依存です。各処理系の差異を吸収してくれる、CFFIというライブラリがあります。 CFFIはQuicklispでインストール可能です。 文字列のエンコードを直接指定しない場合は, cffi:*default-foreign-encoding* に設定されている値が利用されます。
;; ffi-test.lisp
(asdf:load-system :cffi)

(defpackage :ffi-test
  (:use :cl :cffi)
  (:export message-box))

(in-package :ffi-test)

(load-foreign-library "user32.dll")

(defcfun ("MessageBoxW" message-box) :int32
  (hWnd :pointer)
  (lpText (:string :encoding :utf-16le))
  (lpCaption (:string :encoding :utf-16le))
  (uType :uint))
> (load "ffi-test.lisp")
> (ffi-test:message-box (cffi:null-pointer) "hello" "わーるど" 0)
または
(cffi:foreign-funcall 
   "MessageBoxW"
   :pointer (cffi:null-pointer)
   (:string :encoding :utf-16le) "hello"
   (:string :encoding :utf-16le) "わーるど"
   :uint 0
   :int32)

Racket

Racketではffi/unsafeライブラリを利用すればよさそうです。
#lang racket
;; ffi-test.rkt
(require ffi/unsafe)
(provide message-box)

(define user32 "user32.dll")

(define message-box
  (get-ffi-obj
   "MessageBoxW" user32
   (_fun _pointer
  _string/utf-16
  _string/utf-16
  _uint32
  -> _int32)
   #f))
> (load "ffi-test.rkt")
> (require 'ffi-test)
> (message-box #f "hello" "わーるど" 0)

Ruby

RubyでWindowsのDLLの関数を呼び出すには、Win32APIライブラリを利用すればよさそうです。
# -*- coding: utf-8 -*-
require "Win32API"
require "nkf"

class String
  def to_utf16le
    NKF.nkf("-w16L0", self)
  end
end

msgbox = Win32API.new('user32', 'MessageBoxW', %w(p p p i), 'i')
msgbox.call(0, "hello".to_utf16le, "わーるど".to_utf16le, 0)

Python

Pythonではctypesライブラリを利用すればよさそうです。
# -*- coding: utf-8 -*-
import ctypes

user32 = ctypes.windll.user32

user32.MessageBoxW(None, "hello", "わーるど", 0)

0 件のコメント:

コメントを投稿