Skip to content

Instantly share code, notes, and snippets.

@wqweto
Last active March 19, 2019 09:48
Show Gist options
  • Save wqweto/7952402 to your computer and use it in GitHub Desktop.
Save wqweto/7952402 to your computer and use it in GitHub Desktop.
Scripting.Dictionary supports For Each enumeration through IEnumVARIANT on DISPID_NEWENUM, not by using Variant array default property.
Option Explicit
Private Const LOCALE_SYSTEM_DEFAULT As Long = &H800
Private Const S_OK As Long = 0
Private Type DISPPARAMS
rgPointerToVariantArray As Long
rgPointerToLongNamedArgs As Long
cArgs As Long
cNamedArgs As Long
End Type
Private Type EXCEPINFO
wCode As Integer
wReserved As Integer
Source As String
Description As String
HelpFile As String
dwHelpContext As Long
pvReserved As Long
pfnDeferredFillIn As Long
sCode As Long
End Type
Public Enum UcsInvokeCallEnum
ucsIclMethod = 1
ucsIclPropGet = 2
ucsIclPropLet = 4
ucsIclPropSet = 8
End Enum
Public Function DispInvoke( _
ByVal pDisp As IVbDispatch, _
Name As Variant, _
Optional ByVal CallType As UcsInvokeCallEnum = ucsIclMethod, _
Optional Result As Variant, _
Optional Args As Variant) As Boolean
Const DISPID_PROPERTYPUT As Long = -3
Dim IID_NULL As VBGUID
Dim lDispID As Long
Dim uParams As DISPPARAMS
Dim uInfo As EXCEPINFO
Dim aParams() As Variant
Dim lNamedParam As Long
Dim lIdx As Long
Dim lParamCount As Long
Dim lArgErr As Long
Dim lPtrResult As Long
If pDisp Is Nothing Then
Exit Function
End If
'--- get disp id
If IsNumeric(Name) Then
lDispID = CLng(Name)
Else
If pDisp.GetIDsOfNames(IID_NULL, CStr(Name), 1, LOCALE_SYSTEM_DEFAULT, lDispID) <> S_OK Then
Exit Function
End If
End If
'--- process params
If Not IsMissing(Args) Then
If IsArray(Args) Then
lParamCount = UBound(Args) - LBound(Args)
ReDim aParams(0 To lParamCount)
For lIdx = 0 To lParamCount
Call VariantCopy(aParams(lParamCount - lIdx), Args(lIdx))
Next
Else
ReDim aParams(0 To 0)
Call VariantCopy(aParams(0), Args)
End If
With uParams
.cArgs = lParamCount + 1
.rgPointerToVariantArray = VarPtr(aParams(0))
End With
If CallType = ucsIclPropLet Or CallType = ucsIclPropSet Then
lNamedParam = DISPID_PROPERTYPUT
With uParams
.cNamedArgs = 1
.rgPointerToLongNamedArgs = VarPtr(lNamedParam)
End With
End If
End If
If CallType = ucsIclPropGet Or CallType = ucsIclMethod And Not IsMissing(Result) Then
Result = Empty
lPtrResult = VarPtr(Result)
End If
DispInvoke = (pDisp.Invoke(lDispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, CallType, uParams, ByVal lPtrResult, uInfo, lArgErr) = S_OK)
End Function
Private Sub Command1_Click()
Const DISPID_NEWENUM As Long = -4
Dim pDict As Object
Dim vResult As Variant
Set pDict = CreateObject("Scripting.Dictionary")
If DispInvoke(pDict, DISPID_NEWENUM, ucsIclMethod, vResult) Then
Debug.Print TypeName(vResult)
End If
End Sub
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment