Cocoa 获取 SIMBL 插件的当前 运行 路径
Cocoa get current running path of SIMBL Plugin
我正在开发由 macOS
上的第 3 方主机应用程序加载的 SIMBL 插件。它几乎完全是用 C++
编写的,只有极少的 objective-c 组件。 (UI 主要由 API 调用主机应用程序提供。)其中一个要求是插件包可以从不同的子目录加载多次。它是一个 Lua 解释器,目标是为每个实例托管不同配置的 lua 脚本,这些脚本出现在主机应用程序的单独菜单中。第三方可以将此插件与其脚本的自定义配置捆绑在一起,它们将在应用程序的插件菜单中显示为单独的项目。
我遇到的问题是:我需要找出我的插件在哪个目录中执行。我可以创建一个名为 MY_BUNDLE_ID_CLASS
的特殊 class 并使用:
[NSBundle bundleForClass:[MY_BUNDLE_ID_CLASS class]];
一旦我有了正确的 NSBundle
,获取文件路径就很简单了。
问题是如果我的包的多个实例被加载(从不同的文件夹),Cocoa 抱怨 class MY_BUNDLE_ID_CLASS
在多个位置定义并且不会保证我使用了哪一个。对于其他类似的 classes 这对我的插件来说没问题,因为我唯一的 class 名称是宏,等同于包含版本号的错位名称,但在这种情况下是不行的。它可能是同一版本的多个实例。有没有其他方法可以找出我的插件代码正在执行的文件夹?这似乎是一个简单的请求,但我一无所获。欢迎提出建议。
给定可执行文件中的地址,dladdr
函数可用于查询动态链接器有关包含该地址的 dynamically-linked 映像;即,给定对插件中符号的引用,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
),但您应该注意不要传入可以动态分配的指针——因为那可能会失败,或者将您指向主机进程的内存 space。
在我的机器上,使用简单的 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
这确实是磁盘上插件的路径。
我正在开发由 macOS
上的第 3 方主机应用程序加载的 SIMBL 插件。它几乎完全是用 C++
编写的,只有极少的 objective-c 组件。 (UI 主要由 API 调用主机应用程序提供。)其中一个要求是插件包可以从不同的子目录加载多次。它是一个 Lua 解释器,目标是为每个实例托管不同配置的 lua 脚本,这些脚本出现在主机应用程序的单独菜单中。第三方可以将此插件与其脚本的自定义配置捆绑在一起,它们将在应用程序的插件菜单中显示为单独的项目。
我遇到的问题是:我需要找出我的插件在哪个目录中执行。我可以创建一个名为 MY_BUNDLE_ID_CLASS
的特殊 class 并使用:
[NSBundle bundleForClass:[MY_BUNDLE_ID_CLASS class]];
一旦我有了正确的 NSBundle
,获取文件路径就很简单了。
问题是如果我的包的多个实例被加载(从不同的文件夹),Cocoa 抱怨 class MY_BUNDLE_ID_CLASS
在多个位置定义并且不会保证我使用了哪一个。对于其他类似的 classes 这对我的插件来说没问题,因为我唯一的 class 名称是宏,等同于包含版本号的错位名称,但在这种情况下是不行的。它可能是同一版本的多个实例。有没有其他方法可以找出我的插件代码正在执行的文件夹?这似乎是一个简单的请求,但我一无所获。欢迎提出建议。
给定可执行文件中的地址,dladdr
函数可用于查询动态链接器有关包含该地址的 dynamically-linked 映像;即,给定对插件中符号的引用,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
),但您应该注意不要传入可以动态分配的指针——因为那可能会失败,或者将您指向主机进程的内存 space。
在我的机器上,使用简单的 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
这确实是磁盘上插件的路径。