diff --git a/.github/actions/spell-check/dictionary/apis.txt b/.github/actions/spell-check/dictionary/apis.txt
index d50ce266603..1bf739dcf9b 100644
--- a/.github/actions/spell-check/dictionary/apis.txt
+++ b/.github/actions/spell-check/dictionary/apis.txt
@@ -2,9 +2,15 @@ ACCEPTFILES
ACCESSDENIED
bitfield
bitfields
+CLASSNOTAVAILABLE
+EXPCMDFLAGS
+EXPCMDSTATE
href
IBox
+IBind
ICustom
+IClass
+IExplorer
IMap
IObject
IStorage
@@ -12,6 +18,7 @@ LCID
NCHITTEST
NCLBUTTONDBLCLK
NCRBUTTONDBLCLK
+NOAGGREGATION
NOREDIRECTIONBITMAP
oaidl
ocidl
diff --git a/.github/actions/spell-check/dictionary/microsoft.txt b/.github/actions/spell-check/dictionary/microsoft.txt
index 50831af918c..62cd27b72cd 100644
--- a/.github/actions/spell-check/dictionary/microsoft.txt
+++ b/.github/actions/spell-check/dictionary/microsoft.txt
@@ -3,6 +3,7 @@ mfcribbon
microsoft
microsoftonline
osgvsowi
+powerrename
powershell
tdbuildteamid
vcruntime
diff --git a/.github/actions/spell-check/expect/expect.txt b/.github/actions/spell-check/expect/expect.txt
index 84ddc0aba21..8334d6e8225 100644
--- a/.github/actions/spell-check/expect/expect.txt
+++ b/.github/actions/spell-check/expect/expect.txt
@@ -603,6 +603,7 @@ dllexport
DLLGETVERSIONPROC
dllimport
dllinit
+dllmain
DLLVERSIONINFO
DLOAD
DLOOK
@@ -2088,6 +2089,7 @@ SHIFTJIS
Shl
shlguid
shlobj
+shobjidl
shlwapi
SHORTPATH
SHOWCURSOR
diff --git a/.github/actions/spell-check/expect/web.txt b/.github/actions/spell-check/expect/web.txt
index 7ec457b6949..61bdfa1f807 100644
--- a/.github/actions/spell-check/expect/web.txt
+++ b/.github/actions/spell-check/expect/web.txt
@@ -4,3 +4,5 @@ www
ecma
rapidtables
WCAG
+winui
+appshellintegration
diff --git a/.github/actions/spell-check/patterns/patterns.txt b/.github/actions/spell-check/patterns/patterns.txt
index 765eef4c23c..cddd540bffe 100644
--- a/.github/actions/spell-check/patterns/patterns.txt
+++ b/.github/actions/spell-check/patterns/patterns.txt
@@ -1,4 +1,4 @@
-https://(?:(?:[-a-zA-Z0-9?&=]*\.|)microsoft\.com)/[-a-zA-Z0-9?&=_\/.]*
+https://(?:(?:[-a-zA-Z0-9?&=]*\.|)microsoft\.com)/[-a-zA-Z0-9?&=_#\/.]*
https://aka\.ms/[-a-zA-Z0-9?&=\/_]*
https://www.w3.org/[-a-zA-Z0-9?&=\/_#]*
https://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
diff --git a/OpenConsole.sln b/OpenConsole.sln
index bb55346956c..560dc62f757 100644
--- a/OpenConsole.sln
+++ b/OpenConsole.sln
@@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Terminal", "Terminal", "{59840756-302F-44DF-AA47-441A9D673202}"
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "CascadiaPackage", "src\cascadia\CascadiaPackage\CascadiaPackage.wapproj", "{CA5CAD1A-224A-4171-B13A-F16E576FDD12}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B} = {F2ED628A-DB22-446F-A081-4CC845B51A2B}
+ EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.EXE", "src\host\exe\Host.EXE.vcxproj", "{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}"
ProjectSection(ProjectDependencies) = postProject
@@ -85,6 +88,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Host.Tests.Feature", "src\h
{18D09A24-8240-42D6-8CB6-236EEE820263} = {18D09A24-8240-42D6-8CB6-236EEE820263}
{FC802440-AD6A-4919-8F2C-7701F2B38D79} = {FC802440-AD6A-4919-8F2C-7701F2B38D79}
{9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B} = {9CBD7DFA-1754-4A9D-93D7-857A9D17CB1B}
+ {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A} = {58A03BB2-DF5A-4B66-91A0-7EF3BA01269A}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalParser.UnitTests", "src\terminal\parser\ut_parser\Parser.UnitTests.vcxproj", "{12144E07-FE63-4D33-9231-748B8D8C3792}"
@@ -188,6 +192,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalApp", "src\cascadia
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TerminalSettings", "src\cascadia\TerminalSettings\TerminalSettings.vcxproj", "{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsTerminalShellExt", "src\cascadia\ShellExtension\WindowsTerminalShellExt.vcxproj", "{F2ED628A-DB22-446F-A081-4CC845B51A2B}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests_TerminalCore", "src\cascadia\UnitTests_TerminalCore\UnitTests.vcxproj", "{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}"
ProjectSection(ProjectDependencies) = postProject
{06EC74CB-9A12-429C-B551-8562EC954747} = {06EC74CB-9A12-429C-B551-8562EC954747}
@@ -1108,6 +1114,25 @@ Global
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x64.Build.0 = Release|x64
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.ActiveCfg = Release|Win32
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.Release|x86.Build.0 = Release|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|Any CPU.ActiveCfg = Release|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|ARM64.ActiveCfg = Release|ARM64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|x64.ActiveCfg = Release|x64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|x64.Build.0 = Release|x64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.AuditMode|x86.ActiveCfg = Release|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Debug|ARM64.Build.0 = Debug|ARM64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Debug|x64.ActiveCfg = Debug|x64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Debug|x64.Build.0 = Debug|x64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Debug|x86.ActiveCfg = Debug|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Debug|x86.Build.0 = Debug|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Release|Any CPU.ActiveCfg = Release|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Release|ARM64.ActiveCfg = Release|ARM64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Release|ARM64.Build.0 = Release|ARM64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Release|x64.ActiveCfg = Release|x64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Release|x64.Build.0 = Release|x64
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Release|x86.ActiveCfg = Release|Win32
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B}.Release|x86.Build.0 = Release|Win32
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9}.AuditMode|x64.ActiveCfg = AuditMode|x64
@@ -1558,6 +1583,7 @@ Global
{CA5CAD1A-1754-4A9D-93D7-857A9D17CB1B} = {59840756-302F-44DF-AA47-441A9D673202}
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12} = {59840756-302F-44DF-AA47-441A9D673202}
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907} = {59840756-302F-44DF-AA47-441A9D673202}
+ {F2ED628A-DB22-446F-A081-4CC845B51A2B} = {59840756-302F-44DF-AA47-441A9D673202}
{2C2BEEF4-9333-4D05-B12A-1905CBF112F9} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{EF3E32A7-5FF6-42B4-B6E2-96CD7D033F00} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
{16376381-CE22-42BE-B667-C6B35007008D} = {81C352DB-1818-45B7-A284-18E259F1CC87}
diff --git a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj
index cfff16b6435..6fbd04d0d53 100644
--- a/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj
+++ b/src/cascadia/CascadiaPackage/CascadiaPackage.wapproj
@@ -64,7 +64,9 @@
+
+
diff --git a/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest b/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
index a8ccfe6c73c..da2051a1711 100644
--- a/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
+++ b/src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
@@ -3,9 +3,13 @@
@@ -39,7 +43,7 @@
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
@@ -58,6 +62,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest b/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
index c69242ccb1b..ba258abe77c 100644
--- a/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
+++ b/src/cascadia/CascadiaPackage/Package-Pre.appxmanifest
@@ -41,7 +41,7 @@
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
@@ -60,6 +60,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/CascadiaPackage/Package.appxmanifest b/src/cascadia/CascadiaPackage/Package.appxmanifest
index ad429698b69..c7dad075204 100644
--- a/src/cascadia/CascadiaPackage/Package.appxmanifest
+++ b/src/cascadia/CascadiaPackage/Package.appxmanifest
@@ -41,7 +41,7 @@
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
@@ -60,6 +60,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascadia/ShellExtension/OpenTerminalHere.cpp b/src/cascadia/ShellExtension/OpenTerminalHere.cpp
new file mode 100644
index 00000000000..8091754832c
--- /dev/null
+++ b/src/cascadia/ShellExtension/OpenTerminalHere.cpp
@@ -0,0 +1,211 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "OpenTerminalHere.h"
+
+// TODO GH#6112: Localize these strings
+static constexpr std::wstring_view VerbDisplayName{ L"Open in Windows Terminal" };
+static constexpr std::wstring_view VerbDevBuildDisplayName{ L"Open in Windows Terminal (Dev Build)" };
+static constexpr std::wstring_view VerbName{ L"WindowsTerminalOpenHere" };
+
+static constexpr std::wstring_view WtExe{ L"wt.exe" };
+static constexpr std::wstring_view WtdExe{ L"wtd.exe" };
+static constexpr std::wstring_view WindowsTerminalExe{ L"WindowsTerminal.exe" };
+
+static constexpr std::wstring_view LocalAppDataAppsPath{ L"%LOCALAPPDATA%\\Microsoft\\WindowsApps\\" };
+
+// This code is aggressively copied from
+// https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/
+// Win7Samples/winui/shell/appshellintegration/ExplorerCommandVerb/ExplorerCommandVerb.cpp
+
+// Function Description:
+// - This is a helper to determine if we're running as a part of the Dev Build
+// Package or the release package. We'll need to return different text, icons,
+// and use different commandlines depending on which one the user requested.
+// - Uses a C++11 "magic static" to make sure this is only computed once.
+// - If we can't determine if it's the dev build or not, we'll default to true
+// Arguments:
+// -
+// Return Value:
+// - true if we believe this extension is being run in the dev build package.
+static bool IsDevBuild()
+{
+ // use C++11 magic statics to make sure we only do this once.
+ static bool isDevBuild = []() -> bool {
+ try
+ {
+ const auto package{ winrt::Windows::ApplicationModel::Package::Current() };
+ const auto id = package.Id();
+ const std::wstring name{ id.FullName() };
+ // Does our PFN start with WindowsTerminalDev?
+ return name.rfind(L"WindowsTerminalDev", 0) == 0;
+ }
+ CATCH_LOG();
+ return true;
+ }();
+
+ return isDevBuild;
+}
+
+// Function Description:
+// - Helper function for getting the path to the appropriate executable to use
+// for this instance of the shell extension. If we're running the dev build,
+// it should be a `wtd.exe`, but if we're preview or release, we want to make
+// sure to get the correct `wt.exe` that corresponds to _us_.
+// - If we're unpackaged, this needs to get us `WindowsTerminal.exe`, because
+// the `wt*exe` alias won't have been installed for this install.
+// Arguments:
+// -
+// Return Value:
+// - the full path to the exe, one of `wt.exe`, `wtd.exe`, or `WindowsTerminal.exe`.
+static std::wstring _getExePath()
+{
+ // use C++11 magic statics to make sure we only do this once.
+ static const std::wstring exePath = []() -> std::wstring {
+ // First, check a packaged location for the exe. If we've got a package
+ // family name, that means we're one of the packaged Dev build, packaged
+ // Release build, or packaged Preview build.
+ //
+ // If we're the preview or release build, there's no way of knowing if the
+ // `wt.exe` on the %PATH% is us or not. Fortunately, _our_ execution alias
+ // is located in "%LOCALAPPDATA%\Microsoft\WindowsApps\", _always_, so we can use that to look up the exe easier.
+ try
+ {
+ const auto package{ winrt::Windows::ApplicationModel::Package::Current() };
+ const auto id = package.Id();
+ const std::wstring pfn{ id.FamilyName() };
+ if (!pfn.empty())
+ {
+ const std::filesystem::path windowsAppsPath{ wil::ExpandEnvironmentStringsW(LocalAppDataAppsPath.data()) };
+ const std::filesystem::path wtPath = windowsAppsPath / pfn / (IsDevBuild() ? WtdExe : WtExe);
+ return wtPath;
+ }
+ }
+ CATCH_LOG();
+
+ // If we're here, then we couldn't resolve our exe from the package. This
+ // means we're running unpackaged. We should just use the
+ // WindowsTerminal.exe that's sitting in the directory next to us.
+ try
+ {
+ HMODULE hModule = GetModuleHandle(nullptr);
+ THROW_LAST_ERROR_IF(hModule == nullptr);
+ std::wstring dllPathString;
+ THROW_IF_FAILED(wil::GetModuleFileNameW(hModule, dllPathString));
+ const std::filesystem::path dllPath{ dllPathString };
+ const std::filesystem::path rootDir = dllPath.parent_path();
+ std::filesystem::path wtPath = rootDir / WindowsTerminalExe;
+ return wtPath;
+ }
+ CATCH_LOG();
+
+ return L"wt.exe";
+ }();
+ return exePath;
+}
+
+// Method Description:
+// - This method is called when the user activates the context menu item. We'll
+// launch the Terminal using the current working directory.
+// Arguments:
+// - psiItemArray: a IShellItemArray which contains the item that's selected.
+// Return Value:
+// - S_OK if we successfully attempted to launch the Terminal, otherwise a
+// failure from an earlier HRESULT.
+HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
+ IBindCtx* /*pBindContext*/)
+{
+ DWORD count;
+ psiItemArray->GetCount(&count);
+
+ winrt::com_ptr psi;
+ RETURN_IF_FAILED(psiItemArray->GetItemAt(0, psi.put()));
+
+ wil::unique_cotaskmem_string pszName;
+ RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
+
+ {
+ wil::unique_process_information _piClient;
+ STARTUPINFOEX siEx{ 0 };
+ siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
+
+ // Append a "\." to the given path, so that this will work in "C:\"
+ std::wstring cmdline = fmt::format(L"\"{}\" -d \"{}\\.\"", _getExePath(), pszName.get());
+ RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
+ nullptr,
+ cmdline.data(),
+ nullptr, // lpProcessAttributes
+ nullptr, // lpThreadAttributes
+ false, // bInheritHandles
+ EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
+ nullptr, // lpEnvironment
+ nullptr,
+ &siEx.StartupInfo, // lpStartupInfo
+ &_piClient // lpProcessInformation
+ ));
+ }
+
+ return S_OK;
+}
+
+HRESULT OpenTerminalHere::GetToolTip(IShellItemArray* /*psiItemArray*/,
+ LPWSTR* ppszInfoTip)
+{
+ // tooltip provided here, in this case none is provided
+ *ppszInfoTip = nullptr;
+ return E_NOTIMPL;
+}
+
+HRESULT OpenTerminalHere::GetTitle(IShellItemArray* /*psiItemArray*/,
+ LPWSTR* ppszName)
+{
+ // Change the string we return depending on if we're running from the dev
+ // build package or not.
+ const bool isDevBuild = IsDevBuild();
+ return SHStrDup(isDevBuild ? VerbDevBuildDisplayName.data() : VerbDisplayName.data(), ppszName);
+}
+
+HRESULT OpenTerminalHere::GetState(IShellItemArray* /*psiItemArray*/,
+ BOOL /*fOkToBeSlow*/,
+ EXPCMDSTATE* pCmdState)
+{
+ // compute the visibility of the verb here, respect "fOkToBeSlow" if this is
+ // slow (does IO for example) when called with fOkToBeSlow == FALSE return
+ // E_PENDING and this object will be called back on a background thread with
+ // fOkToBeSlow == TRUE
+
+ // We however don't need to bother with any of that, so we'll just return
+ // ECS_ENABLED.
+
+ *pCmdState = ECS_ENABLED;
+ return S_OK;
+}
+
+HRESULT OpenTerminalHere::GetIcon(IShellItemArray* /*psiItemArray*/,
+ LPWSTR* ppszIcon)
+{
+ // the icon ref ("dll,-") is provided here, in this case none is provided
+ *ppszIcon = nullptr;
+ // TODO GH#6111: Return the Terminal icon here
+ return E_NOTIMPL;
+}
+
+HRESULT OpenTerminalHere::GetFlags(EXPCMDFLAGS* pFlags)
+{
+ *pFlags = ECF_DEFAULT;
+ return S_OK;
+}
+
+HRESULT OpenTerminalHere::GetCanonicalName(GUID* pguidCommandName)
+{
+ *pguidCommandName = __uuidof(this);
+ return S_OK;
+}
+
+HRESULT OpenTerminalHere::EnumSubCommands(IEnumExplorerCommand** ppEnum)
+{
+ *ppEnum = nullptr;
+ return E_NOTIMPL;
+}
diff --git a/src/cascadia/ShellExtension/OpenTerminalHere.h b/src/cascadia/ShellExtension/OpenTerminalHere.h
new file mode 100644
index 00000000000..5be0c0d370c
--- /dev/null
+++ b/src/cascadia/ShellExtension/OpenTerminalHere.h
@@ -0,0 +1,51 @@
+/*++
+Copyright (c) Microsoft Corporation
+Licensed under the MIT license.
+
+Module Name:
+- OpenTerminalHere.h
+
+Abstract:
+- This is the class that implements our Explorer Context Menu item. By
+ implementing IExplorerCommand, we can provide an entry to the context menu to
+ allow the user to open the Terminal in the current working directory.
+- Importantly, we need to make sure to declare the GUID of this implementation
+ class explicitly, so we can refer to it in our manifest, and use it to create
+ instances of this class when the shell asks for one.
+- This is defined as a WRL type, so that we can use WRL's CoCreatableClass magic
+ to create the class factory and module management for us. See more details in
+ dllmain.cpp.
+
+Author(s):
+- Mike Griese - May 2020
+
+--*/
+#pragma once
+
+#include
+#include "../../cascadia/inc/cppwinrt_utils.h"
+
+using namespace Microsoft::WRL;
+
+struct __declspec(uuid("9f156763-7844-4dc4-b2b1-901f640f5155"))
+ OpenTerminalHere : public RuntimeClass, IExplorerCommand>
+{
+#pragma region IExplorerCommand
+ HRESULT Invoke(IShellItemArray* psiItemArray,
+ IBindCtx* pBindContext);
+ HRESULT GetToolTip(IShellItemArray* psiItemArray,
+ LPWSTR* ppszInfoTip);
+ HRESULT GetTitle(IShellItemArray* psiItemArray,
+ LPWSTR* ppszName);
+ HRESULT GetState(IShellItemArray* psiItemArray,
+ BOOL fOkToBeSlow,
+ EXPCMDSTATE* pCmdState);
+ HRESULT GetIcon(IShellItemArray* psiItemArray,
+ LPWSTR* ppszIcon);
+ HRESULT GetFlags(EXPCMDFLAGS* pFlags);
+ HRESULT GetCanonicalName(GUID* pguidCommandName);
+ HRESULT EnumSubCommands(IEnumExplorerCommand** ppEnum);
+#pragma endregion
+};
+
+CoCreatableClass(OpenTerminalHere);
diff --git a/src/cascadia/ShellExtension/PlaceholderType.cpp b/src/cascadia/ShellExtension/PlaceholderType.cpp
new file mode 100644
index 00000000000..dc45a6a1e47
--- /dev/null
+++ b/src/cascadia/ShellExtension/PlaceholderType.cpp
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "PlaceholderType.h"
+#include "PlaceholderType.g.cpp"
+
+namespace winrt::Microsoft::Terminal::ShellExtension::implementation
+{
+}
diff --git a/src/cascadia/ShellExtension/PlaceholderType.h b/src/cascadia/ShellExtension/PlaceholderType.h
new file mode 100644
index 00000000000..d56395c9257
--- /dev/null
+++ b/src/cascadia/ShellExtension/PlaceholderType.h
@@ -0,0 +1,37 @@
+/*++
+Copyright (c) Microsoft Corporation
+Licensed under the MIT license.
+
+Module Name:
+- PlaceholderType.h
+
+Abstract:
+- This class is just here to make our .wapproj play nicely with this project. If
+ we don't define any winrt types, then we won't generate a .winmd, and the
+ .wapproj will become _very_ mad at this project. So we'll use this placeholder
+ class just to trick cppwinrt into generating a winmd for us. If we ever _do_
+ add a real winrt type to this project, this can be removed.
+
+Author(s):
+- Mike Griese - May 2020
+
+--*/
+#pragma once
+
+#include
+#include "PlaceholderType.g.h"
+#include "../../cascadia/inc/cppwinrt_utils.h"
+
+namespace winrt::Microsoft::Terminal::ShellExtension::implementation
+{
+ struct PlaceholderType : PlaceholderTypeT
+ {
+ PlaceholderType() = default;
+ GETSET_PROPERTY(int32_t, Placeholder, 42);
+ };
+}
+
+namespace winrt::Microsoft::Terminal::ShellExtension::factory_implementation
+{
+ BASIC_FACTORY(PlaceholderType);
+}
diff --git a/src/cascadia/ShellExtension/PlaceholderType.idl b/src/cascadia/ShellExtension/PlaceholderType.idl
new file mode 100644
index 00000000000..0dbe7adfacc
--- /dev/null
+++ b/src/cascadia/ShellExtension/PlaceholderType.idl
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+// This class is just here to make our .wapproj play nicely with this project.
+// If we don't define any winrt types, then we won't generate a .winmd, and the
+// .wapproj will become _very_ mad at this project. So we'll use this
+// placeholder class just to trick cppwinrt into generating a winmd for us. If
+// we ever _do_ add a real winrt type to this project, this can be removed.
+
+namespace Microsoft.Terminal.ShellExtension
+{
+ [default_interface] runtimeclass PlaceholderType {
+ PlaceholderType();
+ Int32 Placeholder
+ {
+ get;
+ set;
+ };
+ };
+
+}
diff --git a/src/cascadia/ShellExtension/WindowsTerminalShellExt.def b/src/cascadia/ShellExtension/WindowsTerminalShellExt.def
new file mode 100644
index 00000000000..d0e5f0b59d3
--- /dev/null
+++ b/src/cascadia/ShellExtension/WindowsTerminalShellExt.def
@@ -0,0 +1,4 @@
+EXPORTS
+DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
+DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
+DllGetClassObject PRIVATE
diff --git a/src/cascadia/ShellExtension/WindowsTerminalShellExt.vcxproj b/src/cascadia/ShellExtension/WindowsTerminalShellExt.vcxproj
new file mode 100644
index 00000000000..12565176959
--- /dev/null
+++ b/src/cascadia/ShellExtension/WindowsTerminalShellExt.vcxproj
@@ -0,0 +1,68 @@
+
+
+
+ {f2ed628a-db22-446f-a081-4cc845b51a2b}
+ WindowsTerminalShellExt
+ Microsoft.Terminal.ShellExtension
+
+
+ DynamicLibrary
+ Console
+
+ true
+
+ true
+
+
+
+
+
+
+
+
+
+ PlaceholderType.idl
+
+
+
+
+ Create
+
+
+ PlaceholderType.idl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {18D09A24-8240-42D6-8CB6-236EEE820263}
+
+
+ {CA5CAD1A-039A-4929-BA2A-8BEB2E4106FE}
+ false
+
+
+
+
+
+
diff --git a/src/cascadia/ShellExtension/dllmain.cpp b/src/cascadia/ShellExtension/dllmain.cpp
new file mode 100644
index 00000000000..d7c93e96f31
--- /dev/null
+++ b/src/cascadia/ShellExtension/dllmain.cpp
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+#include "OpenTerminalHere.h"
+
+// For reference, see:
+// * https://docs.microsoft.com/en-us/cpp/cppcx/wrl/how-to-create-a-classic-com-component-using-wrl?view=vs-2019
+// * https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/move-to-winrt-from-wrl#porting-a-wrl-module-microsoftwrlmodule
+//
+// We don't need to implement DllGetActivationFactory or DllCanUnloadNow
+// manually, since the generated module.g.cpp will handle it for us, and will
+// handle our WRL types appropriately.
+//
+// We DO need to implement DllGetClassObject, because that's what explorer.exe
+// will call to attempt to create a class factory for our shell extension. The
+// CoCreatableClass macro in OpenTerminalHere.h will create the factory for us,
+// so that the GetClassObject call will work like magic.
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv)
+{
+ return Microsoft::WRL::Module::GetModule().GetClassObject(rclsid, riid, ppv);
+}
+
+STDAPI_(BOOL)
+DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ DisableThreadLibraryCalls(hinst);
+ }
+ return TRUE;
+}
diff --git a/src/cascadia/ShellExtension/packages.config b/src/cascadia/ShellExtension/packages.config
new file mode 100644
index 00000000000..8db4233e6a9
--- /dev/null
+++ b/src/cascadia/ShellExtension/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/cascadia/ShellExtension/pch.cpp b/src/cascadia/ShellExtension/pch.cpp
new file mode 100644
index 00000000000..3c27d44d570
--- /dev/null
+++ b/src/cascadia/ShellExtension/pch.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
diff --git a/src/cascadia/ShellExtension/pch.h b/src/cascadia/ShellExtension/pch.h
new file mode 100644
index 00000000000..5962c68100a
--- /dev/null
+++ b/src/cascadia/ShellExtension/pch.h
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+//
+// pch.h
+// Header for platform projection include files
+//
+
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN
+
+#include
+// This is inexplicable, but for whatever reason, cppwinrt conflicts with the
+// SDK definition of this function, so the only fix is to undef it.
+// from WinBase.h
+// Windows::UI::Xaml::Media::Animation::IStoryboard::GetCurrentTime
+#ifdef GetCurrentTime
+#undef GetCurrentTime
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
diff --git a/src/host/ft_host/Host.FeatureTests.vcxproj b/src/host/ft_host/Host.FeatureTests.vcxproj
index b31c4ef4490..e62dc672862 100644
--- a/src/host/ft_host/Host.FeatureTests.vcxproj
+++ b/src/host/ft_host/Host.FeatureTests.vcxproj
@@ -44,7 +44,7 @@
{18d09a24-8240-42d6-8cb6-236eee820263}
-
+ {58a03bb2-df5a-4b66-91a0-7ef3ba01269a}
@@ -59,9 +59,4 @@
-
-
- $(OutDir)\conpty.lib;%(AdditionalDependencies)
-
-
-
\ No newline at end of file
+