2015年6月6日土曜日

C#でIEを自動制御しよう (目次)

C#で、COMを用いてIE (InternetExplorer)を自動制御する方法を以下の記事にまとめています。

前書き

プロジェクト作成時の前準備、概略説明

サンプルコードを動作させるために必要な設定の話など。

基本操作サンプルコード一覧

(7)以降では、「C#でIEを自動制御しよう (6) ページの読み込み完了まで待機する」で紹介している拡張メソッド Waitを利用しています。

Appendix: VBA編

VBAで、SeleniumVBAを用いてFirefox/Chrome/IEを操作する方法を以下にまとめています。

C#でIEを自動制御しよう (14) フレーム分割されたページを操作する

■フレーム分割されたページを操作する

最近ではあまり見なくなりましたが、frameを利用したページを操作したいこともあるかと思います。下記サンプルコードでは、俳優 阿部寛さんのホームページを開き、フレーム分割された右側のページを開きます。

サンプルコード


補足説明

InternetExporerオブジェクトのDocumentプロパティをmshtml.IHTMLDocument2 に変換し、framesプロパティで、ページに含まれるframe要素を取得しています。
各要素は、dynamic型で取得されます。実態はmshtml.HTMLWindow2型のため、変換しておくと、後処理が楽になります。

C#でIEを自動制御しよう (13) 表示しているページタイトル&URLを取得する

■表示しているページタイトル&URLを取得する

InternetExplorerオブジェクトのLocationNameプロパティでページのタイトルを、LocationURLプロパティでページのURLを取得できます。下記サンプルコードは、デバッグ実行するとYahoo!ファイナンスのページを開き、ページのタイトル&URLを、VSの出力ウィンドウに出力します。

サンプルコード

C#でIEを自動制御しよう (12) 画像をクリックする

■画像をクリックする

要素を取得して、clickメソッドを呼ぶだけです。下記サンプルコードでは、Yahoo!ファイナンスのページを開き、画面右にある日経平均株価のチャート画像をクリックします。

サンプルコード


補足説明

特にコメントすることもないのですが、強いて言うならば、IMG要素は、mshtml.HTMLImg型に変換しておくと、altプロパティで、alt属性を確認できるので便利ですよ、というところでしょうか。

C#でIEを自動制御しよう (11) チェックボックス(ラジオボタン)にチェックを入れる

■チェックボックス(ラジオボタン)にチェックを入れる

タイトルのとおりです。2通りほどやり方がありました。

サンプルコード

補足説明

1つ目と2つ目ともに、該当するNameを持つ要素をgetElementsByNameでかっさらったあと、foreachで所望のvalueを持つものか確認し、チェックを入れています。itemメソッドで上手く拾えなかったんですよね。何故か…。

本題に入ると、1つ目の方法は、clickメソッドでチェックを入れています。2つ目の方法は、setAttributeメソッドでchecked属性を設定しています。このあたりは、「お好みでどうぞ」という感じでしょうか。

C#でIEを自動制御しよう (10) セレクトボックス(メニュー)の選択肢を選択する

■セレクトボックス(メニュー)の選択肢を選択する

ドロップダウンリストととも呼ばれるタイプのアレ、の選択肢を選択します。ざっと試してみた感じでは3通りほどやり方がありました。

サンプルコード

補足説明

1つ目は、要素をmshtml.HTMLSelectElementに変換後、selectedIndexプロパティを使う方法。目視でどの要素を選択したいか(何番目の要素を選択したいか)を決め打ちできる場合は、この方法が楽ですね。ただし、要素の順番が不定の場合は使えないでしょう。

2つ目は、同じくmshtml.HTMLSelectElementに変換後、setAttributeメソッドを用いてvalue属性を設定する方法。HTMLのソースを見て、optionタグごとにvalueが固定されていれば利用できる感じです。

3つ目は、同じくmshtml.HTMLSelectElementに変換後、optionsプロパティを呼び出し、各要素をmshtml.HTMLOptionElementに変換して、innerTextが所望の文字列と合致するかを確認しています。文字ベースで、選択肢を選択したい場合はこれ一択ですね。本当はLINQを使いたいところなのですが、上手いことCastできなかったのでforeachで回しています…。

C#でIEを自動制御しよう (9) LINQでリンクを取得してクリックして開く

