-
Notifications
You must be signed in to change notification settings - Fork 508
COM Interop Guidance #4219
Comments
@wjk Thanks for your interest , as you mentioned most of the COM specific code in System.Private.Interop is tailored to work with the internal MCG tool. But the good new is that we are working on making the MCG tool public , we don't have any time lines yet. With MCG tooling you should be able to do Desktop style COM interop. I will keep you posted on the progress and once it's out in public you should be able to contribute. |
@tijoytom @jkotas I had a thought on how we might go about implementing CoreCLR-style COM interop on CoreRT. Rather than try to bring up the MCG-specific functionality in |
Hosting both CoreCLR and CoreRT in the same process sounds pretty non-trivial. You may want to take a look at https://github.com/SharpGenTools/SharpGenTools . It is interop generator for COM that is very similar to MCG. I am not sure whether anybody tried it with CoreRT, but it should just work or it should be pretty easy to make it work. I believe that SharpGenTools are the easiest way to make COM work in CoreRT at this point. |
SharpGenTools isn't an option for two reasons: One, I haven't found any good, real-world examples on how to marshal COM types using it. Two, Windows Forms/WPF don't use it, and I take dependencies on those in all my projects. |
Agree - making SharpGenTools work for Windows Forms/WPF would need some work. Still, I think it is easier to make SharpGenTools work than to make both CoreCLR and CoreRT run in the same process to reuse COM interop. |
Unable to use corert until COM is built in, I manipulate Windows firewall and do not want to launch netsh process for each little rule change. |
@jkotas @MichalStrehovsky
|
We have abandoned the MCG tool. We do not have plans to open source the MCG tool anymore. Yes, generating the interop marshaling code using build-time tooling is the way to solve this. IDispatch brings additional complications. Starting with IUnknown makes sense. |
Does this code can be part of CoreRT tooling? or it is assumed that any program to be run under CoreRT has to manually manage COM objects? |
Does this kind of tooling preserve debugging (PDBs) and edit-and-continue support in VS? Last time I checked IL rewriting was not usable for working on large products because they degrade the development tools experience massively. If having COM interop support (which is pretty common for Windows applications) requires sacrificing development tools thats a no-go. |
SharpGenTools take C++ header files that define the prototypes/layouts of COM classes and produce .NET code that can call the APIs in the headers. The generated .NET code can run on any runtime. CppCodegen doesn't have any advantage in this respect. The key thing is that the generated .NET code doesn't rely on runtime's built-in COM support.
It should be an external tool that runs before the CoreRT compiler - it's easier to test it that way - the generated code should still run on all .NET runtimes (including CoreCLR), but won't rely on the internal COM handling anymore. It's how the closed source MCG tool operates as well. It would be beneficial for .NET in general - COM interop cannot be pregenerated by any of the .NET Core ahead of time technologies right now (neither CoreCLR nor Mono can do COM without doing a bunch of JITting). Having a tool would enable pregeneration on all runtimes (CoreCLR with ReadyToRun, Mono AOT, and CoreRT).
Debugging info will typically be preserved by the rewriter. I don't think edit and continue is supported on COM interfaces so that limitation would stay in place. |
@jkotas I trying to understand what do you think needed for COM support in CoreRT. I see dotnet/runtime#1845 and other issues which you mention landed in .NET 5. I imagine that .NET 5 would be requirement to start playing with COM support in CoreRT. Does this sample (dotnet/samples#2873) can be used for starting poking hole in the COM support? Seems to be this is for exposing .NET object as IDispatch, so not so valuable for short term tests. If I take example how My first goal is to have basic controls working, and only function which is holding me for now, is
so maybe I can implement very simple holder class for I'm trying to limit amount of work in that area, so I can manage learning and implementation. |
Here is how to start on this.
@AaronRobinsonMSFT or me will happy to help with any problems you hit along the way. We have not really validated whether the step 5 is doable for something like WinForms, so there may be unexpected issues along the way. |
I make dummy implementation which just throw. and then I immediately hit another issue.
That interface is internal to WinForms. See https://github.com/dotnet/winforms/blob/5d7ad6eb0eac45d01407d512bb4fef86d1ecd800/src/System.Windows.Forms.Primitives/src/Interop/OleAut32/Interop.IEnumVariant.cs#L15 If I just drag it to project, it does not helps too. So this is first bottleneck.
|
Ideally, Roslyn would have support for I do not think you want to take
|
I don't recall discussions about On the other hand, there is the option to handle this at the original callsite. The caller may know what type is expected and instead of calling The globally registered version is going to have to QI for all types it can project. The set is finite but can be large if the desire is to have a truly universal |
Agree that is possible to address all of this by changing the calling code. I was hoping that
Or we need to look at bringing back ICastable in some form... |
What information do you think would be helpful here? It could be done for specific scenarios. In this case the globally registered version could know about each and every WinForms interface, but it doesn't really help with the look up. We need to know the calling context - not supplied at the callsite typically - and the finite set of interfaces to consider. The latter is possible if we know that WinForms is the target. How do you envision optimizing this scenario without knowing what the
I really need to look into that tech more. I wish I knew more about it. |
Just to give some stats
and I really hope this would not be needed
My small experiment stuck after I implement 2 RCW for (IAssesible and IEnumVariant). Next step would be create CCW for |
That address looks like a sentinel value ( |
@AaronRobinsonMSFT @elinor-fung It looks like a bug here: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/interopconverter.cpp#L467 We QueryInterface for the requested interface, but then we throw it away and return IUnknown. The bogus pointer that we are crashing on came from IUnknown being used instead of the requested interface. |
Opened dotnet/runtime#35883 |
I was trying to run application under locally built .NET 5, but seems to be to no avail.
Then I try
and following error
Error from missing locally built ASP.NET Core, but I do not expect it to be included when run WindowsForms and don't know how to out out. I suspect that issue caused by the differences in |
The easiest way to use your locally built runtime with a WinForms app is to publish the app as self-contained and then copy over your locally build CoreCLR (ie copy over everything from |
Okay, I manage to make some progress. I do not done with debugging, but seems to be I can get stuck in the middle, so will go for a walk. I have local CoreCLR from dotnet/runtime#36054
Location where originate that exception. So far seems to be this is issue on CoreCLR side or I screw my application in major way. |
|
Okay. Walking on fresh air help slightly. The actual error happens during marshalling of
So not sure if this is me which plug After I remove |
Since you are doing the marshalling, it would be best to do all of it. Change the delegate to:
And convert the IntPtr to IRawElementProviderSimple yourself. |
Would this pattern works?
I want to return unmanaged COM interface from that method, which wraps call to
|
You also need to do QueryInterface for the interface with the right GUID. |
So it would be something like that? public static int HostRawElementProviderInternal(IntPtr thisPtr, IntPtr* i)
{
i = null;
try
{
var inst = ComInterfaceDispatch.GetInstance<IRawElementProviderSimple>((ComInterfaceDispatch*)thisPtr);
IntPtr pUnk = Marshal.GetIUnknownForObject(inst.HostRawElementProvider);
Guid targetInterface = typeof(IRawElementProviderSimple).GUID;
int result = Marshal.QueryInterface(pUnk, ref targetInterface, out IntPtr ppv);
if (result == 0)
{
*i = ppv;
}
return result;
}
catch (Exception e)
{
return e.HResult;
}
return 0; // S_OK;
}
`` |
You also need to release the pUnk once you are one with it. Performance:
|
Seems to be I'm close
Next set of questions while I have your attention. There need to bring ComWrappers into CoreRT. My understanding that you and @MichalStrehovsky copy code from dotnet/runtime by moving existing commits and preserve authorship. Can you share some snippets how I can do that. and how I can select which commit to choose.
What's way to move forward on this? |
I do not think it applies here. The implementation in CoreRT is going to be sufficiently different (it should be 99+% C#) that you can start from scratch, not worrying about preserving history. |
I plan to add tests, to guide implementation, but since they are targeting .NET Core 2.1 I have compilation errors that |
I am considering using CoreRT with my .NET Core compatible GUI framework. However, to fully implement the GUI feature support I require, I will need to do some COM interop. Having studied the CoreRT source code, I can tell that COM support is not currently implemented. To make this usable, here is what I would do:
ComImportAttribute
-decorated types toCoCreateInstance
. Wrap the return value of that P/Invoke into something like this.ComImportAttribute
-decorated interfaces to code that takes the slot number of the method called, gets the corresponding vtable entry and performs acalli
.The problem is, though, this is not compatible in the slightest with the extensive but nonfunctional COM interop code already in the CoreRT repo. This COM interop code is only partially open-source (it references .NET Native functionality, as well as the MCG tool which is still proprietary), and is entirely WinRT-specific on top of that. Modifying the existing COM interop code to be compatible with desktop-style COM is currently far above my pay grade. Could anyone please give some pointers on how I or others might start working on implementing this? Thanks so much!
The text was updated successfully, but these errors were encountered: