こんにちは。
現在、WindowsXP、Visual Studio2005(以下VS)にて既存のアプリケーションの操作を行うツールを作成しようとしています。
Findwindow関数で親のハンドルをとり、EnumChildWindow関数でコントロールのハンドルを取得しましたが、操作したいボタンの情報が取れません。
参考にさせていただいたコードは以下です。
http://blog.goo.ne.jp/masaki_goo_2006/e/cea1b601 …

VS付属spy++の調査も同様の結果で、そのボタンの情報が出てきませんでした。
コントロールの情報がとれないという事はあるのでしょうか?

ちなみにボタンはtoolbarの上にありtoolbarの情報は取れています。

情報が取れない場合、操作は出来ないということでしょうか?

このQ&Aに関連する最新のQ&A

A 回答 (4件)

 こんにちは。

ツールボタンのどの情報を取りたいのでしょうか。
 SendMessage() TB_???のメッセージで情報を受け取る際、構造体等のポインタを必要とするものが多数ありますが、他プロセスのウィンドウハンドルに向かって此方側のポインタを渡してみた所で、向こう側からしてみれば「寝耳に水」も良い所です。
 プロセス間共有メモリを仲介して、データをやり取りする事になります。どちらにしろ、そんな簡単な事ではありません。
 以下ではVirtualAllocEx()を使用していますが、windows xpで上手くいくかはわかりません(windows 2000sp4の上では上手くいっています)。
 参考資料程度に。

#include<tchar.h>
#include<windows.h>
#include<commctrl.h>
#include<stdio.h>

typedef struct ProcessMemory
{
DWORD dwProcessID;
DWORD dwThreadID;
HANDLE hProcess;
union
{
LPVOID pVoid;
LPBYTE pByte;
LPARAM lParam;
};
} PROCESSMEMORY, *LPPROCESSMEMORY;

static BOOL OpenProcessMemory(LPPROCESSMEMORY p, HWND hWndOutProcess, DWORD dwSize)
{
p->dwThreadID = ::GetWindowThreadProcessId(hWndOutProcess, &p->dwProcessID);
if(!p->dwThreadID || !p->dwProcessID)
return FALSE;

p->hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, p->dwProcessID);
if(!p->hProcess)
return FALSE;

p->pVoid = ::VirtualAllocEx(p->hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
return p->pVoid != NULL;
}

static BOOL CloseProcessMemory(LPPROCESSMEMORY p)
{
if(!p->hProcess)
return FALSE;

::VirtualFreeEx(p->hProcess, p->pVoid, 0, MEM_RELEASE);
::CloseHandle(p->hProcess);
::ZeroMemory(p, sizeof(PROCESSMEMORY));
return TRUE;
}

static DWORD WriteProcessMemory(LPPROCESSMEMORY p, DWORD dwByteOfOffset, const void* pIn, DWORD dwSizeOfIn)
{
DWORD dwLen = 0;
::WriteProcessMemory(p->hProcess, &p->pByte[dwByteOfOffset], pIn, dwSizeOfIn, &dwLen);
return dwLen;
}

static DWORD ReadProcessMemory(const LPPROCESSMEMORY p, DWORD dwByteOfOffset, void* pOut, DWORD dwSizeOfOut)
{
DWORD dwLen = 0;
::ReadProcessMemory(p->hProcess, &p->pByte[dwByteOfOffset], pOut, dwSizeOfOut, &dwLen);
return dwLen;
}

int main()
{
//見つかっているものとする
HWND hWndOutProcess = ::FindWindow(_T("Afx:400000:b:10011:6:7042d"), NULL);
HWND hWndCtlBar = ::FindWindowEx(hWndOutProcess, NULL, _T("AfxControlBar42d"), NULL);
HWND hWndToolBar = ::FindWindowEx(hWndCtlBar, NULL, TOOLBARCLASSNAME, NULL);

//他プロセスのメインウィンドウ
PROCESSMEMORY pm = {0};
::OpenProcessMemory(&pm, hWndOutProcess, sizeof(TBBUTTON));

//他プロセスのツールバーの数を取る
const int count = ::SendMessage(hWndToolBar, TB_BUTTONCOUNT, 0, 0);
for(int i = 0; i < count; ++i)
{
//受け皿
TBBUTTON tbb = {0};

//プロセス間共有メモリをゼロで初期化
::WriteProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON));

//他プロセスのツールボタンメッセージ→プロセス間共有メモリ
::SendMessage(hWndToolBar, TB_GETBUTTON, i, pm.lParam);

//プロセス間共有メモリ→受け皿
::ReadProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON));

