11

別のWindowsアプリケーションをプログラムで処理する必要があります。グーグルを検索すると、DLLImport属性を使用してWindows計算機を処理し、user32.dll関数をC#の管理対象関数にインポートするサンプルが見つかりました。

アプリケーションが実行されています。メインウィンドウのハンドル、つまり電卓自体を取得していますが、その後のコードが機能していません。FindWindowExメソッドは、ボタンやテキストボックスなどの電卓の子のハンドルを返しません。

DLLImportでSetLastError=Trueを使用しようとしましたが、「Procedurenotfound」というエラーコード127が表示されることがわかりました。

これは私がサンプルアプリケーションを入手したところからのリンクです:

http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=14519&av=34503

誰かがそれを解決する方法を知っているなら助けてください。

更新:DLLImportは次のとおりです。

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

動作していないコードは次のとおりです。

hwnd=FindWindow(null,"Calculator"); // This is working, I am getting handle of Calculator

// The following is not working, I am getting hwndChild=0 and err = 127
hwndChild = FindWindowEx((IntPtr)hwnd,IntPtr.Zero,"Button","1");

                Int32 err = Marshal.GetLastWin32Error();
4

3 に答える 3

13

試行しているコードは、個々のボタンのキャプションに依存してボタンを識別します。たとえば、次のコードを使用して「1」ボタンへのハンドルを取得します。

hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "Button", "1");

これは、ウィンドウクラスの名前に「ボタン」を指定し、ウィンドウの名前に「1」を指定します(ボタンの場合、これはボタン自体に表示されるキャプションテキストと同じです)。

このコードは、電卓のボタンがテキストのキャプションで識別されていたWindows XP(および以前のバージョン)で正常に機能しました。「1」ボタンのウィンドウ名は「1」であるため、ボタンのキャプションとして「1」が表示されていました。

ただし、Windows 7では状況が変わったようです(Vistaでも同様ですが、そのようなシステムにアクセスできないため、これを確認することはできません)。Spy ++を使用して電卓ウィンドウを調査すると、「1」ボタンのウィンドウ名が「1」ではなくなっていることが確認されます。実際、ウィンドウ名はまったくありません。キャプションはNULLです。おそらく、電卓の新しい派手な外観では、ボタンをカスタム描画する必要がありました。したがって、どのボタンがどの機能に対応するかを示すためにキャプションは不要になりました。カスタムペイントルーチンは、必要なキャプションの描画を処理します。

指定したウィンドウテキストのボタンが見つからないNULLため、ウィンドウハンドルに値0()が返されます。

関数ドキュメントにはFindWindowExNULL、パラメーターを指定できることが示されていますlpszWindowが、これはもちろん、指定されたクラスのすべてのウィンドウに一致します。電卓アプリにはたくさんのボタンがあるので、この場合はおそらくあなたが望むものではありません。

良い回避策はわかりません。電卓はこのように「自動化」されるようには設計されておらず、Microsoftは内部の動作を変更しないことを保証していませんでした。これは、他のアプリケーションのウィンドウを混乱させるためにこのアプローチを使用する際に取るリスクです。


編集:あなたがリンクしたコードは、以前のバージョンのWindowsでも、別のかなり深刻な方法で間違っています。hwnd変数を型intではなく型として宣言しますIntPtr。ウィンドウハンドルはポインタであるため、常に型として保存する必要がありますIntPtrFindWindowExこれにより、赤旗を送信するはずだった関数呼び出しの醜いキャストも修正されます。

SendMessageまた、の宣言を修正して、最初のパラメーターがタイプになるようにする必要がありますIntPtr

コードは次のように記述されている必要があります。

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");
    }
}
else
{
    //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);

    //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);
}
于 2011-03-09T06:14:47.713 に答える
2

Win7Proでこれを再現することができました。あなたの問題は、ボタンのラベルがキャプションとしてではなく、電卓のテーマを介して描かれている可能性があります。テーマサービスの実行中に電卓を起動すると、キャプションのないボタンが表示されます。

適切なボタンキャプションを取得するには、次のことを行う必要があります。

  1. テーマサービスを停止します(net stop themes管理者特権のコマンドプロンプトから実行するか、サービス管理ツールを使用します)。
  2. 電卓を起動します。

テーマサービスを停止するときに電卓を実行している場合は、すべてのボタンが空白になっていることに気付くでしょう。

于 2011-03-09T06:51:34.670 に答える
2

次のコードは、クラシックテーマのWindows 7のCaculatorで正常に機能します(ベーシックまたはAeroテーマでは機能しません)。

IntPtr hwndFrame = FindWindowEx(hwnd, IntPtr.Zero, "CalcFrame", null); 
IntPtr hwndDialog = FindWindowEx(hwndFrame, IntPtr.Zero, "#32770", null); 
IntPtr hwndDialog2 = FindWindowEx(hwndFrame, (IntPtr)hwndDialog, "#32770", null);

IntPtr hwndThree = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "3"); 
SendMessage((int)hwndThree, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndPlus = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "+");
SendMessage((int)hwndPlus, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndOne = FindWindowEx((IntPtr)hwndDialog2, IntPtr.Zero, "Button", "1");
SendMessage((int)hwndOne, BN_CLICKED, 0, IntPtr.Zero);

IntPtr hwndEqual = FindWindowEx(hwndDialog2, IntPtr.Zero, "Button", "=");
SendMessage((int)hwndEqual, BN_CLICKED, 0, IntPtr.Zero);
于 2012-04-16T11:25:32.960 に答える