-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Opt COM methods out of the new Windows instance-method handling. #23974
Opt COM methods out of the new Windows instance-method handling. #23974
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
@JeremyKuhne just a heads up that we're reverting the change to supporting returning structures from COM methods in .NET (we're keeping it for ThisCall). So we still won't be able to support mapping DirectX via the built-in COM support without additional work done at some point in the future (likely some sort of explicit opt-in attribute on individual methods). |
cc: @tannergooding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
It might be worthwhile adding a COM test explicitly validating the struct wrapper behavior, however.
I would agree with this. It would also provide a nice location to document the scenario that appears to be so common (i.e. |
Can someone explain (or link to the issue) why having a struct HRESULT which has a memory layout equivalent to an integer is preventing a fix to COM/DirectX interop? I'm doing a lot of windows interop (including some DirectX via builtin interop) and never ran into an issue, so I'm really curios. Isn't a managed struct with explicit layout to 4 byte and int at offset zero, equivalent in memory layout to a plain integer? I can see how there can be bugs by code not looking closely enough at the struct, but why would this prevent correctly handling calling conventions? Is a C struct wrapping an integer not equivalent to a plain integer in these calling conventions? |
The memory layout is equivalent, but the C++ calling convention rules for these two are not always the same. For example, compile the following C++ snippet on Windows x86:
And look at the disassembly for methods M1 and M2:
You can see that the value is returned via
Classic COM methods always return HRESULTs. DirectX is using atypical flavor of COM (it is sometimes called However, there are number of other reasons why the built-in COM interop is not a great fit for DirectX and why SharpDX was invented. It is unlikely that the fix alone would turn build-in COM interop with DirectX into a success story. |
Thats strange, if I try to return a wrapper struct from a STDCALL non-member function then it goes through EAX for me. Can't find a clear technical specification of STDCALL right now. struct HRESULT2 { HRESULT hr; };
struct ITest { STDMETHOD_(HRESULT2, Run)() = 0; };
struct ITestVtbl { HRESULT2 (STDMETHODCALLTYPE *Run)(ITest* This); };
struct Test : ITest { STDMETHODIMP_(HRESULT2) Run() { return { E_FAIL }; } };
static STDMETHODIMP_(HRESULT2) RunImpl(ITest* This) { return { E_FAIL }; } both are Seeing that #19474 was probably what triggered this whole thing, unless I made a mistake somewhere that would make the ID2D1RenderTarget::GetSize API inherently nonportable across languages, as you can't call it via C based interop anymore. Usually the Windows headers used to be C compatible, and classic MIDL style COM even generates a vtbl struct of function pointers, but if you would do that for this interface then the calling convention of a function pointer and instance method is not the same ?! Thats a really unfortunate mess of a calling convention :-( Thanks a lot for the explanation. |
You can find more documentation on the Windows calling conventions here and in the neighboring docs: https://docs.microsoft.com/en-us/cpp/cpp/thiscall?view=vs-2019 The primary reason for |
This is not correct. Consider this:
compiles into:
|
Yeah, what I'm going for is that apparently The current issue with COM aside, this difference will probably affect the C# language proposals for static delgates / function pointers as well. You probably want to be able to express both, and just specifying STDCALL won't be enough then. @jkotas do you know if this is already being considered, or if not, where to bring it up in case it is relevant? I'm not up to date anymore with those proposals, but last I've seen (~ half a year ago) they were still being considered as language extensions. I remember some people wanted to use this feature for exactly this kind of interop ... |
The design document is in csharplang repo. I have submitted dotnet/csharplang#2432 to capture this point in it. Please take a look. |
@jkoritzinsky This looks like a legitimate test failure in COM. |
Yeah I’ll take a look tomorrow morning when I get into the office to see what’s up. |
…consider thiscall.
I've verified locally that dialogs in NuGet Package Explorer work with this change. |
Test failures are from an infra issue. Merging this into master. |
…net/coreclr#23974) * Opt COM methods out of the new Windows instance-method handling. * Add test for an HResult "struct" returned from a COM method. * Update ErrorMarshalTesting.cs * Update "is member function" check on the ilmarshalers.h side to only consider thiscall. Commit migrated from dotnet/coreclr@9f9dcdd
Some of our users (such as WPF), use a struct to wrap their HRESULT return types on COM members when they use PreserveSig. When we updated CoreCLR to correctly handle the Windows calling convention, we broke this behavior.
Remove tests that were verifying that COM follows the new behavior.
Supercedes #23955
cc: @jeffschwMSFT @davidwrighton