マウス位置に存在するエクスプローラ内のアイテムを取得しようと思っております。

エクスプローラの左側のフォルダ一覧(クラス名: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

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

A 回答 (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);

この回答への補足

現在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オンリーにしたいのです。。。


何はともあれもう一度チャレンジ!

補足日時:2001/12/07 07:56
    • good
    • 0
この回答へのお礼

VB仕様かな?と思って、同様の処理をCでも作成して検証しました。

LVM_HITTESTを行うと、やはりメモリの違反が発生します。
海外サイトでも、別プロセスへのHITTESTのサンプルが存在しないのは、根本的に無理だから?

とりあえず、別方法を考えます。

お礼日時:2001/12/07 17:14

VBのサンプルです。


OleDrag&Dropで出来そうですね。

参考URL:http://homepage2.nifty.com/inform/vbmania/source …

この回答への補足

ありがとうございます。ファイルのコピーはそれで確かにできますね。

しかし、ファイルはローカルには存在していない状態から行う処理をするのです。
FTPソフトなので、ドラッグが始まるたびにDLして、セットしていては無駄な処理が多くなります。ですので、ドラッグが終わったときにドラッグ先のパスを取得し、同名ファイルの有無を取得した後DLするかどうかの問い合わせを行って、その後にローカル¥TempにDLを行います。DLが終了したら、指定のパスにファイルを移動します。


VBのOLEStartDragはドラッグスタート時に発生するイベントです。
VBの内部で行われている処理は、StreamにCF_HDROP(VBのvbCFFiles)型のデータをセットしてしまい、受け側がその型をサポートしている場合は受け側でそれを読み取るという処理を行っていると勝手に思ってますが・・・

現在行いたいのは、ファイルのコピーや移動ではなく、そのドラッグ先のパス取得です。


※現段階の調査結果の報告
1.エクスプローラ内のリスビューに、リストビューメッセージを渡すだけの処理は可能。
2.共有メモリを使用しても、エクスプローラ内のリスビューに、パラメータに値を返すリストビューメッセージを渡すとメモリエラー発生。

2について・・・
エクスプローラはメモリの共有参照不可にしているようです。これはVBでもCでも検証しました。(技術不足?)#3の発言を元に作成したもの以外に、GlobalAllocでメモリ確保して、コールバック関数でDrag処理をさせてもリストビューのアイテムを取得しようとすると、同じ状況になります。


※今後の検証予定
Shellエクステンション系の操作を試みようと思います。
今は、どのエクスプローラが、どのフォルダを開いているかが取得可能になりました。しかしエクスプローラ内リストビューの中にサブフォルダが存在していて、そのサブフォルダの上にドラッグされたときの判断ができないので、その部分の処理を調査したいと思っています。

補足日時:2001/12/10 16:09
    • good
    • 0
この回答へのお礼

何とか別方法で取得ができました。

共有メモリを確保して、ウィンドウズ側が発するメッセージを横取りしました。

お礼日時:2001/12/13 14:11

エキスプローラーへのドロップという事でしたら


OleDrag&Dropを使ったほうが簡単かもしれません。
SAMPLEがあるURLのせておきますので参考にしてください。

参考URL:http://support.microsoft.com/default.aspx?scid=k …

この回答への補足

ありがとうございます。
現在デバッグ中につき、報告はちょっと待ってください。

補足日時:2001/12/07 09:32
    • good
    • 0
この回答へのお礼

ちょっとプロジェクトが大きめで、デバッグに時間がかかってしまいました。

現在作成中のアプリは、完成したら書物にしようと思っております。
VBでも一応プロセス監視などができるのですが、できるだけ使用したくない気持ちもあるのです。

参考コードをVBにコンバートしきれるかどうかがちょっと不安ですが。。。
もう少しやってみます。

お礼日時:2001/12/07 17:19

>うーむ、行き詰まってます・・・



別の方法があるかもしれません。
反則ぎみなアドバイスをひとつ。
LHUT32というフリーソフトがエクスプローラへファイルをドロップできます。
これをSpyしてみては?

この回答への補足

LHUTではないですが、類似ソフトでの調査済みなので報告します。

受け側のエクスプローラ内のSysListView32内ではLVM_HITTESTは発生しているのですが、これはエクスプローラ本体が送っているメッセージ、あるいはWINDOWSそのものが送っているメッセージであって、アプリ側からLVM_HITTESTを送っているようには見えませんでした。

知り合いに相談した結果、「おそらくファイル名ではなく、"FileContents"でStreamを渡し・・・云々」というのですが、さっぱりです。

何か手は無いものでしょうか?

補足日時:2001/12/06 19:49
    • good
    • 0

↓に該当しませんか?



参考URL:http://support.microsoft.com/default.aspx?scid=k …

この回答への補足

英語が苦手なのでよく理解していませんが・・・

これはListViewのHITTESTですよね。
現在の方法で、ListViewのHITTESTは可能なのですが・・・

どうやらSysListView32へのHITTESTはちょっと違うようです。
フラグをセットする以前に、メッセージで送った構造体の各値と、受けている状態をスパイでデバッグした各値が違うのです。

最初に述べたように英語が苦手なので、意味不明な返答でしたらごめんなさい。
もし、参考URLが解決策を書いているのであれば、どのような内容か教えてください。

お願いいたします。

補足日時:2001/12/06 14:56
    • good
    • 0
この回答へのお礼

お礼ではなくさらに補足です。

デスクトップのクリック検出って、グローバルフックを使用しますよね?
だから、もしかしてフックしなくてはいけないのかな?

うーむ、行き詰まってます・・・

お礼日時:2001/12/06 17:40

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

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

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

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

Qクラスのインスタンス名をクラス内で取得できますか?

クラスのインスタンス名をクラス内で取得できますか?

今VC++6.0を使っています。例として下記のクラスのコンストラクタで
CTest::CTest() { TRACE("%s",typeid(this).name()); }
としておいて、
別なクラスで CTest testInst; を生成すると
デバッグエリアに 「class CTest *」 と表示することはできました。
これが出来るのなら、インスタンス名 testInst をCTestクラスの内部から
取得することは出来ないのかと思ったのですが、
取得することは可能なのでしょうか?

Aベストアンサー

オブジェクトの定義時に、名前をコンストラクタに渡すようなマクロでも作れば実現できなくもないのかもしれませんが、一般的には無理です。
また、そもそも名前のないオブジェクト、例えば、newで割り付けたオブエジェクトや一時オブジェクトはどうするのでしょうか?

QWin32APIにて、ウィンドウ全体をドラッグして動かしたいのですが。

こんにちは。
いつもお世話になっております。

小生、只今WindowsXPSP3上で、C言語とWin32APIを使用し、BCC5.5.1でコンパイルしながら、Windowsプログラミングを勉強しています。

度々、質問させて頂き、その都度回答を頂戴し、誠に恐縮ではあるのですが、今回も質問させて下さい。

下記のコードをコンパイルすると、タイトルバーをドラッグして移動する事は出来るのですが、ウィンドウ全体(クライアント領域も含めて)移動するにはどのようにすればいいのでしょうか??

/* ウィンドウ表示 */
#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE, LPCSTR);
BOOL InitInstance(HINSTANCE, int, LPCSTR);

int WINAPI WinMain(
HINSTANCE hCurInst,
HINSTANCE hPrevInst,
LPSTR lpsCmdLine,
int nCmdShow)
{
MSG msg;
BOOL bRet;
LPCSTR szClassName = "Window";

if(!InitApp(hCurInst, szClassName)){
return FALSE;
}

if(!InitInstance(hCurInst, nCmdShow, szClassName)){
return FALSE;
}

while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0){
if(bRet == -1){
MessageBox(NULL, "GetMessage Error", "Error", MB_OK);
break;
}
else{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int)msg.wParam;
}

//ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst, LPCSTR szClassName)
{
WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(
NULL,
MAKEINTRESOURCE(IDC_ARROW),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCSTR)szClassName;
wc.hIconSm = (HICON)LoadImage(
NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);

return (RegisterClassEx(&wc));
}

//ウィンドウの生成
BOOL InitInstance(HINSTANCE hInst, int nCmdShow, LPCSTR szClassName)
{
HWND hWnd;

hWnd = CreateWindow(
szClassName,
"Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
200,
200,
NULL,
NULL,
hInst,
NULL);

if(!hWnd){
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}

//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch(msg){
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}

return 0;
}

