Terminal: Does not detect wsl distro

Created on 7 May 2019  路  27Comments  路  Source: microsoft/terminal

  • Your Windows build number: 10.0.18890.1000

  • What you're doing and what's happening: Open windows terminal and press the down arrow, it shows cmd and PowerShell but not wsl, I have wsl debian installed.

  • What's wrong / what should be happening instead: It should let me select wsl debian

Area-Settings Help Wanted Issue-Feature Needs-Tag-Fix Product-Terminal

Most helpful comment

Looks like autodetect isn麓t working for now , i was need to edit mi settings file for work with Ubuntu

image

All 27 comments

I just installed PowerShell core, it does not detect it either.

Can you explain what do you mean about PSCore not detecting WSL? As I see it, PSCore would open powershell 6, and then you have to write wsl to enter the WSL terminal.

I mean that windows shell does not detect them and give you an option to open them within windows shell

Seems like autodetecting doesn't work right now. You can add them manually by editing the settings json file.

Looks like autodetect isn麓t working for now , i was need to edit mi settings file for work with Ubuntu

image

Seems like autodetecting doesn't work right now. You can add them manually by editing the settings json file.

Code needs to be added to the CascadiaSettings::_CreateDefaultProfiles() function under CascadiaSettings.cpp. I don't think there is an environment variable to manage WSL installations like there is for PowerShell, so something like CascadiaSettings::_IsPowerShellCoreInstalled will need to be added.

I know wslconfig /list exists, but is there a more clean way of determining what is available and where the executables are?

@JBanks I agree with you. We need to add WSL-related code to default profile.

We can find it from the registry. I've uploaded the examples to find default WSL distro from it.
https://github.com/YaSuenag/garakuta/blob/master/wslgit/wslgit/wslgit.cpp

I guess Windows Terminal will have similar code in future because screen shot in Developers Blog has WSL in the menu. So I will wait GA release - if it do not have it, I will send PR :-)

Yes, we do plan eventually auto-detecting WSL distros and creating profiles for them.

If someone wants to try their hand at doing this, I would happily review the PR :) The bulk of the work would probably be in src/cascadia/TerminalApp/CascadiaSettings.cpp

I've tried the following, but I can't seem to get it to link.

// Add all WSL distros from: HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss\[guid]\DistributionName
Profile WSLDistro{};
HKEY hLXSSKey;
if (RegOpenKeyExW(HKEY_CURRENT_USER, 
    L"Software\\Microsoft\\Windows\\CurrentVersion\\Lxss\\", 
    0, 
    KEY_READ, 
    &hLXSSKey)) 
{
    wchar_t WSLKey[MAX_PATH] = L"";
    DWORD WSLKey_Length = 0;
    wchar_t DistributionName[MAX_PATH] = L"";
    DWORD DistributionName_Length = 0;
    wchar_t SYSTEM_32[MAX_PATH] = L"%systemroot%\\system32\\";
    wchar_t WSLCommandLine[MAX_PATH];
    for (int i = 0; RegEnumKeyExW(hLXSSKey, i, WSLKey, &WSLKey_Length, NULL, NULL, NULL, NULL); i++) {
        if (RegGetValueW(hLXSSKey, WSLKey, L"DistributionName", RRF_RT_REG_SZ, NULL, &DistributionName, &DistributionName_Length)) {
            lstrcpyW(WSLCommandLine, SYSTEM_32);
            lstrcatW(WSLCommandLine, DistributionName);
            lstrcatW(WSLCommandLine, L".exe");
            if (std::filesystem::exists(WSLCommandLine)) {
                WSLDistro.SetName(DistributionName);
                WSLDistro.SetCommandline(WSLCommandLine);
                _profiles.emplace_back(WSLDistro);
            }
        }
    }
}

I get the following error, I've even tried adding #include <winreg.h>, but that didn't help.

12>CascadiaSettings.obj : error LNK2001: unresolved external symbol __imp_RegOpenKeyExW
12>CascadiaSettings.obj : error LNK2001: unresolved external symbol __imp_RegEnumKeyExW
12>CascadiaSettings.obj : error LNK2001: unresolved external symbol __imp_RegGetValueW
12>C:\Users\jerem_000\source\repos\Terminal\x64\Release\TerminalApp\TerminalApp.dll : fatal error LNK1120: 3 unresolved externals

I haven't done any Registry programming in C++ before, so any help would be appreciated.

You'll probably need to add Advapi32.lib to the TerminalApp.vcxproj file's AdditionalDependencies, like so:

    <Link>
      <AdditionalDependencies>Advapi32.lib;WindowsApp.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>

========== Rebuild All: 12 succeeded, 0 failed, 0 skipped ==========

That did it!

