パスワードを忘れた? アカウント作成
14263088 journal
Windows

route127の日記: Perl+Win32::APIでウィンドウ生成 3

日記 by route127

PerlでWin32::APIを使っていてふとGUIを作りたくなって学生の頃VCでGUI書こうとして挫折したことを思い出した。
それ以降、中途半端にTkとか使ったことはあっても真面目にGUIに取組んだことはなかった。

Win32::GUIを使えばGUIは作れるはずだがWin32::APIのみでも不可能ではなかろうと古本屋で買ったWin32APIリファレンスとcpan、VB6やDelphi時代のHPなどを見ながらやっとウィンドウを出せた。
面倒臭かったところ:

1. Importかnewか …newの書式はVB寄り、ImportはC寄り
2. hInstance …Cと違ってGetModuleHandleを使って自分で取ってくる
3. 引数の型 …VB向けの書式を参考に
4. 定数(WM_*、) …いちいち調べるの面倒
5. 構造体 …Win32::Structを使う

Cによるウィンドウ生成メッセージループを参考にした。
メッセージループを回すのにGetMessageが引数にMSG構造体を取るが、それをWin32::API::Structで書き下す必要があった。
cpanのWin32::API::StructにPOINT構造体の例があるので参考にした。
MSG構造体はPOINT構造体を含むが、こういった、Win32::API::Structが入れ子が許されるのか不安だったが特に問題は生じなかった。

メッセージの実体である整数値(例えばWM_LBUTTONUPは0x0202)についてもCのようにwinuser.h等のヘッダファイルを参照できないのでスクリプト中にベタ書きしていた。

use strict;
use warnings;
use Win32::API;
 
my $GetModuleHandle = Win32::API->new('kernel32', 'GetModuleHandleA', 'N', 'N');
my $hInstance = $GetModuleHandle->Call(0);
 
use constant WS_CAPTION => hex('C00000');
my $CreateWindow = Win32::API->new('user32', 'CreateWindowExA', 'NPPNIIIINNNN', 'N');
my $hWnd = $CreateWindow->Call(0, 'BUTTON', 'Hello', WS_CAPTION, 100, 100, 200, 200, 0, 0, $hInstance, 0);
die if $hWnd==0;
 
use constant SW_SHOW => hex('5');
my $ShowWindow = Win32::API->new('user32', 'ShowWindow', 'NN', 'N');
$ShowWindow->Call($hWnd, SW_SHOW);
 
Win32::API::Struct->typedef( POINT => qw{
  LONG x;
  LONG y;
});
 
Win32::API::Struct->typedef( MSG => qw{
  LONG hWnd;
  UINT message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD time;
  POINT pt
});
my $lpMsg = Win32::API::Struct->new('MSG');
 
use constant WM_LBUTTONUP => hex('202');
my $GetMessage = Win32::API->new('user32', 'GetMessageA', 'SNNN', 'N');
my $DispatchMessage = Win32::API->new('user32', 'DispatchMessageA', 'S', 'N');
 
while(1){
  $GetMessage->Call($lpMsg, 0, 0, 0);
  #die $lpMsg->{message};
  last if ($lpMsg->{message} eq WM_LBUTTONUP);
  $DispatchMessage->Call($lpMsg);
}

Win32APIと定数の定義をまとめたりして清書すればよかったかと思ったが臨場感重視で。

  • 「あ、これプログラミングWindows(上)で見たやつだ!」って感じるくらいエンシャント成分たっぷりですね。
    この抽象度で本格的なメッセージ処理をswitchステートメントのないperlで始めたら一体どうなってしまうんです?
    もしかしてこれがSwitchモジュールができた経緯だったり?

    # そんなもんモジュールで実装すんなよって昔から思ってた。
    # そしてどうせモジュール実装だったらRustのmatch相当品実装しとけ。
    # なんでモジュール実装したswitchすらC言語的switch止まりなんや。

    ここに返信
    • by Anonymous Coward

      別にtk_messageBoxが偉いわけじゃなくてほぼMessageBox APIをラップしてるだけじゃん。関数1つ呼び出すだけならWin32::APIでも大して変わらん。つーかWin32::GUIで(たぶんもっと簡単に)できることをあえてWin32::APIだけでやってるって書いてるのが読めんのか。

      # プログラミングWindowsの最新版はUWP App入門に大変身していたのでAC

    • by Anonymous Coward

      たぶんこんな感じ? 別に追加モジュールはいらんと思うが

      sub wndproc {
        my ($hwnd, $msg, $wparam, $lparam) = @_;
        my %callbacks = (
          WM_KEYUP() => sub {
            ...
          },
          WM_KEYDOWN() => sub {
            ...
          },
          ...
        );
        return $callbacks{$msg}->($hwnd, $wparam, $lparam);
      }

typodupeerror

日本発のオープンソースソフトウェアは42件 -- ある官僚

読み込み中...