Encontrar la aplicación predeterminada para abrir un tipo de archivo particular en Windows

StackOverflow https://stackoverflow.com/questions/162331

  •  03-07-2019
  •  | 
  •  

Pregunta

Estoy desarrollando una aplicación dirigida a .NET Framework 2.0 con C # para la cual necesito poder encontrar la aplicación predeterminada que se usa para abrir un tipo de archivo en particular.

Sé que, por ejemplo, si solo desea abrir un archivo con esa aplicación, puede usar algo como:

System.Diagnostics.Process.Start( "C:\...\...\myfile.html" );

para abrir un documento HTML en el navegador predeterminado, o

System.Diagnostics.Process.Start( "C:\...\...\myfile.txt" );

para abrir un archivo de texto en el editor de texto predeterminado.

Sin embargo, lo que quiero poder hacer es abrir archivos que no tienen necesariamente una extensión .txt (por ejemplo), en el editor de texto predeterminado, por lo que debo estar capaz de averiguar la aplicación predeterminada para abrir archivos .txt , lo que me permitirá invocarla directamente.

Supongo que hay algunas API de Win32 que necesitaré P / Invoke para hacer esto, sin embargo, un vistazo rápido tanto de Google como de MSDN no reveló nada de mucho interés; Encontré una gran cantidad de páginas completamente irrelevantes, pero no hay nada como lo que estoy buscando.

¿Fue útil?

Solución

Puede consultar en la sección de registro HKEY_CLASSES_ROOT para obtener detalles sobre la extensión y la acción. La documentación para esto es en MSDN . Alternativamente, puede usar la interfaz IQueryAssociations .

Otros consejos

Todas las respuestas actuales no son confiables. El registro es un detalle de la implementación y, de hecho, ese código está roto en mi máquina con Windows 8.1. La forma correcta de hacerlo es mediante la API de Win32, específicamente AssocQueryString :

using System.Runtime.InteropServices;

[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern uint AssocQueryString(
    AssocF flags, 
    AssocStr str,  
    string pszAssoc, 
    string pszExtra, 
    [Out] StringBuilder pszOut, 
    ref uint pcchOut
); 

[Flags]
public enum AssocF
{
    None = 0,
    Init_NoRemapCLSID = 0x1,
    Init_ByExeName = 0x2,
    Open_ByExeName = 0x2,
    Init_DefaultToStar = 0x4,
    Init_DefaultToFolder = 0x8,
    NoUserSettings = 0x10,
    NoTruncate = 0x20,
    Verify = 0x40,
    RemapRunDll = 0x80,
    NoFixUps = 0x100,
    IgnoreBaseClass = 0x200,
    Init_IgnoreUnknown = 0x400,
    Init_Fixed_ProgId = 0x800,
    Is_Protocol = 0x1000,
    Init_For_File = 0x2000
}

public enum AssocStr
{
    Command = 1,
    Executable,
    FriendlyDocName,
    FriendlyAppName,
    NoOpen,
    ShellNewValue,
    DDECommand,
    DDEIfExec,
    DDEApplication,
    DDETopic,
    InfoTip,
    QuickTip,
    TileInfo,
    ContentType,
    DefaultIcon,
    ShellExtension,
    DropTarget,
    DelegateExecute,
    Supported_Uri_Protocols,
    ProgID,
    AppID,
    AppPublisher,
    AppIconReference,
    Max
}

Documentación relevante:

Uso de muestra:

static string AssocQueryString(AssocStr association, string extension)
{
    const int S_OK = 0;
    const int S_FALSE = 1;

    uint length = 0;
    uint ret = AssocQueryString(AssocF.None, association, extension, null, null, ref length);
    if (ret != S_FALSE)
    {
        throw new InvalidOperationException("Could not determine associated string");
    }

    var sb = new StringBuilder((int)length); // (length-1) will probably work too as the marshaller adds null termination
    ret = AssocQueryString(AssocF.None, association, extension, null, sb, ref length);
    if (ret != S_OK)
    {
        throw new InvalidOperationException("Could not determine associated string"); 
    }

    return sb.ToString();
}

Doh! Por supuesto.

HKEY_CLASSES_ROOT\.txt

incluye una referencia a

HKEY_CLASSES_ROOT\txtfile

que contiene una subclave

HKEY_CLASSES_ROOT\txtfile\shell\open\command

que hace referencia al Bloc de notas.

¡Ordenados, muchas gracias!

Bart

Aquí hay una publicación de blog con información sobre esto tema. Los ejemplos de código están en VB.net, pero debería ser fácil portarlos a C #.

Puedes consultar el registro. Primero obtenga la entrada predeterminada en HKEY_CLASSES_ROOT \ .ext

Eso te dará el nombre de clase. Por ejemplo .txt tiene un valor predeterminado de txtfile

Luego, abra HKEY_CLASSES_ROOT \ txtfile \ Shell \ Open \ Command

Eso te dará el comando predeterminado utilizado.

  

Una respuesta tardía, pero hay un buen paquete NUGET que maneja las asociaciones de archivos: Asociación de archivos

Asociación de archivos de enlace NUGET

El uso es simple, por ejemplo, para agregar todas las extensiones de archivo permitidas a un menú contextual:

private void OnMenuSourceFileOpening(object sender, ...)
{   // open a context menu with the associated files + ".txt" files
    if (File.Exists(this.SelectedFileName))
    {
        string fileExt = Path.GetExtension(this.SelectedFileNames);
        string[] allowedExtensions = new string[] { fileExt, ".txt" };
        var fileAssociations = allowedExtensions
            .Select(ext => new FileAssociationInfo(ext));
        var progInfos = fileAssociations
            .Select(fileAssoc => new ProgramAssociationInfo (fileAssoc.ProgID));
        var toolstripItems = myProgInfos
            .Select(proginfo => new ToolStripLabel (proginfo.Description) { Tag = proginfo });
        // add also the prog info as Tag, for easy access
        //  when the toolstrip item is selected
        // of course this can also be done in one long linq statement

        // fill the context menu:
        this.contextMenu1.Items.Clear();
        this.contextMenuOpenSourceFile.Items.AddRange (toolstripItems.ToArray());
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top