質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

1421閲覧

Windowsのエクスプローラー上のフォルダアイコンのサムネイルの変更方法(できればPythonで)

shiki980

総合スコア1

Windows 10

Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

1クリップ

投稿2022/10/23 15:15

前提

Windowsのエクスプローラーで表示されるフォルダ内のサムネイルを、Pythonを使って変更したいのですが、方法が分からないため教えていただきたいです。
(Windowsのエクスプローラーで、特大アイコン表示をすると以下のようにフォルダ内の画像がサムネイルとして表示されますが、画像が複数枚ある時にはランダムで画像が選択されるため、Pythonを使ってこの画像を指定したいです。)
イメージ説明

フォルダのプロパティからも手動で画像を指定できるのですが、指定したいフォルダの数が大量にあり、機械的に処理したいと思っています。
Python指定なのは私がPythonしか使えないためです。
ただ、他の言語等で解決策がある場合、そちらでもよいので教えていただけると幸いです。

調べたことなど

以下の、SHFOLDERCUSTOMSETTINGS構造体に含まれるpszLogoが、フォルダのサムネイル画像を指しているのだと思い、これを変更しようと試みました。
https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/ns-shlobj_core-shfoldercustomsettings

以下のコードを参考にして、pszLogoを書き換えるようなコードを書いて実行してみましたが、サムネイルは変化しませんでした。
https://stackoverflow.com/questions/4662759/how-to-change-folder-icons-with-python-on-windows
(上記コードはサムネイルではなくアイコン自体を書き換える処理です。一応、上記を実行するとアイコンの書き換えはできました)

実行したソースコード

python3

1import os 2import ctypes 3from ctypes import POINTER, Structure, c_wchar, c_int, sizeof, byref 4from ctypes.wintypes import BYTE, WORD, DWORD, LPWSTR, LPSTR 5import win32api 6 7HICON = c_int 8LPTSTR = LPWSTR 9TCHAR = c_wchar 10MAX_PATH = 260 11FCS_READ = 0x00000001 12FCSM_LOGO = 0x00000020 13FCSM_ICONFILE = 0x00000010 14FCS_FORCEWRITE = 0x00000002 15SHGFI_ICONLOCATION = 0x000001000 16 17class GUID(Structure): 18 _fields_ = [ 19 ('Data1', DWORD), 20 ('Data2', WORD), 21 ('Data3', WORD), 22 ('Data4', BYTE * 8)] 23 24class SHFOLDERCUSTOMSETTINGS(Structure): 25 _fields_ = [ 26 ('dwSize', DWORD), 27 ('dwMask', DWORD), 28 ('pvid', POINTER(GUID)), 29 ('pszWebViewTemplate', LPTSTR), 30 ('cchWebViewTemplate', DWORD), 31 ('pszWebViewTemplateVersion', LPTSTR), 32 ('pszInfoTip', LPTSTR), 33 ('cchInfoTip', DWORD), 34 ('pclsid', POINTER(GUID)), 35 ('dwFlags', DWORD), 36 ('pszIconFile', LPTSTR), 37 ('cchIconFile', DWORD), 38 ('iIconIndex', c_int), 39 ('pszLogo', LPTSTR), 40 ('cchLogo', DWORD)] 41 42class SHFILEINFO(Structure): 43 _fields_ = [ 44 ('hIcon', HICON), 45 ('iIcon', c_int), 46 ('dwAttributes', DWORD), 47 ('szDisplayName', TCHAR * MAX_PATH), 48 ('szTypeName', TCHAR * 80)] 49 50def setthumbnail(folderpath, thumbnailpath): 51 52 shell32 = ctypes.windll.shell32 53 54 folderpath = str(os.path.abspath(folderpath)) 55 thumbnailpath = str(os.path.abspath(thumbnailpath)) 56 57 fcs = SHFOLDERCUSTOMSETTINGS() 58 fcs.dwSize = sizeof(fcs) 59 fcs.dwMask = FCSM_LOGO 60 fcs.pszLogo = thumbnailpath 61 fcs.cchLogo = 0 62 63 hr = shell32.SHGetSetFolderCustomSettings(byref(fcs), folderpath, 64 FCS_FORCEWRITE) 65 66 if hr: 67 raise WindowsError(win32api.FormatMessage(hr)) 68 69 sfi = SHFILEINFO() 70 hr = shell32.SHGetFileInfoW(folderpath, 0, byref(sfi), sizeof(sfi), 71 SHGFI_ICONLOCATION) 72 if hr == 0: 73 raise WindowsError(win32api.FormatMessage(hr)) 74 75 index = shell32.Shell_GetCachedImageIndexW(sfi.szDisplayName, sfi.iIcon, 0) 76 if index == -1: 77 raise WindowsError() 78 79 shell32.SHUpdateImageW(sfi.szDisplayName, sfi.iIcon, 0, index) 80 81setthumbnail({対象フォルダのパス}, {.pngのパス})

setthumbnailで、icoファイルはbmpファイルを指定しても変化はありませんでした。

どなたかわかる方がいらっしゃいましたらご教示お願い致します。

teamikl👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

私の環境では win10/python3.10 で、WindowsError が出ますが、設定自体は正常に変更できました。
(追記: SHGetSetFolderCustomSettings 迄で変更可能だったので、関数内の後半は不要です)

イメージ説明

隠しファイルを表示する設定にして、対象フォルダ内のdesktop.ini ファイルの中身を確認してみてください。

Desktop.iniを使用してフォルダーをカスタマイズする方法

  • PathMakeSystemFolder (attrib +s FolderName コマンド) で
    対象フォルダをシステムフォルダに変更 (desktop.ini によるカスタマイズを有効にする)
  • desktop.ini を配置
  • エクスプローラー(explorer.exe) を再起動。キャッシュが影響しないように 設定変更を反映させるため再読込。

 追記: SHChangeNotify により設定変更を通知

フォルダプロパティのカスタマイズから変更した場合
フォルダー内の desktop.ini の [ViewState] セクション内の Logo に記録されます。
上記のスクリプトを用いた場合は [.ShellClassInfo] セクションの Logo に記録されます。

カスタマイズから変更した場合や、上記のスクリプト(win32 API)で変更した場合は即時反映されますが
desktop.ini ファイルをエディタで直接編集や、プログラムで直接編集した場合は即時反映されないようです。
(訂正: 恐らくキャッシュなどの影響 変更した設定は再読み込みまで反映されない)

追記: 設定の反映方法について、SHChangeNotify により通知できるようです。folderikonより、ctypesを用いた呼び出し例
https://github.com/demberto/FolderIkon/blob/master/folderikon/notify_shell.py


尚、できれば Python でとのことですが、ファイルを直接編集するコードの場合は
desktop.ini は 標準ライブラリの configparser モジュールにより扱うことができます。
より簡潔で解りやすいコードにできるはずです。

※ サムネイルではなくアイコンですが、desktop.ini を configparser で操作するコードの参考に。


ctypes でwin32 API を使う方法(質問に掲載のコードの方法) は、
同様のコードを書く場合は C言語で書いたほうが短くかけます。
(ctypes で扱う場合は、構造体館の宣言が必要ですが、C言語では必要なヘッダを読み込むのみ)

C言語と言うと、巨大な開発環境のインストールが必要そうに思われるかもしれませんが、
これくらいの規模のユーティリティーであれば、tcc (Tiny C Compiler) がお勧めです。
C 言語の学習コストがあるかもしれませんが、C言語で行う必要があるのは API 呼び出し部分のみなので
Python でフォルダーの一覧のループ処理をして、path 情報のみを C言語で作ったプログラムへ subprocess.call 等で渡す
といった使い方であれば、学習コストを必要最低限に抑えることができます。

投稿2022/10/24 03:41

編集2022/10/24 06:49
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shiki980

2022/10/26 12:46

反応が遅くなり申し訳ありません。 大変ご丁寧な回答、ありがとうございます。 SHGetSetFolderCustomSettingsはdesktop.iniを作成、編集していたんですね。 色々試した結果私の環境ではなぜか画像のパスに日本語や環境変数が含まれていると変更が反映されないようで、 それらを含まない相対パスを入力にするとスクリプト実行直後にサムネイルを変更することができました(元々絶対パスしか試していませんでした)。 結局Pythonによるiniファイルの修正作業等は不要でしたが、色々と詳しく補足情報も書いていただき、大変ありがとうございました。 また、今後win32 APIを使う機会があった場合、C言語での実装も検討してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問