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

Add a context menu entry to "Open Windows Terminal here" #6100

Merged
26 commits merged into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c67b606
Lets just start by adding a new project
zadjii-msft May 20, 2020
d2aab9e
I guess this implements a COM interface?
zadjii-msft May 20, 2020
f314d90
I'm not sure what I did wrong
zadjii-msft May 20, 2020
f5fdae7
okay yea I missed this
zadjii-msft May 20, 2020
1d6b017
my dude it works
zadjii-msft May 21, 2020
1851535
Well this works to pop up a cmd window
zadjii-msft May 21, 2020
44c7da6
turns out it's real important to restart explorer.exe
zadjii-msft May 21, 2020
3c59824
Lots of polish
zadjii-msft May 21, 2020
643125f
Use a magic static to compute if this should be the dev build or not
zadjii-msft May 21, 2020
ad69e3f
cleanup for review
zadjii-msft May 21, 2020
ccb7160
Good bot
zadjii-msft May 21, 2020
b2184fb
Merge remote-tracking branch 'origin/master' into dev/migrie/f/shell-…
zadjii-msft May 26, 2020
bb2713c
do it with WRL, this is dirty but it works
zadjii-msft May 26, 2020
ae42447
Clean this code up a bit
zadjii-msft May 26, 2020
5b75378
Clean up, add comments, remove audit mode
zadjii-msft May 26, 2020
753fcb3
pr nits, spellcheck
zadjii-msft May 27, 2020
790f679
good bot
zadjii-msft May 27, 2020
380ccc5
pls mr bot, love me
zadjii-msft May 27, 2020
f54c7f6
Merge branch 'master' into dev/migrie/f/shell-extension
zadjii-msft May 27, 2020
4850d0e
pr nits
zadjii-msft May 27, 2020
11e9d60
What? No, I didn't just change the GUID to make spellchack happy. Tha…
zadjii-msft May 27, 2020
b43f6b2
constexpr for carlos, and pls bot, pls
zadjii-msft May 27, 2020
0edda7f
Welp, I missed this manifest somehow
zadjii-msft May 27, 2020
5a0766c
Merge remote-tracking branch 'origin/master' into dev/migrie/f/shell-…
zadjii-msft May 28, 2020
d5dcc37
Maybe this will fix the build?
zadjii-msft May 28, 2020
a42c340
I really don't understand why this was here at all
zadjii-msft May 28, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions OpenConsole.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -188,7 +191,7 @@ 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}") = "ShellExtension", "src\cascadia\ShellExtension\ShellExtension.vcxproj", "{f2ed628a-db22-446f-a081-4cc845b51a2b}"
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
Expand Down Expand Up @@ -1091,27 +1094,6 @@ Global
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}.Release|x64.Build.0 = Release|x64
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}.Release|x86.ActiveCfg = Release|Win32
{CA5CAD1A-44BD-4AC7-AC72-F16E576FDD12}.Release|x86.Build.0 = Release|Win32

{f2ed628a-db22-446f-a081-4cc845b51a2b}.AuditMode|Any CPU.ActiveCfg = Debug|Win32
{f2ed628a-db22-446f-a081-4cc845b51a2b}.AuditMode|ARM64.ActiveCfg = Release|ARM64
{f2ed628a-db22-446f-a081-4cc845b51a2b}.AuditMode|x64.ActiveCfg = AuditMode|x64
{f2ed628a-db22-446f-a081-4cc845b51a2b}.AuditMode|x64.Build.0 = AuditMode|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

