C#におけるCOMインターフェイスの呼び出しがうまくいかないです・・・
エクスプローラで表示されるサムネイルのイメージを取り出したく、IShellFolderインターフェイスをネットで幾つか調べ、試行錯誤しているのですがうまく動きません。
呼び出しているどのメソッドも動かないため、もしかしたらコーディング上の問題だけではなく、プロジェクトの設定や環境にも問題があるのか・・・と思うのですが何か御存知の方、教えて頂けないでしょうか。
呼び出したのは、BindToObject、GetUIObjectOf、ParseDisplayNameですが、どれもダメでした。
なおWin7 64bit環境だったのでAnyCPUをやめて32bitにしてみたりもしましたが、結果は変わりませんでした。
恐れ入りますがご教示頂けると幸いです。
static Guid IID_IExtractImage = new Guid("{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}");
// COMによりエクスプローラのサムネイル画像を取得するインターフェイスを実装
[ComImportAttribute()]
[GuidAttribute("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
interface IExtractImage
{
[PreserveSig()]
UInt32 GetLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszPathBuffer,
UInt32 cchMax, out UInt32 pdwPriority, ref SIZE prgSize, UInt32 dwRecClrDepth, ref IEIFLAG pdwFlags);
[PreserveSig()]
UInt32 Extract(out IntPtr phBmpThumbnail);
}
static Guid IID_IShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}");
[ComImportAttribute()]
[GuidAttribute("000214E6-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
interface IShellFolder
{
UInt32 BindToObject(IntPtr pidl, IntPtr pbc, [In] ref Guid riid, ref IntPtr ppvOut);
UInt32 BindToStorage(IntPtr pidl, IntPtr pbc, [In] ref Guid riid, IntPtr ppvOut);
[PreserveSig()]
UInt32 CompareIDs(Int32 lparam, IntPtr pidl1, IntPtr pidl2);
[PreserveSig()]
UInt32 CreateViewObject(IntPtr hwndOwner, [In] ref Guid riid, ref IntPtr ppv);
[PreserveSig()]
UInt32 EnumObjects(IntPtr hwndOwner, [MarshalAs(UnmanagedType.U4)] SHCONTF grfFlags, ref IntPtr ppenumIDLis);
[PreserveSig()]
//UInt32 GetAttributesOf(UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
// IntPtr[] apidl, ref SFGAO rgfInOut);
UInt32 GetAttributesOf(UInt32 cidl, IntPtr apidl, [MarshalAs(UnmanagedType.U4)] ref SFGAO rgfInOut);
[PreserveSig()]
UInt32 GetDisplayNameOf(IntPtr pidl, SHGDNF uFlags, out STRRET pName);
[PreserveSig()]
//UInt32 GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
// IntPtr[] apidl, [In] ref Guid riid, ref UInt32 rgfReserved, out IntPtr ppv);
UInt32 GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, ref IntPtr apidl, [In] ref Guid riid, ref UInt32 rgfReserved, ref IntPtr ppv);
[PreserveSig()]
UInt32 ParseDisplayName(IntPtr hwndOwner, IntPtr pbc, [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
ref IntPtr pchEaten, ref IntPtr pidl, ref UInt32 pdwAttributes);
[PreserveSig()]
UInt32 SetNameOf(IntPtr hwndOwner, IntPtr pidl, string pszName, SHGDNF uFlags, out IntPtr ppidlOut);
}
#region IShellFolder type definitions
[Flags]
enum SHCONTF: uint
{
SHCONTF_CHECKING_FOR_CHILDREN = 0x00010,
SHCONTF_FOLDERS = 0x00020,
SHCONTF_NONFOLDERS = 0x00040,
SHCONTF_INCLUDEHIDDEN = 0x00080,
SHCONTF_INIT_ON_FIRST_NEXT = 0x00100,
SHCONTF_NETPRINTERSRCH = 0x00200,
SHCONTF_SHAREABLE = 0x00400,
SHCONTF_STORAGE = 0x00800,
SHCONTF_NAVIGATION_ENUM = 0x01000,
SHCONTF_FASTITEMS = 0x02000,
SHCONTF_FLATLIST = 0x04000,
SHCONTF_ENABLE_ASYNC = 0x08000,
SHCONTF_INCLUDESUPERHIDDEN = 0x10000
}
[Flags]
enum SFGAO: uint
{
SFGAO_CANCOPY = 0x00000001,
SFGAO_CANMOVE = 0x00000002,
SFGAO_CANLINK = 0x00000004,
SFGAO_STORAGE = 0x00000008,
SFGAO_CANRENAME = 0x00000010,
SFGAO_CANDELETE = 0x00000020,
SFGAO_HASPROPSHEET = 0x00000040,
SFGAO_DROPTARGET = 0x00000100,
SFGAO_CAPABILITYMASK = 0x00000177,
SFGAO_SYSTEM = 0x00001000,
SFGAO_ENCRYPTED = 0x00002000,
SFGAO_ISSLOW = 0x00004000,
SFGAO_GHOSTED = 0x00008000,
SFGAO_LINK = 0x00010000,
SFGAO_SHARE = 0x00020000,
SFGAO_READONLY = 0x00040000,
SFGAO_HIDDEN = 0x00080000,
SFGAO_DISPLAYATTRMASK = 0x000FC000,
SFGAO_NONENUMERATED = 0x00100000,
SFGAO_NEWCONTENT = 0x00200000,
SFGAO_CANMONIKER = 0x00000000, //Not supported.
SFGAO_HASSTORAGE = 0x00000000, //Not supported.
SFGAO_STREAM = 0x00400000,
SFGAO_STORAGEANCESTOR = 0x00800000,
SFGAO_VALIDATE = 0x01000000,
SFGAO_REMOVABLE = 0x02000000,
SFGAO_COMPRESSED = 0x04000000,
SFGAO_BROWSABLE = 0x08000000,
SFGAO_FILESYSANCESTOR = 0x10000000,
SFGAO_FOLDER = 0x20000000,
SFGAO_FILESYSTEM = 0x40000000,
SFGAO_STORAGECAPMASK = 0x70C50008,
SFGAO_HASSUBFOLDER = 0x80000000,
SFGAO_CONTENTSMASK = 0x80000000,
SFGAO_PKEYSFGAOMASK = 0x81044000
}
enum SHGDNF: uint
{
SHGDN_NORMAL = 0,
SHGDN_INFOLDER = 0x1,
SHGDN_FOREDITING = 0x1000,
SHGDN_FORADDRESSBAR = 0x4000,
SHGDN_FORPARSING = 0x8000
}
enum STREET_TYPE: uint
{
STREET_OFFSET = 0x0001,
STREET_WSTR = 0x0000,
STREET_CSTR = 0x0002
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 4)]
struct STRRET_UNIONC
{
[FieldOffset(0)]
IntPtr pOleStr;
[FieldOffset(0)]
UInt32 uOffset;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.LPStr, SizeConst = 260)]
string pStr;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 4)]
struct STRRET_UNIONW
{
[FieldOffset(0)]
IntPtr pOleStr;
[FieldOffset(0)]
UInt32 uOffset;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.LPWStr, SizeConst = 260 / 2)]
string pStr;
}
[StructLayout(LayoutKind.Explicit, Pack = 4)]
struct STRRET {
//UInt32 uType;
[FieldOffset(0)]
STREET_TYPE uType;
// union start
[FieldOffset(4)]
STRRET_UNIONC uniC;
[FieldOffset(4)]
STRRET_UNIONW uniW;
// union end
}
class ShellApi
{
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
static extern int SHGetDesktopFolder(out IntPtr ppshf);
public static IShellFolder GetDesktopFolder()
{
IntPtr res = IntPtr.Zero;
SHGetDesktopFolder(out res);
return (IShellFolder)Marshal.GetTypedObjectForIUnknown(res, typeof(IShellFolder));
}
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern UInt32 SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] String pszName,
IntPtr pbc, out IntPtr ppidl, UInt32 sfgaoIn, out UInt32 psfgaoOut);
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern Int32 SHBindToObject(IShellFolder shell, IntPtr pidl, IntPtr pbc, ref Guid riid,
out IntPtr ppvOut);
}
public static Image GetThumbnailImage(string strFilePath)
{
IntPtr peaten = IntPtr.Zero;
IntPtr ppidl = IntPtr.Zero;
UInt32 iattr = 0;
IntPtr pbmp = IntPtr.Zero;
string strDir = strFilePath.Substring(0, strFilePath.LastIndexOf('\\')) + '\\';
string strFile = Path.GetFileName(strFilePath);
IShellFolder shell = null;
try
{
shell = ShellApi.GetDesktopFolder();
}
catch (Exception e)
{
}
//shell.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, strFile, ref peaten, ref ppidl, ref iattr); //うまく動かない
ShellApi.SHParseDisplayName(strFilePath, IntPtr.Zero, out ppidl, 0, out iattr); //うまく動かないため代用
IExtractImage ieimg = null;
peaten = IntPtr.Zero;
if (ppidl != IntPtr.Zero)
{
UInt32 rgfRes = 0;
IntPtr res = IntPtr.Zero;
shell.GetUIObjectOf(IntPtr.Zero, 1, ref ppidl, ref IID_IExtractImage, ref rgfRes, ref res); //うまく動かない
ieimg = (IExtractImage)Marshal.GetTypedObjectForIUnknown(res, typeof(IExtractImage)); //resがnullのため例外発生
//以下、例外発生のため未テスト
if (ieimg != null)
{
StringBuilder sb = new StringBuilder(1024);
SIZE size = new SIZE();
size.cx = 64;
size.cy = 64;
UInt32 priority = 0;
IEIFLAG flag = IEIFLAG.IEIFLAG_ORIGSIZE | IEIFLAG.IEIFLAG_SCREEN | IEIFLAG.IEIFLAG_ASPECT;
ieimg.GetLocation(sb, (UInt32)sb.Capacity, out priority, ref size, 32, ref flag);
ieimg.Extract(out pbmp);
Marshal.FreeCoTaskMem(ppidl);
}
}
Image image = null;
if (pbmp != null)
{
image = Image.FromHbitmap(pbmp);
}
if (shell != null)
{
Marshal.ReleaseComObject(shell);
}
if (ieimg != null)
{
Marshal.ReleaseComObject(ieimg);
}
return image;
}
参考にしたのは、以下のサイトなどです。ここに登録してまだ間もないためURLが2つまでしか引用できませんでした。。。
Re[4]: IExtractImageによるサムネイルの取得
Rewrite DirectoryInfo using IShellFolder
追記です。
教えて頂いた情報をもとにコードを修正しました。
それにより、ParseDisplayName()
、BindToObject()
がうまく動く様になったようです。しかし、GetUIObjectOf()
の最後の引数に結果が帰って来ず、nullのままです。
GetUIObjectOf()
の引数の取り方に誤りがあるでしょうか?もしくは何か不足があるでしょうか。
度々すみませんがおねがいいたしますm(__)m
☆Program.cs (未変更)
[STAThread]についてはそのままです。
static class Program
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new formMain());
}
}
☆メインフォーム
public partial class formMain : Form
{
public formMain()
{
InitializeComponent();
}
private void formMain_Load(object sender, EventArgs e)
{
pictureBox1.Image = Libs.Acrobat.AcrobatControl.GetThumbnailImage(@"D:Data\20150123-01.pdf");
}
☆IShellFolder定義と呼び出し
static Guid IID_IShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}");
[ComImportAttribute()]
[GuidAttribute("000214E6-0000-0000-C000-000000000046")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
interface IShellFolder
{
void ParseDisplayName(IntPtr hwndOwner, IntPtr pbc, [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
[In, Out] ref IntPtr pchEaten, out IntPtr pidl, [In, Out] ref UInt32 pdwAttributes);
IEnumIDList EnumObjects(IntPtr hwndOwner, [MarshalAs(UnmanagedType.U4)] SHCONTF grfFlags);
//[return: MarshalAs(UnmanagedType.Interface)]
void BindToObject(IntPtr pidl, IntPtr pbc, [In] ref Guid riid, out IntPtr ppv);
//[return: MarshalAs(UnmanagedType.Interface)]
object BindToStorage(IntPtr pidl, IntPtr pbc, [In] ref Guid riid, out IntPtr ppv);
[PreserveSig()]
UInt32 CompareIDs(Int32 lparam, IntPtr pidl1, IntPtr pidl2);
[return: MarshalAs(UnmanagedType.Interface)]
object CreateViewObject(IntPtr hwndOwner, [In] ref Guid riid);
//[PreserveSig()]
//UInt32 GetAttributesOf(UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
// IntPtr[] apidl, ref SFGAO rgfInOut);
[PreserveSig()]
UInt32 GetAttributesOf(UInt32 cidl, IntPtr apidl, [In, Out] [MarshalAs(UnmanagedType.U4)] ref SFGAO rgfInOut);
//[PreserveSig()]
//UInt32 GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
// IntPtr[] apidl, [In] ref Guid riid, ref UInt32 rgfReserved, out IntPtr ppv);
[PreserveSig()]
UInt32 GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, ref IntPtr apidl, [In] ref Guid riid, ref UInt32 rgfReserved, ref IntPtr ppv); //←☆☆これがまだちゃんと動かない
void GetDisplayNameOf(IntPtr pidl, SHGDNF uFlags, out STRRET pName);
[PreserveSig()]
void SetNameOf(IntPtr hwndOwner, IntPtr pidl, [MarshalAs(UnmanagedType.LPWStr)] string pszName,
SHGDNF uFlags, out IntPtr ppidlOut);
}
class ShellApi
{
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern int SHGetDesktopFolder(out IShellFolder ppshf);
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern UInt32 SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] String pszName,
IntPtr pbc, out IntPtr ppidl, UInt32 sfgaoIn, out UInt32 psfgaoOut);
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern Int32 SHBindToObject(IShellFolder shell, IntPtr pidl, IntPtr pbc, ref Guid riid,
out IntPtr ppvOut);
}
public static Image GetThumbnailImage(string strFilePath)
{
IntPtr peaten = IntPtr.Zero;
IntPtr ppidl = IntPtr.Zero;
UInt32 iattr = 0;
IntPtr pbmp = IntPtr.Zero;
string strDir = strFilePath.Substring(0, strFilePath.LastIndexOf('\\')) + '\\';
//string strFile = Path.GetFileName(strFilePath);
IShellFolder shell = null;
try
{
ShellApi.SHGetDesktopFolder(out shell);
}
catch (Exception e)
{
}
shell.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, strFilePath, ref peaten, out ppidl, ref iattr);
//ShellApi.SHParseDisplayName(strFilePath, IntPtr.Zero, out ppidl, 0, out iattr);
IExtractImage ieimg = null;
peaten = IntPtr.Zero;
if (ppidl != IntPtr.Zero)
{
UInt32 rgfRes = 0;
IntPtr res = IntPtr.Zero;
shell.GetUIObjectOf(IntPtr.Zero, 1, ref ppidl, ref IID_IExtractImage, ref rgfRes, ref res); //☆☆←どうしてもresの結果がnullのまま、うまくいかない
ieimg = (IExtractImage)Marshal.GetTypedObjectForIUnknown(res, typeof(IExtractImage));
if (ieimg != null)
{
StringBuilder sb = new StringBuilder(1024);
SIZE size = new SIZE();
size.cx = 64;
size.cy = 64;
UInt32 priority = 0;
IEIFLAG flag = IEIFLAG.IEIFLAG_ORIGSIZE | IEIFLAG.IEIFLAG_SCREEN | IEIFLAG.IEIFLAG_ASPECT;
ieimg.GetLocation(sb, (UInt32)sb.Capacity, out priority, ref size, 32, ref flag);
ieimg.Extract(out pbmp);
Marshal.FreeCoTaskMem(ppidl);
}
}
Image image = null;
if (pbmp != null)
{
image = Image.FromHbitmap(pbmp);
}
if (shell != null)
{
Marshal.ReleaseComObject(shell);
}
if (ieimg != null)
{
Marshal.ReleaseComObject(ieimg);
}
AcroPDFLib.AcroPDF pdf = new AcroPDF();
pdf.gotoNextPage();
return image;
}
}