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

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

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

Win32APIでヘッダーコントロールの文字が取得できない

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

■103295 / inTopicNo.1)  Win32APIでヘッダーコントロールの文字が取得できない
  
□投稿者/ PATIO (1回)-(2024/08/28(Wed) 15:46:39)

分類:[その他の言語] 

ずいぶんお久しぶりです。
PATIOです。

この所、VBAを使った業務の自動化ツールの開発に携わってまして、
Win32APIを叩いて外部アプリの制御をやっています。
リストビューから情報を取得する時にどの列にどんな情報がセットされているかを知る為に
ヘッダーコントロールの文字列を取得してサブアイテムのインデックスと情報名を紐づけています。
社内の整備ツールで行っていて実績もあったのですが、
最近、この整備ツールをベースに新しく提供されたツールではヘッダーコントロールからの文字列取得が
全て空になってしまい、内容の列位置の判断が出来なくなってしまっています。

使っているのはSendMessageAでHDM_GETITEMを送るというベーシックな方法です。
取得用のメモリも共有メモリを確保する方法で行っていて以前は動作していた方法です。

同じく、タブコントロールの文字列も取得できなくなっており、タブの名称指定で選択する機能も動かない状態です。
方法もほぼ同じでTCM_GETITEMを使って取得していました。

特に手掛かりがなくネット上での検索でも情報を見つける事が出来ていません。
何か心当たりがある方がいらっしゃいましたら情報の提供をお願いいたします。

引用返信 編集キー/
■103296 / inTopicNo.2)  Re[1]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ kiku (441回)-(2024/08/28(Wed) 16:27:32)
No103295 (PATIO さん) に返信
> ずいぶんお久しぶりです。
> PATIOです。
>
> この所、VBAを使った業務の自動化ツールの開発に携わってまして、
> Win32APIを叩いて外部アプリの制御をやっています。
> リストビューから情報を取得する時にどの列にどんな情報がセットされているかを知る為に
> ヘッダーコントロールの文字列を取得してサブアイテムのインデックスと情報名を紐づけています。

その外部アプリは、複数あるのでしょうか?
複数あると仮定して、そのすべてに対して同じ現象が発生しているのでしょうか?
一部のアプリのみであると仮定して、そのアプリの動作環境は.NETFrameWork、.NET、ネイテクブなど、
条件が絞れるような情報はないでしょうか?

質問に対する回答にはなっていませんが、
もう少し絞れる情報があったり、
再現可能な条件であったりがあると、
みなさん回答しやすくなると思います。
引用返信 編集キー/
■103297 / inTopicNo.3)  Re[1]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ とくま (15回)-(2024/08/28(Wed) 17:06:39)
No103295 (PATIO さん) に返信
・・・当たり前の話だけど、

>以前は動作していた方法
実績のあるツールが、全く同じ条件で、同じ端末で、今は動かないなら環境だよね。
OS アップデートとかセキュリティソフトとか。

実績のあるツールは動くけど、新しいツールが動かないならコーディングミスだよね。
VBA なら、Office のバージョンとか、信頼できるフォルダに配置とか、証明書とか、管理者で実行とかも
含めて、新しいツールで同じ条件を再現できていないということだよね。

引用返信 編集キー/
■103298 / inTopicNo.4)  Re[1]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ 魔界の仮面弁士 (3797回)-(2024/08/28(Wed) 17:28:37)
No103295 (PATIO さん) に返信
> 使っているのはSendMessageAでHDM_GETITEMを送るというベーシックな方法です。
> 取得用のメモリも共有メモリを確保する方法で行っていて以前は動作していた方法です。

通信先のプロセスが「管理者モードで実行」されている、ということはないでしょうか。
引用返信 編集キー/
■103299 / inTopicNo.5)  Re[2]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (2回)-(2024/08/29(Thu) 08:34:17)
No103296 (kiku さん) に返信
> ■No103295 (PATIO さん) に返信
> その外部アプリは、複数あるのでしょうか?
> 複数あると仮定して、そのすべてに対して同じ現象が発生しているのでしょうか?
> 一部のアプリのみであると仮定して、そのアプリの動作環境は.NETFrameWork、.NET、ネイテクブなど、
> 条件が絞れるような情報はないでしょうか?

現状、症状が確認できているのは一つのアプリケーションだけです。
仕様書を確認しないと確実なことは言えませんが、VC++ネイティブで組まれていると思います。
新しくリリースされたツールは見た目は元のプログラムからほとんど変わっていませんが、
部分的に項目やボタンが追加されているという状態です。
おそらく元のプログラムをベースに追加修正を行っていると思われます。
考えられるとすると今回の改修時に開発環境のアップデートを行っている可能性があります。
ランタイム等のバージョンが上がっているかもしれません。

