Move plugin loading outside of the OBS constructor

Fixes a race condition crash when plugins tried to use API functions which weren't ready since the constructor hadn't returned a valid OBS *App for the API.
master
Richard Stanway 2015-12-28 20:05:24 +01:00
parent 2d9f782ecb
commit 63c55478de
3 changed files with 97 additions and 91 deletions

View File

@ -777,6 +777,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
App = new OBS;
App->LoadAllPlugins();
HACCEL hAccel = LoadAccelerators(hinstMain, MAKEINTRESOURCE(IDR_ACCELERATOR1));
MSG msg;

View File

@ -159,6 +159,100 @@ VOID CheckPermissionsAndDiskSpace()
//---------------------------------------------------------------------------
VOID OBS::LoadAllPlugins()
{
//-----------------------------------------------------
// load plugins
OSFindData ofd;
HANDLE hFind = OSFindFirstFile(TEXT("plugins/*.dll"), ofd);
if (hFind)
{
do
{
if (!ofd.bDirectory) //why would someone give a directory a .dll extension in the first place? pranksters.
{
String strLocation;
strLocation << TEXT("plugins/") << ofd.fileName;
HMODULE hPlugin = LoadLibrary(strLocation);
if (hPlugin)
{
bool bLoaded = false;
//slightly redundant I suppose seeing as both these things are being added at the same time
LOADPLUGINEXPROC loadPluginEx = (LOADPLUGINEXPROC)GetProcAddress(hPlugin, "LoadPluginEx");
if (loadPluginEx) {
bLoaded = loadPluginEx(OBSGetAPIVersion());
}
else {
LOADPLUGINPROC loadPlugin = (LOADPLUGINPROC)GetProcAddress(hPlugin, "LoadPlugin");
bLoaded = loadPlugin && loadPlugin();
}
if (bLoaded) {
PluginInfo *pluginInfo = plugins.CreateNew();
pluginInfo->hModule = hPlugin;
pluginInfo->strFile = ofd.fileName;
/* get event callbacks for the plugin */
pluginInfo->startStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStream");
pluginInfo->stopStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStream");
pluginInfo->startStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStreaming");
pluginInfo->stopStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStreaming");
pluginInfo->startRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartRecording");
pluginInfo->stopRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopRecording");
pluginInfo->statusCallback = (OBS_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnOBSStatus");
pluginInfo->streamStatusCallback = (OBS_STREAM_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnStreamStatus");
pluginInfo->sceneSwitchCallback = (OBS_SCENE_SWITCH_CALLBACK)GetProcAddress(hPlugin, "OnSceneSwitch");
pluginInfo->sceneCollectionSwitchCallback = (OBS_SCENE_SWITCH_CALLBACK)GetProcAddress(hPlugin, "OnSceneCollectionSwitch");
pluginInfo->scenesChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnScenesChanged");
pluginInfo->sceneCollectionsChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSceneCollectionsChanged");
pluginInfo->sourceOrderChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourceOrderChanged");
pluginInfo->sourceChangedCallback = (OBS_SOURCE_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnSourceChanged");
pluginInfo->sourcesAddedOrRemovedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourcesAddedOrRemoved");
pluginInfo->micVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnMicVolumeChanged");
pluginInfo->desktopVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnDesktopVolumeChanged");
pluginInfo->logUpdateCallback = (OBS_LOG_UPDATE_CALLBACK)GetProcAddress(hPlugin, "OnLogUpdate");
pluginInfo->startRecordingReplayBufferCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartRecordingReplayBuffer");
pluginInfo->stopRecordingReplayBufferCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopRecordingReplayBuffer");
pluginInfo->replayBufferSavedCallback = (OBS_REPLAY_BUFFER_SAVED_CALLBACK)GetProcAddress(hPlugin, "OnReplayBufferSaved");
//GETPLUGINNAMEPROC getName = (GETPLUGINNAMEPROC)GetProcAddress(hPlugin, "GetPluginName");
//CTSTR lpName = (getName) ? getName() : TEXT("<unknown>");
//FIXME: TODO: log this somewhere else, it comes before the OBS version info and looks weird.
//Log(TEXT("Loaded plugin '%s', %s"), lpName, strLocation);
}
else
{
Log(TEXT("Failed to initialize plugin %s"), strLocation.Array());
FreeLibrary(hPlugin);
}
}
else
{
DWORD err = GetLastError();
Log(TEXT("Failed to load plugin %s, %d"), strLocation.Array(), err);
#ifndef _DEBUG
if (err == 193)
{
#ifdef _M_X64
String message = FormattedString(Str("Plugins.InvalidVersion"), ofd.fileName, 32);
#else
String message = FormattedString(Str("Plugins.InvalidVersion"), ofd.fileName, 64);
#endif
OBSMessageBox(hwndMain, message.Array(), NULL, MB_ICONEXCLAMATION);
}
#endif
}
}
} while (OSFindNextFile(hFind, ofd));
OSFindClose(hFind);
}
}
OBS::OBS()
{
@ -724,97 +818,6 @@ OBS::OBS()
if(GlobalConfig->GetInt(TEXT("General"), TEXT("ShowWebrootWarning"), TRUE) && IsWebrootLoaded())
OBSMessageBox(hwndMain, TEXT("Webroot Secureanywhere appears to be active. This product will cause problems with OBS as the security features block OBS from accessing Windows GDI functions. It is highly recommended that you disable Secureanywhere and restart OBS.\r\n\r\nOf course you can always just ignore this message if you want, but it may prevent you from being able to stream certain things. Please do not report any bugs you may encounter if you leave Secureanywhere enabled."), TEXT("Just a slight issue you might want to be aware of"), MB_OK);
//-----------------------------------------------------
// load plugins
OSFindData ofd;
HANDLE hFind = OSFindFirstFile(TEXT("plugins/*.dll"), ofd);
if(hFind)
{
do
{
if(!ofd.bDirectory) //why would someone give a directory a .dll extension in the first place? pranksters.
{
String strLocation;
strLocation << TEXT("plugins/") << ofd.fileName;
HMODULE hPlugin = LoadLibrary(strLocation);
if(hPlugin)
{
bool bLoaded = false;
//slightly redundant I suppose seeing as both these things are being added at the same time
LOADPLUGINEXPROC loadPluginEx = (LOADPLUGINEXPROC)GetProcAddress(hPlugin, "LoadPluginEx");
if (loadPluginEx) {
bLoaded = loadPluginEx(OBSGetAPIVersion());
} else {
LOADPLUGINPROC loadPlugin = (LOADPLUGINPROC)GetProcAddress(hPlugin, "LoadPlugin");
bLoaded = loadPlugin && loadPlugin();
}
if (bLoaded) {
PluginInfo *pluginInfo = plugins.CreateNew();
pluginInfo->hModule = hPlugin;
pluginInfo->strFile = ofd.fileName;
/* get event callbacks for the plugin */
pluginInfo->startStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStream");
pluginInfo->stopStreamCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStream");
pluginInfo->startStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartStreaming");
pluginInfo->stopStreamingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopStreaming");
pluginInfo->startRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartRecording");
pluginInfo->stopRecordingCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopRecording");
pluginInfo->statusCallback = (OBS_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnOBSStatus");
pluginInfo->streamStatusCallback = (OBS_STREAM_STATUS_CALLBACK)GetProcAddress(hPlugin, "OnStreamStatus");
pluginInfo->sceneSwitchCallback = (OBS_SCENE_SWITCH_CALLBACK)GetProcAddress(hPlugin, "OnSceneSwitch");
pluginInfo->sceneCollectionSwitchCallback = (OBS_SCENE_SWITCH_CALLBACK)GetProcAddress(hPlugin, "OnSceneCollectionSwitch");
pluginInfo->scenesChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnScenesChanged");
pluginInfo->sceneCollectionsChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSceneCollectionsChanged");
pluginInfo->sourceOrderChangedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourceOrderChanged");
pluginInfo->sourceChangedCallback = (OBS_SOURCE_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnSourceChanged");
pluginInfo->sourcesAddedOrRemovedCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnSourcesAddedOrRemoved");
pluginInfo->micVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnMicVolumeChanged");
pluginInfo->desktopVolumeChangeCallback = (OBS_VOLUME_CHANGED_CALLBACK)GetProcAddress(hPlugin, "OnDesktopVolumeChanged");
pluginInfo->logUpdateCallback = (OBS_LOG_UPDATE_CALLBACK)GetProcAddress(hPlugin, "OnLogUpdate");
pluginInfo->startRecordingReplayBufferCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStartRecordingReplayBuffer");
pluginInfo->stopRecordingReplayBufferCallback = (OBS_CALLBACK)GetProcAddress(hPlugin, "OnStopRecordingReplayBuffer");
pluginInfo->replayBufferSavedCallback = (OBS_REPLAY_BUFFER_SAVED_CALLBACK)GetProcAddress(hPlugin, "OnReplayBufferSaved");
//GETPLUGINNAMEPROC getName = (GETPLUGINNAMEPROC)GetProcAddress(hPlugin, "GetPluginName");
//CTSTR lpName = (getName) ? getName() : TEXT("<unknown>");
//FIXME: TODO: log this somewhere else, it comes before the OBS version info and looks weird.
//Log(TEXT("Loaded plugin '%s', %s"), lpName, strLocation);
}
else
{
Log(TEXT("Failed to initialize plugin %s"), strLocation.Array());
FreeLibrary(hPlugin);
}
}
else
{
DWORD err = GetLastError();
Log(TEXT("Failed to load plugin %s, %d"), strLocation.Array(), err);
#ifndef _DEBUG
if (err == 193)
{
#ifdef _M_X64
String message = FormattedString(Str("Plugins.InvalidVersion"), ofd.fileName, 32);
#else
String message = FormattedString(Str("Plugins.InvalidVersion"), ofd.fileName, 64);
#endif
OBSMessageBox(hwndMain, message.Array(), NULL, MB_ICONEXCLAMATION);
}
#endif
}
}
} while (OSFindNextFile(hFind, ofd));
OSFindClose(hFind);
}
CheckPermissionsAndDiskSpace();
ConfigureStreamButtons();

View File

@ -1323,6 +1323,7 @@ public:
void AddPendingStream(ClosableStream *stream, std::function<void()> finishedCallback = {});
void AddPendingStreamThread(HANDLE thread);
void ClosePendingStreams();
void LoadAllPlugins();
};
LONG CALLBACK OBSExceptionHandler (PEXCEPTION_POINTERS exceptionInfo);