月別アーカイブ: 2009年4月

ctypes で WindowsAPI

Python には Windows の DLL に直接アクセスできるモジュールがあるようで。

14.14 ctypes — Pythonのための外部関数ライブラリ。

面白そうなので試してみる。
実験だから簡単なのにしたいなぁ。
MessaageBox 関数ならロードする関数は一つなのでコレでいこう。

14.14.1.2 ロードしたdllから関数にアクセスする

に書いてあるけど Windows の関数は Ansi 版と UNICODE 版がある。
当然 TCHAR マクロも使えない、これは VC++ がコンパイル時に変換しているから。

MessageBox 関数も例外ではない。
MessageBoxA と MessageBoxW にコンパイル時に振り分けされる。
幸いにも Python3.0 の文字列は UNICODE なので MessageBoxW を使う。

そして MessageBoxW は user32.dll にあります。
ということで。

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

import ctypes

MB_OK = 0
MB_OKCANCEL = 0x00000001
IDOK = 1

dll = ctypes.windll.user32
res = dll.MessageBoxW(0, str(dll), "たいとる", MB_OKCANCEL)

if res == IDOK:
    dll.MessageBoxW(0, "OK を押しました", "りざると", MB_OK)
else:
    dll.MessageBoxW(0, "きゃんせるを押しました", "りざると", MB_OK)

mbox

うわぁコレでいけちゃうんだ。
MB_OK とかの定義は WindowsSDK の WinUser.h を見てちょ。

全部 DLL から呼び出せばウインドウもコントロールも作れるね。
でも定数を全部自分で定義せにゃいかんのが面倒そう…

えむえでぃた

とりあえず Windows での Python は EmEditor で行こうと思う。
一応こんな設定にしてみた。

emedit

Home キーでカーソルをインデントの先頭に行かせる。
Shift+Tab でインデント分カーソルを戻す。
という動作は秀丸ではできないっぽいんで。

PyScripter なんてのも見つけたけど普通のテキストエディタのほうがエエわ。
スクリプト言語を IDE で書くなんて馬鹿げていると思うようになったよ。
更に言語ごとに別の IDE だなんて何がしたいの?みたいな。

とりあえずコイツにはスニペットプラグインもあるしガンガン登録してしまえ!
と思ったけどこのスニペットって単語登録ができるだけっぽいな。
それも Tab キーで補完じゃなく選択して Enter なんだ、ガッカリ。

まあ EmEditor はアウトプットがあるから便利だ。
と思ったけど…

output

おもくそ文字化けしとるやないの。
コンソールなら普通に表示できるのになんやこれ、ガッカリ。

それとツールに Python と IronPython を登録。
これでボタンを選ぶだけでどちらも動作確認ができるぞと。
アウトプットが化けるから pythonw.exe でなく python.exe にしておくか…

Ruby も一応ツールに登録していたんだけど全く使わないので登録解除。
IronRuby なんてもう忘れられた子になっている、そんなのあったなぁ…

他に VL ゴシックにしたり読み書きは BOM 無し UTF-8 に指定したり。
なんか意地でも Ubuntu の gEdit に合わせようとしている自分が怖い。

しかし弄くれば弄くるほど Windows と Linux の文化の違いを感じるよ。
テキストエディタに求められているものが違いすぎ。

追記

アウトプットの文字化けは私の設定ミスだった…
出力エンコードを UTF-8 にしていた、システム規定でよかったのね。
江村さんごめんなさい。

それと Shift+Tab の動作だが Tab 分カーソルが戻るだけだった。
文字列を選択していない場合は逆インデントをやってくれない。
これは困る、逆インデントに BackSpace を4回叩くなんてやってられないよ。

しかたがないのでマクロを作る。

if (document.selection.IsEmpty) {
	document.selection.DeleteLeft(4);
} else {
	document.selection.UnIndent(1)
}

を作り Shift+Tab の割り付けをコッチに変更という強引なワザで。
これで範囲選択状態の動作は維持しながら未選択の場合は前方四文字削除だ。
というか gEdit と同じ動作。

問題はインデントの先頭で実行することしか考えていないことだったりする。

IronPython で WPF

IronPython には nt という os の代替モジュールがあることを今更知った。
ということは前回のコードは

# -*- coding: UTF-8 -*-

# 環境変数の書き出し

import nt

keys = nt.environ.keys()
result = ""
for key in keys:
	result += key + "\n" + nt.environ[key] + "\n\n"

f = open("env2.txt", "w")
f.write(result)
f.close()

あーあ、os を nt に書き換えるだけで動いてしまったお。
open() とかは組み込み関数だからそのまま使えるし。