//取りあえず表示
::printf("[ボタン番号 : %d][ボタン状態 : %d][ボタンスタイル : %d][ボタンID : %d][ビットマップ番号 : %d]\n", i, tbb.fsState, tbb.fsStyle, tbb.idCommand, tbb.iBitmap);
}

::CloseProcessMemory(&pm);

return 0;
}
    • good
    • 0
この回答へのお礼

具体的な例ありがとうございます。
とても参考になります。

>ツールボタンのどの情報を取りたいのでしょうか。

やりたいことはそれぞれのボタンを押すことです。
その為のツールバー上のボタンのハンドル?をどのようにとればよいかわかりませんでした。

なかなか難しい内容で時間がかかるかもしれませんが
いただいた情報を頼りになんとか確認してみたいと思います。

お礼日時:2009/05/23 01:25

 こんにちは。

御礼頂きました。
 すっかり見落としていました。プログラムからツールボタンを操作するのが目的でした。
 此れに関して回答すると、WM_COMMANDをツールバーの親ウィンドウに送るか、WM_LBUTTONDOWN/WM_LBUTTONUPにツールボタンの座標を指定してクリックされた事にすれば出来ます。

//メモリの割り当て
PROCESSMEMORY pm = {0};
::OpenProcessMemory(&pm, hWndOutProcess, sizeof(TBBUTTON));

//受け皿
TBBUTTON tbb = {0};

//必要があれば此処でhWndOutProcessを最前面に持ってくる

//プロセス間共有メモリをゼロで初期化
::WriteProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON));

//2番目のツールボタンの情報を取る
::SendMessage(hWndToolBar, TB_GETBUTTON, 1, pm.lParam);

//プロセス間共有メモリ→受け皿
::ReadProcessMemory(&pm, 0, &tbb, sizeof(TBBUTTON));

//ツールバーの親ウィンドウにWM_COMMANDを送る
::SendMessage(hWndCtlBar/*ツールバーの親ウィンドウを指定*/, WM_COMMAND, tbb.idCommand, (LPARAM)hWndToolBar);

//メモリを閉じる
::CloseProcessMemory(&pm);

 又は、

//メモリの割り当て
PROCESSMEMORY pm = {0};
::OpenProcessMemory(&pm, hWndOutProcess, sizeof(RECT));

//受け皿
RECT rc = {0};

//必要があれば此処でhWndOutProcessを最前面に持ってくる

//プロセス間共有メモリをゼロで初期化
::WriteProcessMemory(&pm, 0, &rc, sizeof(RECT));

//2番目のツールボタンの矩形領域を取る
::SendMessage(hWndToolBar, TB_GETITEMRECT, 1, pm.lParam);

//プロセス間共有メモリ→受け皿
::ReadProcessMemory(&pm, 0, &rc, sizeof(RECT));

//ツールバーのボタン上でマウスの左ボタンが押された事にする
::SendMessage(hWndToolBar, WM_LBUTTONDOWN, 0, MAKELONG(rc.left + 2, rc.top + 2));

//ツールバーのボタン上でマウスの左ボタンが離された事にする
::SendMessage(hWndToolBar, WM_LBUTTONUP, 0, MAKELONG(rc.left + 2, rc.top + 2));

//メモリを閉じる
::CloseProcessMemory(&pm);

 と言った具合です(当方のPC上では両方とも動きます)。
    • good
    • 0
この回答へのお礼

動作確認のため返信遅れました。
申し訳ありません。
ほぼいただいたコード通りで無事に押すことが出来ました。
ありがとうございます。とても助かりました。
 
 ただ、ボタンが8個しかないのに、"TB_BUTTONCOUNT"で取得した数は19を示しています。
(この数の違いは何を示しているのかは後ほど知らべたいと思います。)
押せるボタンは8個ですのでどの番号がどのボタンを示しているのか、総当りで探した次第です。

しかし調べてみたところTB_ISBUTTONCHECKEDなどの他のメッセージを使えばこの辺の特定がうまく出来そうなので組み込んでみたいと思います。

お礼日時:2009/05/26 10:48
    • good
    • 0
この回答へのお礼

ありがとうございます。
調べてみます。

お礼日時:2009/05/23 01:20

ツールバーのボタンはボタンのようでボタンではありません。

あくまでツールバーの一部です。

なので、情報を取得するには、ツールバーのメッセージを使うとよいでしょう。
    • good
    • 0
この回答へのお礼

ありがとうございます。

ボタン(のようなもの)が10個くらいついているのですが
どのボタンかを特定するのはどうすればいいのでしょうか?

一つは位置情報かなと考えているのですが。

お礼日時:2009/05/22 15:01

このQ&Aに関連する人気のQ&A

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

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q他のウィンドウのボタンを自動的に押したい

