前回からの続きです。
開発目標の確認
ここで第1回で掲げた開発目標を確認してみます。
目標 | 結果 |
---|---|
AVX2 未対応の古い CPU でも動く | 特に何もしていないが出来た |
Windows内蔵の C# コンパイラだけでビルドできる | ちょっと頑張れば出来た |
使用する将棋エンジンをコンパイル無しで切替可能 | 初期設定ファイルで対応 ※第5回で説明 |
対局するプレイヤー名を表示できるようにする | ShogiGUI のタイトルバーから読み出す ※第4回で説明 |
評価値バーを常に最前面で表示できるようにする | 超簡単にできた ※詳しくはソースコード参照 |
最後にWindows内蔵のC#コンパイラだけでビルドできるようにするためのちょっとした苦労を紹介します。
Windows 内蔵の C# コンパイラだけでビルド
Windows 内蔵の C# コンパイラでビルドするためのバッチファイルを以下に示します。C# コンパイラのインストールパスはPCによってあまり変わらないと思いますが,一応,レジストリを検索して正確なインストールパスを得るようにしています。
※シンタクスハイライトがおかしいので VScode のを貼りました。

build.bat のテキストを参照したい人はコチラ
@echo off
setlocal
rem ----------------------------------------------------------------------------
rem csc.exe にパスが通っているかどうかの確認
rem ----------------------------------------------------------------------------
set DOTNETPATH=
for %%I in ( csc.exe ) do set DOTNETPATH=%%~$PATH:I
if defined DOTNETPATH goto LETS_COMPILE
rem ----------------------------------------------------------------------------
rem .NET Framework のインストールパスを探す
rem ----------------------------------------------------------------------------
for /F "usebackq tokens=1,2,*" %%I in ( `reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v InstallPath` ) do (
if "%%I"=="InstallPath" set "DOTNETPATH=%%K"
)
if defined DOTNETPATH goto APPEND_PATH
echo ^[[91m.NET Framework のインストールパスが見つかりません!
pause
exit /b
:APPEND_PATH
echo パスに %DOTNETPATH% を追加します。
set "PATH=%PATH%;%DOTNETPATH%"
:LETS_COMPILE
rem ----------------------------------------------------------------------------
rem コンパイル
rem ----------------------------------------------------------------------------
echo evalbar.cs をコンパイルします。
if exist evalbar.exe del evalbar.exe
csc -o -w:4 -win32icon:shogi.ico evalbar.cs
if exist evalbar.exe goto SUCCESS
echo ^[[91mevalbar のコンパイルに失敗しました!
pause
exit /b
:SUCCESS
echo evalbar のコンパイルに成功しました。
pause
exit /b
便利な拡張メソッド
string.Contains() は,指定した文字が指定した文字列の中に存在するか確認するという便利なメソッドですが,Windows 内蔵の C# コンパイラ(.NET Framework)は対応していません。しかし,C# の持つ拡張メソッドという機能のおかげで以下のコードを追加するだけでよく,string.Contains() を使用しているコードを書き換えずに済みました。いやあ C# って本当に便利な言語ですね。
//------------------------------------------------------------------------------
// ユーザ拡張クラス
//------------------------------------------------------------------------------
static class UserExtension {
//--------------------------------------------------------------------------
// 指定した“文字”が指定した文字列内に存在するか確認する
//--------------------------------------------------------------------------
public static bool Contains( this string s, char c ) {
for( int i = 0; i < s.Length; i++ )
if( s[i] == c ) return( true );
return( false );
}
}
おまけ
アイコンでちょっと苦労したという話です。今回,将棋の駒型のアイコン shogi.ico を自作しています。これをアプリケーションプログラムにリンクするために下記のようなオプションをつけてビルドしました。こうするとビルドされたアプリケーションプログラム evalbar.exe は,エクスプローラーから将棋の駒型アイコンとして表示されます。
csc -o -w:4 -win32icon:shogi.ico evalbar.cs
しかし,今度は評価値バーのプログラム内で shogi.ico を利用しようと思っても,このアイコンを認識することができません。どうやら .NET Framework の機能では実現できないようです。このため SHGetFileInfo() というWin32 API を用いることになりました。
以下は,メインウィンドウのコンストラクタでタイトルバーアイコンを設定するところです。アプリケーションプログラム自身 Application.ExecutablePath をデータとして読み込み,アイコンのハンドルを取得しています。
//----------------------------------------------------------------------
// タイトルバーアイコン
//----------------------------------------------------------------------
IntPtr icon = WindowsAPI.GetApplicationIcon( Application.ExecutablePath );
if( icon != IntPtr.Zero ) this.Icon = Icon.FromHandle( icon );
Win32 API のラッパー部分です。
//------------------------------------------------------------------------------
// Windows API ラッパー
//------------------------------------------------------------------------------
class WindowsAPI {
//--------------------------------------------------------------------------
// SHGetFileInfo 関数で使用する定数
//--------------------------------------------------------------------------
private const uint SHGFI_ICON = 0x0100;
private const uint SHGFI_SYSICONINDEX = 0x4000;
private const uint SHGFI_LARGEICON = 0x0000;
private const uint SHGFI_SMALLICON = 0x0001;
private const uint SHGFI_OPENICON = 0x0002;
private const uint SHGFI_SHELLICONSIZE = 0x0004;
//--------------------------------------------------------------------------
// SHGetFileInfo 関数で使用する構造体
//--------------------------------------------------------------------------
private struct SHFILEINFO {
public IntPtr hIcon;
public IntPtr iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
//--------------------------------------------------------------------------
// SHGetFileInfo 関数
//--------------------------------------------------------------------------
[DllImport("shell32.dll")]
private static extern IntPtr SHGetFileInfo(
string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags );
//--------------------------------------------------------------------------
// アプリケーションアイコンを得る
//--------------------------------------------------------------------------
public static IntPtr GetApplicationIcon( string filename ) {
SHFILEINFO shinfo = new SHFILEINFO();
IntPtr hSuccess = SHGetFileInfo( Application.ExecutablePath, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON );
return hSuccess == IntPtr.Zero ? IntPtr.Zero : shinfo.hIcon;
}
}
以下のサイトの情報が大変参考になりました。
.NET TIPS 実行ファイルからアプリケーションのアイコンを取得するには?(atmarkIT)
以上で,将棋評価値バーを作るというシリーズ連載を終わります。
将棋評価値バーを使ってみたい方はコチラをご覧ください。