「平成」を感じるもの

C#,Visual Studio 2010 (.NET Framework 4.0) で作りたいのですが、「自作アプリからAPIで他のアプリとデータをやり取りする方法」というキーワードで検索しましたが、良くわかりませんでした。

やりたい事は、

namespace NowplayingAPL
{
public partial class MainWindow : Form
{


で定義されたウィンドウのMainWindow.TextBox.Text からデータを受け取り、編集後 MainWindow.TextBox.Text にデータを挿入したいです。 編集処理は作成済みです。

Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer

http://d.hatena.ne.jp/maeyan/20091227/1261848549

…が参考になりそうなのですが、C#での定義方法から分かりません。

C# , ・・・ の環境で実現できるでしょうか?できるのなら、他に必要な情報はありますか?
データを受け取る事が難しければ、データを挿入するだけでも構いません。

ソースを結合すれば、なんなくやりたい事は実現できるのですが、訳あって、面倒な方法を取っています。

教えて頂けば、幸いです。

A 回答 (2件)

この回答への補足

回答ありがとうございます。今、電卓を起動して、ボタンを押す処理を作っています。

http://stackoverflow.com/questions/5241984/findw …

そのままですが…、まずは、最小限ソースを弄って、動く状態にする所から始めています。

using System.Runtime.InteropServices; を追加しました。

テスト用のボタンをクリックしたときに、処理します、

 private void ButtonTest_Click(object sender, EventArgs e)
 {
  IntPtr hwnd = IntPtr.Zero;
  IntPtr hwndChild = IntPtr.Zero;

  //Get a handle for the Calculator Application main window
  hwnd = FindWindow(null, "Calculator");
  if (hwnd == IntPtr.Zero)
  {
    if (MessageBox.Show("Couldn't find the calculator" +
      " application. Do you want to start it?",
      "TestWinAPI",
      MessageBoxButtons.YesNo) == DialogResult.Yes)
    {
      System.Diagnostics.Process.Start("Calc");
     //BringWindowToTop("Calculator", true);
     //SetForegroundWindow((IntPtr)hwnd);
    }
  }
  else
  {  //elseの条件を通る事がありません。FindWindowもおかしいのかもしれません(汗)

  //Get a handle for the "1" button
  hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "1");

  //send BN_CLICKED message
  SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero); //BN_CLICKEDの所でビルドエラーになります。

  //Get a handle for the "+" button
  hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "+");

  //send BN_CLICKED message
  SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);

  //Get a handle for the "2" button
  hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "2");

  //send BN_CLICKED message
  SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);

  //Get a handle for the "=" button
  hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Button", "=");

  //send BN_CLICKED message
  SendMessage(hwndChild, BN_CLICKED, 0, IntPtr.Zero);

  //BringWindowToTop("Calculator", true);
  }
 }

 // Find window by Caption, and wait 1/2 a second and then try again.
 public static IntPtr FindWindow(string windowName, bool wait)
 {
  IntPtr hWnd = FindWindow(null, windowName);
  while (wait && hWnd == IntPtr.Zero)
  {
   System.Threading.Thread.Sleep(500);
   hWnd = FindWindow(null, windowName);
  }

  return hWnd;
 }

 // THE FOLLOWING METHOD REFERENCES THE SetForegroundWindow API
 public static void BringWindowToTop(string windowName, bool wait)
 {
  IntPtr hWnd = FindWindow(windowName, wait);
  if (hWnd != IntPtr.Zero)
  {
   SetForegroundWindow((IntPtr)hWnd);
  }
 }


 //// For Windows Mobile, replace user32.dll with coredll.dll
 [DllImport("user32.dll", SetLastError = true)]
 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

 // Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
 [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
 public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);

 [DllImport("User32.dll")]
 public static extern int SetForegroundWindow(IntPtr hWnd);

  //[DllImport("user32.dll", SetLastError = true)]
  //static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

  [DllImport("user32.dll", SetLastError = true)]
  public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

 [DllImport("user32.dll")]
 private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
 //private static extern IntPtr SendMessage (IntPtr hWnd, uint Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
 }
}


