vendredi 29 octobre 2021

Create Delegate From ComObject Method (via Reflection)

I am able to retrieve it from a COM object via Reflection and run it with the MethodInfo.Invoke method.

However, I am trying to create a Delegate to be faster because I will use it in a loop. Unfortunately, I couldn't find a solution to the error message below. How can I create a delegate for a COM method?

"Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type."

My Delegate:

Public Delegate Function GetDriveNameDelegate(path As String) As String

My test Button:

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click

      Dim fsoType As Type = Type.GetTypeFromProgID("Scripting.FileSystemObject")
      Dim fsoInstance As Object = Activator.CreateInstance(fsoType)

      'Dim result As Type

#Region " This is working... "

      'Dim dispatch As IDispatchInfo = fsoInstance

      'dispatch.GetTypeInfo(0, 0, result)

      'Dim mi As MethodInfo = result.GetMethod("GetDriveName")

      'Dim param = New Object() {"C:\Windows"}

      'MessageBox.Show(mi.Invoke(fsoInstance, param))

#End Region

#Region " This is not working... "

      Dim fsoDelegate As GetDriveNameDelegate = GetDelegateFromCOM(fsoInstance, "GetDriveName")

      MessageBox.Show(fsoDelegate.Invoke("C:\Windows"))

#End Region

   End Sub   

My Delegate creator function:

   Public Function GetDelegateFromCOM(comObj As Object, methodName As String) As GetDriveNameDelegate
      Dim result As Type

      CType(comObj, IDispatchInfo).GetTypeInfo(0, 0, result)

      Dim mi As MethodInfo = result.GetMethod(methodName)

      Return [Delegate].CreateDelegate(GetType(GetDriveNameDelegate), mi, True)
   End Function

The IDispatch Interface:

<ComImport>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
<Guid("00020400-0000-0000-C000-000000000046")>
Public Interface IDispatchInfo
   ''' <summary>
   ''' Gets the number of Types that the object provides (0 or 1).
   ''' </summary>
   ''' <param name="typeInfoCount">Returns 0 or 1 for the number of Types provided by <see cref="GetTypeInfo"/>.</param>
   ''' <remarks>
   ''' http://msdn.microsoft.com/en-us/library/da876d53-cb8a-465c-a43e-c0eb272e2a12(VS.85)
   ''' </remarks>
   <PreserveSig>
   Function GetTypeInfoCount(ByRef typeInfoCount As Integer) As Integer

   ''' <summary>
   ''' Gets the Type information for an object if <see cref="GetTypeInfoCount"/> returned 1.
   ''' </summary>
   ''' <param name="typeInfoIndex">Must be 0.</param>
   ''' <param name="lcid">Typically, LOCALE_SYSTEM_DEFAULT (2048).</param>
   ''' <param name="typeInfo">Returns the object's Type information.</param>
   ''' <remarks>
   ''' http://msdn.microsoft.com/en-us/library/cc1ec9aa-6c40-4e70-819c-a7c6dd6b8c99(VS.85)
   ''' </remarks>
   Sub GetTypeInfo(typeInfoIndex As Integer, lcid As Integer, <MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef:=GetType(TypeToTypeInfoMarshaler))> ByRef typeInfo As Type)

   ''' <summary>
   ''' Gets the DISPID of the specified member name.
   ''' </summary>
   ''' <param name="riid">Must be IID_NULL.  Pass a copy of Guid.Empty.</param>
   ''' <param name="name">The name of the member to look up.</param>
   ''' <param name="nameCount">Must be 1.</param>
   ''' <param name="lcid">Typically, LOCALE_SYSTEM_DEFAULT (2048).</param>
   ''' <param name="dispId">If a member with the requested <paramref name="name"/>
   ''' is found, this returns its DISPID and the method's return value is 0.
   ''' If the method returns a non-zero value, then this parameter's output value is
   ''' undefined.</param>
   ''' <returns>Zero for success. Non-zero for failure.</returns>
   ''' <remarks>
   ''' http://msdn.microsoft.com/en-us/library/6f6cf233-3481-436e-8d6a-51f93bf91619(VS.85)
   ''' </remarks>
   <PreserveSig>
   Function GetDispId(ByRef riid As Guid, ByRef name As String, nameCount As Integer, lcid As Integer, ByRef dispId As Integer) As Integer

   ' NOTE: The real IDispatch also has an Invoke method next, but we don't need it.
   ' We can invoke methods using .NET's Type.InvokeMember method with the special
   ' [DISPID=n] syntax for member "names", or we can get a .NET Type using GetTypeInfo
   ' and invoke methods on that through reflection.
   ' Type.InvokeMember: http://msdn.microsoft.com/en-us/library/de3dhzwy.aspx
End Interface




Aucun commentaire:

Enregistrer un commentaire