ランタイムの作成

ランタイムの作成には必要なファイルが2つあります。
1つはHSPのインストール先のHSPSDKフォルダにあるhsp2lib.libです。これにはHSPのスクリプトエンジンとしての全機能が入っています。
もう1つはそのhsp2lib.libが使用するC標準ライブラリです。HSPはCで作成されているため当然標準ライブラリを使用していますがその内容はhsp2lib.libには含まれていません。そのため、C標準ライブラリを用意する必要があります。Cの開発環境があればC標準ライブラリが付いているので、ライセンス規約に問題なければそれを使用すればいいでしょう。ここではVC++6.0のlibc.libを使用します。

ランタイムの実行はWinMainCRTStartupから始まり、大まかに以下のようになっています。
WinMainCRTStartupはlibc.libの関数、WinMainはユーザ作成の関数、HSPWinMainはhsp2lib.libの関数です。

(WinMainCRTStartup)
標準ライブラリの初期化
↓↑
(WinMain)
追加機能の登録と初期化・終了処理
↓↑
(HSPWinMain)
HSPスクリプトの実行

ランタイムの作成手順は

1:追加機能を作成
2:1をHSPに登録するためのWinMainを作成
3:1・2とhsp2lib.lib、libc.libをリンク

となります。

追加機能は「プラグインの作成」で作成したTestHpi.asmを3行修正して使用します。


ファイル名:TestHpi.asm

;*********************************************************************
;タイトルに日付を持つMessageBoxを表示
;TestProc p1,p2
;TestProc2 p1,p2
;p1:メッセ−ジ
;p2:MessageBoxのタイプ
;*********************************************************************
        .386
        .model flat,stdcall
        option casemap:none

        include windows.inc
        include hspdll.inc

        include kernel32.inc
        include user32.inc
        includelib kernel32.lib
        includelib user32.lib
;*********************************************************************
.data
        fmt db "%04d年%02d月%02d日",0
.code
;*********************************************************************
testhpi_DllMain PROC ,hInstDLL:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID
        mov eax,TRUE
        ret
testhpi_DllMain ENDP
;*********************************************************************
TestProc PROC EXPORT,pBms:ptr BMSCR, pMsg:ptr CHAR ,uType ,tmp  ;type 6
        LOCAL stime:SYSTEMTIME ,date[SIZEOF fmt]:CHAR

        invoke GetLocalTime,ADDR stime
        movzx eax,stime.wYear
        movzx ecx,stime.wMonth
        movzx edx,stime.wDay
        invoke wsprintf,ADDR date,ADDR fmt,eax,ecx,edx
        mov ecx,pBms
        invoke MessageBox,[ecx].BMSCR.hwnd,pMsg,ADDR date,uType
        neg eax
        ret
TestProc ENDP
;*********************************************************************
TestProc2 PROC EXPORT USES ebx ,pExinfo:ptr HSPEXINFO, tmp1,tmp2,tmp3   ;type$202
        LOCAL stime:SYSTEMTIME ,date[SIZEOF fmt]:CHAR ,pMsg ,uType

        invoke GetLocalTime,ADDR stime
        movzx eax,stime.wYear
        movzx ecx,stime.wMonth
        movzx edx,stime.wDay
        invoke wsprintf,ADDR date,ADDR fmt,eax,ecx,edx
        mov ebx,pExinfo
        ASSUME ebx:ptr HSPEXINFO
        invoke [ebx].HspFunc_prm_gets
        mov pMsg,eax
        invoke [ebx].HspFunc_prm_getdi,MB_OK
        mov uType,eax
        mov ecx,[ebx].er
        mov eax,[ecx]
        .if eax
                ret
        .endif
        mov eax,[ebx].actscr
        invoke [ebx].HspFunc_getbmscr,DWORD ptr [eax]
        mov ecx,eax     ;eaxはスタック変数のアドレス取得に使われる
        invoke MessageBox,[ecx].BMSCR.hwnd,pMsg,ADDR date,uType
        neg eax
        ret
TestProc2 ENDP
;*********************************************************************

END

DllMainをtesthpi_DllMainに変更しているのは、複数のプラグインをランタイムに加える場合、名前の衝突が起こるためです。
ENDディレクティブのパラメータは外します。

作成したランタイムが関数をエクスポートした状態にしたくない場合はPROCディレクティブのEXPORTを削除します。(そのままでも問題はありません)



WinMainのサンプルを示します。


ファイル名:TestHrt.asm

;**************************************************************************
        .386
        .model flat,stdcall
        option casemap:none

        include windows.inc
        include hspdll.inc

        includelib kernel32.lib
        includelib gdi32.lib
        includelib user32.lib
        includelib comdlg32.lib
        includelib shell32.lib
        includelib winmm.lib
        includelib advapi32.lib

        includelib hsp2lib.lib
        includelib libc.lib
