0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UWSCRAdvent Calendar 2023

Day 12

UWSCRで拡張された機能:def_dll

Last updated at Posted at 2023-12-11

def_dllにもいくつかの新機能が追加されています。

エイリアス機能

呼び出したいdll関数に任意の名前を付けることができるようになりました。

uwscr
// 別名:DLL関数名 と記述することで別名で呼び出せるようになる
// MessageBoxWをMessageBoxという名前で呼べるようにする
def_dll MessageBox:MessageBoxW(hwnd, wstring, wstring, uint):int:user32.dll

print MessageBox(0, "別名呼び出しサンプル", "テスト", 0)

// これによりgetkeystate問題も解消される
def_dll GetKeyStateWin32:GetKeyState(int):word:user32

print GetKeyStateWin32(VK_RETURN) // Win32のGetKeyStateが呼ばれる
print getkeystate(VK_RETURN)      // 組み込み関数が呼ばれる

配列サイズの明記

UWSCでは引数の型が配列だった場合に型名[]という記述ができましたが、それに加えて型名[サイズ]と書けるようになりました。サイズを指定した場合、異なるサイズの配列を引数として渡すとエラーになります。サイズ未指定時はUWSCと同等の動作(のはず)です。

uwsc
// UWSC名物、配列による構造体の雑定義
def_dll GetWindowPlacement(hwnd, var int[]):bool:user32.dll

// 引数として渡す配列のサイズに気を付ける必要があった
dim wp[10]
GetWindowPlacement(idtohnd(id), wp)
for v in wp
    print v
next
uwscr
// UWSCRならサイズを明記することで安全に書ける
def_dll GetWindowPlacement(hwnd, var int[11]):bool:user32.dll

また、UWSCではどうにもならなかったサイズ指定のあるbytecharを持つ構造体にも対応できるようになりました。

uwscr
def_dll WSAStartup(word, {word, word, char[257], char[129]}):long:ws2_32.dll
def_dll WSACleanup():long:ws2_32.dll

dim wVersion, wHighVersion, szDescription, szSystemStatus

WSAStartup($202, wVersion, wHighVersion, szDescription, szSystemStatus)
WSACleanup()

print wVersion
print wHighVersion
print szDescription
print szSystemStatus

追加された型定義

  • handle: 引数がハンドル値であることを示す
  • pointer: 引数がポインタであることを示す
  • struct: 引数がユーザー定義構造体であることを示す
  • callback: 引数がコールバック関数であることを示す (後述します)
  • void: 戻り値がないことを明示するために使います

handlehwndと大差ないのですが、hwndじゃないのにhwndって書くの気持ち悪いな…という思いから生まれました。pointerは構造体の生ポインタを得たい場合なんかに使うことがあります。ちなみにこれらはアーキテクチャによってサイズが可変なので注意してください。

UWSCのヘルプを見ると型のサイズ説明で

dword=uint=hwnd

と書かれていましたが、UWSCRではx64版があるためその限りではありません。x86版であればギリギリOKですが、hwndであるべきところをdwordと書くみたいなのはなるべくやめましょう。

structはユーザー定義構造体を受ける引数を示します。そう、UWSCRではついにCライクな構造体を定義できるようになったのです。冗長かつ複雑な{}展開表記から開放されます!

ユーザー定義構造体については翌日(12/13)の記事で詳しく解説します。

woidは戻り型専用です。戻り値がないことを明示します。

uwscr
// これらは同じ
def_dll hoge():hoge.dll
def_dll hoge():void:hoge.dll

コールバック

UWSCでは不可能だったコールバック関数に対応しました。
callback(引数型):戻り型のように記述することでコールバック関数の引数と戻り値の型を定義し、それに合わせたユーザー定義関数を渡すことでそのユーザー定義関数がコールバック関数として呼び出されるようになります。

uwscr
// コールバック関数を定義
function MonitorEnumProc(hmonitor, hdc, prect, lparam)
    print hmonitor
    result = TRUE
fend

// 第三引数はコールバック関数定義
def_dll EnumDisplayMonitors(handle, pointer, callback(handle, handle, pointer, pointer):bool, pointer):bool:user32.dll

// callbackにはコールバック関数として呼ばれるユーザー定義関数を渡す
EnumDisplayMonitors(null, null, MonitorEnumProc, 0)

例に挙げたEnumDisplayMonitorsであれば第四引数に渡したポインタがそのままコールバック関数の第四引数(ここではlparam)に渡ります。ユーザー定義構造体を利用することで構造体から得たポインタを渡してコールバック関数内でポインタから構造体の実態を得るといったことができるようになります。詳しくは翌日(12/13)の記事で解説します。

と、ここまで書いてみたのですがまたしても0.14.0では動作しなくなっていました…STATUS_HEAP_CORRUPTIONで落ちているようです。これも原因を確認して0.15.0で修正します。

UWSCとの実装の差異について

DLL関数によってはUWSCと同様の定義では動作しない場合がありえます。
例えば以下はUWSCでは正常動作しますがUWSCRでは動作しません。

uwsc
def_dll WNetGetUniversalNameA(string, long, {var string}, var long):long:mpr

buf = format(NULL, 260)
len = lengthb(buf)

// 第二引数の 1 は UNIVERSAL_NAME_INFO_LEVEL
print WNetGetUniversalNameA("Z:", 1, buf, len)
print buf

UWSCRでは以下のような記述をすれば一応動作はします。

uwscr
def_dll WNetGetUniversalNameA(string, long, {pointer, char[260]}, var long):long:mpr

dim buf, ptr = 0, size = 260

print WNetGetUniversalNameA("Z:", 1, ptr, buf, size)
print buf

今のところWNetGetUniversalNameでしかこのようなケースは見たことがないのですが、正直こういったケースにどう対応すればいいのか?が現時点では分からず手詰まり状態です。UNIVERSAL_NAME_INFOA構造体が

typedef struct _UNIVERSAL_NAME_INFOA {
  LPSTR lpUniversalName;
} UNIVERSAL_NAME_INFOA, *LPUNIVERSAL_NAME_INFOA;

なので{string}だけで良さそうなんですけどなんでなんですかね?
詳しい方がご覧になってたらコメントしていただけるとありがたいです…

また上記にも関連するのかもしれませんが、文字列型(string, pchar, wstring, pwchar)の実装はUWSCと同じようにできている自信がまったくありません。何かまだ理解が及んでいない部分があるのではないか…という懸念があります。おかしな動作が見受けられた場合はgithubでご一報ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?