Visual Studio 2019 Tips-コンソールプロジェクトでWPF/WinFormを使えるようにする

初めに

Garmin Connect IQ-コマンドラインでのビルド・シミュレーター起動でGarminのシミュレーター等をコマンドラインで起動できることが分かったので、ビルド・起動と合わせ画面の確認なども、自動でできないかなと思い立った。

そこで調べたところ、C#でSystem.Windows.Automationを使えば実現できるのではと思い立った。

System.Windows.Automationに関しては以下を参照。

UI オートメーションの概要 - .NET Framework
Windows Presentation Foundation (WPF) をサポートしている Windows オペレーティング システムのアクセシビリティ フレームワークである、Microsoft UI オートメーションの概要について説明...

サンプルとして利用しようとしたのが以下のページ。

UI AutomationでWindowsプログラムの自動化などしてみる - Qiita
WindowsのGUIで出来たプログラムを評価していて、頻度の低い問題にぶち当たったとします。例えば下記の処理を100回繰り返すと1回ぐらい例外で落ちるんですーみたいなの。EXECUTEボタンをク…

このサンプルで使用している主要な要素は以下のものだった。

  1. System.Windows.Automation
  2. Windows Formsを使ったGUI
  3. コンソール入出力

ここで、以下の問題が出た。

問題点1 System.Windows.Automation/Windows Formsの参照ができない

サンプルではコンソール入出力を使っていたため、.Net Core/.Net 5.0のコンソールプロジェクトで新規プロジェクトを立ち上げたところ、System.Windows.AutomationとWindows Formsの名前解決ができないことが判明。

.Net Frameworkプロジェクトであれば、参照アセンブリで、「UIAutomation~」を指定することでSystem.Windows.Automationの名前解決はできた。

Windows Formsの方も同様にできるのだろう。

しかし.Net Core/.Net 5.0ではそれらに類するものがCOM参照ではあったのだが、付けても名前解決はできなかった。

調査1

System.Windows.AutomationがWPFパッケージのものだという記述を参考に、WPFプロジェクトとコンソールプロジェクトを作成し、比較してみたところ、以下の様になった。

左がWPFプロジェクト、右がコンソールプロジェクト。

WPFプロジェクトの方には、UseWPFタグが入っていた。

これをもとに、コンソールアプリ側にUseWPFを入れたところWPFプロジェクト同様に、WPFのフレームワークが依存関係に加わった。

同様にWindows Formsプロジェクトを見たところそちらにはUseWindowsFormsタグが追加されていた。

問題点2 コンソール入出力ができない

UseWPFをプロジェクトに入れた場合、今度はコンソールが表示されず、そこでの入出力ができない結果となった。

これはWPFやWindows Formプロジェクトを作成した場合と同様な動作になったものと思われる。

調査2

こちらに関してはC#、コンソールと検索すると、結構なサンプルがあり、それを参考にプログラムを組み込んだところ、問題なく動作した。

対応方法まとめ

System.Windows.Automation/Windows Formsの参照対応

使用するパッケージに合わせUseWPF、UseWindowsFormsのタグを入れる。

一応、UseWPFとUseWindowsFormsの2つのタグがcsprojに入った場合、どのフレームワークが追加さるか調べたところ、以下の様になった。

UseWPF UseWindowsForms パッケージ名
true Microsoft.WindowsDesktop.App.WPF
true Microsoft.WindowsDesktop.App.WindowsForm
true true Microsoft.WindowsDesktop.App
これは、WPFとWindowsFormを包含したもの

コンソールへの出力

ただコンソールプロジェクトとしたのに、UseWPF, UseWindowsFormsを入れてしまうと、コンソールが表示されないプロジェクトとなってしまった。

これについては、以下の2種類の対応で対処できる。

  1. 既存コンソールへのアタッチ
  2. 自前コンソールの作成

Win32 APIを呼び出す方法なのだが、よく使われる手でもあるらしい。
今回ものでは、自前コンソールの作成をした方がいいかもしれない。

既存コンソールへのアタッチ

[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
static extern bool AttachConsole(int processId);

static void Main(string[] args)
{
    AttachConsole(-1);

自前コンソールの作成

[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
public static extern bool AllocConsole();

static void Main(string[] args)
{
    AllocConsole();

最後に

一応、今回の対策をすることで、以下で示されるコードは、ビルド、実行は可能になった。

UI AutomationでWindowsプログラムの自動化などしてみる - Qiita
WindowsのGUIで出来たプログラムを評価していて、頻度の低い問題にぶち当たったとします。例えば下記の処理を100回繰り返すと1回ぐらい例外で落ちるんですーみたいなの。EXECUTEボタンをク…

ただベースをコンソールにしたい場合は今回の方法は有効かもしれないが、コンソールを使う必要がないのであれば、WPFやWindow Formsの画面用プロジェクトを使った方が面倒じゃないことがよくわかった。

後、C#プロジェクトの基本的なことは以下に記載がある。

.NET プロジェクト SDK の概要
.NET プロジェクト SDK について説明します。

コメント

タイトルとURLをコピーしました