作为我recent question关于.NET Compact Framework调试的后续内容,我目前正在尝试使用.NET Compact Framework和.NET Framework应用程序中的OpenGL ES。我使用this wrapper,它是为OpenGL ES创建的,并从libGLES_CM.dll导入。
为了简化调试,我创建了一个.NET Framework应用程序,使用相同的文件(仅为Desktop框架构建)重新创建了OpenGL ES和EGL的导入项目,为DLL名称创建了常量,因此它们将从libGLESv2导入Windows上的.dll和libEGL.dll以及CF上的libGLES_CM.dll。这些DLL来自PowerVR OpenGL ES Emulation SDK(目标设备有一个PowerVR SGX),它只是一个围绕真正的OpenGL实现的OpenGL ES包装器。这就是问题所在:
在包装器库中,OpenGL函数在两个静态类(gl和egl)中并且具有通常的名称,但没有gl / egl前缀,因此调用它们将是egl.GetDisplay()
而不是{{1 }}。它们是这样导入的:
egl.eglGetDisplay()
这在Compact Framework上运行良好。在桌面项目中,抛出了EntryPointNotFoundException - 因为函数的名称类似于[DllImport(DllName, EntryPoint = "eglGetDisplay")]
static extern IntPtr GetDisplay(EGLNativeDisplayType display_id);
(旁注:WMD捕获Alt-Gr + Q用于块引用,这是德语键盘布局上的at符号.I必须粘贴这个。)根据Dependency Walker。
我设法通过有条件地将字符串常量设置为空字符串或“_”,并将其连接到入口点名称,将下划线添加到桌面项目的函数名称中,但不添加到CF函数名称中,因此它看起来像这样:
_eglGetDisplay@4
这里没问题。但是仍然没有找到该功能,因为缺少了@ 4(究竟是什么?)。如果我添加@ 4,这是有效的,但由于所有函数在这里都有不同的值,我必须手动执行此操作,并且可能数字对于CF版本不正确。这是一个奇怪的部分:
如果我只是没有指定入口点而是将该函数命名为应该命名,那么导入工作正常!现在这很丑陋,因为双前缀(静态类名和函数名),虽然我可以通过添加这个包装器来解决这个问题。由于我不会严重依赖这些功能(只需要一个相当简单的2D引擎),这不会是一个问题,但它感觉不对。
为什么在指定入口点时不起作用?我该怎么做才能让它像它应该的那样工作?
答案 0 :(得分: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模板的借口......
答案 1 :(得分:1)
装饰名称是编译器在编译函数定义或原型期间创建的字符串。名称中的“@ 4”表示它的总参数长度为4个字节(32位整数?)。
您可以使用dumpbin.exe从您这里获取装饰名称。
答案 2 :(得分:0)
使用#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);
调用Project / exe:
[DllImport("DeployHook.dll",EntryPoint = "InstallHook",CharSet = CharSet::Auto, SetLastError = true)] extern bool InstallHook(void);
//避免使用EntryPointNotFoundException