C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: 他のアプリ上にあるマウスポインタを消去する方法


(過去ログ 171 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■98588 / inTopicNo.1)  他のアプリ上にあるマウスポインタを消去する方法
  
□投稿者/ Tom (8回)-(2021/12/05(Sun) 21:03:41)

分類:[C#] 


他のアプリに「文字列を送信してマウスクリックさせる」定型操作をさせるプログラムを作っています。
文字列送信も指定座標へマウスを移動して、クリックもうまくいきました。
ただ、送信後に自分プログラムに制御が戻ってきたときに、送信先のアプリ上にマウスポインタの残骸が残ったままなのです。
(Cursor.Show();をやっても自分のプログラム制御でないためか、消えませんでした)

もちろんちょっとでもマウスを動かすと残骸は消えますが、非常に見た目が悪いです。
これをプログラム制御で消したいのですがうまい手はありませんでしょうか?

賢者の方、アドバイスを頂けませんでしょうか?
引用返信 編集キー/
■98589 / inTopicNo.2)  Re[1]: 他のアプリ上にあるマウスポインタを消去する方法
□投稿者/ くま (38回)-(2021/12/05(Sun) 22:03:26)
> マウスポインタの残骸
これがどの様な状態か分かりませんが
Tomさんの話されている「文字列を送信してマウスクリックさせる」の意味が
a. マウスポインタを指定のテキストボックスに移動(アプリが操作)
b. マウスポインタクリック動作(アプリが操作)
c. 文字列を入力(アプリが操作)
b. マウスポインタを指定のボタンに移動(アプリが操作)
d. マウスポインタクリック動作(アプリが操作)
とするならば
a.の前にマウスポインタの位置を記録
d.の後に記録しておいたマウスポインタの位置へ戻す
をしないと実際のマウス位置と違うため操作しずらくなります。

マウスポインタの位置を取得、変更(移動)する
https://dobon.net/vb/dotnet/system/cursorposition.html

自分の場合、相手のアプリにもよりますがWindowハンドルが取得できるコントロールなら
(SPY++ で調べて判断)直接メッセージを送信します。
でないとアプリ操作中は操作禁止を人が制御しないといけないからです。
あとできるだけ相手のアプリは外部操作可能なものを選んでその方法を採用します
・office関連ならCOM ライブラリ
・ブラウザ操作ならseleniumとかWebView2とか
・コマンドプロンプトで操作できるならそちらから操作とか

自分の経験では汎用的なアプリの操作としてマウスや入力を他のアプリから行うのはオススメできません。
(練習や習熟の為なら構いませんが。)
セキュリティもそうなんですが、とにかくコントロールが面倒なんです。
Aの動作後、Bの動作までのタイミングは?とか考えると面倒で...。


引用返信 編集キー/
■98590 / inTopicNo.3)  Re[1]: 他のアプリ上にあるマウスポインタを消去する方法
□投稿者/ KOZ (183回)-(2021/12/06(Mon) 08:57:24)
No98588 (Tom さん) に返信
> ただ、送信後に自分プログラムに制御が戻ってきたときに、送信先のアプリ上にマウスポインタの残骸が残ったままなのです。

メモ帳などをターゲットにして、現象のおきる最低限のコードを提示できないでしょうか?
コードを整理すると問題に気付いたりすることもあります。

> もちろんちょっとでもマウスを動かすと残骸は消えますが、非常に見た目が悪いです。

今の段階では、作っているプログラムでマウスを動かせばいいのでは?としか言えません。

引用返信 編集キー/
■98596 / inTopicNo.4)  Re[2]: 他のアプリ上にあるマウスポインタを消去する方法
□投稿者/ くま (42回)-(2021/12/06(Mon) 19:02:09)
偶然にも
「UpDate VB.NET OpenFileDialog について」
http://bbs.wankuma.com/index.cgi?mode=al2&namber=98591
で同じような自動操作についての質問がありました。

> Windowハンドルが取得できるコントロールなら直接メッセージを送信します。
そちらにサンプルを書き込んだので参考までに

引用返信 編集キー/
■98623 / inTopicNo.5)  Re[3]: 他のアプリ上にあるマウスポインタを消去する方法
□投稿者/ Tom (9回)-(2021/12/08(Wed) 01:28:14)
くま さま
KOZ さま

アドバイスありがとうございます。
最低限のコードのサンプルをつくってみては? とのことなので、作ってみたところ…
期待通り
(トリガーとなるボタンを押したら、
 メモ帳にマウスカーソルが移動してクリック、
 その後マウスカーソル消す)
の動作しちゃいました。
しかし、今度はメモ帳から戻ってきたはずのマウスポインタが消えたままになってしまいました。
(マウスカーソルがボタンに進入すると色が変わるのでそこにいる事は間違いないのですが)
何が間違っているのかよくわかりません。
更なるアドバイスを頂けませんでしょうか?

下記がそのサンプルです。
開発環境はVisual Studio 2017
言語はc#
プロジェクトのタイプは「Windowsフォームアプリケーション(.NET Framework)」で、
フォームにボタンを1つ作っただけです。

