clang: adjust formatting rules (#1015)

This commit is contained in:
ReenigneArcher 2023-03-27 21:45:29 -04:00 committed by GitHub
commit 21eb4eb6dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
103 changed files with 26883 additions and 25173 deletions

View file

@ -16,242 +16,250 @@
#include "src/utility.h"
DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING
DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING
DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2);
using namespace std::literals;
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
constexpr auto SAMPLE_RATE = 48000;
int device_state_filter = DEVICE_STATE_ACTIVE;
int device_state_filter = DEVICE_STATE_ACTIVE;
namespace audio {
template<class T>
void Release(T *p) {
p->Release();
}
template<class T>
void co_task_free(T *p) {
CoTaskMemFree((LPVOID)p);
}
using device_enum_t = util::safe_ptr<IMMDeviceEnumerator, Release<IMMDeviceEnumerator>>;
using collection_t = util::safe_ptr<IMMDeviceCollection, Release<IMMDeviceCollection>>;
using prop_t = util::safe_ptr<IPropertyStore, Release<IPropertyStore>>;
using device_t = util::safe_ptr<IMMDevice, Release<IMMDevice>>;
using audio_client_t = util::safe_ptr<IAudioClient, Release<IAudioClient>>;
using audio_capture_t = util::safe_ptr<IAudioCaptureClient, Release<IAudioCaptureClient>>;
using wave_format_t = util::safe_ptr<WAVEFORMATEX, co_task_free<WAVEFORMATEX>>;
using wstring_t = util::safe_ptr<WCHAR, co_task_free<WCHAR>>;
using handle_t = util::safe_ptr_v2<void, BOOL, CloseHandle>;
class prop_var_t {
public:
prop_var_t() {
PropVariantInit(&prop);
template <class T>
void
Release(T *p) {
p->Release();
}
~prop_var_t() {
PropVariantClear(&prop);
template <class T>
void
co_task_free(T *p) {
CoTaskMemFree((LPVOID) p);
}
PROPVARIANT prop;
};
using device_enum_t = util::safe_ptr<IMMDeviceEnumerator, Release<IMMDeviceEnumerator>>;
using collection_t = util::safe_ptr<IMMDeviceCollection, Release<IMMDeviceCollection>>;
using prop_t = util::safe_ptr<IPropertyStore, Release<IPropertyStore>>;
using device_t = util::safe_ptr<IMMDevice, Release<IMMDevice>>;
using audio_client_t = util::safe_ptr<IAudioClient, Release<IAudioClient>>;
using audio_capture_t = util::safe_ptr<IAudioCaptureClient, Release<IAudioCaptureClient>>;
using wave_format_t = util::safe_ptr<WAVEFORMATEX, co_task_free<WAVEFORMATEX>>;
const wchar_t *no_null(const wchar_t *str) {
return str ? str : L"Unknown";
}
using wstring_t = util::safe_ptr<WCHAR, co_task_free<WCHAR>>;
struct format_t {
std::string_view name;
int channels;
int channel_mask;
} formats[] {
{ "Mono"sv,
1,
SPEAKER_FRONT_CENTER },
{ "Stereo"sv,
2,
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT },
{ "Surround 5.1"sv,
6,
SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT },
{ "Surround 7.1"sv,
8,
SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT }
};
using handle_t = util::safe_ptr_v2<void, BOOL, CloseHandle>;
void set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nChannels = format.channels;
wave_format->nBlockAlign = wave_format->nChannels * wave_format->wBitsPerSample / 8;
wave_format->nAvgBytesPerSec = wave_format->nSamplesPerSec * wave_format->nBlockAlign;
if(wave_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
((PWAVEFORMATEXTENSIBLE)wave_format.get())->dwChannelMask = format.channel_mask;
}
}
audio_client_t make_audio_client(device_t &device, const format_t &format) {
audio_client_t audio_client;
auto status = device->Activate(
IID_IAudioClient,
CLSCTX_ALL,
nullptr,
(void **)&audio_client);
if(FAILED(status)) {
std::cout << "Couldn't activate Device: [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return nullptr;
}
wave_format_t wave_format;
status = audio_client->GetMixFormat(&wave_format);
if(FAILED(status)) {
std::cout << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return nullptr;
}
wave_format->wBitsPerSample = 16;
wave_format->nSamplesPerSec = SAMPLE_RATE;
switch(wave_format->wFormatTag) {
case WAVE_FORMAT_PCM:
break;
case WAVE_FORMAT_IEEE_FLOAT:
break;
case WAVE_FORMAT_EXTENSIBLE: {
auto wave_ex = (PWAVEFORMATEXTENSIBLE)wave_format.get();
if(IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, wave_ex->SubFormat)) {
wave_ex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
wave_ex->Samples.wValidBitsPerSample = 16;
break;
class prop_var_t {
public:
prop_var_t() {
PropVariantInit(&prop);
}
std::cout << "Unsupported Sub Format for WAVE_FORMAT_EXTENSIBLE: [0x"sv << util::hex(wave_ex->SubFormat).to_string_view() << ']' << std::endl;
}
default:
std::cout << "Unsupported Wave Format: [0x"sv << util::hex(wave_format->wFormatTag).to_string_view() << ']' << std::endl;
return nullptr;
~prop_var_t() {
PropVariantClear(&prop);
}
PROPVARIANT prop;
};
set_wave_format(wave_format, format);
status = audio_client->Initialize(
AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0,
wave_format.get(),
nullptr);
if(status) {
return nullptr;
const wchar_t *
no_null(const wchar_t *str) {
return str ? str : L"Unknown";
}
return audio_client;
}
struct format_t {
std::string_view name;
int channels;
int channel_mask;
} formats[] {
{ "Mono"sv,
1,
SPEAKER_FRONT_CENTER },
{ "Stereo"sv,
2,
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT },
{ "Surround 5.1"sv,
6,
SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT },
{ "Surround 7.1"sv,
8,
SPEAKER_FRONT_LEFT |
SPEAKER_FRONT_RIGHT |
SPEAKER_FRONT_CENTER |
SPEAKER_LOW_FREQUENCY |
SPEAKER_BACK_LEFT |
SPEAKER_BACK_RIGHT |
SPEAKER_SIDE_LEFT |
SPEAKER_SIDE_RIGHT }
};
void print_device(device_t &device) {
audio::wstring_t wstring;
DWORD device_state;
void
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nChannels = format.channels;
wave_format->nBlockAlign = wave_format->nChannels * wave_format->wBitsPerSample / 8;
wave_format->nAvgBytesPerSec = wave_format->nSamplesPerSec * wave_format->nBlockAlign;
device->GetState(&device_state);
device->GetId(&wstring);
audio::prop_t prop;
device->OpenPropertyStore(STGM_READ, &prop);
prop_var_t adapter_friendly_name;
prop_var_t device_friendly_name;
prop_var_t device_desc;
prop->GetValue(PKEY_Device_FriendlyName, &device_friendly_name.prop);
prop->GetValue(PKEY_DeviceInterface_FriendlyName, &adapter_friendly_name.prop);
prop->GetValue(PKEY_Device_DeviceDesc, &device_desc.prop);
if(!(device_state & device_state_filter)) {
return;
if (wave_format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
((PWAVEFORMATEXTENSIBLE) wave_format.get())->dwChannelMask = format.channel_mask;
}
}
std::wstring device_state_string = L"Unknown"s;
switch(device_state) {
case DEVICE_STATE_ACTIVE:
device_state_string = L"Active"s;
break;
case DEVICE_STATE_DISABLED:
device_state_string = L"Disabled"s;
break;
case DEVICE_STATE_UNPLUGGED:
device_state_string = L"Unplugged"s;
break;
case DEVICE_STATE_NOTPRESENT:
device_state_string = L"Not present"s;
break;
audio_client_t
make_audio_client(device_t &device, const format_t &format) {
audio_client_t audio_client;
auto status = device->Activate(
IID_IAudioClient,
CLSCTX_ALL,
nullptr,
(void **) &audio_client);
if (FAILED(status)) {
std::cout << "Couldn't activate Device: [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return nullptr;
}
wave_format_t wave_format;
status = audio_client->GetMixFormat(&wave_format);
if (FAILED(status)) {
std::cout << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return nullptr;
}
wave_format->wBitsPerSample = 16;
wave_format->nSamplesPerSec = SAMPLE_RATE;
switch (wave_format->wFormatTag) {
case WAVE_FORMAT_PCM:
break;
case WAVE_FORMAT_IEEE_FLOAT:
break;
case WAVE_FORMAT_EXTENSIBLE: {
auto wave_ex = (PWAVEFORMATEXTENSIBLE) wave_format.get();
if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, wave_ex->SubFormat)) {
wave_ex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
wave_ex->Samples.wValidBitsPerSample = 16;
break;
}
std::cout << "Unsupported Sub Format for WAVE_FORMAT_EXTENSIBLE: [0x"sv << util::hex(wave_ex->SubFormat).to_string_view() << ']' << std::endl;
}
default:
std::cout << "Unsupported Wave Format: [0x"sv << util::hex(wave_format->wFormatTag).to_string_view() << ']' << std::endl;
return nullptr;
};
set_wave_format(wave_format, format);
status = audio_client->Initialize(
AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0,
wave_format.get(),
nullptr);
if (status) {
return nullptr;
}
return audio_client;
}
std::wcout
<< L"===== Device ====="sv << std::endl
<< L"Device ID : "sv << wstring.get() << std::endl
<< L"Device name : "sv << no_null((LPWSTR)device_friendly_name.prop.pszVal) << std::endl
<< L"Adapter name : "sv << no_null((LPWSTR)adapter_friendly_name.prop.pszVal) << std::endl
<< L"Device description : "sv << no_null((LPWSTR)device_desc.prop.pszVal) << std::endl
<< L"Device state : "sv << device_state_string << std::endl
<< std::endl;
void
print_device(device_t &device) {
audio::wstring_t wstring;
DWORD device_state;
if(device_state != DEVICE_STATE_ACTIVE) {
return;
device->GetState(&device_state);
device->GetId(&wstring);
audio::prop_t prop;
device->OpenPropertyStore(STGM_READ, &prop);
prop_var_t adapter_friendly_name;
prop_var_t device_friendly_name;
prop_var_t device_desc;
prop->GetValue(PKEY_Device_FriendlyName, &device_friendly_name.prop);
prop->GetValue(PKEY_DeviceInterface_FriendlyName, &adapter_friendly_name.prop);
prop->GetValue(PKEY_Device_DeviceDesc, &device_desc.prop);
if (!(device_state & device_state_filter)) {
return;
}
std::wstring device_state_string = L"Unknown"s;
switch (device_state) {
case DEVICE_STATE_ACTIVE:
device_state_string = L"Active"s;
break;
case DEVICE_STATE_DISABLED:
device_state_string = L"Disabled"s;
break;
case DEVICE_STATE_UNPLUGGED:
device_state_string = L"Unplugged"s;
break;
case DEVICE_STATE_NOTPRESENT:
device_state_string = L"Not present"s;
break;
}
std::wcout
<< L"===== Device ====="sv << std::endl
<< L"Device ID : "sv << wstring.get() << std::endl
<< L"Device name : "sv << no_null((LPWSTR) device_friendly_name.prop.pszVal) << std::endl
<< L"Adapter name : "sv << no_null((LPWSTR) adapter_friendly_name.prop.pszVal) << std::endl
<< L"Device description : "sv << no_null((LPWSTR) device_desc.prop.pszVal) << std::endl
<< L"Device state : "sv << device_state_string << std::endl
<< std::endl;
if (device_state != DEVICE_STATE_ACTIVE) {
return;
}
for (const auto &format : formats) {
// Ensure WaveFromat is compatible
auto audio_client = make_audio_client(device, format);
std::cout << format.name << ": "sv << (!audio_client ? "unsupported"sv : "supported"sv) << std::endl;
}
}
} // namespace audio
for(const auto &format : formats) {
// Ensure WaveFromat is compatible
auto audio_client = make_audio_client(device, format);
std::cout << format.name << ": "sv << (!audio_client ? "unsupported"sv : "supported"sv) << std::endl;
}
}
} // namespace audio
void print_help() {
void
print_help() {
std::cout
<< "==== Help ===="sv << std::endl
<< "Usage:"sv << std::endl
<< " audio-info [Active|Disabled|Unplugged|Not-Present]" << std::endl;
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[]) {
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY);
auto fg = util::fail_guard([]() {
CoUninitialize();
});
if(argc > 1) {
if (argc > 1) {
device_state_filter = 0;
}
for(auto x = 1; x < argc; ++x) {
for(auto p = argv[x]; *p != '\0'; ++p) {
if(*p == ' ') {
for (auto x = 1; x < argc; ++x) {
for (auto p = argv[x]; *p != '\0'; ++p) {
if (*p == ' ') {
*p = '-';
continue;
@ -260,16 +268,16 @@ int main(int argc, char *argv[]) {
*p = std::tolower(*p);
}
if(argv[x] == "active"sv) {
if (argv[x] == "active"sv) {
device_state_filter |= DEVICE_STATE_ACTIVE;
}
else if(argv[x] == "disabled"sv) {
else if (argv[x] == "disabled"sv) {
device_state_filter |= DEVICE_STATE_DISABLED;
}
else if(argv[x] == "unplugged"sv) {
else if (argv[x] == "unplugged"sv) {
device_state_filter |= DEVICE_STATE_UNPLUGGED;
}
else if(argv[x] == "not-present"sv) {
else if (argv[x] == "not-present"sv) {
device_state_filter |= DEVICE_STATE_NOTPRESENT;
}
else {
@ -286,9 +294,9 @@ int main(int argc, char *argv[]) {
nullptr,
CLSCTX_ALL,
IID_IMMDeviceEnumerator,
(void **)&device_enum);
(void **) &device_enum);
if(FAILED(status)) {
if (FAILED(status)) {
std::cout << "Couldn't create Device Enumerator: [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return -1;
@ -297,7 +305,7 @@ int main(int argc, char *argv[]) {
audio::collection_t collection;
status = device_enum->EnumAudioEndpoints(eRender, device_state_filter, &collection);
if(FAILED(status)) {
if (FAILED(status)) {
std::cout << "Couldn't enumerate: [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return -1;
@ -307,7 +315,7 @@ int main(int argc, char *argv[]) {
collection->GetCount(&count);
std::cout << "====== Found "sv << count << " audio devices ======"sv << std::endl;
for(auto x = 0; x < count; ++x) {
for (auto x = 0; x < count; ++x) {
audio::device_t device;
collection->Item(x, &device);

View file

@ -10,21 +10,23 @@
using namespace std::literals;
namespace dxgi {
template<class T>
void Release(T *dxgi) {
dxgi->Release();
}
template <class T>
void
Release(T *dxgi) {
dxgi->Release();
}
using factory1_t = util::safe_ptr<IDXGIFactory1, Release<IDXGIFactory1>>;
using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter1>>;
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
using output1_t = util::safe_ptr<IDXGIOutput1, Release<IDXGIOutput1>>;
using device_t = util::safe_ptr<ID3D11Device, Release<ID3D11Device>>;
using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDuplication>>;
using factory1_t = util::safe_ptr<IDXGIFactory1, Release<IDXGIFactory1>>;
using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter1>>;
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
using output1_t = util::safe_ptr<IDXGIOutput1, Release<IDXGIOutput1>>;
using device_t = util::safe_ptr<ID3D11Device, Release<ID3D11Device>>;
using dup_t = util::safe_ptr<IDXGIOutputDuplication, Release<IDXGIOutputDuplication>>;
} // namespace dxgi
} // namespace dxgi
LSTATUS set_gpu_preference(int preference) {
LSTATUS
set_gpu_preference(int preference) {
// The GPU preferences key uses app path as the value name.
WCHAR executable_path[MAX_PATH];
GetModuleFileNameW(NULL, executable_path, ARRAYSIZE(executable_path));
@ -38,7 +40,7 @@ LSTATUS set_gpu_preference(int preference) {
REG_SZ,
value_data,
(wcslen(value_data) + 1) * sizeof(WCHAR));
if(status != ERROR_SUCCESS) {
if (status != ERROR_SUCCESS) {
std::cout << "Failed to set GPU preference: "sv << status << std::endl;
return status;
}
@ -46,7 +48,8 @@ LSTATUS set_gpu_preference(int preference) {
return ERROR_SUCCESS;
}
HRESULT test_dxgi_duplication(dxgi::adapter_t &adapter, dxgi::output_t &output) {
HRESULT
test_dxgi_duplication(dxgi::adapter_t &adapter, dxgi::output_t &output) {
D3D_FEATURE_LEVEL featureLevels[] {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
@ -68,41 +71,42 @@ HRESULT test_dxgi_duplication(dxgi::adapter_t &adapter, dxgi::output_t &output)
&device,
nullptr,
nullptr);
if(FAILED(status)) {
if (FAILED(status)) {
std::cout << "Failed to create D3D11 device for DD test [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return status;
}
dxgi::output1_t output1;
status = output->QueryInterface(IID_IDXGIOutput1, (void **)&output1);
if(FAILED(status)) {
status = output->QueryInterface(IID_IDXGIOutput1, (void **) &output1);
if (FAILED(status)) {
std::cout << "Failed to query IDXGIOutput1 from the output"sv << std::endl;
return status;
}
// Return the result of DuplicateOutput() to Sunshine
dxgi::dup_t dup;
return output1->DuplicateOutput((IUnknown *)device.get(), &dup);
return output1->DuplicateOutput((IUnknown *) device.get(), &dup);
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[]) {
HRESULT status;
// Display name may be omitted
if(argc != 2 && argc != 3) {
if (argc != 2 && argc != 3) {
std::cout << "ddprobe.exe [GPU preference value] [display name]"sv << std::endl;
return -1;
}
std::wstring display_name;
if(argc == 3) {
if (argc == 3) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
display_name = converter.from_bytes(argv[2]);
}
// We must set the GPU preference before making any DXGI/D3D calls
status = set_gpu_preference(atoi(argv[1]));
if(status != ERROR_SUCCESS) {
if (status != ERROR_SUCCESS) {
return status;
}
@ -117,30 +121,30 @@ int main(int argc, char *argv[]) {
});
dxgi::factory1_t factory;
status = CreateDXGIFactory1(IID_IDXGIFactory1, (void **)&factory);
if(FAILED(status)) {
status = CreateDXGIFactory1(IID_IDXGIFactory1, (void **) &factory);
if (FAILED(status)) {
std::cout << "Failed to create DXGIFactory1 [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return status;
}
dxgi::adapter_t::pointer adapter_p {};
for(int x = 0; factory->EnumAdapters1(x, &adapter_p) != DXGI_ERROR_NOT_FOUND; ++x) {
for (int x = 0; factory->EnumAdapters1(x, &adapter_p) != DXGI_ERROR_NOT_FOUND; ++x) {
dxgi::adapter_t adapter { adapter_p };
dxgi::output_t::pointer output_p {};
for(int y = 0; adapter->EnumOutputs(y, &output_p) != DXGI_ERROR_NOT_FOUND; ++y) {
for (int y = 0; adapter->EnumOutputs(y, &output_p) != DXGI_ERROR_NOT_FOUND; ++y) {
dxgi::output_t output { output_p };
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
// If a display name was specified and this one doesn't match, skip it
if(!display_name.empty() && desc.DeviceName != display_name) {
if (!display_name.empty() && desc.DeviceName != display_name) {
continue;
}
// If this display is not part of the desktop, we definitely can't capture it
if(!desc.AttachedToDesktop) {
if (!desc.AttachedToDesktop) {
continue;
}

View file

@ -11,30 +11,32 @@
using namespace std::literals;
namespace dxgi {
template<class T>
void Release(T *dxgi) {
dxgi->Release();
}
template <class T>
void
Release(T *dxgi) {
dxgi->Release();
}
using factory1_t = util::safe_ptr<IDXGIFactory1, Release<IDXGIFactory1>>;
using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter1>>;
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
using factory1_t = util::safe_ptr<IDXGIFactory1, Release<IDXGIFactory1>>;
using adapter_t = util::safe_ptr<IDXGIAdapter1, Release<IDXGIAdapter1>>;
using output_t = util::safe_ptr<IDXGIOutput, Release<IDXGIOutput>>;
} // namespace dxgi
} // namespace dxgi
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[]) {
HRESULT status;
dxgi::factory1_t::pointer factory_p {};
status = CreateDXGIFactory1(IID_IDXGIFactory1, (void **)&factory_p);
status = CreateDXGIFactory1(IID_IDXGIFactory1, (void **) &factory_p);
dxgi::factory1_t factory { factory_p };
if(FAILED(status)) {
if (FAILED(status)) {
std::cout << "Failed to create DXGIFactory1 [0x"sv << util::hex(status).to_string_view() << ']' << std::endl;
return -1;
}
dxgi::adapter_t::pointer adapter_p {};
for(int x = 0; factory->EnumAdapters1(x, &adapter_p) != DXGI_ERROR_NOT_FOUND; ++x) {
for (int x = 0; factory->EnumAdapters1(x, &adapter_p) != DXGI_ERROR_NOT_FOUND; ++x) {
dxgi::adapter_t adapter { adapter_p };
DXGI_ADAPTER_DESC1 adapter_desc;
@ -54,13 +56,13 @@ int main(int argc, char *argv[]) {
<< " ====== OUTPUT ======"sv << std::endl;
dxgi::output_t::pointer output_p {};
for(int y = 0; adapter->EnumOutputs(y, &output_p) != DXGI_ERROR_NOT_FOUND; ++y) {
for (int y = 0; adapter->EnumOutputs(y, &output_p) != DXGI_ERROR_NOT_FOUND; ++y) {
dxgi::output_t output { output_p };
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
auto width = desc.DesktopCoordinates.right - desc.DesktopCoordinates.left;
auto width = desc.DesktopCoordinates.right - desc.DesktopCoordinates.left;
auto height = desc.DesktopCoordinates.bottom - desc.DesktopCoordinates.top;
std::wcout

View file

@ -19,9 +19,10 @@
* To run a command, such as 'ipconfig /flushdns', with administrative privileges, execute:
* elevator.exe cmd /C "ipconfig /flushdns"
*/
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[]) {
// Check if the user provided at least one argument (the command to run)
if(argc < 2) {
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <command> [arguments]" << std::endl;
return 1;
}
@ -31,23 +32,23 @@ int main(int argc, char *argv[]) {
std::wstring arguments;
// Concatenate the remaining arguments (if any) into a single wstring
for(int i = 2; i < argc; ++i) {
for (int i = 2; i < argc; ++i) {
arguments += std::wstring(argv[i], argv[i] + strlen(argv[i]));
if(i < argc - 1) {
if (i < argc - 1) {
arguments += L" ";
}
}
// Prepare the SHELLEXECUTEINFOW structure with the necessary information
SHELLEXECUTEINFOW info = { sizeof(SHELLEXECUTEINFOW) };
info.lpVerb = L"runas"; // Request elevation
info.lpFile = command.c_str();
info.lpParameters = arguments.empty() ? nullptr : arguments.c_str();
info.nShow = SW_SHOW;
info.fMask = SEE_MASK_NOCLOSEPROCESS; // So we can wait for the process to finish
info.lpVerb = L"runas"; // Request elevation
info.lpFile = command.c_str();
info.lpParameters = arguments.empty() ? nullptr : arguments.c_str();
info.nShow = SW_SHOW;
info.fMask = SEE_MASK_NOCLOSEPROCESS; // So we can wait for the process to finish
// Attempt to execute the command with elevation
if(!ShellExecuteExW(&info)) {
if (!ShellExecuteExW(&info)) {
std::cout << "Error: ShellExecuteExW failed with code " << GetLastError() << std::endl;
return 1;
}
@ -58,7 +59,7 @@ int main(int argc, char *argv[]) {
DWORD exitCode = 0;
// Retrieve the exit code of the launched process
if(!GetExitCodeProcess(info.hProcess, &exitCode)) {
if (!GetExitCodeProcess(info.hProcess, &exitCode)) {
std::cout << "Error: GetExitCodeProcess failed with code " << GetLastError() << std::endl;
}

View file

@ -6,7 +6,7 @@
// PROC_THREAD_ATTRIBUTE_JOB_LIST is currently missing from MinGW headers
#ifndef PROC_THREAD_ATTRIBUTE_JOB_LIST
#define PROC_THREAD_ATTRIBUTE_JOB_LIST ProcThreadAttributeValue(13, FALSE, TRUE, FALSE)
#define PROC_THREAD_ATTRIBUTE_JOB_LIST ProcThreadAttributeValue(13, FALSE, TRUE, FALSE)
#endif
SERVICE_STATUS_HANDLE service_status_handle;
@ -15,32 +15,34 @@ HANDLE stop_event;
#define SERVICE_NAME "SunshineSvc"
DWORD WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) {
switch(dwControl) {
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
DWORD WINAPI
HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) {
switch (dwControl) {
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
case SERVICE_CONTROL_PRESHUTDOWN:
// The system is shutting down
case SERVICE_CONTROL_STOP:
// Let SCM know we're stopping in up to 30 seconds
service_status.dwCurrentState = SERVICE_STOP_PENDING;
service_status.dwControlsAccepted = 0;
service_status.dwWaitHint = 30 * 1000;
SetServiceStatus(service_status_handle, &service_status);
case SERVICE_CONTROL_PRESHUTDOWN:
// The system is shutting down
case SERVICE_CONTROL_STOP:
// Let SCM know we're stopping in up to 30 seconds
service_status.dwCurrentState = SERVICE_STOP_PENDING;
service_status.dwControlsAccepted = 0;
service_status.dwWaitHint = 30 * 1000;
SetServiceStatus(service_status_handle, &service_status);
// Trigger ServiceMain() to start cleanup
SetEvent(stop_event);
return NO_ERROR;
// Trigger ServiceMain() to start cleanup
SetEvent(stop_event);
return NO_ERROR;
default:
return NO_ERROR;
default:
return NO_ERROR;
}
}
HANDLE CreateJobObjectForChildProcess() {
HANDLE
CreateJobObjectForChildProcess() {
HANDLE job_handle = CreateJobObjectW(NULL, NULL);
if(!job_handle) {
if (!job_handle) {
return NULL;
}
@ -54,7 +56,7 @@ HANDLE CreateJobObjectForChildProcess() {
// the lifetime of SunshineSvc.exe. This avoids unexpected user data loss if we crash or are killed.
job_limit_info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
if(!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &job_limit_info, sizeof(job_limit_info))) {
if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &job_limit_info, sizeof(job_limit_info))) {
CloseHandle(job_handle);
return NULL;
}
@ -62,16 +64,17 @@ HANDLE CreateJobObjectForChildProcess() {
return job_handle;
}
LPPROC_THREAD_ATTRIBUTE_LIST AllocateProcThreadAttributeList(DWORD attribute_count) {
LPPROC_THREAD_ATTRIBUTE_LIST
AllocateProcThreadAttributeList(DWORD attribute_count) {
SIZE_T size;
InitializeProcThreadAttributeList(NULL, attribute_count, 0, &size);
auto list = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, size);
if(list == NULL) {
auto list = (LPPROC_THREAD_ATTRIBUTE_LIST) HeapAlloc(GetProcessHeap(), 0, size);
if (list == NULL) {
return NULL;
}
if(!InitializeProcThreadAttributeList(list, attribute_count, 0, &size)) {
if (!InitializeProcThreadAttributeList(list, attribute_count, 0, &size)) {
HeapFree(GetProcessHeap(), 0, list);
return NULL;
}
@ -79,21 +82,22 @@ LPPROC_THREAD_ATTRIBUTE_LIST AllocateProcThreadAttributeList(DWORD attribute_cou
return list;
}
HANDLE DuplicateTokenForConsoleSession() {
HANDLE
DuplicateTokenForConsoleSession() {
auto console_session_id = WTSGetActiveConsoleSessionId();
if(console_session_id == 0xFFFFFFFF) {
if (console_session_id == 0xFFFFFFFF) {
// No console session yet
return NULL;
}
HANDLE current_token;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &current_token)) {
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &current_token)) {
return NULL;
}
// Duplicate our own LocalSystem token
HANDLE new_token;
if(!DuplicateTokenEx(current_token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &new_token)) {
if (!DuplicateTokenEx(current_token, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &new_token)) {
CloseHandle(current_token);
return NULL;
}
@ -101,7 +105,7 @@ HANDLE DuplicateTokenForConsoleSession() {
CloseHandle(current_token);
// Change the duplicated token to the console session ID
if(!SetTokenInformation(new_token, TokenSessionId, &console_session_id, sizeof(console_session_id))) {
if (!SetTokenInformation(new_token, TokenSessionId, &console_session_id, sizeof(console_session_id))) {
CloseHandle(new_token);
return NULL;
}
@ -109,7 +113,8 @@ HANDLE DuplicateTokenForConsoleSession() {
return new_token;
}
HANDLE OpenLogFileHandle() {
HANDLE
OpenLogFileHandle() {
WCHAR log_file_name[MAX_PATH];
// Create sunshine.log in the Temp folder (usually %SYSTEMROOT%\Temp)
@ -129,7 +134,8 @@ HANDLE OpenLogFileHandle() {
NULL);
}
bool RunTerminationHelper(HANDLE console_token, DWORD pid) {
bool
RunTerminationHelper(HANDLE console_token, DWORD pid) {
WCHAR module_path[MAX_PATH];
GetModuleFileNameW(NULL, module_path, _countof(module_path));
std::wstring command { module_path };
@ -137,23 +143,23 @@ bool RunTerminationHelper(HANDLE console_token, DWORD pid) {
command += L" --terminate " + std::to_wstring(pid);
STARTUPINFOW startup_info = {};
startup_info.cb = sizeof(startup_info);
startup_info.lpDesktop = (LPWSTR)L"winsta0\\default";
startup_info.cb = sizeof(startup_info);
startup_info.lpDesktop = (LPWSTR) L"winsta0\\default";
// Execute ourselves as a detached process in the user session with the --terminate argument.
// This will allow us to attach to Sunshine's console and send it a Ctrl-C event.
PROCESS_INFORMATION process_info;
if(!CreateProcessAsUserW(console_token,
NULL,
(LPWSTR)command.c_str(),
NULL,
NULL,
FALSE,
CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS,
NULL,
NULL,
&startup_info,
&process_info)) {
if (!CreateProcessAsUserW(console_token,
NULL,
(LPWSTR) command.c_str(),
NULL,
NULL,
FALSE,
CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS,
NULL,
NULL,
&startup_info,
&process_info)) {
return false;
}
@ -172,57 +178,58 @@ bool RunTerminationHelper(HANDLE console_token, DWORD pid) {
return exit_code == 0;
}
VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
VOID WINAPI
ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
service_status_handle = RegisterServiceCtrlHandlerEx(SERVICE_NAME, HandlerEx, NULL);
if(service_status_handle == NULL) {
if (service_status_handle == NULL) {
// Nothing we can really do here but terminate ourselves
ExitProcess(GetLastError());
return;
}
// Tell SCM we're starting
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
service_status.dwServiceSpecificExitCode = 0;
service_status.dwWin32ExitCode = NO_ERROR;
service_status.dwWaitHint = 0;
service_status.dwControlsAccepted = 0;
service_status.dwCheckPoint = 0;
service_status.dwCurrentState = SERVICE_START_PENDING;
service_status.dwWin32ExitCode = NO_ERROR;
service_status.dwWaitHint = 0;
service_status.dwControlsAccepted = 0;
service_status.dwCheckPoint = 0;
service_status.dwCurrentState = SERVICE_START_PENDING;
SetServiceStatus(service_status_handle, &service_status);
stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
if(stop_event == NULL) {
if (stop_event == NULL) {
// Tell SCM we failed to start
service_status.dwWin32ExitCode = GetLastError();
service_status.dwCurrentState = SERVICE_STOPPED;
service_status.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(service_status_handle, &service_status);
return;
}
auto log_file_handle = OpenLogFileHandle();
if(log_file_handle == INVALID_HANDLE_VALUE) {
if (log_file_handle == INVALID_HANDLE_VALUE) {
// Tell SCM we failed to start
service_status.dwWin32ExitCode = GetLastError();
service_status.dwCurrentState = SERVICE_STOPPED;
service_status.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(service_status_handle, &service_status);
return;
}
// We can use a single STARTUPINFOEXW for all the processes that we launch
STARTUPINFOEXW startup_info = {};
startup_info.StartupInfo.cb = sizeof(startup_info);
startup_info.StartupInfo.lpDesktop = (LPWSTR)L"winsta0\\default";
startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
startup_info.StartupInfo.hStdInput = NULL;
STARTUPINFOEXW startup_info = {};
startup_info.StartupInfo.cb = sizeof(startup_info);
startup_info.StartupInfo.lpDesktop = (LPWSTR) L"winsta0\\default";
startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES;
startup_info.StartupInfo.hStdInput = NULL;
startup_info.StartupInfo.hStdOutput = log_file_handle;
startup_info.StartupInfo.hStdError = log_file_handle;
startup_info.StartupInfo.hStdError = log_file_handle;
// Allocate an attribute list with space for 2 entries
startup_info.lpAttributeList = AllocateProcThreadAttributeList(2);
if(startup_info.lpAttributeList == NULL) {
if (startup_info.lpAttributeList == NULL) {
// Tell SCM we failed to start
service_status.dwWin32ExitCode = GetLastError();
service_status.dwCurrentState = SERVICE_STOPPED;
service_status.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(service_status_handle, &service_status);
return;
}
@ -238,19 +245,19 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
// Tell SCM we're running (and stoppable now)
service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
service_status.dwCurrentState = SERVICE_RUNNING;
service_status.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(service_status_handle, &service_status);
// Loop every 3 seconds until the stop event is set or Sunshine.exe is running
while(WaitForSingleObject(stop_event, 3000) != WAIT_OBJECT_0) {
while (WaitForSingleObject(stop_event, 3000) != WAIT_OBJECT_0) {
auto console_token = DuplicateTokenForConsoleSession();
if(console_token == NULL) {
if (console_token == NULL) {
continue;
}
// Job objects cannot span sessions, so we must create one for each process
auto job_handle = CreateJobObjectForChildProcess();
if(job_handle == NULL) {
if (job_handle == NULL) {
CloseHandle(console_token);
continue;
}
@ -265,17 +272,17 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
NULL);
PROCESS_INFORMATION process_info;
if(!CreateProcessAsUserW(console_token,
L"Sunshine.exe",
NULL,
NULL,
NULL,
TRUE,
CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
(LPSTARTUPINFOW)&startup_info,
&process_info)) {
if (!CreateProcessAsUserW(console_token,
L"Sunshine.exe",
NULL,
NULL,
NULL,
TRUE,
CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
(LPSTARTUPINFOW) &startup_info,
&process_info)) {
CloseHandle(console_token);
CloseHandle(job_handle);
continue;
@ -283,20 +290,20 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
// Wait for either the stop event to be set or Sunshine.exe to terminate
const HANDLE wait_objects[] = { stop_event, process_info.hProcess };
switch(WaitForMultipleObjects(_countof(wait_objects), wait_objects, FALSE, INFINITE)) {
case WAIT_OBJECT_0:
// The service is shutting down, so try to gracefully terminate Sunshine.exe.
// If it doesn't terminate in 20 seconds, we will forcefully terminate it.
if(!RunTerminationHelper(console_token, process_info.dwProcessId) ||
WaitForSingleObject(process_info.hProcess, 20000) != WAIT_OBJECT_0) {
// If it won't terminate gracefully, kill it now
TerminateProcess(process_info.hProcess, ERROR_PROCESS_ABORTED);
}
break;
switch (WaitForMultipleObjects(_countof(wait_objects), wait_objects, FALSE, INFINITE)) {
case WAIT_OBJECT_0:
// The service is shutting down, so try to gracefully terminate Sunshine.exe.
// If it doesn't terminate in 20 seconds, we will forcefully terminate it.
if (!RunTerminationHelper(console_token, process_info.dwProcessId) ||
WaitForSingleObject(process_info.hProcess, 20000) != WAIT_OBJECT_0) {
// If it won't terminate gracefully, kill it now
TerminateProcess(process_info.hProcess, ERROR_PROCESS_ABORTED);
}
break;
case WAIT_OBJECT_0 + 1:
// Sunshine terminated itself.
break;
case WAIT_OBJECT_0 + 1:
// Sunshine terminated itself.
break;
}
CloseHandle(process_info.hThread);
@ -311,9 +318,10 @@ VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv) {
}
// This will run in a child process in the user session
int DoGracefulTermination(DWORD pid) {
int
DoGracefulTermination(DWORD pid) {
// Attach to Sunshine's console
if(!AttachConsole(pid)) {
if (!AttachConsole(pid)) {
return GetLastError();
}
@ -321,21 +329,22 @@ int DoGracefulTermination(DWORD pid) {
SetConsoleCtrlHandler(NULL, TRUE);
// Send a Ctrl-C event to Sunshine
if(!GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
return GetLastError();
}
return 0;
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[]) {
static const SERVICE_TABLE_ENTRY service_table[] = {
{ (LPSTR)SERVICE_NAME, ServiceMain },
{ (LPSTR) SERVICE_NAME, ServiceMain },
{ NULL, NULL }
};
// Check if this is a reinvocation of ourselves to send Ctrl-C to Sunshine.exe
if(argc == 3 && strcmp(argv[1], "--terminate") == 0) {
if (argc == 3 && strcmp(argv[1], "--terminate") == 0) {
return DoGracefulTermination(atol(argv[2]));
}
@ -344,9 +353,9 @@ int main(int argc, char *argv[]) {
// This requires stripping off 2 path components: the file name and the last folder
WCHAR module_path[MAX_PATH];
GetModuleFileNameW(NULL, module_path, _countof(module_path));
for(auto i = 0; i < 2; i++) {
for (auto i = 0; i < 2; i++) {
auto last_sep = wcsrchr(module_path, '\\');
if(last_sep) {
if (last_sep) {
*last_sep = 0;
}
}