0

上のサードパーティのホスト アプリケーションによってロードされる SIMBL プラグインに取り組んでいますmacOS。ほぼ完全に記述されてC++おり、目的の c コンポーネントは最小限しかありません。(UI の大部分は、ホスト アプリへの API 呼び出しによって提供されます。) 要件の 1 つは、プラグイン バンドルを異なるサブディレクトリから複数回ロードできることです。これは Lua インタープリターであり、ホスト アプリケーションの個別のメニューに表示される Lua スクリプトの異なる構成を各インスタンスでホストすることが目標です。サード パーティは、このプラグインをスクリプトのカスタム構成にバンドルすることができ、アプリのプラグイン メニューに個別の項目として表示されます。

私が抱えているこの問題は次のとおりです。プラグインが実行されているディレクトリを見つける必要があります。次の名前の特別なクラスを作成してMY_BUNDLE_ID_CLASS使用できます。

[NSBundle bundleForClass:[MY_BUNDLE_ID_CLASS class]];

正しい を取得したらNSBundle、ファイル パスを取得するのは簡単です。

問題は、バンドルの複数のインスタンスが (異なるフォルダーから) ロードされた場合、クラスMY_BUNDLE_ID_CLASSが複数の場所で定義されていると Cocoa が文句を言い、どの場所が使用されたかを保証しないことです。他の同様のクラスの場合、これは私のプラグインには問題ありません。私の固有のクラス名は、バージョン番号を含むマングル名と同等のマクロであるためですが、この場合は問題ありません。同じバージョンの複数のインスタンスである可能性があります。プラグイン コードが実行されているフォルダを見つける他の方法はありますか? 単純な要求のように思えますが、私は空っぽです。提案を歓迎します。

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 に答える