diff --git a/steam_helper/steam.cpp b/steam_helper/steam.cpp index 3cad4e69..1bbb9288 100644 --- a/steam_helper/steam.cpp +++ b/steam_helper/steam.cpp @@ -32,7 +32,10 @@ * a small subset of the actual Steam functionality for games that expect * Windows version of Steam running. */ +#include "ntstatus.h" +#define WIN32_NO_STATUS #include +#include #include #include #include @@ -1172,6 +1175,94 @@ static void setup_steam_files(void) WINE_ERR("Could not write %s.\n", wine_dbgstr_w(libraryfolders_nameW)); } +#ifndef DIRECTORY_QUERY +#define DIRECTORY_QUERY 0x0001 +#endif + +static HANDLE find_ack_event(void) +{ + static const WCHAR steam_ack_event[] = L"STEAM_START_ACK_EVENT"; + static const WCHAR name[] = L"\\BaseNamedObjects\\Session\\1"; + DIRECTORY_BASIC_INFORMATION *di; + OBJECT_ATTRIBUTES attr; + HANDLE dir, ret = NULL; + ULONG context, size; + UNICODE_STRING str; + char buffer[1024]; + NTSTATUS status; + + di = (DIRECTORY_BASIC_INFORMATION *)buffer; + + RtlInitUnicodeString(&str, name); + InitializeObjectAttributes(&attr, &str, 0, 0, NULL); + status = NtOpenDirectoryObject( &dir, DIRECTORY_QUERY, &attr ); + if (status) + { + WINE_WARN("Failed to open directory %s, status %#x.\n", wine_dbgstr_w(name), status); + return NULL; + } + + status = NtQueryDirectoryObject(dir, di, sizeof(buffer), TRUE, TRUE, &context, &size); + while (!status) + { + if (!strncmpW(di->ObjectName.Buffer, steam_ack_event, ARRAY_SIZE(steam_ack_event) - 1)) + { + WINE_TRACE("Found event %s.\n", wine_dbgstr_w(di->ObjectName.Buffer)); + ret = OpenEventW(SYNCHRONIZE, FALSE, di->ObjectName.Buffer); + if (!ret) + WINE_WARN("Failed to create event, err %u.\n", GetLastError()); + break; + } + status = NtQueryDirectoryObject(dir, di, sizeof(buffer), TRUE, FALSE, &context, &size); + } + if (status && status != STATUS_NO_MORE_ENTRIES) + WINE_WARN("NtQueryDirectoryObject failed, status %#x.\n", status); + WINE_TRACE("ret %p.\n", ret); + + CloseHandle(dir); + return ret; +} + +static DWORD WINAPI steam_drm_thread(void *arg) +{ + HANDLE consume, produce; + HANDLE start_ack = NULL; + HANDLE child = arg; + DWORD pid; + LONG prev; + + consume = CreateSemaphoreA(NULL, 0, 512, "STEAM_DIPC_CONSUME"); + if (!consume) + { + WINE_ERR("Failed to create consume semaphore, err %u.\n", GetLastError()); + return -1; + } + produce = CreateSemaphoreA(NULL, 1, 512, "SREAM_DIPC_PRODUCE"); + if (!produce) + { + CloseHandle(consume); + WINE_ERR("Failed to create produce semaphore, err %u.\n", GetLastError()); + return -1; + } + + pid = GetProcessId(child); + + WINE_TRACE("Child pid %04x.\n", pid); + + while (WaitForSingleObject(consume, INFINITE) == WAIT_OBJECT_0) + { + WINE_TRACE("Got event.\n"); + + if (!start_ack) + start_ack = find_ack_event(); + if (start_ack) + SetEvent(start_ack); + ReleaseSemaphore(produce, 1, &prev); + WINE_TRACE("prev %d.\n", prev); + } + + return 0; +} int main(int argc, char *argv[]) { HANDLE wait_handle = INVALID_HANDLE_VALUE; @@ -1240,6 +1331,9 @@ int main(int argc, char *argv[]) else CloseHandle(child); } + + if (game_process) + CreateThread(NULL, 0, steam_drm_thread, child, 0, NULL); } if(wait_handle != INVALID_HANDLE_VALUE)