Как связать расширение файла с текущим исполняемым файлом в C #

Я хотел бы связать расширение файла с текущим исполняемым файлом на C #. Таким образом, когда пользователь затем щелкает файл в проводнике, он запускает мой исполняемый файл с заданным файлом в качестве первого аргумента. В идеале он также должен был бы установить значок для заданных расширений файла на значок для моего исполняемого файла. Спасибо всем.


person Community    schedule 16.09.2008    source источник
comment
codeproject.com/KB/dotnet/System_File_Association.aspx Тогда, возможно, csharpfriends.com/Forums/ShowPost.aspx?PostID=32627 Может быть помощь. При необходимости вы всегда можете самостоятельно редактировать реестр через API напрямую для ассоциации ... но на ваше усмотрение РЕДАКТИРОВАТЬ: Также прочтите там комментарии, некоторые хорошие моменты, например, использование кавычек для путей с пробелами: @C: \ SomePath \ MyApp.exe% 1 Также проблемы с разрешениями для доступа к реестру, особенно в Vista ... удачи :)   -  person White Dragon    schedule 16.09.2008
comment
На этот вопрос был дан подробный ответ в следующем поток переполнения стека. Мы использовали эту реализацию, и она отлично работает. Он также имеет открытый исходный код и интегрируется в MSBuild.   -  person Blake Niemyjski    schedule 02.05.2012
comment
На этот вопрос был дан подробный ответ в следующем потоке: stackoverflow.com/questions/2993118/   -  person Blake Niemyjski    schedule 02.05.2012
comment
@BlakeNiemyjski Как ваши ссылки о встраивании значков в сборки .NET имеют отношение к этому вопросу об ассоциации расширений файлов?   -  person Dean Kuga    schedule 22.08.2012
comment
Я ссылался на сообщение о переполнении стека, в котором содержится полезная информация Wix о привязке расширения файла через установщик Wix.   -  person Blake Niemyjski    schedule 27.08.2012
comment
Большая проблема с примером codeproject заключается в том, что он записывает в HKEY_CLASSES_ROOT вместо того, чтобы дать вам выбор между этим и HKEY_CURRENT_USER, иначе вы бы использовали его.   -  person Kelly Elton    schedule 29.10.2013


Ответы (9)


Похоже, что не существует API .Net для прямого управления ассоциациями файлов, но вы можете использовать классы реестра для чтения и записи необходимых вам ключей.

Вам нужно будет создать ключ в HKEY_CLASSES_ROOT с именем, установленным в соответствии с расширением вашего файла (например: «.txt»). Задайте для этого ключа значение по умолчанию, уникальное имя для вашего типа файла, например «Acme.TextFile». Затем создайте еще один ключ в HKEY_CLASSES_ROOT с именем, установленным на «Acme.TextFile». Добавьте подраздел с именем «DefaultIcon» и установите значение ключа по умолчанию для файла, содержащего значок, который вы хотите использовать для этого типа файла. Добавьте еще одного брата по имени «оболочка». Под ключом «shell» добавьте ключ для каждого действия, которое вы хотите сделать доступным через контекстное меню проводника, установив значение по умолчанию для каждого ключа, указав путь к вашему исполняемому файлу, за которым следует пробел, и «% 1» для представления пути. в выбранный файл.

Например, вот образец файла реестра для создания связи между файлами .txt и EmEditor:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.txt]
@="emeditor.txt"

[HKEY_CLASSES_ROOT\emeditor.txt]
@="Text Document"

[HKEY_CLASSES_ROOT\emeditor.txt\DefaultIcon]
@="%SystemRoot%\\SysWow64\\imageres.dll,-102"

[HKEY_CLASSES_ROOT\emeditor.txt\shell]

[HKEY_CLASSES_ROOT\emeditor.txt\shell\open]

[HKEY_CLASSES_ROOT\emeditor.txt\shell\open\command]
@="\"C:\\Program Files\\EmEditor\\EMEDITOR.EXE\" \"%1\""

[HKEY_CLASSES_ROOT\emeditor.txt\shell\print]

[HKEY_CLASSES_ROOT\emeditor.txt\shell\print\command]
@="\"C:\\Program Files\\EmEditor\\EMEDITOR.EXE\" /p \"%1\""
person X-Cubed    schedule 16.09.2008
comment
Есть ли способ передать некоторые аргументы в exe (в данном случае в C: \ Program Files \ EmEditor \ EMEDITOR.EXE)? - person Apparao; 20.01.2016
comment
@Apparao да, посмотрите на команду Print в качестве примера. Он передает параметр / p перед именем файла. - person X-Cubed; 18.01.2017
comment
Я знаю, что этому ответу более десяти лет, но все же - я не думаю, что это хороший способ связать открытый формат файла, представляющий собой открытый текст (*.txt), со случайной программой - это в основном берет на себя ассоциацию файлов , если уже была, по крайней мере, предыдущая ассоциация текстовых файлов с какой-либо программой (ами), переопределение ее. В документации Microsoft, хотя и не реализованной, по крайней мере указано, что способ связать программу с общедоступным типом файла (с помощью контекстного меню «Открыть с помощью») - это использовать OpenWithProgIds ключ реестра под ключом типа файла. - person amn; 20.03.2020