VisualC++で作ったアプリケーションから、例えばWindowsに標準搭載の「電卓アプリケーション」のウィンドウをアクティブにして、さらにその中の「1」ボタンを認識して押す、テキストボックスを認識してそこに文字列を入れるといったソフトを作りたいです。

簡単にいうと、他のアプリケーションを自動的に操作するソフトを作りたいのです。

これを実現するために、Web検索してみましたが、関連する技術の名前やMFCでのAPI名がわからないです。これはどういった名前の技術で、VisualC++でどういった名前の関数を使うのでしょうか?

当方の環境はWindowsXP&VisualC++6.0です。

以上、よろしくお願いします。

Aベストアンサー

★列挙方法のアドバイス
・補足になる仕様の
>(1)ウィンドウのタイトルバーの名前(例:「電卓」)、
>またはウィンドウのIDでウィンドウを探す
 ↑
 これなら FindWindow() 関数でウインドウ・ハンドルを探せます。
 例: HWND hWnd = FindWindow( "SciCalc", "電卓" );
>(2)最初にヒットしたウィンドウをアクティブにする
 ↑
 最初にヒットした hWnd を SetForegroundWindow() 関数でアクティブにします。
 例: SetForegroundWindow( hWnd );
>(3)アクティブにしたウィンドウの中にあるボタンを探す
 ↑
 (1)で取得しているウインドウに対して子ウインドウ(ボタンなど)を列挙します。
 列挙には EnumChildWindows() 関数と EnumChildProc() のコールバック関数を使います。
>(4)「1」のボタン、またはボタンのIDがヒットしたらそのボタンを押す
 ↑
 列挙のコールバック関数(EnumChildProc)でボタンのキャプションを調べて
 『1』となっている文字列が電卓の『1』ボタンです。
 このときにボタンを押す処理をプログラムから行います。
 例: SendMessage( hChild, BM_CLICK, 0, 0 );
 URL: http://wisdom.sakura.ne.jp/system/winapi/win32/win53.html
・上記のような感じで操作できます。
 一番重要なのは操作するウインドウのハンドルを正しく見つけ出すことです。
 このウインドウ・ハンドルを見つけるには次の方法があります。
 (1)FindWindow() 関数を使う
 (2)EnumWindows() 関数を使う
 (3)Process32First()、Process32Next() 関数を使う
 (4)EnumProcesses() 関数を使う
 などがあります。
 今回は簡単な(1)を紹介しました。
 もしもウインドウのクラス名やキャプション名以外で詳しく捜査対象の
 ウインドウを検索するには(2)の EnumWindows() 関数や起動パス名を
 調べて特定できる (3)、(4)の関数群を利用します。
>テキストの内容の認識や保存など色々な機能を盛り込んだソフトを作りたいからです。
 ↑
 ボタンなどのテキストを認識、保存には GetWindowText()、WM_GETTEXT メッセージを
 使います。メッセージの場合は SendMessage() 関数でキャプション文字列を取得します。
 例: SendMessage( hChild, WM_GETTEXT, sizeof(szBuff), szBuff );
・下に簡単なボタンの列挙を載せます。これを活用して下さい。

サンプル:
#include <stdio.h>
#include <windows.h>

// コールバック関数
BOOL CALLBACK EnumChildProc( HWND hWnd, LPARAM lParam )
{
 TCHAR szBuff[ 1024 ];
 
 // キャプションの取得
 GetWindowText( hWnd, szBuff, sizeof(szBuff) );
 printf( "├[%s]\n", szBuff );
 return TRUE;
}

// メイン関数
int main( void )
{
 HWND hCalc;
 
 if ( (hCalc = FindWindow("SciCalc","電卓")) != NULL ){
  printf( "◆電卓のコントロール列挙\n" );
  EnumChildWindows( hCalc, EnumChildProc, NULL );
 }
 return 0;
}
以上。

★列挙方法のアドバイス
・補足になる仕様の
>(1)ウィンドウのタイトルバーの名前(例:「電卓」)、
>またはウィンドウのIDでウィンドウを探す
 ↑
 これなら FindWindow() 関数でウインドウ・ハンドルを探せます。
 例: HWND hWnd = FindWindow( "SciCalc", "電卓" );
>(2)最初にヒットしたウィンドウをアクティブにする
 ↑
 最初にヒットした hWnd を SetForegroundWindow() 関数でアクティブにします。
 例: SetForegroundWindow( hWnd );
>(3)アクティブにしたウィンドウの中にあるボタンを...続きを読む

Qc#で他のアプリの文字入力フォームに指定の文字を入力したい

