使用资源管理器中的多个文件作为参数打开一次程序

发布于 2024-08-30 14:53:38 字数 218 浏览 16 评论 0 原文

我有一个程序,可以在使用资源管理器中的右键单击菜单打开文件时运行。但是,如果我选择多个文件,然后右键单击并使用我的程序打开,那么它将打开我的程序的多个实例,而不是仅将多个文件作为参数传递给单个实例。该程序是用 vb.net 编写的,但不是 Windows 窗体,它只是一个模块,因此我可以在 Visual Studio 的属性中勾选“单实例”选项。

那么如何在单个实例中从资源管理器上下文菜单打开多个文件。

I have a program that works when, a file is opened with it using the right click menu in explorer. But if I select multiple files and then right click and open with my program then it opens multiple instances of my program, instead of just passing the multiple files as arguments to a single instance. The program is written in vb.net but is not a windows form, it is just a module, so I can to tick the Single instance option in the properties in Visual Studio.

So how do I open multiple files from explorer context menu in a single instance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

巨坚强 2024-09-06 14:53:38

这里没有令人满意的答案,Windows 资源管理器没有提供一种简单的方法来启动程序并传递所有选定的文件。这需要一个 shell 上下文菜单处理程序,它们很难用托管编写代码。并且.NET 4.0 之前的版本都无法安全编写。

尽管如此,使用 VB.NET 中提供的应用程序框架来模拟它还是很容易的,使您的应用程序成为单例并实现 StartupNextInstance 事件。唯一的问题是这不是特别快。而且它不适用于控制台模式应用程序。

No happy answers here, Windows Explorer doesn't provide an easy way to start your program passing all selected files. That requires a shell context menu handler, they are very difficult to write in managed code. And up to .NET 4.0 could not be safely written.

It is nevertheless easy to simulate it with the application framework available in VB.NET, make your app a singleton and implement the StartupNextInstance event. The only issue is that this is not particularly fast. And that it doesn't work in console mode apps.

意中人 2024-09-06 14:53:38

此链接帮助我通过单击上下文菜单项来获取资源管理器中所选文件的路径:
.NET Shell 扩展 - Shell 上下文菜单

在 C# 语言中,但正如那篇文章海报所说,它也可以在 vb.net 中使用。

真的很简单:)

希望这也能帮助你! :)

步骤如下:

1) 下载 SharpShell 库>>

下载文章顶部的“SharpShell Library”zip 文件,并添加对下载的 SharpShell.dll 文件的引用。

或者您可以通过 Nuget 下载它:

如果您安装了 Nuget,只需快速搜索 SharpShell 并直接安装 - 或者在 https://www.nuget.org/packages/SharpShell

添加以下引用:

System.Windows.Forms
System.Drawing

在代码顶部使用这些引用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpShell;
using SharpShell.SharpContextMenu;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using SharpShell.Attributes;

SharpContextMenu 派生您的类
右键单击该行的 SharpContextMenu 部分,然后选择Implement Abstract Class

CanShowMenu

调用此函数来确定是否应该显示给定文件集的上下文菜单扩展。用户选择的文件位于属性 SelectedItemPaths 中。我们可以检查这些文件路径,看看我们是否真的想要显示菜单。如果应该显示菜单,则返回true。如果不是,则返回false

CreateMenu 调用

此函数来实际创建上下文菜单。我们需要返回一个标准的 WinForms ContextMenuStrip

这是整个命名空间的 SourceCode:

namespace CountLinesExtension
{
[ComVisible(true)]
[COMServerAssociation(AssociationType.ClassOfExtension, ".txt")]
public class Class1 : SharpContextMenu
{
protected override bool CanShowMenu()
{
        //  We will always show the menu.
        return true;
        //throw new NotImplementedException();
    }

    protected override ContextMenuStrip CreateMenu()
    {
        //  Create the menu strip.
        var menu = new ContextMenuStrip();

        //  Create a 'count lines' item.
        var itemCountLines = new ToolStripMenuItem
        {
            Text = "Count Lines"
        };

        //  When we click, we'll call the 'CountLines' function.
        itemCountLines.Click += (sender, args) => CountLines();

        //  Add the item to the context menu.
        menu.Items.Add(itemCountLines);

        //  Return the menu.
        return menu;
        //throw new NotImplementedException();
    }
    private void CountLines()
    {
        //  Builder for the output.
        var builder = new StringBuilder();

        //  Go through each file.
        foreach (var filePath in SelectedItemPaths)
        {
            //  Count the lines.
            builder.AppendLine(string.Format("{0} - {1} Lines",
              Path.GetFileName(filePath), File.ReadAllLines(filePath).Length));
        }

        //  Show the ouput.
        MessageBox.Show(builder.ToString());
    } 

}
}

接下来,我们必须为程序集指定一个强名称。有多种方法可以满足此要求,但通常这是最好的方法。为此,右键单击该项目并选择“属性”。然后转到“签名”。选择“签署程序集”,为密钥指定“新建”并选择密钥名称。如果需要,您可以使用密码保护密钥,但这不是必需的

现在安装并注册 Shell 扩展:
regasm 工具

您可以使用“regasm”工具来安装和注册 shell 扩展。当使用regasm时,shell扩展将被安装到注册表中(即COM服务器的类ID将被放入COM服务器类部分并与实际服务器文件的路径关联),它还将注册关联。

服务器管理器工具

