{"id":106713,"date":"2022-06-06T07:00:00","date_gmt":"2022-06-06T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106713"},"modified":"2022-06-06T06:48:18","modified_gmt":"2022-06-06T13:48:18","slug":"20220606-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220606-00\/?p=106713","title":{"rendered":"An opinionated comparison of C++ frameworks for consuming and implementing Windows Runtime types"},"content":{"rendered":"<p>There are three leading C++ frameworks for consuming and implementing Windows Runtime types. The current recommendation (as of this writing) is C++\/WinRT.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<th>WRL<\/th>\n<th>C++\/CX<\/th>\n<th>C++\/WinRT<\/th>\n<\/tr>\n<tr>\n<th>Error handling<\/th>\n<td><code>HRESULT<\/code>-based<\/td>\n<td>Exception-based<\/td>\n<td>Exception-based<\/td>\n<\/tr>\n<tr>\n<th>Interop with C++<br \/>\nstandard library<\/th>\n<td>Poor<\/td>\n<td>Middling<\/td>\n<td>Good<\/td>\n<\/tr>\n<tr>\n<th>Code verbosity<\/th>\n<td>Very high<\/td>\n<td>Low<\/td>\n<td>Low<\/td>\n<\/tr>\n<tr>\n<th>Code generation<\/th>\n<td>Small<\/td>\n<td>Explosively large<\/td>\n<td>Small<\/td>\n<\/tr>\n<tr>\n<th>Compile time<\/th>\n<td>Low<\/td>\n<td>Low<\/td>\n<td>High\u00b9<\/td>\n<\/tr>\n<tr>\n<th>IDL file<\/th>\n<td>Manually authored<\/td>\n<td>Automatically generated\u00b2<\/td>\n<td>Manually authored<\/td>\n<\/tr>\n<tr>\n<th>Static class constructor\u00b3<\/th>\n<td>Supported<\/td>\n<td>Not supported<\/td>\n<td>Supported<\/td>\n<\/tr>\n<tr>\n<th>COM static lifetime<br \/>\nfor factories\u2074<\/th>\n<td>Can implement manually<\/td>\n<td>Cannot implement<\/td>\n<td>Built-in<\/td>\n<\/tr>\n<tr>\n<th>Default threading model<\/th>\n<td>It&#8217;s complicated\u2075<\/td>\n<td>Free<\/td>\n<td>Free<\/td>\n<\/tr>\n<tr>\n<th>Can choose nondefault<br \/>\nthreading model<\/th>\n<td>Yes<\/td>\n<td>No<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<th>Language<\/th>\n<td>Standard C++<\/td>\n<td>Nonstandard extension<\/td>\n<td>Standard C++<\/td>\n<\/tr>\n<tr>\n<th>Static analysis tools<\/th>\n<td>Supported<\/td>\n<td>Not supported<\/td>\n<td>Supported<\/td>\n<\/tr>\n<tr>\n<th>Language standard<br \/>\nrequired<\/th>\n<td>C++11 and higher<\/td>\n<td>C++14 or C++17<br \/>\nwith <code>\/await<\/code><\/td>\n<td>C++17 and higher<\/td>\n<\/tr>\n<tr>\n<th>Forward compatibility<\/th>\n<td>Compatible<\/td>\n<td>Incompatible with C++20<\/td>\n<td>Compatible<\/td>\n<\/tr>\n<tr>\n<th>XAML compiler support<\/th>\n<td>No<\/td>\n<td>Yes<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<th>Coroutine support<\/th>\n<td>No<\/td>\n<td>Yes via PPL\u2076<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<th>License\/source code<\/th>\n<td>Ships in SDK<\/td>\n<td>Closed source<\/td>\n<td><a href=\"https:\/\/github.com\/Microsoft\/cppwinrt\">Open source<\/a><\/td>\n<\/tr>\n<tr>\n<th>Support<\/th>\n<td>Maintenance<\/td>\n<td>None<\/td>\n<td>Active<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><b>Notes<\/b><\/p>\n<p>\u00b9 C++\/WinRT contains a large number of types and template specializations, which slows down the compiler. The precompiled header file easily exceeds 1GB in size. You can <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/uwp\/cpp-and-winrt-apis\/macros\"> define <code>WINRT_<wbr \/>LEAN_<wbr \/>AND_<wbr \/>MEAN<\/code><\/a> to remove rarely-used features and improve compile times.<\/p>\n<p>\u00b2 Automatic generation of the IDL file is a two-edged sword. Although it saves a lot of effort, it can also get in the way: If you need to make a runtime class object marshallable, you need to register a marshaller for the autogenerated interface, which will have an ugly autogenerated name, and whose UUID may not be stable. Autogeneration also conflicts with versioning, makes it harder to interop with other languages, and it can result in puzzling behavior if you don&#8217;t understand how the autogeneration works. Furthermore, the autogenerated interface names do not follow Windows Runtime naming conventions.<\/p>\n<p>\u00b3 Static class constructors allow class statics to be delay-initialized. This is significant because running constructors at <code>DLL_<wbr \/>PROCESS_<wbr \/>ATTACH<\/code> creates the risk of deadlocks and other unfortunate behaviors. C++\/CX clients must work around this by having a static <code>Initialize\u00adStatics()<\/code> method which initializes the statics (e.g., dependency properties) and calling it at an opportune moment.<\/p>\n<p>\u2074 <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210208-00\/?p=104812\"> COM static lifetime<\/a> allows you to register an object in the COM static lifetime store, which allows you to (1)\u00a0obtain it later, and (2)\u00a0destruct it automatically when COM is uninitialized. The former provides a persistent-lifetime object for things like global event sources. The latter permits the object&#8217;s destructors to run while COM is still initialized.<\/p>\n<p>\u2075 Default is normally free-threaded, but if <code>BUILD_<wbr \/>WINDOWS<\/code> is set, then default is single-threaded.<\/p>\n<p>\u2076 PPL coroutine support is very large.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The three leading contenders.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-106713","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The three leading contenders.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106713","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106713"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106713\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106713"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106713"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106713"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}