saber - Cómo asociar una extensión de archivo al ejecutable actual en C#
programas para abrir archivos de todo tipo (9)
Además, si decide seguir el camino del registro, tenga en cuenta que las asociaciones de usuarios actuales se encuentran en HKEY_CURRENT_USER / Software / Classes . Podría ser mejor agregar su aplicación allí en lugar de las clases de máquinas locales.
Si su programa lo ejecutarán usuarios limitados, no podrá modificar CLASSES_ROOT de todos modos.
Me gustaría asociar una extensión de archivo al ejecutable actual en C #. De esta forma, cuando el usuario haga clic en el archivo después en el explorador, ejecutará mi ejecutable con el archivo dado como primer argumento. Idealmente, también establecería el ícono para las extensiones de archivo dadas al ícono para mi ejecutable. Gracias a todos.
Aquí hay un ejemplo completo:
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;
}
El siguiente código es una función que debería funcionar, agrega los valores requeridos en el registro de Windows. Por lo general, ejecuto SelfCreateAssociation (". Abc") en mi ejecutable. (form constructor o onload o onshown) Actualizará la entrada de registro para el usuario actual, cada vez que se ejecute el ejecutable. (bueno para la depuración, si tiene algunos cambios). Si necesita información detallada sobre las claves de registro involucradas, consulte este enlace de MSDN.
https://msdn.microsoft.com/en-us/library/windows/desktop/dd758090(v=vs.85).aspx
Para obtener más información sobre la clave de registro ClassesRoot general. Vea este artículo de 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);
}
Hay dos herramientas cmd que han existido desde Windows 7 que hacen que sea muy fácil crear asociaciones simples de archivos. Ellos son assoc y ftype . Aquí hay una explicación básica de cada comando.
- assoc : asocia una extensión de archivo (como ''.txt'') con un '''' tipo de archivo ''''.
- ftype : define un ejecutable que se ejecutará cuando el usuario abra un "tipo de archivo" determinado.
Tenga en cuenta que estas son herramientas de cmd y archivos no ejecutables (exe). Esto significa que solo se pueden ejecutar en una ventana de cmd o utilizando ShellExecute con "cmd / c assoc". Puede obtener más información sobre ellos en los enlaces o escribiendo "assoc /?" y "ftype /?" en un indicador de cmd.
Entonces, para asociar una aplicación con una extensión .bob, podría abrir una ventana de cmd (WindowKey + R, escribir cmd, presionar enter) y ejecutar lo siguiente:
assoc .bob=BobFile
ftype BobFile=c:/temp/BobView.exe "%1"
Esto es mucho más simple que jugar con el registro y es más probable que funcione en la versión de Windows en el futuro.
Envolviéndolo, aquí hay una función C # para crear una asociación de archivos:
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;
}
}
Las asociaciones de archivos se definen en el registro bajo HKEY_CLASSES_ROOT.
Hay un ejemplo de VB.NET here que puedo dirigir fácilmente a C #.
No parece haber una API .Net para administrar directamente asociaciones de archivos, pero puede usar las clases de Registry para leer y escribir las claves que necesita.
Tendrá que crear una clave bajo HKEY_CLASSES_ROOT con el nombre establecido en su extensión de archivo (por ejemplo: ".txt"). Establezca el valor predeterminado de esta clave en un nombre único para su tipo de archivo, como "Acme.TextFile". Luego crea otra clave bajo HKEY_CLASSES_ROOT con el nombre establecido en "Acme.TextFile". Agregue una subclave llamada "DefaultIcon" y establezca el valor predeterminado de la clave para el archivo que contiene el icono que desea usar para este tipo de archivo. Agregue otro hermano llamado "shell". Debajo de la tecla "shell", agregue una clave para cada acción que desee tener disponible a través del menú contextual de Explorer, establezca el valor predeterminado para cada tecla en la ruta al ejecutable seguido de un espacio y "% 1" para representar la ruta al archivo seleccionado.
Por ejemplo, aquí hay un archivo de registro de muestra para crear una asociación entre archivos .txt y 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/""
Para ser específico sobre el modo "Registro de Windows":
Creo claves bajo HKEY_CURRENT_USER / Software / Classes (como dijo Ishmaeel)
y siga las instrucciones respondidas por X-Cubed.
El código de muestra se ve así:
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();
}
Solo les muestro una demostración rápida, muy fácil de entender. Podrías modificar esos valores clave y todo está bien para ir.
Puede haber razones específicas por las que elige no usar un paquete de instalación para su proyecto, pero un paquete de instalación es un gran lugar para realizar fácilmente tareas de configuración de aplicaciones tales como registrar extensiones de archivos, agregar accesos directos de escritorio, etc.
A continuación, se explica cómo crear una asociación de extensión de archivo con las herramientas de instalación de Visual Studio incorporadas:
Dentro de su solución de C # existente, agregue un nuevo proyecto y seleccione el tipo de proyecto como
Other Project Types
->Setup and Deployment
->Setup Project
(o pruebe el Asistente de configuración)Configure su instalador (muchos documentos existentes para esto si necesita ayuda)
Haga clic con el botón derecho en el proyecto de configuración en el Explorador de soluciones, seleccione
View
->File Types
, y luego agregue la extensión que desea registrar junto con el programa para ejecutarlo.
Este método tiene el beneficio adicional de limpiarse a sí mismo si un usuario ejecuta la desinstalación para su aplicación.
Si usa la implementación de ClickOnce, todo esto se maneja para usted (al menos, en VS2008 SP1); simplemente:
- Propiedades del proyecto
- Publicar
- Opciones
- Asociaciones de archivos
- (agrega lo que necesites)
(tenga en cuenta que debe ser de plena confianza, destino .NET 3.5 y configurado para uso fuera de línea)
Vea también MSDN: Cómo: Crear asociaciones de archivos para una aplicación ClickOnce