

エクスプローラで表示されるサムネイルのイメージを取り出したく、IShellFolderインターフェイスをネットで幾つか調べ、試行錯誤しているのですがうまく動きません。  
呼び出しているどのメソッドも動かないため、もしかしたらコーディング上の問題だけではなく、プロジェクトの設定や環境にも問題があるのか・・・と思うのですが何か御存知の方、教えて頂けないでしょうか。  
呼び出したのは、BindToObject、GetUIObjectOf、ParseDisplayNameですが、どれもダメでした。

なおWin7 64bit環境だったのでAnyCPUをやめて32bitにしてみたりもしましたが、結果は変わりませんでした。  
恐れ入りますがご教示頂けると幸いです。

[code]

    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;
        }
    
[/code]

参考にしたのは、以下のサイトなどです。ここに登録してまだ間もないためURLが2つまでしか引用できませんでした。。。

[Re[4]:
IExtractImageによるサムネイルの取得](http://bbs.wankuma.com/index.cgi?mode=al2&namber=3122&KLOG=12)  
[Rewrite DirectoryInfo using
IShellFolder](http://www.codeproject.com/Articles/39224/Rewrite-DirectoryInfo-
using-IShellFolder)

* * *

追記です。  
教えて頂いた情報をもとにコードを修正しました。  
それにより、`ParseDisplayName()`、`BindToObject()`がうまく動く様になったようです。しかし、`GetUIObjectOf()`の最後の引数に結果が帰って来ず、nullのままです。  
`GetUIObjectOf()`の引数の取り方に誤りがあるでしょうか？もしくは何か不足があるでしょうか。  
度々すみませんがおねがいいたしますm(__)m

☆Program.cs (未変更)  
[STAThread]についてはそのままです。

[code]

    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new formMain());
        }
    }
    
[/code]

☆メインフォーム

[code]

    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");
        }
    
[/code]

☆IShellFolder定義と呼び出し

[code]

        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;
        }
    }
    
[/code]


CC BY-SA 3.0
2015-02-04T16:19:57.460
5954
2015-02-10T10:19:33.343
2015-02-10T01:52:15.213
49
7966
question
c# com pinvoke
C#におけるCOMインターフェイスの呼び出しがうまくいかないです・・・


動作確認は、行っていませんが恐らく、STA以外のスレッドからCOMにアクセスしているためです。  
一部のCOMオブジェクトは、STAスレッドからアクセスする必要があります。

[STAThread] 属性をMainメソッド(エントリポイント)に指定する必要があります。  
また非同期操作などを行っている場合、UIスレッド、すなわちSTAスレッド上でCOMを操作しなければなりません。


CC BY-SA 3.0
2015-02-04T18:50:44.180
5958
2015-02-04T18:50:44.180
2207
5954
answer


COMにはIUknownから直接派生するものとIDispatch（これ自体もIUknownからの派生ですが）から派生するものの２種類があります。挙げられたコードでも`[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]`と指定されているものがIUnknownなわけです。  
で、IUnknownから派生する場合、呼び出しにはメソッド名は使われずに先頭から何番目のメソッドを呼び出したかで処理されます。ですので、C#上でのinterface宣言の順序が重要になってきます。ちなみにIDispatchの場合、IUnknownと同じく先頭からの順序とすることもできますが、それとは別にメソッド名での呼び出しもできます。

さて、Visual
StudioのC++インクルードファイルディレクトリの拡張子.IDLファイルにはCOMインターフェースの宣言がされています。検索するとIExtractImageもIShellFolderもShObjIdl.idlファイルで見つかります。見比べるとIShellFolderの方が順序が記載のコードと異なっています。（[call_as]の付いている関数は読み飛ばしてください。）

これだけでは解決しないと思いますが１つずつ進めていく必要があると思います。

* * *

レジストリエディタで検索するとわかりますが、例えばIShellFolder
{000214E6-0000-0000-C000-000000000046}の場合

>
> HKEY_CLASSES_ROOT\Interface\{000214E6-0000-0000-C000-000000000046}\ProxyStubClsid32  
>  (Default) = "{C90250F3-4D7D-4991-9B69-A5C5BC1C2AE6}"  
>
> HKEY_CLASSES_ROOT\CLSID\{C90250F3-4D7D-4991-9B69-A5C5BC1C2AE6}\InProcServer32  
>  ThreadingModel = "Both"

となっています。BothはSTAスレッドでもMTAスレッドでも動作可能なことを意味します。IExtractImageも同様です。`[STAThread]`を指定すれば何でも解決するわけではありません。

* * *

挙げられたコードはSIZEの宣言がないなどのため実行しての確認はしていませんが、パッと見でもう１点  
SHGetDesktopFolder()のC宣言は

[code]

    HRESULT SHGetDesktopFolder(_Out_  IShellFolder **ppshf);
    
[/code]

ですので、C#では

