Windows API」カテゴリーアーカイブ

ipconfigを呼ばないでMACアドレスのリストを取得する(twapi 3.1.17対応ほか)

「ipconfigを呼ばないでMACアドレスのリストを取得する」を書いた時点のtwapiのバージョンはたしか3.0.32だったんじゃないかと思いますが、3.0.32の次のバージョン3.1.17が去年の暮に出ていました。出てるのは知ってたんですが、8.4サポート廃止ということで使ってはいませんでした。

SourceForge.com twapi 3.1.17

最近新しいPCを手に入れて、8.6や8.5を試していたのですが、get_netif_info -typeの仕様が変わって、今までのように文字列でなく数値が返ってくるようになっていたので、一応3.0.xとの互換性も考慮した修正をしておきました。
あと、前のスクリプトでは有線LANしか取得してませんでしたが、無線LANインターフェースのMACアドレスも取得できるようにしておきました。

proc getPhysicalAddresses {} {
	set macs {}
	foreach i [twapi::get_netif_indices] {
		set opt_type [twapi::get_netif_info $i -type]
		if {$opt_type eq {}} {
			continue
		}
		foreach {opt type} $opt_type break
		if {($type != 6 && $type ne "ethernet") && ($type != 71 && $type ne "other")} {
			continue
		}
		set opt_physicaladdress [twapi::get_netif_info $i -physicaladdress]
		if {$opt_physicaladdress eq {}} {
			continue
		}
		foreach {opt physicaladdress} $opt_physicaladdress break
		lappend macs [string toupper $physicaladdress]
	}
	return $macs
}

それから、ケーブルが抜かれてるインターフェースに関してはtwapi::get_netif_indicesで情報取得できません。
以下のスクリプトを使えば可能になります。

proc twapi::get_netif_indices {} {
	set size [twapi::get_netif_count]
	set indices {}
	set cnt 0
	set idx 1
	for {set cnt 0} {$cnt < $size} {} {
		if {![catch {twapi::get_netif_info $idx -adapterindex} opt_adapterindex]} {
			if {$opt_adapterindex ne {}} {
				foreach {opt adapterindex} $opt_adapterindex break
				if {$adapterindex == $idx} {
					lappend indices $idx
				}
			}
			incr cnt
		}
		incr idx
	}
	return $indices
}

いったい何の役に立つのかは内緒です。とにかくMACアドレスリストを取得したいんだというひとが他にいれば役立ててくれれば幸いです。

[Tcl/Tk] Tkウィンドウ上でマウスポインタの下の色を取得する

Tcler's Wikiには以下のページで2通りの方法が紹介されています。

http://wiki.tcl.tk/15339

1つ目はキャンバスアイテムがimageの場合は、中身の画像に対してgetコマンドを使用してピクセルのRGB値を取得し、それ以外のアイテムに対してはitemcget -fillの値を取得するという方法で、2つ目はウィンドウのキャプチャを取得して、それに対してgetコマンドを発行する方法になっています。

が、いずれもいまいちでした。
まず、1つ目の方法ではimage以外の図形のフチの色が取得できません。
2つ目の方法はめちゃくちゃ遅いので実用的ではありません。

以下を参考にして、GDIを使う方法にしました。

http://www.csharp411.com/c-getpixel-and-setpixel/

この方法だと別にcanvasに限らず色が取得できます。

ただし、Windows専用になります。Tkのウィンドウの外に出るとマウスの動きをキャプチャできなくなるので一般的なカラーピッカーみたいなのを作りたければ、そこのところを作りこむ必要があります。

本当はそこまでやりたかったけど、TclでWM_MOUSEMOVEメッセージを処理する方法が分からないので保留。

SetPixelはおまけです。
Ffidlはこちらからダウンロードできます。

