How to load a plugin from another plugin?
Copy link to clipboard
Copied
Hi,
I'm trying to load a plugin, which is not located in the plugin-paths of After Effects from another plugin. It seems to load the aex(dll) and execute the main function fine, but afterwards it crashes immediately and I have no idea why.
This is how my pluginLoader-PlugIn looks like:
1. I created a commandHook to be able to trigger the pluginLoad from the Edit Menu
2. for the actual load of the dll I use the following commands:
AEGP_SuiteHandler suites(basic_suite);
std::string dllName = "C:/PATH/TO/plugin.aex";
// defining type and order of the arguments of the entry function
typedef A_Err (*args_type)(SPBasicSuite *pica_basicP, A_long major_versionL, A_long minor_versionL, A_long aegp_plugin_id, AEGP_GlobalRefcon *global_refconP);
args_type pluginEntryMethod = NULL;
// loading the dll(aex) and the entry function
# ifdef _WIN32
HMODULE hDLL = LoadLibrary(dllName.c_str());
if (hDLL != NULL)
{
pluginEntryMethod = (args_type) GetProcAddress(hDLL, "EntryPointFunc");
}
else
{
return err;
}
# else
void *pLib = ::dlopen(szMyLib, RTLD_LAZY);
if (pLib != NULL) {
pluginEntryMethod = (args_type)::dlsym(pLib, "EntryPointFunc");
}
else
{
return err;
}
# endif
if (pluginEntryMethod != NULL)
{
// hardcoding the plugin version
A_long mavL = 0L;
A_long mivL = 1L;
AEGP_PluginID plId;
// to get a valid plugin-id I use this command
suites.UtilitySuite3()->AEGP_RegisterWithAEGP(*globalRefcon, "nameOfPlugin", &plId);
// I create copy of the refcon and the suite
AEGP_GlobalRefcon newRefcon(*globalRefcon);
SPBasicSuite newSuite(*basic_suite);
pluginEntryMethod(&newSuite, mavL, mivL, plId, &newRefcon);
}
# ifdef _WIN32
FreeLibrary(hDLL);
# else
dlclose(pLib);
# endif
If I run After Effects with the debugger, the EntryFunction of the new plugin runs through without errors. But Then it crashes and stops at random positions: sometimes in the IdleHook of the newly loaded Plugin, sometimes in the MenuHook.
Does anyone have an idea, what I am doing wrong?
btw: when I copy the second plugin in the default Afx-Plugin-Folder it loads fine and seems to work correct.
Thanks for your help!
Martin
Copy link to clipboard
Copied
hi martin! welcome to the forum!
well, a few things can go wrong with such an operation.
1. AE loads plug-ins at start-up time. perhaps such a late registration is
not possible.
2. are you doing any operations prior to calling that plug-in that might
overrun each other? such as the inner plug-in returning different data with
the out_data structure that AE who called the first plug-in would have
expected.
these are just off the top of my head.
what's the bigger picture?
Copy link to clipboard
Copied
Hi Shachar,
First of all, thank you for your reply.
As you said it might be impossible. This functionality is not documented in the SDK-documentation.
According to other operations I do: I only load the inner plugin by the outer one. I don't call any function of the inner plugin from the outer one except the entry function to initialize the inner plugin. The inner plugin registers itselfs with the entry function, so that there is currently no communication between the inner and the outer plugin going on.
The bigger picture: I would like to create a plugin, which is able to initialize other plugins not situated in the default plugin locations, but situated at locations given by an environment variable.
As you said, it might not be possible to late-register a plugin, but I think it's worth a try and I was hoping for some input if it is possible or not. When I use an invalid pluginid to load the inner plugin. It starts registering and creates the menu commands as expected, but fails somewhen later in the registering process, so I am quite optimistic, that I can get it to work if I can figure out what I'm currently doing wrong.
At the moment the plugin I try to load is quite complex (uses multiple threads, boost and Qt), and I'll try it tomorrow with a very simple SDK-example plugin to make sure, that it has nothing to do with the plugin I try to load.
Another assumption is, that the AEGP_RegisterWithAEGP doesn't do what I expect it to and that I need to find another way to gather a valid plugin-id. I'm also not certain if I really have to create copies of the global refcon and the basic plugin suite before registering the plugin. The SDK-documentation is not very detailed in the field of how registering a plugin actually works.
Maybe it has also something to do with the scope. Maybe I have to keep the library loaded until the outer plugin (and after effects) closes.
What do you think?
Cheers,
Martin
Copy link to clipboard
Copied
not that i want to be a smart ass, but you can create a short cut in the
plug-in folder to wherever you want and the destination will be scanned and
loaded...
anyways, if your loader plug-in is just an empty shell transmitting it's
inputs into the other plug-in, then it should work.
however, in the entry point of an AEGP which is called only once at
startup, you register all of the functions that AE will call later on. when
registering, you give the ram address of the function. for the address to
remain valid, you have to keep the inner plug-in loaded at all times,
otherwise these ram addresses will be invalidated.
another logical problem i see, is that each "shell" plug-in can only load
one AEGP (at least it seems so to me), so you have to have 10 shells on the
plug-in's folder to load 10 plug-ins elsewhere... i don't know if that
defeats your purpose or not.

