Как библиотека C# может зависеть от неуправляемой библиотеки DLL, имя которой будет указано позже в окончательном приложении?

В C вы можете скомпилировать статическую библиотеку, которая зависит от заголовка C, определяющего несколько функций. Вам не нужно знать, какая библиотека в конечном итоге реализует эти функции, поэтому ваша статическая библиотека может быть независимой от реализации. Пока вы предоставляете действительную реализацию, вы можете связать статическую библиотеку с окончательным исполняемым файлом.

Как я могу сделать что-то подобное на С#? Я хочу создать библиотеку, которая зависит от общего API, который может быть реализован несколькими библиотеками DLL C++. (Чтобы было ясно, я имею в виду динамическую компоновку, а не статическую компоновку, как в моей аналогии выше.) Но для использования DllImport и P/Invoke я должен указать имя DLL. Очевидно, я должен сделать это в какой-то момент, но я хотел бы создать DLL библиотеки классов, которая зависит от API из неуказанной на этом этапе DLL, а затем указать только имя этой неуправляемой DLL в финале. прикладной проект.

Знаете ли вы, что DLL — это сокращение от динамической библиотеки?

shingo 19.01.2023 06:00

@shingo Да, конечно. Вы подразумеваете, что я мог бы вызвать DllImport с переменной вместо строкового литерала? Но в этих примерах DllImport не вызывается внутри функции. Я далек от эксперта по С#, поэтому, если можно передать ему переменную, я не знаю, как это сделать.

curiousdannii 19.01.2023 06:05

Нет, я имею в виду, что вы только что сравнили статическую библиотеку на C с динамической библиотекой на C#, что несовместимо. Когда вам нужно использовать DLL в C, вам также необходимо указать ее имя, иначе вам придется использовать LoadLibrary + GetProcAddress.

shingo 19.01.2023 06:10

@shingo А, чтобы было ясно, я хочу динамически связывать библиотеки DLL, а не связывать их статически. Статические библиотеки были просто лучшим примером, который я мог придумать для независимой от реализации стратегии API, хотя я уверен, что динамическая компоновка в C/C++ также допускает то же самое. Аналогия может быть не лучшей, но я думаю, что вопрос ясно объясняет, что я хотел бы сделать на С#.

curiousdannii 19.01.2023 06:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Имя, которое вы предоставляете [DllImport], должно быть постоянным во времени компиляции, поэтому вы не можете передавать здесь «динамическое» значение. Однако вы можете использовать какое-то имя по умолчанию или даже фиктивное имя, а затем преобразовать это имя во время выполнения в допустимую библиотеку, используя NativeLibrary.SetDllImportResolver.

Например, в одном проекте я использую нативную библиотеку C libgphoto. В Windows я включаю его в дистрибутив предварительно скомпилированным, и так получилось, что нужная мне функциональность разделена между двумя dll с именами «libgphoto2-6.dll» и «libgphoto2_port-12.dll». Однако на linux и macos вы можете установить эту библиотеку из пакета, и все функции будут в библиотеке с именем просто «gphoto».

Итак, я определяю свой импорт, используя имена dll "windows":

private const string LibGPhotoName = "libgphoto2-6";
[DllImport(LibGPhotoName)]
public static extern int gp_widget_get_id(IntPtr widget, out int id);

Но тогда, если я не в Windows, я делаю:

NativeLibrary.SetDllImportResolver(typeof(GPhoto2).Assembly, (name, asm, search) => {
    if (name == "libgphoto2-6" || name == "libgphoto2_port-12")
    {
        return NativeLibrary.Load("gphoto2", asm, search);
    }
    return IntPtr.Zero;
});

Поэтому, если среда выполнения хочет загрузить собственную библиотеку «libgphoto2-6» или «libgphoto2_port-12», я говорю ей вместо этого загрузить «gphoto2».

Вы можете сделать то же самое в вашем случае.

Другие вопросы по теме