Fix x64 cross-apartment marshaling of IScriptError (Error cast -> E_NOINTERFACE)#36
Open
hugo-fc-visions wants to merge 1 commit into
Open
Conversation
…OINTERFACE)
On x64, casting ScriptControl.Error to the strongly-typed IScriptError/Error
interface fails with E_NOINTERFACE when the object is consumed from a COM MTA
thread (e.g. a .NET host whose main thread is MTA):
Unable to cast COM object ... to interface type 'MSScriptControl.Error' ...
QueryInterface ... IID '{70841C78-067D-11D0-95D8-00A02463AB28}' ...
E_NOINTERFACE (0x80004002)
Root cause: the control is registered ThreadingModel=Apartment (STA). When it
is created from an MTA thread, COM returns a proxy, and QueryInterface on that
proxy for the IScriptError vtable interface needs marshaling metadata. The
type library only declared IScriptControl, never IScriptError, so there was no
proxy/stub nor type-library marshaler registered for {70841C78-...} on x64 and
the cross-apartment QI failed. (Late-bound/IDispatch access still works because
IDispatch is always marshalable; only the strongly-typed vtable cast breaks.)
Fix: declare IScriptError in the .idl (dual + oleautomation, with the exact
vtable order and dispids CTScriptError already implements) so it becomes part
of the type library. The existing DllRegisterServer -> RegisterTypeLib call
then registers an oleautomation marshaler for the interface, and the
cross-apartment QueryInterface (and the managed cast) succeed.
No C++ change: CTScriptError already implements the interface (it uses the
#import-ed IScriptError, same IID); tsc64.cpp does not include the MIDL header,
so there is no type clash.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On x64, casting ScriptControl.Error to the strongly-typed IScriptError/Error interface fails with E_NOINTERFACE when the object is consumed from a COM MTA thread (e.g. a .NET host whose main thread is MTA):
Unable to cast COM object ... to interface type 'IScriptError' ...
QueryInterface ... IID '{70841C78-067D-11D0-95D8-00A02463AB28}' ...
E_NOINTERFACE (0x80004002)
Root cause: the control is registered ThreadingModel=Apartment (STA). When it is created from an MTA thread, COM returns a proxy, and QueryInterface on that proxy for the IScriptError vtable interface needs marshaling metadata. The type library only declared IScriptControl, never IScriptError, so there was no proxy/stub nor type-library marshaler registered for {70841C78-...} on x64 and the cross-apartment QI failed. (Late-bound/IDispatch access still works because IDispatch is always marshalable; only the strongly-typed vtable cast breaks.)
Fix: declare IScriptError in the .idl (dual + oleautomation, with the exact vtable order and dispids CTScriptError already implements) so it becomes part of the type library. The existing DllRegisterServer -> RegisterTypeLib call then registers an oleautomation marshaler for the interface, and the cross-apartment QueryInterface (and the managed cast) succeed.
No C++ change: CTScriptError already implements the interface (it uses the #import-ed IScriptError, same IID); tsc64.cpp does not include the MIDL header, so there is no type clash.
Code to reproduce using .net 10 console app: