2009-05-06 8 views
12

Fondamentalmente ho un TcxGrid che elencerà vari nomi di file e vorrei fornire ulteriori dettagli basati sull'estensione del file, in particolare la sua descrizione (ad esempio per .PDF è "Documento Adobe Acrobat") ed è un'icona correlata.Come ottenere icona e descrizione dall'estensione usando Delphi?

Noto che c'è uno very similar question already ma è correlato a C# e mi piacerebbe qualcosa basato su Delphi.

I suggerimenti su dove cercare questo tipo di informazioni sarebbero buoni e se c'è una classe simile a quella menzionata nel post C# sopra (ovviamente in Delphi) sarebbe fantastico.

risposta

17

Grazie a Rob Kennedy per me che punta nella direzione di SHGetFileInfo . Poi ho cercato su Google e ho trovato questi due esempi: Delphi 3000, Torry's. Da ciò ho scritto la seguente lezione per fare ciò di cui avevo bisogno.

Inoltre, proprio mentre stavo finendo la risposta di Bill Miller mi ha dato l'ultimo aiuto che mi serviva. Originariamente stavo passando nomi di file completi a ShGetFileInfo, che non era idealmente quello che volevo. Il tweak suggerito di passare "* .EXT" è stato grandioso.

La classe potrebbe fare più lavoro ma fa quello che mi serve.Sembra gestire le estensioni di file che non hanno alcun dettaglio associato.

Infine, in quello che sto usando l'ho passato a usare TcxImageList invece di TImageList, dato che avevo problemi con i bordi neri che apparivano sulle icone, perché era una soluzione rapida.

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. 

Anche qui è un app esempio test di usarlo, è molto semplice, basta un modulo con un TPageControl su di esso. Il mio uso effettivo non era per questo, ma per un Developer Express TcxImageComboxBox in 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. 

Grazie a tutti per le vostre risposte!

+0

Una nota: quando si passano nomi di file completi, le scorciatoie come '% 1' come scorciatoia per i file di icone o bitmap producono il risultato corretto per ogni file specifico. * .ext mostrerà solo un'icona generica in questi casi. – Martijn

+0

@Martijn, cosa intendi con '% 1'? Puoi mostrare un esempio? – pcunite

+0

@pcunite: ora vedo che il mio commento non è stato molto chiaro. In alcuni casi, "% 1" è definito come DefaultIcon per un tipo di file; questo di solito è il caso dei file '.ico': ogni file di icone contiene l'icona da visualizzare. In tal caso, l'utilizzo del nome completo produrrà l'icona corretta. Utilizzando solo l'estensione qui si otterrebbe un'icona 'generica'. – Martijn

1

Non sembrare rumoroso, ma Google è tuo amico. Qui ci sono un paio di primi risultati per "Delphi associati icona":

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

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

+0

Grazie Bruce per i suggerimenti, sfortunatamente non è esattamente quello che cercavo. Avevo anche la descrizione. Inoltre, ho solo pensato di provare StackOverflow, vedere quale esperienza Delphi ha, non penso che sia fatto troppo male! – Pauk

2

chiamata ShGetFileInfo. Può dirti la descrizione (il "nome tipo", nel vocabolario di quella funzione), e può darti un handle di icone, o un handle per l'elenco di immagini di sistema, dove risiede l'icona, o il percorso per il modulo che contiene la risorsa immagine. Quella funzione può fare molte cose diverse, quindi assicurati di leggere attentamente la documentazione.

MSDN saysShGetFileInfo "potrebbe essere lento" e chiama l'interfaccia IExtractIcon un'alternativa "più flessibile ed efficiente". Ma la sequenza che consiglia è di utilizzare un'interfaccia IShellFolder, quindi chiamare GetUIObjectOf per ottenere l'interfaccia IExtractIcon del file e quindi chiamare GetIconLocation e Extract su di esso per recuperare l'handle dell'icona.

Per quanto ne so, questo è esattamente ciò ShGetFileInfo fa in ogni caso, ma è molto più ingombrante, e dopo aver fatto tutto questo, ancora non avrebbe descrizione tipo di file. Rimanere con ShGetFileInfo fino a quando la velocità e l'efficienza diventano un problema evidente.

+0

Grazie Rob, questo mi ha indirizzato nella giusta direzione. – Pauk

0

L'altro metodo consiste nel cercare l'estensione nel registro in HKEY_CLASSES_ROOT, quindi seguire la chiave nel valore predefinito (se disponibile) e il valore predefinito è la descrizione. Questo secondo livello è anche il punto in cui è possibile aprire i comandi della shell o stampare il tipo di file e il percorso dell'icona predefinita.

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

Grazie Bill per entrambe le tue risposte. Ho notato che sei riuscito a passare solo l'estensione a SHGetFileInfo (stavo usando nomi di file completi) e quindi ho ottimizzato il mio codice di conseguenza. – Pauk