学校の課題でwebカメラでQRコードを読み取り、その結果を処理して外部デバイス(FPGAボード)に送るというものを作成した。
そのときのメインはFPGAボード側の開発だったのでQRコード読み取りは簡略化するためにフリーソフトを使うことにした。
しかし、フリーソフトと言えど自らプログラムを書きかえれるわけではなかったのでソフトに表示された文字列を読み取ることにした。
読み取った値を処理して送信するということも必要であったので、フリーソフトが出力した値を自前のソフトで読み取らせるというプログラムを作った。
方法としてはwin32APIを用いる。
まず、必要なソフトウェア
・Winspector SPY
被取得側のハンドルを取得するソフト。読み取りたい部分のハンドルの構成を教えてくれる。
他にもいろいろと役に立つのでオススメ。
・iALink
QRコードを読み取るのに使用したフリーソフト。一番シンプルなものだったのでこれにした。
iALinkの読み取りたい場所はQRコードで読み取った文字列が出力されるこの部分。

winspectorでiALinkのハンドル構成を解析する。(使い方は参考ページ参照)
iALinkのハンドルのツリー構成を確認。

つまりハンドルのツリー構成は
“- iALink”ウィンドウ->ReBarWindow32->#32770->Edit
つまり、この順番でアクセスしていけば、出力部分(Edit)にアクセスする。
次はC#側のおはなし。
今回使用する関数を簡単に説明すると
FindWindow関数:引数に与えられた文字列と一致するウィンドウを探し出す関数
FindWindowEx関数:引数に与えられた文字列と一致するウィンドウのハンドルを探し出す関数
SendMessage関数:指定されたウィンドウからメッセージ(文字列など)を取得してくる関数
これらを使用できる用に準備して、親ハンドルから子ハンドルにアクセスしていくプログラムを作った。
一つ一つ掘り下げていってアクセスしているがもっと単純な方法があるのかもしれない。。。
ソースコードはこんな感じ。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace camera
{
public partial class Form1 : Form
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowThreadProcessId(IntPtr hWnd,out int lpdwProcessId);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd,UInt32 Msg,int wParam,StringBuilder lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent,IntPtr hwndChildafter,string lpszClass,string lpszWindow);
private const int WM_GETTEXT = 0x000D;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IntPtr hWnd = FindWindow(null," - iALink");
if (hWnd != IntPtr.Zero)
{
//ウィンドウを作成したプロセスのIDを取得する
int processId;
GetWindowThreadProcessId(hWnd, out processId);
//processのオブジェクトを作成する
Process p = Process.GetProcessById(processId);
IntPtr hWndc1 = FindWindowEx(hWnd, IntPtr.Zero, "ReBarWindow32", "");
IntPtr hWndc2 = FindWindowEx(hWndc1,IntPtr.Zero,"#32770","");
IntPtr hWndc3 = FindWindowEx(hWndc2,IntPtr.Zero,"Edit","");
StringBuilder sb = new StringBuilder(256);
SendMessage(hWndc3, WM_GETTEXT, 255, sb);
label1.Text = sb.ToString();
}
else {
label1.Text = "Not Found";
}
}
}
}
実行結果はこんな感じ。
iALinkに入力されている文字列がしっかりと自作ソフトで読み込めていることが確認できたので成功。
