¿Cómo obtener el icono y la descripción de la extensión de archivo usando Delphi?
-
06-07-2019 - |
Pregunta
Básicamente tengo un TcxGrid que enumerará varios nombres de archivos y me gustaría dar más detalles en función de la extensión del archivo, específicamente su descripción (por ejemplo, para .PDF es '' Documento de Adobe Acrobat '') y su icono relacionado .
Noto que hay un muy similar pregunta ya pero está relacionada 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 C # anterior (obviamente en Delphi) sería genial.
Solución
Gracias a Rob Kennedy por señalarme en dirección a ShGetFileInfo. Luego busqué en Google y encontré estos dos ejemplos: Delphi 3000 , Torry's . A partir de eso, escribí la siguiente clase para hacer lo que necesitaba.
Además, justo cuando estaba terminando, la respuesta de Bill Miller me dio la última ayuda que necesitaba. Originalmente, estaba pasando los nombres completos de los archivos a ShGetFileInfo, que idealmente no era lo que quería. El ajuste sugirió pasar '' *. EXT '' fue genial.
La clase podría hacer más trabajo pero hace lo que necesito. Parece manejar extensiones de archivo que tampoco tienen detalles asociados.
Finalmente, en lo que estoy usando, lo cambié a usar una TcxImageList en lugar de una TImageList, ya que tenía problemas con los 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í hay una aplicación de prueba de ejemplo que lo usa, es muy simple, solo un formulario con un TPageControl. Mi uso real no era 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!
Otros consejos
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;
Llame a ShGetFileInfo
. Puede indicarle la descripción (el "tipo de nombre" en el vocabulario de esa función), y puede darle un identificador de icono o un identificador de 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 dice ShGetFileInfo
" puede ser lento " y llama al IExtractIcon
interfaz a "más flexible y eficiente" alternativa. Pero la secuencia que recomienda es usar un IShellFolder
, luego llame a GetUIObjectOf
para obtener la interfaz IExtractIcon
del archivo y luego llame a GetIconLocation
y Extracto
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, aún no tendría la descripción del tipo de archivo. Siga con ShGetFileInfo
hasta que la velocidad y la eficiencia se conviertan en un problema notable.
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;
No para sonar simplista, pero Google es tu amigo. Estos son algunos de los primeros resultados para " icono asociado de delphi " ;:
http://www.delphi3000.com/articles/article_453.asp? SK =
http://www.jpgriffiths.com/tutorial/Snippets%5Cgetassociatedicon.html
El otro método es buscar la extensión en el registro bajo HKEY_CLASSES_ROOT, luego seguir la clave en el valor predeterminado (si está disponible) y su valor predeterminado es la descripción. Este segundo nivel también es donde puede abrir los comandos de shell o imprimir el tipo de archivo, así como la ruta al icono predeterminado.
Aquí hay un par de buenos ejemplos del uso de ShGetFileInfo de bitwisemag.com: