UWSCRで拡張された機能：def_dll

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

# エイリアス機能

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

```php: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と同等の動作(のはず)です。

```php: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
```

```php:uwscr
// UWSCRならサイズを明記することで安全に書ける
def_dll GetWindowPlacement(hwnd, var int[11]):bool:user32.dll
```

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

```php: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: 戻り値がないことを明示するために使います

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

:::note warn
UWSCのヘルプを見ると型のサイズ説明で
> dword=uint=hwnd

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

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

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

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

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

# コールバック

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

```php: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)
```

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

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







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

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

```php: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では以下のような記述をすれば一応動作はします。

```php: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
```

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

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

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

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