> 質問に対する回答にはなっていませんが、
> もう少し絞れる情報があったり、
> 再現可能な条件であったりがあると、
> みなさん回答しやすくなると思います。

すいません。
今、手元でわかる範囲で出していくつもりですが、
調べて分かったことがあれば追記していきますので
お付き合いいただけるとありがたいです。
引用返信 編集キー/
■103300 / inTopicNo.6)  Re[2]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (3回)-(2024/08/29(Thu) 08:42:26)
No103297 (とくま さん) に返信
> ■No103295 (PATIO さん) に返信
> ・・・当たり前の話だけど、
>
> >以前は動作していた方法
> 実績のあるツールが、全く同じ条件で、同じ端末で、今は動かないなら環境だよね。
> OS アップデートとかセキュリティソフトとか。
>
> 実績のあるツールは動くけど、新しいツールが動かないならコーディングミスだよね。
> VBA なら、Office のバージョンとか、信頼できるフォルダに配置とか、証明書とか、管理者で実行とかも
> 含めて、新しいツールで同じ条件を再現できていないということだよね。

既存のツールについてはWin11で動くことが分かっているのでOSが直接の原因ではないのではと考えています。
新規にリリースされたツールは既存のツールをベースに別の用途用に必要な機能を追加して作成されたもので
プロジェクトを複製して改修を行っていると思われます。
プロジェクトを複製したときに新しい開発環境に合わせてコンバートされているとすると
ランタイム等が最新のものを使用するように変換されているかもしれません。
この辺りは開発部署に直接問い合わせないと出てこない情報だと思います。

後出し情報で申し訳ないのですが、
SendMessageでWM_GETTEXTを呼び出した時の文字列については取得できているので
すべてがうまく行っていないというわけではありません。
現状確認できているのはリストビューのヘッダーコントロールから文字列が取得できない。(数は取得できる)
タブコントロールの文字列が取得できない。(数は取得できる)
という状況です。調べればできていない機能がまだ出てくる可能性はあると思います。

引用返信 編集キー/
■103301 / inTopicNo.7)  Re[2]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (4回)-(2024/08/29(Thu) 08:50:54)
No103298 (魔界の仮面弁士 さん) に返信
> ■No103295 (PATIO さん) に返信
>>使っているのはSendMessageAでHDM_GETITEMを送るというベーシックな方法です。
>>取得用のメモリも共有メモリを確保する方法で行っていて以前は動作していた方法です。
>
> 通信先のプロセスが「管理者モードで実行」されている、ということはないでしょうか。

ないとは言い切れないので調べてみます。
とりあえず、プロセスの起動時に管理者権限を指定しているかくらいはすぐ確認できると思います。

他の返信でも書いていますが、全部がダメというわけではなく、
リストビューのヘッダーコントロールから文字列が取得できない。(数は取得できる)
タブコントロールの文字列が取得できない。(数は取得できる)
という状況でWM_GETTEXTは正常に動作しています。
今の状態だと自動化ツールが途中までは動いて止まるという状態です。
ざっと見た感じではほかの機能は正常に動作しているようです。

APIの機能を変更で取得方法が変わったとかならそれに対応すればいいのですが、
そういう情報を見つける事ができていないので実際のところはわかりません。

引用返信 編集キー/
■103302 / inTopicNo.8)  Re[3]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ kiku (442回)-(2024/08/29(Thu) 09:13:34)
No103300 (PATIO さん) に返信
> ■No103297 (とくま さん) に返信
>>■No103295 (PATIO さん) に返信

> 新規にリリースされたツールは既存のツールをベースに別の用途用に必要な機能を追加して作成されたもので
> プロジェクトを複製して改修を行っていると思われます。

新規ツール、新規テスト対象システムのセットで問題が発生していると
理解しました。
であるならば、同じPC上で改修前ツール、改修前ツールが対応しているテスト対象システムの
セットで動作させてみて問題がなければ、
下記が言えるのではないでしょうか?
・PCの環境は変わらないので環境の問題ではない
・新規ツールに問題がある可能性がある
・新規テスト対象システム側の問題で取得できない可能性がある
引用返信 編集キー/
■103304 / inTopicNo.9)  Re[4]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (5回)-(2024/08/29(Thu) 09:51:29)
No103302 (kiku さん) に返信
> ■No103300 (PATIO さん) に返信
>>■No103297 (とくま さん) に返信
> >>■No103295 (PATIO さん) に返信
>
>>新規にリリースされたツールは既存のツールをベースに別の用途用に必要な機能を追加して作成されたもので
>>プロジェクトを複製して改修を行っていると思われます。
>
> 新規ツール、新規テスト対象システムのセットで問題が発生していると
> 理解しました。
> であるならば、同じPC上で改修前ツール、改修前ツールが対応しているテスト対象システムの
> セットで動作させてみて問題がなければ、
> 下記が言えるのではないでしょうか?
> ・PCの環境は変わらないので環境の問題ではない
> ・新規ツールに問題がある可能性がある
> ・新規テスト対象システム側の問題で取得できない可能性がある

