How to raise an exception from C++ that will trigger scripting exception handlers
Question
I've been finding bits and pieces to this answer on the web, but not a crystal clear solution.
Here's what i'm trying to do. 1) Create an ATL Simple Object. 2) Add a method to that object which returns a BOOL, not an HRESULT. The caller wants true/false return values. 3) Throw an exception to a jscript or vbscript caller that will provide e.description and e.number data.
RE 2) I've found that I can use STDMETHODIMP_(BOOL) along with [local] to allow BOOL to be returned RE 3) I've found that I can pass IErrorInfo via SetErrorInfo() to populate the Error object
My dilemma is I can't figure out how to architect C++ to throw an exception across the ABI boundary that won't crash the caller.
Solution
When you write code for a scripting client then you must use a subset of COM called Automation. Which dictates that:
- all interfaces must be derived from IDispatch
- a coclass should implement only one source interface
- all methods must return a HRESULT, only STDMETHODIMP is valid
- argument types must be restricted to the subset permitted by Automation.
In particular that means that BOOL is not permitted, it must be VARIANT_BOOL. You declare a method that returns a boolean by writing it like this in IDL:
[id(42)] HRESULT Foo([out,retval] VARIANT_BOOL* retval);
Assign VARIANT_TRUE or VARIANT_FALSE to *retval in your code. The scripting language uses natural syntax like var = Foo()
.
You generate an exception in the scripting client by returning a failure HRESULT.
OTHER TIPS
You can make the client handle an 'exception' by
- setting the IErrorInfo like you said
- returning a non HRESULT hr != S_OK
So, you need IDispatch/Interop compatible interfaces, which require HRESULT return types (AFAIR).
IDL allows a lot more, but 'dynamic' clients like script hosts (VBS, JScript, VBA and others) don't consume those natively, so the interoperability will not be optimal.