WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

C++/WinRT - including the Microsoft.Windows.AppLifecycle.h header file causes issues

Open jaigak opened this issue 4 years ago • 8 comments

Describe the bug

When you include the Microsoft.Windows.AppLifecycle.h (or any other header that starts with Microsoft.Windows), it causes issues in other AppSDK headers included after that (eg: Microsoft.UI.Xaml.h) since the generated code references types under the Windows::Foundation namespace but the compiler thinks that it's the Microsoft::Windows::Foundation namespace which doesn't exist.

Steps to reproduce the bug

  1. Include any header that starts with "Microsoft.Windows" before other AppSDK headers.
  2. See the error.

Expected behavior

This should compile and work. Including the header, after all other AppSDK headers works but shouldn't be necessary.

Screenshots

Screenshot 2021-12-12 at 16 52 30

NuGet package version

1.0.0

Packaging type

Packaged (MSIX)

Windows version

Windows 10 version 21H2 (19044, November 2021 Update)

IDE

Visual Studio 2022

Additional context

No response

jaigak avatar Dec 12 '21 11:12 jaigak

This sounds like an issue with "using" statements. Can you show me your repro C++ file and/or precompiled header? I suspect the specific issue here is that since Windows isn't prefixed with "::", if you add the line "using Microsoft", the name Windows becomes ambiguous. Tthe error shown seems slightly misaligned with that interpretation, so I'd like to repro what you're seeing before jumping too far ahead.

BenJKuhn avatar Dec 13 '21 20:12 BenJKuhn

@BenJKuhn I'm not "using Microsoft" inside the precompiled header and the error occurs only inside the Microsoft namespace.

jaigak avatar Dec 14 '21 01:12 jaigak

It's not an issue with using statements.

The gist of the issue is that since the namespace is unqualified, lookup rules will traverse the namespace tree backwards to find a Windows namespace. Because of the inclusion order (<winrt/Microsoft.Windows.AppLifecycle.h> is included before <winrt/Microsoft.UI.Xaml.h>) a winrt::Microsoft::Windows namespace exists while <winrt/Microsoft.UI.Xaml.h> is being parsed. The namespace lookup goes as follows.

  • It will look at winrt::Microsoft::UI::Xaml to see if there's a Windows namespace within. There is not.
  • It will look at winrt::Microsoft::UI to see if there's a Windows namespace within. There is not.
  • It will look at winrt::Microsoft to see if there's a Windows namespace within. There is, so the search stops here.

Then, it will lookup winrt::Microsoft::Windows for a namespace named Foundation, which does not exist. So the compiler stops here and throws the error seen above.

TLDR; this is an issue with the cppwinrt codegen, it should use winrt::Windows::Foundation::IUnknown here.

sylveon avatar Dec 23 '21 09:12 sylveon

I also think not using Microsoft.Windows would be the best move considering that according to https://github.com/microsoft/WindowsAppSDK/issues/1823, adding a using namespace within the winrt namespace is considered "best practice" (I would personally not consider anything involving using namespace to be best practice, but w/e), somebody is bound to do

namespace winrt
{
    using namespace Microsoft;
}

and everything will blow up spectacularly (something as simple as winrt::Windows becomes ambiguous).

But it's probably too late for that.

sylveon avatar Dec 23 '21 10:12 sylveon

@chrisguzak fyi on the practice of nesting using namespaces under winrt and unintended consequences

asklar avatar Dec 27 '21 03:12 asklar

I think this is a bug in cppwinrt.exe which has already been fixed there. When I manually generate the headers using the latest cppwinrt NuGet the headers correctly contain the winrt:: prefix.

Since we can’t use these headers generated by the newer cppwinrt.exe since they don’t match the cppwinrt version used to generate the WinRT system headers we use this crude one-liner to manually fix up our generated headers:

powershell -noprofile -command "Get-ChildItem -Recurse -Filter *.h | Foreach-Object {"^
  "  $tmp = (Get-Content -Path $_.FullName) -Replace '([^:])(Windows::Foundation)', '$1winrt::$2';"^
  "  [System.IO.File]::WriteAllLines($_.FullName, $tmp)"^
  "}"

triplef avatar Sep 22 '22 10:09 triplef

Why not use cppwinrt NuGet for everything? It is generating headers for system APIs too.

sylveon avatar Sep 22 '22 12:09 sylveon

If there was some actual documentation for cppwinrt.exe we could probably figure out how to do that, but since there isn’t we’re just happy we figured out how to generate the Windows App SDK headers against the system SDK and will leave it at that + crude workarounds. Also we’re not using Visual Studio but Qt, so this is all a manual process for us.

triplef avatar Sep 22 '22 13:09 triplef

you can run cppwinrt.exe to see its command line options and will find the implementation here. the command line support is stable as there are many dependecies on it. Raymond wrote about some of the command line usage here

ChrisGuzak avatar Sep 23 '22 22:09 ChrisGuzak

@ChrisGuzak yes I can get a list of command-line options with terse descriptions, but is there any place where they are documented and explained?

triplef avatar Oct 02 '22 08:10 triplef

Closing, as this issue was fixed in cppwinrt: https://github.com/microsoft/cppwinrt/pull/1004/files

Scottj1s avatar Nov 04 '22 17:11 Scottj1s

@triplef This might be helpful: https://github.com/microsoft/cppwinrt/tree/master/nuget

Scottj1s avatar Nov 04 '22 17:11 Scottj1s