Add initial form of appLauncher

pull/130/head
Peter Repukat 3 years ago
parent 2b99d1f89b
commit aaf9b50433

@ -0,0 +1,171 @@
/*
Copyright 2021 Peter Repukat - FlatspotSoftware
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "AppLauncher.h"
#include <spdlog/spdlog.h>
#ifdef _WIN32
#include <ShObjIdl.h>
#include <atlbase.h>
#endif
#include <regex>
AppLauncher::AppLauncher(std::function<void()> shutdown) : shutdown_(std::move(shutdown))
{
#ifdef _WIN32
UnPatchValveHooks();
#endif
};
void AppLauncher::launchApp(const std::wstring& path, const std::wstring& args)
{
launchWin32App(path, args);
}
void AppLauncher::update()
{
if (process_check_clock_.getElapsedTime().asSeconds() > 1) {
#ifdef _WIN32
if (process_info.dwProcessId > 0) {
if (!IsProcessRunning(process_info.dwProcessId)) {
shutdown_();
}
}
if (uwp_pid_ > 0) {
if (!IsProcessRunning(uwp_pid_)) {
shutdown_();
}
}
#endif
process_check_clock_.restart();
}
}
void AppLauncher::close()
{
#ifdef _WIN32
if (process_info.dwProcessId > 0) {
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
}
#endif
}
#ifdef _WIN32
bool AppLauncher::IsProcessRunning(DWORD pid)
{
const HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (process == nullptr)
return false;
const DWORD ret = WaitForSingleObject(process, 0);
CloseHandle(process);
return ret == WAIT_TIMEOUT;
}
#endif
#ifdef _WIN32
void AppLauncher::UnPatchValveHooks()
{
spdlog::debug("Unpatching Valve CreateProcess hook...");
// need to load addresses that way.. Otherwise we may land before some jumps...
auto kernel32dll = GetModuleHandle(L"kernel32.dll");
if (kernel32dll) {
BYTE* address = reinterpret_cast<BYTE*>(GetProcAddress(kernel32dll, "CreateProcessW"));
if (address) {
DWORD dw_old_protect, dw_bkup;
const auto len = CREATE_PROC_ORIG_BYTES.size();
VirtualProtect(address, len, PAGE_EXECUTE_READWRITE, &dw_old_protect); //Change permissions of memory..
for (DWORD i = 0; i < len; i++) //unpatch Valve's hook
{
*(address + i) = CREATE_PROC_ORIG_BYTES[i];
}
VirtualProtect(address, len, dw_old_protect, &dw_bkup); //Revert permission change...
spdlog::trace("Unpatched CreateProcessW");
}
else {
spdlog::error("failed to unpatch CreateProcessW");
}
}
else {
spdlog::error("kernel32.dll not found... sure...");
}
}
void AppLauncher::launchWin32App(const std::wstring& path, const std::wstring& args)
{
const auto native_seps_path = std::regex_replace(path, std::wregex(L"(\\/|\\\\)"), L"\\");
std::wstring launch_dir;
std::wsmatch m;
if (!std::regex_search(native_seps_path, m, std::wregex(L"(.*?\\\\)*"))) {
spdlog::warn("Couldn't detect launch application directory"); // Shouldn't ever happen...
} else {
launch_dir = m[0];
}
std::wstring args_cpy(args);
if (CreateProcessW(native_seps_path.data(),
args_cpy.data(),
nullptr,
nullptr,
TRUE,
0,
nullptr,
launch_dir.empty() ? nullptr : launch_dir.data(),
&info,
&process_info)) {
spdlog::info(L"Started Program: \"{}\" in directory: {}", native_seps_path, launch_dir);
}
else {
spdlog::error(L"Couldn't start program: \"{}\" in directory: {}", native_seps_path, launch_dir);
}
}
void AppLauncher::launchUWPApp(const LPCWSTR package_full_name)
{
HRESULT result = CoInitialize(nullptr);
if (SUCCEEDED(result)) {
CComPtr<IApplicationActivationManager> sp_app_activation_manager;
// Initialize IApplicationActivationManager
result = CoCreateInstance(
CLSID_ApplicationActivationManager,
nullptr,
CLSCTX_LOCAL_SERVER,
IID_IApplicationActivationManager,
reinterpret_cast<LPVOID*>(&sp_app_activation_manager));
if (SUCCEEDED(result)) {
// This call ensures that the app is launched as the foreground window and sometimes may randomly fail...
result = CoAllowSetForegroundWindow(sp_app_activation_manager, nullptr);
if (!SUCCEEDED(result)) {
spdlog::warn("CoAllowSetForegroundWindow failed. Code: {}", result);
}
// Launch the app
result = sp_app_activation_manager->ActivateApplication(package_full_name, nullptr, AO_NONE, &uwp_pid_);
if (!SUCCEEDED(result)) {
spdlog::error("ActivateApplication failed: Code {}", result);
} else {
spdlog::info(L"Launched UWP Package \"{}\"", package_full_name);
}
} else {
spdlog::error("CoCreateInstance failed: Code {}", result);
}
CoUninitialize();
}
else {
spdlog::error("CoInitialize failed: Code {}", result);
}
}
#endif

@ -0,0 +1,53 @@
/*
Copyright 2021 Peter Repukat - FlatspotSoftware
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#ifdef _WIN32
#define NOMINMAX
#include <Windows.h>
#endif
#include <functional>
#include <string>
#include <SFML/System/Clock.hpp>
class AppLauncher {
public:
explicit AppLauncher(std::function<void()> shutdown = [](){});
void launchApp(const std::wstring& path, const std::wstring& args = L"");
void update();
void close();
private:
std::function<void()> shutdown_;
sf::Clock process_check_clock_;
#ifdef _WIN32
static bool IsProcessRunning(DWORD pid);
// Valve also hooks "CreateProcess"
// Unpatch that so that launched programs don't also get hooked...
static inline const std::string CREATE_PROC_ORIG_BYTES = "\x4C\x8B\xDC\x48\x83";
static void UnPatchValveHooks();
void launchWin32App(const std::wstring& path, const std::wstring& args = L"");
void launchUWPApp(LPCWSTR package_full_name);
STARTUPINFO info{sizeof(info)};
PROCESS_INFORMATION process_info{};
DWORD uwp_pid_ = 0;
#endif
};

@ -163,6 +163,7 @@
<ClCompile Include="..\deps\imgui\imgui_tables.cpp" />
<ClCompile Include="..\deps\imgui\imgui_widgets.cpp" />
<ClCompile Include="..\deps\subhook\subhook.c" />
<ClCompile Include="AppLauncher.cpp" />
<ClCompile Include="HidHide.cpp" />
<ClCompile Include="InputRedirector.cpp" />
<ClCompile Include="main.cpp" />
@ -175,6 +176,7 @@
<ClInclude Include="..\deps\imgui-sfml\imgui-SFML.h" />
<ClInclude Include="..\deps\imgui\imgui.h" />
<ClInclude Include="..\deps\subhook\subhook.h" />
<ClInclude Include="AppLauncher.h" />
<ClInclude Include="HidHide.h" />
<ClInclude Include="imconfig.h" />
<ClInclude Include="InputRedirector.h" />

@ -72,6 +72,9 @@
<ClCompile Include="..\deps\imgui-sfml\imgui-SFML.cpp">
<Filter>Source Files\imgui-sfml</Filter>
</ClCompile>
<ClCompile Include="AppLauncher.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SteamTarget.h">
@ -110,6 +113,9 @@
<ClInclude Include="OverlayLogSink.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AppLauncher.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\deps\SFML\out\build\x64-Debug\lib\sfml-system-d-2.dll" />

@ -28,7 +28,8 @@ limitations under the License.
SteamTarget::SteamTarget(int argc, char* argv[])
: window_([this] { run_ = false; }, getScreenshotHotkey()),
overlay_(window_.getOverlay()),
detector_([this](bool overlay_open) { onOverlayChanged(overlay_open); })
detector_([this](bool overlay_open) { onOverlayChanged(overlay_open); }),
launcher_([this] { run_ = false; })
{
target_window_handle_ = window_.getSystemHandle();
}
@ -57,18 +58,21 @@ Application will not function!");
input_redirector_.run();
#endif
// launcher_.launchApp(L"1234"); // TODO
keepControllerConfig(true);
while (run_) {
detector_.update();
window_.update();
overlayHotkeyWorkaround();
launcher_.update();
}
#ifdef _WIN32
input_redirector_.stop();
hidhide_.disableHidHide();
#endif
launcher_.close();
return 1;
}

@ -25,6 +25,7 @@ limitations under the License.
#include <subhook.h>
#endif
#include "AppLauncher.h"
#include "Overlay.h"
#include <filesystem>
@ -76,6 +77,7 @@ class SteamTarget {
TargetWindow window_;
Overlay& overlay_;
SteamOverlayDetector detector_;
AppLauncher launcher_;
WindowHandle last_foreground_window_ = nullptr;
static inline WindowHandle target_window_handle_ = nullptr;

Loading…
Cancel
Save