teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

4

修正とToDoを追加

2019/06/19 01:41

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -43,7 +43,7 @@
43
43
  }
44
44
  }
45
45
  // 必ず見つかる(確信)
46
- foreach (Control c in formUITarget.Controls)
46
+ foreach (Control c in targetForm.Controls)
47
47
  {
48
48
  if (c is DataGridView)
49
49
  {
@@ -63,6 +63,10 @@
63
63
  }
64
64
 
65
65
  ```
66
+
67
+ ToDo:
68
+ Application.Idleを使ってコントロールをメンバに保持
69
+ ButtonやMenuStripを操作できるように調査
66
70
  ### 前提・実現したいこと
67
71
 
68
72
  C#を用いて作成したアプリケーションから、既存のアプリで`DataGridView`を用いて表示されている内容を取得したい。

3

進捗晒し

2019/06/19 01:41

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -1,4 +1,68 @@
1
1
  よろしくお願いいたします。
2
+ ### 解決コード
3
+ まだ途中だけど
4
+ ```c#
5
+ using System.Threading;
6
+ using System.Reflection;
7
+
8
+ public partial class Form1 : Form
9
+ {
10
+ ThreadUITarget m_uiAutomationTargetThread;
11
+ DataGridView m_uiAutoTargetDGV;
12
+
13
+ public Form1()
14
+ {
15
+ InitializeComponent();
16
+ }
17
+
18
+ private void Form1_Load(object sender, EventArgs e)
19
+ {
20
+ // Assembly.EntryPoint.Invoke()するとAssembly.Load()したやつにスレッドを占有されちゃうのでサブスレッドを生成
21
+ new Thread(new ThreadStart( RunApp));
22
+ }
23
+
24
+ private void RunApp()
25
+ {
26
+ // このプログラムのプロジェクトからexeファイルを参照したtargetAppって名前のWindows Formアプリを立ち上げる
27
+ Assembly assemblyTargetApp = Assembly.Load("targetApp");
28
+ assemblyTargetApp.EntryPoint.Invoke(null, new object[0]);
29
+ }
30
+
31
+ private void button1_Click(object sender, EventArgs e)
32
+ {
33
+ FormCollection fc = Application.OpenForms;
34
+ // FormCollectionには自分も含まれちゃうので外部操作を行いたいアプリの親フォームを捜してあげる
35
+ Form targetForm = null;
36
+ foreach(Form f in fc)
37
+ {
38
+ // 外部操作を行いたいアプリのFormのTextプロパティに"targetApp"が登録されてる前提
39
+ if (f.Text == "targetApp")
40
+ {
41
+ targetForm = f;
42
+ break;
43
+ }
44
+ }
45
+ // 必ず見つかる(確信)
46
+ foreach (Control c in formUITarget.Controls)
47
+ {
48
+ if (c is DataGridView)
49
+ {
50
+ string msg;
51
+ DataGridView dgv = (DataGridView)c;
52
+ foreach( DataGridViewRow r in dgv.Rows)
53
+ foreach( DataGridViewCell c in r.cells)
54
+ msg += c.Value.ToString() + "\n"; // DataGridViewはDataGridViewCells.Value==nullなセルが発生することがあるけどここでは無視
55
+
56
+ Messagebox.Show(msg);
57
+ }
58
+ else if(c is Button)
59
+ {
60
+ c.Invoke(b.PerformClick.GetType, EventArgs.Empty); // まだ動いてないけどこれもやりたいので一応
61
+ }
62
+ }
63
+ }
64
+
65
+ ```
2
66
  ### 前提・実現したいこと
3
67
 
4
68
  C#を用いて作成したアプリケーションから、既存のアプリで`DataGridView`を用いて表示されている内容を取得したい。

2

経過を追加

2019/06/19 01:21

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -4,6 +4,8 @@
4
4
  C#を用いて作成したアプリケーションから、既存のアプリで`DataGridView`を用いて表示されている内容を取得したい。
5
5
 
6
6
  既存のアプリの`Button`を`SendMessage`でクリックしたり、`TextBox`の内容を取得したりするアプリケーションを開発中です。
7
+ 言い方を変えればウィンドウハンドル頼りで他アプリを乗っ取る自動実験用アプリのようなものを実運用で使おうとしています。
8
+
7
9
  既存のアプリはC#をベースにサードパーティのActiveXやOCXを子ダイアログにちりばめたマルチダイアログなアプリです。
8
10
 
9
11
  既存のアプリの操作や情報取得には`FindWindowEx()`や`GetWindowText()`などWinAPIを利用しています。
@@ -28,6 +30,23 @@
28
30
  WindowsForms10.Window.8.app.0.141b42a_r14_ad1
29
31
  ```
30
32
 
33
+ - DataGridViewは.NET独自の描画でありWin32 APIが役に立たない。
34
+
35
+ - 社外品のアプリであり直接改造ができない。
36
+
37
+ - すでにDataGridView以外の代理操作はウィンドウハンドラで作ってありあまり変更したくない。
38
+
39
+ - 運用上の開発案件であり、(残念ながら)お客も(私も)この方法でなんら問題がないものと思い込んでいるため(嫌な予感はするが)既存ソフトの上から覆いかぶさって人間の操作を自動化する
40
+ ###行動方針
41
+
42
+ - 既存のアプリを参照により開発アプリに取り込んで操作する
43
+
44
+ 課題:DataGridView以外の操作はウィンドウハンドラ経由で行っていたが、参照を利用して開発アプリのプロセスに取り込むため全て変更する必要がある。
45
+ 利点:既存アプリを乗っ取る形になるためウィンドウハンドラを利用する方法より色々手出しできるようになる?
46
+ - Active Accessibilityを利用する
47
+
48
+ 課題:(往々にあることだけど)肝心の関数の引数がことごとく理解不能。
49
+ 利点:ほかプロセスから手出しするため今までどおりの方針を維持できる。
31
50
  ### 補足情報(FW/ツールのバージョンなど)
32
51
  - Windows7 (64bit)
33
52
  - VisualStudio 2015 (SP1)

1

言い訳を追加

2019/06/18 02:38

投稿

退会済みユーザー
title CHANGED
File without changes
body CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  Webにもこれといった情報が見つけられず、途方にくれているような状態です。
16
16
  こういう方針でなら除き見る方法があるよ、などの情報をご教授いただきたいです。
17
+ 投げっぱなしな質問ですが皆さんのご経験から問題解決のヒントを分けて頂けたら大変助かります。
17
18
 
18
19
  ### 今分かっていること
19
20