我使用C#和Windows API中的IContextMenu接口和IShellExtInit接口,在Windows XP的资源管理器中,为所有类型的文件和目录添加了一个简单的菜单项 “Hoo Command Shell"。这个菜单项在绝大部分类型的文件与目录上都显示正常。唯独在zip文件上出现问题:原有的“Open with Winzip”,“Explorer"和“Print”三项不见了;
TortoiseSVN及其子菜单项的文本标题变成了空白;
倒是“Hoo Command Shell“能正常显示。恳请高手们指点迷津啊!主类代码如下:
[Guid("24E4E314-AEE1-4906-8CE6-DA49D60E4D29")]
public class CommandContextMenu : IShellExtInit, IContextMenu {
protected static readonly string guid = "{" + typeof(CommandContextMenu).GUID.ToString() + "}";
protected uint hDrop = 0; int IContextMenu.QueryContextMenu(uint hMenu, uint iMenu, int idCmdFirst, int idCmdLast, uint uFlags) {
// Create the popup to insert
uint handleMenuPopup = Win32Helpers.CreatePopupMenu();  int id = 1;
if ((uFlags & 0xf) == 0 || (uFlags & (uint)CMF.CMF_EXPLORE) != 0) {
uint count = Win32Helpers.DragQueryFile(hDrop, 0xffffffff, null, 0);
if (count == 0xffffffff) {
//No file selected.

} else if (count >= 1) {
StringBuilder sb = new StringBuilder(1024);
Win32Helpers.DragQueryFile(hDrop, 0, sb, sb.Capacity + 1);
string path = sb.ToString();

//Set current directory base on first selection
//If the first selection is a file, set its parent directory as current directory.
//If the first selection is a folder, set it as current directory.
if (Directory.Exists(path)) {
Directory.SetCurrentDirectory(path);
} else {
Directory.SetCurrentDirectory(Path.GetDirectoryName(path));
}
}

id = idCmdFirst + id;
MENUITEMINFO menuItemInfo = new MENUITEMINFO();
menuItemInfo.cbSize = 48;
menuItemInfo.fMask = (uint)MIIM.ID | (uint)MIIM.TYPE | (uint)MIIM.STATE;
menuItemInfo.wID = id;
menuItemInfo.fType = (uint)MF.STRING;
menuItemInfo.dwTypeData = "Hoo Command Shell";
menuItemInfo.fState = (uint)MF.ENABLED;
Win32Helpers.InsertMenuItem(hMenu, (uint)iMenu, 1, ref menuItemInfo);
}
Logger.Info(string.Format("Menu ID: {0}", id));
return id;
}
 
void IContextMenu.GetCommandString(int idCmd, uint uFlags, int pwReserved, StringBuilder commandString, int cchMax) {
switch (uFlags) {
case (uint)GCS.VERB:
commandString = new StringBuilder("...");
break;
case (uint)GCS.HELPTEXT:
commandString = new StringBuilder("...");
break;
}
} void IContextMenu.InvokeCommand(IntPtr pici) {
Logger.Info("Inside InvokeCommand()");
try {
Type commandType = typeof(INVOKECOMMANDINFO);
INVOKECOMMANDINFO ici = (INVOKECOMMANDINFO)Marshal.PtrToStructure(pici, commandType);
switch (ici.verb - 1) {
case 0:
OpenCommandShell();
break;
default:
break;
}
} catch (Exception ex) {
}
} private void OpenCommandShell() {            
Process p = new Process();    
p.StartInfo.FileName = "cmd.exe";           
p.StartInfo.Arguments = "/k pushd " + Directory.GetCurrentDirectory();
p.Start();       
} int IShellExtInit.Initialize(IntPtr pidlFolder, IntPtr lpdobj, uint hKeyProgID) {
try {
StringBuilder folderPath = new StringBuilder(1024);
if (pidlFolder != IntPtr.Zero) {
if (Win32Helpers.SHGetPathFromIDListW(pidlFolder, folderPath)) {
string currentDirectory = folderPath.ToString();
Directory.SetCurrentDirectory(currentDirectory);
Logger.Info("Current folder: " + currentDirectory);
} else {
Logger.Info("Could not convert PIDL " + pidlFolder);
}
} if (lpdobj != (IntPtr)0) {
// Get info about the directory
IDataObject dataObject = (IDataObject)Marshal.GetObjectForIUnknown(lpdobj);
FORMATETC fmt = new FORMATETC();
fmt.cfFormat = CLIPFORMAT.CF_HDROP;
fmt.ptd = 0;
fmt.dwAspect = DVASPECT.DVASPECT_CONTENT;
fmt.lindex = -1;
fmt.tymed = TYMED.TYMED_HGLOBAL;
STGMEDIUM medium = new STGMEDIUM();
dataObject.GetData(ref fmt, ref medium);
hDrop = medium.hGlobal;
}
} catch (Exception) {
}
return 0;
} [System.Runtime.InteropServices.ComRegisterFunctionAttribute()]
static void RegisterServer(String str1) {
try {
Logger.Info("Register assembly: " + guid);
// For Winnt set me as an approved shellex
RegistryKey root;
RegistryKey rk;
root = Registry.LocalMachine;
rk = root.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", true);
rk.SetValue(guid, "Hoo Command Shell");
rk.Close(); //Register for all files
root = Registry.ClassesRoot;
rk = root.OpenSubKey(@"*\shellex\ContextMenuHandlers\Hoo Windows Shell", true);
if (rk == null)
rk = root.CreateSubKey(@"*\shellex\ContextMenuHandlers\Hoo Windows Shell");
rk.SetValue("", guid);
rk.Close(); //Register for directory
rk = root.OpenSubKey(@"Directory\shellex\ContextMenuHandlers\Hoo Windows Shell", true);
if (rk == null)
rk = root.CreateSubKey(@"Directory\shellex\ContextMenuHandlers\Hoo Windows Shell");
rk.SetValue("", guid);
rk.Close(); //Register for directory background
rk = root.OpenSubKey(@"Directory\Background\shellex\ContextMenuHandlers\Hoo Windows Shell", true);
if (rk == null)
rk = root.CreateSubKey(@"Directory\Background\shellex\ContextMenuHandlers\Hoo Windows Shell");
rk.SetValue("", guid);
rk.Close(); } catch (Exception e) {
System.Console.WriteLine(e.ToString());
}
} [System.Runtime.InteropServices.ComUnregisterFunctionAttribute()]
static void UnregisterServer(String str1) {
try {
RegistryKey root;
RegistryKey rk; // Remove ShellExtenstions registration
root = Registry.LocalMachine;
rk = root.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved", true);
rk.DeleteValue(guid);
rk.Close(); // Delete  regkey
root = Registry.ClassesRoot;
root.DeleteSubKey(@"*\shellex\ContextMenuHandlers\Hoo Windows Shell", false);
root.DeleteSubKey(@"Directory\shellex\ContextMenuHandlers\Hoo Windows Shell", false);
root.DeleteSubKey(@"Directory\Background\shellex\ContextMenuHandlers\Hoo Windows Shell", false);
} catch (Exception e) {
System.Console.WriteLine(e.ToString());
}
}
}
 

解决方案 »

  1.   

    It has nothing to do with C#. I suggest you ask in a shell programming newsgroup.
      

  2.   

    CSDN里可没有shell programming newsgroup, 难道要我到C++版去问?
      

  3.   

    唉,不知是MSDN上的人气太火爆了,还是我这儿上网有问题,在它的newsgroup上发了几次都没有成功。
    不过我的问题已经解决了。
    原因是理解错了QueryContextMenu的返回值和id变量的意义。不应当写id = idCmdFirst + id;