ランタイムの作成には必要なファイルが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行修正して使用します。
;********************************************************************* ;タイトルに日付を持つ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のサンプルを示します。
;************************************************************************** .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は使用されていないが、リンク設定になっているので外すように指定します
@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 ===============================終了=======================================
;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