秀丸エディタから HSP のスクリプトをコンパイルして実行するための hspcmp のラッパー DLL とマクロを作りました。コマンドラインコンパイラを使ってコンパイルする秀丸マクロ ( Fuji Diablog ) ではスクリプトをファイルに保存しないとコンパイルできないのが問題でしたが、今回は保存する必要がありません。
VC++ で作ったものだったのですが、他のPCで動かなかった(多分作り方を間違えている)ので BCC で作り直したのをアップしなおしました。今度は他の PC でも動くはずです。
以下のようなマクロで呼び出します。
loaddll "hspcmpWrapper.dll";
if( !result ) {
message "DLL のロードに失敗しました。";
endmacro;
}
$tmpScript = directory + "\\hsptmp";
#ret = dllfunc( "CreateEmptyFile", $tmpScript );
appendsave $tmpScript;
#ret = dllfunc( "HSPCompile", hidemaruhandle(0), "C:\\Program Files\\hsp31", $tmpScript, basename2, "", 1 );
freedll;
最後の二つの引数は、起動オプションとコンパイルのモードです。最後から二つ目の引数には起動オプション(実行するHSP のプログラムへ送るコマンドライン)を指定します。最後の引数はコンパイルのモードです。 1 だとコンパイル+実行(デバッグ)ですが、 2 にすると EXE を作成します。
DLL のソースコードは以下の通りです。
#include <windows.h>
// ポインタを int にキャストするときの warning を無効に
#pragma warning(disable: 4311)
#ifdef UNICODE
// 秀丸マクロや HSPCMP.DLL の関係で Unicode 文字セットは使用できない
#error Unicode 文字セットを使わない設定にしてください
#endif
extern "C" __declspec(dllexport) int CreateEmptyFile( LPCSTR fileName ) {
// 空のファイルを作成( hsptmp 作成用)
if ( ::IsBadStringPtr( fileName, 1 ) ) {
// 引数が不正
return 1;
}
HANDLE hFile = ::CreateFile( fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( hFile == INVALID_HANDLE_VALUE ) {
return 1;
}
DWORD dwWriteSize;
::WriteFile( hFile, "", 0, &dwWriteSize, NULL );
::FlushFileBuffers( hFile );
::CloseHandle( hFile );
return 0;
}
typedef BOOL ( CALLBACK *FUNC_HSPCMP )( int, int, int, int );
#define COMPMODE_DEBUG 1
#define COMPMODE_MAKEEXE 2
extern "C" __declspec(dllexport) int HSPCompile(
HWND hWnd,
LPCSTR HSPDirName,
LPCSTR scriptFileName,
LPCSTR refScriptFileName,
LPCSTR commandLine,
int compileMode
) {
if (
::IsBadStringPtr( HSPDirName, 1 ) ||
::IsBadStringPtr( scriptFileName, 1 ) ||
::IsBadStringPtr( refScriptFileName, 1 ) ||
::IsBadStringPtr( commandLine, 1 )
) {
// 引数が不正
return 1;
}
if ( !::IsWindow( hWnd ) ) { // 存在しないウィンドウのハンドル
hWnd = NULL;
}
// DLL を読み込み
char dllFileName[1024];
::lstrcpy( dllFileName, HSPDirName );
::lstrcat( dllFileName, "\\hspcmp.dll" );
HINSTANCE hDLL = ::LoadLibrary( dllFileName );
if ( hDLL == NULL ) {
::MessageBox( hWnd, "DLL を読み込むことができません。", "hspcmpWrapper.dll", MB_OK | MB_ICONEXCLAMATION );
return 1;
}
FUNC_HSPCMP hsc_ini = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc_ini@16" );
FUNC_HSPCMP hsc_refname = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc_refname@16" );
FUNC_HSPCMP hsc_objname = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc_objname@16" );
FUNC_HSPCMP hsc_compath = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc_compath@16" );
FUNC_HSPCMP hsc_comp = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc_comp@16" );
FUNC_HSPCMP hsc_getmes = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc_getmes@16" );
FUNC_HSPCMP hsc_bye = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc_bye@16" );
FUNC_HSPCMP hsc3_make = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc3_make@16" );
FUNC_HSPCMP hsc3_getruntime = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc3_getruntime@16" );
FUNC_HSPCMP hsc3_run = ( FUNC_HSPCMP )::GetProcAddress( hDLL, "_hsc3_run@16" );
int result = 0;
LPCSTR objFileName = ( compileMode == COMPMODE_MAKEEXE ) ? "start.ax" : "obj";
hsc_ini( 0, reinterpret_cast<int>(scriptFileName), 0, 0 );
hsc_refname( 0, reinterpret_cast<int>(refScriptFileName), 0, 0 );
hsc_objname( 0, reinterpret_cast<int>(objFileName), 0, 0 );
// common ディレクトリのパス
char commonDirName[1024];
::lstrcpy( commonDirName, HSPDirName );
::lstrcat( commonDirName, "\\common\\" );
hsc_compath( 0, reinterpret_cast<int>(commonDirName), 0, 0 );
// オブジェクトファイルの作成
if( ( compileMode == COMPMODE_MAKEEXE ) ? hsc_comp( 0, 4, 0, 0 ) : hsc_comp( 1, 0, 1, 0 ) ) {
// 失敗
char errbuf[32000];
hsc_getmes( reinterpret_cast<int>(errbuf), 0, 0, 0 );
char errorMessage[32000];
::lstrcpy( errorMessage, "コンパイルに失敗しました\n" );
::lstrcat( errorMessage, errbuf );
::MessageBox( hWnd, errorMessage, "hspcmpWrapper.dll", MB_OK | MB_ICONEXCLAMATION );
result = 1;
goto free;
}
if ( compileMode == COMPMODE_MAKEEXE ) { // EXE作成
// ランタイムディレクトリのパス
char runtimeDirName[1024];
::lstrcpy( runtimeDirName, HSPDirName );
::lstrcat( runtimeDirName, "\\runtime" );
if ( hsc3_make( 0, reinterpret_cast<int>(runtimeDirName), 0, 0 ) ) {
// 失敗
char errbuf[32000];
hsc_getmes( reinterpret_cast<int>(errbuf), 0, 0, 0 );
char errorMessage[32000];
::lstrcpy( errorMessage, "EXE の作成に失敗しました\n" );
::lstrcat( errorMessage, errbuf );
::MessageBox( hWnd, errorMessage, "hspcmpWrapper.dll", MB_OK | MB_ICONEXCLAMATION );
result = 1;
} else {
::MessageBox( hWnd, "EXE を作成しました", "hspcmpWrapper.dll", MB_OK | MB_ICONINFORMATION );
}
goto free;
}
// デバッグ
// ランタイムファイル名の取得
char runtimeFileName[1024];
hsc3_getruntime( reinterpret_cast<int>(runtimeFileName), reinterpret_cast<int>(objFileName), 0, 0 );
if ( *runtimeFileName == '\0' ) {
::lstrcpy( runtimeFileName, "hsp3" );
}
// 実行のコマンドを作成
char execmd[1024];
::lstrcpy( execmd, HSPDirName );
::lstrcat( execmd, "\\" );
::lstrcat( execmd, runtimeFileName );
::lstrcat( execmd, " " );
::lstrcat( execmd, objFileName );
::lstrcat( execmd, " " );
::lstrcat( execmd, commandLine );
// 実行
if ( hsc3_run( reinterpret_cast<int>(execmd), 0, 0, 0 ) ) {
::MessageBox( hWnd, "実行用ランタイムファイルが見つかりません。", "hspcmpWrapper.dll", MB_OK | MB_ICONEXCLAMATION );
result = 1;
goto free;
}
free:
hsc_bye( 0, 0, 0, 0 );
::FreeLibrary( hDLL );
return result;
}
ちなみにこの hspcmpWrapper.dll は HSP からも使えたりします。
#uselib "hspcmpWrapper.dll"
#func CreateEmptyFile "CreateEmptyFile" sptr
#func HSPCompile "HSPCompile" int, sptr, sptr, sptr, sptr, int
HSPCompile hWnd, dir_exe, dir_exe + "\\sample\\demo\\demo.hsp", "demo.hsp", "", 1
HSP では hspcmp.dll 自体をそのまま使えるのであまり意味はないと思いますけど。