Skip to content

Commit d6c7b4d

Browse files
Adds proper callback/monitoring of OBS for deeplinking launching OBS, opening owned products window, etc.. (#32)
* Adds proper callback/monitoring of OBS for deeplinking launching OBS, opening owned products window, etc.. * Adds handling of open command via pipe. * Adds more user friendly output for helper app, and does not automatically close if there is an issue. * Updates version to 1.0.2 * Adds friendly name to mp-connect-loader app.
1 parent c3f2732 commit d6c7b4d

File tree

6 files changed

+252
-19
lines changed

6 files changed

+252
-19
lines changed

buildspec.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"displayName": "Elgato Marketplace Connect",
4141
"versionMajor": 1,
4242
"versionMinor": 0,
43-
"versionPatch": 1,
43+
"versionPatch": 2,
4444
"buildNumber": 0,
4545
"releaseType": "release",
4646
"author": "Elgato",

cmake/windows/helpers.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ function(set_target_properties_plugin target)
6060

6161
configure_file(cmake/windows/resources/resource.rc.in "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")
6262
target_sources(${CMAKE_PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")
63+
64+
configure_file(cmake/windows/resources/elgato-marketplace-connect-loader.rc.in "${CMAKE_CURRENT_BINARY_DIR}/elgato-marketplace-connect-loader.rc")
65+
target_sources(${CMAKE_PROJECT_NAME}-loader PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/elgato-marketplace-connect-loader.rc")
6366
endfunction()
6467

6568
# Helper function to add resources into bundle
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Microsoft Visual C++ generated resource script.
2+
//
3+
//{{NO_DEPENDENCIES}}
4+
// Microsoft Visual C++ generated include file.
5+
// Used by elgato-marketplace-connect-loader.rc
6+
7+
// Next default values for new objects
8+
//
9+
#ifdef APSTUDIO_INVOKED
10+
#ifndef APSTUDIO_READONLY_SYMBOLS
11+
#define _APS_NEXT_RESOURCE_VALUE 101
12+
#define _APS_NEXT_COMMAND_VALUE 40001
13+
#define _APS_NEXT_CONTROL_VALUE 1001
14+
#define _APS_NEXT_SYMED_VALUE 101
15+
#endif
16+
#endif
17+
18+
19+
#define APSTUDIO_READONLY_SYMBOLS
20+
/////////////////////////////////////////////////////////////////////////////
21+
//
22+
// Generated from the TEXTINCLUDE 2 resource.
23+
//
24+
#include "winres.h"
25+
26+
/////////////////////////////////////////////////////////////////////////////
27+
#undef APSTUDIO_READONLY_SYMBOLS
28+
29+
/////////////////////////////////////////////////////////////////////////////
30+
// English (United States) resources
31+
32+
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
33+
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
34+
35+
#ifdef APSTUDIO_INVOKED
36+
/////////////////////////////////////////////////////////////////////////////
37+
//
38+
// TEXTINCLUDE
39+
//
40+
41+
1 TEXTINCLUDE
42+
BEGIN
43+
"resource.h\0"
44+
END
45+
46+
2 TEXTINCLUDE
47+
BEGIN
48+
"#include ""winres.h""\r\n"
49+
"\0"
50+
END
51+
52+
3 TEXTINCLUDE
53+
BEGIN
54+
"\r\n"
55+
"\0"
56+
END
57+
58+
#endif // APSTUDIO_INVOKED
59+
60+
61+
/////////////////////////////////////////////////////////////////////////////
62+
//
63+
// Version
64+
//
65+
66+
VS_VERSION_INFO VERSIONINFO
67+
FILEVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0
68+
PRODUCTVERSION ${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},0
69+
FILEFLAGSMASK 0x3fL
70+
#ifdef _DEBUG
71+
FILEFLAGS 0x1L
72+
#else
73+
FILEFLAGS 0x0L
74+
#endif
75+
FILEOS 0x40004L
76+
FILETYPE 0x1L
77+
FILESUBTYPE 0x0L
78+
BEGIN
79+
BLOCK "StringFileInfo"
80+
BEGIN
81+
BLOCK "040904b0"
82+
BEGIN
83+
VALUE "CompanyName", "${PLUGIN_AUTHOR}"
84+
VALUE "FileDescription", "Marketplace Connect for OBS"
85+
VALUE "FileVersion", "${PROJECT_VERSION}"
86+
VALUE "InternalName", "elgato-m.exe"
87+
VALUE "LegalCopyright", "(C) ${CURRENT_YEAR} ${PLUGIN_AUTHOR}"
88+
VALUE "OriginalFilename", "elgato-m.exe"
89+
VALUE "ProductName", "Marketplace Connect for OBS"
90+
VALUE "ProductVersion", "${PROJECT_VERSION}"
91+
END
92+
END
93+
BLOCK "VarFileInfo"
94+
BEGIN
95+
VALUE "Translation", 0x409, 1200
96+
END
97+
END
98+
99+
#endif // English (United States) resources
100+
/////////////////////////////////////////////////////////////////////////////
101+
102+
#ifndef APSTUDIO_INVOKED
103+
/////////////////////////////////////////////////////////////////////////////
104+
//
105+
// Generated from the TEXTINCLUDE 3 resource.
106+
//
107+
108+
/////////////////////////////////////////////////////////////////////////////
109+
#endif // not APSTUDIO_INVOKED
110+

loader/main.cpp

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ DWORD GetProcessIdFromExe(const std::wstring& exeName) {
4747
// Create a snapshot of all running processes
4848
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
4949
if (hSnapshot == INVALID_HANDLE_VALUE) {
50-
printf("Error taking snapshot of processes.");
50+
std::cerr << "[ERROR]: Error taking snapshot of processes." << std::endl;
5151
return 0;
5252
}
5353

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

102102
int connect_attempts_remaining = 6;
103-
103+
std::cout << "Attempting to connect to Marketplace Connect Plugin" << std::flush;
104104
while (connect_attempts_remaining-- > 0 &&
105105
pipe == INVALID_HANDLE_VALUE) {
106106
pipe_number = 0;
107107
while (pipe_number < 10) {
108108
attempt_name = base_name + std::to_string(pipe_number);
109-
printf("Attempting %s\n", attempt_name.c_str());
109+
std::cout << "." << std::flush;
110110
pipe = CreateFileA(attempt_name.c_str(), GENERIC_WRITE,
111111
0, &sa, OPEN_EXISTING, 0, NULL);
112112
if (pipe != INVALID_HANDLE_VALUE) {
113-
printf("Success\n");
113+
std::cout << "\nSuccess" << std::endl;
114114
break;
115115
}
116116
pipe_number++;
@@ -120,22 +120,82 @@ int send_auth_to_obs(std::string payload) {
120120
}
121121
}
122122
if (pipe == INVALID_HANDLE_VALUE) {
123-
printf("Could not open named pipe!");
123+
std::cerr << "[ERROR] Could not find connection Marketplace Connect Plugin." << std::endl;
124124
return 1;
125125
}
126126
DWORD mode = PIPE_READMODE_MESSAGE;
127127
auto success = SetNamedPipeHandleState(pipe, &mode, NULL, NULL);
128128
if (!success) {
129129
CloseHandle(pipe);
130-
printf("Could not configure named pipe!");
130+
std::cerr << "[ERROR] Could not negotiate connection with Marketplace Connect Plugin." << std::endl;
131131
return 1;
132132
}
133133

134134
DWORD written = 0;
135135
success = WriteFile(pipe, payload.c_str(), static_cast<DWORD>(payload.size()), &written,
136136
NULL);
137137
if (!success || written < payload.size()) {
138-
printf("Failed to write to named pipe!");
138+
std::cerr << "[ERROR] Could not send data to Marketplace Connect Plugin." << std::endl;
139+
CloseHandle(pipe);
140+
return 1;
141+
}
142+
143+
CloseHandle(pipe);
144+
return 0;
145+
}
146+
147+
int open_obs_mp_window()
148+
{
149+
int pipe_number = 0;
150+
std::string pipe_name = "elgato_cloud";
151+
std::string base_name = "\\\\.\\pipe\\" + pipe_name;
152+
std::string attempt_name;
153+
HANDLE pipe = INVALID_HANDLE_VALUE;
154+
SECURITY_ATTRIBUTES sa;
155+
SECURITY_DESCRIPTOR sd;
156+
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
157+
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
158+
sa.nLength = sizeof(sa);
159+
sa.lpSecurityDescriptor = &sd;
160+
sa.bInheritHandle = FALSE;
161+
162+
int connect_attempts_remaining = 60;
163+
164+
std::cout << "Waiting for OBS to launch" << std::flush;
165+
166+
while (connect_attempts_remaining-- > 0 &&
167+
pipe == INVALID_HANDLE_VALUE) {
168+
pipe_number = 0;
169+
attempt_name = base_name + std::to_string(pipe_number);
170+
std::cout << "." << std::flush;
171+
pipe = CreateFileA(attempt_name.c_str(), GENERIC_WRITE,
172+
0, &sa, OPEN_EXISTING, 0, NULL);
173+
if (pipe != INVALID_HANDLE_VALUE) {
174+
std::cout << "\nConnected To OBS" << std::endl;
175+
break;
176+
}
177+
if (pipe == INVALID_HANDLE_VALUE) {
178+
Sleep(1000);
179+
}
180+
}
181+
if (pipe == INVALID_HANDLE_VALUE) {
182+
std::cerr << "[ERROR] Could not find connection Marketplace Connect Plugin." << std::endl;
183+
return 1;
184+
}
185+
DWORD mode = PIPE_READMODE_MESSAGE;
186+
auto success = SetNamedPipeHandleState(pipe, &mode, NULL, NULL);
187+
if (!success) {
188+
CloseHandle(pipe);
189+
std::cerr << "[ERROR] Could not negotiate connection with Marketplace Connect Plugin." << std::endl;
190+
return 1;
191+
}
192+
193+
DWORD written = 0;
194+
std::string payload = "elgatolink://open";
195+
success = WriteFile(pipe, payload.c_str(), static_cast<DWORD>(payload.size()), &written,
196+
NULL);
197+
if (!success || written < payload.size()) {
198+
std::cerr << "[ERROR] Could not send data to Marketplace Connect Plugin." << std::endl;
139199
CloseHandle(pipe);
140200
return 1;
141201
}
@@ -169,12 +229,12 @@ int launch_obs()
169229
STARTUPINFOW si = { sizeof(STARTUPINFO) };
170230
PROCESS_INFORMATION pi;
171231

172-
printf("Try create %ls with %ls\n", launch_path.c_str(),
173-
wd.c_str());
232+
//printf("Try create %ls with %ls\n", launch_path.c_str(),
233+
// wd.c_str());
174234

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

@@ -185,7 +245,7 @@ int launch_obs()
185245
} else if (running) {
186246
DWORD processId = GetProcessIdFromExe(L"obs64.exe");
187247
if (processId == 0) {
188-
printf("Process not found!");
248+
std::cerr << "[ERROR] OBS appears to have quit." << std::endl;
189249
return 1;
190250
}
191251
EnumWindows(WindowToForeground, processId);
@@ -198,26 +258,31 @@ bool obs_is_running(std::wstring name) {
198258
if (!iswalnum(name[i]))
199259
name[i] = L'_';
200260
}
201-
202-
printf("CHECKING %ls\n", name.c_str());
203261
HANDLE h = OpenMutexW(SYNCHRONIZE, false, name.c_str());
204262
return !!h;
205263
}
206264

207265
int main(int argc, char *argv[]) {
208266
if (argc < 2) {
209-
printf("Please provide an argument");
267+
std::cerr << "[ERROR] No argument provided." << std::endl;
268+
system("pause");
210269
return 1;
211270
}
271+
int resp;
212272

213273
std::string payload = argv[1];
214274

215275
if (payload.find("elgatolink://auth") == 0) {
216276
// Send auth to OBS which requested it.
217-
return send_auth_to_obs(payload);
277+
resp = send_auth_to_obs(payload);
218278
} else {
219-
return launch_obs();
279+
resp = launch_obs();
280+
if(resp == 0) resp = open_obs_mp_window();
281+
}
282+
283+
if (resp == 1) {
284+
system("pause");
220285
}
221-
printf("No obs found to launch.");
222-
return 1;
286+
287+
return resp;
223288
}

src/elgato-cloud-data.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,18 +59,41 @@ std::unique_lock<std::mutex> *GetElgatoCloudLoopLock()
5959

6060
ElgatoCloud::ElgatoCloud(obs_module_t *m)
6161
{
62+
_openOnLaunch = false;
63+
_obsReady = false;
6264
_modulePtr = m;
6365
//_translate = t;
6466
_securerand = QRandomGenerator::securelySeeded();
67+
obs_frontend_add_event_callback(ElgatoCloud::FrontEndEventHandler, this);
6568
_Initialize();
6669
_Listen();
6770
}
6871

6972
ElgatoCloud::~ElgatoCloud()
7073
{
74+
obs_frontend_remove_event_callback(ElgatoCloud::FrontEndEventHandler, this);
7175
obs_data_release(_config);
7276
}
7377

78+
void ElgatoCloud::FrontEndEventHandler(enum obs_frontend_event event, void* data)
79+
{
80+
auto ec = static_cast<ElgatoCloud*>(data);
81+
switch (event) {
82+
case OBS_FRONTEND_EVENT_FINISHED_LOADING:
83+
ec->_obsReady = true;
84+
if (ec->_openOnLaunch) {
85+
ec->_openOnLaunch = false;
86+
QMetaObject::invokeMethod(
87+
QCoreApplication::instance()
88+
->thread(),
89+
[ec]() {
90+
OpenElgatoCloudWindow();
91+
});
92+
}
93+
break;
94+
}
95+
}
96+
7497
obs_data_t *ElgatoCloud::GetConfig()
7598
{
7699
obs_data_addref(_config);
@@ -169,6 +192,7 @@ void ElgatoCloud::_Listen()
169192
{
170193
_listenThread = std::thread([this]() {
171194
listen_on_pipe("elgato_cloud", [this](std::string d) {
195+
obs_log(LOG_INFO, "Pipe received: %s", d.c_str());
172196
if (d.find("elgatolink://auth") == 0) {
173197
if (mainWindowOpen && window) {
174198
QMetaObject::invokeMethod(
@@ -242,6 +266,33 @@ void ElgatoCloud::_Listen()
242266
authorizing = false;
243267
return;
244268
}
269+
else if (d.find("elgatolink://open") == 0)
270+
{
271+
obs_log(LOG_INFO, "OPEN COMMAND RECEIEVED!");
272+
if (!_obsReady) {
273+
_openOnLaunch = true;
274+
return;
275+
}
276+
if (mainWindowOpen && window) {
277+
QMetaObject::invokeMethod(
278+
QCoreApplication::instance()
279+
->thread(),
280+
[this]() {
281+
//window->setLoading();
282+
window->show();
283+
window->raise();
284+
window->activateWindow();
285+
LoadPurchasedProducts();
286+
});
287+
} else {
288+
QMetaObject::invokeMethod(
289+
QCoreApplication::instance()
290+
->thread(),
291+
[this]() {
292+
OpenElgatoCloudWindow();
293+
});
294+
}
295+
}
245296
});
246297
});
247298

0 commit comments

Comments
 (0)