例えばabc.exeというアプリがあったとします。
このアプリには文字列を入力するフォームがいくつかあり、
このアプリのフォームに文字を入れるプログラムを作成したいと思います。

まずはabc.exeをアクティブにし、
アプリのフォームの上から順に配列に代入された文字列の入力をしたいと思います。

つまり、
abc.exeの一番上のフォームにはmoji[0]にある文字列
二番目のフォームにはmoji[1]にある文字列
三番目のフォームにはmoji[2]にある文字列

という形です、こういったことは可能でしょうか?
SendKeys.SendWaitというのはこういうケースでも使えるのでしょうか?
もし可能であれば解説ページ、コードの例をご教示頂ければ幸いです。
よろしくお願いします。

Aベストアンサー

補足説明の方ありがとうございます。
かなり力技になってしまいますが・・・よければご参考までに

まず市販ソフトということなのでTabIndexが設定されてると思います。
そこで、Button押下後Tabキーと入力文字キーを送ってやります。
下記にサンプルを記述します。



using System.Runtime.InteropServices;

[DllImport("user32.dll")]
extern static IntPtr GetWindow(IntPtr hWnd, uint uCmd);

[DllImport("user32.dll")]
extern static IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
extern static int GetWindowText(IntPtr hWnd, StringBuilder lpStr, int nMaxCount);

[DllImport("user32.dll")]
extern static bool IsWindowVisible(IntPtr hWnd);

[DllImport("user32.dll")]
extern static bool SetForegroundWindow(IntPtr hWnd);


//ButtonClickイベント
const int GW_HWNDNEXT = 2;
StringBuilder sb = new StringBuilder(100);
IntPtr hwnd = GetForegroundWindow();
while (hwnd != IntPtr.Zero)
{
if (IsWindowVisible(hwnd))
{
GetWindowText(hwnd, sb, sb.Capacity); // タイトルバー文字列を取得
if (sb.ToString().IndexOf(textBox1.Text) != -1)
{

SetForegroundWindow(hwnd); // アクティブ

/***
*ここにSendKeys.SendWaitでキーを送ります。
*ラジオボタンがある場合Tabキーでラジオボタンをアクティブにし「↑」「↓」ボタンで変更
*チェックボックスの場合スペースキーでOnOff切り替え可能
*下記にキーコードが記述されています。
*MSDN SendKeys:http://msdn.microsoft.com/ja-jp/library/system.windows.forms.sendkeys(VS.80).aspx
*
*
***/


break;
}
}
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
}


この例ではTextBox1に別アプリケーションの名前の一部を入れることでアクティブにしています。
Ex)GoogleChrome → Google を入力し、Button1をクリックでGoogleChromeがアクティブになります。

力技すぎて汎用性も何もありませんが・・・ご参考までに

補足説明の方ありがとうございます。
かなり力技になってしまいますが・・・よければご参考までに

まず市販ソフトということなのでTabIndexが設定されてると思います。
そこで、Button押下後Tabキーと入力文字キーを送ってやります。
下記にサンプルを記述します。



using System.Runtime.InteropServices;

[DllImport("user32.dll")]
extern static IntPtr GetWindow(IntPtr hWnd, uint uCmd);

[DllImport("user32.dll")]
extern static IntPtr GetForegroundWindow...続きを読む

Q【C#】FindWindowExの使い方を教えてください

はじめまして
Visual Studio 2005を使用しています。
C#.NETは、いじり初めて1週間の超初心者です。
C#.NETでのFindWindowExの使い方を教えてください。
まずはじめに、vb.netで作ったアプリAの"Form1"があり、その中にテキストボックス"TextBox1"があります。
"TextBox1"のテキスト(キャプション?)には同じく"TextBox1"と入力されています。

そこで、C#側のアプリBでVBのアプリAの"Form1"のハンドルをFindWindowで取得します。
ここまでは出来ました。
次に、FindWindowExを使って"TextBox1"のハンドルを取得したいのですが、どうしてもうまく取得できません(0が返ってきます)

以下、C#のソースです。
(textBox1のMultilineはTrueです)
==================================================================

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr hWnd, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

public IntPtr hWnd = (IntPtr)0;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
IntPtr hWnd;
IntPtr hWndTest;
string sClassName = null;
string sWindowText = "AppA";

// アプリAのウインドウハンドルを取得
hWnd = FindWindow(sClassName, sWindowText);
textBox1.Text = "ウインドウのハンドル " + hWnd + "\r\n";

// アプリAのウインドウ内のTextBox1のハンドルを取得
hWndTest = hWnd;
sClassName = null;
sWindowText = "TextBox1";
hWnd = FindWindowEx(hWndTest, IntPtr.Zero, sClassName, sWindowText);
textBox1.Text += "テキストボックスのハンドル " + hWnd;

}
}
}

