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

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

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

Re[4]: C#からエクスプローラーのコンテキストメニューを表示させたい


(過去ログ 97 を表示中)

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

■57758 / inTopicNo.1)  C#からエクスプローラーのコンテキストメニューを表示させたい
  
□投稿者/ naiasin (1回)-(2011/03/13(Sun) 21:06:51)

分類:[C#] 

2011/03/13(Sun) 21:09:58 編集(投稿者)
(複数選択できなかったため分類はC#とさせていただいていますが、C++/CLIも利用しています。)

OS:Windows XP SP3
開発環境:Visual C# 2010 Express, Visual C++ 2010 Express

C#のフォームアプリケーションでエクスプローラー的なものを作成しようとしています。

ファイル/フォルダ名の右クリック押下でエクスプローラーの右クリックメニューと同様の
メニューを表示させようとしているのですが、エラーにより停止してしまいます。
以下に、作成したコンテキストメニュー表示のためのコードの一部抜粋を記載します。

○ C#コード

// .NET Framework のListViewを継承したクラスの定義
class ListView : System.Windows.Forms.ListView
{
        // 右クリックメニュー押下時に呼ばれる
        private void ShowContextMenu()
        {
                // C++/CLI で定義しているインスタンスを生成
                var contextMenu = new ContextMenu();

                // Handleプロパティ、ファイルパス文字列を引数にメンバ関数呼び出し
                contextMenu.show(Handle, /* ファイルパス */);
        }
}

○ C++/CLI コード

void ContextMenu::show(IntPtr handleOwner, String^ contentPath)
{
        // マネージ文字列からアンマネージ文字列に変換
        char* path = (char*)(void*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(contentPath);

        // IntPtrからHWNDに変換して下記メソッド呼び出し
        show(reinterpret_cast<HWND>(handleOwner.ToPointer()), path);

        System::Runtime::InteropServices::Marshal::FreeHGlobal((IntPtr)path);
}

int ContextMenu::show(HWND windowHandle, char* filePath)
{
        // メニューを作成
        HMENU menu = ::CreatePopupMenu();

        // デスクトップフォルダのインターフェースを取得
        IShellFolder* desktopFolder;
        ::SHGetDesktopFolder(&desktopFolder);

        // ファイルパスを元にアイテムIDリストを取得
        // (自作メソッドですが、詳細は省略します。)
        LPCITEMIDLIST itemIdList = GetItemIDList(filePath);
        
        // コンテキストメニューのインターフェースを取得
        LPCONTEXTMENU contextMenu;
        HRESULT hRes = desktopFolder->GetUIObjectOf(windowHandle, 1, (LPCITEMIDLIST *)&itemIdList
                , IID_IContextMenu, 0, (LPVOID *)&contextMenu );
        
        if( hRes != NOERROR ) 
                return FALSE;

        // メニューにメニュー項目を追加
        hRes = contextMenu->QueryContextMenu( menu, 0, 1, 0xffff, CMF_NORMAL );
        if( hRes == NULL )
                goto CleanUp;

        // メニューを表示
        // !! エラー発生 !!
        int iCommand;
        iCommand = ::TrackPopupMenu( menu
                        , TPM_LEFTALIGN | TPM_BOTTOMALIGN  | TPM_RETURNCMD | TPM_LEFTBUTTON
                        , 0, 0, 0, windowHandle, NULL );

        // 以下省略
        
        ・・・

}

上記コードをVisual Studio でデバッグ実行しますと

以下のような内容のウィンドウが表示され、::TrackPopupMenu 関数内で停止してしまいます。

・タイトル:FatalExecutionEngineErrorが検出されました。
・メッセージ内容:
  "ランタイムの重大なエラーが発生しました。エラーのアドレスは 0x792d884c、スレッド 0xe58 です。エラー コードは 0xc0000005 です。
  これは CLR のバグであるか、またはユーザー コードのアンセーフまたは確認不可能な部分にバグがある可能性があります。
  このバグの一般的な原因には、スタックが壊れる可能性のある COM-interop または PInvoke のユーザー マーシャリング エラーが含まれています。"

TrackPopupMenu 呼び出しの直前で
・第一引数 menu には、::CreatePopupMenu 関数の戻り値が格納されていること
・第六引数 windowHandle には、C#側のListView.Handleと同じ値が格納されていること
は確認したのですが、何が原因なのかわかりません。

原因について何かお分かりになる方いらっしゃいましたら、教えていただけませんでしょうか?

引用返信 編集キー/
■57759 / inTopicNo.2)  Re[1]: C#からエクスプローラーのコンテキストメニューを表示させたい
□投稿者/ Azulean (704回)-(2011/03/14(Mon) 06:23:37)
ぱっとは原因を思いついていませんが、少し気になったところを。

No57758 (naiasin さん) に返信
> 以下のような内容のウィンドウが表示され、::TrackPopupMenu 関数内で停止してしまいます。

単に CreatePopupMenu して、TrackPopupMenu とした場合は問題ないのですよね?
(間のシェル関連のコードに問題があるかどうかの切り分け)

> // メニューにメニュー項目を追加
> hRes = contextMenu->QueryContextMenu( menu, 0, 1, 0xffff, CMF_NORMAL );
> if( hRes == NULL )
> goto CleanUp;

元のサンプルからのようですが、エラー判定を間違えています。
FAILED(hRes) で goto するようにしてください。エラー時は 0 を返しませんので。
(元のサンプル:http://www.kab-studio.biz/Programing/Codian/ShellExtension/07.html

念のためですが、この hRes は成功になっているのですよね?
(この時点でエラーになっていないとは思いますが…)
引用返信 編集キー/
■57770 / inTopicNo.3)  Re[2]: C#からエクスプローラーのコンテキストメニューを表示させたい
□投稿者/ naiasin (2回)-(2011/03/14(Mon) 23:48:33)
Azulean さん、ご回答いただきありがとうございました。

> 単に CreatePopupMenu して、TrackPopupMenu とした場合は問題ないのですよね?
> (間のシェル関連のコードに問題があるかどうかの切り分け)

おっしゃっていただいたように変更したところ、問題の現象は発生しませんでした。

> 元のサンプルからのようですが、エラー判定を間違えています。
> FAILED(hRes) で goto するようにしてください。エラー時は 0 を返しませんので。
> (元のサンプル:http://www.kab-studio.biz/Programing/Codian/ShellExtension/07.html

> 念のためですが、この hRes は成功になっているのですよね?
> (この時点でエラーになっていないとは思いますが…)

な、なぜ参考にさせていただいたサイトがお分かりになったのでしょうか。。。(汗)
エラー判定を FAILED(hRes) に変更し、goto文が実行されないことを確認しました。
(ちなみにhResの値は75でした)

もう少し問題の箇所を絞り込んでいきたいと思います。

引用返信 編集キー/
■57771 / inTopicNo.4)  Re[3]: C#からエクスプローラーのコンテキストメニューを表示させたい
□投稿者/ Azulean (705回)-(2011/03/15(Tue) 07:41:48)
No57770 (naiasin さん) に返信
> おっしゃっていただいたように変更したところ、問題の現象は発生しませんでした。

シェル関連コードの呼び出しが悪いか、メニューとして追加される項目が悪いかでしょうか。


> な、なぜ参考にさせていただいたサイトがお分かりになったのでしょうか。。。(汗)

情報を探していたときにほぼ同じコメント、コードのサイトを見つけたというのが実情です。
参考にして実験する間は構わないと思いますが、コピーベースでコードを書いた場合、著作権の問題が生じることもあります点、ご注意ください。


> もう少し問題の箇所を絞り込んでいきたいと思います。

たとえば、QueryContextMenu をコメントアウトすると発生しないのかとか、0xffff を 2 や 5 みたいに数を絞った場合に発生しないのかとか。
引用返信 編集キー/
■57889 / inTopicNo.5)  Re[4]: C#からエクスプローラーのコンテキストメニューを表示させたい
□投稿者/ naiasin (3回)-(2011/03/20(Sun) 19:10:08)
Azulean さん、ご回答いただきありがとうございました。
また、ご連絡が遅くなってしまい、申し訳ありませんでした。

>>な、なぜ参考にさせていただいたサイトがお分かりになったのでしょうか。。。(汗)
>
> 情報を探していたときにほぼ同じコメント、コードのサイトを見つけたというのが実情です。
> 参考にして実験する間は構わないと思いますが、コピーベースでコードを書いた場合、著作権の問題が生じることもあります点、ご注意ください。

そうでしたか。著作権に関しましては、頭に留めておきたいと思います。

> たとえば、QueryContextMenu をコメントアウトすると発生しないのかとか、0xffff を 2 や 5 みたいに数を絞った場合に発生しないのかとか。

コメントアウトすると発生しませんでした。
第四引数は色々値を変更してみましたが、結果は変わりませんでした。

ただ、ロジックを変更しなくてもごく稀にそれらしきメニューが表示されたこともありました。

一通り各APIに渡す引数を見直して、怪しそうなところは変えてみたりしましたが、成果なしでした。

こちらの時間の都合で申し訳ありませんが、ひとまずあきらめたいと思います。

Azulean さん、ご協力いただきありがとうございました。

引用返信 編集キー/


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

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -