OBS
+ -

obs模块化原理

2024-03-20 5 0

OBS是模块化设计,各个模块按照约定提供相应的导出函数,并且以DLL的形式存于模块所在的路径。

OBS加载模块时,每个模块分配一个obs_module结构体。

struct obs_module {
    char *mod_name;  //模块的名称
    const char *file; //模块的文件名
    char *bin_path;  //dll完整路径
    char *data_path; //资源数据路径
    void *module;    //HMODULE
    bool loaded;     //load函数的返回值

//dll导出的函数,未写名的为可选函数,写名的为必须存在的函数
    bool (*load)(void);  //函数名必须为obs_module_load
    void (*unload)(void);
    void (*post_load)(void);
    void (*set_locale)(const char *locale);
    bool (*get_string)(const char *lookup_string,  const char **translated_string);
    void (*free_locale)(void);
    uint32_t (*ver)(void);                      //函数名必须为obs_module_ver
    void (*set_pointer)(obs_module_t *module); //函数名必须为obs_module_set_pointer
    const char *(*name)(void);
    const char *(*description)(void);
    const char *(*author)(void);

//下个模块,链表
    struct obs_module *next;
};

使用函数load_module_exports解析导出函数。有些函数是必须的,有些函数是可选的。

static int load_module_exports(struct obs_module *mod, const char *path)
{
    mod->load = os_dlsym(mod->module, "obs_module_load");
    if (!mod->load)
        return req_func_not_found("obs_module_load", path);

    mod->set_pointer = os_dlsym(mod->module, "obs_module_set_pointer");
    if (!mod->set_pointer)
        return req_func_not_found("obs_module_set_pointer", path);

    mod->ver = os_dlsym(mod->module, "obs_module_ver");
    if (!mod->ver)
        return req_func_not_found("obs_module_ver", path);

    /* optional exports */
    mod->unload = os_dlsym(mod->module, "obs_module_unload");
    mod->post_load = os_dlsym(mod->module, "obs_module_post_load");
    mod->set_locale = os_dlsym(mod->module, "obs_module_set_locale");
    mod->free_locale = os_dlsym(mod->module, "obs_module_free_locale");
    mod->name = os_dlsym(mod->module, "obs_module_name");
    mod->description = os_dlsym(mod->module, "obs_module_description");
    mod->author = os_dlsym(mod->module, "obs_module_author");
    mod->get_string = os_dlsym(mod->module, "obs_module_get_string");
    return MODULE_SUCCESS;
}

模块初始化时使用obs_open_module来初始化模块。

int obs_open_module(obs_module_t **module, const char *path,
            const char *data_path)
{
    struct obs_module mod = {0};

    //Windows下本质为LoadLibray,不过为了处理DLL依赖的资源,需要设置SetDllDirectoryW
    mod.module = os_dlopen(path);
    if (!mod.module) {
        blog(LOG_WARNING, "Module '%s' not loaded", path);
        return MODULE_FILE_NOT_FOUND;
    }

    //加载导出函数
    errorcode = load_module_exports(&mod, path);
    if (errorcode != MODULE_SUCCESS)
        return errorcode;

    mod.bin_path = bstrdup(path);
    mod.file = strrchr(mod.bin_path, '/');
    mod.file = (!mod.file) ? mod.bin_path : (mod.file + 1);
    mod.mod_name = get_module_name(mod.file);
    mod.data_path = bstrdup(data_path);
    mod.next = obs->first_module;

    if (mod.file) {
        blog(LOG_DEBUG, "Loading module: %s", mod.file);
    }

    *module = bmemdup(&mod, sizeof(mod));
    obs->first_module = (*module);
    mod.set_pointer(*module);

    if (mod.set_locale)
        mod.set_locale(obs->locale);

    return MODULE_SUCCESS;
}

而obs_open_module则由load_all_callback函数实现:

static void load_all_callback(void *param, const struct obs_module_info2 *info)
{
...
int code = obs_open_module(&module, info->bin_path, info->data_path);
...
    if (!obs_init_module(module))
        free_module(module);
}

obs_init_module函数的功能就是调用obs_module结构体中导出的函数load。

调用顺序

  • main
    • run_program
      • OBSBasic::OBSInit()
        • obs_load_all_modules2
          • obs_find_modules2(load_all_callback, &fail_info);

所以由obs_find_modules2扫描模块路径下的所有模块,并调用load_all_callback加载模块。

0 篇笔记 写笔记

作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!