IContextMenu::GetCommandString 不在 Windows 资源管理器中显示帮助文本
我正在为 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。
谢谢。
i am implementing a shell context menu for windows explorer and have successfully created the menu's. What i am having trouble with is the IContextMenu::GetCommandString method that displays the help text in the status bar when you hover over the selected menu item.
When i do hover over each item nothing is displayed, but whats weird is that some of the other items that i didnt create, eg - open, or print have had their help text turned into garbage..
Here is a code sample of 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;
}
}
Does anyone have any suggestions? I have read a number of articles on how to build shell extensions and have also been reading MSDN as well..
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的 GetCommandString 声明不正确 - GetCommandString 传递其自己的缓冲区,您应该在其中复制字符串。我认为在这种情况下你不能将其声明为 StringBuilder 。将其声明为 IntPtr,然后使用 Encoding.Unicode.GetBytes 和 Marshal.Copy 将字符串复制到缓冲区 - 确保添加空终止符。
Your declaration of GetCommandString is incorrect - GetCommandString passes its own buffer where you are supposed to copy the string. I don't think you can declare it as StringBuilder in this case. Declare it as IntPtr and then use Encoding.Unicode.GetBytes and Marshal.Copy to copy your string to the buffer - be sure to add the null terminator.
为了准确起见,您还需要验证 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 文档是否正确(可能是字节数而不是字符数)。
To be accurate, you need to verify also the GetCommandString flags. Even if the pszName is declared as LPSTR, check if the GCS_... constants are A (ansi) or W (unicode).
If, for example, uFlags is GCS_VERBA, then pszName is a LPSTR (char*) and you need to pass copy cch characters from an ANSI string.
If uFlags is GCS_VERBW, then pszName is a LPWSTR type (wchar_t*) (even if declared as LPSTR) and you need to copy cch characters from an Unicode string.
I don't remember if the documentation is correct here for cchMax (might be a byte count and not a character count).