■LINQでリンクを取得してクリックして開く

最初に。このサンプルコードだけLINQを使っています。using System.Linq;を忘れずに。

getElementsByTagName("A")で、Aタグをさらった後、Whereで目的とするAタグだけを取得しています。あとは、クリックするだけ。

サンプルコード


補足説明

注意点は、今回の場合、getElementsByTagName("A")で拾ってきた要素の中には、innerTextがnullの要素が含まれている可能性がある点でしょうか。具体的には、画像にリンクが貼られている場合ですかね。

C#でIEを自動制御しよう (8) ボタンをクリックする

■ボタンをクリックする

文字の入力に続いて、今回は、ボタンをクリックします。Googleの検索ボタンをクリックします。といっても、ボタンを示す要素を取得して、clickメソッドを呼び出すだけです。要素取得後は、C#らしさは微塵もなく、javascriptと何ら変わりありません。.getElementsByNameでは、IHTMLElementCollectionが返ってくるので、続いてitemメソッドで目的の要素を指定しています。

サンプルコード

補足説明

javascriptの場合に比べて、itemメソッドの指定方法がちょっと違う感じでしょうか。上記サンプルコードのコメントに記載しているように、itemメソッドは、第1引数がnameの指定、第2引数がindexの指定となっています。

C#でIEを自動制御しよう (7) フォーム(テキストボックス)に文字を入力する

■フォーム(テキストボックス)に文字を入力する

表示しているHTMLドキュメントの情報は、Documentプロパティで取得可能です。ただし、そのままではdynamic型になるため、VSの補完を有効にするために、利用する際には型を指定した方が良いように思います。下記では、as演算子でmshtml.IHTMLDocument3 に変換しています。

 Documentプロパティ自体は、 IHTMLDocument, IHTMLDocument2, IHTMLDocument3の3つのインターフェースを実装しているため、必要なメソッドに応じてこれらのいずれかに変換すると良いです。個人的な感覚になりますが、IHTMLDocumentは機能がなさすぎて使い道なし、IHTMLDocument3は、DOMをゴリゴリ直接操作したい人向け、IHTMLDocument2は手軽にページの各要素を操作したい人向け(IHTMLDocument3のラッパー的な位置づけ)、という印象です。

 以下のサンプルコードでは、getElementByIdでグーグルの検索ボックスを指定し、innerTextで文字列を代入しています。 詳しくは、mshtml.IHTMLDocument3の操作は、MSDNのページ(IHTMLDocument3 interface (Windows))を参照してください。取得した要素の操作はjavascriptでのDOM操作と変わるところがないので、説明は省略します。

サンプルコード

補足説明