Copy link to clipboard
Copied
You said you were using Qt in your plugin. Are you linking the Qt libraries statically or dynamically? If dynamically, there is a known issue with loading DLLs that are itself loading external DLLs, especially with Qt.
I don't know if it applies to you, but here is some info on that: https://forums.adobe.com/message/6901217#6901217
Copy link to clipboard
Copied
Hi Tobias,
I think you are right. I compiled the two example plugins today and they all seem to work fine. I think it has something to do with the dynamically linked Qt-libraries. Do you know why this happens, exactly? Do you think, that the problem will be gone if I just link Qt and boost statically in the aex?
@shachar: Using symlinks will not do the trick, because After Effects doesn't follow links on Windows. At least, that's what they write in the SDK-docs
When launched, After Effects recursively descends 10 levels deep into
subdirectories of its path. MacOS aliases are traversed, but Windows
shortcuts are not. Directories terminated by parentheses or preceded by the
symbols ¬ (MacOS) or ~ (Windows) are not scanned.
That was the first thing I tried. There is a way to change the plugin-path in the registry as well, but this only works for a single plugin-location. I would like to have multiple different folders.
Thanks for your help.
Cheers,
Martin

Copy link to clipboard
Copied
Static linking removes the dependancy on any external Qt DLLs, so yes, that should fix your problem.
As far as I remember, one problem with dynamically loaded DLLs was that if you load a plugin that load another DLL which itself requires external DLLs (like Qt), Windows will look in the current directory of the host application for the additional DLLs, not in the directory of the plugin that actually needs them. This is true for Windows DLLs in general.
So if you have your main plugin MAIN.AEX in your usual AE plugin folder, and from this plugin you load a SUB.AEX from a different folder, and this SUB.AEX requires Qt DLLs, they need to be present in either the global search path or the directory of the MAIN.AEX, but NOT in the directoy of the SUB.AEX.
Copy link to clipboard
Copied
Okay, unfortunately it had nothing to do with static or dynamic linking of the dependencies.
I was able to boil it down to the following problem but I'm still stuck on how to solve the situation:
The problem has to do with an invalid AEGP_GlobalRefcon of the Plugin I load:
the plugin loader:
// the load of the inner plugin..
AEGP_GlobalRefcon newRefcon; // generating a new refcon
suites.UtilitySuite5()->AEGP_RegisterWithAEGP(newRefcon, pluginName.c_str(), &plId); // gathering a plugin id
pluginEntryMethod(basic_suite, mavL, mivL, plId, &newRefcon) // calling the entry function
the loaded plugin:
A_Err EntryPointFunc(
struct SPBasicSuite *pica_basicP,
A_long major_versionL,
A_long minor_versionL,
AEGP_PluginID aegp_plugin_id,
AEGP_GlobalRefcon *global_refconP)
{
*global_refconP = (AEGP_GlobalRefcon) new CustomClass(pica_basicP, aegp_plugin_id); // this is where the refcon gets invalid
return err;
}
To gather a valid plugin id, I register the plugin and assign a new AEGP_GlobalRefcon to it, which is for instance at address 0x0001234abcd (plugin-loader line 3)
then I call the entry function(plugin-loader line 4) and the entry function creates a custom class and stores a pointer to its instance in the global_refconP pointer, which changes the address from 0x0001234abcd to 0x0a010b020c3d4.
The crash happens later, when a hook (eg IdleHook) is called, which tries to reinterpret the refconPV-pointer of the plugin (address 0x0001234abcd) to a CustomClass-instance, because the actual instance is stored at 0x0a010b020c3d4.
I reckon, that I can fix this if I either can change the global refcon of the plugin after the enty function has run or if I can get a valid plugin id before calling the entry function and doing the registration with the new refcon I got returned by the entry function of the loaded plugin.
Does anyone know how to achieve one of these two goals?

