This can be very easy or somewhat difficult depending on the syntax you require.
One way would be to create your own name/values collection in the ActiveX control.
You could add just two methods:
HRESULT GetPropery([in] BSTR name, [out,retval] VARIANT value);
HRESULT SetPropery([in] BSTR name, [in] VARIANT value);
Basically you would have ONE property on the control that would contain a collection of all the others. This is the most straight-forward way.
You could instead create a com collection (link assumes ATL, but theres generic info about com collections) property of variants. Make the Item() call of the collection accept strings. Accessing it would be like (the collection is named "Properties"):
myValue = myControl.Properties("Name")
I'm not sure how you could set values like this?
myControl.Properties("Name") = newValue
That may require the collection to return not variants but COM objects with a "default" property. I don't even remember the much of the details of default properties - but I think VB6 clients support them well and all you had to be was set some attributes in your IDL/ODL file.
Both ideas require the callers have that little bit of indirection of a method (Get/SetProperty) or use of the collection property (myobject.Properties.XXXX). If you MUST have syntax like this:
x = myControl.MyDynamticProperty
You'll need to write your own implementation of IDispatch's GetIDsOfName and Invoke. I've done this awhile ago, it was ugly. Thankfully this was all removed since we went a different direction with that part of the application. You'd have to force the callers to use the non-vtable IDispatch interface (and be late-bound) - I suppose this could be easy or hard depending on the calling language. My callers were always VB script so this was not a problem.