お忙しい中申し訳ございませんが、
先輩方、アドバイス宜しくお願い致します。

こんにちは。
いつもお世話になっております。

小生、只今WindowsXPSP3上で、C言語とWin32APIを使用し、BCC5.5.1でコンパイルしながら、Windowsプログラミングを勉強しています。

度々、質問させて頂き、その都度回答を頂戴し、誠に恐縮ではあるのですが、今回も質問させて下さい。

下記のコードをコンパイルすると、タイトルバーをドラッグして移動する事は出来るのですが、ウィンドウ全体(クライアント領域も含めて)移動するにはどのようにすればいいのでしょうか??

/* ウィンドウ表示 */
#incl...続きを読む

Aベストアンサー

#3です。

すみません。#3で紹介したサイトの情報を良く見ていませんでした。

#3のコードだと、クライアント領域上でダブルクリックすると、「最大化」、または、
「元のサイズに戻す」の動作が実行されてしまいますね。
(これはこれで、面白い動作ですが。。。)

ですので、これで支障がある場合は、同サイトの【方法2】の方法を採った方が、
良いと思います。

以下は、【方法2】のコード例です。
ウィンドウプロシージャ「WndProc」の部分のみ掲載致します。

■改造ソース(その2)
注)インデント等のため、全角スペースを入れています。
  ご使用の際は、半角スペースorタブに置換して下さい。

