UWSCRではstruct-endstruct
構文によりCライクな構造体を定義できるようになりました。
構造体定義
// メンバ名: 型名を記述
// 型名に関してはdef_dllとほぼ同じ
// varまたはrefを付けるとその型のポインタになる
struct MyStruct
foo: int
bar: wchar[100]
baz: var int
endstruct
構造体の初期化
構造体名()
とすることで構造体を初期化します。
struct MyStruct
foo: int
endstruct
s = MyStruct()
データの読み書き
.メンバ名
でアクセスできます。
s = MyStruct()
print s.foo // 0
s.foo = 100
print s.foo // 100
構造体のメソッド
構造体は共通のメソッドを持ちます。
size()
構造体のサイズを返します。
struct MyStruct
foo: dword // 4
bar: word // 2
baz: word // 2
endstruct
s = MyStruct()
print s.size() // 8
// サイズはlength関数でも得られる
print length(s) // 8
print length(MyStruct) // 8
この値は単純にメンバサイズの合計というわけではありません。構造体サイズが必要な場合はこのメソッドを使用してください。
0.14.0
ではネストした構造体のサイズが正しく得られない場合があります。
address()
構造体のアドレス(ポインタ)を得ます。
s = MyStruct()
ptr = s.address()
ポインタから構造体の実体を得る
構造体名(ポインタ)
とすることで構造体の実体を得られます。
例えばWTSEnumerateSessionsExW
という関数は第四引数がWTS_SESSION_INFO_1
構造体のポインタを受ける変数のポインタであったため{}
が使えず、さらにWTS_SESSION_INFO_1
は複数個存在する可能性があるためUWSCではこの関数から情報を得ることが困難でした。
UWSCRであれば予めWTS_SESSION_INFO_1
を定義しておくことでポインタからその実体を得て値を参照することができます。
def_dll WTSEnumerateSessionsExW(handle, var dword, dword, var pointer, var dword):bool:Wtsapi32
def_dll WTSFreeMemoryExW(dword, pointer, dword):bool:Wtsapi32
struct WTS_SESSION_INFO_1
ExecEnvId : dword
State : dword
SessionId : dword
pSessionName: wstring
pHostName : wstring
pUserName : wstring
pDomainName : wstring
pFarmName : wstring
endstruct
size = length(WTS_SESSION_INFO_1)
dim ptr, cnt, plevel = 1
// WTS_SESSION_INFO_1のポインタをptrで、個数をcntで受ける
if WTSEnumerateSessionsExW(0, plevel, 0, ptr, cnt) then
for i = 0 to cnt - 1
// WTS_SESSION_INFO_1構造体は複数個が連結している
// 元のポインタ + インデックス * 構造体サイズ でそれぞれのポインタが得られる
info = WTS_SESSION_INFO_1( ptr + i * size )
print info.ExecEnvId
print info.State
print info.SessionId
print info.pSessionName
print info.pHostName
print info.pUserName
print info.pDomainName
print info.pFarmName
print
next
// WTS_SESSION_INFO_1構造体をすべて開放する
WTSFreeMemoryExW(2, ptr, cnt)
endif
LPARAMとしての構造体利用
Win32 APIではコールバック関数とのデータの橋渡しとしてLPARAMが用いられますが、そのデータとして構造体を利用できます。
uwscr
// 利用するDLL関数を定義する
def_dll EnumDisplayMonitors(handle, pointer, callback(handle, handle, pointer, pointer):bool, pointer):bool:user32.dll
def_dll GetMonitorInfoW(handle, struct):bool:user32.dll
def_dll EnumDisplayDevicesW(wstring, dword, struct, dword):bool:user32.dll
// EnumDisplayMonitorsに呼び出されるコールバック関数
// TRUEを返すと続行し、FALSEを返すとその時点でEnumDisplayMonitorsを終了します
// lparamはEnumDisplayMonitorsに渡したUserData構造体のポインタです
function MonitorEnumProc(hmonitor, hdc, prect, lparam)
// ポインタからUserData構造体を得る
data = UserData(lparam)
// モニタハンドルを配列に入れる
data.handles[data.count] = hmonitor
// カウントを進める
data.count += 1
if data.count == length(data.handles) then
// 取得上限を超えたら終了する
result = FALSE
else
// trueを返して次に進む
result = TRUE
endif
fend
// lparamとして渡される構造体
struct UserData
// モニタハンドルを入れる配列
// 今回は最大10個まで取得することとします
handles: handle[10]
// ハンドル数
count : uint
endstruct
// UserData構造体を初期化
data = UserData()
// 構造体アドレスをLPARAMとして渡す
lparam = data.address()
// callbackにはコールバック関数として呼ばれるユーザー定義関数を渡す
EnumDisplayMonitors(null, null, MonitorEnumProc, lparam)
for i = 0 to data.count - 1
// 構造体からハンドル値を得ます
handle = data.handles[i]
// デバイス名を得る
info = MONITORINFOEX()
info.monitorInfo.cbSize = info.size() // ※1
// info.monitorInfo.cbSize = 104
GetMonitorInfoW(handle, info)
print info.szDevice
// モニタデバイスの詳細を得る
device = DISPLAY_DEVICEW()
device.cb = device.size()
EnumDisplayDevicesW(info.szDevice, 0, device, 0)
print device.DeviceName
print device.DeviceString
next
// デバイス情報取得のための構造体定義
// MONITORINFO構造体で使用されるため定義する必要がある
struct RECT
left : int
top : int
right : int
bottom: int
endstruct
// MONITORINFOEX構造体で使われる
struct MONITORINFO
cbSize : uint
rcMonitor: RECT // ※2
rcWork : RECT // ※2
dwFlags : uint
endstruct
// szDeviceにデバイス名が入る
struct MONITORINFOEX
monitorInfo: MONITORINFO
szDevice : wchar[32]
endstruct
// MONITORINFOEXのszDeviceからEnumDisplayDevicesWで詳細を得るのに使う
struct DISPLAY_DEVICEW
cb : uint
DeviceName : wchar[32]
DeviceString: wchar[128]
StateFlags : uint
DeviceID : wchar[128]
DeviceKey : wchar[128]
endstruct