On Wed Apr 10 21:18:15 2024 +0000, Jacek Caban wrote:
This ultimately is an interop issue with MSHML. We will need an interface that exposes more dispex capabilities by this MR (by allowing using arbitrary names) outside jscript. I imagine that internally, in jscript, we will have a similar interface on dispex side. For jscript objects, they would operate on that internal interface. For external (MSHTML) object, those could be routed on `builtin_info_t` layer to the public interface (or something like that). Is that right? This means that those two interfaces need to be compatible. It's hard to comment on slices of the design without a big picture. For the big picture, the most important thing seems to be how the interop interface will look like. Could you draft the interface that we could discus it? Just a (not necessarily even compiling) header or IDL snippet should be enough for now.
Well yes, in a way it does require interop, but that's not the point I'm trying to make. As in, this specific part of the code—dealing with "async" props—has to be done regardless.
Imagine that localStorage was a jscript object, no mshtml at all. So, we write to the local file, add some keys and values. Now *every* localStorage object needs to have that key as a prop.
So, my point was only about hooks in this case for stuff like prop_get, delete_prop, definining new props (to see if an old one now exists from the file) and looking up props (by name or DISPID). Hooks that we would need *even if the localStorage object was in jscript*. That's because we have to look at them regardless of whether we have a jscript prop or not.
Now for the other topic, for mshtml interop, so far I have it like this, and btw it works so it's not a dead end:
```idl interface IWineJSDispatchHost : IDispatchEx { IWineJSDispatch** GetProxyFieldRef(); HRESULT PropFixOverride([out] struct proxy_prop_info *info); HRESULT PropOverride([in] const WCHAR *name, [out, optional] VARIANT *value); HRESULT PropDefineOverride([out] struct proxy_prop_info *info); HRESULT PropGetInfo([in] const WCHAR *name, [in] BOOL case_insens, [retval, out] struct proxy_prop_info *info); HRESULT PropInvoke([in] IDispatch *this_obj, [in] DISPID id, [in] LCID lcid, [in] DWORD flags, [in] DISPPARAMS *dp, [out, optional] VARIANT *ret, [out] EXCEPINFO *ei, [in] IServiceProvider *caller); HRESULT PropDelete([in] DISPID id); HRESULT PropEnum(); HRESULT ToString([retval, out] BSTR *string); } ``` Most of those after `PropGetInfo` are self-explanatory and out of scope for this. The ones dealing with the async hooks are `PropOverride` and `PropFixOverride`.
`PropOverride` is the one dealing with the hooks I outlined above; right now, of course without this MR, in prop_get for instance I have this at the top:
```c if((proxy_target = get_proxy_target(prop_obj))) { hres = IWineJSDispatchHost_PropOverride(proxy_target, prop->name, &var); if(hres != S_FALSE) { if(SUCCEEDED(hres)) { hres = variant_to_jsval(This->ctx, &var, r); VariantClear(&var); } goto done; } } ``` As you can see, it redirects the get to check if an async prop exists now first. **Even if** this was a jscript object, something similar would be required (I mean, a hook/check here for such object).
In my idea, along with this MR, it would be to simply have the prop_get method in the vtbl (now in the per-prop vtbl) handle this without any special checks. That is, for jscript proxy objects, we'd have something like:
```c static HRESULT proxy_prop_get(struct prop_desc *prop, IDispatch *jsthis, jsval_t *r) { /* Do checks here if it's dispex prop etc */ ...
hres = IWineJSDispatchHost_PropOverride(proxy_target, p->name, &var); if(hres != S_FALSE) { if(SUCCEEDED(hres)) { hres = variant_to_jsval(ctx, &var, r); VariantClear(&var); } return hres; }
/* Forward to normal dispex method */ return dispex_prop_get(prop, jsthis, r); } ``` And the rest of the code that uses prop.vtbl->get is completely unchanged, no special casing needed. Similar is for stuff like delete_prop or defining new props.
Now `PropFixOverride` is different. It "fixes" them up similar to fix_protref_prop. It will need new stuff in the vtbl, because it's used when looking up the prop (get_prop and find_prop_name). Obviously I'm not going to include that, and dead code, in this MR yet. It's not needed by Typed Arrays either. And maybe there's a better way with it, too.
Anyway, I should probably start to rewrite this so it uses mandatory methods in the object vtbl, right? It's probably hard to see how it would look, but one thing I want to avoid is to add special cases and checks, since the whole point of the vtbl approach was to get rid of them…