[code]

    [DllImport("shell32.dll")]
    static extern int SHGetDesktopFolder(out IShellFolder ppshf);
    
[/code]

とできます。（この関数では文字列を扱いませんが、C#におけるCharSet.AutoはANSIすなわちShift-
JISを指すのでUnicodeの方がいいでしょう。）

* * *

通常ですと[Reference
Source](http://referencesource.microsoft.com/)を参照するとよく使われるCOMインターフェースについては.NET内部でも宣言されたものが見つかり参考になるのですが…が…が、IShellFolderに関しては.NET内部でも誤った宣言がなされていて一部動作しませんのでお気を付けを。（少なくともGetUIObjectOf()とGetDisplayNameOf()は壊れています。）

* * *

あまり必要ないかもしれませんが…

> [PreserveSig()]  
>  UInt32 GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, ref IntPtr apidl, [In]
> ref Guid riid, ref UInt32 rgfReserved, ref IntPtr ppv); //←☆☆これがまだちゃんと動かない
>
> static Guid IID_IExtractImage = new
> Guid("{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}");
>
> 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));

追記されたコードは（cidl=1に限り）動作しました。表示できないのはファイルの関連付けなど別要因と思われます。蛇足ですが、

[code]

    // 最後の引数がoutの場合、戻り値にできる
    // COMポインターはIUknownなobject型にマーシャリング可能
    // Guid構造体に限りUnmanagedType.LPStructが使える
    [return: MarshalAs(UnmanagedType.IUnknown)]
    object GetUIObjectOf(IntPtr hwndOwner, UInt32 cidl, ref IntPtr apidl, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, ref UInt32 rgfReserved);
    
    // COMオブジェクトの型キャストはCOMのQueryInterfaceに相当する
    // Type.GUIDでGuidAttributeの値が取得できる
    // またrefでなくしたのでいったん変数に置く必要がなくなる
    ieimg = (IExtractImage)shell.GetUIObjectOf(IntPtr.Zero, 1, ref ppidl, typeof(IExtractImage).GUID, ref rgfRes, ref res);
    
[/code]

とできます。  
.NET Frameworkクラスライブラリ内においてもこの辺りのテクニックを把握していないと思われるコードがちょくちょくあります。


CC BY-SA 3.0
2015-02-04T23:47:51.663
5959
2015-02-10T04:02:26.247
2020-06-17T08:14:45.997
-1
4236
5954
answer


Vista以降で問題が無いのであれば、[WindowsAPICodePack](https://www.nuget.org/packages/WindowsAPICodePack-
Shell/)の`ShellThumbnail`クラスや内部で使用されているCOMインターフェイスの`IShellItemImageFactory`を利用してはいかがでしょうか。ソースコードは[GitHub](https://github.com/aybe/Windows-
API-Code-Pack-1.1)等で入手できます。

[code]

    public static Image GetThumbnailImage(string strFilePath)
    {
        var item = ShellObject.FromParsingName(strFilePath);
        item.Thumbnail.FormatOption = ShellThumbnailFormatOption.IconOnly;
        return item.Thumbnail.MediumBitmap;
    }
    
[/code]


CC BY-SA 3.0
2015-02-05T13:42:17.840
6013
2015-02-09T10:21:06.450
2015-02-09T10:21:06.450
5750
5750
5954
answer


質問に追記されていた`GetUIObjectOf`について調べてみました。WindowsAPICodePackを使うとのことなので、ここではなるべく前提知識なしで読めるように書きます。

`ParseDisplayName`はパスを文字列で指定すると`ITEMIDLIST`という形にしてくれるわけですが、`GetUIObjectOf`に指定する`apidl`は、そのフォルダに存在するファイル名である必要があります。なので質問に書かれている掲示板でも、一度対象ファイルの親フォルダを取得して、その上でファイル名に対応する`ITEMIDLIST`を取得して`GetUIObjectOf`、といった二段構えになっています。

質問主さんのコードの場合、フルパスをそのまま`ITEMIDLIST`にしていますから、これをそのまま`GetUIObjectOf`に使うことはできません。

またWindowsAPICodePackでは`IShellItemImageFactory`という別のインターフェイスを使っています。`SHCreateItemFromParsingName`でフルパスから直接作ることができますし、Vista以降のキャッシュ機能も活かされるので、これが使えるならその方がよいでしょう。  
（同じようにして`IExtractImage`が取得できないかと思いましたが、`E_NOINTERFACE`でした）

参考  
<http://pg-torch-ic.jugem.jp/?eid=31>  
<http://d.hatena.ne.jp/opossamu/20110328/1301345961>  
<http://eternalwindows.jp/shell/shellname/shellname04.html>


CC BY-SA 3.0
2015-02-10T05:55:52.657
6237
2015-02-10T10:19:33.343
2015-02-10T10:19:33.343
8000
8000
5954
answer