1

我正在为 Windows 资源管理器实现一个 shell 上下文菜单,并成功创建了菜单。我遇到的问题是 IContextMenu::GetCommandString 方法,当您将鼠标悬停在所选菜单项上时,该方法会在状态栏中显示帮助文本。

当我将鼠标悬停在每个项目上时,什么都没有显示,但奇怪的是我没有创建的其他一些项目,例如 - 打开或打印,它们的帮助文本变成了垃圾。

这是 IContextMenu::QueryContextMenu & IContextMenu::GetCommandString 的代码示例。

int ShellExtLib.IContextMenu.QueryContextMenu(IntPtr hMenu, uint indexMenu, uint idCmdFirst, uint idCmdLast, uint uFlags)
{
    uint idCmd = idCmdFirst;
    StringBuilder sb = new StringBuilder(1024);

    try
    {
        if ((uFlags & 0xf) == 0 || (uFlags & (uint)ShellExtLib.CMF.CMF_EXPLORE) != 0)
        {
            uint selectedFileCount = Helpers.DragQueryFile(m_hDrop, 0xffffffff, null, 0);

            if (selectedFileCount == 1)
            {
                Helpers.DragQueryFile(m_hDrop, 0, sb, sb.Capacity + 1);
                Documents.Add(sb.ToString());
            }
            else
            {
                // MULTIPLE FILES SELECTED.
                for (uint i = 0; i < selectedFileCount; i++)
                {
                    Helpers.DragQueryFile(m_hDrop, i, sb, sb.Capacity + 1);
                    Documents.Add(sb.ToString());
                }
            }

            Helpers.InsertMenu(hMenu, indexMenu++, ShellExtLib.UFLAGS.MF_SEPARATOR | ShellExtLib.UFLAGS.MF_BYPOSITION, 0, null);

            IntPtr hSubMenu = Helpers.CreateMenu();
            if (hSubMenu != IntPtr.Zero)
            {
                Helpers.InsertMenu(hSubMenu, 0, ShellExtLib.UFLAGS.MF_STRING | ShellExtLib.UFLAGS.MF_BYPOSITION, idCmd++, "Item 1");
                Helpers.InsertMenu(hSubMenu, 1, ShellExtLib.UFLAGS.MF_STRING | ShellExtLib.UFLAGS.MF_BYPOSITION, idCmd++, "Item 2");
                Helpers.InsertMenu(hSubMenu, 2, ShellExtLib.UFLAGS.MF_SEPARATOR | ShellExtLib.UFLAGS.MF_BYPOSITION, idCmd++, null);
                Helpers.InsertMenu(hSubMenu, 3, ShellExtLib.UFLAGS.MF_STRING | ShellExtLib.UFLAGS.MF_BYPOSITION, idCmd++, "Item 3");
                Helpers.InsertMenu(hSubMenu, 4, ShellExtLib.UFLAGS.MF_SEPARATOR | ShellExtLib.UFLAGS.MF_BYPOSITION, idCmd++, null);
                Helpers.InsertMenu(hSubMenu, 5, ShellExtLib.UFLAGS.MF_STRING | ShellExtLib.UFLAGS.MF_BYPOSITION, idCmd++, "Item 4");
                Helpers.InsertMenu(hSubMenu, 6, ShellExtLib.UFLAGS.MF_STRING | ShellExtLib.UFLAGS.MF_BYPOSITION, idCmd++, "Item 5");
            }

            Helpers.InsertMenu(hMenu, indexMenu++, ShellExtLib.UFLAGS.MF_STRING | ShellExtLib.UFLAGS.MF_BYPOSITION | ShellExtLib.UFLAGS.MF_POPUP, (uint)hSubMenu, "Main Menu");

            Helpers.InsertMenu(hMenu, indexMenu++, ShellExtLib.UFLAGS.MF_SEPARATOR | ShellExtLib.UFLAGS.MF_BYPOSITION, 0, null);

            return (int)(idCmd - idCmdFirst);
        }
    }
    catch { }

    return 0;
}



void ShellExtLib.IContextMenu.GetCommandString(int idCmd, uint uFlags, int pwReserved, StringBuilder commandString, int cchMax)
    {
        switch (uFlags)
        {
            case (uint)ShellExtLib.GCS.VERB:
                commandString = new StringBuilder("x");
                break;

            case (uint)ShellExtLib.GCS.HELPTEXTA:
                commandString = new StringBuilder("y");
                break;
        }
    }

有没有人有什么建议?我已经阅读了许多关于如何构建 shell 扩展的文章,并且也一直在阅读 MSDN。

谢谢。

4

2 回答 2

1

您的 GetCommandString 声明不正确 - GetCommandString 将其自己的缓冲区传递到您应该复制字符串的位置。在这种情况下,我认为您不能将其声明为 StringBuilder 。将其声明为 IntPtr,然后使用 Encoding.Unicode.GetBytes 和 Marshal.Copy 将您的字符串复制到缓冲区 - 确保添加空终止符。

于 2010-03-20T05:40:46.427 回答
1

为了准确起见,您还需要验证GetCommandString 标志。即使 pszName 被声明为 LPSTR,也要检查 GCS_... 常量是 A (ansi) 还是 W (unicode)。
例如,如果 uFlags 是 GCS_VERBA,则 pszName 是 LPSTR (char*),您需要从 ANSI 字符串中传递复制 cch 字符。
如果 uFlags 是 GCS_VERBW,则 pszName 是 LPWSTR 类型 (wchar_t*)(即使声明为 LPSTR),您需要从 Unicode 字符串中复制 cch 字符。
我不记得这里的文档对于 cchMax 是否正确(可能是字节数而不是字符数)。

于 2015-05-15T13:38:19.267 回答