views:

1197

answers:

3

As a follow-up to my recent question about .NET Compact Framework debugging, I am currently trying to use OpenGL ES from both a .NET Compact Framework and a .NET Framework application. I use this wrapper, which has been created for OpenGL ES and imports from libGLES_CM.dll.

To make debugging easier, I created a .NET Framework application, recreated the import project for OpenGL ES and EGL with the same files (just building for Desktop framework), created constants for the DLL names so they'll import from libGLESv2.dll and libEGL.dll on Windows and from libGLES_CM.dll on CF. The DLLs are from the PowerVR OpenGL ES Emulation SDK (the target device has a PowerVR SGX) and are just a OpenGL ES wrapper around the real OpenGL implementation. And here comes the problem:

In the wrapper library, the OpenGL functions are in two static classes (gl and egl) and have the usual name, but without the gl/egl prefix, so calling them would be egl.GetDisplay() instead of egl.eglGetDisplay(). They are imported like this:

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

This works fine on the Compact Framework. In the desktop project, an EntryPointNotFoundException is thrown - because the functions are named like _eglGetDisplay@4 (side note: the WMD catches Alt-Gr+Q for blockquotes, which is the at symbol on German keyboard layouts. I had to paste this one.) according to Dependency Walker.

I managed to get the underscore added to the function name for the desktop project, but not for the CF one, by conditionally setting a string constant to empty string or "_", and concatenating it and the entry point name, so it looks like this:

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

No problem here. But the function is still not found, because the @4 (what exactly is that?) is missing. If I add the @4, this works, but since all functions have different values here, I had to do this by hand and likely the numbers wouldn't be correct for the CF version. Here comes the strange part:

If I just don't specify the entry point and instead name the function like it should be named, the import works fine! Now this is ugly because of the double prefix (static class name and function name), though I could get around this by just adding a wrapper for this one. Since I won't rely heavily on these functions (need only a rather simple 2D engine), this wouldn't be a problem, but it just doesn't feel right.

Why doesn't it work when specifying the entry point? What can I do to make it work like it should?

+1  A: 

A decorated name is a string created by the compiler during compilation of the function definition or prototype. "@4" in the name means it has total parameter length of 4 bytes (a 32-bit integer?).

You can use dumpbin.exe to get the decorated names from you .dll.

Groo
Then I'd still have to put them somewhere into the wrapper project. Doesn't appeal to me :)
OregonGhost
I just oversaw your explanation of the @4 thing. Yes, it's a 32-bit int in that case. +1 for that explanation, though it doesn't really help me ;)
OregonGhost
Thanks, sorry if it didn't help much. Hope you won't need to wrap too many methods! :)
Groo
No, shouldn't be too many, just basic 2D operations - it's just to get the 3D accelerator to be used. Maybe it'll be OpenVG in the end, but I guess the problem is the same then? :D
OregonGhost
+2  A: 

If the CF and desktop APIs have different entry points you need to work with this. It means you need different DllImport's defined.

Easiest may be to have two wrapper classes implementing all the internal (.NET) names, which call their import, then instantiate the correct one at runtime depending on platform. Then access the APIs through the common interface.

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(...)


EDIT: The interface and four classes should be creatable with a little code generation. Input file containing Name DesktopImport CFImport (maybe adding dll names if these vary). Would be an excuse to learn VS's T4 templating ...

Richard
I hoped it would be easier. In that case, I think I'll prefer importing them with the right name and without specifying the entry point, and then just putting a wrapper around them to make the name beautiful.
OregonGhost
@your edit: Yes, a co-worker suggested a similar solution. But as I already said, I won't need so many functions and will have to wrap them into my own small library anyway (you know, with classes and objects instead of free-floating functions)... We'll see ;)
OregonGhost
A: 

use #define yourdllname_API extern "C" __declspec(dllexport) to expose methods in your dll, avoiding function decoration that way you wont get above mentioned excepcion, example:

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);

Calling Project/exe:

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

//EntryPointNotFoundException avoided

That's unfortunately missing the point, since I don't have control over the imported DLLs. Thanks for your input anyway.
OregonGhost