2009-06-24 4 views
6

Est-il possible de modifier une icône de dossier Windows à l'aide d'un script Perl?Est-il possible de modifier une icône de dossier Windows à l'aide d'un script Perl?

Mon intention est de changer l'icône ordinaire du dossier "xxx_documents" en une autre icône. Je dois exécuter le script de telle sorte qu'il prenne soin de tout le lecteur.

Le lecteur contient plusieurs dossiers. Je dois rechercher chaque dossier nommé "documents" (par exemple "xxx_documents" ou simplement "documents") et changer son icône en un de la bibliothèque "%SystemRoot%\system32\SHELL32.dll".

Est-ce possible en Perl? Merci à tous ceux qui m'aident avec ça.

Répondre

8

Vous pouvez le faire avec Perl. Windows contrôle les icônes de répertoire en utilisant un fichier système caché Dekstop.ini dans chaque dossier. Le contenu ressemble à ceci:

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

Sous Windows XP (et je suppose sur d'autres systèmes), l'icône 41 est un arbre. Windows nécessite ce fichier être explicitement défini comme un système fichier pour que cela fonctionne, cela signifie que nous aurons besoin de creuser dans Win32API::File pour le créer:

#!/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 vous exécutez le code ci-dessus, il doit définir l'icône du répertoire courant vers un arbre. Vous devrez peut-être actualiser votre liste de répertoires avant que l'explorateur ne détecte la modification.

Maintenant que nous avons un moyen de changer les icônes, nous pouvons maintenant parcourir un lecteur entier et changer chaque dossier qui correspond à notre modèle. Nous pouvons le faire assez facilement avec File::Find, ou l'une de ses alternatives (par exemple, File::Find::Rule ou 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(); 
} 

Malheureusement, je viens de découvrir que l'icône ne se changé si le répertoire a actuellement , ou une fois, une icône ... Il y a clairement un attribut qui est placé sur le répertoire lui-même qui amène Windows à rechercher un fichier Desktop.ini, mais je ne peux pas, pour la vie de moi, comprendre ce que c'est. En tant que tel, la solution ci-dessus est incomplète; Nous devons également trouver et corriger les attributs du répertoire dans lequel nous ajoutons l'icône.

Paul

+3

Selon http://msdn.microsoft.com/en-us/library/cc144102.aspx, vous devez également définir l'attribut système sur le dossier contenant. – ephemient

+0

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

0

Pour obtenir l'icône pour rafraîchir, vous devrez invoquer un SHChangeNotify voodoo (C++ par exemple, mais vous voyez l'idée):

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 
Questions connexes