Кроме того, если вы решите использовать реестр, имейте в виду, что текущие ассоциации пользователей находятся в разделе HKEY_CURRENT_USER \ Software \ Classes. Возможно, было бы лучше добавить туда свое приложение вместо локальных машинных классов.

Если ваша программа будет запускаться ограниченными пользователями, вы все равно не сможете изменить CLASSES_ROOT.

person Ishmaeel    schedule 16.09.2008

Если вы используете развертывание ClickOnce, все это делается за вас (по крайней мере, в VS2008 SP1); просто:

  • Свойства проекта
  • Публиковать
  • Опции
  • Файловые ассоциации
  • (добавьте все, что вам нужно)

(обратите внимание, что он должен быть с полным доверием, иметь целевой .NET 3.5 и быть настроен для автономного использования)

См. Также MSDN: Как: создать файловые ассоциации для приложения ClickOnce

person Marc Gravell    schedule 25.08.2009
comment
У меня VS2008 Professional, SP1, и я не вижу этой опции. Я, должно быть, что-то упускаю. - person Jerry; 27.01.2010

Вот полный пример:

public class FileAssociation
{
    public string Extension { get; set; }
    public string ProgId { get; set; }
    public string FileTypeDescription { get; set; }
    public string ExecutableFilePath { get; set; }
}

public class FileAssociations
{
    // needed so that Explorer windows get refreshed after the registry is updated
    [System.Runtime.InteropServices.DllImport("Shell32.dll")]
    private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

    private const int SHCNE_ASSOCCHANGED = 0x8000000;
    private const int SHCNF_FLUSH = 0x1000;

    public static void EnsureAssociationsSet()
    {
        var filePath = Process.GetCurrentProcess().MainModule.FileName;
        EnsureAssociationsSet(
            new FileAssociation
            {
                Extension = ".binlog",
                ProgId = "MSBuildBinaryLog",
                FileTypeDescription = "MSBuild Binary Log",
                ExecutableFilePath = filePath
            },
            new FileAssociation
            {
                Extension = ".buildlog",
                ProgId = "MSBuildStructuredLog",
                FileTypeDescription = "MSBuild Structured Log",
                ExecutableFilePath = filePath
            });
    }

