cxq
cxq

Reputation: 31

Could I mix pimpl and C Interface like this?

I want maintain the back compatibility of my dll, though Pimpl pattern involved that the whole class must be exported,so the name mangling caused the different compilers can not be supported, in such a case, could I offer the C compatible interface together like follow?

in the public head:

#ifdef CPPDYNAMICLINKLIBRARY_EXPORTS
#   define SYMBOL_DECLSPEC __declspec(dllexport)
#   define SYMBOL_DEF
#else
#   define SYMBOL_DECLSPEC __declspec(dllimport)
#   define SYMBOL_DEF      __declspec(dllimport)
#endif

#ifdef _WIN32
   #define GRAPHICAPI __stdcall
#else
   #define GRAPHICAPI
#endif 

#ifdef __cplusplus
   #define EXTERN_C     extern "C"
#else
   #define EXTERN_C
#endif // __cplusplus

#ifdef __cplusplus
namespace myapi{
  struct SYMBOL_DECLSPEC  Graphics{
        Graphics();
       ~Graphics();
       void drawLine(int,int,int,int);
       void drawLine(Point,Point);
  private:
     struct Impl;
     const Impl* impl;
  }
}//end of myapi   
#endif // __cplusplus

struct Graphics;
typedef struct Graphics *PGraphics;

#ifdef __cplusplus
  extern "C" {
#endif
  SYMBOL_DEF  PGraphics GRAPHICAPI newGraphics();
  SYMBOL_DEF void GRAPHICAPI deleteGraphics(PGraphics);
  SYMBOL_DEF  int GRAPHICAPI Graphics_drawLine4(PGraphics,int,int,int,int);
  SYMBOL_DEF  int GRAPHICAPI Graphics_drawLine2(PGraphics,Point,Point);
#ifdef __cplusplus
  }
#endif 

Also in the dll project, the def file had following definitions:

exports
         newGraphics    @1
         deleteGraphics    @2
         Graphics_drawLine4    @3
         Graphics_drawLine2   @4

If you did not specify the ordinals in the def file, when you add new function like Graphics_drawArc, the function Graphics_drawArc would export before Graphics_drawLine4, the old app call Graphics_drawLine4 did call the Graphics_drawArc in fact ,result in crash.

Did above solution correct?

Upvotes: 2

Views: 151

Answers (1)

greatwolf
greatwolf

Reputation: 20878

I would hide the calling convention behind a macro in case you're porting this to a different platform where there's no notion of a __stdcall:

#ifdef _WIN32
#define GRAPHICAPI __stdcall
#else
#define GRAPHICAPI
#endif

SYMBOL_DEF  PGraphics GRAPHICAPI newGraphics();
SYMBOL_DEF void GRAPHICAPI deleteGraphics(PGraphics);
SYMBOL_DEF  int GRAPHICAPI Graphics_drawLine4(PGraphics,int,int,int,int);
SYMBOL_DEF  int GRAPHICAPI Graphics_drawLine2(PGraphics,Point,Point);

Other than that, I don't see any problems with it. Any ABI differences between different C++ compilers gets hidden away behind a C interface which has a fairly stable ABI.

Upvotes: 1

Related Questions