Is it OK to use Windows API? Windows Terminal seems to be UWP (using winrt namespace).
I'm finding how to read HKCU from UWP since last night, but I'm not sure we should do that...

BTW I think we can use key name (GUID style) of WSL distros to Profile::_guid. So I prefer to add setter for it to Profile.

@YaSuenag Have you seen anything that says you can access the registry from the winrt namespace? Everything I've read says that you can't do it, but that knowledge is all a few years old, that's why I adapted your code from above.

Regarding the GUID, I do see value added if someone were to go between the terminal settings and this section of the registry, but I think it's a bit of a stretch.

@JBanks For .NET app, I think we should use Microsoft.Win32 namespace instead of Windows API. I tried to use it in TerminalApp, but it is not completed yet.
https://docs.microsoft.com/en-US/dotnet/api/microsoft.win32.registrykey?view=netframework-4.8

Also I concern whether we can use registry in TerminalApp. (Should be add #ifdef to it?)
(I'm not familiar in UWP App. So I'm not sure this approach is correct.)

We're actually not a pure UWP application. We're a normal, full-trust Win32 application. We're able to use UWP XAML UI elements thanks to the wonderful work of the Xaml Islands team.

So, we're perfectly capable of reading the registry.

We're not a .NET app, so we don't need to mess with that at all.

Thanks @zadjii-msft ! I understood we can use Win32 API for reading registry.
However @JBanks 's proposal will not work with Ubuntu 18.04 store app.

Its DistributionName is Ubuntu-18.04 . However its executable is located at C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu18.04onWindows_1804.2018.817.0_x64__79rhkp1fndgsc\ubuntu1804.exe.

WSL API provides WslLaunch() to start WSL. I think we can use this API.
However this API does not feasible now because it requires pipes for stdin/out/err and it does not fit to current CreateConPty() form which uses command line.

I think it can be used if we can change CreateConPty(), TerminalSetting, and Profile. But it might be large changes.

What do you think?

Oh ho ho. You've come to a idea I've had for a while, but the terminal isn't ready for. It would theoretically be possible to launch WSL directly, without needing conpty. We'd create a new ITerminalConnection implementation to use instead of the ConhostConnection that the terminal currently uses. That connection would be responsible for calling WslLaunch instead of CreateConPty.

This however is probably _not_ something we should do quite yet. When client applications are running attached to ConPty, conpty will interpret all the VT sequences they emit, and then re-render the results to a much simpler subset of VT. Right now, the Windows Terminal only knows how to deal with _that particular subset_ of VT.

We'd _really_ like to get the Terminal's VT support to completely match that of conhost, so it can be used as a standalone terminal, without conpty. Unfortunately, we're just not there yet. So if you _did_ make a WslConnection (or similar), the Terminal would almost certainly not render things correctly.

I'd probably caution against that route for the time being.

Its DistributionName is Ubuntu-18.04 . However its executable is located at C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu18.04onWindows_1804.2018.817.0_x64__79rhkp1fndgsc\ubuntu1804.exe.

@YaSuenag Good catch. I was going off of bash.exe and WSL.exe and hadn't gotten far enough to realize that they weren't all in the system32 directory.

I wonder if we can use the PackageFamilyName value to extract the folder from C:\Program Files\WindowsApps\ and then use whatever executable is present. Do you have any other distros installed? Do they have multiple executables in that folder?

@zadjii-msft I agree with you. It's better to call WSL via WslLaunch(), and I hope Windows Terminal has new interface which can handle API call.

This is off the topic, but I want to connect to the device with serial console (e.g. Raspberry Pi) from Windows Terminal. So I started to create simple console app for serial console. I will integrate it to Windows Terminal via profile.json.
But if Windows Terminal has new interface as you said, it might easy to have various interface like serial console.

I wonder if we can use the PackageFamilyName value to extract the folder from C:\Program Files\WindowsApps\ and then use whatever executable is present. Do you have any other distros installed? Do they have multiple executables in that folder?

Sorry, I don't have other distros.
But I don't think it is not enough if I (and/or you) have other distros because some user might install custom distros.
https://docs.microsoft.com/en-US/windows/wsl/build-custom-distro

If so, I'm not sure what data will be written into registry.

@zadjii-msft Fun Fact: My terminal Extraterm (http://extraterm.org) when running WSL and Cygwin sessions actually starts up a small proxy process inside WSL/Cygwin which then creates and manages the PTYs and starting up the shell processes. Extraterm communicates with the proxy via stdin/stdout using a simple JSON protocol. This is all done to get past the Windows console layer and to talk as directly as possible with the shell and commands using regular VT codes likes you would on Linux.

But I don't think it is not enough if I (and/or you) have other distros because some user might install custom distros.

This could be a problem. Unfortunately I can't put that much time into solving any of those types of problems. Hopefully someone who has done that comes along and speaks up. I have the following working for my setup, but it needs some cleanup before being put in a pull request. @YaSuenag Do you mind checking it over and telling me your thoughts or any oversights I may have had?

// Add all WSL distros from: HKCU\Software\Microsoft\Windows\CurrentVersion\Lxss\[guid]\DistributionName
Profile WSLDistro{};
HKEY hLXSSKey;
// Should I use RegOpenCurrentUser to access the uncached profile?
// https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regopencurrentuser#remarks
if (RegOpenKeyExW(HKEY_CURRENT_USER, 
    TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Lxss"),
    0, KEY_READ, &hLXSSKey) == ERROR_SUCCESS) 
{
    DWORD RegResult = 0;

    std::filesystem::path AppsDirectory = ExpandEnvironmentVariableString(L"%ProgramFiles%");
    AppsDirectory /= "WindowsApps";
    std::filesystem::path WSLCommandLine = L"";

    wchar_t WSLKey[MAX_PATH] = L"";
    DWORD WSLKey_Length = MAX_PATH;

    wchar_t DistributionName[MAX_PATH] = L"";
    DWORD DistributionName_Length = MAX_PATH;

    wchar_t PackageFamilyName[MAX_PATH] = L"";
    DWORD PackageFamilyName_Length = MAX_PATH;
    DWORD subKeys = 0;
    DWORD LargestKeySize = 0;
    RegResult = RegQueryInfoKeyW(hLXSSKey, NULL, NULL, NULL, 
                &subKeys, &LargestKeySize, NULL, NULL, NULL, NULL, NULL, NULL);
    for (int i = 0; 
        RegEnumKeyExW(hLXSSKey, i, WSLKey, &WSLKey_Length, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; 
        i++) 
    {
        WSLKey_Length = LargestKeySize;
        DistributionName_Length = MAX_PATH;
        PackageFamilyName_Length = MAX_PATH;
        if (RegGetValueW(hLXSSKey, WSLKey, L"DistributionName", RRF_RT_REG_SZ, NULL, 
                    DistributionName, &DistributionName_Length) == ERROR_SUCCESS
            && RegGetValueW(hLXSSKey, WSLKey, L"PackageFamilyName", RRF_RT_REG_SZ, NULL, 
                    PackageFamilyName, &PackageFamilyName_Length) == ERROR_SUCCESS) {
            WSLCommandLine = AppsDirectory;
            std::wstring PFNString = PackageFamilyName;

            for (auto& file : std::filesystem::directory_iterator(WSLCommandLine)) {
                // The PackageFamilyName is split and has version information placed in the middle
                // when creating the ProgramFiles directory.  I chose to only compare the last section.
                std::wstring PFNSubString = PFNString.substr(PFNString.find(L"_"));
                std::wstring FileString = file.path().wstring();
                if (FileString.find(PFNSubString) != std::wstring::npos) {
                    WSLCommandLine = file.path();

                    for (auto& file : std::filesystem::directory_iterator(WSLCommandLine)) {
                        if (file.path().extension() == ".exe") {
                            WSLDistro.SetCommandline(file.path());
                            WSLDistro.SetName(DistributionName);
                            WSLDistro.SetColorScheme({ L"Campbell" });
                            _profiles.emplace_back(WSLDistro);
                            break;
                        }
                    }
                    break;
                }
            }
        }
    }
}
RegCloseKey(hLXSSKey);

@JBanks I can look into adding this to my pre-existing PR, it looks like it could be something that could work.

So I just added this to #679 and CI's pending.

@JBanks I saw your change on #695. It looks good to me.

In future, I think we should call WslLaunch() to start WSL distros. But it can't now.
@zadjii-msft do you have any plan to support console which is not implemented as a standalone executable? I want to watch them (issue and/or PR) if avilable.

Post by @benhillis regarding this issue located here: https://github.com/microsoft/Terminal/pull/695#issuecomment-491974238

Assumptions that I'm going to make based on https://github.com/microsoft/Terminal/issues/441#issuecomment-491295244

  • Executable will be [name].exe
  • Executable will be present in the user's path
  • Executable will have punctuation marks removed (e.g. "Ubuntu-18.04" becomes ubuntu1804.exe)

Please let me know if anyone sees any problems or shortcomings with this.

Just to move the executable part of the discussion back here:

_The ideal way to launch a WSL distribution is via wsl.exe -d <distribution name>_. That way, there's no executable guess-and-test.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dev-logan picture dev-logan  路  3Comments

DieselMeister picture DieselMeister  路  3Comments

ghost picture ghost  路  3Comments

ghvanderweg picture ghvanderweg  路  3Comments

xmm1989218 picture xmm1989218  路  3Comments