==================================================================

Spy++で覗くとテキストボックスにもハンドルが割り与えられているので取得できるはずだと思っているのですが、どうしてもいまくいきません。
どうか、よろしくご享受願います。

ちなみに、アプリAのテキストボックスのクラス名が”WindowsForms10.EDIT.app.0.378734a”となっているのですが、これはどの環境でビルド(コンパイル)しても不変なのでしょうか?
不変だとしたら、クラス名を使えば悩まずに取得できると思うのですが・・・(実験済み)

はじめまして
Visual Studio 2005を使用しています。
C#.NETは、いじり初めて1週間の超初心者です。
C#.NETでのFindWindowExの使い方を教えてください。
まずはじめに、vb.netで作ったアプリAの"Form1"があり、その中にテキストボックス"TextBox1"があります。
"TextBox1"のテキスト(キャプション?)には同じく"TextBox1"と入力されています。

そこで、C#側のアプリBでVBのアプリAの"Form1"のハンドルをFindWindowで取得します。
ここまでは出来ました。
次に、FindWindowExを使って"TextBox1"のハン...続きを読む

Aベストアンサー

FindWindowExの中でGetWidnowTextを呼び出しているため失敗するのだと思いますよ

GetWidnowTextはプロセスを超えては取得できないようです
取得できたとしても間違ったデータを返す場合があるようです
MSDNなどの GetWindowTextを確認してみてください

プロセスを超えて子コントロールのテキストを取得する場合は
WM_GETTEXTを直接コントロールにSendMessageで送って取得するようにしないといけないようです

Spy++は GetWindowで子コントロールのハンドルを取得してタイトルの取得にはWM_GETTEXTをSendMessageで送っているのではないかと思われます

VB.NETのAppAのテキストボックスのデータを書き換えても起動時に設定してあったデータで無いと失敗するようです

Q他アプリの操作(メニューバー)

市販されているアプリケーションを自分で作成しているソフトで操作したいのですが、どの様に制御したらいいのか判りません。プログラムはVB6.0で作成しております。
したい事は他のアプリケーションでメニューバーの中の項目の
印刷項目を選択したいのですが、メニューバーのハンドルを取得
出来ず困っております。
そもそもメニューバーのハンドルって取得できるのでしょうか?

Aベストアンサー

ウィンドウハンドルの取得については割愛します。

Option Explicit

Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const WM_COMMAND = &H111

Private Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type

' hWndに指定したウィンドウのメニュークリックをエミュレート
' Menusには、メニューを辿る順序を文字列配列で定義
' ファイル -> 印刷 であれば Menus() = {"ファイル", "印刷"}
Private Sub EmulateMenuClick(ByVal hWnd As Long, Menus() As String)
Dim hMenu As Long, lngID As Long, intMenuIndex As Integer
hMenu = GetMenu(hWnd)

' メニュー階層をたどる
For intMenuIndex = 0 To UBound(Menus)

If ContainMenu(hMenu, Menus(intMenuIndex), lngID) = False Then
Call MsgBox("一致するメニューはありません。")
Exit Sub
End If

Next

' 最終的に見つかったメニューのIDをWM_COMMANDでPostMessage
Call PostMessage(hWnd, WM_COMMAND, lngID, 0&)
End Sub

' hMenuのメニューハンドル内でTextの文字列と一致するメニューがあるかどうかを返す
' 見つかればTrue。このとき、hMenuにはサブメニューのハンドル、IDにはメニューのIDが返される
' 見つからなければFalse
Private Function ContainMenu(hMenu As Long, ByVal Text As String, ID As Long) As Boolean
Dim lngCount As Long, lngPos As Long
Dim typMenuItem As MENUITEMINFO
lngCount = GetMenuItemCount(hMenu)

' メニューの個数でループ
For lngPos = 0 To lngCount - 1
typMenuItem.fMask = &H3F&

typMenuItem.dwTypeData = vbNullChar
typMenuItem.cch = 0
typMenuItem.cbSize = Len(typMenuItem)
Call GetMenuItemInfo(hMenu, lngPos, 1, typMenuItem)

typMenuItem.dwTypeData = String(typMenuItem.cch, " ")
typMenuItem.cch = typMenuItem.cch + 1
typMenuItem.cbSize = Len(typMenuItem)
Call GetMenuItemInfo(hMenu, lngPos, 1, typMenuItem)

Debug.Print typMenuItem.dwTypeData

' メニューの文字列を比較(比較方法はどちらでも)
'If typMenuItem.dwTypeData = Text Then
If typMenuItem.dwTypeData Like Text Then

