Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion buildspec.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"displayName": "Elgato Marketplace Connect",
"versionMajor": 1,
"versionMinor": 0,
"versionPatch": 1,
"versionPatch": 2,
"buildNumber": 0,
"releaseType": "release",
"author": "Elgato",
Expand Down
3 changes: 3 additions & 0 deletions cmake/windows/helpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ function(set_target_properties_plugin target)

configure_file(cmake/windows/resources/resource.rc.in "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")
target_sources(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")

configure_file(cmake/windows/resources/elgato-marketplace-connect-loader.rc.in "${CMAKE_CURRENT_BINARY_DIR}/elgato-marketplace-connect-loader.rc")
target_sources(${CMAKE_PROJECT_NAME}-loader PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/elgato-marketplace-connect-loader.rc")
endfunction()

# Helper function to add resources into bundle
Expand Down
110 changes: 110 additions & 0 deletions cmake/windows/resources/elgato-marketplace-connect-loader.rc.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by elgato-marketplace-connect-loader.rc

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif


#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// English (United States) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE
BEGIN
"resource.h\0"
END

2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END

3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END

#endif // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Version
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0
PRODUCTVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "${PLUGIN_AUTHOR}"
VALUE "FileDescription", "Marketplace Connect for OBS"
VALUE "FileVersion", "${PROJECT_VERSION}"
VALUE "InternalName", "elgato-m.exe"
VALUE "LegalCopyright", "(C) ${CURRENT_YEAR} ${PLUGIN_AUTHOR}"
VALUE "OriginalFilename", "elgato-m.exe"
VALUE "ProductName", "Marketplace Connect for OBS"
VALUE "ProductVersion", "${PROJECT_VERSION}"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////

#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//

/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

101 changes: 83 additions & 18 deletions loader/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ DWORD GetProcessIdFromExe(const std::wstring& exeName) {
// Create a snapshot of all running processes
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
printf("Error taking snapshot of processes.");
std::cerr << "[ERROR]: Error taking snapshot of processes." << std::endl;
return 0;
}

Expand Down Expand Up @@ -100,17 +100,17 @@ int send_auth_to_obs(std::string payload) {
sa.bInheritHandle = FALSE;

int connect_attempts_remaining = 6;

std::cout << "Attempting to connect to Marketplace Connect Plugin" << std::flush;
while (connect_attempts_remaining-- > 0 &&
pipe == INVALID_HANDLE_VALUE) {
pipe_number = 0;
while (pipe_number < 10) {
attempt_name = base_name + std::to_string(pipe_number);
printf("Attempting %s\n", attempt_name.c_str());
std::cout << "." << std::flush;
pipe = CreateFileA(attempt_name.c_str(), GENERIC_WRITE,
0, &sa, OPEN_EXISTING, 0, NULL);
if (pipe != INVALID_HANDLE_VALUE) {
printf("Success\n");
std::cout << "\nSuccess" << std::endl;
break;
}
pipe_number++;
Expand All @@ -120,22 +120,82 @@ int send_auth_to_obs(std::string payload) {
}
}
if (pipe == INVALID_HANDLE_VALUE) {
printf("Could not open named pipe!");
std::cerr << "[ERROR] Could not find connection Marketplace Connect Plugin." << std::endl;
return 1;
}
DWORD mode = PIPE_READMODE_MESSAGE;
auto success = SetNamedPipeHandleState(pipe, &mode, NULL, NULL);
if (!success) {
CloseHandle(pipe);
printf("Could not configure named pipe!");
std::cerr << "[ERROR] Could not negotiate connection with Marketplace Connect Plugin." << std::endl;
return 1;
}

DWORD written = 0;
success = WriteFile(pipe, payload.c_str(), static_cast<DWORD>(payload.size()), &written,
NULL);
if (!success || written < payload.size()) {
printf("Failed to write to named pipe!");
std::cerr << "[ERROR] Could not send data to Marketplace Connect Plugin." << std::endl;
CloseHandle(pipe);
return 1;
}

CloseHandle(pipe);
return 0;
}

int open_obs_mp_window()
{
int pipe_number = 0;
std::string pipe_name = "elgato_cloud";
std::string base_name = "\\\\.\\pipe\\" + pipe_name;
std::string attempt_name;
HANDLE pipe = INVALID_HANDLE_VALUE;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;

int connect_attempts_remaining = 60;

std::cout << "Waiting for OBS to launch" << std::flush;

while (connect_attempts_remaining-- > 0 &&
pipe == INVALID_HANDLE_VALUE) {
pipe_number = 0;
attempt_name = base_name + std::to_string(pipe_number);
std::cout << "." << std::flush;
pipe = CreateFileA(attempt_name.c_str(), GENERIC_WRITE,
0, &sa, OPEN_EXISTING, 0, NULL);
if (pipe != INVALID_HANDLE_VALUE) {
std::cout << "\nConnected To OBS" << std::endl;
break;
}
if (pipe == INVALID_HANDLE_VALUE) {
Sleep(1000);
}
}
if (pipe == INVALID_HANDLE_VALUE) {
std::cerr << "[ERROR] Could not find connection Marketplace Connect Plugin." << std::endl;
return 1;
}
DWORD mode = PIPE_READMODE_MESSAGE;
auto success = SetNamedPipeHandleState(pipe, &mode, NULL, NULL);
if (!success) {
CloseHandle(pipe);
std::cerr << "[ERROR] Could not negotiate connection with Marketplace Connect Plugin." << std::endl;
return 1;
}

DWORD written = 0;
std::string payload = "elgatolink://open";
success = WriteFile(pipe, payload.c_str(), static_cast<DWORD>(payload.size()), &written,
NULL);
if (!success || written < payload.size()) {
std::cerr << "[ERROR] Could not send data to Marketplace Connect Plugin." << std::endl;
CloseHandle(pipe);
return 1;
}
Expand Down Expand Up @@ -169,12 +229,12 @@ int launch_obs()
STARTUPINFOW si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi;

printf("Try create %ls with %ls\n", launch_path.c_str(),
wd.c_str());
//printf("Try create %ls with %ls\n", launch_path.c_str(),
// wd.c_str());

//WCHAR lpCommandLine[] = L"";
if (CreateProcess(launch_path.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, wd.c_str(), &si, &pi) == 0) {
printf("Failed to launch OBS.");
std::cerr << "[ERROR] Failed to launch OBS." << std::endl;
return 1;
}

Expand All @@ -185,7 +245,7 @@ int launch_obs()
} else if (running) {
DWORD processId = GetProcessIdFromExe(L"obs64.exe");
if (processId == 0) {
printf("Process not found!");
std::cerr << "[ERROR] OBS appears to have quit." << std::endl;
return 1;
}
EnumWindows(WindowToForeground, processId);
Expand All @@ -198,26 +258,31 @@ bool obs_is_running(std::wstring name) {
if (!iswalnum(name[i]))
name[i] = L'_';
}

printf("CHECKING %ls\n", name.c_str());
HANDLE h = OpenMutexW(SYNCHRONIZE, false, name.c_str());
return !!h;
}

int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Please provide an argument");
std::cerr << "[ERROR] No argument provided." << std::endl;
system("pause");
return 1;
}
int resp;

std::string payload = argv[1];

if (payload.find("elgatolink://auth") == 0) {
// Send auth to OBS which requested it.
return send_auth_to_obs(payload);
resp = send_auth_to_obs(payload);
} else {
return launch_obs();
resp = launch_obs();
if(resp == 0) resp = open_obs_mp_window();
}

if (resp == 1) {
system("pause");
}
printf("No obs found to launch.");
return 1;

return resp;
}
51 changes: 51 additions & 0 deletions src/elgato-cloud-data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,41 @@ std::unique_lock<std::mutex> *GetElgatoCloudLoopLock()

ElgatoCloud::ElgatoCloud(obs_module_t *m)
{
_openOnLaunch = false;
_obsReady = false;
_modulePtr = m;
//_translate = t;
_securerand = QRandomGenerator::securelySeeded();
obs_frontend_add_event_callback(ElgatoCloud::FrontEndEventHandler, this);
_Initialize();
_Listen();
}

ElgatoCloud::~ElgatoCloud()
{
obs_frontend_remove_event_callback(ElgatoCloud::FrontEndEventHandler, this);
obs_data_release(_config);
}

void ElgatoCloud::FrontEndEventHandler(enum obs_frontend_event event, void* data)
{
auto ec = static_cast<ElgatoCloud*>(data);
switch (event) {
case OBS_FRONTEND_EVENT_FINISHED_LOADING:
ec->_obsReady = true;
if (ec->_openOnLaunch) {
ec->_openOnLaunch = false;
QMetaObject::invokeMethod(
QCoreApplication::instance()
->thread(),
[ec]() {
OpenElgatoCloudWindow();
});
}
break;
}
}

obs_data_t *ElgatoCloud::GetConfig()
{
obs_data_addref(_config);
Expand Down Expand Up @@ -169,6 +192,7 @@ void ElgatoCloud::_Listen()
{
_listenThread = std::thread([this]() {
listen_on_pipe("elgato_cloud", [this](std::string d) {
obs_log(LOG_INFO, "Pipe received: %s", d.c_str());
if (d.find("elgatolink://auth") == 0) {
if (mainWindowOpen && window) {
QMetaObject::invokeMethod(
Expand Down Expand Up @@ -242,6 +266,33 @@ void ElgatoCloud::_Listen()
authorizing = false;
return;
}
else if (d.find("elgatolink://open") == 0)
{
obs_log(LOG_INFO, "OPEN COMMAND RECEIEVED!");
if (!_obsReady) {
_openOnLaunch = true;
return;
}
if (mainWindowOpen && window) {
QMetaObject::invokeMethod(
QCoreApplication::instance()
->thread(),
[this]() {
//window->setLoading();
window->show();
window->raise();
window->activateWindow();
LoadPurchasedProducts();
});
} else {
QMetaObject::invokeMethod(
QCoreApplication::instance()
->thread(),
[this]() {
OpenElgatoCloudWindow();
});
}
}
});
});

Expand Down
Loading