Thank you very much.
I really like your approach.

Could you explain what to modify so that it works with our implementations?
I have many RegFree dlls and I would like to use this system.

I think I understand that you have to copy the cEventSink file for each late-bound object you want to use.
and modify the functions

Code:
Public Event BeforeShowMsgBox(sNewMessage As String, bCancel As Boolean)
add more events

Friend Sub ObjectRaiseEvent(dispIdMember As Long, pDispParams As oleexp.DISPPARAMS, Optional LCID As Long) ' This is the Callback function from our light-weight EventSink object
Dim sEventName As String, vaParams() As Variant, tSA As tSafeArray
    With pDispParams
        InitSA tSA, ArrPtr(vaParams), 16, .rgPointerToVariantArray, .cArgs ' Build an array of variants from the DispParams structure (this contains the event parameters in reversed order)
    End With
    If GetEventName(dispIdMember, sEventName, LCID) Then ' Getting the event name works only in IDE for local classes! ActiveX classes work everywhere.
        Select Case sEventName ' Just in case we have more than one event
            Case "BeforeShowMsgBox": RaiseEventBeforeShowMsgBox vaParams ' First we need to parse the variant array of parameters before raising the actual event
        add more case 
        End Select
    End If
End Sub


Can you explain this?

Private Sub RaiseEventBeforeShowMsgBox(vaParams() As Variant)
Dim i As Long, wVarType As Integer, lParamPtr As Long, sNewMessage As String, bCancel As Boolean
    sNewMessage = vaParams(1): bCancel = vaParams(0) ' Copy the parameters from the variant array into locally declared variables of the appropriate type
    RaiseEvent BeforeShowMsgBox(sNewMessage, bCancel) ' This is where we finally get to raise the event! Was it worth it?
    For i = UBound(vaParams) To LBound(vaParams) Step -1 ' It's not over yet, we need to process any "ByRef" parameters in case they were changed in the event procedure and send them back!
        GetMem2 vaParams(i), wVarType
        If (wVarType And VT_BYREF) = VT_BYREF Then ' Check whether this is a "ByRef" or "ByVal" parameter
            GetMem4 ByVal VarPtr(vaParams(i)) + 8, lParamPtr ' In case of "ByRef" parameters the variant holds a pointer to the actual value of the parameter
            Select Case wVarType And VT_TYPEMASK ' Check the true type of the parameter
                Case vbString
                    PutMem4 ByVal lParamPtr, StrPtr(sNewMessage) ' Place the modified string back in the variant (regardless whether it was modified or not in the event procedure)
                    PutMem4 ByVal VarPtr(sNewMessage), 0& ' We need to uninitialize the locally declared string to prevent VB6 from trying to free it since it now resides in the variant!
                Case vbBoolean
                    PutMem2 ByVal lParamPtr, bCancel ' The boolean parameter goes straight into the variant
                 Do you have to add more types here or do you have to do more things?
            End Select
        End If
    Next i
End Sub

Thank you very much for your work.
Sorry for my translation and my lack of knowledge.