1

作業中の小さなアプリケーション用に、非常に基本的なシェル拡張機能を開発しました。しばらく問題なく使用していますが、Windows XPの[スタート]メニュー->[すべてのプログラム]で、フォルダを右クリックして[開く]または[探索]を選択すると、エクスプローラウィンドウの代わりに小さなアプリケーションが表示されます。これを見たとき、私がどれほど幸せで誇りに思っていたか想像できます。これが起こる唯一の場所なので、私はそれが奇妙だと思います(これまでのところ...)。シェル拡張機能を「ディレクトリ」レジストリキーで登録したので、フォルダを右クリックしたときにのみ表示されます。

私はシェル拡張に関するいくつかの良い記事を見つけました、そして私はそれらでこれまでにそれを作りました、しかし私はこのwinapiのもので私の快適なゾーンのどこにも近くありません。IDをいじくりまわしましたが、何が問題なのかわかりません。

これが私のquerycontextmenuの実装であり、C++の第一人者がすぐに見つけられるというばかげた間違いをしたことを願っています。どんな助けでもありがたいです。

STDMETHODIMP ShellExtension::QueryContextMenu(HMENU hMenu,  UINT indexMenu,  UINT idCmdFirst,  UINT idCmdLast, UINT uFlags){
if (CMF_DEFAULTONLY & uFlags)
{
    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
}

UINT uID = idCmdFirst;

if (!InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL))
{
    return HRESULT_FROM_WIN32(GetLastError());
}

HMENU hSubmenu = CreatePopupMenu();

InsertMenu (hSubmenu, 0, MF_BYPOSITION, uID++, (this->isFrench ? SET_REF_TEXT : SET_REF_TEXT_EN));
InsertMenu (hSubmenu, 1, MF_BYPOSITION, uID++, (this->isFrench ? SET_COMP_TEXT : SET_COMP_TEXT_EN));

MENUITEMINFO mii = { sizeof(mii) };
mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_BITMAP | MIIM_SUBMENU | MIIM_DATA | MIIM_STRING;
mii.hSubMenu = hSubmenu;
mii.fType = MFT_STRING;
mii.dwTypeData = (this->isFrench ? MAIN_TEXT : MAIN_TEXT_EN);
mii.hbmpItem = IsRequirePainting() ? HBMMENU_CALLBACK : m_hMenuBmp;
mii.wID = uID++;

if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii))
{
    return HRESULT_FROM_WIN32(GetLastError());
}

if (!InsertMenu(hMenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL))
{
    return HRESULT_FROM_WIN32(GetLastError());
}

return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uID - idCmdFirst);}

ありがとう!

編集:

これは私のために働いた解決策です...ここでつまずいた人のために:

STDMETHODIMP ShellExtension::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
    if (!HIWORD(lpcmi->lpVerb))
    {
        UINT idCmd = LOWORD(lpcmi->lpVerb);

        switch (idCmd)
        {
        case 0:
            doStuffForFirstCommand();
            break;
        case 1:
            doStuffForSecondCommand();
            break;
        }

        return S_OK;
    }
    else
    {
        return E_INVALIDARG; //this is what I forgot...
    }
}

ヘルプに感謝し、コードのインデントをお詫びします。コードタグがわからないようです。

4

1 に答える 1

3

上記の議論を真の答えに要約します。

直接のユーザーアクションによって呼び出されることに加えて、コンテキストメニュー拡張機能は他のいくつかの方法で呼び出すことができます。ユーザーがWindowsエクスプローラーでアイテムを右クリックするときに、「開く」や「印刷」などのシェルの組み込み動詞の1つを選択すると、Windowsは、登録されている各シェル拡張機能を順番に照会して、それを処理するものを見つけます。ShellExecuteユーザーがプログラムで動詞を呼び出すために呼び出した場合も同じことが起こります。

これにより、サードパーティの開発者はシェルの語彙に新しい動詞を追加できますが、シェル拡張機能がこのケースを処理しない場合にも問題が発生します。

この問題は、コンテキストメニューハンドラーのInvokeCommandメソッドがそのパラメーターをチェックしない場合に発生します。CMINVOKECOMMANDINFOメンバーについてのドキュメントの内容は次のlpVerbとおりです(私の強調):

上位ワードがゼロでない場合、このメンバーは、実行するコマンドの言語に依存しない名前を指定するnullで終了する文字列のアドレスです。このメンバーは通常、コマンドがアプリケーションによってアクティブ化されているときの文字列です。システムは、次のコマンド文字列に対して事前定義された定数値を提供します。

これは固定セットではありません。新しい正規動詞は、コンテキストメニューハンドラーによって発明でき、アプリケーションはそれらを呼び出すことができます。

正規の動詞が存在し、メニューハンドラーが正規の動詞を実装していない場合、次のハンドラーがこの動詞を処理できるようにするには、失敗コードを返す必要があります。これを行わないと、を含むシステムの機能が損なわれますShellExecute

Raymond Chen's blog post "Sure, we do that: Context menu edition" describes the kind of things that can happen in this situation. He also points the unfortunate truth that enough shell extensions exhibit this impolite behavior that the Windows team has created a special registry key to help deal with these bugs.

Of course, if you're the developer, you should be sure to check the parameters of InvokeCommand and return the proper code rather than relying on the registry workaround.

于 2012-07-12T14:17:31.313 に答える