/////↓ここから///////////////////////////////////
//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
//  UINT nRes;

  //メッセージ処理
  switch(msg)
  {
//////こちらは使用しない///////////
//  //マウス移動のメッセージ処理
//  case WM_NCHITTEST:
//    //クライアント領域だった場合は、タイトルバー上での動作と
//    //同じ動作を行わせる
//    nRes = DefWindowProc(hWnd, msg, wp, lp);
//    if (nRes == HTCLIENT) nRes = HTCAPTION;
//    return nRes;
////////////////////////////////

  //マウスの左ボタン押下時の処理
  case WM_LBUTTONDOWN:
    //クライアント領域だった場合でも、タイトルバーでクリック
    //されたことにしてメッセージ送信
    PostMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lp);
    break;

  //プログラム終了時のウインドウ破棄
  case WM_DESTROY:
    PostQuitMessage(0);
    break;

  default:
    return (DefWindowProc(hWnd, msg, wp, lp));
  }

  return 0;
}
/////↑ここまで///////////////////////////////////

以上です。

#3です。

すみません。#3で紹介したサイトの情報を良く見ていませんでした。

#3のコードだと、クライアント領域上でダブルクリックすると、「最大化」、または、
「元のサイズに戻す」の動作が実行されてしまいますね。
(これはこれで、面白い動作ですが。。。)

ですので、これで支障がある場合は、同サイトの【方法2】の方法を採った方が、
良いと思います。

以下は、【方法2】のコード例です。
ウィンドウプロシージャ「WndProc」の部分のみ掲載致します。

■改造ソース(その2)
注)...続きを読む

Q親フォルダのIShellFolderインターフェースとアイテムIDの取得方法

SHBindToParent()関数でアイテムIDリストから親フォルダなどが取得できると
MSDNで知り、ヘッダーファイル(shobj.h)とライブラリファイル(shell32.lib)を
インクルードさせてみたのですが、関数が定義されていませんというメッセージが
表示されて使えません。
使用環境は以下のとおりです。
   VC++6.0(SP5)
   Windows2000(SP2)
   SHELL32.DLL(5.00.3315.2902)

特別な設定をしないと(または、設定がなされてないと)使えないのでしょうか?
何方かご教授よろしくお願いします。

Aベストアンサー

>現在、合計342MBのファイルをDL中なのですが、UpdateしたSDKを用いて作成した
>アプリケーションでも別のパソコンで問題なく実行できるのでしょうか?

該当のバージョンのDLLがインストールされていれば動作します。


>あと、LoadLibrary、GetProcAddress関数の使い方なのですが、下記コードだと
>パラメータ数に問題があるということでコンパイルができません。

FARPROCで関数ポインタを宣言しているためです。
VC++6.0ではSTRICTがデフォルトで定義されているので、
明示的に正しい関数の型宣言を定義しなければいけません

//関数型の宣言(ヘッダに記述するのが普通)
typedef HRESULT (WINAPI* SHBINDTOPARENT)
(
LPCITEMIDLIST pidl,
REFIID riid,
VOID** ppv,
LPCITEMIDLIST* ppidlLast
);


