代码之家  ›  专栏  ›  技术社区  ›  OregonGhost

具有不同入口点的DllImport(不同项目中相同导入的不同DLL)

  •  0
  • OregonGhost  · 技术社区  · 17 年前

    作为我报告的后续行动 recent question 关于.NET Compact Framework调试,我目前正在尝试使用来自.NET Compact Framework和.NET Framework应用程序的OpenGL ES。我用 this wrapper ,它是为OpenGL ES和从libGLES_CM.dll导入而创建的。

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

    egl.GetDisplay() 而不是 egl.eglGetDisplay() . 它们是这样进口的:

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

    这在紧凑的框架上运行良好。在桌面项目中,抛出EntryPointNotFoundException,因为函数的名称如下 _eglGetDisplay@4 (旁注:WMD捕捉到blockquotes的Alt Gr+Q,这是德国键盘布局上的at符号。我不得不粘贴这个。)

    通过有条件地将字符串常量设置为空字符串或“\u1”,并将其与入口点名称连接,我成功地将下划线添加到桌面项目的函数名中,但没有添加到CF项目的函数名中,因此看起来如下所示:

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

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

    3 回复  |  直到 9 年前
        1
  •  4
  •   Richard    17 年前

    最简单的方法可能是让两个包装器类实现所有内部(.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模板的借口。。。

        2
  •  1
  •   vgru    17 年前

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

    你可以用 dumpbin.exe

        3
  •  0
  •   Someone Someone    17 年前

    使用#定义你的dllname_API 外部“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);
    

    正在调用Project/exe:

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

    //已避免EntryPointNotFoundException

    推荐文章