上記のgetElementByIdや、getElementsByName, getElementsByTagNameで取得した要素は、そのままではdynamic型になりますが、mshtml.IHTMLElementもしくは、これが実装されたクラスである mshtml.HTMLSelectElement, mshtml.HTMLInputElementなどに変換できます。この実装されたクラスがとんでもない数ある (* https://msdn.microsoft.com/en-us/library/hh801967(v=vs.85).aspx )ので、慣れるまではわりと手探りになります。ジーザス。

C#でIEを自動制御しよう (6) ページの読み込み完了まで待機する

■ページの読み込み完了まで待機する

さて、続いて、IEに表示されたページ内のボタンやテキストボックスなどの各要素を操作、と進みたいところなのですが、ここで一旦寄り道をします。ページ内の各要素を操作するにあたっては、ページ内の各要素が表示され終わっている(読み込みが完了している)必要があります。

 「ちょっと何を言っているか分からない。」という方向けに、説明を補足すると…。InternetExplorerオブジェクトのNavigateメソッドを実行すると、非同期にページの読み込みが実行されます。このため、ページの読み込みが始まるとともに、プログラムは、Navigateメソッドの次のステップに進みます。次のステップでページ内の各要素を操作する場合、ページの読み込みが完了していない状態では、ページの各要素は必ずしも存在しないため、存在しない要素を操作しようとして例外が発生する可能性があります。(というより、昨今のPCは処理が速いので、高確率でこの例外が発生します。)
 
 というわけで、ページの読み込みが完了するまで待つようなメソッドが必要になります。読み込みの完了を検出する方法は色々あるのですが、自分は下記のような拡張メソッドを定義して使っています。BusyプロパティとReadyStateプロパティの状態を確認する、という最も手軽な方法を使っています。

サンプルコード


補足説明

引数は省略可能です。引数に数値を指定すると、指定した数値分(ミリ秒)、一旦停止します。うまく完了まで待機できないときの応急処置に使うと良いのではないでしょうか。(例えば、引数に5000を指定すると、5秒待機するので、たいていのページはその間に読み込みが完了します。その場しのぎの対応で良い場合は、これで十分かなと思います。)

 余談になりますが、上記Waitメソッドでは上手く完了待ちができない場合(動的にjavascriptなどでページが書き換えられているような場合)、目的とするページの状態に含まれる要素を調査し、当該要素が出現するまでループさせるのが、確実かつお手軽です。

C#でIEを自動制御しよう (5) IEを閉じる

■IEを閉じる

IEを起動したら閉じましょう。車のドアだって開きっぱなしでは迷惑がかかりますし、やはりここは純然たる大人たるもの、開いたIEは閉じましょう。Quitメソッドを呼べばOKです。これでジ・エンドです。

サンプルコード

C#でIEを自動制御しよう (4) IEで指定したURLを開く

■IEで指定したURLを開く

IEを立ち上げ、まずすることといえば、Webサイトを開くことでしょう。ここでは、とりあえず検索サイトを開くこととします。Navigateメソッドを呼びましょう。話はそれからだ。

サンプルコード1


補足説明1

見ての通り、第1引数に string型でURLを指定すればOKです。第2引数以降は省略可能なので、上記例では全て省略しています。引数について詳しくは、MSDN をご参照ください。第2引数以降で、(IE7以降では)タブを新規作成するか否かを決めたり、POSTデータを投げたり、Headerを書き換えたり出来るようです。さらに余談ですが、戻り値としてエラーの有無などがLong型で返ってきます。お好みで拾ってください。

また、InternetExplorerオブジェクトには、Navigate2メソッドも存在しています。

サンプルコード2


補足説明2 

こちらは第1引数がobject型である必要があります。MSDNによれば、URLにPIDLを指定できる点がNavigateとの大きな差異点のようですが…。使い道がオモイツカナイナー。Webブラウジングをする分には、Navigateメソッドでいいと思います。

C#でIEを自動制御しよう (3) IEを起動する

■IEを起動する

SHDocVw.InternetExplorerのインスタンスを生成すると、IEが立ち上がります。VisibleプロパティをTrueに設定すると、空のIEが起動したことを目視することができます。初期状態(False)でも、プロセスモニタなどでIEが起動したことを確認できますが、動作検証の際には、目視できたほうが便利です。忘れずVisible=Trueを設定しましょう。

サンプルコード

C#でIEを自動制御しよう (2) プロジェクトの設定

【動作確認環境】

  • Windows 8.1
  • InternetExplorer11
  • Visual Studio 2013 Update4
    • C#プロジェクト (ターゲット .NET Framework4.5)

【C#プロジェクトの設定に関して】

参照設定で、タイプライブラリ
  • Microsoft Internet Controls (SHDocVw.DLL)
  • Microsoft HTML Object Library (MSHTML.DLL)
を追加しています。
各ライブラリのプロパティ「相互運用機能型の埋め込み」はTrueです(デフォルト設定)。

【基本的な話】

【はじめに】で書いたことの繰り返しになりますが、参照設定する2つのライブラリについて補足説明すると、Microsoft Internet Controls (SHDocVw.DLL)は、InternetExplorerのウェブブラウザとしての主要な動作を担うライブラリで、Microsoft HTML Object Library (MSHTML.DLL)は、HTML(DOM)・CSSの解析、操作を行うライブラリになります。前者は、IEを操作するために必須、後者は、(dynamicを多用することで)参照なしでもコードを書けなくはないのですが、VSのコード補完が効かずシニタクナルノデ忘れず追加しておきましょう。そうしましょう。

 以降、SHDocVw.DLLに含まれる SHDocVw.InternetExplorerというクラスのインスタンス(オブジェクト)を生成することで、IEの制御を行っていきます。また、IE上に表示されたページの各要素(DOMオブジェクト)の操作は、Microsoft HTML Object Library (MSHTML.DLL)に含まれる各クラスを通じて操作していくことになります。

 ぶっちゃけ、InternetExplorerオブジェクトのメソッド一覧は、MSDN (InternetExplorer object (Windows) )に載っておりますので、そちらを見ていただくと本記事を読む必要性は皆無です。本家リファレンスだけに完璧です。

 気を取り直して。次からは、実際のサンプルコードを踏まえて、IEの制御方法を説明していきます。

C#でIEを自動制御しよう (1) はじめに

【想定する読者】


  • Webページの構成、特に、フロントエンドの技術(HTML, CSS, JavaScriptなど)を多少理解できる程度の能力
  • JavaScriptやVBAなど他言語でDOMの直接操作が多少できる程度の能力

を備えたC#プログラマ

【はじめに】

この一連のblog記事では、C#でIE(Internet Explorer)を自動制御するためのサンプルコードをまとめています。本blogでは、今までにもVBAを用いたIEやFirefoxの自動制御方法についてまとめています。今回、VBAでできる範囲を越えて、「単体アプリケーションを開発したい」といった用途や、「既存のアプリケーションにIEの自動制御機能を付けたい」といった用途向けに、C#でも同じようにIEを自動制御できることをまとめることとしました。

 今回の記事では、筆者の勉強も兼ねて、SeleniumやWatiNなどのサードパーティのライブラリは用いず、素のIEを操作しています。IEは、Microsoft公式サイト(MSDN)の解説記事「Internet Explorer のアーキテクチャ」にもあるように、IEのウェブブラウザとしての主要動作を担うShDocVw.dll と、その下層に位置し、HTMLやCSSの解析・表示を担うMSHTML.dllとを有しています。本記事で、IEを操作するにあたっては、この2つのライブラリを参照・利用しています。(具体的手順は後述)

 本記事ではタイトルに「C#で」と銘打ってはいますが、IEを制御するコードの実態は 上記2つのライブラリ COM(Component Object Model)オブジェクトを呼び出しているだけです。このため、基本的にはVBAでのIE操作と変わるところは何らありません。ぶっちゃけて言えば、VBAを用いる場合との違いは、①クラス名・メソッド名などの細則が異なる場合がある、②ある程度正確にクラス名を把握しておいた方が良い、といったところくらいでしょうか。このため、C#プログラマの皆様にとって、初心者向けに書いた本記事が必要とされるのか、というと甚だ疑問が残るところではありますが、何から何まで1から調べるのはめんどくさいですし、こんなサンプルコード集があったら少しは楽かなということで筆を取った次第です。

※ 本心を言えば、VS(Visual Studio)でC#からIEの制御をテストするのが、めんどくさい。めんどくさすぎる。戻り値にdynamic型が多く、少しコードを書くたびに、クラス名・メソッド名を把握するためデバッガを走らせたり、リファレンス引きまくったりと、肝心のロジック作成がさっぱり進まず、心底アリエナイ!感じでした。おまけにクラスの数が多すぎて覚えてられない、ヤッテランナイ!というわけで、物忘れの激しい自分用にサンプルコードをまとめておきたかったというところです。正直、「みんな、どーやってIE制御してんの?VBAでやるより数倍めんどくさいよ、マジで。」という感じなので、「オメーが間違ってんだよ。正解はこれだッ!(ドヤァ」みたいな感じでツッコミを頂けますと大変嬉しく思います。特に、後半かなり怪しい感じですので、わりと真面目にツッコミ歓迎です。なお、「Selenium使え」はナシの方向でお願いします。

 最後になりましたが、本記事を通じて読者のみなさまのC#プログラミングが少しでも楽になれば幸いです。


2015年6月5日金曜日

C# のクライアントアプリケーションをリモートデバッグする(VisualStudio 2013でのリモートデバッグ方法)

開発PCとは別のリモートPC上で実行したC#のWindowsアプリケーション(コンソールアプリケーション、もしくはWinForms、WPFアプリケーション)を、リモートデバッグする方法を、備忘録を兼ねてまとめてみました。

(※ ここで、開発PCとリモートPCとは、有線または無線で、同一のサブネット内に接続されているものとしています。)

Windowsストアアプリを作る場合や、C++でアプリケーションを作る場合とは、設定画面などに異なる点があったため、ネット上の情報を参考にする際は少しだけ注意が必要です。(下記公式資料が一番確実です。以下は、公式資料の補足説明といった位置づけになります。)


ざっくりとした概略