対象の整備システムはインストールが勝手にできないので上記を試すのは簡単にはできそうにないです。
既存のツールと新規ツールの同時インストールを想定しているのかわからないので。
現状の自動化ツールの動作が新規ツールで動かない現象が特定のPCではなく、同環境のほかのPCでも発生するなら
PC固有ではなく、整備システムの違いのよるものという事は言えると思うのですが、
そこから先は環境構築のところからやらないといけないので時間がかかりそうです。
いずれにしても台風の事もあってリモートで作業しているので今週中は無理そうです。

引用返信 編集キー/
■103309 / inTopicNo.10)  Re[3]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ 魔界の仮面弁士 (3798回)-(2024/08/29(Thu) 16:58:09)
No103301 (PATIO さん) に返信
>> 使っているのはSendMessageAでHDM_GETITEMを送るというベーシックな方法です。
>> 取得用のメモリも共有メモリを確保する方法で行っていて以前は動作していた方法です。

そうですね。値を返す API (HDM_GETITEMCOUNT メッセージなど)と違い、
ポインタでやりとりする API (HDM_GETITEM メッセージなど)は、
プロセスを超えてメモリアドレスを渡すことができないため、
共有メモリを用意する必要があるでしょう。

WM_COPYDATA メッセージなども、内部的には共有メモリを使っているらしい。


> リストビューのヘッダーコントロールから文字列が取得できない。(数は取得できる)
> タブコントロールの文字列が取得できない。(数は取得できる)
> という状況でWM_GETTEXTは正常に動作しています。

WM_SETTEXT や WM_GETTEXT は Win16 時代からの互換性な事情により、特例的に、
プロセスを超えてメモリアドレスを渡しても文字列を授受できる仕様になっていたかと。
(EM_SETTEXT や SetWindowText はどうだっけ)


> APIの機能を変更で取得方法が変わったとかならそれに対応すればいいのですが、

原因が特定できていない以上、まずは情報収集ということで、
どういうコードを用意して、それがどういう結果になっているのか確認していきたいところですね。

・HDITEM.pszText メンバーに確保していたバッファーが更新されない?
・HDITEM.pszText が元のバッファーとは異なるテキストを指すようになっている?
・HDITEM.pszText で受け取った文字列が空っぽになっている?
・HDM_GETITEM メッセージ自体が失敗して FALSE を返してきている?

VBA ということで、その Office がストアアプリ版かどうかも確認しておいた方が良いかも。
引用返信 編集キー/
■103310 / inTopicNo.11)  Re[5]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ とっちゃん (832回)-(2024/08/29(Thu) 17:02:49)
No103304 (PATIO さん) に返信

とりあえず一番最後にぶら下げておこう…

プロセスをまたいでメッセージを送ってるんですよね?
メッセージで文字列などメモリを転送できるのは
WM_GETTEXT と WM_COPYDATA の2つでだけです。
それ以外は、値をそのままやり取りするだけメモリとしての転送処理は行ってくれません。



で、従来の環境ではそれを回避するため共有メモリを利用して
同じアドレス上にメモリがあるように見せて
間接的にメモリ転送していたのだと思います。


最近ビルドした(==環境が新しい)アプリだとうまくいかないということを考えると
メモリアドレスのランダム化とかもあるからそのあたりじゃないかなぁ?
もしかしたらx64化とかもあり得ますが。

おそらくグローバルフックを使って相手プロセス内で情報収集して
それをドキュメントされている方法で転送するくらいしかないと思います。

一応フックのリファレンスを貼っておきます。

・フック
https://learn.microsoft.com/ja-jp/windows/win32/winmsg/hooks?WT.mc_id=DT-MVP-32182