{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|Any CPU.ActiveCfg = Debug|Win32
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|ARM64.ActiveCfg = Release|ARM64
{CA5CAD1A-D7EC-4107-B7C6-79CB77AE2907}.AuditMode|x64.ActiveCfg = AuditMode|x64
Expand All @@ -1131,6 +1113,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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@miniksa @DHowett Okay, how did I mess this up? I thought this was how you un-include a project from audit mode? I really don't think I had anything to do with this error

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, maybe the U8U16Test error isn't from this PR - I just checked out master and that can't build it in release either, but I've filed #6220 for this

{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
Expand Down Expand Up @@ -1581,7 +1582,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}
{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}
Expand Down
2 changes: 2 additions & 0 deletions src/cascadia/CascadiaPackage/CascadiaPackage.wapproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
<ProjectReference Include="..\WindowsTerminal\WindowsTerminal.vcxproj" />
<ProjectReference Include="..\..\host\exe\Host.EXE.vcxproj" />
<ProjectReference Include="..\TerminalAzBridge\TerminalAzBridge.vcxproj" />
<ProjectReference Include="..\ShellExtension\WindowsTerminalShellExt.vcxproj" />
</ItemGroup>

<Target Name="OpenConsoleStompSourceProjectForWapProject" BeforeTargets="_ConvertItems">
<ItemGroup>
<!-- Stomp all "SourceProject" values for all incoming dependencies to flatten the package. -->
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/CascadiaPackage/Package-Dev.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@

<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="ShellExtension">
<com:Class Id="9f156763-7844-4dc4-bbb1-901f640f5155" Path="ShellExtension.dll" ThreadingModel="STA"/>
<com:SurrogateServer DisplayName="WindowsTerminalShellExt">
<com:Class Id="9f156763-7844-4dc4-bbb1-901f640f5155" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/CascadiaPackage/Package.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@

<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="ShellExtension">
<com:Class Id="9f156763-7844-4dc4-bbb1-901f640f5155" Path="ShellExtension.dll" ThreadingModel="STA"/>
<com:SurrogateServer DisplayName="WindowsTerminalShellExt">
<com:Class Id="9f156763-7844-4dc4-bbb1-901f640f5155" Path="WindowsTerminalShellExt.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
Expand Down
68 changes: 60 additions & 8 deletions src/cascadia/ShellExtension/OpenTerminalHere.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
#include "pch.h"
#include "OpenTerminalHere.h"

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

// TODO GH#6112: Localize these strings
static std::wstring VerbDisplayName{ L"Open in Windows Terminal" };
static std::wstring VerbDevBuildDisplayName{ L"Open in Windows Terminal (Dev Build)" };
static std::wstring VerbName{ L"WindowsTerminalOpenHere" };
Expand Down Expand Up @@ -44,6 +42,60 @@ bool IsDevBuild()
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:
// - <none>
// Return Value:
// - the full path to the exe, one of `wt.exe`, `wtd.exe`, or `windowsterminal.exe`.
std::wstring _getExePath()
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
// 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\<our package family
// name>", _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<std::wstring>(L"%LOCALAPPDATA%\\Microsoft\\WindowsApps\\") };
const std::filesystem::path wtPath = windowsAppsPath / pfn / (IsDevBuild() ? L"wtd.exe" : L"wt.exe");
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 / "WindowsTerminal.exe";
return wtPath;
}
CATCH_LOG();

return L"wt.exe";
}

// Method Description:
// - This method is called when the user activates the context menu item. We'll
// launch the Terminal using the current working directory.
Expand All @@ -69,8 +121,7 @@ HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray,
STARTUPINFOEX siEx{ 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);

