[2018/3/1/21:00]
ビルドしたプログラムでbatファイルが呼び出されなかった不具合を修正し, 追記しました。
#はじめに
Unityで作成したアプリでカメラアプリも並行して使わないといけなくなったため
カメラアプリの起動と終了を自動化させるbatファイルを作成しました。
今回のカメラアプリは何でも良かったため、
Windowsに搭載されているMicrosoft社のカメラアプリ(Windowsカメラ)を使用しました。
(あの左下の入力するところに「カメラ」と打つと出てくるやつです。)
#開発および実行環境
- Unity 5.6.3f1
- Windows 10 Home
- WindowsCamera.exe
#本システムについて
特殊な環境だと思うので簡単に本システムについて解説します。
結構長いので余計な部分は読み飛ばしていただいて大丈夫です。
##batファイルとは
Windowsのコマンドラインで使われるコマンドをまとめたファイルです。
このファイルを実行すると記述されたコマンドが上から順に実行されていきます。
しかし、普通のコマンドの書き方とは違うものもあるので注意が必要です。
##なぜbatファイルを起用したか
今回、batファイルでの外部アプリの起動をおこなったということで
**「なぜbatファイルでの起動をおこなうことにしたか」**ということを説明します。
Unityにて実行する際にexeファイルを直接指定してやれば、起動できます。
しかし、その際に多くのファイルは絶対パスで指定する必要があります。
我らがメモ帳(notepad.exe)でも例外ではありません。
しかし、メモ帳や電卓(calc)等は標準で環境変数が登録されており、
コマンドラインから名前を叩くだけで実行できます。
いろんなアプリを異なる多くの環境で実行させるために
コマンドラインを叩くのがいいだろうということで
batファイルを起用しました。
##全体図
本システムの全体図です。
カメラアプリの起動
- UnityでProcessManager.csのstartCameraAppメソッドを呼び出すとStartCameraApp.batが起動します。
- StartCameraApp.batではWindowsカメラを起動し, そのプロセスIDをpid.txtに書き出します。
カメラアプリの終了
- UnityでProcessManager.csのendCameraAppメソッドを呼び出すとEndCameraApp.batが起動します。
- EndCameraApp.batではpid.txtに書かれたプロセスIDからカメラアプリを特定し, 終了させています。
#実際のコード
以下に実際に作成したコードを載せます。
batファイルはAssets/StreamingAssets/ProcessScriptsディレクトリに置いてあります。
ビルド後のプログラムではStreamingAssets以下に置かれたファイルに対して
プログラムからアクセスできるみたいです。(2018/3/1/21:00追記)
###ProcessManager.cs
Unity側からbatファイルを呼び出すC#プログラム
ここでいう外部プロセスはbatファイルを操作するプロセスのことであり,
カメラアプリそのもののプロセスではないので注意が必要です。
[2018/3/1/21:00]
batファイルが入ったディレクトリのパスを変更
using UnityEngine;
using System.Diagnostics;
public class ProcessManager {
Process process;
// プロセスを起動させるbatファイルが格納されたディレクトリのパス
string scriptPath = Application.dataPath + "/StreamingAssets/ProcessScripts/";
/* カメラアプリを起動 */
public void startCameraApp()
{
callBatFile("StartCameraApp.bat");
}
/* カメラアプリを終了 */
public void endCameraApp()
{
callBatFile("EndCameraApp.bat");
}
/* アプリを起動/終了させるbatファイルを実行 */
private void callBatFile(string batFilePath)
{
// 他のプロセスが実行しているなら行わない
if (process != null) return;
// 新規プロセスを作成し、batファイルのパスを登録
process = new Process();
process.StartInfo.FileName = scriptPath + batFilePath;
// 外部プロセスの終了を検知するための設定
process.EnableRaisingEvents = true;
process.Exited += process_Exited;
// 外部プロセスを実行
process.Start();
}
// 外部プロセスの終了を検知してプロセスを終了
void process_Exited(object sender, System.EventArgs e)
{
process.Dispose();
process = null;
}
}
###StartCameraApp.bat
カメラアプリを起動させるbatファイル
@echo off
setlocal
set PIDFile="pid.txt"
set AppName="WindowsCamera.exe"
set LogFile="log.txt"
rem 誤作動防止のため0にする
echo 0 > %PIDFile%
rem カメラアプリを起動
start "" "microsoft.windows.camera:"
rem カメラアプリのPIDを検索
for /f "usebackq tokens=2" %%a in (`tasklist ^| find %AppName%`) do (set PID=%%a)
if not defined PID (
echo 0 > %PIDFile%
echo could not find camera App Process ID > %LogFile%
)
rem カメラアプリのPIDを外部ファイルに出力
echo %PID% > %PIDFile%
endlocal
###EndCameraApp.bat
カメラアプリを終了させるbatファイル
@echo off
setlocal enabledelayedexpansion
set PIDFile="pid.txt"
set ProcessName=
set TargetName=WindowsCamera.exe
set LogFile="log.txt"
rem pidファイルの中身を取得
set /p ProcessID=<%PIDFile%
rem pidファイルの中身が0でなければ
if not %ProcessID%==0 (
rem プロセスIDからプロセス名を取得
for /f "usebackq tokens=1" %%i in (`tasklist /FI "PID eq %ProcessID%"`) do (set ProcessName=%%i)
rem プロセスがカメラアプリであれば
if !ProcessName!==%TargetName% (
rem プロセスを終了
taskkill /pid %ProcessID% /F
) else (
echo Error: Process ID is different > %LogFile%
)
) else (
echo Error: Can not get Process ID > %LogFile%
)
rem 誤作動防止のため0にする
echo 0 > %PIDFile%
endlocal
現在はカメラアプリのみを使う想定ですが, そのUnityアプリで用いる外部アプリの分だけpid.txtが必要になります。
カメラアプリとメモ帳アプリを用意する場合, 「CameraPid.txt」と「NotepadPid.txt」みたいに用意して
それぞれを起動/終了させるbatファイルのPidFileをそれぞれのpid.txtの名前に書きかえればできます。
#最後に
今回作成したbatファイルは同じ名前のアプリが起動してたら扱えないとかpid.txtがなくなってたら終了できないとか
問題はいろいろあるので直していく必要がありそうです。
#参考
C#(Unity)関係
batファイル関係
全般的に https://qiita.com/kshibamo/items/9368b0b2a4a2f40b61f1
注意とか https://qiita.com/yz2cm/items/8058d503a1b84688af09
tasklist http://wa3.i-3-i.info/word12514.html
for https://qiita.com/sawa_tsuka/items/67be34bab1fdf3fb87f9
kill https://qiita.com/nasum/items/22585cff8745fa61d187
https://social.msdn.microsoft.com/Forums/vstudio/en-US/270f0842-963d-4ed9-b27d-27957628004c/what-is-the-pid-of-the-current-cmdexe?forum=msbuild
https://oshiete.goo.ne.jp/qa/5699529.html