WinAppDriverを利用してExcelを保存する場合の注意点。

Windows Application Driverを利用して、起動中のエクセルを保存するときに
はまったのでまとめておきます。
(環境設定については、いろいろな記事が出てるのでここでは割愛します。)

環境

  • VisualStudio2017Community
  • Office 2016

エクセル操作

テンプレートの取得

GitHubのUIRecorderのページからWinAppDriverのテンプレートプロジェクトを取得します。

WinAppDriver/Tools/UIRecorder/UIRecorderTemplate at master · Microsoft/WinAppDriver · GitHub

XPathの取得

WinAppDriverUiRecorderを起動してエクセルのXPathを取得します。
通常保存時にはこのような保存ダイアログが表示されます。

f:id:ita_87:20190113113334p:plain
保存ダイアログ

開いたディレクトリにそのまま保存する場合には問題ありません。 ただし保存先を変更しようとファイル名にC:\temp\hoge.xlsxなどをSendKeyで入力する必要がありますが、
実行するとファイル名にはC:]temp]hoge.xlsxと入力されてしまいます。

この原因はこちらのブログで紹介されているようにキーボードの問題のようです。

qiita.com

この問題(2018/1現在)は解消していないようなので、別の方法で入力します。 同僚の方に相談したところアドレスバーのパスは/でも行けると教えてもらったので

  1. アドレスバーをクリック
  2. SendKeyでc:/tempと打つ
  3. SendkeyでEnterを打つ

という感じで操作します。

保存時ダイアログのアドレスバーをクリックするコードです。

string xp1 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Book1 - Excel\"][@ClassName=\"XLMAIN\"]/Window[@Name=\"名前を付けて保存\"][@ClassName=\"#32770\"]/Pane[@ClassName=\"ReBarWindow32\"]/Pane[@ClassName=\"Address Band Root\"]/ProgressBar[@ClassName=\"msctls_progress32\"]/Pane[@ClassName=\"Breadcrumb Parent\"]/ToolBar[@Name=\"アドレス: ドキュメント\"][@ClassName=\"ToolbarWindow32\"]";
var winElem1 = MyDesktopSession.FindElementByXPath(xp1);
if (winElem1 != null)
{
    winElem1.Click();
}
else
{
    Console.WriteLine($"Failed to find element {xp1}");
    return;
}

ちょっとXPathが長いですが、注目するのは最後の /ToolBar[@Name=\"アドレス: ドキュメント\"][@ClassName=\"ToolbarWindow32\"]"で
Nameの部分に表示時のパスがついてきてしまいます。
Excel起動時にパスが異なると動かないので[@Name=\"アドレス: ドキュメント\"]の部分は削除します。

アドレスバーのクリックからパスの入力までやるこんな感じのコードになります。

string xp1 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Book1 - Excel\"][@ClassName=\"XLMAIN\"]/Window[@Name=\"名前を付けて保存\"][@ClassName=\"#32770\"]/Pane[@ClassName=\"ReBarWindow32\"]/Pane[@ClassName=\"Address Band Root\"]/ProgressBar[@ClassName=\"msctls_progress32\"]/Pane[@ClassName=\"Breadcrumb Parent\"]/ToolBar[@ClassName=\"ToolbarWindow32\"]";

var winElem1 = MyDesktopSession.FindElementByXPath(xp1);
if (winElem1 != null)
{
    winElem1.Click();
}
else
{
    Console.WriteLine($"Failed to find element {xp1}");
    return;
}

string xp2 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Book1 - Excel\"][@ClassName=\"XLMAIN\"]/Window[@Name=\"名前を付けて保存\"][@ClassName=\"#32770\"]/Pane[@ClassName=\"ReBarWindow32\"]/Pane[@ClassName=\"Address Band Root\"]/ProgressBar[@ClassName=\"msctls_progress32\"]/ComboBox[@Name=\"アドレス\"][@ClassName=\"ComboBox\"]/Edit[@Name=\"アドレス\"][@ClassName=\"Edit\"]";
var winElem2 = MyDesktopSession.FindElementByXPath(xp2);
if (winElem2 != null)
{
    winElem2.SendKeys("c:/work");
    winElem2.SendKeys(Keys.Enter);

}
else
{
    Console.WriteLine($"Failed to find element {xp2}");
}