COM dynamic proxyAuthor: Dave Date: 10.07.25 - 7:13pm SO i had a little fun with chatgpt this week and I was able to coax out something I had wanted for a lonnng time. This project is a dynamic COM object proxy which wraps an arbitrary COM object and lets you intercept methods and add arbitrary ones on any COM object. Download: dynproxy.zip Below is the read me:
# π§© dynproxy β Dynamic COM Proxy for VB6 (and beyond)
> *βThe missing dynamic layer VB6 never had.β*
> A raw C++ COM proxy that turns VB6 into a dynamic runtime.
---
## π What This Does
`dynproxy.dll` lets **VB6 (or any COM client)** create objects that
respond to *any* property or method call dynamically β even ones that
donβt exist.
It acts like a **programmable middle-man** between VB6 and COM:
- Intercepts every `IDispatch::Invoke` and `GetIDsOfNames`.
- Can forward to a real inner COM object or fake a response.
- Lets your **VB6 class** decide in real time what happens.
**No ATL. No MFC. Pure COM.**
---
## π§ Why It Exists
No good reason..just a wish list
`dynproxy` fixes that: it lets you build **dynamic COM faΓ§ades** that VB6 treats as real.
Now you can:
- Build **synthetic COM trees** (`o.Kitty.Meow = 12`).
- **Mock** sprawling APIs (Acrobat, Office, etc.).
- **Log or reroute** calls before they hit the real object.
- **Bridge** VB6 to scripting engines or remote APIs.
- Turn VB6 into something approaching Python or JavaScriptβs `Proxy`.
---
## βοΈ How It Works
### π§ The Proxy Pipeline
```text
ββββββββββββββββββββββββββββ
β VB6 Runtime β
β (calls o.SomeMethod) β
ββββββββββββββββ¬ββββββββββββ
β IDispatch::Invoke("SomeMethod")
βΌ
ββββββββββββββββββββββ
β ProxyDispatch β
β (dynproxy.dll) β
ββββββββββββββββββββββ
β
ββββΆ 1οΈβ£ Inner object? β Forward call
β
ββββΆ 2οΈβ£ Resolver class?
β β’ Call VB6: ResolveGetID / ResolveInvoke
β β’ Pass name, args, and DISPATCH_ flags
β
ββββΆ 3οΈβ£ Neither? Invent a DISPID and let resolver fake it
````
### π Call Flow Details
1. **VB6** late-bound calls always go through `IDispatch::Invoke`.
2. The proxy catches that and checks a cache (`name β DISPID`).
3. If unknown, it calls:
* `inner->GetIDsOfNames()` first (default), or
* `resolver->ResolveGetID()` first if resolver-wins mode is active.
4. The final `Invoke` routes accordingly:
* Forward to the inner COM object, **or**
* Call your resolverβs `ResolveInvoke(name, flags, args())`.
---
## π§© VB6 Resolver Interface
Your resolver implements two public methods:
```vb
Public Function ResolveGetID(ByVal name As String) As Long
' Return non-zero to claim this name
' Return 0 to let the inner object handle it
End Function
Public Function ResolveInvoke(ByVal name As String, _
ByVal flags As Long, _
args() As Variant) As Variant
' Handle the call
End Function
```
### `flags` meanings
| Flag | Hex | Meaning |
| ---- | --- | ------------------------------ |
| 1 | 0x1 | DISPATCH_METHOD (Sub/Function) |
| 2 | 0x2 | DISPATCH_PROPERTYGET |
| 4 | 0x4 | DISPATCH_PROPERTYPUT |
| 8 | 0x8 | DISPATCH_PROPERTYPUTREF |
---
## π± Example: Dynamic Tree
```vb
' --- CResolver.cls ---
Option Explicit
Private m_children As Object, m_props As Object
Private Sub Class_Initialize()
Set m_children = CreateObject("Scripting.Dictionary")
Set m_props = CreateObject("Scripting.Dictionary")
End Sub
Public Function ResolveGetID(ByVal name As String) As Long
Select Case LCase$(name)
Case "kitty", "meow": ResolveGetID = -30000
Case Else: ResolveGetID = 0
End Select
End Function
Public Function ResolveInvoke(ByVal name As String, ByVal flags As Long, args() As Variant) As Variant
Dim lname As String: lname = LCase$(name)
' Property GET
If (flags And 2) <> 0 Then
If lname = "kitty" Then
If Not m_children.Exists("kitty") Then
Dim child As CResolver: Set child = New CResolver
Dim p As Long: p = CreateProxyForObjectRaw(0&, ObjPtr(child))
Dim o As Object: Set o = ObjectFromPtr(p)
m_children.Add "kitty", o
End If
Set ResolveInvoke = m_children("kitty"): Exit Function
End If
If m_props.Exists(lname) Then ResolveInvoke = m_props(lname)
Exit Function
End If
' Property PUT
If (flags And 4) <> 0 Then
m_props(lname) = args(0): Exit Function
End If
End Function
```
Demo:
```vb
Dim root As New CResolver
Dim p As Long: p = CreateProxyForObjectRaw(0&, ObjPtr(root))
Dim o As Object: Set o = ObjectFromPtr(p)
o.kitty.meow = 12
Debug.Print o.kitty.meow ' β 12
```
---
## π§© Key Exports
| Function | Description |
| ---------------------------------------------------------- | ------------------------------------------------------ |
| `CreateProxyForObjectRaw(inner, resolver)` | Create proxy with an optional inner and resolver. |
| `CreateProxyForObjectRawEx(inner, resolver, resolverWins)` | Same, but choose resolver-first at creation. |
| `SetProxyResolverWins(proxy, enable)` | Toggle resolver-first mode at runtime. |
| `ClearProxyNameCache(proxy)` | Clear cached DISPIDs (call after toggling). |
| `SetProxyOverride(proxy, name, dispid)` | Force a name to route to resolver. |
| `ReleaseDispatchRaw(ptr)` | Manual release if you never wrapped the pointer in VB. |
All exports are `stdcall`, callable from VB6 directly.
---
## π§° Build Notes
* **Language:** C++17
* **No** ATL or MFC
* **Link:** `oleaut32.lib`
* Build as **Win32 DLL**
```
cl /LD /std:c++17 dynproxy.cpp oleaut32.lib /EHsc /Fe:dynproxy.dll
```
---
## π§© Project Layout
```
dynproxy/
βββ dynproxy.cpp # core proxy
βββ dynproxy.h # exports & ProxyDispatch class
βββ msgf.cpp/.h # debug output
βββ VB6/
β βββ CResolver.cls
β βββ modProxyDecls.bas
β βββ modDemo.bas
β βββ README_demo.txt
βββ README.md
```
---
## β‘ Why Itβs Cool
* Intercepts and rewrites COM calls in real time.
* Lets VB6 behave like Python or JavaScript β dynamic and late-bound.
* Mocks any proprietary API instantly (no IDL hell).
* Enables powerful debugging, scripting, and adapter layers.
---
## β οΈ Caveats
* Works only for **late-bound** (`IDispatch`) calls.
* STA threading only (standard VB6 COM).
* Donβt double-release VB6-wrapped objects.
* VB6 only runs 32-bit, so the DLL should be x86.
---
## π§ββοΈ Credits & Origin
Implemented in pure C++ because ATL/MFC got in the way.
This project turns that pain into power β a *universal COM proxy* that lets old tech do new tricks.
---
**Platform:** Win32 COM
**Language:** C++ / VB6
**Keywords:** VB6, COM, IDispatch, dynamic proxy, API mocking, automation, Acrobat
Comments: (0) |
About Me More Blogs Main Site
|
|||||||||||||||||||||||||||||||||