UWSCでGetMonitorInfoにMONITORINFOEXを渡す

UWSCでWin32APIのGetMonitorInfoにMONITORINFOEXを渡す方法がわからない、という質問をいただいたので、その回答です。

素のUWSCで、真面目にやるなら、

DEF_DLL GetMonitorInfoW(DWORD,{long,long,...,wchar,wchar,...}): BOOL: user32

「long,long,...」はlongを10個。「wchar,wchar,...」はwcharを32個書いてください。
これで多分、上手くいきます。(未検証)
もちろん、引数も42+1個書いてくださいね!


誰がそんなことするか!

横着定義

基本は横着定義です。
まー、簡単に言えば、GetMonitorInfoWの第二引数は104Byteのメモリーを確保したポインターを渡せば良いです。
(DWORD相当10個と、WCHARが32個。4*10+2*32=104Byte)
なので、long[25](UWSCはこう書くと0~25まで使える。すなわち26個分確保される)を渡せば良いことになります。
この辺を詳しく知りたいなら、UWSCのDEF_DLLについて - じゅんじゅんのきまぐれでも読んで。


ということで以下のような感じ。

DEF_DLL MonitorFromPoint(long,long,DWORD): DWORD: user32
DEF_DLL GetMonitorInfoW(DWORD,long[]): BOOL: user32
DEF_DLL RtlMoveMemory(var pwchar,long[],DWORD): kernel32

CONST MONITORINFO_SIZE = 40
CONST LONG_SIZE = 4
CONST CCHDEVICENAME = 32
CONST WCHAR_SIZE = 2
DIM i, x, y, inf[MONITORINFO_SIZE / LONG_SIZE - 1 + CCHDEVICENAME / LONG_SIZE * WCHAR_SIZE], device
inf[0] = MONITORINFO_SIZE + CCHDEVICENAME * WCHAR_SIZE
FOR i = 0 TO MONITOR() - 1
	x = MONITOR(i, MON_X)
	y = MONITOR(i, MON_Y)
	IFB GetMonitorInfoW(MonitorFromPoint(x, y, 0), inf) THEN	// 0:MONITOR_DEFAULTTONULL
		device = FORMAT(CHR(0), inf[0] / WCHAR_SIZE)
		RtlMoveMemory(device, inf, inf[0])	// 一旦構造体全体を文字列として解釈
		device = COPY(device, MONITORINFO_SIZE / WCHAR_SIZE + 1)	// MONITORINFO部分をカットする
		PRINT "(" + inf[1] + "," + inf[2] + ")-(" + inf[3] + "," + inf[4] + ") (" + inf[5] + "," + inf[6] + ")-(" + inf[7] + "," + inf[8] + ") " + inf[9] + " " + device
	ENDIF
NEXT

szDevice部分を取り出すのに少し工夫が必要ですね。

美しくない

上記の問題点は、inf[1]とか参照が美しくないことにあります。
以前、 UWSCで構造体を使う - じゅんじゅんのきまぐれ というものを書きました。
これですよ。
これならちゃんと.参照で書けますし、szDeviceを取り出すのも簡単です。
ただ、ダサいことにStructモジュールがUnicode対応していないので、GetMonitorInfoAを使います。

CALL Struct.uws

DEF_DLL MonitorFromPoint(long,long,DWORD): DWORD: user32
DEF_DLL GetMonitorInfoA(DWORD,DWORD): BOOL: user32

DIM name = "RECT"
TEXTBLOCK _rect_struct
{
	left:	['long'],
	top:	['long'],
	right:	['long'],
	bottom:	['long']
}
ENDTEXTBLOCK
Struct.Define(name, _rect_struct)
name = "MONITORINFOEX"
TEXTBLOCK _monitorinfoex_struct
{
	cbSize:['DWORD'],
	rcMonitor:['RECT'],
	rcWork:['RECT'],
	dwFlags:['DWORD'],
	szDevice:['char', null, 32]
}
ENDTEXTBLOCK

DIM i, x, y, inf, pInf
inf = Struct.Create(name, _monitorinfoex_struct)
inf.cbSize = Struct.GetSize(name, inf)
pInf = Struct.Alloc(inf)
FOR i = 0 TO MONITOR() - 1
	x = MONITOR(i, MON_X)
	y = MONITOR(i, MON_Y)
	IFB GetMonitorInfoA(MonitorFromPoint(x, y, 0), pInf) THEN	// 0:MONITOR_DEFAULTTONULL
		Struct.Update(inf, pInf)
		PRINT "(" + inf.rcMonitor.left + "," + inf.rcMonitor.top + ")-(" + inf.rcMonitor.right + "," + inf.rcMonitor.bottom + ") (" + inf.rcWork.left + "," + inf.rcWork.top + ")-(" + inf.rcWork.right + "," + inf.rcWork.bottom + ") " + inf.dwFlags + " " + inf.szDevice
	ENDIF
NEXT
Struct.Dispose()

cbSizeもきれいに書けるので嬉しい限りです。