const bool isDevBuild = IsDevBuild();
std::wstring cmdline = fmt::format(L"{}.exe -d \"{}\"", isDevBuild ? L"wtd" : L"wt", pszName);
std::wstring cmdline = fmt::format(L"\"{}\" -d \"{}\"", _getExePath(), pszName);
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
nullptr,
cmdline.data(),
Expand All @@ -94,7 +145,7 @@ HRESULT OpenTerminalHere::GetToolTip(IShellItemArray* /*psiItemArray*/,
LPWSTR* ppszInfotip)
{
// tooltip provided here, in this case none is provided
*ppszInfotip = NULL;
*ppszInfotip = nullptr;
return E_NOTIMPL;
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -127,7 +178,8 @@ HRESULT OpenTerminalHere::GetIcon(IShellItemArray* /*psiItemArray*/,
LPWSTR* ppszIcon)
{
// the icon ref ("dll,-<resid>") is provided here, in this case none is provided
*ppszIcon = NULL;
*ppszIcon = nullptr;
// TODO GH#6111: Return the Terminal icon here
return E_NOTIMPL;
}

Expand All @@ -145,6 +197,6 @@ HRESULT OpenTerminalHere::GetCanonicalName(GUID* pguidCommandName)

HRESULT OpenTerminalHere::EnumSubCommands(IEnumExplorerCommand** ppEnum)
{
*ppEnum = NULL;
*ppEnum = nullptr;
return E_NOTIMPL;
}
9 changes: 8 additions & 1 deletion src/cascadia/ShellExtension/OpenTerminalHere.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Module Name:
- 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
Expand All @@ -22,8 +25,10 @@ Author(s):
#include <conattrs.hpp>
#include "../../cascadia/inc/cppwinrt_utils.h"

using namespace Microsoft::WRL;

struct __declspec(uuid("9f156763-7844-4dc4-bbb1-901f640f5155"))
OpenTerminalHere : winrt::implements<OpenTerminalHere, IExplorerCommand>
OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IExplorerCommand>
zadjii-msft marked this conversation as resolved.
Show resolved Hide resolved
{
#pragma region IExplorerCommand
HRESULT Invoke(IShellItemArray* psiItemArray,
Expand All @@ -42,3 +47,5 @@ struct __declspec(uuid("9f156763-7844-4dc4-bbb1-901f640f5155"))
HRESULT EnumSubCommands(IEnumExplorerCommand** ppEnum);
#pragma endregion
};

CoCreatableClass(OpenTerminalHere);
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{f2ed628a-db22-446f-a081-4cc845b51a2b}</ProjectGuid>
<ProjectName>ShellExtension</ProjectName>
<ProjectName>WindowsTerminalShellExt</ProjectName>
<RootNamespace>Microsoft.Terminal.ShellExtension</RootNamespace>
<!-- cppwinrt.build.pre.props depends on these settings: -->
<!-- build a dll, not exe (Application) -->
Expand Down Expand Up @@ -44,7 +44,7 @@
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="ShellExtension.def" />
<None Include="WindowsTerminalShellExt.def" />
</ItemGroup>

<!-- ========================= Project References ======================== -->
Expand Down
89 changes: 18 additions & 71 deletions src/cascadia/ShellExtension/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,84 +3,31 @@

#include "pch.h"
#include "OpenTerminalHere.h"
// NOTE: All this file is pretty egregiously taken from PowerToys's PowerRename,
// specifically:

// 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
//
// https://github.com/microsoft/PowerToys/blob/master/
// src/modules/powerrename/dll/dllmain.cpp
// We don't need to implement DllGetActivationFactory or DllCanUnloadNow
// manually, since the generated module.g.cpp will handle it for us, and will
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised we get a module.g.cpp . . . did we make sure the cppwinrt WRL hookup works right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we get it because of PlaceholderType? It does seem to do some WRL magic. I have no idea how, but it does seem to work ¯\_(ツ)_/¯

// handle our WRL types appropriately.
//
// I'm not positive how much of it we need, but we definitely need:
// * a ClassFactory that can create our implementation of IExplorerCommand
// * a DllGetClassObject that will return the aforementioned class factory.

std::atomic<DWORD> g_dwModuleRefCount = 0;
HINSTANCE g_hInst = 0;

extern "C" IMAGE_DOS_HEADER __ImageBase;
void ModuleAddRef()
{
g_dwModuleRefCount++;
}
// 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.

void ModuleRelease()
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, _COM_Outptr_ void** ppv)
{
g_dwModuleRefCount--;
return Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
}

struct ShellExtClassFactory : winrt::implements<ShellExtClassFactory, IClassFactory>
STDAPI_(BOOL)
DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
{
public:
ShellExtClassFactory(_In_ REFCLSID clsid) :
m_clsid{ clsid } {};

// IClassFactory methods
IFACEMETHODIMP CreateInstance(_In_opt_ IUnknown* punkOuter,
_In_ REFIID riid,
_Outptr_ void** ppv)
if (reason == DLL_PROCESS_ATTACH)
{
*ppv = NULL;
HRESULT hr;
if (punkOuter)
{
hr = CLASS_E_NOAGGREGATION;
}
else if (m_clsid == __uuidof(OpenTerminalHere))
{
hr = winrt::make<OpenTerminalHere>()->QueryInterface(riid, ppv);
}
else
{
hr = CLASS_E_CLASSNOTAVAILABLE;
}
return hr;
DisableThreadLibraryCalls(hinst);
}

IFACEMETHODIMP LockServer(BOOL bLock)
{
if (bLock)
{
ModuleAddRef();
}
else
{
ModuleRelease();
}
return S_OK;
}

private:
CLSID m_clsid;
};

// !IMPORTANT! Make sure that DllGetClassObject is exported in <dllName>.def!
HRESULT __stdcall DllGetClassObject(GUID const& clsid, GUID const& iid, void** result)
{
*result = nullptr;
// !IMPORTANT! Explorer is going to call DllGetClassObject with the clsid of
// the class it wants to create, and the iid of IClassFactory. First we must
// return the ClassFactory here - later on, the ClassFactory will have
// CreateInstance called, where we can actually create the thing it
// requested in clsid.
auto pClassFactory = winrt::make<ShellExtClassFactory>(clsid);
return pClassFactory->QueryInterface(iid, result);
return TRUE;
}
3 changes: 3 additions & 0 deletions src/cascadia/ShellExtension/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@

#include <Shobjidl.h>
#include <shlwapi.h>

#include <wrl.h>
#include <wrl\module.h>