0

作为我最近关于 .NET Compact Framework 调试的问题的后续,我目前正在尝试从 .NET Compact Framework 和 .NET Framework 应用程序中使用 OpenGL ES。我使用这个包装器,它是为 OpenGL ES 创建并从 libGLES_CM.dll 导入的。

为了使调试更容易,我创建了一个 .NET Framework 应用程序,使用相同的文件重新创建了 OpenGL ES 和 EGL 的导入项目(只是为桌面框架构建),为 DLL 名称创建了常量,以便它们将从 libGLESv2.dll 和Windows 上的 libEGL.dll 和 CF 上的 libGLES_CM.dll。DLL 来自 PowerVR OpenGL ES Emulation SDK(目标设备具有 PowerVR SGX)并且只是围绕真实 OpenGL 实现的 OpenGL ES 包装器。问题来了:

在包装器库中,OpenGL 函数位于两个静态类(gl 和 egl)中,并具有通常的名称,但没有 gl/egl 前缀,因此调用它们将egl.GetDisplay()代替egl.eglGetDisplay(). 它们是这样导入的:

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

这在 Compact Framework 上运行良好。根据_eglGetDisplay@4 _ _到 Dependency Walker。

我设法将下划线添加到桌面项目的函数名称中,但不是为 CF 项目,通过有条件地将字符串常量设置为空字符串或“_”,并将它和入口点名称连接起来,所以它看起来像这:

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

这里没问题。但是仍然找不到该函数,因为缺少@4(那到底是什么?)。如果我添加@4,这可行,但由于这里所有函数都有不同的值,我必须手动执行此操作,并且对于 CF 版本,这些数字可能不正确。奇怪的部分来了:

如果我只是不指定入口点,而是将函数命名为应该命名的函数,则导入工作正常!现在这很丑,因为有双重前缀(静态类名和函数名),尽管我可以通过为此添加一个包装器来解决这个问题。因为我不会严重依赖这些功能(只需要一个相当简单的 2D 引擎),这不会是一个问题,但它只是感觉不对。

为什么指定入口点时不起作用?我该怎么做才能让它像它应该的那样工作?

4

3 回答 3

4

如果 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模板的借口......

于 2009-03-17T13:06:24.137 回答
1

修饰名称是编译器在编译函数定义或原型期间创建的字符串。名称中的“@4”表示它的总参数长度为 4 个字节(一个 32 位整数?)。

您可以使用dumpbin.exe从您的 .dll 中获取修饰名称。

于 2009-03-17T13:05:07.523 回答
0

使用 #define yourdllname_API extern "C" __declspec(dllexport) 在你的 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 避免

于 2009-07-17T05:37:34.353 回答