C#でのウィンドウへのキー送信

結論としては、以下の2種類の方法があるとわかりました。

① .NetのSendKeys.SendWaitメソッド:
 → 最前面のウィンドウ限定。引数が単純で使いやすい。
② ・WindowsAPIのPostMessageメソッド:
 → 送信先のウィンドウ指定可能。引数が複雑で使いにくい。必要な引数はSpy++にて調査可能。

以下経緯などです。

今携わっている案件で、プログラムからキー送信を行うことで
外部のアプリをショートカットキーにより自動操作することになりました。

お客様の調査により、
.NetのSendKeys.SendWaitメソッドにより実現可能だとわかっていたのですが、
このメソッドは送信先を指定できず、必ず最前面のウィンドウにキー送信を行うもので、
自動操作中にユーザ操作などで最前面のウィンドウが切り替わってしまうと
誤ったアプリにキーを送信してしまうことになります。

そこで可能ならウィンドウを指定して送信するという方針になり、
社内メンバーからウィンドウのハンドルを引数に与えてキー送信できるメソッドがあると伺いました。

調べてみたところWindowsAPIのPostMessageがそれにあたるとわかり、
試してみたのですが、文字列を引数に与えるだけのSendKeys.SendWaitとは異なり、
引数が複雑(ハンドルとキー内容だけでなく、複数のパラメータを32bitに詰め込んだ値が必要)で、
目的のキーを送信するためにどうすればよいかわかりませんでした。

そこで更に調べてみたところ、VisualStudioに含まれるSpy++というアプリにより、
目的のソフトへキーを送信した際のメッセージをログ出力して、
送信時の引数を調べることができるとわかりました。
参考:
VBAのSendKeys,System.Windows.FormsのSendWaitなどが反応しないときに読む記事 – 適材適所

これにより、無事PostMessageによるキー送信をテストすることに成功しました。

結果的には、
操作対象のアプリはそもそも最前面に表示されている状態でないとキー送信による操作を受け付けないとわかったため、
今回はキー送信前に毎回ウィンドウのActivateする方針に決まりましたが、
PostMessage(+ Spy++による送信内容の調査)は今後何かしらに役に立ちそうだなと感じています。

また余談ですが、
調査中にPostMessageによりゲームにキー送信を行い自動で操作する旨の話をチラッと見かけました。
学生時代に見かけたゲームAIの研究で、
「ゲームの状態を画像処理で読み取り、行動を決定し、外部からゲームを操作するAI」
を見かけたことがあったのですが、
あの実現にはこの辺りのメソッドを呼んでいたのだなと懐かしみながら今更のように思いました。

以上です。

C#で配列やリストをforとforeachで走査する際の速度比較

先日、コードの速度チューニングを行ったのですが、
その際にC#ではforeach文よりもfor文の方が速いという話を思い出して、
書き換えを行う前に調査してみました。

次の記事を参考に速度調査させていただきました。ありがとうございます。
forとforeachのアクセス速度比較 – Qiita

個人的な結論としては、以下のようになりました。
・リスト使用時はfor文が速い(要素へのアクセスには注意)
・配列使用時はforeach文が速い
・リストよりも配列の方が速い
なので、カリカリにチューニングしたい場合は配列+foreachが良いのかもしれません。
(そこまでする必要がある場合は、実際のコードで速度比較して決定した方が良さそうです)

それぞれの速度比較は以下です。(処理時間は末尾に記載)

・リスト使用時の速度
for文(一時キャッシュあり)> ForEachメソッド > foreach文 >>> for文(一時キャッシュなし)
・配列使用時の速度
foreach文 > for文(一時キャッシュあり)> for文(一時キャッシュなし)

調査してわかったこと・わからなかったことは以下です。
・Listの値へのインデクサでのアクセスはその都度個数チェックが発生するので、
 何度も使う場合遅い。一時変数にキャッシュすべし。
・ListのEnumeratorでは個数以外のチェックも行っているので、
 個数チェックだけのfor文やArrayのEnumeratorより遅い
・配列の場合に、for文よりもforeachの方が速い理由は不明
 (個数へのアクセスが内部フィールドな分速いとか?)

処理速度を調査するにあたり
参考にさせていただいだ記事中のコードに以下のようなコードを追記し、
リストと配列の2パターン用意してテストしました。

for (var i = 0; i < testlist.Count; i++) {
	var value = testlist[i]; // 一時変数にキャッシュ
	for (var cnt = 0; cnt < 1000; cnt++) {
		buf = value;
	}
}

それぞれの処理時間は以下です。10回平均です。
(tmp = 一時キャッシュあり)