「エラー 1 名前 'BN_CLICKED' は現在のコンテキスト内に存在しません。」と出るので、
public const System.UInt32 BN_CLICKED = 245;
としてみましたが、他の所がエラーになります。

引数おIntPtrとintとが型が違っていて、無理やりキャストとかしてました(意味がないですね)
残骸が残っていたらすみません。途中経過報告のつもりです。

最終的には、目的のアプリケーションを起動し、クラス名、ウィンドウ名、オブジェクト名を指定して、データを挿入したいです。

↓これを参考にするつもりです。
http://www.pinvoke.net/default.aspx/user32.findw …

補足日時:2013/10/22 12:40
    • good
    • 0
この回答へのお礼

SPY++ というツールを使って、目的の機能は実現しました。
お二方、アドバイスを頂き有難う御座いました。

親クラスから、一個一個たどって行かなければならないのですね。
ただ、このクラス名を指定するやり方は、私以外の環境でも動くのでしょうか?
(動かないとすると、このコーディングの意味がありませんが・・・)

 public const uint WM_GETTEXT = 0x000D;
 public const uint WM_SETTEXT = 0x000C;

 private string GetOrSetText(String myMode)
 {
  IntPtr hwnd = IntPtr.Zero;
  IntPtr hwndChild = IntPtr.Zero;

  //Get a handle for the Calculator Application main window   
  hwnd = FindWindow(null, "メインアプリ");

  //hwnd = FindWindow("CalcFrame", "電卓");

  if (hwnd == IntPtr.Zero)
  {
   //MessageBox.Show("アプリが起動されていません。",
   //     "警告",
   //     MessageBoxButtons.OK);

   string myPath = GetAppPath() + "\\" + "メインアプリ.exe";
   if (System.IO.File.Exists(myPath))
   {
    System.Diagnostics.Process.Start(myPath);

    //メッセージキューに現在あるWindowsメッセージをすべて処理する
    //System.Windows.Forms.Application.DoEvents();

    System.Threading.Thread.Sleep(1500);

    //Get a handle for the Calculator Application main window   
    hwnd = FindWindow(null, "メインアプリ");
   }
   else
   {
    MessageBox.Show("「メインアプリ」を起動して下さい。",
         "警告",
         MessageBoxButtons.OK);

    return "";
   }

  }

  // http://oshiete.goo.ne.jp/qa/7220109.html

  //メインウィンドウのハンドル取得
  hwnd = FindWindowEx(hwnd, IntPtr.Zero, "WindowsForms10.SysTabControl32.app.0.******_r**_ad1", null);

  //タブウィンドウのハンドル取得
  hwnd = FindWindowEx(hwnd, IntPtr.Zero, null, "設定");

  //フレームのハンドル取得
  hwnd = FindWindowEx(hwnd, IntPtr.Zero, null, "詳細設定");


  //テキストボックスのハンドル取得
  hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "WindowsForms10.EDIT.app.0.*******_r**_ad1", null);


  if (hwndChild == IntPtr.Zero)
  {
   //MessageBox.Show("対象オブジェクトが見つかりませんでした。",
   //     "警告",
   //     MessageBoxButtons.OK);   

   return "";
  }

  if (myMode.Equals("GET"))
  {

   StringBuilder sb1 = new StringBuilder(1024);
   SendMessage(hwndChild, WM_GETTEXT, (IntPtr)sb1.Capacity, sb1);

   this.EditBOX.Text = sb1.ToString();

   return this.EditBOX.Text;
  }
  else if(myMode.Equals("SET"))
  {
   //hwnd = FindWindow(null, "メインアプリ");
   //WakeupWindow(hwnd);

   StringBuilder sb2 = new StringBuilder(this.EditBOX.Text);
   SendMessage(hwndChild, WM_SETTEXT, IntPtr.Zero, sb2);

   return this.EditBOX.Text;
  }else{
   MessageBox.Show("プログラミングエラーです。引数にGETかSETを指定して下さい。",
        "警告",
        MessageBoxButtons.OK);
   return "";
  }
  }

   [DllImport("user32.dll", CharSet = CharSet.Auto)]
   static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
   [DllImport("user32.dll", SetLastError = true)]
   static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
   [DllImport("user32.dll", CharSet = CharSet.Auto)]
   static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr ptr, StringBuilder lParam);

