win32metadata は Microsoft 公式のプロジェクトで、Win32 API のメタデータを提供している。Rust では Microsoft が開発している windows-rs が 広く使われており、このプロジェクトのデータを利用している。
その Python 版にあたるのが win32more で、こちらはコミュニティによって開発されている。実際に使ってみた内容を簡単にまとめる。
インストール
pip install win32more
コード例
Microsoft の Win32 API サンプルプログラム を Python で書き直した。エントリポイントについては、MinGW-w64 の crtexewin.c を参考にした。
import sys
from win32more.Windows.Win32.Graphics.Gdi import (
COLOR_WINDOW,
PAINTSTRUCT,
BeginPaint,
EndPaint,
FillRect,
)
from win32more.Windows.Win32.System.Environment import GetCommandLineW
from win32more.Windows.Win32.System.LibraryLoader import GetModuleHandleW
from win32more.Windows.Win32.System.Threading import (
STARTF_USESHOWWINDOW,
STARTUPINFOW,
GetStartupInfoW,
)
from win32more.Windows.Win32.UI.WindowsAndMessaging import (
CW_USEDEFAULT,
MSG,
SW_SHOWDEFAULT,
WM_DESTROY,
WM_PAINT,
WNDCLASSW,
WNDPROC,
WS_OVERLAPPEDWINDOW,
CreateWindowExW,
DefWindowProcW,
DispatchMessageW,
GetMessageW,
PostQuitMessage,
RegisterClassW,
ShowWindow,
TranslateMessage,
)
@WNDPROC
def WindowProc(hwnd, uMsg, wParam, lParam):
if uMsg == WM_DESTROY:
PostQuitMessage(0)
return 0
elif uMsg == WM_PAINT:
ps = PAINTSTRUCT()
hdc = BeginPaint(hwnd, ps)
# All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, ps.rcPaint, COLOR_WINDOW + 1)
EndPaint(hwnd, ps)
return 0
return DefWindowProcW(hwnd, uMsg, wParam, lParam)
def wWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow):
# Register the window class.
CLASS_NAME = "Sample Window Class"
wc = WNDCLASSW()
wc.lpfnWndProc = WindowProc
wc.hInstance = hInstance
wc.lpszClassName = CLASS_NAME
RegisterClassW(wc)
# Create the window.
hwnd = CreateWindowExW(
0, # Optional window styles.
CLASS_NAME, # Window class
"Learn to Program Windows", # Window text
WS_OVERLAPPEDWINDOW, # Window style
# Size and position
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
None, # Parent window
None, # Menu
hInstance, # Instance handle
None, # Additional application data
)
if hwnd == None:
return 0
ShowWindow(hwnd, nCmdShow)
# Run the message loop.
msg = MSG()
while GetMessageW(msg, None, 0, 0) > 0:
TranslateMessage(msg)
DispatchMessageW(msg)
return 0
if __name__ == "__main__":
hInstance = GetModuleHandleW(None)
pCmdLine = GetCommandLineW()
if pCmdLine != None:
in_double_quote = False
i = 0
while i < len(pCmdLine) and (pCmdLine[i] > " " or in_double_quote):
if pCmdLine[i] == '"':
in_double_quote = not in_double_quote
i += 1
while i < len(pCmdLine) and pCmdLine[i] <= " ":
i += 1
pCmdLine = pCmdLine[i:]
else:
pCmdLine = ""
startup_info = STARTUPINFOW()
GetStartupInfoW(startup_info)
if startup_info.dwFlags & STARTF_USESHOWWINDOW:
nCmdShow = startup_info.wShowWindow
else:
nCmdShow = SW_SHOWDEFAULT
sys.exit(wWinMain(hInstance, None, pCmdLine, nCmdShow))
API がどの階層にあるか調べる方法
Win32 API の公式ドキュメントには win32metadata における階層は記載されていないため、自分で調べる必要がある。
win32metadata の README には次のように記載されている。
If you'd like to browse the metadata to see what we're emitting, extract Windows.Win32.winmd from the Microsoft.Windows.SDK.Win32Metadata NuGet package and load Windows.Win32.winmd in ILSpy. Download the package and rename it to .zip to browse and extract its content.
つまり、NuGet パッケージから Windows.Win32.winmd を取り出し、ILSpy で読み込んで検索できるという意味である。手順を整理すると以下のとおり。
- ILSpy を入手する (Zip 版で十分なので解凍して使用する)
- win32metadata の NuGet パッケージをダウンロードする。右側 「About」 の 「Download package (X.XX MiB)」リンクからダウンロードできる
- ダウンロードした
microsoft.windows.sdk.win32metadata.~.nupkgの拡張子を.zipに変更する - 中にある
Windows.Win32.winmdを解凍する。(他のファイルは不要) - ILSpy を起動し、「Assemblies」ウィンドウに
Windows.Win32.winmdをドラッグ&ドロップする - ツールバーの 「Window」 → 「Search (Ctrl + Shift + F)」を開く
- 検索対象 (Search for:) を「Types and Members」に設定し、検索欄に「
=検索したい名前」と入力して検索する- 例1:
=CreateWindowExW - 例2:
=WS_OVERLAPPEDWINDOW
- 例1:
- 検索結果をダブルクリックすると、「Assemblies」ウィンドウ内でハイライトされる
- 右クリックで「Copy FQ Name」を実行すると、フルネームがクリップボードにコピーされる
- 関数や定数の場合、コピーした名前に
.Apisや.型名の階層が含まれるため、必要に応じて削除する
- 例1:
Windows.Win32.UI.WindowsAndMessaging.Apis.CreateWindowExW→.Apisを削除 - 例2:
Windows.Win32.UI.WindowsAndMessaging.WINDOW_STYLE.WS_OVERLAPPEDWINDOW→.WINDOW_STYLEを削除