By List
for Loop : 204 ms
for Loop tmp : 79.5 ms
foreach Loop : 82.7 ms
ForEach Loop : 81.8 ms

By Array
for Loop : 67.8 ms
for Loop tmp : 50.7 ms
foreach Loop : 49.7 ms

以上です。

軸制御案件の見積もり

先日、案件の見積もりを行いました。

ざっくり言うと3軸アームを制御してアームに取り付けたセンサによりワークの検査を行うシステムで、
ワークそのものも何かしらのセンサとなります。
機能が多く、かなり見積もり工数が膨らんだため、
工数内に予定通り納められるか不安ではあるのですが、
自分は軸制御の案件は初めてなので実装を楽しみにもしています。

個人的に一番楽しみなポイントは、
ワークであるセンサの出力の波形から適した近似式のパラメータを求めるところです。
近似式を計算する関数に一回通すだけでなく、
n手間加えて若干最適化のような処理を行う仕様となる予定で、
実装するのを楽しみにしています。

まだ注文が出たわけではないのですが、
注文が出たら頑張ります。

ChatAIを用いたオープンソースコードの調査

先日、PythonのコードをC#に書き直すことになる案件の工数見積のために、
Pythonコードの調査を行いました。
以前もPythonの書き直しの案件はありましたが、
今回は以前と違って他社さんが作成したコードでなくGithub上のオープンソースのコードが対象です。
(もちろんライセンスには準拠します。)

自分がPythonに不慣れなのもあるのですが、
Pythonは型宣言がほとんどなくデータの型を追いにくい
(特に多次元行列をスライス記法でnumpyなどに投げた結果、
 どのようなデータに整形されたかがわかりにくい)
といった理由で読むだけでは判断が付かず、
実際に動かしてみないと処理内容に確証が持てないことが自分は多々あります。

そこで今回は、読んでいる途中でBingChatに投げてみました。
メソッドを貼り付けて、
・「以下のコードを説明してください」
・「以下のコードを1行ずつ説明してください」
などとお願いしたところ、
わかりやすくメソッド概要とコードの1行ずつの解説が出力してくれて、調査の時短になりました。
説明が不明瞭or不足している箇所も部分的に「この部分を説明してください」とお願いすることで、
深堀りして説明を得られました。
これさえあれば自力で解読する必要はないかもしれませんね。
(解説を理解し、間違っていないか判断するためにプログラムの知識は必要ですが)

業務コードを投げるのはコンプライアンス的に問題ですが、オープンソースなら大丈夫ですし、
・GPTのバージョンにより学習期間は異なりますが、
 オープンソースは基本学習済みのため精度の高い回答を貰える可能性が高い
・単純なコードでない限り、自力で解読するより圧倒的に速い
ように思いますので、オープンソースの解読には積極的にChatAIを利用しようと思います。

おすすめのアミノ酸

皆さん、日々元気にお過ごしでしょうか。

自分は平日毎日働くだけで疲れがちだったのですが、
最近ネットで味の素のアミノバイタルなるアミノ酸を飲むと良いと見かけたので、
試しに買ってみて就寝2,3時間前に毎日飲んでいます。
まだ2週間程度ですが既に効果を実感しており、
疲労が溜まりにくく元気に過ごせております。
アミノ酸量の異なる2種(アミノバイタル プロ3800mg/アクティブファイン2200mg)を試してみているのですが、
量の多い方がより効果を感じています。

本来は運動や筋トレをしている人が踏ん張る力や疲労回復を目的に運動前や運動後に飲むことが多いようなのですが、
デスクワーカーでも効果があるみたいです。
もしプラシーボ効果だったとしても日々を元気に過ごせるなら儲けものですね!

以上、おすすめ商品紹介でした。

コンテンツ自動生成プログラム

GWに趣味で、パターン画像を再帰的に描画するプログラムをC#とOpenCVで実装しました。
フラクタル図形描画プログラムのようなものです。
遠出している最中に処理を考え、その日の内に処理の流れだけ実装し、別日に本実装をしたのですが、
すんなり動くものが実装できて良かったです。
素直に書いたら5重ループになったので、計算量削減には若干手間がかかりました。
人力でも作成可能な画像ではあるのですが、
気が遠くなるような時間がかかるところをPC性能や再帰回数次第ですが数分で描画できます。
自分の代わりに何かコンテンツを自動生成してくれるプログラムは、万能感を感じることができるので好きです。

