Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
<Import Project="..\Microsoft.CmdPal.UI\CmdPal.pre.props" Condition="Exists('..\Microsoft.CmdPal.UI\CmdPal.pre.prop')" />
<Import Project="..\Microsoft.CmdPal.UI\CmdPal.pre.props" Condition="Exists('..\Microsoft.CmdPal.UI\CmdPal.pre.props')" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
Expand Down Expand Up @@ -53,7 +53,6 @@
<PreprocessorDefinitions>
EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;
%(PreprocessorDefinitions);
$(CommandPaletteBranding)
</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(CommandPaletteBranding)'=='' or '$(CommandPaletteBranding)'=='Dev'">
IS_DEV_BRANDING;%(PreprocessorDefinitions)
Expand Down
124 changes: 92 additions & 32 deletions src/modules/cmdpal/CmdPalModuleInterface/dllmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@

#include <interface/powertoy_module_interface.h>

#include <atomic>
#include <common/logger/logger.h>
#include <common/utils/logger_helper.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/SettingsAPI/settings_objects.h>
#include <common/utils/resources.h>
#include <common/utils/package.h>
#include <common/utils/process_path.h>
#include <common/utils/winapi_error.h>
#include <common/interop/shared_constants.h>
#include <Psapi.h>
#include <TlHelp32.h>
#include <common/utils/winapi_error.h>
#include <thread>

HINSTANCE g_hInst_cmdPal = 0;

Expand All @@ -37,23 +39,28 @@ BOOL APIENTRY DllMain(HMODULE hInstance,
class CmdPal : public PowertoyModuleIface
{
private:
bool m_enabled = false;

std::wstring app_name;

//contains the non localized key of the powertoy
std::wstring app_key;

HANDLE m_hTerminateEvent;

void LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs, bool elevated)
// Track if this is the first call to enable
bool firstEnableCall = true;

static bool LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs, bool elevated, bool silentFail)
{
std::wstring dir = std::filesystem::path(appPath).parent_path();

SHELLEXECUTEINFO sei = { 0 };
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.hwnd = nullptr;
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE;
if (silentFail)
{
sei.fMask = sei.fMask | SEE_MASK_FLAG_NO_UI;
}
sei.lpVerb = elevated ? L"runas" : L"open";
sei.lpFile = appPath.c_str();
sei.lpParameters = commandLineArgs.c_str();
Expand All @@ -64,7 +71,11 @@ class CmdPal : public PowertoyModuleIface
{
std::wstring error = get_last_error_or_default(GetLastError());
Logger::error(L"Failed to launch process. {}", error);
return false;
}

m_launched.store(true);
return true;
}

std::vector<DWORD> GetProcessesIdByName(const std::wstring& processName)
Expand Down Expand Up @@ -122,6 +133,9 @@ class CmdPal : public PowertoyModuleIface
}

public:
static std::atomic<bool> m_enabled;
static std::atomic<bool> m_launched;

CmdPal()
{
app_name = L"CmdPal";
Expand All @@ -133,10 +147,7 @@ class CmdPal : public PowertoyModuleIface

~CmdPal()
{
if (m_enabled)
{
}
m_enabled = false;
CmdPal::m_enabled.store(false);
}

// Destroy the powertoy and free memory
Expand Down Expand Up @@ -203,15 +214,18 @@ class CmdPal : public PowertoyModuleIface
{
Logger::trace("CmdPal::enable()");

m_enabled = true;
CmdPal::m_enabled.store(true);

try
{
std::wstring packageName = L"Microsoft.CommandPalette";
std::wstring packageName = L"Microsoft.CommandPalette";
std::wstring launchPath = L"shell:AppsFolder\\Microsoft.CommandPalette_8wekyb3d8bbwe!App";
#ifdef IS_DEV_BRANDING
packageName = L"Microsoft.CommandPalette.Dev";
packageName = L"Microsoft.CommandPalette.Dev";
launchPath = L"shell:AppsFolder\\Microsoft.CommandPalette.Dev_8wekyb3d8bbwe!App";
#endif
if (!package::GetRegisteredPackage(packageName, false).has_value())

if (!package::GetRegisteredPackage(packageName, false).has_value())
{
try
{
Logger::info(L"CmdPal not installed. Installing...");

Expand All @@ -238,36 +252,79 @@ class CmdPal : public PowertoyModuleIface
}
}
}
catch (std::exception& e)
{
std::string errorMessage{ "Exception thrown while trying to install CmdPal package: " };
errorMessage += e.what();
Logger::error(errorMessage);
}
}
catch (std::exception& e)

if (!package::GetRegisteredPackage(packageName, false).has_value())
{
std::string errorMessage{ "Exception thrown while trying to install CmdPal package: " };
errorMessage += e.what();
Logger::error(errorMessage);
Logger::error("Cmdpal is not registered, quit..");
return;
}
try

if (!firstEnableCall)
{
#ifdef IS_DEV_BRANDING
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette.Dev_8wekyb3d8bbwe!App", L"RunFromPT", false);
#else
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette_8wekyb3d8bbwe!App", L"RunFromPT", false);
#endif
Logger::trace("Not first attempt, try to launch");
LaunchApp(launchPath, L"RunFromPT", false /*no elevated*/, false /*error pop up*/);
}
catch (std::exception& e)
else
{
std::string errorMessage{ "Exception thrown while trying to launch CmdPal: " };
errorMessage += e.what();
Logger::error(errorMessage);
throw;
// If first time enable, do retry launch.
Logger::trace("First attempt, try to launch");
std::thread launchThread(&CmdPal::RetryLaunch, launchPath);
launchThread.detach();
}

firstEnableCall = false;
}

virtual void disable()
{
Logger::trace("CmdPal::disable()");
TerminateCmdPal();

m_enabled = false;
CmdPal::m_enabled.store(false);
}

static void RetryLaunch(std::wstring path)
{
const int base_delay_milliseconds = 1000;
int max_retry = 9; // 2**9 - 1 seconds. Control total wait time within 10 min.
int retry = 0;
do
{
auto launch_result = LaunchApp(path, L"RunFromPT", false, retry < max_retry);
if (launch_result)
{
Logger::info(L"CmdPal launched successfully after {} retries.", retry);
return;
}
else
{
Logger::error(L"Retry {} launch CmdPal launch failed.", retry);
}

// When we got max retry, we don't need to wait for the next retry.
if (retry < max_retry)
{
int delay = base_delay_milliseconds * (1 << (retry));
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
}
++retry;
} while (retry <= max_retry && m_enabled.load() && !m_launched.load());

if (!m_enabled.load() || m_launched.load())
{
Logger::error(L"Retry cancelled. CmdPal is disabled or already launched.");
}
else
{
Logger::error(L"CmdPal launch failed after {} attempts.", retry);
}
}

virtual bool on_hotkey(size_t) override
Expand All @@ -282,11 +339,14 @@ class CmdPal : public PowertoyModuleIface

virtual bool is_enabled() override
{
return m_enabled;
return CmdPal::m_enabled.load();
}
};

std::atomic<bool> CmdPal::m_enabled{ false };
std::atomic<bool> CmdPal::m_launched{ false };

extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new CmdPal();
}
}
Loading