HSP3 .NET Framework 統合ランタイム — コンパイラ・ランタイム拡張仕様 — 最終更新: 2026-04-18
対象: IronHSP (OpenHSP 3.8beta1 ベース) / .NET Framework 4.8 / ツールセット v143 (VS2022)
hspdll.txt, hsp3code.txt) に記載されていない IronHSP 固有の拡張仕様 を網羅します。バニラ HSP の仕様は上記文書を参照してください。
IronHSP (hsp3net) は OpenHSP 3.8beta1 をベースに、以下のレイヤーを追加した .NET Framework 統合ランタイムです。
┌─────────────────────────────────────────────────┐
│ HSP スクリプト (.hsp) │
├─────────────────────────────────────────────────┤
│ hspcmp (拡張コンパイラ) │
│ - #defstruct / #defunion / #field │
│ - #defcbcom / #cbmethod │
│ - #cfuncst / #cfuncd / #cfuncf │
│ - intptr 型 / Allman ブレース │
├─────────────────────────────────────────────────┤
│ .ax (拡張中間コード) │
├─────────────────────────────────────────────────┤
│ hsp3net ランタイム │
│ ┌───────────────────────────────────────────┐ │
│ │ コア (hsp3code / hsp3int) │ │
│ │ - NSTRUCT / MAP / WSTR / INT64 型 │ │
│ │ - dimmap / delmap / structdim 命令 │ │
│ │ - _struct_poke / _struct_peek │ │
│ ├───────────────────────────────────────────┤ │
│ │ Win32 GUI / DLL 拡張 (hsp3ext_win) │ │
│ │ - callfuncst / callfuncd / callfuncf │ │
│ │ - COM コールバック (動的 thunk 生成) │ │
│ │ - コールバック thunk (x86/x64) │ │
│ ├───────────────────────────────────────────┤ │
│ │ .NET 連携レイヤー (C++/CLI) │ │
│ │ - Hsp3Net (リフレクション) │ │
│ │ - GlobalAccess (GCHandle 管理) │ │
│ │ - HspForms (WinForms 統合) │ │
│ │ - NETOBJ 変数型 │ │
│ │ - HspCallbackProxy (デリゲートブリッジ) │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
| 項目 | バニラ HSP3 | IronHSP (hsp3net) |
|---|---|---|
| 変数型数 | 最大 11 (FLAG 0〜10) | 最大 13 (FLAG 0〜12) +2 |
| 構造体 | TYPE_STRUCT (module 擬似) | NSTRUCT (バイナリレイアウト保持) + #defstruct |
| 連想配列 | なし | MAP 型 (dimmap / map("key")) |
| DLL 戻り値 | int のみ (#cfunc) | int / double / float / struct (#cfunc / #cfuncd / #cfuncf / #cfuncst) |
| COM コールバック | なし | #defcbcom で任意 COM インターフェース実装 |
| .NET 連携 | なし | C++/CLI 経由でリフレクション・WinForms |
| ポインタ型 | int (32bit固定) | intptr (プラットフォーム幅) |
| 文字列エンコード | Shift-JIS (CP_ACP) | UTF-8 基盤 + WSTR (UTF-16) |
Win32 API や DLL とのデータ交換で必要な C 構造体互換のバイナリレイアウト を HSP スクリプトから定義できます。
#defstruct [global] 構造体名 [, pack=N]
#field 型名 メンバ名 [配列サイズ]
...
#defunion ; ネストされた共用体開始
#field ...
#endunion
#endstruct
#defunion 共用体名 ; トップレベル共用体
#field ...
#endunion
| 型名 | サイズ | C 相当 | 備考 |
|---|---|---|---|
byte | 1 | unsigned char | |
short | 2 | short / WORD | |
int | 4 | int / DWORD / LONG | |
int64 | 8 | __int64 / LONGLONG | |
float | 4 | float | |
double | 8 | double | |
intptr | 4 or 8 | INT_PTR / size_t | 32bit=4, 64bit=8 |
bool | 4 | BOOL (Win32) | 4バイト整数 |
bool1 | 1 | bool (C++) | 1バイト |
bool2 | 2 | VARIANT_BOOL | COM 用 |
char N | N | char[N] | 固定長 ANSI 文字列 |
wchar N | N*2 | wchar_t[N] | 固定長 UTF-16 文字列 |
構造体名 | 可変 | struct 入れ子 | ネスト構造体 |
デフォルトは pack=8 で MSVC の C 構造体 ABI に準拠します。各メンバのオフセットは min(フィールド自然アライメント, pack値) の倍数に揃えられます。構造体全体のサイズは最大メンバアライメントの倍数に切り上げられます。
#defstruct POINT
#field int x
#field int y
#endstruct
#defstruct RECT
#field int left
#field int top
#field int right
#field int bottom
#endstruct
; global で宣言すると #module 内からも参照可能
#defstruct global GUID, pack=1
#field int Data1
#field short Data2
#field short Data3
#field byte Data4 8
#endstruct
; 使い方
stdim pt, POINT ; NSTRUCT 変数を確保
pt->x = 100
pt->y = 200
mes "x=" + pt->x
#defstruct global 名前 で宣言すると、構造体名がグローバルスコープに登録され、任意の #module 内から参照できます。省略するとファイルスコープです。
#defstruct で定義した構造体の NSTRUCT 変数に対して、C 言語風の -> 演算子でメンバを読み書きできます。
stdim rc, RECT
rc->left = 10
rc->top = 20
rc->right = 640
rc->bottom = 480
mes "width = " + (rc->right - rc->left)
プリプロセッサフェーズで以下のように展開されます:
| HSP コード | 展開結果 |
|---|---|
v->member (読み取り) | _struct_peek(v, offset, type, size) |
v->member = val (書き込み) | _struct_poke v, offset, type, struct_size, member_size, val |
ネストされた構造体チェーン a->b->c や配列インデックス arr(i)->member もサポートされています。
-> はコンパイル時のテキスト展開であり、ランタイムコストはバイトオフセットによる直接メモリアクセスのみです。C のポインタ演算と同等の速度で動作します。
任意の COM インターフェースを HSP スクリプトから実装できます。IDropTarget, IBindStatusCallback 等の COM コールバックをスクリプト側で処理するために使用します。
#defcbcom クラス名 インターフェース名
#cbmethod vtableインデックス 戻り値型 [引数型, ...] *ラベル
...
#endcbcom
| 要素 | 説明 |
|---|---|
| クラス名 | HSP 側で使用するクラス識別名 |
| インターフェース名 | #usecom で事前登録した COM インターフェース名 |
| vtableインデックス | IUnknown の 3 メソッド (0,1,2) の次から。3 以上 64 未満 |
| 戻り値型 | int, int64, intptr, double, float, str, wstr, comobj |
| 引数型 | 上記に加え sval<N> (構造体値渡し) |
#usecom IDropTarget "{00000122-0000-0000-C000-000000000046}"
#defcbcom MyDropTarget IDropTarget
; vtable 3: DragEnter(pDataObj, grfKeyState, pt_lo, pt_hi, pdwEffect)
#cbmethod 3 int comobj, int, int, int, intptr, *on_drag_enter
; vtable 4: DragOver
#cbmethod 4 int int, int, int, intptr, *on_drag_over
; vtable 5: DragLeave
#cbmethod 5 int *on_drag_leave
; vtable 6: Drop
#cbmethod 6 int comobj, int, int, int, intptr, *on_drop
#endcbcom
; インスタンス化
newcomcb myobj, "MyDropTarget"
; myobj は COM オブジェクトとして Win32 API に渡せる
*on_drag_enter
; comprm(N) で引数取得
key_state = comprm(1)
comret 0 ; S_OK
return
*on_drop
comret 0 ; S_OK
return
| 命令/関数 | 説明 |
|---|---|
comprm(N) | N 番目の引数を取得 (0 始まり) |
comret 値 | 戻り値を設定 |
comcbidx() | 現在呼び出されている vtable インデックス |
comcbtag() | newcomcb 時に設定した整数タグ |
comcbtags() | newcomcb 時に設定した文字列タグ |
comcbis(var) | 現在の this ポインタが var と同じか判定 |
comcbthis() | 現在の this ポインタを intptr で取得 |
バニラ HSP の #cfunc は int 戻り値しかサポートしていません。IronHSP では構造体・double・float 戻り値に対応しています。
| ディレクティブ | 戻り値型 | 内部オペコード | 備考 |
|---|---|---|---|
#cfunc | int | callfunc (0x100) | バニラ HSP と同じ |
#cfuncd | double | callfuncd (0x107) | IronHSP |
#cfuncf | float | callfuncf (0x108) | IronHSP float→double 昇格 |
#cfuncst | struct (値渡し) | callfuncst (0x10A) | IronHSP 隠し第1引数にポインタ |
; 新形式 (構造体名指定)
#cfuncst [global] 構造体名 関数名 "エントリポイント" [パラメータ型...]
; レガシー形式 (サイズ直指定)
#cfuncst [global] 関数名 "エントリポイント" サイズ [, パラメータ型...]
C/C++ で構造体を値で返す関数は、実際には呼び出し元が確保したバッファへのポインタを隠し第1引数 (x64: RCX, x86: スタック先頭) として渡します。#cfuncst はこの 隠し引数挿入 を自動的に行います。
; C 側: POINT GetCursorPos2(void)
; 実際の ABI: void GetCursorPos2(POINT *__retval)
#defstruct POINT
#field int x
#field int y
#endstruct
#uselib "mylib.dll"
#cfuncst POINT GetCursorPos2 "GetCursorPos2"
; 呼び出し (戻り値は NSTRUCT 変数に自動格納)
pt = GetCursorPos2()
mes pt->x + ", " + pt->y
#cfuncst の戻り値は NSTRUCT 型 です。ランタイムが hsp_nstruct_pending_size にサイズヒントを設定し、代入先の変数が暗黙的に NSTRUCT として確保されます。
| オペコード | キーワード | 説明 |
|---|---|---|
| 0x21 | dim64 | 64ビット整数 (INT64) 配列確保 |
| 0x22 | stdim | NSTRUCT 変数確保 |
| 0x23 | _struct_poke | 構造体メンバ書き込み (内部用) |
| 0x24 | wsdim | UTF-16 ワイド文字列 (WSTR) 配列確保 |
| 0x25 | dimmap | 連想配列 (MAP) 確保 |
| オペコード | キーワード | 説明 |
|---|---|---|
| 0x032 | setenv | 環境変数を設定 |
| 0x033 | delenv | 環境変数を削除 |
| 0x034 | delmap | MAP エントリを削除 |
| 0x035 | mapclear | MAP を全消去 |
| オペコード | キーワード | 説明 |
|---|---|---|
| 0x17 | _struct_peek | 構造体メンバ読み取り (内部用) |
| 0x200 | getenv | 環境変数を取得 (UTF-8) |
| 0x201 | hasenv | 環境変数の存在確認 |
| 0x202 | getcmdargc | コマンドライン引数の数 |
| 0x203 | getcmdarg | N 番目のコマンドライン引数 |
| 0x204 | getcmdargs | 名前付きコマンドライン引数 |
| 0x207 | hasmap | MAP キーの存在確認 |
| 0x208 | mapcount | MAP エントリ数 |
| 0x209 | mapkey | MAP キーをインデックスで取得 |
| オペコード | キーワード | 説明 |
|---|---|---|
| 0x40 | _cb_class_begin | COM コールバッククラス開始 (内部) |
| 0x41 | _cb_class_method | COM コールバックメソッド定義 (内部) |
| 0x42 | _cb_class_end | COM コールバッククラス終了 (内部) |
| 0x43 | newcomcb | COM コールバックインスタンス作成 |
| 0x44 | comret | コールバック戻り値設定 |
| 0x150 | comprm | コールバック引数取得 |
| 0x151 | comcbidx | 現在の vtable インデックス |
| 0x152 | comcbtag | 整数タグ取得 |
| 0x153 | comcbtags | 文字列タグ取得 |
| 0x154 | comcbis | this ポインタ比較 |
| 0x155 | comcbthis | this ポインタ (intptr) |
intptr はプラットフォームのポインタ幅に合わせて 32bit 環境では 4 バイト、64bit 環境では 8 バイトとなる整数型です。
| 定義 | 値 | ファイル |
|---|---|---|
MPTYPE_INTPTR | -24 | hsp3struct.h:248 |
HSPLPTR | long (64bit) / int (32bit) | hsp3struct.h:33-37 |
| 構造体メンバ型 | SMT_PTR | token.h StructMemberType enum |
#func, #cfunc, #comfunc 等のパラメータ型として intptr を指定できます。DLL の void*, HANDLE, HWND, LPARAM 等のポインタ引数に使用してください。
#uselib "user32.dll"
#cfunc FindWindowW "FindWindowW" wstr, wstr
#func SetWindowTextW "SetWindowTextW" intptr, wstr
hwnd = FindWindowW("Notepad", 0)
SetWindowTextW hwnd, "Hello"
バニラ HSP では if の後にブレースを同一行に書く必要がありましたが、IronHSP では 次の行にブレースを置く Allman スタイル もサポートしています。
; K&R スタイル (従来通り動作)
if a > 0 {
mes "positive"
}
; Allman スタイル (IronHSP で追加)
if a > 0
{
mes "positive"
}
実装: codegen.cpp の if 解析で、行末 { がなかった場合に次行の先頭を先読みして { を検出します。
| FLAG | 名前 | 定義 | 概要 |
|---|---|---|---|
| 8 | INT64 | hspvar_int64 | 64ビット整数 |
| 9 | NETOBJ | hspvar_netobj | .NET オブジェクト参照 (GCHandle) |
| 10 | WSTR | hspvar_wstr | UTF-16 ワイド文字列 |
| 11 | NSTRUCT | hspvar_nstruct | ネイティブ構造体 (バイナリレイアウト) |
| 12 | MAP | hspvar_map | 連想配列 (文字列→文字列) |
バニラ HSP の変数型: 0=なし, 1=label, 2=str, 3=double, 4=int, 5=struct, 6=comobj (最大 FLAG=10)
Win32 API や C DLL とのデータ交換で必要な バイナリレイアウトを正確に保持 する変数型です。バニラ HSP の TYPE_STRUCT (モジュール変数) とは異なり、名前付きフィールドではなくバイトオフセットで直接メモリにアクセスします。
PVal
├─ flag = HSPVAR_FLAG_NSTRUCT (11)
├─ len[0] = 要素サイズ (バイト数) 例: POINT なら 8
├─ len[1] = 配列サイズ 例: 10 個なら 10
├─ pt → calloc(要素サイズ * 配列サイズ) で確保した生バッファ
└─ mode = HSPVAR_MODE_MALLOC
; #defstruct で定義した構造体名を使用
stdim var, POINT ; POINT サイズの NSTRUCT を 1 個確保
stdim arr, RECT, 10 ; RECT サイズの配列を 10 個確保
; cfuncst の戻り値は自動的に NSTRUCT になる
pt = GetSomePoint() ; 暗黙確保 (hsp_nstruct_pending_size で通知)
Set/Get: memcpy ベースのバイナリコピー_struct_poke / _struct_peek: メンバ単位の読み書き (-> 演算子から呼び出し)FIXEDARRAY, FLEXSIZE| コード | 型 | サイズ |
|---|---|---|
| 0 | SMT_BYTE | 1 |
| 1 | SMT_SHORT | 2 |
| 2 | SMT_INT | 4 |
| 3 | SMT_INT64 | 8 |
| 4 | SMT_FLOAT | 4 |
| 5 | SMT_DOUBLE | 8 |
| 6 | SMT_PTR | 4 or 8 (intptr) |
| 7 | SMT_BOOL | 4 |
| 8 | SMT_BOOL1 | 1 |
| 9 | SMT_BOOL2 | 2 |
| 10 | SMT_CHAR_ARRAY | 可変 |
| 11 | SMT_WCHAR_ARRAY | 可変 (MultiByteToWideChar で変換) |
// hspvar_map.cpp
struct MapData {
std::unordered_map<std::string, std::string> entries;
std::string current_key; // ArrayObject の書き込みターゲットキー
std::string read_buf; // ArrayObjectRead の戻りバッファ
};
std::string)map("key") = value で代入、map("key") で読み取りArrayObject / ArrayObjectRead フックで配列添字アクセスを横取りSTORAGE, ARRAYOBJ, NOCONVERT, VARUSE; 確保
dimmap m
; 書き込み
m("name") = "Alice"
m("age") = "30"
; 読み取り
mes m("name") ; "Alice"
; 存在確認
if hasmap(m, "name") { mes "found" }
; エントリ数
mes "count = " + mapcount(m)
; キー一覧
repeat mapcount(m)
mes mapkey(m, cnt)
loop
; 削除
delmap m, "name"
; 全消去
mapclear m
int(m("key")) 等の明示的な変換が必要です。
Win32 W 版 API に直接渡せる UTF-16 (Little Endian) 文字列型です。
wsdim ws, 260 ; 260 wchar_t 分のバッファ確保
#func / #cfunc のパラメータ型として wstr を指定すると、HSP 文字列 (UTF-8) から自動的に UTF-16 に変換されて渡されます。var で受け取った場合は変換されず、UTF-16 バイト列がそのまま格納されます。
wstr パラメータで UTF-8→UTF-16 自動変換var パラメータで UTF-16 バッファを受け取り、WideCharToMultiByte で手動変換dim64 v, 10 ; INT64 配列を 10 要素確保
8バイト (64ビット) 整数配列です。Win32 API の LARGE_INTEGER, FILETIME 等のデータ格納に使用します。
Section 2.5 の一覧も参照してください。ここでは使い方を解説します。
; 環境変数を設定
setenv "MY_KEY", "MY_VALUE"
; 環境変数を取得 (UTF-8)
val = getenv("PATH")
val2 = getenv("MISSING", "default") ; デフォルト値指定
; 存在確認
if hasenv("MY_KEY") { mes "exists" }
; 削除
delenv "MY_KEY"
; 引数の数
n = getcmdargc()
; N番目の引数 (0始まり, 0=実行ファイル名)
repeat n
mes getcmdarg(cnt)
loop
; 名前付き引数: program.exe --port 8080 --name test
port = getcmdargs("--port", "3000") ; デフォルト "3000"
name = getcmdargs("--name", "unknown")
内部では CommandLineToArgvW() + UTF-8 変換を使用。最初の呼び出し時に 1 回だけパースしてキャッシュします。
.NET 連携は C++/CLI で実装されています。HSP ランタイム (ネイティブ C++) と .NET マネージドコード (C#/VB.NET) の間を C++/CLI がブリッジします。
HSP スクリプト
│ mcall / newnet / callnet
▼
hsp3ext_win.cpp (ネイティブ C++)
│ Hsp3Net::InvokeMethod() 等
▼
Hsp3Net.h / Hsp3Net.cpp (C++/CLI マネージドラッパー)
│ System::Reflection
▼
.NET Framework (System.*, System.Windows.Forms, etc.)
| クラス | ファイル | 役割 |
|---|---|---|
Hsp3Net | Hsp3Net.h/cpp | リフレクション経由でメソッド呼び出し・プロパティアクセス・配列操作 |
GlobalAccess | Hsp3Net.h:382-561 | GCHandle 管理。マネージドオブジェクトへのネイティブポインタの発行・追跡・解放 |
HspCallbackProxy | Hsp3Net.h:572-660 | HSP ラベルを .NET デリゲートにブリッジ |
HspForms | HspForms.h/cpp | WinForms コントロール管理 |
HspFormsInterop | HspFormsInterop.h/cpp | C リンケージでネイティブ→マネージド呼び出し |
NETOBJ (FLAG=9) は .NET オブジェクトへのネイティブポインタ (GCHandle) を格納する変数型です。
newnet var, "System.Collections.ArrayList" で .NET インスタンス作成GlobalAccess::CreateNativePtr() が GCHandle.Alloc() でマネージドオブジェクトをピン留めdelnet var で GlobalAccess::Free() → GCHandle.Free()GlobalAccess は 2 つのセットでポインタを追跡します:
_NativePtrAllSet: 全てのアクティブな GCHandle_NativePtrCurrentScopeSet: 現在のスコープで作成された GCHandle (スタック式)PushNativePtrCurrentStack() / PopNativePtrCurrentStack() で関数呼び出しスコープに連動した自動解放を行います。
| 方向 | 変換内容 |
|---|---|
| STR → NETOBJ | Hsp3Net::CreateString() |
| INT → NETOBJ | Hsp3Net::CreateInt32() |
| DOUBLE → NETOBJ | Hsp3Net::CreateDouble() |
| NETOBJ → STR | obj.ToString() |
| NETOBJ → INT | Convert.ToInt32() |
| NETOBJ → DOUBLE | Convert.ToDouble() |
| オペコード | 命令 | 構文 | 説明 |
|---|---|---|---|
| 0x0d | loadnet | loadnet "名前", opt [, refs...] | アセンブリ読み込み (下記参照) |
| 0x0e | newnet | newnet var, "クラス名" [, args...] | .NET インスタンス作成 |
| 0x0f | delnet | delnet var | .NET オブジェクト解放 |
| 0x10 | netres | netres(var) | メソッド呼び出し結果取得 |
| opt | 意味 | 例 |
|---|---|---|
| 0 | GAC 短縮名 | loadnet "System.Windows.Forms", 0 |
| 1 | GAC 完全名 | loadnet "System.Windows.Forms, Version=4.0.0.0, ...", 1 |
| 2 | ファイルパス | loadnet "MyLib.dll", 2 |
| 3 | C# ソースコード | loadnet cs_source, 3 [, "ref1.dll", ...] |
| 4 | VB.NET ソースコード | loadnet vb_source, 4 [, "ref1.dll", ...] |
loadnet の opt=3 で C# ソースコードを動的コンパイルして即座にロードできます。
cs = {"
using System;
public class MyMath {
public static int Add(int a, int b) { return a + b; }
public static string Greet(string name) {
return "Hello, " + name + "!";
}
}
"}
loadnet cs, 3
; 静的メソッド呼び出し
newnet dummy, "MyMath"
mcall dummy, "Add", result, 10, 20
mes result ; 30
mcall dummy, "Greet", greeting, "HSP"
mes greeting ; "Hello, HSP!"
loadnet cs, 3, "System.Xml.dll", "System.Xml.Linq.dll"
hsp3net の GUI ランタイムは内部で System.Windows.Forms.Form をホストし、HSP のウィンドウと WinForms コントロールをハイブリッドで管理します。
| 関数 | 説明 |
|---|---|
HspInterop_CreateButton | Button コントロール作成 |
HspInterop_CreateCheckBox | CheckBox 作成 |
HspInterop_CreateTextBox | TextBox 作成 |
HspInterop_CreateComboBox | ComboBox 作成 |
HspInterop_CreateListBox | ListBox 作成 |
HspInterop_IsManagedControl | マネージドコントロールか判定 |
HspInterop_DestroyControl | コントロール破棄 |
HspInterop_SetControlText | テキスト設定 |
上位レベルでは iron_forms.hsp が mcall 経由で DataGridView, PropertyGrid, TabControl, Anchor/Dock 等の高機能コントロールを提供します。
HspCallbackProxy クラスが HSP ラベルを .NET デリゲートにブリッジします。
| パターン | メソッド | 用途 |
|---|---|---|
EventHandler | HandleEvent(sender, e) | ボタンクリック等のイベント |
Action | HandleAction() | 引数なしコールバック |
Func<T, bool> | HandlePredicate(item) | LINQ Where 等 |
Func<T, TResult> | HandleSelector(item) | LINQ Select 等 |
内部では HSP の code_callback() を呼び出し、HSP スクリプト上の *label にジャンプ → stat を戻り値として回収します。
COM インターフェースの vtable メソッドが呼ばれた際に HSP ラベルにジャンプするために、動的にマシンコードを生成 (JIT thunk) しています。
; 512 バイトのコードバッファ
; RCX, RDX, R8, R9 → args[0..3] に保存
; スタック引数 → args[4+] に保存
; R10/R11 をスクラッチレジスタとして使用
; hsp_cbcom_bridge() を呼び出し
; 256 バイトのコードバッファ
; スタック引数をコピー
; __cdecl 呼び出し規約
; hsp_cbcom_bridge() を呼び出し
VirtualAlloc で PAGE_EXECUTE_READWRITE メモリを確保し、マシンコードを書き込みます。vtable にこの thunk のアドレスを設定することで、COM メソッド呼び出しが HSP ラベルにディスパッチされます。
*ppv = this、不一致は E_NOINTERFACEInterlockedIncrement(&refcount)InterlockedDecrement(&refcount)。0 でクリーンアップ| マクロ | 定義時 | 用途 |
|---|---|---|
HSP64 | 64ビットビルド | ランタイム全体で条件分岐 |
PTR64BIT | 64ビットポインタ | 構造体サイズ計算 |
PTR32BIT | 32ビットポインタ | 構造体サイズ計算 |
.ax (オブジェクトファイル) は 32bit アラインメントで保存されるため、64bit ランタイムではポインタフィールドの変換が必要です:
| 構造体 | ファイル上 (HED_*) | メモリ上 (32bit) | メモリ上 (64bit) |
|---|---|---|---|
STRUCTDAT | int p_libptr | void *proc (4byte) | void *proc (8byte) |
HPIDAT | int p_libptr | void *libptr (4byte) | void *libptr (8byte) |
LIBDAT | int p_hlib | void *hlib (4byte) | void *hlib (8byte) |
| 項目 | x86 | x64 |
|---|---|---|
| 引数バッファ型 | int *prm | INT_PTR *prm |
| double 戻り値 | call_extfunc_double_x86 (FPU ST(0)) | call_extfunc_double (XMM0) |
| float 戻り値 | call_extfunc_float_x86 (FPU ST(0)) | call_extfunc_float (XMM0) |
| COM ポインタ | code_getdi() (32bit cast) | code_getdi64() (64bit 保持) |
| Thunk サイズ | 256 バイト | 512 バイト (SEH 互換) |
バニラ HSP にはない環境変数・コマンドライン引数操作を追加しています。全て UTF-8 で処理されます。
setenv "KEY", "VALUE" ; 設定 (内部: MultiByteToWideChar + SetEnvironmentVariableW)
val = getenv("KEY") ; 取得 (内部: GetEnvironmentVariableW + WideCharToMultiByte)
val = getenv("KEY", "default") ; デフォルト値付き
if hasenv("KEY") { ... } ; 存在確認
delenv "KEY" ; 削除
n = getcmdargc() ; 引数数 (内部: CommandLineToArgvW)
arg0 = getcmdarg(0) ; 実行ファイルパス
arg1 = getcmdarg(1) ; 第1引数
; 名前付き引数: --key value 形式
port = getcmdargs("--port", "8080")
HSP の #define は大文字・小文字を区別しません。#define LOG_DEBUG 0 を宣言すると、log_debug という関数名もマクロ展開されて壊れます。定数名と関数名の衝突に注意してください。
; NG: LOG_DEBUG が log_debug にもマッチする
#define LOG_DEBUG 0
log_debug "msg" ; → 0 "msg" に展開されてエラー
; OK: プレフィックスで回避
#define LOGLV_DEBUG 0
#cfunc / #cfuncd / #cfuncf / #cfuncst で宣言した関数は 必ず関数形式 r = func(args) で呼び出してください。命令形式 func args はコンパイルエラーにならないことがありますが、正しく動作しません。
; NG
FindWindowW "Notepad", 0
; OK
hwnd = FindWindowW("Notepad", 0)
#module 〜 #global 内のトップレベルに書いた dim / sdim 等の初期化コードは 実行されません。初期化は #deffunc 内で行うか、varname@modname 構文でモジュール変数に直接代入してください。
#defcfunc の str パラメータは一時バッファを指しているため、peek や strmid を直接適用するとクラッシュすることがあります。ローカル変数にコピーしてから操作してください。
#defcfunc my_func str s
local ss
ss = s ; ローカルにコピー
c = peek(ss, 0) ; OK
return c
W 版 API (GetTempPathW 等) の出力は UTF-16 です。var で受け取った後、WideCharToMultiByte(65001, ...) で UTF-8 に変換する必要があります。
また、W 版 API の出力を別の W 版 API の入力に渡す 場合、wstr ではなく var で渡してください。wstr は UTF-8→UTF-16 変換を行うため、既に UTF-16 のバッファを二重変換してしまいます。
HSP の return で文字列を返す場合、stat は変更されず refstr に格納されます。確実に stat を返したい場合は var 出力パラメータを使用してください。
; NG: stat は直前の API 戻り値のまま
#deffunc my_read str key
return "value" ; refstr に入る, stat は不定
; OK: var で明示出力
#deffunc my_read str key, var out_result
out_result = "value"
return 0 ; stat = 0
MAP の内部は std::unordered_map<string, string> です。数値を格納すると文字列に変換されます。取り出し時に int() や double() で明示変換が必要です。
cfuncst 関数の戻り値を変数に代入すると、その変数は自動的に NSTRUCT 型になります。hsp_nstruct_pending_size グローバル変数を通じてサイズが通知され、代入時にクリアされます。一度確保された NSTRUCT 変数はそのまま再利用できます。
newcomcb で作成した COM オブジェクトの寿命は AddRef/Release のリファレンスカウントで管理されます。HSP 変数がスコープを抜けても、COM 側で参照が残っていれば解放されません。リークに注意してください。
64bit ビルドでは COM メソッドのポインタ引数に intptr を使用してください。int では上位 32bit が切り捨てられます。
| ファイル | 主要な責務 |
|---|---|
hspcmd.cpp | キーワード定義テーブル (全 TYPE のオペコード↔キーワード対応) |
token.cpp | プリプロセッサ (PP_* 関数群): #defstruct パース、-> 展開、構造体検出、sval<N> 変換 |
token.h | StructDef / StructMember / CbComClass 構造体、StructMemberType enum、変数→構造体ID マップ |
codegen.cpp | コード生成 (GenerateCodePP_*): #defstruct/#defcbcom/#cbmethod のバイトコード出力、アライメント計算 |
errormsg.h | エラーコード定義 (CGERROR_PP_* 系追加) |
| ファイル | 主要な責務 |
|---|---|
hspvar_core.h | 変数型 FLAG 定義 (MAX=13)、PVal 構造体 |
hspvar_core.cpp | 変数型登録 (NSTRUCT, MAP 追加) |
hspvar_map.cpp/h | MAP 型実装 (MapData, ArrayObject/Read) |
hspvar_nstruct.cpp | NSTRUCT 型実装 (calloc, memcpy, pending_size) |
hsp3struct.h | MPTYPE_INTPTR 定義、STRUCTDAT/HPIDAT/LIBDAT の 32/64bit 分岐 |
hsp3code.cpp | 中間コード実行: dimmap/structdim/_struct_poke 命令処理 |
hsp3int.cpp | 拡張命令実行: setenv/delenv/delmap/mapclear + getenv/hasenv/getcmdarg* 関数 |
| ファイル | 主要な責務 |
|---|---|
Hsp3Net.h | Hsp3Net/GlobalAccess/HspCallbackProxy クラス定義 (C++/CLI) |
Hsp3Net.cpp | リフレクション実装: メソッド呼び出し、C#/VB コンパイル、型変換 |
hspvar_netobj.cpp/h | NETOBJ 変数型 (GCHandle ⇔ void*) |
hsp3ext_win.cpp | DLL 拡張: callfunc*/newcomcb/comret + COM コールバック thunk 生成 |
HspForms.cpp/h | WinForms コントロール管理 |
HspFormsInterop.cpp/h | ネイティブ→マネージド C リンケージブリッジ |