    public static void EnsureAssociationsSet(params FileAssociation[] associations)
    {
        bool madeChanges = false;
        foreach (var association in associations)
        {
            madeChanges |= SetAssociation(
                association.Extension,
                association.ProgId,
                association.FileTypeDescription,
                association.ExecutableFilePath);
        }

        if (madeChanges)
        {
            SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero);
        }
    }

    public static bool SetAssociation(string extension, string progId, string fileTypeDescription, string applicationFilePath)
    {
        bool madeChanges = false;
        madeChanges |= SetKeyDefaultValue(@"Software\Classes\" + extension, progId);
        madeChanges |= SetKeyDefaultValue(@"Software\Classes\" + progId, fileTypeDescription);
        madeChanges |= SetKeyDefaultValue($@"Software\Classes\{progId}\shell\open\command", "\"" + applicationFilePath + "\" \"%1\"");
        return madeChanges;
    }

    private static bool SetKeyDefaultValue(string keyPath, string value)
    {
        using (var key = Registry.CurrentUser.CreateSubKey(keyPath))
        {
            if (key.GetValue(null) as string != value)
            {
                key.SetValue(null, value);
                return true;
            }
        }

        return false;
    }
person Kirill Osenkov    schedule 29.06.2017

Могут быть определенные причины, по которым вы решите не использовать установочный пакет для своего проекта, но установочный пакет - отличное место для простого выполнения задач настройки приложения, таких как регистрация расширений файлов, добавление ярлыков на рабочий стол и т. Д.

Вот как создать ассоциацию расширений файлов с помощью встроенных инструментов установки Visual Studio:

  1. В существующем решении C # добавьте новый проект и выберите тип проекта как Other Project Types -> Setup and Deployment -> Setup Project (или попробуйте мастер установки)

  2. Сконфигурируйте свой установщик (множество существующих документов для этого, если вам нужна помощь)

  3. Щелкните правой кнопкой мыши проект установки в обозревателе решений, выберите View -> File Types, а затем добавьте расширение, которое вы хотите зарегистрировать, вместе с программой для его запуска.

Дополнительным преимуществом этого метода является очистка после себя, если пользователь запускает удаление вашего приложения.

person Paul J    schedule 22.05.2009

Чтобы быть конкретным о способе "Реестр Windows":

Я создаю ключи в HKEY_CURRENT_USER \ Software \ Classes (как сказал Исмаил)

и следуйте инструкциям, полученным от X-Cubed.

Пример кода выглядит так:

private void Create_abc_FileAssociation()
{
    /***********************************/
    /**** Key1: Create ".abc" entry ****/
    /***********************************/
    Microsoft.Win32.RegistryKey key1 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);

    key1.CreateSubKey("Classes");
    key1 = key1.OpenSubKey("Classes", true);

    key1.CreateSubKey(".abc");
    key1 = key1.OpenSubKey(".abc", true);
    key1.SetValue("", "DemoKeyValue"); // Set default key value

    key1.Close();

    /*******************************************************/
    /**** Key2: Create "DemoKeyValue\DefaultIcon" entry ****/
    /*******************************************************/
    Microsoft.Win32.RegistryKey key2 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);

    key2.CreateSubKey("Classes");
    key2 = key2.OpenSubKey("Classes", true);

    key2.CreateSubKey("DemoKeyValue");
    key2 = key2.OpenSubKey("DemoKeyValue", true);

    key2.CreateSubKey("DefaultIcon");
    key2 = key2.OpenSubKey("DefaultIcon", true);
    key2.SetValue("", "\"" + "(The icon path you desire)" + "\""); // Set default key value

    key2.Close();

    /**************************************************************/
    /**** Key3: Create "DemoKeyValue\shell\open\command" entry ****/
    /**************************************************************/
    Microsoft.Win32.RegistryKey key3 = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software", true);

    key3.CreateSubKey("Classes");
    key3 = key3.OpenSubKey("Classes", true);

    key3.CreateSubKey("DemoKeyValue");
    key3 = key3.OpenSubKey("DemoKeyValue", true);

    key3.CreateSubKey("shell");
    key3 = key3.OpenSubKey("shell", true);

    key3.CreateSubKey("open");
    key3 = key3.OpenSubKey("open", true);

    key3.CreateSubKey("command");
    key3 = key3.OpenSubKey("command", true);
    key3.SetValue("", "\"" + "(The application path you desire)" + "\"" + " \"%1\""); // Set default key value

    key3.Close();
}

Просто покажите вам, ребята, небольшую демонстрацию, очень простую для понимания. Вы можете изменить эти ключевые значения, и все будет хорошо.

person Strong84    schedule 18.02.2015
comment
Не забудьте добавить необходимый код, чтобы уведомить оболочку об использовании значка. SHChangeNotify(0x8000000, 0, 0, 0); - person randomsolutions; 19.08.2015

Приведенный ниже код - это функция, которая должна работать, она добавляет необходимые значения в реестр Windows. Обычно я запускаю SelfCreateAssociation (". Abc") в своем исполняемом файле. (конструктор формы или onload или onshown) Он будет обновлять запись в реестре для текущего пользователя каждый раз при выполнении исполняемого файла. (хорошо для отладки, если есть изменения). Если вам нужна подробная информация о задействованных ключах реестра, ознакомьтесь с этой ссылкой MSDN.

https://msdn.microsoft.com/en-us/library/windows/desktop/dd758090(v=vs.85).aspx

Чтобы получить дополнительные сведения об общем разделе реестра ClassesRoot. См. Эту статью MSDN.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms724475(v=vs.85).aspx

public enum KeyHiveSmall
{
    ClassesRoot,
    CurrentUser,
    LocalMachine,
}