' 一致したらIDとサブメニューハンドルを返す
ID = typMenuItem.wID
hMenu = typMenuItem.hSubMenu
ContainMenu = True
Exit Function
End If
Next

ContainMenu = False
End Function

EmulateMenuClickにウィンドウハンドルと実行したいメニューを辿る文字列配列を渡してください。
画像は、このコードを利用してAPIビューアのバージョン情報をForm1から実行して表示させたものです。

ウィンドウハンドルの取得については割愛します。

Option Explicit

Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA...続きを読む

QC#で自分のウインド・ハンドルを取得するにはどうすればよいのでしょうか

C#を勉強中のものですが、教えて下さい。

タイトル通りですが、自分自身のウインドハンドルを取得する方法はあるのでしょうか?

Aベストアンサー

フォーム(コントロール)のHandleプロパティで取得できます。

QFindWindowの戻り値が違う!?

いつもお世話になっております。
FindWindowの戻り値についてご教授願います。

ret = FindWindow(NULL,"sample");
上記を実行した場合、取得する画面がアクティブの時と非アクティブの時でFindWindowの戻り値が違うのは何故でしょうか?

私は、sample画面が非アクティブでもアクティブ状態の時と同じハンドルが取得したのですが、良い方法は有りますでしょうか?

取得画面タイトル:sample
実行ファイル名:sample.exe

実行環境:WindowsXP
開発環境:VC++ 6.0

Aベストアンサー

No.1, No.2 への補足読みました。

VC++ に付属の Spy++ というツールを使うと,任意のウィンドウのウィンドウクラス名を調べることができます。
使い方は参考 URL を。

これで調べたウィンドウクラス名を,FindWindow の第1引数に渡してやればよいです。

ただし,ウィンドウクラス名は一意ではないので,確実に目的のウィンドウのハンドルが取れる保証はありません。
要は仕様でどこまで要求されるかですが,それじゃ困るという場合には別な方法を考えないといけませんね,ということで。

参考URL:http://www.microsoft.com/japan/developer/library/vcug/_asug_using_the_window_finder_tool.htm

QAlt+P,Alt+NをPostmessageで送るには

あるアプリがあり、そのハンドルを取得してからメッセージを送るプログラムを作っています。
PageUp,PageDownをそれぞれAlt+P,Alt+Nに変換して送るものです。
関数・定数宣言部は省略しています。

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  Dim hTest As Long
  hTest = FindWindow(vbNullString, "Test")
  If KeyCode = 33 Then 'PageUp
    PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0
    PostMessage MPL, WM_KEYDOWN, VK_N, 0
    PostMessage MPL, WM_KEYUP, VK_N, 0
    PostMessage MPL, WM_SYSKEYUP, VK_ALT, 0
  ElseIf KeyCode = 34 Then 'PageDown
    PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0
    PostMessage MPL, WM_KEYDOWN, VK_P, 0
    PostMessage MPL, WM_KEYUP, VK_P, 0
    PostMessage MPL, WM_SYSKEYUP, VK_ALT, 0
  End If
End Sub

送り先(Test.exe)では、
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  Dim L As String
  L = ""
  If Shift = 4 Then L = "Alt + "
  Label1.Caption = L & KeyCode
End Sub

ラベルで「Alt+P」などが来ているかどうか見ています。こちらのウィンドウで「Alt+P」を押すとちゃんと表示されます。

しかし、この2つを組み合わせるとPのみやNのみしか送られてきません。どこかおかしいのでしょうか。

Alt+PなどをPostMessageで送る方法でよい方法があれば、お教え下さい。
よろしくお願いします。

あるアプリがあり、そのハンドルを取得してからメッセージを送るプログラムを作っています。
PageUp,PageDownをそれぞれAlt+P,Alt+Nに変換して送るものです。
関数・定数宣言部は省略しています。

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  Dim hTest As Long
  hTest = FindWindow(vbNullString, "Test")
  If KeyCode = 33 Then 'PageUp
    PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0
    PostMessage MPL, WM_KEYDOWN, VK_N, 0
    PostMessage MPL,...続きを読む

Aベストアンサー

ALTキーとの組み合わせでしたら、WM_SYSCHARのほうがいいのでは?
たぶん、送り先もVB製でしたら内部でTranslateMessageような感じですし。


あと、
>PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0

MPLってなんですか?
>hTest = FindWindow(vbNullString, "Test")
で取得したウィンドウにPostMessageするんじゃないんですか?


次に、
>Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

KeyDownイベントに処理が書かれてますが、このイベント自体は呼ばれてますか?キー操作を受け付けるコントロールが張り付いてるのにKeyPreviewプロパティがFalseなんてことは無いですか?