とはいえ IronPython ではコッチで書く人はほとんどいないだろう。
C# コードからの変換ばかりやるはめになるのは目に見えているし。

ということで

の本で WPF アプリのコードがあまりに不親切だったので補完。
部品を作るのにいきなり XAML を利用では IronPython の意味が無いでしょみたく。
XAMLPAD では Glade のようにはいかないと思うし、機能がショボすぎる。

マイレビューを一つ、CPython コードを書くのにも少し役に立ったよと。
ちなみに上記の nt モジュールの存在はコレを読み直して知った…
しかし mono の本同様にコレしかなく選べない状態が続いているのは悲しい。

さて最小限のコードを書いてみる。

# -*- coding: UTF-8 -*-

import clr

# 最小限下記ライブラリ(dll)が必要
clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")

import System

w = System.Windows.Window()
w.Title = "実験"
a = System.Windows.Application()
a.Run(w)

最小限のライブラリとは VC# とかを持っている人なら解るかな?
ソリューションエクスプローラにある参照設定以下のことね。
VC# なら右クリックして「参照の追加」をするけど IronPython はコードで行う。

se

本当は System も必要だけど最初から含まれているっぽい。

後、上記の本ではいきなり from 文を使っているけど理解してから使いましょう。
Window や Application というクラスは System.Windows 名前空間にあります。

知っていると思うけど Python の名前空間はモジュール名そのままである。
partial 指定ができないのが場合によっては辛いかもしれない。
boo という Python そっくりな言語はココの画像を見るとできるっぽい。

【ハウツー】F#、IronPython、Booまで使えるフリーの統合開発環境「SharpDevelop」 (3) 利用できるプログラミング言語 | エンタープライズ | マイコミジャーナル

まあそれはよくて。
上記を拡張しても後々で困るのでさっさとクラスに変更します。

# -*- coding: UTF-8 -*-

import clr

# 最小限下記ライブラリ(dll)が必要
clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")

from System import *
from System.Windows import *

class TestWin(Window):
    def __init__(self):
        self.Title = "class の実験"
        self.Closing += self.onClosing
    
    def onClosing(self, sender, e):
        MessageBox.Show("閉じます")

if __name__ == "__main__":
    w = TestWin()
    a = Application()
    a.Run(w)

やっぱり面倒なので from を利用、これで C# の using と同じ意味。

VC# で作るのと同じように Window を継承したクラスを __main__ で作る。
最後に Application インスタンスの Run() にぶち込めばクラス化は完了である。
これで C# コードからの変換が簡単になりました。

ついでに終了時にダイアログを出すようにハンドラを追加してみた。
Python のクラスなので引数に必ず self が必要です、よく忘れるんだこれが。

最後にコントロールを追加してみます。
XAML を使わずにコードで作る方法をば。

# -*- coding: UTF-8 -*-

import clr

# 最小限下記ライブラリ(dll)が必要
clr.AddReferenceByPartialName("PresentationCore")
clr.AddReferenceByPartialName("PresentationFramework")
clr.AddReferenceByPartialName("WindowsBase")

from System import *
from System.Windows import *
from System.Windows.Controls import *

class TestWin(Window):
    def __init__(self):
        self.Title = "Controls"
        # ボタン作成及びクリックハンドラ登録
        button = Button()
        button.Content = "ボタンだよ"
        button.Click += self.onClick
        # 一行エディットの作成
        # 内容を他で使うのでアトリビュートにしておく
        self.textbox = TextBox()
        self.textbox.Text = "なんか書け"
        # TextBlock の作成
        tb = TextBlock()
        tb.Text = "何か書き込んでボタンを押してね"
        # レイアウタを作成してこれらをセット
        sp = StackPanel()
        sp.Orientation = Orientation.Vertical
        sp.Children.Add(button)
        sp.Children.Add(self.textbox)
        sp.Children.Add(tb)
        # レイアウタを Window にセット
        self.Content = sp
        # この指定でコンテンツの大きさ固定なウインドウになる
        self.SizeToContent = SizeToContent.WidthAndHeight
        self.ResizeMode = ResizeMode.NoResize
    
    def onClick(self, sender, e):
        MessageBox.Show(self.textbox.Text)

if __name__ == "__main__":
    a = Application()
    a.Run(TestWin())

Button 等のクラスは System.Windows.Controls にあるので import する。
Window や Button に何かを乗せるには Content プロパティに代入する。
レイアウタにコントロールを追加するには Children.Add() メソッドを利用する。
という簡単な例である、最後に Run() の中で Window を作る小技をば。

