mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-19 02:13:03 +08:00
[feat] add Windows pre-login remote control and fix autostart
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "service_lifetime.h"
|
||||
|
||||
int wmain(int argc, wchar_t** argv) {
|
||||
if (argc == 4 && std::wstring(argv[1]) == L"--child") {
|
||||
crossdesk::ServiceLifetimeWatcher watcher;
|
||||
if (!watcher.Start(argv[2])) return 2;
|
||||
HANDLE ready = OpenEventW(EVENT_MODIFY_STATE, FALSE, argv[3]);
|
||||
if (!ready) return 3;
|
||||
SetEvent(ready);
|
||||
CloseHandle(ready);
|
||||
Sleep(INFINITE); // The real watcher must terminate this child.
|
||||
return 4;
|
||||
}
|
||||
|
||||
wchar_t executable[32768]{};
|
||||
if (!GetModuleFileNameW(nullptr, executable, 32768)) return 1;
|
||||
for (bool abandon : {false, true}) {
|
||||
const auto suffix = std::to_wstring(GetCurrentProcessId()) +
|
||||
(abandon ? L"-abandon" : L"-release");
|
||||
const auto name = L"Global\\CrossDeskLifetimeTest-" + suffix;
|
||||
const auto ready_name = name + L"-ready";
|
||||
HANDLE owned = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
||||
HANDLE exit_owner = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
||||
HANDLE ready = CreateEventW(nullptr, TRUE, FALSE, ready_name.c_str());
|
||||
if (!owned || !exit_owner || !ready) return 1;
|
||||
HANDLE lifetime = nullptr;
|
||||
std::thread owner([&] {
|
||||
lifetime = CreateMutexW(nullptr, TRUE, name.c_str());
|
||||
SetEvent(owned);
|
||||
WaitForSingleObject(exit_owner, INFINITE);
|
||||
if (!abandon && lifetime) ReleaseMutex(lifetime);
|
||||
});
|
||||
WaitForSingleObject(owned, INFINITE);
|
||||
bool ok = lifetime != nullptr;
|
||||
if (ok) {
|
||||
// Cancellation during an ordinary helper exit must not wait for or
|
||||
// release the service's ownership.
|
||||
crossdesk::ServiceLifetimeWatcher cancellation;
|
||||
ok = cancellation.Start(name);
|
||||
}
|
||||
std::wstring command = L"\"" + std::wstring(executable) + L"\" --child \"" +
|
||||
name + L"\" \"" + ready_name + L"\"";
|
||||
STARTUPINFOW startup{};
|
||||
startup.cb = sizeof(startup);
|
||||
PROCESS_INFORMATION child{};
|
||||
if (ok)
|
||||
ok = CreateProcessW(executable, command.data(), nullptr, nullptr, FALSE,
|
||||
CREATE_NO_WINDOW, nullptr, nullptr, &startup,
|
||||
&child) != FALSE;
|
||||
if (ok)
|
||||
ok = WaitForSingleObject(ready, 10000) == WAIT_OBJECT_0 &&
|
||||
WaitForSingleObject(child.hProcess, 0) == WAIT_TIMEOUT;
|
||||
SetEvent(exit_owner);
|
||||
owner.join();
|
||||
if (ok) ok = WaitForSingleObject(child.hProcess, 5000) == WAIT_OBJECT_0;
|
||||
DWORD exit_code = 0;
|
||||
if (ok)
|
||||
ok = GetExitCodeProcess(child.hProcess, &exit_code) &&
|
||||
exit_code == ERROR_BROKEN_PIPE;
|
||||
if (child.hProcess) {
|
||||
if (!ok) TerminateProcess(child.hProcess, 1);
|
||||
WaitForSingleObject(child.hProcess, 5000);
|
||||
CloseHandle(child.hProcess);
|
||||
CloseHandle(child.hThread);
|
||||
}
|
||||
if (lifetime) CloseHandle(lifetime);
|
||||
CloseHandle(owned);
|
||||
CloseHandle(exit_owner);
|
||||
CloseHandle(ready);
|
||||
if (!ok) {
|
||||
std::cerr << "Service lifetime test failed, abandoned=" << abandon
|
||||
<< '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::cout
|
||||
<< "Service release, crash and watcher cancellation checks passed\n";
|
||||
}
|
||||
Reference in New Issue
Block a user