#ちなみに、普通はVK_ALTではなくVK_MENUですので。

QC#でint型をIntPtr型に変換したいです。

C#でint型をIntPtr型に変換したいです。

こちらのサイト↓
http://msdn.microsoft.com/ja-jp/library/a0f1byxz.aspx
は見たのですが、いまいち理解できず困っております。。
sampleがあれば良かったのですが。。

どなたかご教授お願いいたします。
よろしくお願いいたします。

Aベストアンサー

int 元データ;
IntPtr 新データ = new IntPtr(元データ);

Q親ウインドウにあるOKボタンを押す方法

非常に基本的なことを質問して申し訳ございません。

●やりたいこと●
ある親ウィンドウに「テキスト」と「OKボタン」があります。
OKボタンはひとつだけです。
このOKボタンを押して、親ウィンドウを閉じるだけです。
OKボタンを押せば、親ウィンドウは勝手に閉じます。


親ウィンドウのハンドルは取得できたのですが、
子ウィンドウ(ボタン"OK")のハンドルが取得できず、
その後の処理もできておりません。

ボタンはひとつだけなので、ボタンのハンドルを検索したりしなくても、
押すことはできるような気がするのですが・・・
初心者の浅知恵で申し訳ございません。

やはり、ボタンのハンドルを取得して、押すコマンドを実行しないといけないのでしょうか?

ボタンのハンドルを取得して、押すコマンドを実行する場合、
その方法を教えていただけると幸いです。

親ウィンドウのハンドルは変数「hWindow」に入っているとして、
コードをお願いいたします。

親ウィンドウのハンドル取得に使ったFindWindow以外に宣言が必要であればご教授お願いいたします。

非常に基本的なことを質問して申し訳ございません。

●やりたいこと●
ある親ウィンドウに「テキスト」と「OKボタン」があります。
OKボタンはひとつだけです。
このOKボタンを押して、親ウィンドウを閉じるだけです。
OKボタンを押せば、親ウィンドウは勝手に閉じます。


親ウィンドウのハンドルは取得できたのですが、
子ウィンドウ(ボタン"OK")のハンドルが取得できず、
その後の処理もできておりません。

ボタンはひとつだけなので、ボタンのハンドルを検索したりしなくても、
押すことはでき...続きを読む

Aベストアンサー

子ウィンドウを探すには、下の2つのAPIの使います。

  EnumChildWindows(hWnd,lpEnumFunc,0&)
  GetClassName(hWnd,lpClassName,nMaxCount)

EnumChildWindows が、親ウィンドウのハンドルと、子ウィンドウを受け取る関数を
与えます。ただし、子ウィンドウを受け取る関数はフォームモジュールではなく、
標準モジュールにないと駄目です。

すると与えた子ウィンドウを受け取る関数に、親ウィンドウに含まれる全ての子ウィンドウの
ハンドルが返ってきます。

返ってきたハンドルを元に GetClassName で、クラス名を取得し、ボタンのウィンドウを
特定します。今回の場合は、ボタンが1個しかないとのことなので、取得したクラス名が
Buttonであればそのハンドルがボタンのハンドルになります。
参考までに、複数個のボタンがあれば、この場合、どのボタンがOKボタンなのかを特定しない
といけません。「スパイ」とか言うソフトがあれば簡単に特定できるのですが、ない場合は、
子ウィンドウに含まれる、上記の手順で得た全てのボタンのハンドルに対して、プログラムで
BM_CLICKのメッセージを送り一つづつ確認していくしかありません。ただこの場合でも、
特性があって、親ウィンドウに複数個のボタンがあっても、子ウィンドウを受け取る関数には
必ず一定の順番にしか、ハンドルが返ってきないので、最初に一度だけ何番目のボタンかを特定
すればよいです。対象のアプリケーションを再度起動してもこの順番は変わりません。

あと、ボタンのクリックは、SendMessageで、BM_CLICK を送ればOKです。

今回は、簡単な他アプリの制御なので、そんなに問題がないですが、複雑な制御だと、
更に、ウエイトの方法だとか、制御するアプリが確実に動作しているか、確認する操作を
1ステップずつ挿入していかないと駄目です。そうすれば、全ての他のアプリケーションを
自由に操る事ができます。

本格的に作るとなると大変なので、フリーのソフトで沢山でていると思います。一度さがされたら
よいと思います。DLLタイプになっているのがよいとは思います。
以前私も使ったことがありますが、憶えていません。あしからず。現在は自作しております。
自作のがよりきめ細かく制御出来るからです。

子ウィンドウを探すには、下の2つのAPIの使います。

  EnumChildWindows(hWnd,lpEnumFunc,0&)
  GetClassName(hWnd,lpClassName,nMaxCount)