using System;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace WindowsFormsApp4
{
    public partial class Form1 : Form
    {
        //DLL使用するためのおまじない
        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
        [DllImport("user32.dll")]
        public static extern bool SetCursorPos(int X, int Y);
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
        [DllImport("user32.dll")]
        private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        public Form1()
        {
            InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            Process[] notepads = Process.GetProcessesByName("notepad");
            if (notepads.Length == 0) return;
            if (notepads[0] != null)
            {
                //マウスカーソル現在位置を保存
                int Old_xPos = System.Windows.Forms.Cursor.Position.X;  
                int Old_yPos = System.Windows.Forms.Cursor.Position.Y;

                //メモ帳の位置から新しいマウスカーソル位置を決定
                RECT WindowRect;
                GetWindowRect(notepads[0].MainWindowHandle, out WindowRect);
                int New_xPos = WindowRect.Left+10;
                int New_yPos = WindowRect.Top+10;

                //まずは現在のマウスカーソルを非表示
                Cursor.Hide();

                //すぐに移動しちゃうとよくわからないから3秒weitします
                Thread.Sleep(3000);

                //マウスカーソルを新しい位置に移動
                SetCursorPos(New_xPos, New_yPos);

                //マウスクリック(なんかこの時点で勝手にマウスカーソルが表示されちゃう)
                mouse_event(0x2, 0, 0, 0, 0);   
                mouse_event(0x4, 0, 0, 0, 0);

                //すぐに移動しちゃうとよくわからないから3秒weitします
                Thread.Sleep(3000);

                //元の場所に戻るからメモ帳上のマウスカーソルを非表示
                Cursor.Hide();

                //マウスカーソルを元の位置に移動
                SetCursorPos(Old_xPos, Old_yPos);

                //メモ帳上でクリックしたからそっちがアクティブなので自フォームをアクティブにする
                this.Activate();

                //元の場所のマウスカーソルを表示
                Cursor.Show();//←←←これが動作していない
            }
        }
    }
}


引用返信 編集キー/
■98626 / inTopicNo.6)  Re[4]: 他のアプリ上にあるマウスポインタを消去する方法
□投稿者/ くま (54回)-(2021/12/08(Wed) 02:12:12)
なるほど
1. マウス移動をマウスカーソルを消して見せなくしようとしているけどうまくいかない
2. 再表示させようとCursor.Show()してもうまくいかない。
という事ですね。

とりあえず理由と対策は

Form上でマウスカーソルを表示・非表示。Cursor.Hide()・Show()の罠
https://qiita.com/oo2kazuma/items/97b7cc3eb1a92c164f4e

です。
マウスカーソルのアイコン自体をない事にする方法ですが
先の処理もそうですが、アプリが失敗するとマウスカーソル消えたままになります。
(デバックモードで処理途中で停止させても同じ)

消えたらPC立ち上げ直しぐらいしか復旧できないですね。
(マウスカーソル無いからキーボード操作だけで行わないといけない)

チラつきはありますがこのままマウス自動実行ですすめるのであれば
マウスカーソルは消さない事をオススメします。

マウスカーソルが動いているのが見えるのはどうしてもイヤな場合は
先の私のサンプルのようにコントロールにイベントを送信(SendMessage)するか

外部アプリケーションのウィンドウをアクティブにする
https://dobon.net/vb/dotnet/process/appactivate.html

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);

のようにフォーカスを移動させることを提案します。
引用返信 編集キー/
■98627 / inTopicNo.7)  Re[4]: 他のアプリ上にあるマウスポインタを消去する方法
□投稿者/ KOZ (188回)-(2021/12/08(Wed) 03:13:40)
2021/12/08(Wed) 04:23:36 編集(投稿者)
No98623 (Tom さん) に返信
くまさんの回答にありますように、2回 Hide したら 2回 Show すれば出てきます。

あと、mouse_event のところですが

const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;

[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(Point p);

[DllImport("user32.dll")]
static extern IntPtr ChildWindowFromPoint(IntPtr hwndParent, Point p);

[DllImport("user32.dll")]
static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint);

[DllImport("User32.dll", CharSet = CharSet.Auto)]
static extern bool PostMessage(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam);

private IntPtr MakeLParam(int LoWord, int HiWord)
{
    return new IntPtr((int)((HiWord << 16) | (LoWord & 0xFFFF)));
}

    Point p = new Point(New_xPos, New_yPos);
    IntPtr hwndParent = WindowFromPoint(p);
    Point cp = new Point(New_xPos - WindowRect.Left, New_yPos - WindowRect.Top);
    IntPtr hwnd = ChildWindowFromPoint(hwndParent, cp);
    ScreenToClient(hwnd, ref p);
    IntPtr lp = MakeLParam(p.X, p.Y);
    PostMessage(hwnd, WM_LBUTTONDOWN, IntPtr.Zero, lp);
    PostMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, lp);


こんな感じでメッセージを送るといいと思います。

でもたいていの自動化ツールってマウスを表示したまま動かしているような気がしますね。

引用返信 編集キー/
■98643 / inTopicNo.8)  Re[5]: 他のアプリ上にあるマウスポインタを消去する方法
□投稿者/ Tom (10回)-(2021/12/09(Thu) 22:43:45)
くま さま
KOZ さま

アドバイスありがとうございました!
showとhideの実行数、同じにしたところ、ちゃんと動作しました。
showとhideは同じ数でないとダメ ってのはまったく知りませんでした。
目から鱗です。
これでなんとかなりそうです。

ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -