-
Jun 20th, 2019, 03:13 PM
#1
Thread Starter
Member
Has anyone had any success implementing IDispatch / IDispatchEx?
Recently I've found myself wanting to implement the IDispatchEx interface which would allow me to create objects 'on the fly'. The core benefit of which is for syntax sugar:
Code:
Dim person as object
set person = new CDynamic
person.age = 22
person.hair.color = "brown"
person.hair.style = "shaggy"
Or even, a less ambitious dynamic IDispatch implementation:
Code:
Dim person as object
set person = new CDynamic
person.addProperties("age","hair")
set person.hair = new CDynamic
person.hair.addProperties("color","style")
'...
person.age = 22
person.hair.color = "brown"
person.hair.style = "shaggy"
This would be really handy as a developer's tool, especially in making dev friendly frameworks without bloating the codebase too much. Recently I've been trying to implement these interfaces using IFauxInterface but before I pursue this any further I figured I'd ask here to see if anyone else has tried / got anywhere with this?
-
Jun 20th, 2019, 03:52 PM
#2
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Search this forum for the keyword: CreateStdDispatch.
In my recent codebank submission, I apply the API quite a bit to create COM objects on the fly. But "the trick" posted some examples which may fall into what you are attempting (search for that keyword to find his posts).
CreateStdDispatch can be quite complex, has limitations, and documentation/examples in the wild are sparse.
-
Jun 20th, 2019, 07:47 PM
#3
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
-
Jun 20th, 2019, 07:58 PM
#4
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
@dreammanor. I think the OP wants to include ability to get/set properties and methods.
-
Jun 20th, 2019, 08:22 PM
#5
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Yes, he wants VB6 to gain the ability of JavaScript-like dynamic properties (even dynamic objects). If this can be achieved, the capabilities of VB6 will increase dramatically.
Edit:
I've been researching scripting languages (mainly JavaScript) recently. The ability of JavaScript to dynamically create objects is really useful.
Last edited by dreammanor; Jun 20th, 2019 at 08:27 PM.
-
Jun 20th, 2019, 11:14 PM
#6
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
-
Jun 21st, 2019, 02:32 AM
#7
Thread Starter
Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by LaVolpe
Search this forum for the keyword: CreateStdDispatch.
In my recent codebank submission, I apply the API quite a bit to create COM objects on the fly. But "the trick" posted some examples which may fall into what you are attempting (search for that keyword to find his posts).
CreateStdDispatch can be quite complex, has limitations, and documentation/examples in the wild are sparse.
Ah you are totally right! I recall coming across CreateStdDispatch a few weeks ago, remember thinking "Man this looks like it'll do what I need it to". I think I chickened out after seeing the total lack of documentation and examples though lol...
Originally Posted by The trick
Thanks! This will be a super great basis to work off of! Should make it pretty easy Thanks!
-
Jun 21st, 2019, 06:39 AM
#8
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by LaVolpe
@dreammanor. I think the OP wants to include ability to get/set properties and methods.
I thought, that was exactly what example-folder 7 (Dynamic usage of vbIDispatch) of the "vbFriendlyInterfaces"-Demo contains.
Here the complete Code of that "Dyn-Props-Demo" as it exists in fTest.frm:
Code:
Private Sub Form_Click()
AutoRedraw = True: Cls
Dim PS As New cPropStorage
With PS.Props 'PS.Props will accept any Property-Name you throw at it, to "store things" (As Variant)
.foo = "foo"
.bar = "bar"
.foobar = .foo & .bar '<- read-out-test for the dynamic props .foo and .bar
.SomeLong = 123 'fill-in some long...
.SomeLong = 456 '<- and now test for over-writing an existing Value under the same PropertyName
Set .TheForm = Me 'test for storing an Object-Reference (in this case in .TheForm)
'Ok, now the Test-PrintOuts for the above
Print "foo: "; .foo
Print "bar: "; .bar
Print "foobar: "; .foobar
Print "SomeLong: "; .SomeLong
Print "TheForm.Caption: "; .TheForm.Caption
End With
End Sub
And here the complete Code of cPropStorage.cls, which provides that dynamic IDispatch-Implementation:
Code:
Option Explicit
Implements vbIUnknown
Implements vbIDispatch
Private mDict As New Scripting.Dictionary, VStorage() As Variant
Public Function Props() As Object 'our IDispatch-supporting DispObject, which allows LateBound Method-Calling "per Dot"
vbI.NewInstance vbI.pVT(vtbl_IDispatch), Me, VarPtr(Props)
End Function
'************* IUnknown-Implementation *****************
Private Sub vbIUnknown_QueryInterface(UserData As Long, ByVal pVTable As Long, RefCount As Long, sReqIID As String, Unk As stdole.IUnknown)
If vbI.IIDsEqual(sReqIID, vbI.sIID_IDispatch) Then RefCount = RefCount + 1
End Sub
Private Sub vbIUnknown_Terminate(UserData As Long, ByVal pVTable As Long)
End Sub
'************* IDispatch-Implementation ****************
Private Function vbIDispatch_GetIDForMemberName(UserData As Long, ByVal pVTable As Long, MemberName As String) As Long
If mDict.Exists(MemberName) Then
vbIDispatch_GetIDForMemberName = mDict(MemberName)
Else
mDict.Add MemberName, mDict.Count + 1
vbIDispatch_GetIDForMemberName = mDict.Count
ReDim Preserve VStorage(1 To mDict.Count)
End If
End Function
Private Function vbIDispatch_Invoke(UserData As Long, ByVal pVTable As Long, ByVal DispID As Long, ByVal CallType As VbCallType, VResult As Variant, ParamArray P() As Variant) As vbInterfaces.HRESULT
If DispID < 1 Or DispID > mDict.Count Then vbIDispatch_Invoke = DISP_E_MEMBERNOTFOUND: Exit Function
If CallType And (VbGet Or VbMethod) Then 'handle the read-out-requests
If IsObject(VStorage(DispID)) Then Set VResult = VStorage(DispID) Else VResult = VStorage(DispID)
ElseIf CallType = VbLet Then
VStorage(DispID) = P(0)
ElseIf CallType = VbSet Then
Set VStorage(DispID) = P(0)
End If
End Function
So that's the easy way, as the vbFriendlyInterfaces.dll provides it (in a generically usable fashion).
Olaf
-
Jun 21st, 2019, 06:48 AM
#9
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Well, and for those who want to add such stuff in a "super-easy" way, there's always IActiveScripting-interfaces,
which would then allow even simple Function-adding in a dynamic fashion.
Into an empty VB-Project with a Form1 - add a new Class with its default-name Class1 - and paste the following:
Code:
Option Explicit
Private SC As Object
Private Sub Class_Initialize()
Set SC = CreateObject("MSScriptControl.ScriptControl")
SC.Language = "VBScript"
SC.AddCode "Public foo: foo = ""foo"""
SC.AddCode "Public bar: bar = ""bar"""
End Sub
Public Function Dyn() As Object
Set Dyn = SC.CodeObject
End Function
Public Sub AddProp(PropName$, Optional InitVal)
SC.AddCode "Public " & PropName: If IsMissing(InitVal) Then Exit Sub
If IsObject(InitVal) Then CallByName Dyn, PropName, VbSet, InitVal Else _
CallByName Dyn, PropName, VbLet, InitVal
End Sub
Public Sub AddFunc(FuncName$, Code$, Optional ParamList$)
SC.AddCode "Function " & FuncName & "(" & ParamList & ")" _
& vbCrLf & Code & vbCrLf & "End Function"
End Sub
Ok, and here's appropriate Test-Code for the Form:
Code:
Option Explicit
Private Sub Form_Load()
Dim C1 As New Class1
With C1.Dyn
Debug.Print .foo, .bar 'those were ensured already at class_initialize
C1.AddFunc "foobar", "foobar=foo+bar" 'add a new method
Debug.Print foo, .bar, .foobar
.foo = 1: .bar = 2 'Prop-Value-changes
Debug.Print .foo, .bar, .foobar
C1.AddProp "baz", "baz" 'add two more new properties
C1.AddProp "Form", Me
Debug.Print .baz, .Form.Caption
End With
End Sub
Et voilà - there it is - a dynamically expandable Dispatch-Prop...
Olaf
-
Jun 21st, 2019, 07:25 AM
#10
Thread Starter
Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by Schmidt
...
So that's the easy way, as the vbFriendlyInterfaces.dll provides it (in a generically usable fashion).
Olaf
Hi Olaf,
Gotta say your vbFriendlyInterfaces dll does indeed look very nice! That said I'm not sure if you can easily attach methods to your IDispatch implementation without implementing TypeInfo also. (Although this is untested from me as of right now)
Regardless, in my particular use case, I want to (as and where possible) steer away from using any external DLLs, (easier distribution). I'm also trying to steer away from ScriptControl specifically who's VBScript evaluation is actually disabled on most computers I have used, and whos JScript is unlikely to be supported forever either.
This is why I was initially looking into IFauxInterface as this quite literally builds the implementation within VB. That said the DLL version is very neat. Perhaps if the worst comes to the worst I can download the dll at runtime to Appdata.
-
Jun 21st, 2019, 02:02 PM
#11
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by sancarn
Gotta say your vbFriendlyInterfaces dll does indeed look very nice!
That said I'm not sure if you can easily attach methods to your IDispatch implementation without implementing TypeInfo also.
(Although this is untested from me as of right now)
Since Properties are already "Methods" the Implementation of a "true Function" is of course equally possible:
Why not make a fast test with the Demo 7-Code:
At the top of vbIDispatch_GetIDForMemberName add a new, single line:
Code:
Private Function vbIDispatch_GetIDForMemberName(UserData As Long, ByVal pVTable As Long, MemberName As String) As Long
If UCase$(MemberName) = "MYFUNC" Then vbIDispatch_GetIDForMemberName = 10000: Exit Function
...
At the top of vbIDispatch_Invoke add a new, single line:
Code:
Private Function vbIDispatch_Invoke(UserData As Long, ByVal pVTable As Long, ByVal DispID As Long, ByVal CallType As VbCallType, VResult As Variant, ParamArray P() As Variant) As vbInterfaces.HRESULT
If DispID = 10000 Then VResult = Join(P, "_"): Exit Function 'MyFunc Joins all passed Params with an UnderScore-Char
...
And that's it... "MyFunc" was successfully implemented (without any extra TypeInfos).
You can test it in the Form within the With-Block by doing:
Debug.Print .MyFunc("abc", 1, 2, 3, "xyz") '<-- returns and Prints out: abc_1_2_3_xyz
Originally Posted by sancarn
Regardless, in my particular use case, I want to (as and where possible) steer away from using any external DLLs, (easier distribution). I'm also trying to steer away from ScriptControl specifically who's VBScript evaluation is actually disabled on most computers I have used, and whos JScript is unlikely to be supported forever either.
Did you really deactivate VBScript on your Computer(s)?
If yes, how did you do that - and why did you leave JScript alone in that case?
Im asking, because a "deactivated VBScript" usually leaves the vbscript.dll untouched in the System32 or SysWOW64 folders
(if you remove them, there's a good chance MS will re-install them on the next system-update or system-check).
And I've mentioned IActiveScript in my first post, because when you implement these Scripting-interfaces by hand,
you will not need the MS-ScriptControl - but only an installed vbsript.dll or jscript.dll in the SysFolder.
I still consider that solution the most promising one for your case, because when you think about it:
- dynamic properties are easy also with other methods (e.g. via vbFriendlyInterfaces.dll)
- but for "true dynamic functions" which do a bit more than "single-line math-ops or concats" to produce a result,
.. you'll need either a dynamic compiler, or an interpreter ... period.
- the Scripting-stuff is also interesting because it comes in both: 32Bit- and a 64Bit implementations (preinstalled on the system)
- also - you're not restricted to VBScript - the jscript.dll can provide basically the same stuff I've demonstrated with VbScript in my example
Olaf
-
Jun 21st, 2019, 04:14 PM
#12
Thread Starter
Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by Schmidt
And that's it... "MyFunc" was successfully implemented (without any extra TypeInfos).
Lol well that's cheating! But indeed you can do that.
Originally Posted by Schmidt
Did you really deactivate VBScript on your Computer(s)?
I did not do anything of the sort. On all systems I have used the following code:
Code:
Dim sc as object: set sc = CreateObject("MSScriptControl.ScriptControl")
sc.Language = "VBScript"
I have got the error.
Code:
Run-time error '380': A script engine for the specified language can not be created
JScript seems to work, not sure why, but yeah... To be fair, both times I tried this on Win10 computers, so that might also have something to do with it... If one doesn't have to rely on MSScriptControl.ScriptControl then perhaps that is indeed an option also.
Originally Posted by Schmidt
- but for "true dynamic functions" which do a bit more than "single-line math-ops or concats" to produce a result,
.. you'll need either a dynamic compiler, or an interpreter ... period.
Yep I was actually planning on implementing a VB6-like language --> Bytecode compiler + interpreter. Preferably something that would allow syntax customisation. Mainly for Lambda expressions...
Anyway.
I'll definitely be giving all the suggestions a go and ultimately it'll be which ever is more optimal (performance wise). This is a pretty fundamental piece of the architecture of the API so I want it to be as fast as possible. So thanks all for suggestions!
-
Jun 21st, 2019, 07:44 PM
#13
New Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Sancarn, I've not tested every tutorial module, but the fast majority of Olaf's vbFriendly interface's examples work perfectly from the VBA IDE (with just a couple of minor tweaks to cover the differences in the langauges). I also dont think you need the ITypelib reference explicitly in your code, since (Olaf correct me if i'm wrong) you are really directly inserting the desired IID at runtime to ensure the correct type association by the machine?
-
Jul 12th, 2019, 06:03 AM
#14
Fanatic Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by Schmidt
Well, and for those who want to add such stuff in a "super-easy" way, there's always IActiveScripting-interfaces,
which would then allow even simple Function-adding in a dynamic fashion.
Into an empty VB-Project with a Form1 - add a new Class with its default-name Class1 - and paste the following:
Code:
Option Explicit
Private SC As Object
Private Sub Class_Initialize()
Set SC = CreateObject("MSScriptControl.ScriptControl")
SC.Language = "VBScript"
SC.AddCode "Public foo: foo = ""foo"""
SC.AddCode "Public bar: bar = ""bar"""
End Sub
Public Function Dyn() As Object
Set Dyn = SC.CodeObject
End Function
Public Sub AddProp(PropName$, Optional InitVal)
SC.AddCode "Public " & PropName: If IsMissing(InitVal) Then Exit Sub
If IsObject(InitVal) Then CallByName Dyn, PropName, VbSet, InitVal Else _
CallByName Dyn, PropName, VbLet, InitVal
End Sub
Public Sub AddFunc(FuncName$, Code$, Optional ParamList$)
SC.AddCode "Function " & FuncName & "(" & ParamList & ")" _
& vbCrLf & Code & vbCrLf & "End Function"
End Sub
Ok, and here's appropriate Test-Code for the Form:
Code:
Option Explicit
Private Sub Form_Load()
Dim C1 As New Class1
With C1.Dyn
Debug.Print .foo, .bar 'those were ensured already at class_initialize
C1.AddFunc "foobar", "foobar=foo+bar" 'add a new method
Debug.Print foo, .bar, .foobar
.foo = 1: .bar = 2 'Prop-Value-changes
Debug.Print .foo, .bar, .foobar
C1.AddProp "baz", "baz" 'add two more new properties
C1.AddProp "Form", Me
Debug.Print .baz, .Form.Caption
End With
End Sub
Et voilà - there it is - a dynamically expandable Dispatch-Prop...
Olaf
Hi Olaf,
I am trying to use your code in x64bit windows but the ScriptControl no longer works in x64bit.
Do you have any suggestions ?
Regards.
-
Jul 12th, 2019, 02:28 PM
#15
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by JAAFAR
I am trying to use your code in x64bit windows but the ScriptControl no longer works in x64bit.
I don't know where you got that idea. It works fine on the 64bit PC I just tried it on.
-
Jul 12th, 2019, 08:07 PM
#16
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by dilettante
I don't know where you got that idea. It works fine on the 64bit PC I just tried it on.
Sure...
@JAAFAR
Judging from your last postings, you're probably trying to use it from within a 64Bit-Process (as e.g. "64Bit-Excel-VBA").
First option:
...use the 32Bit-Script-COMponent with COM-Marshaling (either via ActiveX-Exe-Instancing or the DllSurrogate-mechanism).
Second option:
...google for VB6-implementations of the IActiveScripting-interfaces (there are a few out there) -
and adapt these sources for VBA-64.
Olaf
-
Jul 12th, 2019, 08:56 PM
#17
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
VBA questions belong in the Office Development forum.
-
Jul 12th, 2019, 11:30 PM
#18
Fanatic Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by dilettante
I don't know where you got that idea. It works fine on the 64bit PC I just tried it on.
Sorry, I meant to say 64bit process not 64 OS.
-
Jul 12th, 2019, 11:38 PM
#19
Fanatic Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by dilettante
VBA questions belong in the Office Development forum.
I know I am not supposed to ask questions related to vba in this forum but the truth is I hardly ever get any answers when I post in the Office Developent section.... Despite me not using vb6, most of my questions in this forum are API related.
Regards.
-
Jul 12th, 2019, 11:39 PM
#20
Fanatic Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by Schmidt
Sure...
@JAAFAR
Judging from your last postings, you're probably trying to use it from within a 64Bit-Process (as e.g. "64Bit-Excel-VBA").
First option:
...use the 32Bit-Script-COMponent with COM-Marshaling (either via ActiveX-Exe-Instancing or the DllSurrogate-mechanism).
Second option:
...google for VB6-implementations of the IActiveScripting-interfaces (there are a few out there) -
and adapt these sources for VBA-64.
Olaf
Thank you very much.
The second option sounds interesting... I'll look into it and see if I can make it work for me.
Regards.
-
Jul 13th, 2019, 10:06 AM
#21
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Some forums are less active than others...well, most, really. However, that's what happens if everybody decides to post questions in the wrong forum.
My usual boring signature: Nothing
-
Sep 2nd, 2020, 06:03 PM
#22
New Member
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by Schmidt
I thought, that was exactly what example-folder 7 (Dynamic usage of vbIDispatch) of the "vbFriendlyInterfaces"-Demo contains.
Here the complete Code of that "Dyn-Props-Demo" as it exists in fTest.frm:
Code:
Private Sub Form_Click()
AutoRedraw = True: Cls
Dim PS As New cPropStorage
With PS.Props 'PS.Props will accept any Property-Name you throw at it, to "store things" (As Variant)
.foo = "foo"
.bar = "bar"
.foobar = .foo & .bar '<- read-out-test for the dynamic props .foo and .bar
.SomeLong = 123 'fill-in some long...
.SomeLong = 456 '<- and now test for over-writing an existing Value under the same PropertyName
Set .TheForm = Me 'test for storing an Object-Reference (in this case in .TheForm)
'Ok, now the Test-PrintOuts for the above
Print "foo: "; .foo
Print "bar: "; .bar
Print "foobar: "; .foobar
Print "SomeLong: "; .SomeLong
Print "TheForm.Caption: "; .TheForm.Caption
End With
End Sub
And here the complete Code of cPropStorage.cls, which provides that dynamic IDispatch-Implementation:
Code:
Option Explicit
Implements vbIUnknown
Implements vbIDispatch
Private mDict As New Scripting.Dictionary, VStorage() As Variant
Public Function Props() As Object 'our IDispatch-supporting DispObject, which allows LateBound Method-Calling "per Dot"
vbI.NewInstance vbI.pVT(vtbl_IDispatch), Me, VarPtr(Props)
End Function
'************* IUnknown-Implementation *****************
Private Sub vbIUnknown_QueryInterface(UserData As Long, ByVal pVTable As Long, RefCount As Long, sReqIID As String, Unk As stdole.IUnknown)
If vbI.IIDsEqual(sReqIID, vbI.sIID_IDispatch) Then RefCount = RefCount + 1
End Sub
Private Sub vbIUnknown_Terminate(UserData As Long, ByVal pVTable As Long)
End Sub
'************* IDispatch-Implementation ****************
Private Function vbIDispatch_GetIDForMemberName(UserData As Long, ByVal pVTable As Long, MemberName As String) As Long
If mDict.Exists(MemberName) Then
vbIDispatch_GetIDForMemberName = mDict(MemberName)
Else
mDict.Add MemberName, mDict.Count + 1
vbIDispatch_GetIDForMemberName = mDict.Count
ReDim Preserve VStorage(1 To mDict.Count)
End If
End Function
Private Function vbIDispatch_Invoke(UserData As Long, ByVal pVTable As Long, ByVal DispID As Long, ByVal CallType As VbCallType, VResult As Variant, ParamArray P() As Variant) As vbInterfaces.HRESULT
If DispID < 1 Or DispID > mDict.Count Then vbIDispatch_Invoke = DISP_E_MEMBERNOTFOUND: Exit Function
If CallType And (VbGet Or VbMethod) Then 'handle the read-out-requests
If IsObject(VStorage(DispID)) Then Set VResult = VStorage(DispID) Else VResult = VStorage(DispID)
ElseIf CallType = VbLet Then
VStorage(DispID) = P(0)
ElseIf CallType = VbSet Then
Set VStorage(DispID) = P(0)
End If
End Function
So that's the easy way, as the vbFriendlyInterfaces.dll provides it (in a generically usable fashion).
Olaf
vbFriendlyInterfaces seems pretty helpful and demo #7 worked for me. Is there a way to handle "dynamic properties" without using the Props() Function?
Code:
Dim PS As New cPropStorage
PS.foo = "foo"
Print PS.foo
-
Sep 3rd, 2020, 05:41 AM
#23
Re: Has anyone had any success implementing IDispatch / IDispatchEx?
Originally Posted by ekinated
vbFriendlyInterfaces seems pretty helpful and demo #7 worked for me.
Is there a way to handle "dynamic properties" without using the Props() Function?
Yes, the cDynFactory-Class in posting #239 here will support that (along with dynamic functions):
https://www.vbforums.com/showthread....=1#post5469025
HTH
Olaf
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|