ショートカットファイルのJumboアイコン
投稿者 るきお  (社会人)
投稿日時
2020/6/11 18:23:37
ここのIronRazerzさんが投稿しているプログラムでexeやdllから大きいサイズのアイコンを取得できるようです。
https://social.msdn.microsoft.com/Forums/windows/en-US/a187f98b-9c16-455b-8e69-642f76447b7d/how-to-extract-large-icon-more-than-32-x-32-from-exe-and-dll?forum=vbgeneral
このサンプルはexeやdllなどが対象ですので、lnkは直接は対象にできないかもしれません。
その場合は、lnkのリンク先を取得してから、その上でこのサンプルを適用する形になると思います。
リンク先が xlsx や txt など単なるデータファイルの場合は、関連付けられたアプリケーションを取得した上で、このサンプルを適用する形になると思います。
https://social.msdn.microsoft.com/Forums/windows/en-US/a187f98b-9c16-455b-8e69-642f76447b7d/how-to-extract-large-icon-more-than-32-x-32-from-exe-and-dll?forum=vbgeneral
このサンプルはexeやdllなどが対象ですので、lnkは直接は対象にできないかもしれません。
その場合は、lnkのリンク先を取得してから、その上でこのサンプルを適用する形になると思います。
リンク先が xlsx や txt など単なるデータファイルの場合は、関連付けられたアプリケーションを取得した上で、このサンプルを適用する形になると思います。
投稿者 mayopee  (社会人)
投稿日時
2020/6/11 23:36:40
るきお様、いつもありがとうございます。
リンク先を拝見しましたが、自分の求めるものとは少し違うようです。
リンク先のは希望するサイズのアイコンが.EXEファイル等に含まれない場合、拡大して返却するもので
エクスプローラで表示されるアイコンとは異なります。
ショートカットのアイコンはオーバーレイアイコンになっていて、矢印の画像が左下にオーバーレイされています。矢印のオーバーレイがない、Jumboアイコン自体は最初に書いた通りIImageList::GetIconやMicrosoft.WindowsAPICodePackを使って取得できています。
わからないのは、ショートカットを表す矢印の画像の取得と、それをオーバーレイする方法です。
エクスプローラで表示されるアイコンと同じものが取得したいのです。
自分の説明がヘタクソで申し訳ありません。
リンク先を拝見しましたが、自分の求めるものとは少し違うようです。
リンク先のは希望するサイズのアイコンが.EXEファイル等に含まれない場合、拡大して返却するもので
エクスプローラで表示されるアイコンとは異なります。
ショートカットのアイコンはオーバーレイアイコンになっていて、矢印の画像が左下にオーバーレイされています。矢印のオーバーレイがない、Jumboアイコン自体は最初に書いた通りIImageList::GetIconやMicrosoft.WindowsAPICodePackを使って取得できています。
わからないのは、ショートカットを表す矢印の画像の取得と、それをオーバーレイする方法です。
エクスプローラで表示されるアイコンと同じものが取得したいのです。
自分の説明がヘタクソで申し訳ありません。
投稿者 mayopee  (社会人)
投稿日時
2020/6/12 07:38:47
一応、出来ました。るきお様に教えてもらったリンク先が参考になりました。
%windir%\System32\shell32.dllの中にショートカットの矢印アイコンが入っているので
そこからリンク先を参考にして矢印アイコンを抽出して、あらかじめ取得してあるJumboアイコンに
DrawImage/DrawIconすることで出来ました。
フォルダ内に大量のショートカットファイルがあり、それを列挙表示する場合には、速度的に無理があるかもしれません。
エクスプローラではスムーズに表示されるので、もっと別の方法があると思うのですが..........
まだ、もやもや感が残るので、解決マークは付けないでおきます。
%windir%\System32\shell32.dllの中にショートカットの矢印アイコンが入っているので
そこからリンク先を参考にして矢印アイコンを抽出して、あらかじめ取得してあるJumboアイコンに
DrawImage/DrawIconすることで出来ました。
フォルダ内に大量のショートカットファイルがあり、それを列挙表示する場合には、速度的に無理があるかもしれません。
エクスプローラではスムーズに表示されるので、もっと別の方法があると思うのですが..........
まだ、もやもや感が残るので、解決マークは付けないでおきます。
投稿者 (削除されました)  ()
投稿日時
2020/6/12 11:57:10
(削除されました)
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2020/6/12 14:09:25
> %windir%\System32\shell32.dllの中にショートカットの矢印アイコンが入っているので
#16769 に、7 サイズ (16x16~64x64) の 32bit アイコン含まれていますね。見落としていました。
#30 にある 2 サイズ (32x32, 16x16) の 4bit アイコンの方は発見していたのですが。
> 最初に書いた通りIImageList::GetIconやMicrosoft.WindowsAPICodePackを使って取得できています。
最初の投稿に Microsoft.WindowsAPICodePack の話は出てきてましたっけ。
自分も Microsoft.WindowsAPICodePack で試してはいたのですが、
なかなか期待する結果が得られていません…。
StockIcon から辿れば、linkOverlay が可能なようですが、Jumbo アイコンが使えない様子。
linkOverlay 無しで、矢印アイコンは後で合成するしかなさそうです。
FromParsingName メソッド → Thumbnail プロパティにて、 Jumbo アイコンを
取得できることは確認しましたが、こちらも単純にはいかず。
殆どのアイコンには透明部があり、時には半透明部も存在するはずですが、
Bitmap プロパティ経由だと背景が Transparent ではなく不透明 Black になってしまう罠。
BitmapSource プロパティで取得すれば、背景を透過した状態で得られますが、
それを WinForm から扱うには、追加の変換が必要になりました。
https://qiita.com/YSRKEN/items/a24bf2173f0129a5825c#bitmapsourcebitmap
WindowsAPICodePack に頼らず、全部 API で片づければ、
GDI+ や WPF を経由させずに済むのかも知れませんが、
API 実装は面倒なので試していません。
ただ、上記の FromParsingName → Thumbnail を使う方法だと、フォルダーのアイコンを
作成する際に、コンテンツを含んだ Stuffed Folder なアイコンにならないようで、
これもまだエクスプローラーと同じアイコン表示には至っていません。
#16769 に、7 サイズ (16x16~64x64) の 32bit アイコン含まれていますね。見落としていました。
#30 にある 2 サイズ (32x32, 16x16) の 4bit アイコンの方は発見していたのですが。
> 最初に書いた通りIImageList::GetIconやMicrosoft.WindowsAPICodePackを使って取得できています。
最初の投稿に Microsoft.WindowsAPICodePack の話は出てきてましたっけ。
自分も Microsoft.WindowsAPICodePack で試してはいたのですが、
なかなか期待する結果が得られていません…。
StockIcon から辿れば、linkOverlay が可能なようですが、Jumbo アイコンが使えない様子。
linkOverlay 無しで、矢印アイコンは後で合成するしかなさそうです。
FromParsingName メソッド → Thumbnail プロパティにて、 Jumbo アイコンを
取得できることは確認しましたが、こちらも単純にはいかず。
殆どのアイコンには透明部があり、時には半透明部も存在するはずですが、
Bitmap プロパティ経由だと背景が Transparent ではなく不透明 Black になってしまう罠。
BitmapSource プロパティで取得すれば、背景を透過した状態で得られますが、
それを WinForm から扱うには、追加の変換が必要になりました。
https://qiita.com/YSRKEN/items/a24bf2173f0129a5825c#bitmapsourcebitmap
Using sf = ShellObject.FromParsingName(lnk)
Dim tn = sf.Thumbnail
tn.FormatOption = ShellThumbnailFormatOption.IconOnly
'bmp = tn.ExtraLargeBitmap
bmpSrc = tn.ExtraLargeBitmapSource
End Using
WindowsAPICodePack に頼らず、全部 API で片づければ、
GDI+ や WPF を経由させずに済むのかも知れませんが、
API 実装は面倒なので試していません。
ただ、上記の FromParsingName → Thumbnail を使う方法だと、フォルダーのアイコンを
作成する際に、コンテンツを含んだ Stuffed Folder なアイコンにならないようで、
これもまだエクスプローラーと同じアイコン表示には至っていません。
投稿者 mayopee  (社会人)
投稿日時
2020/6/12 20:58:41
魔界の仮面弁士様、いつもありがとうございます。
>最初の投稿に Microsoft.WindowsAPICodePack の話は出てきてましたっけ。
言葉足らずで、申し訳ありません。Jumboアイコンは取得出来ているという意味で書きました。
WindowsAPICodePack以外にもIImageList::GetIconとIShellItemImageFactory::GetImageも試しています。
>殆どのアイコンには透明部があり、時には半透明部も存在するはずですが、
>Bitmap プロパティ経由だと背景が Transparent ではなく不透明 Black になってしまう罠。
そうなんです。WindowsAPICodePackでBitmapとして取得すると。。。
なのでBitmap取得後に「 bmp.MakeTransparent(Color.Black) 」を入れてました。が、ゴミが残ったり、
消えてほしくない黒が消えたりで、「なんだかなぁ」と思っていました。
魔界の仮面弁士様の投稿を読んで、自分も再度、WindowsAPICodePackでBitmapSourceとして取得してみました。
結果は同様の結果で、背景を透過したきれいな状態で取得できました。
WPF用に用意されたプロパティだと思っていましたがWinFormからでも利用できるのですね。
自分は以下のページを参考にさせていただき,拡張メソッドとして自作ライブラリに登録しました。
(内容はよくわかっていませんが............)
https://www.nuits.jp/entry/2016/10/17/181232
>API 実装は面倒なので試していません。
Win32APIやCOMインターフェースをVBから利用するのは面倒ですね。
めっきり使う事はなくなりましたがShell廻りを扱うと、どうしても必要な場面がでてきます。
その点、WindowsAPICodePackのようなライブラリを利用すると便利さがよくわかります。
でも、自分が知らないだけかもしれませんが、WindowsAPICodePackのリファレンスはどこかにあるのでしょうか?
自分はMicrosoftからの提供が終了した後から使っているので、もしご存知なら教えてください。
>最初の投稿に Microsoft.WindowsAPICodePack の話は出てきてましたっけ。
言葉足らずで、申し訳ありません。Jumboアイコンは取得出来ているという意味で書きました。
WindowsAPICodePack以外にもIImageList::GetIconとIShellItemImageFactory::GetImageも試しています。
>殆どのアイコンには透明部があり、時には半透明部も存在するはずですが、
>Bitmap プロパティ経由だと背景が Transparent ではなく不透明 Black になってしまう罠。
そうなんです。WindowsAPICodePackでBitmapとして取得すると。。。
なのでBitmap取得後に「 bmp.MakeTransparent(Color.Black) 」を入れてました。が、ゴミが残ったり、
消えてほしくない黒が消えたりで、「なんだかなぁ」と思っていました。
魔界の仮面弁士様の投稿を読んで、自分も再度、WindowsAPICodePackでBitmapSourceとして取得してみました。
結果は同様の結果で、背景を透過したきれいな状態で取得できました。
WPF用に用意されたプロパティだと思っていましたがWinFormからでも利用できるのですね。
自分は以下のページを参考にさせていただき,拡張メソッドとして自作ライブラリに登録しました。
(内容はよくわかっていませんが............)
https://www.nuits.jp/entry/2016/10/17/181232
<Runtime.CompilerServices.Extension>
Public Function ToBitmap(ByVal bitmapSource As BitmapSource, ByVal pixelFormat As Imaging.PixelFormat) As Bitmap
Dim width As Integer = bitmapSource.PixelWidth
Dim height As Integer = bitmapSource.PixelHeight
Dim stride As Integer = width * ((bitmapSource.Format.BitsPerPixel + 7) \ 8)
Dim ptr As IntPtr = IntPtr.Zero
Try
ptr = Marshal.AllocCoTaskMem(height * stride)
bitmapSource.CopyPixels(New Windows.Int32Rect(0, 0, width, height), ptr, height * stride, stride)
Using bitmap = New Bitmap(width, height, stride, pixelFormat, ptr)
Return New Bitmap(bitmap)
End Using
Finally
If ptr <> IntPtr.Zero Then Marshal.FreeCoTaskMem(ptr)
End Try
End Function
>API 実装は面倒なので試していません。
Win32APIやCOMインターフェースをVBから利用するのは面倒ですね。
めっきり使う事はなくなりましたがShell廻りを扱うと、どうしても必要な場面がでてきます。
その点、WindowsAPICodePackのようなライブラリを利用すると便利さがよくわかります。
でも、自分が知らないだけかもしれませんが、WindowsAPICodePackのリファレンスはどこかにあるのでしょうか?
自分はMicrosoftからの提供が終了した後から使っているので、もしご存知なら教えてください。
投稿者 mayopee  (社会人)
投稿日時
2020/6/14 18:13:54
一応、当初の目的である「Jumboアイコンにショートカットを示す矢印を表示する」という事は
達成できたので、解決とさせていただきます。
あれからも、他の方法を試していたのですが、解った事で、これかなというのがあったので、
情報共有の為、残しておきます。
(1)IImageListインターフェースに「SetOverlayImage/GetOverlayImage」という、いかにもというメソッドがある。
(試したのですが、引数の指定方法がわからず、断念しました。)
(2)矢印アイコンはIImageListからも取得できて、Win7ではIndex=4、Win10ではIndex=29に入っている。
これ以上、調査しても時間ばかり消費して、あまり益がないように思うので、これにて打ち止めにしたいと思います。
るきお様、魔界の仮面弁士様、どうもありがとうございました。
達成できたので、解決とさせていただきます。
あれからも、他の方法を試していたのですが、解った事で、これかなというのがあったので、
情報共有の為、残しておきます。
(1)IImageListインターフェースに「SetOverlayImage/GetOverlayImage」という、いかにもというメソッドがある。
(試したのですが、引数の指定方法がわからず、断念しました。)
(2)矢印アイコンはIImageListからも取得できて、Win7ではIndex=4、Win10ではIndex=29に入っている。
これ以上、調査しても時間ばかり消費して、あまり益がないように思うので、これにて打ち止めにしたいと思います。
るきお様、魔界の仮面弁士様、どうもありがとうございました。
投稿者 mayopee  (社会人)
投稿日時
2020/6/25 18:08:02
Stride は、4バイト境界に切り上げられるようで、上のBitmapSource=> Bitmapの変換で
間違いがあったので、訂正しておきます。
https://docs.microsoft.com/ja-jp/dotnet/api/system.drawing.imaging.bitmapdata.stride?view=dotnet-plat-ext-3.1
間違いがあったので、訂正しておきます。
https://docs.microsoft.com/ja-jp/dotnet/api/system.drawing.imaging.bitmapdata.stride?view=dotnet-plat-ext-3.1
<Runtime.CompilerServices.Extension>
Public Function ToBitmap(ByVal bitmapSource As BitmapSource, ByVal pixelFormat As Imaging.PixelFormat) As Bitmap
Dim width As Integer = bitmapSource.PixelWidth
Dim height As Integer = bitmapSource.PixelHeight
Dim stride As Integer = ((width * bitmapSource.Format.BitsPerPixel + 31) \ 32) * 4
Dim ptr As IntPtr = IntPtr.Zero
Try
ptr = Marshal.AllocCoTaskMem(height * stride)
bitmapSource.CopyPixels(New Windows.Int32Rect(0, 0, width, height), ptr, height * stride, stride)
Using bitmap = New Bitmap(width, height, stride, pixelFormat, ptr)
Return New Bitmap(bitmap)
End Using
Finally
If ptr <> IntPtr.Zero Then Marshal.FreeCoTaskMem(ptr)
End Try
End Function
ショートカットファイル(.lik)の48x48や256x256の大きいサイズのアイコンを取得する方法を教えてください。
System.DrawingのIcon.ExtractAssociatedIconメソッドで取得できるでのですが、既定値の32x32でしか取得できません。
これを、拡大するという手法は最終手段としたいので、他の方法を教えてほしいです。
又、https://stackoverflow.com/questions/28525925/get-icon-128128-file-type-c-sharpを参考にして
IImageList::GetIconも試しましたが、こちらではJumboアイコンは取得できますが、
ショートカットを示す矢印が表示されません。