C++ Shell扩展DLL-如果用户在文件夹空白区域内单击,如何捕获文件夹路径?
使用shell扩展dll,如果用户在文件夹空白区域内单击,如何捕获文件夹路径 如果您正在实现一个shell扩展dll,那么您将获得方法中的路径作为pidlFolder参数C++ Shell扩展DLL-如果用户在文件夹空白区域内单击,如何捕获文件夹路径?,c++,windows,shell-extensions,C++,Windows,Shell Extensions,使用shell扩展dll,如果用户在文件夹空白区域内单击,如何捕获文件夹路径 如果您正在实现一个shell扩展dll,那么您将获得方法中的路径作为pidlFolder参数 为了确保扩展也注册了文件夹背景,您还必须在HKCR\Directory\Background\shellex\ContextMenuHandlers下创建相应的条目。如果您正在实现外壳扩展dll,则方法中的路径将作为pidlFolder参数 为了确保您的扩展名也注册了文件夹背景,您必须在HKCR\Directory\Backg
为了确保扩展也注册了文件夹背景,您还必须在HKCR\Directory\Background\shellex\ContextMenuHandlers下创建相应的条目。如果您正在实现外壳扩展dll,则方法中的路径将作为pidlFolder参数
为了确保您的扩展名也注册了文件夹背景,您必须在HKCR\Directory\Background\shellex\ContextMenuHandlers下创建相应的条目,使用VC++语言请参考Winmerge源代码 请参考这篇文章 并更新以下一些地方: 在FileContextMenuExt.cs文件中:
#region Shell Extension Registration
[ComRegisterFunction()]
public static void Register(Type t)
{
try
{
ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, "Directory",
"CSShellExtContextMenuHandler.FileContextMenuExt Class");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // Log the error
throw; // Re-throw the exception
}
}
[ComUnregisterFunction()]
public static void Unregister(Type t)
{
try
{
ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, "Directory");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // Log the error
throw; // Re-throw the exception
}
}
#endregion
...............
public void Initialize(IntPtr pidlFolder, IntPtr pDataObj, IntPtr hKeyProgID)
{
if (pDataObj == IntPtr.Zero && pidlFolder == IntPtr.Zero)
{
throw new ArgumentException();
}
FORMATETC fe = new FORMATETC();
fe.cfFormat = (short)CLIPFORMAT.CF_HDROP;
fe.ptd = IntPtr.Zero;
fe.dwAspect = DVASPECT.DVASPECT_CONTENT;
fe.lindex = -1;
fe.tymed = TYMED.TYMED_HGLOBAL;
STGMEDIUM stm = new STGMEDIUM();
try
{
if (pDataObj != IntPtr.Zero)
{
// The pDataObj pointer contains the objects being acted upon. In this
// example, we get an HDROP handle for enumerating the selected files
// and folders.
IDataObject dataObject = (IDataObject)Marshal.GetObjectForIUnknown(pDataObj);
dataObject.GetData(ref fe, out stm);
// Get an HDROP handle.
IntPtr hDrop = stm.unionmember;
if (hDrop == IntPtr.Zero)
{
throw new ArgumentException();
}
// Determine how many files are involved in this operation.
uint nFiles = NativeMethods.DragQueryFile(hDrop, UInt32.MaxValue, null, 0);
// This code sample displays the custom context menu item when only
// one file is selected.
if (nFiles == 1)
{
// Get the path of the file.
StringBuilder fileName = new StringBuilder(260);
if (0 == NativeMethods.DragQueryFile(hDrop, 0, fileName,
fileName.Capacity))
{
Marshal.ThrowExceptionForHR(WinError.E_FAIL);
}
this.selectedFile = fileName.ToString();
}
else
{
Marshal.ThrowExceptionForHR(WinError.E_FAIL);
}
}
if (pidlFolder != IntPtr.Zero) {
StringBuilder folderName = new StringBuilder(260);
if (0 == NativeMethods.SHGetPathFromIDList(pidlFolder, folderName))
{
Marshal.ThrowExceptionForHR(WinError.E_FAIL);
}
this.selectedFile = folderName.ToString();
}
}
finally
{
NativeMethods.ReleaseStgMedium(ref stm);
}
}
在ShellExtLib.cs文件中添加以下源:
[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, // Address of an item identifier list that
// specifies a file or directory location
// relative to the root of the namespace (the
// desktop).
StringBuilder pszPath); // Address of a buffer to receive the file system
并在ShellExtLib.cs文件中更新RegisterShellExtContextMenuHandler和UnregisterShellExtContextMenuHandler函数
public static void RegisterShellExtContextMenuHandler(Guid clsid,
string fileType, string friendlyName)
{
if (clsid == Guid.Empty)
{
throw new ArgumentException("clsid must not be empty");
}
if (string.IsNullOrEmpty(fileType))
{
throw new ArgumentException("fileType must not be null or empty");
}
// If fileType starts with '.', try to read the default value of the
// HKCR\<File Type> key which contains the ProgID to which the file type
// is linked.
if (fileType.StartsWith("."))
{
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
{
if (key != null)
{
// If the key exists and its default value is not empty, use
// the ProgID as the file type.
string defaultVal = key.GetValue(null) as string;
if (!string.IsNullOrEmpty(defaultVal))
{
fileType = defaultVal;
}
}
}
}
else {
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName1 = string.Format(@"{0}\Background\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName1))
{
// Set the default value of the key.
if (key != null && !string.IsNullOrEmpty(friendlyName))
{
key.SetValue(null, friendlyName);
}
}
}
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName))
{
// Set the default value of the key.
if (key != null && !string.IsNullOrEmpty(friendlyName))
{
key.SetValue(null, friendlyName);
}
}
}
public static void UnregisterShellExtContextMenuHandler(Guid clsid,
string fileType)
{
if (clsid == null)
{
throw new ArgumentException("clsid must not be null");
}
if (string.IsNullOrEmpty(fileType))
{
throw new ArgumentException("fileType must not be null or empty");
}
// If fileType starts with '.', try to read the default value of the
// HKCR\<File Type> key which contains the ProgID to which the file type
// is linked.
if (fileType.StartsWith("."))
{
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
{
if (key != null)
{
// If the key exists and its default value is not empty, use
// the ProgID as the file type.
string defaultVal = key.GetValue(null) as string;
if (!string.IsNullOrEmpty(defaultVal))
{
fileType = defaultVal;
}
}
}
}
else {
// Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName1 = string.Format(@"{0}\Background\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
Registry.ClassesRoot.DeleteSubKeyTree(keyName1, false);
}
// Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
Registry.ClassesRoot.DeleteSubKeyTree(keyName, false);
}
使用VC++语言,请参考Winmerge源代码 请参考这篇文章 并更新以下一些地方: 在FileContextMenuExt.cs文件中:
#region Shell Extension Registration
[ComRegisterFunction()]
public static void Register(Type t)
{
try
{
ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, "Directory",
"CSShellExtContextMenuHandler.FileContextMenuExt Class");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // Log the error
throw; // Re-throw the exception
}
}
[ComUnregisterFunction()]
public static void Unregister(Type t)
{
try
{
ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, "Directory");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message); // Log the error
throw; // Re-throw the exception
}
}
#endregion
...............
public void Initialize(IntPtr pidlFolder, IntPtr pDataObj, IntPtr hKeyProgID)
{
if (pDataObj == IntPtr.Zero && pidlFolder == IntPtr.Zero)
{
throw new ArgumentException();
}
FORMATETC fe = new FORMATETC();
fe.cfFormat = (short)CLIPFORMAT.CF_HDROP;
fe.ptd = IntPtr.Zero;
fe.dwAspect = DVASPECT.DVASPECT_CONTENT;
fe.lindex = -1;
fe.tymed = TYMED.TYMED_HGLOBAL;
STGMEDIUM stm = new STGMEDIUM();
try
{
if (pDataObj != IntPtr.Zero)
{
// The pDataObj pointer contains the objects being acted upon. In this
// example, we get an HDROP handle for enumerating the selected files
// and folders.
IDataObject dataObject = (IDataObject)Marshal.GetObjectForIUnknown(pDataObj);
dataObject.GetData(ref fe, out stm);
// Get an HDROP handle.
IntPtr hDrop = stm.unionmember;
if (hDrop == IntPtr.Zero)
{
throw new ArgumentException();
}
// Determine how many files are involved in this operation.
uint nFiles = NativeMethods.DragQueryFile(hDrop, UInt32.MaxValue, null, 0);
// This code sample displays the custom context menu item when only
// one file is selected.
if (nFiles == 1)
{
// Get the path of the file.
StringBuilder fileName = new StringBuilder(260);
if (0 == NativeMethods.DragQueryFile(hDrop, 0, fileName,
fileName.Capacity))
{
Marshal.ThrowExceptionForHR(WinError.E_FAIL);
}
this.selectedFile = fileName.ToString();
}
else
{
Marshal.ThrowExceptionForHR(WinError.E_FAIL);
}
}
if (pidlFolder != IntPtr.Zero) {
StringBuilder folderName = new StringBuilder(260);
if (0 == NativeMethods.SHGetPathFromIDList(pidlFolder, folderName))
{
Marshal.ThrowExceptionForHR(WinError.E_FAIL);
}
this.selectedFile = folderName.ToString();
}
}
finally
{
NativeMethods.ReleaseStgMedium(ref stm);
}
}
在ShellExtLib.cs文件中添加以下源:
[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, // Address of an item identifier list that
// specifies a file or directory location
// relative to the root of the namespace (the
// desktop).
StringBuilder pszPath); // Address of a buffer to receive the file system
并在ShellExtLib.cs文件中更新RegisterShellExtContextMenuHandler和UnregisterShellExtContextMenuHandler函数
public static void RegisterShellExtContextMenuHandler(Guid clsid,
string fileType, string friendlyName)
{
if (clsid == Guid.Empty)
{
throw new ArgumentException("clsid must not be empty");
}
if (string.IsNullOrEmpty(fileType))
{
throw new ArgumentException("fileType must not be null or empty");
}
// If fileType starts with '.', try to read the default value of the
// HKCR\<File Type> key which contains the ProgID to which the file type
// is linked.
if (fileType.StartsWith("."))
{
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
{
if (key != null)
{
// If the key exists and its default value is not empty, use
// the ProgID as the file type.
string defaultVal = key.GetValue(null) as string;
if (!string.IsNullOrEmpty(defaultVal))
{
fileType = defaultVal;
}
}
}
}
else {
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName1 = string.Format(@"{0}\Background\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName1))
{
// Set the default value of the key.
if (key != null && !string.IsNullOrEmpty(friendlyName))
{
key.SetValue(null, friendlyName);
}
}
}
// Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName))
{
// Set the default value of the key.
if (key != null && !string.IsNullOrEmpty(friendlyName))
{
key.SetValue(null, friendlyName);
}
}
}
public static void UnregisterShellExtContextMenuHandler(Guid clsid,
string fileType)
{
if (clsid == null)
{
throw new ArgumentException("clsid must not be null");
}
if (string.IsNullOrEmpty(fileType))
{
throw new ArgumentException("fileType must not be null or empty");
}
// If fileType starts with '.', try to read the default value of the
// HKCR\<File Type> key which contains the ProgID to which the file type
// is linked.
if (fileType.StartsWith("."))
{
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
{
if (key != null)
{
// If the key exists and its default value is not empty, use
// the ProgID as the file type.
string defaultVal = key.GetValue(null) as string;
if (!string.IsNullOrEmpty(defaultVal))
{
fileType = defaultVal;
}
}
}
}
else {
// Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName1 = string.Format(@"{0}\Background\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
Registry.ClassesRoot.DeleteSubKeyTree(keyName1, false);
}
// Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
fileType, clsid.ToString("B"));
Registry.ClassesRoot.DeleteSubKeyTree(keyName, false);
}
你试着打电话了吗?@dario_ramos:错误的功能。在某些系统上,所有资源管理器窗口都有一个资源管理器进程。如果在两个不同的文件夹上打开了两个窗口,则GetCurrentDir不能同时返回这两个窗口。若您在单独的过程中启用了“打开新窗口”,那个么它就可以工作了。不一定。你试过打电话了吗?@dario_ramos:错误的函数。在某些系统上,所有资源管理器窗口都有一个资源管理器进程。如果在两个不同的文件夹上打开了两个窗口,则GetCurrentDir不能同时返回这两个窗口。若您在单独的过程中启用了“打开新窗口”,那个么它就可以工作了。但不保证。如果我们在文件夹ie中单击,则pidlFolder将不在我的shell扩展中。右键单击文件夹背景空白区域时,pidlFolder不为NULL。但是有一个问题,如果我使用pidlFolder获取路径,QueryContextMenu函数未初始化。您必须注册后台扩展名。值得一提的是,您可以使用SHGetPathFromIDList将此pidlFolder转换为路径字符串。如果我们在文件夹ie内单击,则空区域中的pidlFolder将为Null而不是在我的shell扩展名中。右键单击文件夹背景空白区域时,pidlFolder不为NULL。但存在一个问题,如果使用pidlFolder获取路径,QueryContextMenu函数将不处于hiiting状态。您必须注册后台扩展名。值得一提的是,您可以使用SHGetPathFromIDList将此pidlFolder转换为路径字符串。