2016-11-06 6 views
0

今までインターフェイスについて何も知らなかったので、実際にはthis questionに与えられたソリューションを実装しようとするのは非常に困難です。インターフェイスポインタからインターフェイス/オブジェクトを取得する正しい方法はありますか?

私はIShellFolderインターフェイスへのポインタを正しく取得していると思いますが、実際にそのポインタを使用できないようです。そのポインタを持つときに、どのように使用可能なインターフェイスに到達するのですか?

以下のコードは、私がやっていることとどこで問題が疑わしいかを示しています。

まず、私のインタフェースdelarations

' I have wrapped the interfaces in their own namespace, "BinarusShell". 
' I have declared every interface's functions/subs in the same order as they are in the .idl files of the Windows Platform SDK 7.1. 
' Every function/sub has the <PreserveSig()> attribute so that I can see the native return values when debugging. 
' I'd like to keep the question as lean as possible, so I am showing only a few functions per interface. 
' Of course, I have implemented all of them (as they are in the respective .idl file). 

Namespace BinarusShell 

    <ComImport()> _ 
    <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _ 
    <Guid("000214FA-0000-0000-C000-000000000046")> _ 
    Public Interface IExtractIcon 

    ' The above GUID is the GUID for the UNICODE version of the interface, i.e. IExtractIconW. 
    ' Therefore, the UNICODE variant of strings is used in the parameters of the following functions. 
    ' See also the include files of the Windows SDK where this is done exactly that way as well. 

    <PreserveSig()> Function GetIconLocation(ByVal uFlags As UInteger, 
              <MarshalAs(UnmanagedType.LPWStr, SizeParamIndex:=2)> ByVal pszIconFile As String, 
              ByVal cchmax As UInteger, 
              ByRef piIndex As Integer, 
              ByRef pwFlags As UInteger) As Integer 

    ' ... 
    ' Here comes the second function (IExtractIcon has only two) ... 
    ' ...  

    End Interface 

    <ComImport()> _ 
    <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _ 
    <Guid("000214E6-0000-0000-C000-000000000046")> _ 
    Public Interface IShellFolder 

    <PreserveSig()> Function GetUIObjectOf(<[In]()> ByVal hwndOwner As IntPtr, 
              <[In]()> ByVal cidl As UInteger, 
              <[In]()> <MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal apidl() As IntPtr, 
              <[In]()> <MarshalAs(UnmanagedType.LPStruct)> ByVal riid As Guid, 
              <[In](), Out()> ByRef rgfReserved As UInteger, 
              <Out()> ByRef ppv As IntPtr) As Integer 

    ' ... 
    ' Here come the other functions ... 
    ' ... 

    End Interface 

End Namespace 

第二に、私ののWindows APIの宣言、および 第三は、機能は、私は(私は立ち往生午前ところ、これがある)を実装する:

' The Windows API declarations are in class Win32Api. 
' This class is not wrapped in a certain namespace. 
' To keep this question as lean as possible, I am leaving out my declarations of constants or GUIDs. 
' I have taken all of them literally from the Windows Platform SDK 7.1. 

Public Class Win32Api 

    <DllImport("shell32.dll", CharSet:=CharSet.Auto)> _ 
    Private Shared Function SHBindToParent(<[In]()> ByVal pidl As IntPtr, 
             <[In]()> <MarshalAs(UnmanagedType.LPStruct)> ByVal riid As Guid, 
             <Out()> ByRef ppv As IntPtr, 
             <Out()> ByRef ppidlLast As IntPtr) As Integer 
    End Function 

    <DllImport("shell32.dll", CharSet:=CharSet.Auto)> _ 
    Private Shared Function SHGetKnownFolderIDList(<[In]()> <MarshalAs(UnmanagedType.LPStruct)> ByVal rfid As Guid, 
               <[In]()> ByVal dwFlags As UInteger, 
               <[In]()> ByVal hToken As IntPtr, 
               <Out()> ByRef ppidl As IntPtr) As Integer 
    End Function 

' ----------------------------------------------------- 