;**************************************************************************
        ;hsp2lib.lib用ヘッダ(hsp2lib.inc)

        HSPCMD_INFO STRUCT
                ver DWORD 0                     ;// version info
                DLLname CHAR 24 dup (0)         ;// replace DLL name
                hspfnc ppCHAR 0                 ;// array of function name/ptr
        HSPCMD_INFO ENDS

        HSPWinMain PROTO C,:DWORD,:DWORD,:DWORD,:DWORD
        HSPSetFunc PROTO C,:DWORD
;**************************************************************************
        ;拡張ランタイムのためのヘッダ(testhpi.inc)

        testhpi_Ver equ 0000h                   ;  拡張ランタイムのバージョン(0x0000)
        testhpi_Name equ <"testhpi.dll">        ;  DLLのファイル名(小文字で拡張子も含めること)

        ;DllMain関数の宣言をする
        ;(DllMainを「DLL名_DllMain」に変更したもの)
        testhpi_DllMain PROTO ,hInstDLL:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID

        ;DLLで使用されている関数のプロトタイプ宣言をする

        TestProc  PROTO ,pBms:ptr BMSCR, p1:ptr CHAR, p2:DWORD ,tmp:DWORD
        TestProc2 PROTO ,pExinfo:ptr HSPEXINFO, tmp1:DWORD ,tmp2:DWORD ,tmp3:DWORD

.data
        ;HSPのスクリプトで定義されている命令の名前(小文字)と
        ;それに対応する関数を指定する。
        ;「"HSP定義命令名", (char *)DLL関数名,」
        ;のように指定してください。
        ;「NULL, NULL」が最後の行になります。
        
        FuncName01 db "TestProc",0
        FuncName02 db "TestProc2",0

        align 4

        testhpi_hspfnc pCHAR     FuncName01,TestProc  \
                                ,FuncName02,TestProc2 \
                                ,NULL,NULL

        info HSPCMD_INFO {testhpi_Ver,testhpi_Name,testhpi_hspfnc}

;**************************************************************************

.code
WinMain PROC ,hInstance:HINSTANCE ,hPrevInstance:HINSTANCE ,lpCmdLine:LPSTR ,nCmdShow:DWORD

        invoke HSPSetFunc,ADDR info
        invoke testhpi_DllMain ,hInstance ,DLL_PROCESS_ATTACH ,NULL
        invoke HSPWinMain ,hInstance ,hPrevInstance ,lpCmdLine ,nCmdShow
        push eax
        invoke testhpi_DllMain ,hInstance ,DLL_PROCESS_DETACH ,NULL
        pop eax
        ret
WinMain ENDP

;*************************************************************************

END

WinMainの名前は固定されています。他の名前に変更できません。
エントリポイント(ENDディレクティブのパラメータ)を指定しないのは、WinMainCRTStartupが開始位置に決まっているからです。もしWinMainをエントリポイントにしてしまうと標準ライブラリが初期化されないため、問題が起きてしまいます。

プラグインを複数登録する場合は、プラグインの数だけ、HSPCMD_INFO型変数の作成とHSPSetFunc・DllMainの呼び出しを行います。

プラグインの初期化処理の返り値のチェックはしていません。
プラグインの初期化処理と終了処理は、今回のように何もしていない場合は省略することが可能です。

このファイルとプラグインのファイルとライブラリをリンクすることでランタイムを作成できます。
OLDNAMES.LIBは使用されていないが、リンク設定になっているので外すように指定します


TestHrt.hrt作成用バッチファイル

@ECHO OFF
Rc.exe hsp2.rc
Ml.exe /c /coff TestHrt.asm TestHpi.asm 
if errorlevel 1 goto error
Link.exe /SUBSYSTEM:WINDOWS  /NODEFAULTLIB:OLDNAMES.LIB /OUT:TestHrt.hrt TestHrt.obj TestHpi.obj hsp2.res
if errorlevel 1 goto error
goto fin
:error
echo ===============================エラー======================================
:fin
echo ===============================終了=======================================

TestHrt.hrtを動作させるHSPスクリプト

;CTRL+F9でTest.exeが作成されます
#packopt name "Test.exe"
#packopt runtime "TestHrt.hrt"
#uselib "TestHpi.dll"
#func TestProc  TestProc        6
#func TestProc2 TestProc2       $202
#define MB_ICONERROR    $00000010
#define MB_ICONQUESTION $00000020

testproc "test1",MB_ICONERROR
testproc2 "test2",MB_ICONQUESTION

戻る