Windows shell编程的基本思想是,您可以将给定的文件类型(扩展名)与MS当前调用的编译器(例如,Company.Type.Ver)相关联:
HKCR\.txt @ = Acme.Text.1
HKCR\Acme.Text.1 @ =这是Acme文本文件关联的progid
然后Acme Corp可以将尽可能多的shell动词作为HKCR\Acme.Text.1\shell的子键,例如HKCR\Acme.Text.1\shell\open.
但如果我是XyzCorp,如何在文本文件中添加辅助动词?
我不想篡夺主文件关联 - 我很高兴它与Acme.Text.1相关联,但我想添加"导入到Xyz编辑器".
我可以:
1.向Acme的progid添加一个动词(例如HKCR\Acme.Text.1\shell\my-verb)
2.代表我们创建一个新的progid并将Acme的数据复制到那个,并将XyzCorp的动词合并到
3.将动词直接添加到文件扩展名(至少有一个曾经能够这样做)
4.???
有谁知道这个"正确"的答案?
编辑:我真的不喜欢任何涉及修改别人的PROGID的解决方案.我真的更愿意在相关的PROGID之外添加一些东西 - 一个IContextMenu或其他任何东西,以便为给定的文件类型添加额外的动词/选项.
似乎这样一个疯狂的系统有ext-> progid,其中progid由个别开发公司拥有,并且可以随意删除或更改.这让我觉得很脆弱(卸载东西和poof,你的文件扩展名停止正常工作,或安装一些东西,同样你的辅助动词消失,因为ext现在映射到一个不同的专有PROGID,我没有添加我们的动词安装(当时,不知道任何关于这个其他尚未存在的程序)),而且只是愚蠢.在所有这些时间之后,所有这些版本的Windows和Microsoft从未找到过为给定文件类型提供多层处理程序的方法?真?!?
我发现那令人惊叹!初级编程101涉及学习命令模式或其他分层/级联系统.Windows WinProcs本身是以命令模式模式组织的 - 因此从内部窗口上下文到外部,许多可能的处理程序在给定的MSG中被给予破解.
当然有一种方法可以添加一个适用于多个扩展的动词,而不会覆盖扩展的主要progid关联,它本身完全独立于主扩展 - > progid映射(这样用户可以随着时间的推移安装多个程序,并且仍然有权访问该文件类型的辅助动词).
我想我可以看看HKCR.*...我理解可以在那里添加适用于所有文件类型的动词.但是,我需要找到一些方法来过滤,这样我们的动词才真正存在于我们应该应用的实际文件类型中......
我在我的Win32应用程序中"嵌入Windows资源管理器".(从技术上讲,我在我的应用程序中托管了一个文件夹的ShellView,这是Windows资源管理器所做的).
问题是视图永远不会调用IShellBrowser.BrowseObject.shell视图不是要求我导航到新位置(通过BrowseObject事件),而是启动Windows资源管理器的副本以查看该文件夹.
我希望默认的shell视图(通俗地称为DefView)是可浏览的.
首先,我们需要获取IShellFolder我想要显示的文件夹.要获取的最简单的文件夹是Desktop文件夹,因为SHGetDesktopFolder API它有一个for:
folder: IShellFolder;
SHGetDesktopFolder({out} folder);
Run Code Online (Sandbox Code Playgroud)
接下来我们要求桌面文件夹将其IShellView 交给我们:
view: IShellView;
folder.CreateViewObject(Self.Handle, IID_IShellView, {out}view);
Run Code Online (Sandbox Code Playgroud)
现在我们有文件夹的IShellView(而不是IContextMenu或IExtractIcon),我们现在想通过调用IShellView.CreateViewWindow来显示shell视图:
hostRect: TRect; //where the view is to display itself
folderSettings: TFolderSettings; //display settings for the view
hwndView: HWND; //the newly created view's window handle
folderSettings.ViewMode := FVM_DETAILS; //details mode please, rather than icon/list/etc
folderSettings.fFlags := 0;
hostRect := Rect(20, 20, 660, 500); //the view …Run Code Online (Sandbox Code Playgroud) 我用我的程序打开了一个记事本,Process.Start()但新打开的记事本覆盖了屏幕.但我确实希望我的应用程序保持其重点.
我同样(使用相同的Process.Start)打开MS Excel和Word,但要将焦点重新放回我的表单,我需要编写的是:
this.Focus();
Run Code Online (Sandbox Code Playgroud)
但是用记事本怪起来:我打开记事本(以及所有其他这样的过程)
Process process = new Process();
process.StartInfo.UseShellExecute = true;
process.EnableRaisingEvents = true;
process.StartInfo.FileName = @"abc.log";
process.Start();
Run Code Online (Sandbox Code Playgroud)
现在记事本成为焦点.
我试过这些:
this.Activate(),this.Focus()不用提
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern IntPtr SetFocus(HandleRef hWnd);
{
IntPtr hWnd = myProcess.Handle;
SetFocus(new HandleRef(null, hWnd));
}
Run Code Online (Sandbox Code Playgroud)[DllImport("User32")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[DllImportAttribute("User32.DLL")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SW_SHOW = 5;
private const int SW_MINIMIZE = 6;
private const int SW_RESTORE = 9; …Run Code Online (Sandbox Code Playgroud)可能重复:
获取快捷方式文件夹的目标
例如,在C:\TEMP\我有一个名为test.dll快捷方式的快捷方式将导致文件名test.dll
我想从快捷方式只获取路径名到它自己的文件.所以,我在另一个递归函数中调用此函数,并在每次从我的硬盘中的另一个目录中放入此函数.
例如,第一个目录C:\TEMP就在C:\TEMP那里有快捷方式文件,我只想获取文件的路径.在C:\TEMP测试中,我现在有3个文件:
hpwins23.dat
hpwmdl23.dat
hpwmdl23.dat -Shortcut(C:\TEMP\hpwmdl23.dat)
所以,我想得到的是快捷方式的路径名,本例中是C:\ TEMP
我试着使用这个功能:
public string GetShortcutTargetFile(string shortcutFilename)
{
string pathOnly = System.IO.Path.GetDirectoryName(shortcutFilename);
string filenameOnly = System.IO.Path.GetFileName(shortcutFilename);
Shell shell = new Shell();
Folder folder = shell.NameSpace(pathOnly);
if (folder == null)
{
}
else
{
FolderItem folderItem = folder.ParseName(filenameOnly);
if (folderItem != null)
{
Shell32.ShellLinkObject link = (Shell32.ShellLinkObject)folderItem.GetLink;
return link.Path;
}
}
return string.Empty;
}
Run Code Online (Sandbox Code Playgroud)
但是当我使用该函数并且它到达一个快捷方式时,我遇到异常错误:
Shell32.ShellLinkObject link …Run Code Online (Sandbox Code Playgroud) 我需要获取在Windows资源管理器中选择的当前文件集合.我从这里找到了以下代码.
不过,我不在那里.首先,它GetForegroundWindow来自哪里?另一方面,编译器在线上抱怨
var shell = new Shell32.Shell();
Run Code Online (Sandbox Code Playgroud)
话
"无法找到类型或命名空间名称'Shell32'(您是否缺少using指令或程序集引用?)".我已经添加了SHDocVw作为参考,但我仍然无法通过编译器.有人可以帮我完成这个吗?
IntPtr handle = GetForegroundWindow();
ArrayList selected = new ArrayList();
var shell = new Shell32.Shell();
foreach(SHDocVw.InternetExplorer window in shell.Windows()) {
if (window.HWND == (int)handle)
{
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
foreach(Shell32.FolderItem item in items)
{
selected.Add(item.Path);
}
}
}
Run Code Online (Sandbox Code Playgroud) 我有一个用C++编写的自定义应用程序,它控制连接到嵌入式系统的监视器上的分辨率和其他设置.有时系统无头启动并通过VNC运行,但可以在以后插入监视器(启动后).如果发生这种情况,则在启用监视器之前,监视器不会输入视频.我发现调用"displayswitch/clone"会启动监视器,但我需要知道监视器何时连接.我有一个每5秒运行一次的计时器并查找显示器,但是我需要一些API调用来告诉我显示器是否已连接.
这里有一些psudocode来描述我所追求的(当计时器每5秒到期时执行什么).
if(If monitor connected)
{
ShellExecute("displayswitch.exe /clone);
}else
{
//Do Nothing
}
Run Code Online (Sandbox Code Playgroud)
我试图GetSystemMetrics(SM_CMONITORS)返回监视器的数量,但如果监视器已连接,则返回1.还有其他想法吗?
谢谢!
使用SO帖子"打开文件夹并选择文件"的答案中描述的代码,我创建了这个函数:
public static void OpenExplorerAndSelectFile(string filePath)
{
Process.Start(
@"explorer.exe",
string.Format(@"/select, ""{0}""", filePath));
}
Run Code Online (Sandbox Code Playgroud)
这个功能运行良好,有一个小问题:
首次为特定文件调用该函数时,Windows资源管理器会正确显示该文件的文件夹,但不会选择该文件.
再次为同一个文件调用相同的函数,它会切换回Windows资源管理器中已打开的文件夹,然后选择该文件.
例如,第一次调用OpenExplorerAndSelectFile("C:\MyFolder\MyFile.txt")在新的Windows资源管理器窗口中打开文件夹"C:\ MyFolder".第二次调用OpenExplorerAndSelectFile("C:\MyFolder\MyFile.txt")实际上再次激活该窗口并选择MyFile.txt.
在谷歌浏览器中做类似的事情(转到下载页面并显示以前下载的文件)实际上在第一次尝试时效果很好.
所以我的结论是谷歌Chrome似乎与我有点不同.
我的问题:
有没有办法调试/跟踪谷歌Chrome调用的Win32/Shell方法?
然后我会将它们与我所做的比较以查看差异.
我正在寻找一种方法将文件夹(包含子文件夹)放入具有以下条件的回收站:
它必须以静默方式完成 - 没有任何 Windows UI.
永远不能永久删除该文件夹.如果无法将其放入回收站,我希望API失败.
像CopyFileEx那样获取进程的回调例程.
到目前为止,我能够想出这个:
SHFILEOPSTRUCT sfo = {0};
sfo.wFunc = FO_DELETE;
sfo.pFrom = L"K:\\test del from USB\0"; //Folder on a USB stick
sfo.fFlags = FOF_ALLOWUNDO |
FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR |
FOF_WANTNUKEWARNING;
int res = SHFileOperation(&sfo);
BOOL bFullSuccess = res == 0 && !sfo.fAnyOperationsAborted;
Run Code Online (Sandbox Code Playgroud)
哪个位于USB闪存驱动器上的文件夹可怕失败,即尽管有标志,它仍被永久删除FOF_ALLOWUNDO.
所以我是不是做对了,或者SHFileOperation API是非常错误的!
知道如何做我上面概述的内容吗?
编辑:我实现了IRecycleBinManager::WillRecycle@Denis Anisimov建议的方法,但显然更多.这是我的C++版本.我需要的方法的第一个接口定义:
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("5869092D-8AF9-4A6C-AE84-1F03BE2246CC")
IRecycleBinManager : public IUnknown
{
public: …Run Code Online (Sandbox Code Playgroud) 与其他希望将项目添加到Windows资源管理器的人不同,我想在我的应用程序中显示上下文菜单.现在你可能在想,你正在寻找的课程是ContextMenu.让我告诉你我有兴趣做什么.请原谅小图片......
这是我目前拥有的:

这就是我希望它:

让我们把假设排除在外.我已经检测到用户安装了TortoiseSVN并且他们选择的项目受源代码管理.
我到目前为止的研究:
检索上下文菜单 - 这非常有用.这是Windows资源管理器的ac#库(可以检索特定文件夹/文件的上下文菜单).但是,即使在测试示例时,它也不会检索TortoiseSVN选项.
另一个上下文菜单检索 - 几乎与前一个链接相同(再次使用C#代码).获取Windows资源管理器上下文菜单减去TortoiseSVN选项.
添加上下文菜单的过程 - 我刚刚开始阅读这些深入的帖子.答案可能在本文中,但我需要一些时间来完成它.如果我有这些运气,我会回复一个答案.
用户似乎能够完成此任务 - 这似乎是一个处理SVN开发的电子邮件组.为什么要在这里发布?也许是为了证明这可以做到.引用:"我正在使用TSVN shell上下文菜单.我正在使用IContextMenu.QueryContextMenu(C++代码)方法访问TSVN shell上下文菜单,然后我将通过返回的菜单进行浏览."
总而言之,这似乎应该是一个相当直接的事情,我只是错过了一步.欢迎任何和所有建议.谢谢!
编辑:尝试更好地利用标签和更集中的标题
在即将推出的(当前内部版本)OneDrive客户端 - 按需功能中,Microsoft引入了一些新的shell /命名空间扩展.
还有一列显示文件可用性状态,以及状态栏中的文本.
Microsoft是否为OneDrive同步文件夹或其他一些shell界面开发了特殊的IShellView实现?他们是如何联系到文件选择更改事件的呢?
我知道自从以前的一些Windows版本以来,对列处理程序扩展的支持已被删除.
请指出一些有关开发此类功能的有用资源:自定义列和状态栏扩展(最好使用C#..).
windows-shell ×10
c# ×5
windows ×4
c++ ×3
winapi ×3
.net ×1
contextmenu ×1
explorer ×1
focus ×1
process ×1
recycle-bin ×1
registry ×1
shellexecute ×1
tortoisesvn ×1
winforms ×1