2009-05-06 9 views
12

Básicamente tengo un TcxGrid que listará varios nombres de archivos y me gustaría dar más detalles basados ​​en la extensión del archivo, específicamente su descripción (por ejemplo, para .PDF es "Documento de Adobe Acrobat") y su icono relacionado.¿Cómo obtener el ícono y la descripción de la extensión de archivo usando Delphi?

Me di cuenta de que hay un very similar question already pero está relacionado con C# y me gustaría algo basado en Delphi.

Las sugerencias sobre dónde buscar este tipo de información serían buenas y si hay una clase similar a la mencionada en la publicación anterior de C# (obviamente en Delphi) sería genial.

Respuesta

17

Gracias a Rob Kennedy para señalarme en la dirección de SHGetFileInfo . Luego busqué en Google y encontré estos dos ejemplos: Delphi 3000, Torry's. De eso escribí la siguiente clase para hacer lo que necesitaba.

Además, justo cuando estaba terminando la respuesta de Bill Miller me brindó la última ayuda que necesitaba. Originalmente estaba pasando nombres completos de archivo a ShGetFileInfo, que no era idealmente lo que quería. El cambio sugerido de pasar "* .EXT" fue genial.

La clase podría funcionar con más trabajo pero hace lo que necesito.Parece manejar extensiones de archivos que tampoco tienen detalles asociados.

Finalmente, en lo que estoy usando, lo cambié a usar TcxImageList en lugar de TImageList, ya que tenía problemas con bordes negros que aparecían en los iconos, porque era una solución rápida.

unit FileAssociationDetails; 

{ 
    Created  : 2009-05-07 
    Description : Class to get file type description and icons. 
        * Extensions and Descriptions are held in a TStringLists. 
        * Icons are stored in a TImageList. 

        Assumption is all lists are in same order. 
} 

interface 

uses Classes, Controls; 

type 
    TFileAssociationDetails = class(TObject) 
    private 
    FImages : TImageList; 
    FExtensions : TStringList; 
    FDescriptions : TStringList; 
    public 
    constructor Create; 
    destructor Destroy; override; 

    procedure AddFile(FileName : string); 
    procedure AddExtension(Extension : string);  
    procedure Clear;  
    procedure GetFileIconsAndDescriptions; 

    property Images : TImageList read FImages; 
    property Extensions : TStringList read FExtensions; 
    property Descriptions : TStringList read FDescriptions; 
    end; 

implementation 

uses SysUtils, ShellAPI, Graphics, Windows; 

{ TFileAssociationDetails } 

constructor TFileAssociationDetails.Create; 
begin 
    try 
    inherited; 

    FExtensions := TStringList.Create; 
    FExtensions.Sorted := true; 
    FDescriptions := TStringList.Create; 
    FImages := TImageList.Create(nil); 
    except 
    end; 
end; 

destructor TFileAssociationDetails.Destroy; 
begin 
    try 
    FExtensions.Free; 
    FDescriptions.Free; 
    FImages.Free; 
    finally 
    inherited; 
    end; 
end; 

procedure TFileAssociationDetails.AddFile(FileName: string); 
begin 
    AddExtension(ExtractFileExt(FileName)); 
end; 

procedure TFileAssociationDetails.AddExtension(Extension : string); 
begin 
    Extension := UpperCase(Extension); 
    if (Trim(Extension) <> '') and 
    (FExtensions.IndexOf(Extension) = -1) then 
    FExtensions.Add(Extension); 
end; 

procedure TFileAssociationDetails.Clear; 
begin 
    FExtensions.Clear; 
end; 

procedure TFileAssociationDetails.GetFileIconsAndDescriptions; 
var 
    Icon: TIcon; 
    iCount : integer; 
    Extension : string; 
    FileInfo : SHFILEINFO; 
