2016-09-25 142 views
9

本週早些時候,Kenny Kerr presented C++/WinRT at CppCon 2016 。它是基於Modern的Windows運行時的標準C++投影。據我所知,C++/CX編譯器/預處理器/代碼生成器不會觸及標準C++代碼,並且C++/WinRT是一個標準C++庫,這是我的天真解釋,C++/CX和C++/WinRT可以在同一個項目中使用。C++/CX和C++/WinRT可以在同一個項目中使用嗎?

問題:

  • 首先第一件事情:是我天真的解釋是否正確?
  • 如果是這樣,C++/CX和C++/WinRT可以在同一個編譯單元中使用嗎?
  • 如果C++/CX和C++/WinRT不能駐留在同一個編譯單元中,它們的粒度是多少?
  • C++/WinRT可以在同一個項目中使用C++/CX實現的類型嗎? (我預計這會很困難,因爲C++/WinRT編譯器需要從.winmd元數據生成頭文件,所以依賴於(預)編譯器輸出。)

萬一它很重要,回答這些問題讓我現在就如何將我的C++/CX項目推向未來做出決定。


Embracing Standard C++ for the Windows Runtime (on YouTube)

+0

Hmya,我們不得不看看他過去一年的工作,他沒有更新他的github存儲庫。如果你之前從來沒有充分理由進入WRL,那麼C++/WinRT不太可能旋轉任何螺旋槳。這實際上是什麼,至少現代風格的味道,另一個像WRL的包裝,但更新爲C++ 1xyz。科爾和麥克奈利斯的代碼讓我頭痛,你可以看看它做了什麼,但不容易看出它沒有做什麼。 –

+0

@HansPassant:C++/WinRT(通過C++/CX)的主要原因是性能。編譯時間不是很好,通常錯誤信息是很好的謎語。儘管如此,我還是喜歡簡潔(或者過於簡潔,如果你願意的話)語法,而不是明確的WRL調用(雖然我可能會改變主意,但我必須首次調試真正的問題)。我同意,很難看出,哪些代碼(或不這樣做)。但對於C#/ .NET來說,情況也是如此,並且從來沒有讓它成爲許多人的首選目標。無論如何,個人偏好是個人的,我猜;) – IInspectable

+0

我不是C++專家,但是......爲什麼不呢? C++/CX項目可以有常規的C++代碼,而C++/WinRT只是常規的C++,對吧? –

回答

2

關於「C++/WinRT能否在同一個項目中使用C++/CX實現類型的問題?」

答案是肯定的,沒有。由於在同一個項目中定義了一個'ref class',因此這樣的項目必須使用C++/CX啓用編譯,您的代碼可以像任何ref類一樣簡單地使用該類。然而,如果你想把'ref class'作爲C++/WinRT投影,那麼答案是否定的。

爲了獲得C++/WinRT預計的類定義,您需要在'ref class'的元數據上運行cppwinrt.exe編譯器。這需要以某種方式獲取元數據。你可以建立一些機制來編譯'ref class'一次,獲取winmd,通過mdmerge處理它,將其放入規範形式,在元數據上運行cppwinrt.exe以獲得預計的類定義,然後包含生成的頭文件。

或者,您可以編寫IDL來描述'ref class',使用MIDLRT將其編譯爲元數據,然後運行cppwinrt.exe。國際海事組織也不是。

最合理的選擇是簡單地使用ref類作爲C++/CX類型,因爲定義在相同的解決方案中。接下來最實用的解決方案是把這個類放在一個單獨的項目中,編譯得到winmd,然後從winmd創建頭文件。這種方法還允許使用「ref class」(通過投影)的單獨項目在不使用C++/CX代碼的情況下構建。

要完全透明,請注意,我們的初始版本(現在可在https://github.com/Microsoft/cppwinrt處)不包含cppwinrt.exe編譯器本身。相反,它包含C++/WinRT頭文件,其中包含Windows 10週年更新SDK中定義的所有Windows運行時類型/ API的預測 - 其中包括通用平臺API和所有擴展SDK API。

+0

這是一個很好的總結,謝謝你。這很像我想到的方式。除此之外,我完全錯過了(現在很明顯的)事實,即可以使用其他標準C++代碼(例如C++/WinRT)中的C++/CX語言擴展簡單地使用'ref class's。而當你暗示它:*「很快」*多久?感覺就像我已經失眠超過一年多了。儘管我確實明白你需要在第一時間把它做好,但事先沒有編譯器是有點讓人失望的。 – IInspectable

+0

對於C++/WinRT使用C++/CX類型,現在嘗試應用https://gist.github.com/kennykerr/105f96d61f51b5773670844edec99d85。 :) –

10

簡短的回答是可以在同一個項目中使用C++/CX和C++/WinRT

C++/CX編譯器將Winmd類型注入到根名稱空間中。 C++/WinRT將所有內容封裝在其自己的根winrt名稱空間中,以適應C++/CX的互操作性,並避免與其他庫發生C++編譯器模糊性錯誤。所以,下面的C++/CX代碼:

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"); 

可與C++/WinRT中被改寫爲:

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

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

另外,如果你使用/ ZW進行編譯,然後可以按照以下方式重寫它(避免錯誤C2872:「視窗」:曖昧的符號):

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

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

你可能既包括C++/CX和C++/WinRT中相同的源文件中是使用一個根命名空間既如下另一種方法:

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"); 
} 

在一天結束時,C++/WinRT只是一個標準的C++庫,您可以將其包含到任何適用的C++項目中。不過,C++/CX和C++/WinRT處理元數據的方式非常不同。 C++/CX都直接消耗和生成元數據,而C++/WinRT受標準C++的約束,因此需要一個獨立的工具(cppwinrt.exe)來幫助縮小這個差距。

+0

非常感謝您的回答。所以在源代碼級,C++/CX和C++/WinRT都可以在同一個編譯單元中共存。然而,異構工具可能需要分離(當消費者和生產者生活在不同的語言預測中時)。一個細節我不清楚,但:* cppwinrt.exe *從C++/WinRT源代碼或目標代碼中提取.winmd元數據?還是有額外的需求(如MIDL文件)發佈C++/WinRT實現供其他語言預測使用? – IInspectable

+0

它們可以共存,但應該注意的是,某些特定的系統/實用程序標題在使用'/ ZW''構建時會改變行爲而不是沒有行爲,並且某些標題需要它。如果您使用不帶''/ ZW''的C++/WinRT,這也會導致額外的編譯器警告。 –

+0

似乎要回答OP的問題,/ ZW不能同時出現在同一個編譯單元中。因此,對於標準的C++結構,C++/CX和C++/WinRT共存於同一項目中的最小粒度是在同一個鏈接單元(例如DLL; EXE)中的不同編譯單元。但對於.NET結構,共存的唯一方法是通過C++/CX(和C#)和C++/WinRT展示這些.NET結構 - 絕對不能通過標準C++域繞過幕後。 – optikos

相關問題