0

我正在开发一个由 3rd 方主机应用程序加载的 SIMBL 插件macOS。它几乎完全是用编写的,C++并且只有最少的 Objective-c 组件。(UI 主要由对主机应用程序的 API 调用提供。)其中一项要求是插件包可以从不同的子目录多次加载。它是一个 Lua 解释器,目标是为每个实例托管不同配置的 lua 脚本,这些脚本出现在主机应用程序的单独菜单中。第三方可以将此插件与其脚本的自定义配置捆绑在一起,它们将在应用程序的插件菜单中显示为单独的项目。

我遇到的这个问题是:我需要找出我的插件在哪个目录中执行。我可以创建一个名为MY_BUNDLE_ID_CLASS并使用的特殊类:

[NSBundle bundleForClass:[MY_BUNDLE_ID_CLASS class]];

一旦我有了正确的NSBundle,获取文件路径就很简单了。

问题是,如果我的包的多个实例被加载(从不同的文件夹),Cocoa 抱怨这个类MY_BUNDLE_ID_CLASS是在多个位置定义的,并且不能保证我使用了哪个。对于其他类似的类,这对我的插件来说很好,因为我唯一的类名是等同于包含版本号的损坏名称的宏,但在这种情况下它是不行的。它可能是同一版本的多个实例。有没有其他方法可以找出我的插件代码正在执行的文件夹?这似乎是一个简单的请求,但我却空无一物。我欢迎建议。

4

1 回答 1

0

给定可执行文件中的地址,该dladdr函数可用于向动态链接器查询包含该地址的动态链接图像;即,给定对插件中符号的引用,dladdr可以为您提供有关插件的动态链接信息。

运行时查找可能如下所示:

// Sample: BundleClass.m, the principal class for the plugin

#import "BundleClass.h"
#import <dlfcn.h>

// We'll be using a reference to this variable compiled into the plugin,
// but we can just as easily use a function pointer or similar -- anything
// that will be statically compiled into the plugin.
int someVariable = 0;

@implementation BundleClass

+ (void)load {
    Dl_info info;
    if (dladdr(&someVariable, &info) != 0) {
        NSLog(@"Plugin loaded from %s", info.dli_fname);
    } else {
        // Handle lookup failure.
    }
}

@end

除了&someSymbol,您还可以使用对函数的引用(例如&someFunctionDefinedInThePlugin),但您应该注意不要传入可以动态分配的指针 - 因为这可能会失败,或者将您指向主机的内存空间过程。

在我的机器上,通过简单的 macOS 主机应用程序设置,以下加载代码:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    NSURL *bundleURL = [[NSBundle mainBundle] URLForResource:@"DynamicBundle" withExtension:@"bundle"];
    if (!bundleURL) {
        NSLog(@"Failed to find bundle!");
        return;
    }

    NSLog(@"Bundle class before loading: %@", NSClassFromString(@"BundleClass"));

    NSBundle *bundle = [NSBundle bundleWithURL:bundleURL];
    NSError *error = nil;
    if (![bundle loadAndReturnError:&error]) {
        NSLog(@"Failed to load bundle: %@", error);
        return;
    }

    NSLog(@"Bundle class after loading: %@", NSClassFromString(@"BundleClass"));
}

成功生产

Bundle class before loading: (null)
Loaded plugin from /Volumes/ExtSSD/Developer/Xcode/DerivedData/HostApp/Build/Products/Debug/HostApp.app/Contents/Resources/DynamicBundle.bundle/Contents/MacOS/DynamicBundle
Bundle class after loading: BundleClass

这确实是磁盘上插件的路径。

于 2022-02-09T14:32:00.150 回答