引用返信 編集キー/
■103312 / inTopicNo.12)  Re[4]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (9回)-(2024/08/30(Fri) 10:14:02)
No103309 (魔界の仮面弁士 さん) に返信
>>APIの機能を変更で取得方法が変わったとかならそれに対応すればいいのですが、
>
> 原因が特定できていない以上、まずは情報収集ということで、
> どういうコードを用意して、それがどういう結果になっているのか確認していきたいところですね。
>
> ・HDITEM.pszText メンバーに確保していたバッファーが更新されない?
> ・HDITEM.pszText が元のバッファーとは異なるテキストを指すようになっている?
> ・HDITEM.pszText で受け取った文字列が空っぽになっている?
> ・HDM_GETITEM メッセージ自体が失敗して FALSE を返してきている?

HDITEM.pszTextには、共有メモリで確保した0クリアしたバッファを引き渡しています。
帰ってきたHDITEM.pszTextの中身は引き渡した時と同じ状態で返ってきています。
引き渡し時に0クリアしているので相手側で空文字列を設定したのかどうかまではわかりません。
メッセージのやり取りは失敗していないという認識ですが、
現状、台風の影響でリモートワーク中の上にVPNがパンクして会社に接続できない状態なので
確認ができません。月曜にになれば確認できると思うのですが。


> VBA ということで、その Office がストアアプリ版かどうかも確認しておいた方が良いかも。
Office365を使っているのでExcelも365版です。
おそらくストアアプリ版ではないと思うのですが、
どなたか確認方法をご存じの方いらっしゃいますか?

引用返信 編集キー/
■103313 / inTopicNo.13)  Re[6]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (10回)-(2024/08/30(Fri) 10:25:09)
No103310 (とっちゃん さん) に返信
> ■No103304 (PATIO さん) に返信
>
> とりあえず一番最後にぶら下げておこう…
>
> プロセスをまたいでメッセージを送ってるんですよね?
> メッセージで文字列などメモリを転送できるのは
> WM_GETTEXT と WM_COPYDATA の2つでだけです。
> それ以外は、値をそのままやり取りするだけメモリとしての転送処理は行ってくれません。
>
> で、従来の環境ではそれを回避するため共有メモリを利用して
> 同じアドレス上にメモリがあるように見せて
> 間接的にメモリ転送していたのだと思います。
>
>
> 最近ビルドした(==環境が新しい)アプリだとうまくいかないということを考えると
> メモリアドレスのランダム化とかもあるからそのあたりじゃないかなぁ?
> もしかしたらx64化とかもあり得ますが。

x64化はちょっと疑っていましたが、メモリアドレスのランダム化は考慮に入って言いませんでした。
これってアプリの外部から情報を抜くのを邪魔するためですよね。
まあ、GUIを外部アプリから操作しようという話がそもそも乱暴な話なので
仕方がないのかなぁとは思いますけれど。
本来ならAPI連携するとかアプリの方を改良するとかが本筋だと思いますし。

> おそらくグローバルフックを使って相手プロセス内で情報収集して
> それをドキュメントされている方法で転送するくらいしかないと思います。
>
> 一応フックのリファレンスを貼っておきます。
>
> ・フック
> https://learn.microsoft.com/ja-jp/windows/win32/winmsg/hooks?WT.mc_id=DT-MVP-32182

フックまでしないとダメならあきらめた方が良いのかもしれません。
対象の整備ツールも裏で色々やってそうなのであんまりやりすぎない方がよさそうです。
既存版の方はまだ猶予がありそうなので運用方法も含めて別のやり方を検討してみます。

メモリアドレスのランダム化の内容は一応おさえておこうと思います。

引用返信 編集キー/
■103314 / inTopicNo.14)  Re[5]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ 魔界の仮面弁士 (3799回)-(2024/08/30(Fri) 11:33:30)
2024/08/30(Fri) 11:34:47 編集(投稿者)

No103312 (PATIO さん) に返信
> ・HDITEM.pszText が元のバッファーとは異なるテキストを指すようになっている?
> HDITEM.pszTextには、共有メモリで確保した0クリアしたバッファを引き渡しています。

ポインタの参照先の文字列のことではなく、
ポインタそのものが指し変わっていないか、という点の確認です。

https://learn.microsoft.com/ja-jp/windows/win32/controls/hdm-getitem?WT.mc_id=DT-MVP-8907
上記だと、
 ・要求されたテキストでバッファーを埋めるのではなく、新しいテキストを指すように
  構造体の pszText メンバーを変更できます。 アプリケーションでは、テキストが
  常に要求されたバッファーに配置されることを想定しないでください。
との記述があるので、指定した「共有メモリ」以外に配置される可能性もあるのかな、と。

あるいは HDM_GETITEM を使う代わりに、UIAutomation で辿ってみるとか。


>> VBA ということで、その Office がストアアプリ版かどうかも確認しておいた方が良いかも。
> Office365を使っているのでExcelも365版です。
特に記載はありませんでしたが、Excel の VBA をお使いなのですね。


