I'm having trouble calling a non IDispatch method in an ActiveX control that I've written.
I have a web page with two separate Active X object both of which I've written. I start by calling a method on the first object which returns an interface pointer to a new COM object that is not co-creatable. I then call a method on this new object passing the second ActiveX object as the argument. Inside this method I call QueryInterface to obtain a private/internal interface pointer on my second ActiveX object. The problem is that the returned pointer from QueryInterface is not a valid pointer to my object, and any attempt to use it crashes.
How can I obtain a interface to my actual object that I can use? My private interface uses structures so it not compatible with IDispatch, and being an internal interface I do not desire to expose it at all in the type library.
It's a little hard to tell with just a description, but I assume that the method on the first object is returning an IDispatch pointer to the object it creates? The JScript environment will only be able to cope with that.
Also, is your implementation of QueryInterface valid? Does it work for you in non-scripting contexts?
I am still a little unclear on which objects have which interfaces, but if you have an object with an IDispatch-unfriendly interface, perhaps you can build a simple wrapper object to hold it, where the wrapper object has a proper IDispatch interface?
Apologies if I am way off the mark...I haven't wrestled with ActiveX stuff in a few months.
Related
Note: I now believe this question was based on assumptions about the javascript specification which are actually implementation specific.
I am attempting to build a runtime debugging hook system for a complex dynamic javascript application. A series of choices have let me to choose to use javascript Proxy and Reflect metaprogramming constructs to interpose function calls in the application I am debugging, wrapping all incoming functions arguments in Proxy/Reflect constructs.
The approach involves replacing high level application functions with Proxies and using traps and handlers to provide debugging functionality, ultimately passing arguments through to the application in a transparent way. All property get/set and function executions act as normal. However, by wrapping all objects and functions in Proxies allows tracing of the runtime.
I am installing this hook system into Chrome.
(Note: Please do NOT provide an answer suggesting a different methodology for debugging hooks - options have been evaluated extensively.)
The issue is that some javascript methods in the application invoke closures and pass "this" parameters. When "this" parameters are wrapped in a Proxy, the runtime fails to execute a closure, instead throwing an "Illegal Invocation" Exception.
I have tried reengineering the debugging hook system to not wrap arguments for some methods, or selectively wrap arguments. I have not been able to find a way to tell if an argument is intended to be used as a context, making code that tries this approach hardcoded to many possible methods and calling conventions. Ultimately this is too fragile to calling convention edge cases and requires too many case statements.
I have also removed the logic for wrapping arguments before passing them through. This removes the benefit from the debug hooking system, and so I have always reverted the logic to wrap all incoming arguments.
alert.apply(this, [1]);
p = new Proxy(this, {});
try {
alert.apply(p, [1]);
} catch (e) {
console.log(e);
}
This throws an "Illegal Invocation" Exception.
typeof this === 'object'
true
But it seems that contexts are objects just like everything else.
I expect that passing a Proxy() through to context should succeed in an invocation. Barring this, I would expect the type of a context to be specific enough to determine whether it should be wrapped in a Proxy() or not.
I have two questions.
(1) What are the semantics of context binding closures in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
(2) What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
What type of object are contexts, and how can a javascript method tell one apart from other javascript objects by inspecting its properties at runtime?
There is no special type. Every object can become a context by calling a method upon it. Most objects that will become a context of a method call do have that very method as an (inherited) property, but there's no guarantee.
You cannot tell them apart.
What are the semantics of context binding in javascript that would cause binding to a Proxy(context) to fail with an illegal invocation?
When the method is a native one. In user code functions, the this context being a proxy doesn't make a difference, when you access it then it will just behave as a proxy.
The problem is native methods that expect their this argument to be a native object of the respective type. Sure, those objects are still javascript objects, but they may contain private data on internal properties as well. A proxy's target and handler references are implemented through such internal properties as well, for example - you can sometimes inspect them in the debugger. The native methods don't know to unwrap a proxy and use its target instead, they just look at the object and notice that it doesn't have the required internal properties for the method to do its job. You could've passed a plain {} as well.
Examples for such methods can be found as builtins of the ECMAScript runtime:
Map.prototype.has/get/set/…
Set.prototype.has/get/set/…
TypeArrayPrototype.slice/copyWithin/map/forEach/…
Number/String/Boolean prototype methods
But also (and even more of them) as host objects supplied by the environment:
window.alert/prompt
EventTarget.prototype.addEventListener/removeEventListener
document.createElement
Element.prototype.appendChild/remove/…
really just anything that's browser-specific
but also in other environments, like the nodejs os module
I have tried unwrapping Proxies in the right places by coding in edge cases and by blanket/heuristic policies.
I think the only reasonable approach would be to check whether the called function is a native one, and unwrap all arguments (including the this argument) for them.
Only a few native functions could be whitelisted, such as most of those on the Array.prototype which are explicitly specified in the language standard to work on arbitrary objects.
I have an Object like that:
function A(id) {
this.id = id;
}
A.prototype.getId = function() {
return this.id;
}
It is included in a html-page as a file ("objects.js") as well as in the web worker with importScript("objects.js").
Now I create an instance of A in the html-page with "var a = new A()" and post it with "postMessage()" to a Web Worker.
The funny thing is that in the worker it still has the property "id" with its value but the prototype function is lost.
I guess the reason may be that the prototype functions are "bound" to the html-page context and not to the web worker context.
So what I'm doing in the worker is that:
event.data.a.__proto__ = A.prototype;
It's working and I see it as some kind of cast...
Now my question is if that is the only and a valid way or if there's a better way of posting an object with prototype functions to a web worker.
The object definition is available in both contexts...
The structure clone algorithm that is used for serializing data before sending it to the web worker does not walk the prototype chain (for details, see § 2.7.5 Safe passing of structured data). That explains why the derived functions are not preserved.
Beside manually restoring the object as you did, you could also creating a new object, which has the prototype functions, and use Object.assign to copy the properties from the received object.
Note that both workarounds assume that the prototype object and their functions are known to the web worker. In general, there is no automated way to transfer arbitrary objects while preserving functions (see my answer to this related question about sending objects with functions).
The specification for webworkers does not allow for anything but strings to be passed.
Here is a question about this.
So you should serialize the object data with (for example) json and then deserialize it on the other side, and thus creating a new instance of the object, with the same data, inside the webworker.
The same method can be used to pass the object back out again - but both of them must know how to create, serialize and deserialize object of type A.
I'm trying to pass an object to a web worker through the postMessage function.
This object is a square that has a couple of functions to draw himself on a canvas and some other things. The web worker must return an array of this objects.
The problem is that when I call the postMessage function with this object, I get an this error:
Uncaught Error: DATA_CLONE_ERR: DOM Exception 25
I get this both sending the object to the worker and the other way around.
I think the error is because javascript must serialize the object, but can't do it because the object has functions built-in.
Does anyone ever had a similar problem? Do you know some workarround to this?
Thanks in advance.
There are a few reasons why the error that you mention could have been thrown, the reasons are listed here.
When sending objects to web workers, the object is serialized, and later deserialized in the web worker if the object is a serializable object.
This means that the methods for the objects you send to your web worker are not something that can be passed to the web worker (causing the error that you have run into), and you will need to provide the necessary methods/functions to the objects on the web worker's side of the environment, and make sure they are not part of the object that is passed to the web worker(s).
As you suspected objects with functions cannot be posted. The same goes for objects with recursive references, but this has changed in some browsers lately. Instead of risking doing manual and costly redundant serialization for every post you can perform a test at the beginning of your script to determine which functions to use for sending/receiving data.
I've had the same problem and solved it by moving almost all code into the worker and just keeping a renderer (wrapping the 2d context renderer) in the main thread. In the worker I serialize the different draw calls meant for the canvas into just numbers in an (typed) array. This array is then posted to the main thread.
So for instance when I want to draw an image I invoke the drawImage() method on my worker renderer instance in the worker. The call is translated into something like [13,1,50,40] which corresponds to the draw method enum, image unique id and its xy coordinates. Multiple calls are buffered and put in the same array. At the end of the update loop the array is posted to the main thread. The receiving main renderer instance parses the array and perform the appropriate draw calls.
I recently encountered this same problem when using web workers. Anything I passed to my worker kept all its properties but mysteriously lost all its methods.
You will have to define the methods in the web worker script itself. One workaround is to importScripts the class definition and manually set the __proto__ property of anything you receive. In my case I wanted to pass a grid object, defined in grid.js (yup, I was working on 2048), and did it like so:
importScripts('grid.js')
onMessage = function(e) {
e.data.grid.__proto__ = Grid.prototype;
...
}
When you pass data to a web worker, a copy of the data is made with the structured clone algorithm. It is specified in HTML5 (see § 2.9: Safe passing of structured data).
MDN has an overview of supported types. As functions are not supported, trying to clone objects containing functions will therefore throw a DATA_CLONE_ERR exception.
What to do if you have an object with functions?
If the functions are not relevant, try to create a new object that contains only the data that you want to transfer. As long as you use only supported types, send should work. Using JSON.stringify and JSON.parse can also be used as a workaround, as stringify ignores functions.
If the functions are relevant, there is no portable way. There are attempts to use a combination of toString and eval (e.g., used by the jsonfs library), but this will not work in all cases. For instances, it will break if your function is native code. Also closures are problematic.
The real problem with object and webworkers is with the methods of that objects. A object should not have methods just properties.
Ex:
var myClass = function(){
this.a = 5;
this.myMethod = function(){}
}
var notParseableObject = new myClass();
var myClass2 = function(){
this.a = 5;
}
var parseableObject = new myClass2();
The first wont work (with the mentioned error message) with postMessage and the second will work.
Some type of objects like ArrayBuffer and ImageBitmap which have the Transferable interface implementet and can be transfered without copy the Object.
Thats very usefull in Context of Canvas + Web worker cause you can save the time of copy the data between the threads.
take a look at the vkThread plugin
http://www.eslinstructor.net/vkthread/
it can pass function to a worker, including function with context ( object's method ). It can also pass functions with dependencies, anonymous functions and lambdas.
--Vadim
Another way of handling this (as I come across this question a decade later having needed to do it myself) is to define a static clone() function on your class that constructs a new object from (the properties of) an old one; then you can simply say
MyClass cloneObj = MyClass.clone(evt.data.myObj);
at the start of your worker to get a 'real' object of type MyClass that you can then call methods on from within your worker.
if you want to pass the object with methods you can stringify it and parse it at the receiving end.
postMessage(JSON.stringify(yourObject)
In the listener
this.worker.addEventListener('message', (event) => {
const currentChunk = JSON.parse(event.data);
});
I got a question regarding C++ Object & Javascript Object life cycle mis-synchronization and hope here your gurus could help me out.
Specifically, I am embedding SpiderMonkey in my C++ program. I am not sure if my approach is right or not. What I am doing is like
(1) C++ program loads a Javascript file and call an entry function.
(2) In the entry function, some C++ functions are called to initialize the program. During these calls, some C++ objects will be created.
(3) Based on user interaction, corresponding script function will be called as event handler.
This approach works, but with one problem (there could be unidentified more :)
That is,
In my JS event handler function, I need to fetch a C++ object to the Javascript context and call it member function. For this, in my C++ fetching function, I check if its corresponding JS peer object has been created or not. If not, I use JS_NewObject to create one and return it. Then the JS function could call native function on it.
The problem is that in some cases, the result of such native function call will lead the death of the C++ object. However, I can not find a way to notify the JS context to delete its JS peer object too. I failed to find a JSAPI function to do so.
In my current program, all the JS objects created using JS_NewObject are destroyed when finally the JS runtime is destroyed.
I guess this has something do with SipderMonkey's "garbage collection". But I have not found a good guide yet. Many thanks for any suggestionto
JS is a GC'd environment so you can't simply "delete" a GC allocated object. There are basically 2 options you can take:
Make your C++ object be dependent on the JS wrapper object, if you were using refcounting for instance you would increment the C++ object's ref when you created a wrapper, and decrement the ref in the wrapper objects finalizer.
When you destroy the C++ object, fetch the wrapper object (if it exists) as clear the reference to the C++ object. All your callbacks will now need to null check prior to using the C++ object, but you won't crash (you could throw a JS exception in response perhaps?)
In most cases option 1 is what users expect.
I'd point to the required API but i don't know the SM API (I know the JSC API instead, but they same concepts apply)
V8's documentation explains how to create a Javascript object that wraps a C++ object. The Javascript object holds on to a pointer to a C++ object instance. My question is, let's say you create the C++ object on the heap, how can you get a notification when the Javascript object is collected by the gc, so you can free the heap allocated C++ object?
The trick is to create a Persistent handle (second bullet point from the linked-to API reference: "Persistent handles are not held on a stack and are deleted only when you specifically remove them. ... Use a persistent handle when you need to keep a reference to an object for more than one function call, or when handle lifetimes do not correspond to C++ scopes."), and call MakeWeak() on it, passing a callback function that will do the necessary cleanup ("A persistent handle can be made weak, using Persistent::MakeWeak, to trigger a callback from the garbage collector when the only references to an object are from weak persistent handles." -- that is, when all "regular" handles have gone out of scope and when the garbage collector is about to delete the object).
The Persistent::MakeWeak method signature is:
void MakeWeak(void* parameters, WeakReferenceCallback callback);
Where WeakReferenceCallback is defined as a pointer-to-function taking two parameters:
typedef void (*WeakReferenceCallback)(Persistent<Object> object,
void* parameter);
These are found in the v8.h header file distributed with V8 as the public API.
You would want the function you pass to MakeWeak to clean up the Persistent<Object> object parameter that will get passed to it when it's called as a callback. The void* parameter parameter can be ignored (or the void* parameter can point to a C++ structure that holds the objects that need cleaning up):
void CleanupV8Point(Persistent<Object> object, void*)
{
// do whatever cleanup on object that you're looking for
object.destroyCppObjects();
}
Parameter<ObjectTemplate> my_obj(ObjectTemplate::New());
// when the Javascript part of my_obj is about to be collected
// we'll have V8 call CleanupV8Point(my_obj)
my_obj.MakeWeak(NULL, &CleanupV8Point);
In general, if a garbage-collected language can hold references to resources outside of the language engine (files, sockets, or in your case C++ objects), you should provide a 'close' method to release that resource ASAP, no point waiting until the GC thinks it's worthwhile to destroy your object.
it gets worse if your C++ object is memory-hungry and the garbage-collected object is just a reference: you might allocate thousands of objects, and the GC only sees a few KB's of tiny objects, not enough to trigger collection; while the C++ side is struggling with tens of megabytes of stale objects.
Do all your work in some closed scope (of object or function).
Then you can safely remove the C++ object when you went out of scope. GC doesn't check pointers for existence of pointed objects.