- ベストアンサー
LVM_HITTEST
マウス位置に存在するエクスプローラ内のアイテムを取得しようと思っております。 エクスプローラの左側のフォルダ一覧(クラス名:SysTreeView32)と右側のファイルとフォルダ名の一覧(クラス名:SysTreeView32)において、そのSysListView32内のマウス位置に存在するアイテムを取得したいのです。 なぜかというと、オリジナルアプリ内のリストビューにFTPサーバのファイル一覧を出力し、リストビューからエクスプローラへの直接ドラッグにより、サーバからローカル\TempにDLして、ドラッグ先にDLしたファイルを移動したいのです。 現状としてはLVM_HITTESTをエクスプローラ内のSysListView32に送っているのですが、こちらが送ったLVHITTESTINFO構造体のXYと、SpyでみたXYの値が違っているのです。結果としてアイテムインデックスを得ることができませんでした。 参考までに、LVM_GETITEMCOUNTはエクスプローラからも取得できました・・・ どのようにしたら、マウス位置のアイテムを取得することができるのでしょうか? 簡単に処理内容を記します。 ドラッグ時に GetCursorPos:マウス位置を取得 WindowFromPoint:マウス位置のハンドル取得 GetClassName:マウス位置のハンドルよりそのオブジェクトのクラス名を取得 以下は[クラス名=SysListView32]のときのみの処理 ScreenToClient:SysListView32をベースとした座標に変換 SendMessage: TVM_HITTESTと、LVHITTESTINFO構造体を送る 以上です。 本当は・・・ アプリはVBにて製作中なのですが、この手の質問はこちらのCの掲示板の方が回答を望めるかもと思って、こちらに質問させていただきました。Cで答えていただいて結構です。こちらでコンバートしますので。。。 どうぞよろしくお願いいたします。m(__)m
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
実際に試した訳じゃないのでうまくいくか分かりませんが、 思い付いた事を.... たしか今回のように別のプロセスにあるウィンドウを調べようとした場合、 LVM_GETITEMCOUNTのようにSendMessageの戻り値で取得するのは 問題ないけど、LVM_HITTESTのように構造体のアドレスを渡す場合には CreateFileMappingとMapViewOfFileを使って、共有メモリから 割り当てなければならなかったと思います。 // 共有メモリをオープン HANDLE hFileMapping = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL,PAGE_READWRITE, 0, sizeof(LVHITTESTINFO), NULL); LVHITTESTINFO* pHitTestInfo = (LVHITTESTINFO*)MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0); //LVHITTESTINFO構造体への値設定 ・・・ //HitTest SendMessage(hSysWnd, LVM_HITTEST, 0, (LPARAM)pHitTestInfo); // 共有メモリをクローズ UnmapViewOfFile(pHitTestInfo); CloseHandle(hFileMapping);
その他の回答 (4)
- todo36
- ベストアンサー率58% (728/1234)
VBのサンプルです。 OleDrag&Dropで出来そうですね。
お礼
何とか別方法で取得ができました。 共有メモリを確保して、ウィンドウズ側が発するメッセージを横取りしました。
補足
ありがとうございます。ファイルのコピーはそれで確かにできますね。 しかし、ファイルはローカルには存在していない状態から行う処理をするのです。 FTPソフトなので、ドラッグが始まるたびにDLして、セットしていては無駄な処理が多くなります。ですので、ドラッグが終わったときにドラッグ先のパスを取得し、同名ファイルの有無を取得した後DLするかどうかの問い合わせを行って、その後にローカル¥TempにDLを行います。DLが終了したら、指定のパスにファイルを移動します。 VBのOLEStartDragはドラッグスタート時に発生するイベントです。 VBの内部で行われている処理は、StreamにCF_HDROP(VBのvbCFFiles)型のデータをセットしてしまい、受け側がその型をサポートしている場合は受け側でそれを読み取るという処理を行っていると勝手に思ってますが・・・ 現在行いたいのは、ファイルのコピーや移動ではなく、そのドラッグ先のパス取得です。 ※現段階の調査結果の報告 1.エクスプローラ内のリスビューに、リストビューメッセージを渡すだけの処理は可能。 2.共有メモリを使用しても、エクスプローラ内のリスビューに、パラメータに値を返すリストビューメッセージを渡すとメモリエラー発生。 2について・・・ エクスプローラはメモリの共有参照不可にしているようです。これはVBでもCでも検証しました。(技術不足?)#3の発言を元に作成したもの以外に、GlobalAllocでメモリ確保して、コールバック関数でDrag処理をさせてもリストビューのアイテムを取得しようとすると、同じ状況になります。 ※今後の検証予定 Shellエクステンション系の操作を試みようと思います。 今は、どのエクスプローラが、どのフォルダを開いているかが取得可能になりました。しかしエクスプローラ内リストビューの中にサブフォルダが存在していて、そのサブフォルダの上にドラッグされたときの判断ができないので、その部分の処理を調査したいと思っています。
- akinori_s
- ベストアンサー率60% (21/35)
エキスプローラーへのドロップという事でしたら OleDrag&Dropを使ったほうが簡単かもしれません。 SAMPLEがあるURLのせておきますので参考にしてください。
お礼
ちょっとプロジェクトが大きめで、デバッグに時間がかかってしまいました。 現在作成中のアプリは、完成したら書物にしようと思っております。 VBでも一応プロセス監視などができるのですが、できるだけ使用したくない気持ちもあるのです。 参考コードをVBにコンバートしきれるかどうかがちょっと不安ですが。。。 もう少しやってみます。
補足
ありがとうございます。 現在デバッグ中につき、報告はちょっと待ってください。
- todo36
- ベストアンサー率58% (728/1234)
>うーむ、行き詰まってます・・・ 別の方法があるかもしれません。 反則ぎみなアドバイスをひとつ。 LHUT32というフリーソフトがエクスプローラへファイルをドロップできます。 これをSpyしてみては?
補足
LHUTではないですが、類似ソフトでの調査済みなので報告します。 受け側のエクスプローラ内のSysListView32内ではLVM_HITTESTは発生しているのですが、これはエクスプローラ本体が送っているメッセージ、あるいはWINDOWSそのものが送っているメッセージであって、アプリ側からLVM_HITTESTを送っているようには見えませんでした。 知り合いに相談した結果、「おそらくファイル名ではなく、"FileContents"でStreamを渡し・・・云々」というのですが、さっぱりです。 何か手は無いものでしょうか?
- todo36
- ベストアンサー率58% (728/1234)
↓に該当しませんか?
お礼
お礼ではなくさらに補足です。 デスクトップのクリック検出って、グローバルフックを使用しますよね? だから、もしかしてフックしなくてはいけないのかな? うーむ、行き詰まってます・・・
補足
英語が苦手なのでよく理解していませんが・・・ これはListViewのHITTESTですよね。 現在の方法で、ListViewのHITTESTは可能なのですが・・・ どうやらSysListView32へのHITTESTはちょっと違うようです。 フラグをセットする以前に、メッセージで送った構造体の各値と、受けている状態をスパイでデバッグした各値が違うのです。 最初に述べたように英語が苦手なので、意味不明な返答でしたらごめんなさい。 もし、参考URLが解決策を書いているのであれば、どのような内容か教えてください。 お願いいたします。
お礼
VB仕様かな?と思って、同様の処理をCでも作成して検証しました。 LVM_HITTESTを行うと、やはりメモリの違反が発生します。 海外サイトでも、別プロセスへのHITTESTのサンプルが存在しないのは、根本的に無理だから? とりあえず、別方法を考えます。
補足
現在VBのコードで、HitTestマクロを改良中です。 教えていただいたコードを参考に、このような状況になりました。 わかりずらいかもしれませんが、VBではAPIを呼ぶときに呼びたいAPI関数の宣言を先頭に行います。ですのでポインタで渡さなければならない部分は、きちんとポインタ渡しになっております。 Private Function ListView_HitTest(hwndLV As Long, pInfo As LVHITTESTINFO) As Long Dim hFileMapping As Long Dim pHitTestInfo As Long '共有メモリをオープン hFileMapping = CreateFileMapping(&HFFFFFFFF, ByVal 0&, PAGE_READWRITE, 0, LenB(pInfo), ByVal 0&) pHitTestInfo = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0&, 0&, 0&) 'パラメータによって受けた値を、共有メモリ領域にコピー Call CopyMemory(ByVal pHitTestInfo, pInfo, Len(pInfo)) 'ヒットテスト ListView_HitTest = SendMessage(hwndLV, LVM_HITTEST, 0, ByVal pHitTestInfo) Call CopyMemory(pInfo, ByVal pHitTestInfo, Len(pInfo)) 'それぞれ開放 Call UnmapViewOfFile(pHitTestInfo) Call CloseHandle(hFileMapping) End Function で現状としては、自アプリ中のリストビューからリストビューへのHITTESTは求めている結果を得ることができます。エクスプローラ内のリスビューに送ると、エクスプローラが落ちます。共有メモリの取得失敗? 最初に述べているようにVBで作成中です。使用しているリストビューは、VBのコントロールのリストビューです。スパイで監視したところ、ヒットテストのメッセージがそのVBリストビューコントロールで受けてないように見えます。[LVM_HITTEST]が発生していないのです。もしかして、VB仕様?もしそうなら、みなさんに迷惑をかけてしまってすいません。 もういちど、vbコントロールを使用しないで、API関数のみでリストビューを自作して調査してみます。 それでもだめなら、本当はCでDLLを作成するべきなのでしょうが、「VBでのFTPソフト」を目指しているので、できたらVBオンリーにしたいのです。。。 何はともあれもう一度チャレンジ!