proc getPhysicalAddresses {} {
	set macs {}
	foreach i [twapi::get_netif_indices] {
		set opt_type [twapi::get_netif_info $i -type]
		if {$opt_type eq {}} {
			continue
		}
		foreach {opt type} $opt_type break
		if {($type != 6 && $type ne "ethernet") && ($type != 71 && $type ne "other")} {
			continue
		}
		set opt_physicaladdress [twapi::get_netif_info $i -physicaladdress]
		if {$opt_physicaladdress eq {}} {
			continue
		}
		foreach {opt physicaladdress} $opt_physicaladdress break
		lappend macs [string toupper $physicaladdress]
	}
	return $macs
}

ipconfigを呼ばないでMACアドレスのリストを取得する

TclからNICのMACアドレスのリストを取得する場合、ipconfig/allの出力から取り出してたけど、Windowsのバージョンやロケールによって出力が変わるものを使うのはどうも気に食わんかったので、ちゃんとそれ用のWindows APIを使いたいと思っていた。
今回twapiを使えばできることが分かったので、メモしておく。

package require Tk
package require Ffidl
 
namespace eval Win32 {
	variable HWND_DESKTOP 0
	ffidl::callout GetDC {pointer} pointer [ffidl::symbol user32.dll GetDC]
	ffidl::callout ReleaseDC {pointer pointer} int [ffidl::symbol user32.dll ReleaseDC]
}
namespace eval Gdi32 {
	ffidl::callout GetPixel {pointer int int} int [ffidl::symbol gdi32.dll GetPixel]
	ffidl::callout SetPixel {pointer int int int} int [ffidl::symbol gdi32.dll SetPixel]
}
 
proc GetPixel {hdc x y} {
	set c [Gdi32::GetPixel $hdc $x $y]
 
	set R [expr {($c & 0x000000FF)}]
	set G [expr {($c & 0x0000FF00) >>  8}]
	set B [expr {($c & 0x00FF0000) >> 16}]
 
	return [list $R $G $B]
}
 
proc SetPixel {hdc x y r g b} {
	set c [expr {(int($r & 0x00FF0000) >> 16)
	           | (int($g & 0x0000FF00))
	           | (int($b & 0x000000FF) << 16)
	}]
 
	Gdi32::SetPixel $hdc $x $y $c
}

# demo
set c [canvas .c]
pack $c
 
$c create text  55  95  -text "ABC"     -fill white
$c create rect 125  25  145  45         -fill red
$c create oval  25 125   45 145         -fill green
$c create line  15 100   70 125         -fill blue
$c create poly 100  65  130  65 100  20 -fill cyan -outline black
 
bind $c <Motion> {
	set x [winfo pointerx .]
	set y [winfo pointery .]
 
	set hdc [Win32::GetDC $::Win32::HWND_DESKTOP]
	foreach {R G B} [GetPixel $hdc $x $y] break
	Win32::ReleaseDC $::Win32::HWND_DESKTOP $hdc
 
	wm title . "(x, y) = ($x, $y) : ($R, $G, $B)"
}
console show

ちなみにコマンドプロンプト上ではchcpで932以外のコードページを指定してからipconfigすれば英語の出力になる。
これをTclからもできればよかったんだけど、複数のコマンドをパイプ経由で渡すことはできないようだ。

cmd /c "chcp 437 & ipconfig/all"

というのをexecしたりしても、標準出力を受け取ることができなかった。
一時的にバッチファイルを作り、これを実行してもよいが、美しくない。

そういうわけで、上記のテクニックが今のところ一番いいと思う。

AssocQueryString

AssocQueryStringを使って拡張子に関連付けられた実行ファイルパスを取得するサンプル。
本当はTclで使うからFfidlとかでやりたかったけど、難しかったのでCのコンソールアプリケーションにしました。
勉強のため無駄にUNICODE対応にしています。

使い方は、
assoc_query_string.exe [.extension|extension|file_name.extension|file_path.extension]

拡張子を渡すか、ファイルパスを渡すと、「開く」アクションに関連付けられたEXEのフルパスを標準出力に出力します。

AssocQueryString screenshot
ソースコード: assoc_query_string.zip