Я успешно загрузил плагин C++, используя собственный класс загрузчика плагинов. Каждый плагин имеет внешнюю функцию create_instance "C", которая возвращает новый экземпляр, используя "new".
Плагин — это абстрактный класс с несколькими невиртуальными функциями и несколькими защищенными переменными (одной из них является std::vector refList).
Класс plugin_loader успешно загружает и даже вызывает виртуальный метод загруженного класса (а именно «std::string plugin::getName()».
Основная функция создает экземпляр «host», который содержит вектор интеллектуальных указателей с подсчетом ссылок, refptr, на класс «plugin». Затем main создает экземпляр plugin_loader, который фактически выполняет dlopen/dlsym, и создает экземпляр refptr, передавая ему функцию create_instance(). Наконец, он передает созданный refptr обратно функции addPlugin хоста. host::addPlugin успешно вызывает несколько функций для переданного экземпляра плагина и, наконец, добавляет его в плагин vector‹refptr‹› ›.
Затем основная функция подписывается на несколько событий Apple и вызывает RunApplicationEventLoop(). Обратный вызов события декодирует результат, а затем вызывает функцию хоста host::sendToPlugin, которая идентифицирует подключаемый модуль, для которого предназначено событие, а затем вызывает обработчик в подключаемом модуле. Именно в этот момент что-то перестает работать.
host::sendToPlugin считывает результат и определяет плагин для отправки события.
Я использую чрезвычайно простой плагин, созданный как плагин отладки, который возвращает статические значения для каждой непустой функции.
Любой вызов любой виртуальной функции в плагине в векторе вызывает исключение неправильного доступа. Я попытался заменить refptrs обычными указателями, а также boost::shared_ptrs, и я продолжаю получать одно и то же исключение. Я знаю, что экземпляр плагина действителен, так как я могу проверить экземпляр в отладчике Xcode и даже просмотреть элементы в refList плагина.
Я думаю, что это может быть проблема с потоками, потому что плагины были созданы в основном потоке, в то время как обратный вызов работает в отдельном потоке. Я думаю, что-то все еще работает в основном потоке поток, судя по обратной трассировке, когда программа обнаруживает ошибку, но я не знаю реализацию Apple RunApplicationEventLoop, поэтому я не могу быть уверен.
Любые идеи относительно того, почему это происходит?
class plugin
{
public:
virtual std::string getName();
protected:
std::vector<std::string> refList;
};
и класс pluginLoader:
template<typename T> class pluginLoader
{
public: pluginLoader(std::string path);
// initializes private mPath string with path to dylib
bool open();
// opens the dylib and looks up the createInstance function. Returns true if successful, false otherwise
T * create_instance();
// Returns a new instance of T, NULL if unsuccessful
};
class host
{
public:
addPlugin(int id, plugin * plug);
sendToPlugin(); // this is the problem method
static host * me;
private:
std::vector<plugin *> plugins; // or vector<shared_ptr<plugin> > or vector<refptr<plugin> >
};
код события Apple из host.cpp;
host * host::me;
pascal OSErr HandleSpeechDoneAppleEvent(const AppleEvent *theAEevt, AppleEvent *reply, SRefCon refcon) {
// this is all boilerplate taken straight from an apple sample except for the host::me->ae_callback line
OSErr status = 0;
Result result = 0;
// get the result
if (!status) {
host::me->ae_callback(result);
}
return status;
}
void host::ae_callback(Result result) {
OSErr err;
// again, boilerplate apple code
// grab information from result
if (!err)
sendToPlugin();
}
void host::sendToPlugin() {
// calling *any* method in plugin results in failure regardless of what I do
}
РЕДАКТИРОВАТЬ: это выполняется на OSX 10.5.8, и я использую GCC 4.0 с Xcode. Это не приложение для разных платформ.
РЕДАКТИРОВАТЬ: Чтобы было ясно, плагин работает до тех пор, пока цикл обработки событий Apple не вызовет мою функцию обратного вызова. Когда функция обратного вызова обращается к хосту, все перестает работать. Это проблема, которая у меня возникла, все остальное до этого момента работало.