ぼっちプログラマのメモ

UE4とかUE5とかについて書いたり書かなかったり。

【UE5】外部ファイルを拡張子に関連付けられた既定アプリで開く方法について(LaunchFileInDefaultExternalApplication)

はじめに

UE5からTXTファイルやCSVファイルなどをテキストエディタExcelなどのUE5外のアプリケーションで開きたいことは稀によくあります。

その際に便利な関数としてFPlatformProcess::CreateProcFPlatformProcess::ExecProcessがあります。 papersloth.hatenablog.com

しかし、開くファイルのパスだけでなく、開くアプリケーションのパスも指定する必要があります。たとえばExcelで開こうとした場合だとこんな感じ。

FPlatformProcess::CreateProc(TEXT(""C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE""), ...

色々面倒!パスを事前にチェックしたり、アプリがバージョンアップしてパスが変わってトラブったり、そもそもインストールされてなかったり…パスを短縮化するbatを配布しても誰も使ってくれなかったり…頭痛が痛くなりそうな状況が容易に想像できます。

そこで便利なのが今回紹介する「ファイルを拡張に関連付けられた既定アプリで開く方法」です。更に分かりやすく言うと、ファイルをダブルクリックすると自動的に確認・編集用アプリが開きますが、アレとほぼ同じことができる方法です。

この方法ならアプリのパスが不要なので、先程の懸念事項の大半をカバーできるはずです!たぶん。きっと。C++必須ですが…

ファイルを拡張に関連付けられた既定アプリで開く方法

FPlatformProcess::LaunchFileInDefaultExternalApplication を呼び出すことで実現可能です! 例えば、プロジェクトのSavedフォルダにある hogehoge.csvExcel で開く際は下記のように記述します。

// Savedフォルダ までの相対パスと ファイル名を結合
FString CSVRelativePath = FPaths::ProjectSavedDir() / TEXT("hogehoge.csv");
// LaunchFileInDefaultExternalApplicationはフルパスが必要なので変換
FString CsvFullPath = FPaths::ConvertRelativePathToFull(*CSVRelativePath );
// CSVファイルを既定のアプリで開く
if(FPlatformProcess::LaunchFileInDefaultExternalApplication(*CsvFullPath))
{
    // csvファイルを開くことに成功した場合の処理
}

かんたん!!!

ちなみに、Windowsの場合では内部ではWin32 APIのShellExecuteW関数が呼ばれています。 第2引数以降はShellExecuteW関数の公式ドキュメントやブログ記事などにて使い方を確認するのが良いと思います。

bool FWindowsPlatformProcess::LaunchFileInDefaultExternalApplication( const TCHAR* FileName, const TCHAR* Parms /*= NULL*/, ELaunchVerb::Type Verb /*= ELaunchVerb::Open*/, bool bPromptToOpenOnFailure /*= true */ )
{
    const TCHAR* VerbString = Verb == ELaunchVerb::Edit ? TEXT("edit") : TEXT("open");

    // First attempt to open the file in its default application
    UE_LOG(LogWindows, Log,  TEXT("LaunchFileInExternalEditor %s %s"), FileName, Parms ? Parms : TEXT("") );
    HINSTANCE Code = ::ShellExecuteW( NULL, VerbString, FileName, Parms ? Parms : TEXT(""), TEXT(""), SW_SHOWNORMAL );
    
    UE_LOG(LogWindows, Log,  TEXT("Launch application code for %s %s: %d"), FileName, Parms ? Parms : TEXT(""), (PTRINT)Code );
...

LaunchFileInDefaultExternalApplicationの欠点としては、立ち上がったアプリのプロセスを直接取得することができません(ShellExecuteWの仕様)。そのため、アプリが終了するまで処理を待つ、といったことをしたい場合はFPlatformProcess::IsApplicationRunningという特定のプロセスが存在するか否かを確認する関数を使う必要があります。

while(FPlatformProcess::IsApplicationRunning(TEXT("EXCEL.EXE")))
{
    FPlatformProcess::Sleep(0.1f);
}

とはいえ、サクッとファイルを外部アプリで開くには凄く便利な関数だと思います! UE5外のアプリと連携するワークフローを検討する際は是非お試しください~

おしまし