begin 
    FImages.Clear; 
    FDescriptions.Clear; 

    Icon := TIcon.Create; 
    try 
    // Loop through all stored extensions and retrieve relevant info 
    for iCount := 0 to FExtensions.Count - 1 do 
    begin 
     Extension := '*' + FExtensions.Strings[iCount]; 

     // Get description type 
     SHGetFileInfo(PChar(Extension), 
        FILE_ATTRIBUTE_NORMAL, 
        FileInfo, 
        SizeOf(FileInfo), 
        SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES 
        ); 
     FDescriptions.Add(FileInfo.szTypeName); 

     // Get icon and copy into ImageList 
     SHGetFileInfo(PChar(Extension), 
        FILE_ATTRIBUTE_NORMAL, 
        FileInfo, 
        SizeOf(FileInfo), 
        SHGFI_ICON or SHGFI_SMALLICON or 
        SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES 
        ); 
     Icon.Handle := FileInfo.hIcon; 
     FImages.AddIcon(Icon); 
    end; 
    finally 
    Icon.Free; 
    end; 
end; 

end. 

También aquí es una aplicación ejemplo de prueba de usarlo, es muy sencillo, basta con un formulario con un TPageControl en él. Mi uso real no fue para esto, sino para un Developer Express TcxImageComboxBox en un TcxGrid.

unit Main; 

{ 
    Created  : 2009-05-07 
    Description : Test app for TFileAssociationDetails. 
} 

interface 

uses 
    Windows, Forms, FileAssociationDetails, Classes, Controls, ComCtrls; 

type 
    TfmTest = class(TForm) 
    PageControl1: TPageControl; 
    procedure FormShow(Sender: TObject); 
    procedure FormClose(Sender: TObject; var Action: TCloseAction); 
    private 
    { Private declarations } 
    FFileDetails : TFileAssociationDetails; 
    public 
    { Public declarations } 
    end; 

var 
    fmTest: TfmTest; 

implementation 

{$R *.dfm} 

procedure TfmTest.FormShow(Sender: TObject); 
var 
    iCount : integer; 
    NewTab : TTabSheet; 
begin 
    FFileDetails := TFileAssociationDetails.Create; 
    FFileDetails.AddFile('C:\Documents and Settings\...\Test.XLS'); 
    FFileDetails.AddExtension('.zip'); 
    FFileDetails.AddExtension('.pdf'); 
    FFileDetails.AddExtension('.pas'); 
    FFileDetails.AddExtension('.XML'); 
    FFileDetails.AddExtension('.poo'); 

    FFileDetails.GetFileIconsAndDescriptions; 
    PageControl1.Images := FFileDetails.Images; 

    for iCount := 0 to FFileDetails.Descriptions.Count - 1 do 
    begin 
    NewTab := TTabSheet.Create(PageControl1); 
    NewTab.PageControl := PageControl1; 
    NewTab.Caption := FFileDetails.Descriptions.Strings[iCount]; 
    NewTab.ImageIndex := iCount; 
    end; 
end; 

procedure TfmTest.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
    PageControl1.Images := nil; 
    FFileDetails.Free; 
end; 

end. 

¡Gracias a todos por sus respuestas!

+0

Una nota: cuando se pasan nombres completos de archivos, los accesos directos como '% 1' como acceso directo a los archivos de iconos o mapas de bits producirán el resultado correcto para cada archivo específico. * .ext solo mostrará un icono genérico en tales casos. – Martijn

+0

@Martijn, ¿Qué quiere decir con el uso de '% 1'? ¿Puedes mostrar un ejemplo? – pcunite

+0

@pcunite: Ahora veo que mi comentario no fue muy claro. En algunos casos, "% 1" se define como DefaultIcon para un tipo de archivo; este suele ser el caso de los archivos '.ico': cada archivo de icono en sí contiene el ícono para mostrar. En tal caso, usar el nombre de archivo completo arrojará el ícono correcto. Usar solo la extensión aquí resultaría en un ícono 'genérico'. – Martijn

1

No suena nada fácil, pero Google es tu amigo. Aquí hay un par de los primeros resultados para "icono asociado delphi":

http://www.delphi3000.com/articles/article_453.asp?SK=

http://www.jpgriffiths.com/tutorial/Snippets%5Cgetassociatedicon.html

+0

Gracias Bruce por los indicadores, desafortunadamente eso no es exactamente lo que buscaba. Estaba buscando la descripción también. Además, pensé que probaría StackOverflow, veré qué experiencia tiene Delphi, ¡no creo que se haya hecho tan mal! – Pauk

