Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can C++/CX and C++/WinRT be used in the same project?

Earlier this week, Kenny Kerr presented C++/WinRT at CppCon 20161. It is a Standard C++ projection for the Windows Runtime, based on Modern.

As far as I understand, the C++/CX compiler/preprocessor/code generator doesn't touch Standard C++ code, and with C++/WinRT being a Standard C++ library it is my naïve interpretation, that both C++/CX and C++/WinRT can be used in the same project.

Questions:

  • First things first: Is my naïve interpretation correct?
  • If so, can C++/CX and C++/WinRT be used in the same compilation unit?
  • At what granularity can C++/CX and C++/WinRT be mixed, in case they cannot reside in the same compilation unit?
  • Can C++/WinRT consume types implemented with C++/CX in the same project? (I expect this to be difficult, since the C++/WinRT compiler needs to generate headers from the .winmd metadata, so there is a dependency on the (pre-)compiler output.)

In case it matters, answers to those questions allow me to make decisions now on how to move my C++/CX projects into the future.


1Embracing Standard C++ for the Windows Runtime (on YouTube).
like image 453
IInspectable Avatar asked Sep 25 '16 11:09

IInspectable


2 Answers

The short answer is that yes C++/CX and C++/WinRT can be used within the same project.

The C++/CX compiler injects the Winmd types into the root namespace. C++/WinRT wraps everything inside its own root winrt namespace to accommodate interop with C++/CX and avoid C++ compiler ambiguity errors with other libraries. So the following C++/CX code:

using namespace Windows::Foundation;
using namespace Windows::Networking;

Uri ^ uri = ref new Uri(L"https://moderncpp.com/");
HostName ^ name = ref new HostName(L"moderncpp.com");

May be rewritten with C++/WinRT as follows:

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Networking;

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");

Alternatively, if you’re compiling with /ZW then you might rewrite it as follows (to avoid error C2872: 'Windows': ambiguous symbol):

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Networking;

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");

Another way you might combine both C++/CX and C++/WinRT in the same source file is to use a root namespace for both as follows:

namespace cx
{
    using namespace Windows::Foundation;
    using namespace Windows::Networking;
}

namespace winrt
{
    using namespace Windows::Foundation;
    using namespace Windows::Networking;
}

void Sample()
{
    cx::Uri uri(L"https://moderncpp.com/");
    winrt::HostName name(L"moderncpp.com");
}

At the end of the day, C++/WinRT is just a standard C++ library that you may include into any applicable C++ project. C++/CX and C++/WinRT do however deal with metadata very differently. C++/CX both consumes and produces metadata directly whereas C++/WinRT is constrained by standard C++ and thus requires a standalone tool (cppwinrt.exe) to assist in bridging that gap.

like image 157
Kenny Kerr Avatar answered Oct 23 '22 02:10

Kenny Kerr


Regarding the question "Can C++/WinRT consume types implemented with C++/CX in the same project?"

The answer is Yes and No. With a 'ref class' defined in the same project, as such a project must be compiled with C++/CX enabled, your code can simply use the class as it can any ref class.

However, if you want to consume the 'ref class' as a C++/WinRT projection, the answer is effectively no.

In order to get the C++/WinRT projected class definition, you need to run the cppwinrt.exe compiler over the metadata for the 'ref class'. That would require somehow getting the metadata. You could rig up some mechanism to compile the 'ref class' once, get the winmd, process it through mdmerge to put it in canonical form, run cppwinrt.exe on the metadata to get the projected class definition, then include the generated headers.

Alternatively, you can write the IDL to describe the 'ref class', compile it to metadata using MIDLRT, then run cppwinrt.exe. Neither is practical IMO.

The most reasonable alternative is simply use the ref class as is as a C++/CX type, as the definition is in the same solution. Next most practical solution is put the class in a separate project, compile it getting the winmd, then creating headers from the winmd. This approach also allow the separate project that consumes the 'ref class' (via the projection) to build without use of C++/CX code.

To be completely transparent, note that our initial release (now available at https://github.com/Microsoft/cppwinrt) does not include the cppwinrt.exe compiler itself. Rather, it contains the C++/WinRT header files containing projections for all Windows Runtime types/APIs defined in the Windows 10 Anniversary Update SDK -- this includes the Universal Platform APIs and all Extension SDK APIs.

like image 20
Brent Rector Avatar answered Oct 23 '22 03:10

Brent Rector