DllImport с разными точками входа (разные DLL для одного и того же импорта в разных проектах)

В качестве продолжения моего недавнего вопроса об отладке.NET Compact Framework в настоящее время я пытаюсь использовать OpenGL ES как из.NET Compact Framework, так и из приложения.NET Framework. Я использую эту обертку, которая была создана для OpenGL ES и импортирует из libGLES_CM.dll.

Чтобы упростить отладку, я создал приложение.NET Framework, пересоздал проект импорта для OpenGL ES и EGL с теми же файлами (просто сборка для Desktop Framework), создал константы для имен DLL, чтобы они импортировались из libGLESv2.dll и libEGL.dll в Windows и из libGLES_CM.dll в CF. Библиотеки DLL взяты из PowerVR OpenGL ES Emulation SDK (целевое устройство имеет PowerVR SGX) и являются просто оболочкой OpenGL ES для реальной реализации OpenGL. И тут возникает проблема:

В библиотеке-обертке функции OpenGL находятся в двух статических классах (gl и egl) и имеют обычное имя, но без префикса gl/egl, поэтому их вызов будет egl.GetDisplay() вместо egl.eglGetDisplay(), Они импортируются так:

[DllImport(DllName, EntryPoint = "eglGetDisplay")]
static extern IntPtr GetDisplay(EGLNativeDisplayType display_id);

Это отлично работает на Compact Framework. В настольном проекте выдается исключение EntryPointNotFoundException - потому что функции называются как _eglGetDisplay@4 (примечание: ОМУ ловит Alt-Gr+Q для кавычек, который является символом at на немецких раскладках клавиатуры. Я должен был вставить его.) согласно Dependency Walker.

Мне удалось добавить подчеркивание к имени функции для настольного проекта, но не для CF, с помощью условной установки строковой константы для пустой строки или "_" и конкатенации ее и имени точки входа, чтобы она выглядела как этот:

[DllImport(DllName, EntryPoint = FunctionPrefix + "eglGetDisplay")]

Здесь нет проблем. Но функция все еще не найдена, потому что @4 (что это такое?) Отсутствует. Если я добавлю @4, это сработает, но, поскольку все функции имеют разные значения, я должен был сделать это вручную, и, вероятно, числа будут неправильными для версии CF. Вот странная часть:

Если я просто не укажу точку входа и вместо этого назову функцию так, как она должна быть названа, то импорт работает нормально! Теперь это уродливо из-за двойного префикса (статического имени класса и имени функции), хотя я мог бы обойти это, просто добавив обертку для этого. Поскольку я не буду сильно полагаться на эти функции (нужен только довольно простой 2D-движок), это не будет проблемой, но это просто не правильно.

Почему не работает при указании точки входа? Что я могу сделать, чтобы он работал так, как должен?

3 ответа

Решение

Если у CF и настольных API разные точки входа, вам нужно работать с этим. Это означает, что вам нужны разные определения DllImport.

Проще всего может быть наличие двух классов-оболочек, реализующих все внутренние (.NET) имена, которые вызывают их импорт, а затем создание экземпляра правильного во время выполнения в зависимости от платформы. Затем получите доступ к API через общий интерфейс.

Interface IGLImports {
   IntPtr GetDisplay(EGLNativeDisplayType display_id);
}

static class CFRawImports {
  [DllImport(DllName, EntryPoint = "eglGetDisplay")]
  static extern IntPtr GetDisplay(EGLNativeDisplayType display_id);
}

static class DeskRawImports {
  [DllImport(DllName, EntryPoint = "_eglGetDisplay@4")]
  static extern IntPtr GetDisplay(EGLNativeDisplayType display_id);
}

class DesktopImports : IGLImports {
  public IntPtr GetDisplay(EGLNativeDisplayType display_id) {
    return DeskRawImports.GetDisplay(display_id);
  }
}

class CFImports : IGLImports {
  public IntPtr GetDisplay(EGLNativeDisplayType display_id) {
    return CFRawImports.GetDisplay(display_id);
  }
}

static class ImportLoader {
  public static IGLImports GetImports() {
    if (isCF) {
      return new CFImports();
    } else {
      return new DesktopImports();
    }
  }
}

class MyApp {
  private static IGLIMports gl = ImportLoader.GetImports();

  // In code use gl.GetDesktop(...)

РЕДАКТИРОВАТЬ: интерфейс и четыре класса должны быть созданы с небольшим количеством кода. Входной файл, содержащий Имя DesktopImport CFImport (возможно, добавление имен DLL, если они различаются). Было бы оправданием для изучения шаблонов VS T4...

Декорированное имя - это строка, созданная компилятором во время компиляции определения функции или прототипа. "@4" в имени означает, что длина его параметра составляет 4 байта (32-разрядное целое число?).

Вы можете использовать dumpbin.exe, чтобы получить украшенные имена от вас.dll.

Используйте #define yourdllname_API extern "C" __declspec (dllexport) для предоставления методов в вашей dll, избегая декорирования функций таким образом, как вы не получите вышеупомянутое исключение, например:

DLL:

#ifdef DEPLOYHOOK_EXPORTS
#define DEPLOYHOOK_API  extern "C" __declspec(dllexport)
#else
#define DEPLOYHOOK_API  __declspec(dllimport)
#endif

// This class is exported from the DeployHook.dll

DEPLOYHOOK_API int nDeployHook;


DEPLOYHOOK_API bool InstallHook(void);
DEPLOYHOOK_API bool UnInstallHook(void);

Вызов проекта / exe:

[DllImport("DeployHook.dll",EntryPoint = "InstallHook",CharSet = CharSet::Auto, SetLastError = true)]   extern bool InstallHook(void);

// EntryPointNotFoundException избегается

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