2

llamada ShGetFileInfo. Puede indicarle la descripción (el "nombre de tipo" en el vocabulario de esa función), y puede proporcionarle un identificador de icono o un identificador a la lista de imágenes del sistema, donde reside el icono, o la ruta al módulo que contiene el recurso de imagen. Esa función puede hacer muchas cosas diferentes, así que asegúrese de leer la documentación cuidadosamente.

MSDN saysShGetFileInfo "puede ser lento" y llama a la interfaz IExtractIcon una alternativa "más flexible y eficiente". Pero la secuencia que recomienda es usar una interfaz IShellFolder, luego llamar al GetUIObjectOf para obtener la interfaz IExtractIcon del archivo, y luego llamar al GetIconLocation y Extract para recuperar el identificador del icono.

Por lo que sé, eso es exactamente lo que ShGetFileInfo hace de todos modos, pero es mucho más engorroso, y después de haber hecho todo eso, todavía no tendría la descripción del tipo de archivo. Quédese con ShGetFileInfo hasta que la velocidad y la eficiencia se conviertan en un problema notable.

+0

Gracias Rob, eso me apuntó en la dirección correcta. – Pauk

0

El otro método es buscar la extensión en el registro en HKEY_CLASSES_ROOT, luego seguir la clave en el valor predeterminado (si está disponible) y su configuración predeterminada es la predeterminada. Este segundo nivel es también donde puede obtener los comandos del shell para abrir, o imprimir el tipo de archivo, así como la ruta al icono predeterminado.

2
uses ShellAPI; 

var 
AExtension: string; 
AFileType: string;  
AListItem: TListItem; 
AFileInfo: TSHFileInfo; 
begin 
// get the extensions file icon 
AExtension := ExtractFileExt(FileName); 
if SHGetFileInfo(PChar('*' + AExtension), FILE_ATTRIBUTE_NORMAL, AFileInfo, SizeOf 
    (AFileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_USEFILEATTRIBUTES) <> 0 then 
    AIndex := AFileInfo.iIcon 
else 
    AIndex := -1; 
AListItem.ImageIndex := AIndex; 
// get extensions file info 
if SHGetFileInfo(PChar('*' + AExtension), FILE_ATTRIBUTE_NORMAL, Info, SizeOf(Info), 
    SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES) then 
    AFileType := AFileInfo.szTypeName; 
end; 
3
function GetGenericFileType(AExtension: string): string; 
{ Get file type for an extension } 
var 
    AInfo: TSHFileInfo; 
begin 
    SHGetFileInfo(PChar(AExtension), FILE_ATTRIBUTE_NORMAL, AInfo, SizeOf(AInfo), 
    SHGFI_TYPENAME or SHGFI_USEFILEATTRIBUTES); 
    Result := AInfo.szTypeName; 
end; 

function GetGenericIconIndex(AExtension: string): integer; 
{ Get icon index for an extension type } 
var 
    AInfo: TSHFileInfo; 
begin 
    if SHGetFileInfo(PChar(AExtension), FILE_ATTRIBUTE_NORMAL, AInfo, SizeOf(AInfo), 
    SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_USEFILEATTRIBUTES) <> 0 then 
    Result := AInfo.iIcon 
    else 
    Result := -1; 
end; 

function GetGenericFileIcon(AExtension: string): TIcon; 
{ Get icon for an extension } 
var 
    AInfo: TSHFileInfo; 
    AIcon: TIcon; 
begin 
    if SHGetFileInfo(PChar(AExtension), FILE_ATTRIBUTE_NORMAL, AInfo, SizeOf(AInfo), 
    SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_USEFILEATTRIBUTES) <> 0 then 
    begin 
    AIcon := TIcon.Create; 
    try 
     AIcon.Handle := AInfo.hIcon; 
     Result := AIcon; 
    except 
     AIcon.Free; 
     raise; 
    end; 
    end 
    else 
    Result := nil; 
end; 
+0

Gracias Bill por sus respuestas. Me di cuenta de que solo podías pasar la extensión a SHGetFileInfo (estaba usando nombres de archivo completos) y así pellizqué mi código en consecuencia. – Pauk

Cuestiones relacionadas