2009-06-24 13 views
6

¿Hay alguna manera de cambiar el icono de una carpeta de Windows con un script de Perl?¿Hay alguna forma de cambiar el icono de una carpeta de Windows con un script de Perl?

Mi intención es cambiar el icono ordinario de la carpeta "xxx_documents" por otro icono. Tengo que ejecutar el script de tal manera que cuide toda la unidad.

El disco contiene muchas carpetas. Tengo que buscar cada carpeta llamada "documentos" (por ejemplo, "xxx_documents" o simplemente "documentos") y cambiar su icono por uno de la biblioteca "%SystemRoot%\system32\SHELL32.dll".

¿Es posible en Perl? Gracias a todos los que me ayudaron con esto.

Respuesta

8

Seguro que puedes hacerlo con Perl. Windows controla los iconos del directorio mediante el uso de un archivo oculto del sistema Dekstop.ini en cada carpeta. El contenido se ve más o menos así:

[.ShellClassInfo] 
IconFile=%SystemRoot%\system32\SHELL32.dll 
IconIndex=41 

En Windows XP (y supongo que en otros sistemas), el icono 41 es un árbol. Windows requiere este archivo se establece explícitamente como un archivo sistema para que funcione, esto significa que tendremos que cavar hacia abajo en Win32API::File para crearlo:

#!/usr/bin/perl 
use strict; 
use warnings; 

use Win32API::File qw(createFile WriteFile fileLastError CloseHandle); 

my $file = createFile(
     'Desktop.ini', 
     { 
      Access  => 'w',  # Write access 
      Attributes => 'hs',  # Hidden system file 
      Create  => 'tc',  # Truncate/create 
     } 
) or die "Can't create Desktop.ini - " . fileLastError(); 

WriteFile(
     $file, 
     "[.ShellClassInfo]\r\n" . 
     "IconFile=%SystemRoot%\\system32\\SHELL32.dll\r\n" . 
     "IconIndex=41\r\n", 
     0, [], [] 
) or die "Can't write Desktop.ini - " . fileLastError(); 

CloseHandle($file) or die "Can't close Desktop.ini - " . fileLastError(); 

Si ejecuta el código anterior, se debe establecer el ícono para el directorio actual a un árbol. Es posible que deba actualizar su listado de directorios antes de que el explorador recoja el cambio.

Ahora que tenemos una forma de cambiar los iconos, ahora podemos simplemente recorrer toda una unidad y cambiar cada carpeta que coincida con nuestro patrón. Podemos hacer esto con bastante facilidad con File::Find, o una de sus alternativas (por ejemplo, File::Find::Rule, o File::Next):

#!/usr/bin/perl 
use strict; 
use warnings; 
use File::Find qw(find); 
use Win32API::File qw(createFile WriteFile fileLastError CloseHandle); 

my $topdir = $ARGV[0] or die "Usage: $0 path\n"; 

find(\&changeIcon, $topdir); 

sub changeIcon { 
    return if not /documents$/i; # Skip non-documents folders 
    return if not -d;    # Skip non-directories. 

    my $file = createFile(
     "$_\\Desktop.ini", 
     { 
       Access  => 'w',  # Write access 
       Attributes => 'hs',  # Hidden system file 
       Create  => 'tc',  # Truncate/create 
     } 
    ) or die "Can't create Desktop.ini - " . fileLastError(); 

    WriteFile(
     $file, 
     "[.ShellClassInfo]\r\n" . 
     "IconFile=%SystemRoot%\\system32\\SHELL32.dll\r\n" . 
     "IconIndex=41\r\n", 
     0, [], [] 
    ) or die "Can't write Desktop.ini - " . fileLastError(); 

    CloseHandle($file) or die "Can't close Desktop.ini - " . fileLastError(); 
} 

Por desgracia, sólo he descubierto que el icono solamente se cambia si el directorio tiene actualmente , o una vez lo había hecho, un ícono ... Claramente, hay un atributo que se está configurando en el directorio mismo que hace que Windows busque un archivo Desktop.ini, pero no puedo darme cuenta de qué se trata. Como tal, la solución anterior está incompleta; también necesitamos encontrar y corregir los atributos en el directorio donde estamos agregando el ícono.

Paul

+3

De acuerdo con http://msdn.microsoft.com/en-us/library/cc144102.aspx también necesita establecer el atributo del sistema en la carpeta que contiene. – ephemient

+0

http://www.google.com/search?btnI=&q=%22Customizing+Folders+with+Desktop.ini%22 –

0

Para obtener el icono para actualizar, tendrá que recurrir a algún vudú SHChangeNotify (C++ ejemplo, pero usted consigue la idea):

int imageIndex = Shell_GetCachedImageIndexW(wPath, GetSyncFolderIconIndex(), 0); 
if (imageIndex != -1) 
{ 
    // If we don't do this, and we EVER change our icon, Explorer will likely keep 
    // using the old one that it's already got in the system cache. 
    SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD | SHCNF_FLUSHNOWAIT, &imageIndex, NULL); 
} 
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wPath, NULL); 
2

1.

[.ShellClassInfo] 
[email protected]%SystemRoot%\system32\shell32.dll,-21790 
[email protected]%SystemRoot%\system32\shell32.dll,-12689 
IconResource=%SystemRoot%\system32\imageres.dll,-108 
IconFile=%SystemRoot%\system32\shell32.dll 
IconIndex=-237 

2.

[.ShellClassInfo] 
[email protected]%SystemRoot%\system32\shell32.dll,-21803 
[email protected]%SystemRoot%\system32\shell32.dll,-12689 
IconResource=%SystemRoot%\system32\imageres.dll,-3 
Cuestiones relacionadas