//GetProcAddressの行を下のように変更
SHBINDTOPARENT lpDll = (SHBINDTOPARENT)GetProcAddress(hLib,"SHBindToParent");

>現在、合計342MBのファイルをDL中なのですが、UpdateしたSDKを用いて作成した
>アプリケーションでも別のパソコンで問題なく実行できるのでしょうか?

該当のバージョンのDLLがインストールされていれば動作します。


>あと、LoadLibrary、GetProcAddress関数の使い方なのですが、下記コードだと
>パラメータ数に問題があるということでコンパイルができません。

FARPROCで関数ポインタを宣言しているためです。
VC++6.0ではSTRICTがデフォルトで定義されているので、
明示的に正しい関数の型...続きを読む

Qドラッグしたときにマウスカーソルを変更するには?

こんにちは。
VC6.0 MFCで開発しています。

マウスカーソルの形状をウィンドウをドラッグしているときとしていないときで
違ったものに変更したいのですが、うまくいきません。

ソースはこんなふうにしています。


void CTest::OnLButtonDown(UINT nFlags, CPoint point)
{
//変更する
SetCursor(AfxGetApp()->LoadCursor( IDC_CUR2 ));

CDialog::OnLButtonDown(nFlags, point);
}

void CTest::OnLButtonUp(UINT nFlags, CPoint point)
{
//元に戻す
SetCursor(AfxGetApp()->LoadCursor( IDC_CUR1 ));

CDialog::OnLButtonUp(nFlags, point);
}

どうぞ宜しくお願いします。

Aベストアンサー

「OnLButtonDown」や「OnLButtonUp」ではなくて、「OnMouseMove」だとうまくいきましたよ。
--------------------------------------------------------------
void CTestDlg::OnMouseMove(UINT nFlags, CPoint point)
{
if(nFlags==MK_LBUTTON)
{
// カーソルファイルを読む込む場合
SetCursor(AfxGetApp()->LoadCursor( IDC_CURSOR1 ));
}

CDialog::OnMouseMove(nFlags, point);
}
--------------------------------------------------------------
ちなみに、Windows標準のカーソルの場合はこうです。
 SetCursor(AfxGetApp()->LoadStandardCursor(IDC_WAIT));

では。

「OnLButtonDown」や「OnLButtonUp」ではなくて、「OnMouseMove」だとうまくいきましたよ。
--------------------------------------------------------------
void CTestDlg::OnMouseMove(UINT nFlags, CPoint point)
{
if(nFlags==MK_LBUTTON)
{
// カーソルファイルを読む込む場合
SetCursor(AfxGetApp()->LoadCursor( IDC_CURSOR1 ));
}

CDialog::OnMouseMove(nFlags, point);
}
--------------------------------------------------------------
ちなみに、...続きを読む

Qクラス内のクラスから1つ目のクラスのメソッドよ呼び出しがうまくいきません^^;

こんにちは、ちょっと分かりにくい質問なんですが。

class c1
{
  int k1();

  class c2
  {
    int k2();
  };
};

と言うのがあったとします。
そこで、k2の関数の内部でk1を呼び出したいのですが、

int k2()
{
  return c1::k1();
}

見たいな事をすると、「静的でない関数の呼び出しが正しくありません」とエラーが出てしまい、コンパイルできません・・・

だからといってk1をc1の外に出してしまうとc1の変数にアクセスできなくなってしまうため、それはできません。

何かいい方法はないでしょうか・・・解決策をお待ちしていますm(_ _)m

Aベストアンサー

クラスの設計がちょっと駄目です。
c2からc1::k1にアクセスしたいなら、
c2がc1のポインタを持つか、k1をstaticメンバにします。
ちなみにstaticメンバはCの関数と同じただの関数でメンバ変数にアクセスできません。
またこの場合c2を内包する意味がありません。
class c1
{
  int k1();
  int k2();
};
でいいのです。

return c1::k1();
これが何故だめか、ですが
c1は実体がありません。その為staticメンバ(静的な関数)である必要があるのです。

class c1
{
  static int k1();
  class c2
  {
    int k2();
  };
};
int c1::k1()
{
return 0;
}
int c1::c2::k2()
{
  return c1::k1();
}

一応これでコンパイルは通りますが。


人気Q&Aランキング

おすすめ情報