最近はお絵描きAIがどちらかと言えば悪い意味で話題になっていて、
データを学習しない自動生成プログラムまで叩かれるのではないかと少し不安になりますね。
データを学習するしないに関わらず、法的・倫理的に他者の権利を侵害しない範囲で、
自動生成技術が進歩して行くと良いなと思います。

ユーザビリティの考慮

自分はまだ仕様の整理やプログラムの設計・実装に精一杯で、
ユーザの使用環境を考慮したソフトの使いやすさに気が回らないことが多いです。

例えば最近の失敗だと、お客様からの要望仕様通りではあるのですが、
作業者にキーボードのない小型タッチパネルPCにて
書類ファイル(Wordなど)の入力・登録を強いるような機能仕様としてしまっていました。

ユーザの使用環境を正しく想定できていれば、そのような作業内容は現実的でないため、
後から別のPCにて入力・登録できるようにするといった改善仕様を考えられたのだと思います。

中々難しいですが、ユーザビリティを考慮したソフトを作るようにしたいです。

設計の重要性

最近ソフトウェアのある1機能の開発を行ったのですが、想定よりも工数が多くかかってしまいました。
工数がオーバーした原因を考えると、
全体の設計がぼんやりとした甘い状態からコードを書き始めてしまったために、
実装時の迷いや構造の見直しによる手戻りが生じたりしてしまったからではないかと思われます。

プログラムもそれ以外のものでも、
何かを作る際に全体が曖昧なまま個々の詳細から作り込むと、
最終的にそれらを整合性を保ちながら結合させるのは難しく、
結果として辻褄を合わせるはめになり、時間がかかったり構造が歪になってしまう気がしています。

そうならないためにも、全体を曖昧に設計した後、
まずは徐々に全体設計の詳細を詰めて行き(抽象度を下げて行き)、
中盤以降に詳細を作り込み始める(プログラムだとコードを書き始める)のが良いのだと思います。

今回の場合だと、設計は処理の流れと曖昧なクラス設計のみだったのですが、
社内メンバーからの助言を盛り込むと、
データの流れも考えた上で、クラス設計の最低限上位の部分まではしっかり設計してから、
コードを書き始めるべきだったのかと思います。

手を動かさないと何も進めていないように感じたり思われたりするかもしれませんが、
その時間をかけることで結果的に工数を削減できるのではないかと思われるので、
時間に上限は設けた上でしっかり設計を行うようにしたいです。

Python->C#書き直し業務所感

ここ最近は他社のソフトを作り直す案件に携わっています。
自分の担当はPyhonで書かれた部分をC#で書き直す作業です。
書き直すコードはざっくり言うと画像に写っている人間を検出するコードで、
以下のような処理を行っています。
1. 推論エンジンに入力画像を投げる
2. 推論出力結果から検出された物体の情報を切り出す
3. 切り出した物体情報を元の入力画像上の値に変換する
物体の情報をどのようにデータ構造に格納しているかなどがわかって、書き直していて面白いです。

書き直していて思った所感は他に以下の2点です。

1. Pythonの方が多次元配列を扱いやすい
 Pythonには数値計算ライブラリのnumpyがある関係で多次元配列が扱いやすいです。
 機械学習を行う際の主流になるのも納得です。
 C#で書き直しているコードでは1次元配列で保持し、
 多次元配列のインデックスを1次元配列のものに変換してアクセスするようにしたのですが、
 インデックスの計算などにミスしてしまい、修正に少し手間取ってしまいました。
 …とここまで書いて、ふと調べてみましたがC#でもnumpyのライブラリがあるようでした。
 書き直したコードのパフォーマンスなどに問題あれば、使用を検討しようと思います。

2. コードのコピペをする際は中身を極力解読すべき
 既存Pythonのコードを調査していたところ、コアの部分がネットからコピペされていました。
 ライセンスなどないコードだったのでそれ自体は問題ないかとは思いますが、
 よく解読せずにコピペしたために生じたのではないかと思われる実装ミスがありました。
 (コピペ内で行われている処理をコピペ外で重複して行っており、
  設定次第では正常に動作しなくなっていました)
 マジックナンバーなど解読できないこともあるかと思いますが、
 不精せずに可能な限り解読を試みてコメントを付与して、
 保守しやすい状態にする必要があると感じました。

以上です。

2022年お世話になりました

早いもので2022年ももう少しで終わりですね。

弊社は本日、午前は通常業務、午後からは大掃除を行いまして、本年の業務終了と相成りました。
明日から4日まで冬季休暇で5日から通常業務となります。

皆様本年はお世話になりました。
来年も何卒よろしくお願いいたします。
それではよいお年をお迎えください。