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

Как продолжение моего недавнего вопроса об отладке .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 (примечание: WMD ловит Alt-Gr + Q для цитат, что является символом at на немецких раскладках клавиатуры. Мне пришлось вставьте это.) в соответствии с Уокером Зависимости.

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

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

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

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

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

Ответы [ 3 ]

3 голосов
/ 17 марта 2009

Если у 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 ...

1 голос
/ 17 марта 2009

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

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

0 голосов
/ 17 июля 2009

используйте #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

...