' The function I would like to implement is in class Win32Api as well. 
' The function at this stage does nothing which is useful for the outer world; 
' It is just meant for code which I am stepping through with the debugger. 
' The comments below show the result of every step and my understanding about what has happened. 

    Public Shared Function IconTest() As Boolean 

    Dim ui_ReturnFlags As UInteger 
    Dim i_Result As Integer 
    Dim intptr_CurrentPidlAbsolute As IntPtr, 
     intptr_ParentIShellFolder As IntPtr, 
     intptr_CurrentIExtractIcon As IntPtr 
    Dim arintptr_RelPidList(0) As IntPtr 
    Dim ishellfolder_Parent As BinarusShell.IShellFolder 
    Dim iextracticon_Extractor As BinarusShell.IExtractIcon 

    i_Result = SHGetKnownFolderIDList(FOLDERID_System, 0, 0, intptr_CurrentPidlAbsolute) 
    ' The above seems to work. i_Result is 0 which means success, and 
    ' intptr_CurrentPidlAbsolute has a reasonable value now. 

    i_Result = SHBindToParent(intptr_CurrentPidlAbsolute, IID_IShellFolder, intptr_ParentIShellFolder, arintptr_RelPidList(0)) 
    ' The above seems to work. i_Result is 0 which means success, and 
    ' intptr_ParentIShellFolder and arintptr_RelPidList(0) have reasonable values now. 

    ' Now the PROBLEMS begin. I have no clue how to get an interface/object 
    ' from intptr_ParentIShellFolder which I can use from within VB.net. 
    ' Therefore, I just have tried the following (but believing that it is wrong): 
    ishellfolder_Parent = DirectCast(Marshal.GetObjectForIUnknown(intptr_ParentIShellFolder), BinarusShell.IShellFolder) 
    ' This does not throw an error, but I have no clue what actually is happening. 
    ' Marshal.GetObjectForIUnknown, as the name implies, should return an object which 
    ' encapsulates an IUnknown interface, but I am giving a pointer to an IShellFolder 
    ' interface, so I really wonder why it doesn't freak out. The original idea 
    ' to try it that way was that I believe that IShellFolder inherits IUnknown, 
    ' so it *eventually* could work that way. Could somebody comment about that? 

    i_Result = ishellfolder_Parent.GetUIObjectOf(0, 1, arintptr_RelPidList, IID_IExtractIcon, ui_ReturnFlags, intptr_CurrentIExtractIcon) 
    ' Now this is the point where I am completely puzzled. i_Result is still 0, 
    ' which means success, but intptr_CurrentIExtractIcon is 0 as well, meaning 
    ' that something has gone horribly wrong. According to my understanding of 
    ' the MSDN documentation, GetUIObjectOf MUST NOT return S_OK if something 
    ' has gone wrong; in other words, if it returns S_OK, then intptr_CurrentIExtractIcon 
    ' MUST be set to a reasonable value. Could somebody explain what's happening? 

    ' I have left out the rest of the function because it wouldn't make any sense 
    ' to use the NULL pointer for any further action. 

    End Function 

End Class 

私が間違っていることは何ですか?ドキュメントから、私はのすべてフォルダ項目(仮想かどうか)とファイルがIExtractIconを公開しているという印象を受けました。

+0

Marshal.GetTypedObjectForIUnknown()。あなたが実行可能なコードを投稿していないときに誰かがあなたのためにそれをデバッグするつもりはないと思う。 –

+0

@HansPassant返事をありがとう。私はすでに(上記のものではなく)その方法を試してみましたが、IExtractIconインターフェイスも取得できませんでした。その間、私は自分のエラーを見つけたと思う(私の答えは以下を参照)。この質問とその答えが役に立つと思いますか?そうでなければ、私はすべてを削除するだけです... – Binarus

答えて

0

VB.netでIShellFolderインターフェイスを定義するときに、BindToFolder()関数を含めるのを忘れていました(03:00に実装するようにすべきではありません。 1時間前までのもの)。もちろん

、どこにでも記載されているように、これは私は、BindToFolder()は、インタフェース定義にGetUIObjectOf()前に来て、順番に、後者はGetDisplayNameOf()の前に来るので、IShellFolderインタフェースは、再び本当に私が何を言っているかわからない(間違った結果を生成作られたが私のコードがGetUIObjectOf()と呼ばれるときに実際にGetDisplayNameOf()が呼び出されたと想像できます。これは奇妙な結果を説明します)。

IShellFolderの定義を修正しました(つまり、欠落している機能を追加しました)。私の他のインターフェース定義(エラーなし)をダブルチェックしました。

関連する問題