____________________________________________________________________________________


以上となりました。何かお気づきの点がありましたら、お教え下さい。11月中に締め切る予定です。

お礼日時:2013/11/20 11:42

その相手のアプリケーションがどんなインターフェースを持っているのかがわからなければ、答えようが無いと思うのですが。



例えば、その処理の本体が.NETのDLLになっていて、参照追加して 「 相手アプリAPI.処理(MainWindow.TextBox.Text) ; 」で済むケースもあるし
相手のコントロールに直接Sendkeyとかで送信して、結果をコピペするようなことをしなければならないかもしれません。

この回答への補足

早速の回答ありがとうございます。

すみません、はしょり過ぎて、本体はDLLではありません。私が作った方もDLLではありません。両方EXEです。上手く言えずに申し訳ありませんm(_ _)m

ただ、テキストボックス同士でデータをやり取りしたいだけです(汗)

ちょっと自分で試行錯誤してみるので、

Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer

Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
(ByVal hwndParent As Integer, ByVal hwndChildAfter As Integer, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Integer

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
(ByVal hWnd As Integer, ByVal MSG As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

の C# での宣言方法を教えて頂けませんか?
(参考URLでも結構です)

補足日時:2013/10/22 03:32
    • good
    • 0
この回答へのお礼

お礼の欄に申し訳ありません。クラス名の指定が上手くいきません。その他も・・・

前回の参考にしたWebページでは、FindWindowがオーバーライドされている様だったので、
標準に戻した。

しかし、

hwnd = FindWindow(null, "電卓"); は、通るのに
hwnd = FindWindow("Calc", "電卓"); が通らない

ここでいうクラス名とはどうやって調べればいいのか?


BN_CLICKED とは定数なので、自分で決まった値に定義していいのか? // http://wisdom.sakura.ne.jp/system/winapi/windata …
または、BN_CLICKEDの前に何か、つけるのか?



外部アプリは、タスクトレイに常駐し、アイコンをダブルクリックするか or 右クリック→設定で
MainWindowが表示される。

この場合、オブジェクト名は、MainWindow.TextBox.Text なので、クラス名はMainWindow.TextBoxに
なるのではないか?

【ソースコード】
 private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
 {
  this.Show();
  this.WindowState = FormWindowState.Normal;
  this.Activate();
 }



 private void 設定ToolStripMenuItem_Click(object sender, EventArgs e)
 {
  this.Show();
  this.WindowState = FormWindowState.Normal;
  this.Activate();
 }

で、MainWindowが呼び出されている。その中にテキストボックスがある。
(なお、設定画面などはタブで切り替えられるようになっている。)


SetForegroundWindow( hwnd ); は、外部MainWindowが背後に既に開かれている場合、ちゃんと手前にくるが、
私がやりたいのはhide(最小化?)されているウィンドウをshowしたい

かといって、BringWindowToTop(hWnd)が使えそうだが、定義の方法が分からない。

 private const int WM_LBUTTONDBLCLK = 0x0203;

 hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "notifyIcon1", null);
 SendMessage(hwndChild, WM_LBUTTONDBLCLK, 0, IntPtr.Zero); // http://chokuto.ifdef.jp/urawaza/hsgetmsg1.html

としてもみたが、ビルドエラー。アイコンをダブルクリックを実行したかった。


また、hwndChildが常に0なので、

 private const int WM_GETTEXT = 0x000D;

 StringBuilder strBuilder = new StringBuilder();
 SendMessage(hwndChild, WM_GETTEXT, strBuilder.Capacity, strBuilder);

まで辿り着けない。


【定義部】
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
 [DllImport("user32.dll", SetLastError = true)]
 static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, StringBuilder lParam);


質問だらけで、すみません。

【まとめサイト】
http://www.shise.net/wiki/wiki.cgi?page=C%23%2F% …

【その他】
http://uchukamen.com/Programming1/WindowFunctions/
http://oshiete.goo.ne.jp/qa/7220109.html

できれば、ご教授お願いします。

お礼日時:2013/10/23 13:39

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報