/// <summary>
/// Create an associaten for a file extension in the windows registry
/// CreateAssociation(@"vendor.application",".tmf","Tool file",@"C:\Windows\SYSWOW64\notepad.exe",@"%SystemRoot%\SYSWOW64\notepad.exe,0");
/// </summary>
/// <param name="ProgID">e.g. vendor.application</param>
/// <param name="extension">e.g. .tmf</param>
/// <param name="description">e.g. Tool file</param>
/// <param name="application">e.g.  @"C:\Windows\SYSWOW64\notepad.exe"</param>
/// <param name="icon">@"%SystemRoot%\SYSWOW64\notepad.exe,0"</param>
/// <param name="hive">e.g. The user-specific settings have priority over the computer settings. KeyHive.LocalMachine  need admin rights</param>
public static void CreateAssociation(string ProgID, string extension, string description, string application, string icon, KeyHiveSmall hive = KeyHiveSmall.CurrentUser)
{
    RegistryKey selectedKey = null;

    switch (hive)
    {
        case KeyHiveSmall.ClassesRoot:
            Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(extension).SetValue("", ProgID);
            selectedKey = Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(ProgID);
            break;

        case KeyHiveSmall.CurrentUser:
            Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\Classes\" + extension).SetValue("", ProgID);
            selectedKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(@"Software\Classes\" + ProgID);
            break;

        case KeyHiveSmall.LocalMachine:
            Microsoft.Win32.Registry.LocalMachine.CreateSubKey(@"Software\Classes\" + extension).SetValue("", ProgID);
            selectedKey = Microsoft.Win32.Registry.LocalMachine.CreateSubKey(@"Software\Classes\" + ProgID);
            break;
    }

    if (selectedKey != null)
    {
        if (description != null)
        {
            selectedKey.SetValue("", description);
        }
        if (icon != null)
        {
            selectedKey.CreateSubKey("DefaultIcon").SetValue("", icon, RegistryValueKind.ExpandString);
            selectedKey.CreateSubKey(@"Shell\Open").SetValue("icon", icon, RegistryValueKind.ExpandString);
        }
        if (application != null)
        {
            selectedKey.CreateSubKey(@"Shell\Open\command").SetValue("", "\"" + application + "\"" + " \"%1\"", RegistryValueKind.ExpandString);
        }
    }
    selectedKey.Flush();
    selectedKey.Close();
}

 /// <summary>
    /// Creates a association for current running executable
    /// </summary>
    /// <param name="extension">e.g. .tmf</param>
    /// <param name="hive">e.g. KeyHive.LocalMachine need admin rights</param>
    /// <param name="description">e.g. Tool file. Displayed in explorer</param>
    public static void SelfCreateAssociation(string extension, KeyHiveSmall hive = KeyHiveSmall.CurrentUser, string description = "")
    {
        string ProgID = System.Reflection.Assembly.GetExecutingAssembly().EntryPoint.DeclaringType.FullName;
        string FileLocation = System.Reflection.Assembly.GetExecutingAssembly().Location;
        CreateAssociation(ProgID, extension, description, FileLocation, FileLocation + ",0", hive);
    }
person Carsten R.    schedule 24.10.2017
comment
Оставление большого блока кода без объяснения причин вряд ли поможет будущим читателям. Пожалуйста, попробуйте добавить объяснение того, что делает этот код. - person Nisarg; 24.10.2017
comment
Код рабочий. Объяснение в исходном коде в порядке и идеально подходит для меня. - person Nasenbaer; 10.01.2019

Ассоциации файлов определены в реестре под HKEY_CLASSES_ROOT.

здесь есть пример VB.NET, что я вас легко переносится на C #.

person Steve Morgan    schedule 16.09.2008

Со времен Windows 7 появились два инструмента cmd, которые упрощают создание простых ассоциаций файлов. Это assoc и ftype. Вот базовое объяснение каждой команды.

  • Assoc - связывает расширение файла ( например .txt) с «типом файла».
  • FType - определяет исполняемый файл для запуска когда пользователь открывает данный «тип файла».

Обратите внимание, что это инструменты cmd, а не исполняемые файлы (exe). Это означает, что их можно запускать только в окне cmd или с помощью ShellExecute с "cmd / c assoc." Вы можете узнать о них больше по ссылкам или набрав «assoc /?» и "ftype /?" в командной строке.

Итак, чтобы связать приложение с расширением .bob, вы можете открыть окно cmd (WindowKey + R, введите cmd, нажмите ввод) и выполните следующее:

assoc .bob=BobFile
ftype BobFile=c:\temp\BobView.exe "%1"

Это намного проще, чем возиться с реестром, и, скорее всего, это сработает в будущей версии Windows.

Подводя итог, вот функция C # для создания ассоциации файлов:

public static int setFileAssociation(string[] extensions, string fileType, string openCommandString) {
    int v = execute("cmd", "/c ftype " + fileType + "=" + openCommandString);
    foreach (string ext in extensions) {
        v = execute("cmd", "/c assoc " + ext + "=" + fileType);
        if (v != 0) return v;
    }
    return v;
}
public static int execute(string exeFilename, string arguments) {
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.CreateNoWindow = false;
    startInfo.UseShellExecute = true;
    startInfo.FileName = exeFilename;
    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    startInfo.Arguments = arguments;
    try {
        using (Process exeProcess = Process.Start(startInfo)) {
            exeProcess.WaitForExit();
            return exeProcess.ExitCode;
        }
    } catch {
        return 1;
    }
}
person Mike    schedule 23.10.2017