> おそらくストアアプリ版ではないと思うのですが、
> どなたか確認方法をご存じの方いらっしゃいますか?
C2R, MSI, Store の識別としては、このあたりとか。
https://officesupportjp.github.io/blog/cl0m8t2dj00393gvs3r7oar2m/
https://answers.microsoft.com/ja-jp/msoffice/forum/all/office/956cb54d-5441-4233-b3de-c3dbefe00d26
引用返信 編集キー/
■103316 / inTopicNo.15)  Re[6]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (11回)-(2024/08/30(Fri) 17:12:12)
No103314 (魔界の仮面弁士 さん) に返信
> 2024/08/30(Fri) 11:34:47 編集(投稿者)
>
> ■No103312 (PATIO さん) に返信
>>・HDITEM.pszText が元のバッファーとは異なるテキストを指すようになっている?
>>HDITEM.pszTextには、共有メモリで確保した0クリアしたバッファを引き渡しています。
>
> ポインタの参照先の文字列のことではなく、
> ポインタそのものが指し変わっていないか、という点の確認です。
>
> https://learn.microsoft.com/ja-jp/windows/win32/controls/hdm-getitem?WT.mc_id=DT-MVP-8907
> 上記だと、
>  ・要求されたテキストでバッファーを埋めるのではなく、新しいテキストを指すように
>   構造体の pszText メンバーを変更できます。 アプリケーションでは、テキストが
>   常に要求されたバッファーに配置されることを想定しないでください。
> との記述があるので、指定した「共有メモリ」以外に配置される可能性もあるのかな、と。

なるほど、その発想はなかったです。
最終的にpszTextのアドレスを使ってローカルメモリにWriteMemoryして
そこからStringにしているのでもしpszTextのアドレスが書き換えられていたとすると
参照できないでコピーできないかもしれません。

>
> あるいは HDM_GETITEM を使う代わりに、UIAutomation で辿ってみるとか。
>
>
> >> VBA ということで、その Office がストアアプリ版かどうかも確認しておいた方が良いかも。
>>Office365を使っているのでExcelも365版です。
> 特に記載はありませんでしたが、Excel の VBA をお使いなのですね。
>
>
>>おそらくストアアプリ版ではないと思うのですが、
>>どなたか確認方法をご存じの方いらっしゃいますか?
> C2R, MSI, Store の識別としては、このあたりとか。
> https://officesupportjp.github.io/blog/cl0m8t2dj00393gvs3r7oar2m/
> https://answers.microsoft.com/ja-jp/msoffice/forum/all/office/956cb54d-5441-4233-b3de-c3dbefe00d26

ありがとうございます。
デスクトップ版であることが確認できました。

引用返信 編集キー/
■103317 / inTopicNo.16)  Re[7]: Win32APIでヘッダーコントロールの文字が取得できない
□投稿者/ PATIO (12回)-(2024/09/02(Mon) 15:56:57)
問題が解決いたしましたので原因と解決方法についてご報告致します。

とっちゃんさんからご指摘いただいた64bit化が直接の原因でした。
当方で作成している自動化ツールは32bit版のEXCEL上で動作するVBAマクロです。
外部アプリの操作モジュールは、Win32APIを呼び出して外部アプリを制御しています。
この時、呼び出しに使用する構造体をVBAのユーザ定義型として定義しています。
ご存じの通り、VBAのユーザー定義型はアライメントの調整を行いませんので
ユーザー定義型を定義する時にアライメントを考慮する必要があります。
元々、対象のアプリケーションは32bitアプリとして提供されていましたので
ユーザー定義型も32bitアプリを対象に4バイトアライメントを考慮して定義していました。

今回、改修版を作成するに際に64bit化を行ったそうで提供された物は64bitアプリでした。
64bitアプリの場合、8バイトアライメントを意識して定義する必要があります。
この為、引き渡した構造体メンバーのメモリー上の位置がズレてしまい、
意図した情報が引き渡されていませんでした。
今回の改修版用にユーザー定義型の定義を8バイトアライメントの合わせた物を作成して
動作を確認した所、タブコントロールの文字列、リストビューのヘッダーの文字列ともに
正常に取得する事が出来ました。
分かってしまえばなるほどという内容でしたが、64bit化という可能性を失念していましたので
指摘して戴けて大変助かりました。

あまり頻繁に発生するような問題ではないと思いますが、
同様の問題の解決のヒントになれば、幸いです。

ご協力いただいた皆様に感謝いたします。

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


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

このトピックに書きこむ