Есть ли способ изменить значок папки Windows с помощью сценария Perl? - PullRequest
6 голосов
/ 24 июня 2009

Есть ли способ изменить значок папки Windows с помощью сценария Perl?

Мое намерение состоит в том, чтобы изменить обычный значок папки «xxx_documents» на другой значок. Я должен запустить скрипт так, чтобы он позаботился обо всем диске.

Диск содержит много папок. Я должен найти каждую папку с именем «документы» (например, «xxx_documents» или просто «документы») и изменить ее значок на один из библиотеки "%SystemRoot%\system32\SHELL32.dll".

Это возможно в Perl? Спасибо всем, кто помогает мне с этим.

Ответы [ 3 ]

8 голосов
/ 24 июня 2009

Вы уверены, что можете сделать это с Perl. Windows управляет значками каталогов, используя скрытый системный файл Dekstop.ini в каждой папке. Содержимое выглядит примерно так:

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

В Windows XP (и я полагаю, в других системах) значок 41 является деревом. Windows требует, чтобы этот файл был явно установлен как системный файл, чтобы он работал, это означает, что нам нужно покопаться в Win32API::File, чтобы создать его:

 #!/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();

Если вы запустите приведенный выше код, он должен установить значок для текущего каталога в виде дерева. Возможно, вам придется обновить список каталогов, прежде чем исследователь заметит изменения.

Теперь, когда у нас есть способ менять значки, теперь мы можем просто пройтись по целому диску и изменить каждую папку, соответствующую нашему шаблону. Мы можем сделать это довольно легко с помощью File::Find или одной из его альтернатив (например, File::Find::Rule или 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();
 }

К сожалению, я только что обнаружил, что значок only изменяется, если каталог в настоящее время имеет или когда-то имел значок ... Очевидно, в самом каталоге установлен атрибут, который вызывает Windows ищет файл Desktop.ini, но я не могу понять, что это такое. Таким образом, вышеуказанное решение является неполным; нам также нужно найти и исправить атрибуты в каталоге, куда мы добавляем значок.

Пол

2 голосов
/ 20 апреля 2011

1.

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

2

[.ShellClassInfo]
LocalizedResourceName=@%SystemRoot%\system32\shell32.dll,-21803
InfoTip=@%SystemRoot%\system32\shell32.dll,-12689
IconResource=%SystemRoot%\system32\imageres.dll,-3
0 голосов
/ 25 сентября 2009

Чтобы обновить значок, вам нужно вызвать некоторое SHChangeNotify voodoo (пример C ++, но вы поняли идею):

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...