Uh oh!
There was an error while loading. Please reload this page.
register_com_server: Fix incorrect CoRegisterClassObject rclsid argument - #533
register_com_server: Fix incorrect CoRegisterClassObject rclsid argument#533Fredrik Orderud (forderud) wants to merge 2 commits into
Conversation
Jon Wiswall (jonwis)
commented
Jun 16, 2025
Neat! Is there some improvement to |
Fredrik Orderud (forderud)
commented
Jun 17, 2025
|
…r_com_server function.
Charles Milette (sylveon)
commented
Jun 17, 2025
The docs say:
So it does appear that the C++/WinRT function is broken! It should return the class ID in this case. I think what trips it up is that C++/WinRT doesn't normally expect you to implement COM classes with I think a fix could be to instead try |
Either way, we can definitely merge this fix in IMO, because this is for COM servers, not WinRT servers (as shown by it not calling |
Kenny Kerr (@kennykerr) probably knows best w.r.t the |
Fredrik Orderud (forderud)
commented
Jun 17, 2025
I just created microsoft/cppwinrt#1494 to request either a |
Kenny Kerr (kennykerr)
commented
Jun 30, 2025
Sorry for the delay. I commented on this here: microsoft/cppwinrt#1494 (comment) |
The implementation is currently calling CoRegisterClassObject with the default interface ID GUID as rclsid argument. It should instead be passing the COM class ID GUID (ClassID) as rclsid argument. This commit will trigger an "error C2787: '<ClassName>': no GUID has been associated with this object" in classes passed as template argument to register_com_server that lack a UUID.
311f48d to
8df5ac0Compareroxk
commented
Jul 6, 2025
While these helpers are indeed for COM server, the classes provided by a COM server doesn't necessarily have to be COM classes. Implementing a COM server with WinRT types is valid and should be supported, so I'd object to merging this PR. As a person who pushed for using WinRT for everything in windows, only to get disappointed by the fact that widget API needs to support windows 10 so it cannot use WinRT server due to MSIX limitation...These helpers represent my last ditch effort to reduce friction of implementing everything in WinRT. Merging this PR defeats the purpose of these helpers. I want developers using wil use more WinRT, not more COM. COM support is welcome, but WinRT support is a must. It's the baseline of my contribution. TLDR: IMO the correct fix is to use |
| DWORD registration{}; | ||
| winrt::check_hresult(CoRegisterClassObject( | ||
| winrt::guid_of<T>(), winrt::make<CppWinRTClassFactory<T>>().get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, ®istration)); | ||
| __uuidof(T), winrt::make<CppWinRTClassFactory<T>>().get(), CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, ®istration)); |
There was a problem hiding this comment.
Please do not remove support for winrt::guid_of, thanks!
There was a problem hiding this comment.
Please do not remove support for
winrt::guid_of, thanks!
The WIL register_com_server function in question registers COM servers based on CLSID. I do then believe that __uuidof(T) would be more appropriate than winrt::guid_of<T>() for getting the CLSID for the COM class.
Do you have a concrete example of a COM class where it would be more appropriate to instead use winrt::guid_of<T>() for retrieving the CLSID, so that I can better understand your comment?
| } | ||
| struct MyServer : winrt::implements<MyServer, winrt::Windows::Foundation::IStringable> | ||
| struct __declspec(uuid("8D0E7037-9855-4659-B48D-F5DBD50F7836")) MyServer |
There was a problem hiding this comment.
These are meant to be winrt type types so they wouldn't explicitly define UUID. Please revert this and add MyComClass for testing support for COM classes instead, thanks!
There was a problem hiding this comment.
If this is removed, winrt::guid_of returns the UUID of IStringable, which is definitely not correct behavior for this purpose. CoCreateInstance(__uuidof(ISomeInterface)) should not be valid.
There was a problem hiding this comment.
These are meant to be winrt type types so they wouldn't explicitly define UUID.
However, they are being registered to a COM server so they need a CLSID. The fact these classes implement WinRT interfaces does not detract from this.
However, you have to abide by COM rules and have a CLSID. The current implementation does not do that. winrt::guid_of is only valid here when you have a full class defined in metadata with an exclusiveto default_interface. And if you have that, why the heck are you not implementing a WinRT server. |
Duncan Horn (dunhor)
commented
Jul 21, 2025
Going through this I can see valid arguments for both sides. First, some comments...
Using C++/WinRT for non-WinRT types is quite common, particularly within the Windows codebase itself. Chris Guzak (@ChrisGuzak) has been a major proponent of this usage. That said, it's not incredibly common to
This change doesn't affect that. Really all it's doing is making it more explicit about which GUID to use for the CLSID. You can
There are valid reasons you would want to register a WinRT class as a COM server since many features of Windows use COM types as currencies. Additionally, I think you mean "useful" not "valid" since the (original) tests pretty clearly demonstrate that it compiles with
This is my suggestion. I wrote the following code some years ago; perhaps it's time for a revival: template <typename T>
structhas_iid
{
template <typename U = T, std::enable_if_t<std::is_same_v<GUID, std::decay_t<decltype(__uuidof(U))>>, int> = 0>
static std::true_type invoke(int);
template <typename U = T>
static std::false_type invoke(float);
staticconstexprbool value = decltype(invoke(0))::value;
};
template <typename T>
constexprbool has_iid_v = has_iid<T>::value;You could then |
Charles Milette (sylveon)
commented
Jul 21, 2025
Absolutely, I do so myself. But parts of the supporting infra, like guid_of, was obviously designed for WinRT usage only in mind, and the ship has sailed for amending that because it would be a runtime behavior change. It would be interesting to make it a compiler error in cases where it does unexpected things (like here), however.
I agree there are valid cases. But those cases aren't usually the ones using full WinMD files with metadata and exclusiveto interfaces (the cases where
Unfortunately I don't think it's the best decision: I don't think that accidentally forgetting There is indeed no way to detect if a specific interface is exclusiveto, as that information isn't preserved in C++ source. C++26 will add custom attributes and the ability to reflect on them, which could interesting for C++/WinRT to expose here. I think the most reasonable thing is to directly use |
This isn't as uncommon as you might think, at least with OS code. That said, I'm not aware of any instances that use
Unless the C++ committee is moving heaven and earth even more so than they already are to get the base reflection in the working draft by the C++26 deadline, C++26 won't have reflection for attributes. But that shouldn't be necessary since the code gen can already include that info into the type system in a way that is template metaprogramming friendly.
For authoring, I'll agree with you, however consumption then becomes a little trickier. You'd need to have a In any case, I think I'm starting to come around to just accepting this change as-is. roxk shouldn't be blocked since adding a |
Duncan Horn (dunhor)
commented
Jul 22, 2025
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Charles Milette (sylveon)
commented
Jul 22, 2025
That's what I was thinking specifically. If you have WinMD/IDL files, usually you'd want a WinRT server instead of a COM server, to get the most benefit out of the hassle of getting that setup.
It is in the working draft now! It got merged last month. Static reflection is actually coming :) Anyways, I talked with roxk a bit offline and for them the As you've mentioned, the number of consumers is low (and docs don't exist yet) so I think we can get away with an API break here (it would also be more explicit to the user than a behavior change). |
… calls to use the ClassID instead of interface IDs. Using new random GUIDs from guidgen. This fixes the following compiler errors introduced by the previous commit: C:\Dev\microsoft_wil\include\wil\cppwinrt_register_com_server.h(51): error C2787: 'MyServer': no GUID has been associated with this object C:\Dev\microsoft_wil\include\wil/cppwinrt_register_com_server.h(51): note: the template instantiation context (the oldest one first) is C:\Dev\microsoft_wil\tests\CppWinRTComServerTests.cpp(74): note: see reference to function template instantiation 'std::vector<wil::unique_com_class_object_cookie,std::allocator<wil::unique_com_class_object_cookie>> wil::register_com_server<MyServer,>(void)' being compiled C:\Dev\microsoft_wil\include\wil/cppwinrt_register_com_server.h(70): note: see reference to function template instantiation 'void wil::details::register_com_server<MyServer,>(std::vector<wil::unique_com_class_object_cookie,std::allocator<wil::unique_com_class_object_cookie>> &)' being compiled C:\Dev\microsoft_wil\include\wil\cppwinrt_register_com_server.h(51): error C2787: 'BuggyServer': no GUID has been associated with this object C:\Dev\microsoft_wil\include\wil/cppwinrt_register_com_server.h(51): note: the template instantiation context (the oldest one first) is C:\Dev\microsoft_wil\tests\CppWinRTComServerTests.cpp(94): note: see reference to function template instantiation 'std::vector<wil::unique_com_class_object_cookie,std::allocator<wil::unique_com_class_object_cookie>> wil::register_com_server<BuggyServer,>(void)' being compiled C:\Dev\microsoft_wil\include\wil/cppwinrt_register_com_server.h(70): note: see reference to function template instantiation 'void wil::details::register_com_server<BuggyServer,>(std::vector<wil::unique_com_class_object_cookie,std::allocator<wil::unique_com_class_object_cookie>> &)' being compiled
8df5ac0 to
5b58451CompareFredrik Orderud (forderud)
commented
Jul 22, 2025
I just updated the PR to hopefully resolve the "missing clang format" CI error. |
Duncan Horn (dunhor)
commented
Jul 22, 2025
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Duncan Horn (dunhor)
commented
Jul 22, 2025
Oh, interesting. Attribute reflection really sounded like a future thing when first introduced; glad to see it expedited. Still, a template metaprogramming solution is probably more preferable in the near term should someone wish to pursue that route.
That sounds like a reasonable alternative to me. Just make sure to use something like template <typename... Types>
constexprautomake_clsid_array()
{
return std::array<GUID, sizeof...(Types)>{ winrt::guid_of<Types>()... };
} |
Fredrik Orderud (forderud)
commented
Aug 7, 2025
Closing PR, since it appear to have been replaced by #537 that is now merged. |
The implementation is currently calling
CoRegisterClassObjectwith the default interface ID GUID asrclsidargument. It should instead be passing the COM class ID GUID (ClassID) as rclsid argument.Also, update affected test code to stay in sync.