EnumChildWindows が、親ウィンドウのハンドルと、子ウィンドウを受け取る関数を
与えます。ただし、子ウィンドウを受け取る関数はフォームモジュールではなく、
標準モジュールにないと駄目です。

すると与えた子ウィンドウを受け取る関数に、親ウィンドウに含まれる全ての子ウィンドウの
ハンドルが返ってきます。

返ってきたハンドルを元に G...続きを読む

Q他のアプリケーションとの連携

 VBを使って他の既存のソフトなどへ何らかの命令をかけることは可能でしょうか?
 
 具体的には起動中のほかのアプリケーションへキー操作をさせる…というようなことは可能でしょうか?

 たとえば、コマンドを設置しておいて、そのコマンドをクリックすると起動中の別のアプリケーション上でEnterキーを押した状態を引き起こさせるというようなことです。
 
 また、それとは逆に他のアプリケーションを監視して、キーが押されたときに反応させるというようなことは可能でしょうか?

 API関数等を使用するのでしたらどういう関数を使用すればよいか教えてください。
 よろしくお願いします。

Aベストアンサー

># 反論~にどうぞ。
(゜ .゜)ノ カンシャ デス
真意をわかっていただいて、うれしいです。^^


サンプルです。

このサンプルを実行するには二つのプロジェクトが必要となります。

Project1
└Form1
  ├Command1
  └Command2
'Form1の中身
Option Explicit

Private Sub Command1_Click()
  MsgBox 1
End Sub

Private Sub Command2_Click()
  MsgBox 2
End Sub
と記載して、ボタンが押されたらメッセージボックスを表示するようにしておきます。
これをEXEにして起動しておいてください。



Project2
└標準モジュール
'標準モジュールの中身
Option Explicit

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const WM_COMMAND = &H111
Private Const BN_CLICKED = &H0&

Sub Main()
  Dim lngWindWnd As Long 'ウィンドウハンドル
  Dim lngBtnWnd1 As Long '最初に見つかったボタン
  Dim lngBtnWnd2 As Long '2番目に見つかったボタン
  
  
  'アプリケーションタイトルより、ウィンドウハンドル得ます
  lngWindWnd = FindWindow(vbNullString, "Form1")
  
  
  '指定のウィンドウハンドル内の、最初に見つかったクラス名[ThunderRT6CommandButton](VB6で作成したコマンドボタン)のハンドルを得ます
  '【注意:2番目の引数が0(Nullポインタ)のとき、最初に見つかったものを返すように指定している】
  lngBtnWnd1 = FindWindowEx(lngWindWnd, 0, "ThunderRT6CommandButton", vbNullString)
  Call SendMessage(lngWindWnd, WM_COMMAND, BN_CLICKED, ByVal lngBtnWnd1)
  
  
  '指定のウィンドウハンドル内の、2番目に見つかったクラス名[ThunderRT6CommandButton](VB6で作成したコマンドボタン)のハンドルを得ます
  '【注意:2番目の引数が0以外(Nullポインタではない)とき、2番目のパラメータ以降に見つかったハンドルを返すように指定している】
  lngBtnWnd2 = FindWindowEx(lngWindWnd, lngBtnWnd1, "ThunderRT6CommandButton", vbNullString)
  Call SendMessage(lngWindWnd, WM_COMMAND, BN_CLICKED, ByVal lngBtnWnd2)
End Sub




といった感じです。
一番最初にサンプルを載せたかったのですが、ちょっと納期前ということで、説明を簡略化してしまいました。


>一文字(Enterキー)を渡すだけならSendKeysでも問題はないかな..
たしかにそうですね。。。
話を戻しますが、#3で書いた電子電○帳と連携したソフトですが、目的のボタンにたどりつくために、[TAB]を数回送った後に[ENTER]を送っていました。最初から目的のボタンにフォーカスがあるのであれば、全然問題ないのですが、、、

なので、処理によってはSendkeysで十分だと思いますが、2回以上のSendkeysが連続するようなのであれば、OSの状況に影響されないAPIを使うことをお奨めします。

># 反論~にどうぞ。
(゜ .゜)ノ カンシャ デス
真意をわかっていただいて、うれしいです。^^


サンプルです。

このサンプルを実行するには二つのプロジェクトが必要となります。

Project1
└Form1
  ├Command1
  └Command2
'Form1の中身
Option Explicit

Private Sub Command1_Click()
  MsgBox 1
End Sub

Private Sub Command2_Click()
  MsgBox 2
End Sub
と記載して、ボタンが押されたらメッセージボックスを表示するようにしておきます。
これをEXEにして起動しておい...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報