Enforce non desktop bindings:

done by mid function hooking a function in steamclient.dll
the function appears to be setting the appId of the new controller bindings

inject/hook right after the target launched
switch focus -> binding gets changed to shortcut bindings -> hook function grabs appid
hook function replaces desktop-config appid with the one grabbed everytime steam tries to active desktop-config
glosc_gamelauncher unloads dll when the target closes; unloading dll patches steamclient.dll back to original
UWP_Overlay-legacy
Peter Repukat 8 years ago
parent 616486fd7d
commit 7947d6faac

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{AFA0047E-7DEE-472A-AF4B-436A30459905}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>EnforceBindingDLL</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ENFORCEBINDINGDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;ENFORCEBINDINGDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ENFORCEBINDINGDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;ENFORCEBINDINGDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="EnforceBindings.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="EnforceBindings.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Quelldateien">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Headerdateien">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Ressourcendateien">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="EnforceBindings.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="EnforceBindings.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
</Project>

@ -0,0 +1,139 @@
/*
Copyright 2016 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 "EnforceBindings.h"
//stuff for finding the function as well as the injected code
//should probably be moved somewhere else
DWORD address = 0x381FA91B;
DWORD JMPBack;
int32_t currentBindings;
const int32_t desktopBindingsID = 413080; //desktop_config appid
const int32_t bigPictureBindingsID = 413090; //desktop_config appid
const int32_t steamChordBindingsID = 443510; //desktop_config appid
int32_t enforceBindingsID = 413080; //0x80000009;
char originalBytes[] = "\x8B\x45\x0c\x57\x8B\x7D\x08";
__declspec(naked) void enforceBindingsHookFn()
{
__asm
{
mov eax, dword ptr ss : [ebp + 0xc]
mov currentBindings, eax
}
if (currentBindings != desktopBindingsID
&& currentBindings != bigPictureBindingsID
&& currentBindings != steamChordBindingsID)
{
enforceBindingsID = currentBindings;
}
if (currentBindings == desktopBindingsID)
{
__asm
{
mov eax, enforceBindingsID
}
}
__asm
{
push edi
mov edi, dword ptr ss : [ebp + 0x8]
jmp[JMPBack]
}
}
//\\\
void EnforceBindings::patchBytes()
{
address = FindPattern("steamclient.dll", originalBytes, "xxxxxxx");
JMPBack = address + 0x7; //7 size of pattern/mask == patched instructions
PlaceJMP((BYTE*)address, (DWORD)enforceBindingsHookFn, 7);
}
void EnforceBindings::Unpatch()
{
RestoreBytes((BYTE*)address, (BYTE*)originalBytes, 7);
}
void EnforceBindings::PlaceJMP(BYTE * Address, DWORD jumpTo, DWORD lenght)
{
DWORD dwOldProtect, dwBkup, dwReloadAddr;
VirtualProtect(Address, lenght, PAGE_EXECUTE_READWRITE, &dwOldProtect);
dwReloadAddr = (jumpTo - (DWORD)Address) - 5; //5 == lenght of jump instruction (1byte + 4byte address)
*Address = 0xE9; //jmp instrcution
*((DWORD*)(Address + 0x1)) = dwReloadAddr;
for (DWORD x = 5; x < lenght; x++)
*(Address + x) = 0x90; //nop the rest
VirtualProtect(Address, lenght, dwOldProtect, &dwBkup);
}
void EnforceBindings::RestoreBytes(BYTE * Address, BYTE * original, DWORD lenght)
{
DWORD dwOldProtect, dwBkup, dwReloadAddr;
VirtualProtect(Address, lenght, PAGE_EXECUTE_READWRITE, &dwOldProtect);
for (DWORD x = 0; x < lenght; x++)
{
*(Address + x) = *(original + x);
}
VirtualProtect(Address, lenght, dwOldProtect, &dwBkup);
}
MODULEINFO EnforceBindings::GetModInfo(char * szModule)
{
MODULEINFO ret = { NULL };
HMODULE mod = GetModuleHandleA(szModule);
if (mod != 0)
GetModuleInformation(GetCurrentProcess(), mod, &ret, sizeof(MODULEINFO));
return ret;
}
DWORD EnforceBindings::FindPattern(char * module, char * pattern, char * mask)
{
MODULEINFO mInfo = GetModInfo(module);
DWORD baseAddr = (DWORD)mInfo.lpBaseOfDll;
DWORD size = mInfo.SizeOfImage;
DWORD patLenght = strlen(mask);
for (DWORD i = 0; i < size - patLenght; i++) //bad for loop btw...
{
bool found = true;
for (DWORD j = 0; j < patLenght; j++)
found &= mask[j] == '?' || pattern[j] == *(char*)(baseAddr + j + i);
if (found)
return baseAddr + i;
}
return NULL;
}

@ -0,0 +1,42 @@
/*
Copyright 2016 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
#include <stdint.h>
#include <Windows.h>
#include <psapi.h>
class EnforceBindings
{
public:
static void patchBytes();
static void Unpatch();
private:
static void PlaceJMP(BYTE * Address, DWORD jumpTo, DWORD lenght);
static void RestoreBytes(BYTE *Address, BYTE *original, DWORD lenght);
static MODULEINFO GetModInfo(char *szModule);
static DWORD FindPattern(char *module, char *pattern, char *mask);
};

@ -0,0 +1,38 @@
/*
Copyright 2016 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 <Windows.h>
#include "EnforceBindings.h"
HANDLE hThread;
void WINAPI Run()
{
}
int WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
EnforceBindings::patchBytes();
//hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Run, 0, 0, 0);
} else if (reason == DLL_PROCESS_DETACH) {
EnforceBindings::Unpatch();
//TerminateThread(hThread, 0);
}
return true;
}

@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GloSC", "GloSC\GloSC.vcxpro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GloSC_GameLauncher", "GloSC_GameLauncher\GloSC_GameLauncher.vcxproj", "{431D29FD-73F8-4374-868B-F72972566F41}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EnforceBindingDLL", "EnforceBindingDLL\EnforceBindingDLL.vcxproj", "{AFA0047E-7DEE-472A-AF4B-436A30459905}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -41,6 +43,14 @@ Global
{431D29FD-73F8-4374-868B-F72972566F41}.Release|x64.Build.0 = Release|x64
{431D29FD-73F8-4374-868B-F72972566F41}.Release|x86.ActiveCfg = Release|Win32
{431D29FD-73F8-4374-868B-F72972566F41}.Release|x86.Build.0 = Release|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x64.ActiveCfg = Debug|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x64.Build.0 = Debug|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x86.ActiveCfg = Debug|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Debug|x86.Build.0 = Debug|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Release|x64.ActiveCfg = Release|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Release|x64.Build.0 = Release|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Release|x86.ActiveCfg = Release|Win32
{AFA0047E-7DEE-472A-AF4B-436A30459905}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -5,7 +5,7 @@ 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
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,
@ -21,6 +21,7 @@ GloSC::GloSC(QWidget *parent)
ui.setupUi(this);
updateEntryList();
updateTargetsToNewVersion();
}
@ -46,8 +47,9 @@ void GloSC::writeIni(QString entryName)
settings.beginGroup("BaseConf");
settings.setValue("bShowOverlay", 0 + ui.cbOverlay->isChecked());
settings.setValue("bEnableOverlay", 0 + ui.cbOverlay->isChecked());
settings.setValue("bEnableControllers", 0 + ui.cbControllers->isChecked());
settings.setValue("bHookSteam", 1);
settings.endGroup();
@ -72,6 +74,26 @@ void GloSC::writeIni(QString entryName)
}
void GloSC::updateTargetsToNewVersion()
{
//incredible lazy way to update to this next version but eh...
for (int i = 0; i < ui.lwInstances->count(); i++)
{
on_lwInstances_currentRowChanged(i);
QString name = ui.leName->text();
QSettings settings(name + "\\TargetConfig.ini", QSettings::IniFormat);
settings.beginGroup("BaseConf");
bool newVersion = settings.value("bHookSteam").toBool();
settings.endGroup();
if (!newVersion)
settings.endGroup();
on_pbSave_clicked();
}
}
void GloSC::on_pbSave_clicked()
{
@ -382,7 +404,7 @@ void GloSC::on_lwInstances_currentRowChanged(int row)
settings.beginGroup("BaseConf");
ui.cbOverlay->setChecked(settings.value("bShowOverlay").toBool());
ui.cbOverlay->setChecked(settings.value("bEnableOverlay").toBool());
ui.cbControllers->setChecked(settings.value("bEnableControllers").toBool());
settings.endGroup();

@ -44,8 +44,12 @@ private:
void updateEntryList();
void writeIni(QString entryName);
void updateTargetsToNewVersion();
QList<UWPPair> uwpPairs;
private slots:
void on_pbSave_clicked();
void on_pbDelete_clicked();

@ -106,7 +106,7 @@
<rect>
<x>10</x>
<y>70</y>
<width>111</width>
<width>371</width>
<height>17</height>
</rect>
</property>
@ -122,7 +122,7 @@
<rect>
<x>10</x>
<y>100</y>
<width>151</width>
<width>371</width>
<height>17</height>
</rect>
</property>
@ -138,7 +138,7 @@
<rect>
<x>10</x>
<y>210</y>
<width>91</width>
<width>371</width>
<height>17</height>
</rect>
</property>
@ -239,7 +239,7 @@
<x>10</x>
<y>260</y>
<width>371</width>
<height>31</height>
<height>51</height>
</rect>
</property>
<property name="text">

@ -35,12 +35,23 @@ GloSC_GameLauncher::GloSC_GameLauncher(QWidget *parent)
sharedMemInstance.attach();
sharedMemInstance.lock();
memset(sharedMemInstance.data(), NULL, 1024);
QBuffer buffer;
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << defaultSharedMemData;
int size = buffer.size();
char *to = (char*)sharedMemInstance.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemInstance.size(), size));
sharedMemInstance.unlock();
connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(isAboutToBeKilled()));
connect(&updateTimer, SIGNAL(timeout()), this, SLOT(checkSharedMem()));
updateTimer.setInterval(1000);
updateTimer.setInterval(250);
updateTimer.start();
}
@ -52,62 +63,82 @@ void GloSC_GameLauncher::isAboutToBeKilled()
void GloSC_GameLauncher::checkSharedMem()
{
QBuffer buffer;
QDataStream in(&buffer);
QDataStream dataStream(&buffer);
QStringList stringList;
sharedMemInstance.lock();
buffer.setData((char*)sharedMemInstance.constData(), sharedMemInstance.size());
buffer.open(QBuffer::ReadOnly);
dataStream >> stringList;
buffer.close();
int i = stringList.indexOf(LaunchGame);
if (i > -1)
{
if (stringList.at(i + 1) != "" && stringList.at(i + 2) != "")
{
launchGame(stringList.at(i + 1), stringList.at(i + 2));
stringList = defaultSharedMemData;
}
}
i = stringList.indexOf(IsSteamHooked);
if (i > -1)
{
bHookedSteam = true;
if (stringList.at(i + 1).toInt() > -1)
{
stringList.replace(i + 1, "-1");
}
}
if (pid != NULL)
{
memset(sharedMemInstance.data(), NULL, 1024);
if (!IsProcessRunning(pid))
{
pid = NULL;
stringListFromShared = stringList;
stringList << "LaunchedProcessFinished";
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << stringList;
int size = buffer.size();
char *to = (char*)sharedMemInstance.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemInstance.size(), size));
sharedMemInstance.unlock();
int i = stringList.indexOf(LaunchedProcessFinished) + 1;
stringList.replace(i, "1");
}
} else {
buffer.setData((char*)sharedMemInstance.constData(), sharedMemInstance.size());
buffer.open(QBuffer::ReadOnly);
in >> stringList;
stringListFromShared = stringList;
memset(sharedMemInstance.data(), NULL, 1024);
sharedMemInstance.unlock();
launchGameIfRequired();
}
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << stringList;
int size = buffer.size();
char *to = (char*)sharedMemInstance.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemInstance.size(), size));
buffer.close();
sharedMemInstance.unlock();
if (FindWindow(NULL, L"GloSC_OverlayWindow") == NULL)
{
unhookBindings();
bHookedSteam = false;
}
}
void GloSC_GameLauncher::launchGameIfRequired()
void GloSC_GameLauncher::launchGame(QString type, QString path)
{
if (stringListFromShared.size() > 1)
{
if (stringListFromShared.at(0) == "LaunchWin32Game")
if (type == LGT_Win32)
{
QProcess app;
if (stringListFromShared.at(1).contains("\\"))
if (path.contains("\\"))
{
app.startDetached(stringListFromShared.at(1), QStringList(), stringListFromShared.at(1).mid(0, stringListFromShared.at(1).lastIndexOf("\\")), &pid);
app.startDetached(path, QStringList(), path.mid(0, path.lastIndexOf("\\")), &pid);
}
else
{
app.startDetached(stringListFromShared.at(1), QStringList(), stringListFromShared.at(1).mid(0, stringListFromShared.at(1).lastIndexOf("/")), &pid);
app.startDetached(path, QStringList(), path.mid(0, path.lastIndexOf("/")), &pid);
}
} else if (stringListFromShared.at(0) == "LaunchUWPGame") {
} else if (type == LGT_UWP) {
DWORD pid = 0;
HRESULT hr = CoInitialize(nullptr);
std::wstring appUMId = stringListFromShared.at(1).toStdWString();
std::wstring appUMId = path.toStdWString();
if (SUCCEEDED(hr)) {
HRESULT result = LaunchUWPApp(appUMId.c_str(), &pid);
if (SUCCEEDED(result))
@ -119,8 +150,6 @@ void GloSC_GameLauncher::launchGameIfRequired()
CoUninitialize();
}
}
}
HRESULT GloSC_GameLauncher::LaunchUWPApp(LPCWSTR packageFullName, PDWORD pdwProcessId)
@ -150,3 +179,21 @@ HRESULT GloSC_GameLauncher::LaunchUWPApp(LPCWSTR packageFullName, PDWORD pdwProc
return result;
}
bool GloSC_GameLauncher::IsProcessRunning(DWORD pid)
{
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
DWORD ret = WaitForSingleObject(process, 1);
CloseHandle(process);
return ret == WAIT_TIMEOUT;
}
void GloSC_GameLauncher::unhookBindings()
{
QProcess proc;
proc.setNativeArguments(" --process-name Steam.exe --module-name EnforceBindingDLL.dll --eject ");
proc.start("Injector.exe", QIODevice::ReadOnly);
proc.waitForFinished();
}

@ -31,6 +31,8 @@ limitations under the License.
#include <QBuffer>
#include <qprocess.h>
#include <qmessagebox.h>
class GloSC_GameLauncher : public QMainWindow
{
@ -45,23 +47,36 @@ public slots:
private:
Ui::GloSC_GameLauncherClass ui;
const QString LaunchGame = "LaunchGame";
const QString LGT_UWP = "UWP";
const QString LGT_Win32 = "Win32";
const QString LaunchedProcessFinished = "LaunchedProcessFinished";
const QString IsSteamHooked = "IsSteamHooked";
const QStringList defaultSharedMemData = QStringList()
<< LaunchGame
<< ""
<< ""
<< LaunchedProcessFinished
<< "0"
<< IsSteamHooked
<< "-1";
QSharedMemory sharedMemInstance;
QTimer updateTimer;
QStringList stringListFromShared;
qint64 pid = NULL;
void launchGameIfRequired();
bool bHookedSteam = false;
void launchGame(QString type, QString path);
HRESULT LaunchUWPApp(LPCWSTR packageFullName, PDWORD pdwProcessId);
bool IsProcessRunning(DWORD pid)
{
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
DWORD ret = WaitForSingleObject(process, 1);
CloseHandle(process);
return ret == WAIT_TIMEOUT;
}
bool IsProcessRunning(DWORD pid);
void unhookBindings();
private slots:
void checkSharedMem();

@ -21,6 +21,7 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{431D29FD-73F8-4374-868B-F72972566F41}</ProjectGuid>
<Keyword>Qt4VSv1.0</Keyword>
<ProjectName>GloSC_GameLauncher</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">

@ -33,6 +33,8 @@ SteamTargetRenderer::SteamTargetRenderer()
bDrawOverlay = settings.value(childkey).toBool();
} else if (childkey == "bEnableControllers") {
bEnableControllers = settings.value(childkey).toBool();
}else if (childkey == "bHookSteam") {
bHookSteam = settings.value(childkey).toBool();
}
}
settings.endGroup();
@ -40,12 +42,11 @@ SteamTargetRenderer::SteamTargetRenderer()
#ifndef NDEBUG
bDrawDebugEdges = true;
#endif // NDEBUG
sfCshape = sf::CircleShape(100.f);
sfCshape.setFillColor(sf::Color(128, 128, 128, 128));
sfCshape.setOrigin(sf::Vector2f(100, 100));
sf::VideoMode mode = sf::VideoMode::getDesktopMode();
sfWindow.create(sf::VideoMode(mode.width-16, mode.height-32), "OverlayWindow"); //Window is too large ; always 16 and 32 pixels? - sf::Style::None breaks transparency!
sfWindow.create(sf::VideoMode(mode.width-16, mode.height-32), "GloSC_OverlayWindow"); //Window is too large ; always 16 and 32 pixels? - sf::Style::None breaks transparency!
sfWindow.setVerticalSyncEnabled(bVsync);
if (!bVsync)
sfWindow.setFramerateLimit(iRefreshRate);
@ -117,8 +118,15 @@ void SteamTargetRenderer::RunSfWindowLoop()
//Only works with a console window
//Causes trouble as soon as there is more than the consoleWindow and the overlayWindow
//This is trying to avoid hooking Steam.exe
//----
//alternatively, we can just hook steam and make our lives so much easier
//we inject and hook here to spare IPC and let the dll grab the steam appID of the launched process when the config switches (config switches w/ focus)
if (focusSwitchNeeded)
{
if (bHookSteam)
hookBindings(); //cleanup - unhooking / unloading of dll is managed by the GloSC gamelauncher rather than here
focusSwitchNeeded = false;
SetFocus(consoleHwnd);
sf::Clock clock;
@ -129,7 +137,7 @@ void SteamTargetRenderer::RunSfWindowLoop()
}
//Dirty hack to make the steamoverlay work properly and still keep Apps Controllerconfig when closing overlay.
//This is trying to avoid hooking Steam.exe
//even if hooking steam, this ensures the overlay stays working
if (overlayPtr != NULL)
{
char overlayOpen = *(char*)overlayPtr;
@ -149,6 +157,10 @@ void SteamTargetRenderer::RunSfWindowLoop()
//Actually activate the overlaywindow
SetFocus(sfWindow.getSystemHandle());
//Move the mouse cursor inside the overlaywindow
//this is neccessary because steam doesn't want to switch to big picture bindings if mouse isn't inside
SetCursorPos(16, 16);
//by activating the consolewindow **and bringing it to the foreground** we can trick steam so the controller stays in game bindings
SetFocus(consoleHwnd);
sf::Clock clock;
@ -234,9 +246,62 @@ void SteamTargetRenderer::drawDebugEdges()
}
void SteamTargetRenderer::launchApp()
void SteamTargetRenderer::hookBindings()
{
std::cout << "Hooking Steam..." << std::endl;
QString dir = QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
dir = dir.mid(0, dir.lastIndexOf("\\"));
QProcess proc;
proc.setNativeArguments(" --process-name Steam.exe --module-name " + dir + "\\EnforceBindingDLL.dll --inject ");
proc.start(dir + "\\Injector.exe", QIODevice::ReadOnly);
proc.waitForFinished();
if (QString::fromStdString(proc.readAll().toStdString()).contains("Successfully injected module!")) //if we have injected (and patched the function)
{
std::cout << "Successfully hooked Steam!" << std::endl;
//tell the GloSC_GameLauncher that we have hooked steam
//it will deal with checking if the target is still alive and unload the dll / unhook then
// - ensures unloading / unhooking even if this process crashes or gets unexpectedly killed
QSharedMemory sharedMemInstance("GloSC_GameLauncher");
if (!sharedMemInstance.create(1024) && sharedMemInstance.error() == QSharedMemory::AlreadyExists)
{
QBuffer buffer;
QDataStream dataStream(&buffer);
QStringList stringList;
sharedMemInstance.attach();
sharedMemInstance.lock();
buffer.setData((char*)sharedMemInstance.constData(), sharedMemInstance.size());
buffer.open(QBuffer::ReadOnly);
dataStream >> stringList;
buffer.close();
int i = stringList.indexOf(IsSteamHooked) + 1;
stringList.replace(i, "1");
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << stringList;
int size = buffer.size();
char *to = (char*)sharedMemInstance.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemInstance.size(), size));
buffer.close();
sharedMemInstance.unlock();
sharedMemInstance.detach();
}
} else {
std::cout << "Hooking Steam failed!" << std::endl;
}
}
void SteamTargetRenderer::launchApp()
{
bool launchGame = false;
bool closeWhenDone = false;
QString type = "Win32";
@ -267,25 +332,35 @@ void SteamTargetRenderer::launchApp()
QSharedMemory sharedMemInstance("GloSC_GameLauncher");
if (!sharedMemInstance.create(1024) && sharedMemInstance.error() == QSharedMemory::AlreadyExists)
{
QBuffer buffer;
QDataStream dataStream(&buffer);
QStringList stringList;
if (type == "Win32")
{
stringList << "LaunchWin32Game";
} else if (type == "UWP") {
stringList << "LaunchUWPGame";
}
stringList << path;
QBuffer buffer;
sharedMemInstance.attach();
sharedMemInstance.lock();
buffer.setData((char*)sharedMemInstance.constData(), sharedMemInstance.size());
buffer.open(QBuffer::ReadOnly);
dataStream >> stringList;
buffer.close();
int lgt_index = stringList.indexOf(LaunchGame);
stringList.replace(lgt_index + 1, type);
stringList.replace(lgt_index + 2, path);
buffer.open(QBuffer::ReadWrite);
QDataStream out(&buffer);
out << stringList;
int size = buffer.size();
sharedMemInstance.attach();
char *to = (char*)sharedMemInstance.data();
const char *from = buffer.data().data();
memcpy(to, from, qMin(sharedMemInstance.size(), size));
buffer.close();
sharedMemInstance.unlock();
sharedMemInstance.detach();
@ -313,11 +388,13 @@ void SteamTargetRenderer::checkSharedMem()
buffer.setData((char*)sharedMemInstance.constData(), sharedMemInstance.size());
buffer.open(QBuffer::ReadOnly);
in >> stringList;
memset(sharedMemInstance.data(), NULL, 1024);
buffer.close();
sharedMemInstance.unlock();
sharedMemInstance.detach();
if (stringList.size() > 0 && stringList.at(0) == "LaunchedProcessFinished")
int close_index = stringList.indexOf(LaunchedProcessFinished)+1;
if (close_index > 0 && stringList.at(close_index).toInt() == 1)
{
bRunLoop = false;
renderThread.join();

@ -30,6 +30,9 @@ limitations under the License.
#include <QDatastream>
#include <QSharedmemory>
#include <QSettings>
#include <QCoreApplication>
#include <QDir>
#include "VirtualControllerThread.h"
@ -71,12 +74,29 @@ private:
bool bEnableControllers = true;
bool bHookSteam = false;
void RunSfWindowLoop();
void makeSfWindowTransparent(sf::RenderWindow& window);
void drawDebugEdges();
QTimer updateTimer;
void hookBindings();
const QString LaunchGame = "LaunchGame";
const QString LaunchedProcessFinished = "LaunchedProcessFinished";
const QString IsSteamHooked = "IsSteamHooked";
const QStringList defaultSharedMemData = QStringList()
<< LaunchGame
<< ""
<< ""
<< LaunchedProcessFinished
<< "0"
<< IsSteamHooked
<< "-1";
private slots:
void launchApp();
void checkSharedMem();

@ -5,7 +5,7 @@ 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
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,

@ -2,6 +2,7 @@
bDrawDebugEdges=0
bEnableOverlay=1
bEnableControllers=1
bHookSteam=1
[LaunchGame]
bLaunchGame=0

Loading…
Cancel
Save