服务器管理器工具是我安装/卸载和注册/取消注册的首选方法,至少在开发过程中是这样,因为它允许您将安装和注册作为单独的步骤进行。它还可以让您指定是在 32 位还是 64 位模式下安装/卸载等。

这是整个示例源代码。我们可以添加任意数量的上下文菜单项、任何函数、任何文件扩展名等。

this link helped me to get paths of selected files in explorer by clicking on a context-menu item:
.NET Shell Extensions - Shell Context Menus

it's in C# language but as that article poster said it can be used in vb.net too.

real easy :)

Hope this help you too! :)

Here's The Steps:

1) Download thee SharpShell library>>

Download the 'SharpShell Library' zip file at the top of the article and add a reference to the downloaded SharpShell.dll file.

or you can download it via Nuget:

If you have Nuget installed, just do a quick search for SharpShell and install it directly - or get the package details at https://www.nuget.org/packages/SharpShell.

Add the following references:

System.Windows.Forms
System.Drawing

Use these at top of your code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpShell;
using SharpShell.SharpContextMenu;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using SharpShell.Attributes;

Derive your Class From SharpContextMenu
Right click on the SharpContextMenu part of the line and choose Implement Abstract Class.

CanShowMenu

This function is called to determine whether we should show the Context Menu Extension for a given set of files. The files the user has selected are in the property SelectedItemPaths. We can check these file paths to see whether we actually want to show the menu. If the menu should be shown, return true. If not, return false.

CreateMenu

This function is called to actually create the Context Menu. A standard WinForms ContextMenuStrip is all we need to return.

Here's the whole namespace SourceCode:

namespace CountLinesExtension
{
[ComVisible(true)]
[COMServerAssociation(AssociationType.ClassOfExtension, ".txt")]
public class Class1 : SharpContextMenu
{
protected override bool CanShowMenu()
{
        //  We will always show the menu.
        return true;
        //throw new NotImplementedException();
    }

    protected override ContextMenuStrip CreateMenu()
    {
        //  Create the menu strip.
        var menu = new ContextMenuStrip();

        //  Create a 'count lines' item.
        var itemCountLines = new ToolStripMenuItem
        {
            Text = "Count Lines"
        };

        //  When we click, we'll call the 'CountLines' function.
        itemCountLines.Click += (sender, args) => CountLines();

        //  Add the item to the context menu.
        menu.Items.Add(itemCountLines);

        //  Return the menu.
        return menu;
        //throw new NotImplementedException();
    }
    private void CountLines()
    {
        //  Builder for the output.
        var builder = new StringBuilder();

        //  Go through each file.
        foreach (var filePath in SelectedItemPaths)
        {
            //  Count the lines.
            builder.AppendLine(string.Format("{0} - {1} Lines",
              Path.GetFileName(filePath), File.ReadAllLines(filePath).Length));
        }

        //  Show the ouput.
        MessageBox.Show(builder.ToString());
    } 

}
}

Next, we must give the assembly a strong name. There are ways around this requirement, but generally this is the best approach to take. To do this, right click on the project and choose 'Properties'. Then go to 'Signing'. Choose 'Sign the Assembly', specify 'New' for the key and choose a key name. You can password protect the key if you want to, but it is not required

Now Install and register Shell Extension:
The regasm Tool

You can use the tool 'regasm' to install and register a shell extension. When using regasm, the shell extension will be installed into the registry (i.e. the Class ID of the COM Server will be put in the COM Server Classes section and associated with the path to the actual server file), it will also register the associations.

The Server Manager Tool

The Server Manager Tool is my preferred approach for installing/uninstalling and registering/unregistering, at least during development, because it lets you install and register as separate steps. It will also let you specify whether you're installing/uninstalling etc in 32 bit or 64 bit mode.

It was the whole Sample sourceCode. we can add any number of context-menu items, any function,any fileExtension,etc.

幸福还没到 2024-09-06 14:53:38

虽然我知道这是针对 vb.net 的,但我确信您只需进行一些修改就可以使用此 C# 代码,这对我有用。也许这不是最好的方法,但对我来说,这是最简单的方法。在运行第二个副本之前,它会检查应用程序当前是否正在运行。

这是在 Program.cs 中

 static frmMain Form;

    [STAThread]
    static void Main(string[] args)
    {
        bool blnCurrentlyRunning = false;

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Process[] processes = Process.GetProcesses();
        foreach (var item in processes)
        {
            if (item.MainWindowTitle.IndexOf("Application Title") != -1)
                blnCurrentlyRunning = true;
        }

        if (!blnCurrentlyRunning)
        {
            Form = new frmMain();
            Application.Run(Form);
        }
        else
        {
            Application.Exit();
        }
    }

While I know this was for vb.net, I am sure you can use this c# code with just a few modifications, this worked for me. Maybe it isn't the best way to do it, but for me, it was the simplest way. It checks to see if the application title is currently running before running a second copy.

This is in the Program.cs

 static frmMain Form;

    [STAThread]
    static void Main(string[] args)
    {
        bool blnCurrentlyRunning = false;

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Process[] processes = Process.GetProcesses();
        foreach (var item in processes)
        {
            if (item.MainWindowTitle.IndexOf("Application Title") != -1)
                blnCurrentlyRunning = true;
        }

        if (!blnCurrentlyRunning)
        {
            Form = new frmMain();
            Application.Run(Form);
        }
        else
        {
            Application.Exit();
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文