seira

C# でウインドウをコードで作った人なら解るだろうけどほとんど同じに書けます。
C++ から Pascal への変換を経験した人なら「え?それだけ???」ですよね。
今回はここまで。

環境変数の対応リストを作る

Windows では os.environ[“HOME”] が例外になってしまった。
環境変数が違うようだ、Windows が用意しているのってどんなのがあるのだろう?
C++ では Windows SDK に個別取得する関数があるのであまり気にしていなかった。

今後のプログラム用に環境変数の対応リストが作りたい。

ということで environ のキーと値を書き出す簡易スクリプト。
Windows でも Linux でも動きます、一応 Windows 版は Python 3.0 で試した。
print でリダイレクトしたほうが今の私は早いけど Python だけでやってみよう。

#! /usr/bin/env python
# -*- coding: UTF-8 -*-

# 環境変数の書き出し

import os

keys = os.environ.keys()
result = ""
for key in keys:
	result += key + "\n" + os.environ[key] + "\n\n"

f = open("env.txt", "w")
f.write(result)
f.close()

ちなみに私の環境ではこうなった(合体しています)

env.txt

同じモンがありゃしねぇ、こりゃ環境変数を利用したコードの共有は無理だ。
どうでもいいけど Windows 用 Python での \n は CRLF になるんだね。

ちなみに IronPython では下記の要領で同じことができます。

# -*- coding: UTF-8 -*-

import System

# IronPython は clr なので \n では LF 固定になってしまう
nn = System.Environment.NewLine

# IDictionary が返る
dic = System.Environment.GetEnvironmentVariables()
result = ""
# DictionaryEntry に展開
for ent in dic:
	result += ent.Key + nn + ent.Value + nn + nn

sr = System.IO.StreamWriter("env.txt")
sr.Write(result)
sr.Close()

なんか Python らしくないコードだ、なんたって値取得に括弧が付いていない。
プロパティから取得する部分には当然括弧は付かないわけでこうなってしまう。
大文字が多いのはしかたがないが CPython コードとの見分けになると思えば…

#! /usr/bin/env python は言うまでもなく書いてはいけません。
つーか *.py は Windows での振り分けにはどうしよう?関連づけは CPython だし。

なんて解説をしているのでもう解ると思うけどこのコードは mono でも動きます。
Ubuntu 8.10 デフォルト状態でも IronPython 1.1.2 ならそのまま動かせる。

linux_ipy

とはいえ Linux で IronPython というのは凄く無駄を感じますけど。
動かせるとはいえ実用となると今後もビミョーとしか言いようがない。

一応書くと Mac は全然解りません。

PowerShell はなんとも 2

PowerShell をメニューから起動すると巨大なウインドウになって面食らう。
コレは右クリックしてプロパティから調節できるはずなんだけど…

psproperty

大きさを変更して「適用」するとフォントが太字に早変わり。
パス区切りもバックスラッシュになり Alt+半角/全角 を押しても日本語入力が不能に。
ワケワカンネェ!デフォルトのまま使うしか無いってこと?

と思ったけどメニューにあるショートカットをコピーして弄くるとこうなるっぽい。
本体から右クリックドラッグして直接ショートカットを作ったら普通にカスタマイズできた。
でも「デスクトップにショートカット作成」を利用するとアイコンが cmd.exe に。
わけわかんねぇ、Vista というか私の環境だけか?

画面バッファのサイズがスクロール範囲
ウインドのサイズが半角英数が何文字入力できるか(全角は半分)のようだ。
システム設定を使うにチェックを入れると起動位置は Windows が勝手に決める。
というか cmd.exe も同じなんですけどね。

まぁ標準出力なんだから cmd.exe から使えるんですけどね。

cmdpower

とにかく kill コマンドが使えるのが嬉しい、タスクマネージャより楽。
cmd.exe でもやれるんだろうけど使い方イマイチ解らないし。

でもファイルをドロップしても bash みたくパス名に展開してくれないなぁ…
まあ minipoli を使えばいいんですけど、D&Dは Windows のほうが本場じゃ?
Ctrl+Shift+C (V) という解りやすいコピペのショートカットもやはり無理か。

他に検索すると F7 でコマンド履歴とか見つかるけど上矢印キーのほうが楽だと思う。

そういえば UAC はどうなるの?と思って cp コマンドで system32 フォルダへ。
容赦なく拒否された、UAC ダイアログくらい出してよ、いやそれではリモート接続が…
「管理者として実行」をまずしなきゃいけないの? su なり sudo なりも真似してよ。
UAC が嫌われる原因の一つがよく解った。