Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: workaround for missing COM class on Windows 11 arm64 #2477

Closed

Conversation

dennisameling
Copy link
Contributor

Checklist
  • npm install && npm test passes
  • tests are included (can't add tests as there's no Windows arm64 hosted CI runners)
  • commit message follows commit guidelines
Description of change

After upgrading to Windows 11, node-gyp builds started to fail on my ARM64 device with the following error:

...
could not use PowerShell to find Visual Studio 2017 or newer, try re-running with '--loglevel silly' for more details
...

So I ran the following command:

PS C:\repos\node-gyp> powershell -ExecutionPolicy Unrestricted -Command "Add-Type -Path .\lib\Find-VisualStudio.cs; [VisualStudioConfiguration.Main]::PrintJson()"
Exception calling "PrintJson" with "0" argument(s): "Retrieving the COM class factory for component with CLSID {177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D} failed due to the following error: 80040154 Klasse is niet geregistreerd (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))."
At line:1 char:44
+ ... b\Find-VisualStudio.cs; [VisualStudioConfiguration.Main]::PrintJson()
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : COMException

After some investigation it turned out that the following is the causing this issue:

A workaround is to call the script above from x86 PowerShell (C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe). This works correctly and outputs the JSON. While this works standalone, this doesn't work when node-gyp is invoked by arm64 NodeJS from a x86 shell. The arm64 NodeJS will still trigger the x64 PowerShell and WOW Redirection doesn't work in this scenario.

I've reported this issue to Microsoft and they're currently investigating it. In the meantime, I'd like to introduce a workaround for Windows arm64 to use x86 PowerShell. That's exactly what this PR does. This works on all supported versions of Windows 10 arm64 and Windows 11.

There's a missing COM class for Visual Studio in Windows 11 arm64, which
breaks node-gyp builds when using native arm64 NodeJS. Using x86 works
around this and correctly outputs the requested JSON.

Issue reported to Microsoft as well:
https://developercommunity.visualstudio.com/t/Class-177F0C4A-1CD3-4DE7-A32C-71DBBB9FA3/1491726
@cclauss cclauss added the Windows label Aug 8, 2021
@dennisameling
Copy link
Contributor Author

dennisameling commented Aug 8, 2021

Just for the record: using vswhere, which is an x86-only executable, also works on arm64 to get the installed versions:

.\vswhere -products * -format json -requires Microsoft.VisualStudio.VC.MSBuild.Base

returns

[
  {
    "instanceId": "a7b0332e",
    "installDate": "2021-08-01T14:37:50Z",
    "installationName": "VisualStudio/16.10.4+31515.178",
    "installationPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools",
    "installationVersion": "16.10.31515.178",
    "productId": "Microsoft.VisualStudio.Product.BuildTools",
    "productPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\Common7\\Tools\\LaunchDevCmd.bat",
    "state": 4294967295,
    "isComplete": true,
    "isLaunchable": true,
    "isPrerelease": false,
    "isRebootRequired": false,
    "displayName": "Visual Studio Build Tools 2019",
    "description": "The Visual Studio Build Tools allows you to build native and managed MSBuild-based applications without requiring the Visual Studio IDE. There are options to install the Visual C++ compilers and libraries, MFC, ATL, and C++/CLI support.",
    "channelId": "VisualStudio.16.Release",
    "channelUri": "https://aka.ms/vs/16/release/channel",
    "enginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service",
    "releaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2019/release-notes-v16.10#16.10.4",
    "thirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=660909",
    "updateDate": "2021-08-01T14:37:50.9384817Z",
    "catalog": {
      "buildBranch": "d16.10",
      "buildVersion": "16.10.31515.178",
      "id": "VisualStudio/16.10.4+31515.178",
      "localBuild": "build-lab",
      "manifestName": "VisualStudio",
      "manifestType": "installer",
      "productDisplayVersion": "16.10.4",
      "productLine": "Dev16",
      "productLineVersion": "2019",
      "productMilestone": "RTW",
      "productMilestoneIsPreRelease": "False",
      "productName": "Visual Studio",
      "productPatchVersion": "4",
      "productPreReleaseMilestoneSuffix": "1.0",
      "productSemanticVersion": "16.10.4+31515.178",
      "requiredEngineVersion": "2.10.2174.31177"
    },
    "properties": {
      "campaignId": "",
      "channelManifestId": "VisualStudio.16.Release/16.10.4+31515.178",
      "nickname": "",
      "setupEngineFilePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe"
    }
  }
]

It can even return the full path to the MSBuild executable:

PS C:\Users\denni\Downloads> .\vswhere -products * -format json -requires Microsoft.VisualStudio.VC.MSBuild.Base -find MSBuild\**\Bin\MSBuild.exe
[
  "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\MSBuild\\Current\\Bin\\MSBuild.exe"
]

The current find-visualstudio.js has some hardcoded major version mappings (15 = 2017, 16 = 2019) which is not too scalable, also considering that VS 2022 is coming soon. It might be more future-proof to start using vswhere, which has all of the needed functionality (as far as I can see). It offloads the heavy lifting to an official, Microsoft-supported tool in that case. It can locate VS 2017 and newer, but should be able to detect VS 2015 as well using the -legacy switch if that's still needed.

I see that this was considered already back in 2019, but then the comment was:

vswhere does not print a list of installed components, so we can't filter installations as we do here.

... it can now by doing .\vswhere -products * -format json -include packages, which returns all installed components. Therefore it becomes very easy to look for components like Microsoft.VisualStudio.Component.VC.Tools.x86.x64, Microsoft.VisualStudio.VC.MSBuild.Base or Microsoft.VisualStudio.Component.Windows10SDK. in the list of installed components.

I'm happy to create a PR for moving over to vswhere if the maintainers would like that, either as a replacement for this PR or as a follow-up on it.

@dennisameling
Copy link
Contributor Author

This PR is no longer necessary. The issue occurs when users of Windows ARM64 upgrade from Windows 10 to Windows 11 - in Windows 10, those users can only run x86 and ARM64 binaries, but in Windows 11, x64 emulation was added as well. This requires a full uninstallation, cleanup and reinstall of Visual Studio, after which the x64 class is also registered correctly. 👍🏼

More details here: https://developercommunity.visualstudio.com/t/Class-177F0C4A-1CD3-4DE7-A32C-71DBBB9FA3/1491726#T-N1499903-N1503191

@dennisameling dennisameling deleted the win11-arm64-workaround branch August 13, 2021 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants