Using DLL's created with gcc with msvc7

Started by
7 comments, last by JHL 19 years, 6 months ago
I've written an engine in dev-c++ and wraped it in a dll I export the functions using a class consisting of all virtual functions, but I have another programer who I need to make an level editor he wants to use msvc7 but it can't seem to properly call the functions in the dll, now is this because they have different calling conventions and how do I fix it?
Advertisement
If youre using a library file for static linking, there may be problems (there were in VC++ 6 at least). Not sure about VS.NET.

I'm no expert so that may not hold up.

Are you doing static or dynamic linking?
its dynamic using LoadLibrary to load the dll then use GetProcAddress to get a function which returns a point to an instance of the interface class (the class full of virtual functions)
If you are exporting the entire class (for example by using something like class _declspec(dllexport)), then the answer is easy: forget it. Each compiler uses a different C++ name mangling scheme, and all are incompatible to each other.

If you go the COM-like way and export a simple C-style function, which will return a pointer to a C++ class, then it will work. You should use a common calling convention (cdecl is probably best), and you must force C-style name mangling by specifying extern "C" { } for the function(s) to export/import.
Hi,

to take the explanation a bit further ;) :

AFAIR the VS compiler puts the virtual function into the vtable "as comes" means that the functions are placed into the table in the same order you write them into the class definition.

The Borland C++ compiler for example does put them into the table in alphabetical order. The suborder is determined by the number of parameter and the parameter types.

I don't know how the gcc compiler does this but it should be possible to find that documented somewhere.

Metron
----------------------------------------http://www.sidema.be----------------------------------------
Try declaring your functions:

int __declspec(dllexport) MyFunction(int p1, int p2,....)

I use VS compiler for a lcc compiled dll and it works fine.

Hope it helps
_______________________The best conversation I had was over forty million years ago ... and that was with a coffee machine.
This is how I'm doing it the more COM like way (edited together for ease of displaying here) the exported functions seem to work fine its. The problem is when its calling the virtual class member functions, Metron may be right about it simply expecting different orders how can I find that out though, is there any way to force gcc to use the order I specify maybe like __attribute__((packed))

extern "C" {__declspec(dllexport) Mithrill_ApiInterface* CreateMithrillApiInterface();}Mithrill_ApiInterface* CreateMithrillApiInterface(){  return new Mithrill_ApiInterface;}class Mithrill_ApiInterface{  public:  virtual void SetUp(HWND,bool,dword,dword,dword,bool,bool,bool,bool,bool,const char*);  virtual void SetFPSControl(HWND);  virtual void TakeDown();  virtual void DisplayLoadScreen(const char*);  virtual void Run();  virtual void StartFrame();  virtual void EndFrame();  virtual void MoveViewInScreenSpace(float,float);  virtual void CenterViewOnUnit(void *Unit);  virtual void CenterViewOnPoint(float,float);  virtual void MoveViewAngle(float);  virtual void MoveViewDistance(float);  virtual void ResetView();  virtual void SetFieldofView(float);  virtual float GetFieldofView();  virtual void SendInputSingleLeftDown(int,int,bool,bool);  virtual void SendInputSingleRightDown(int,int,bool,bool);  virtual void SendInputSingleLeftUp(int,int,bool,bool);  virtual void SendInputSingleRightUp(int,int,bool,bool);  virtual void SendInputDoubleLeft(int,int,bool,bool);  virtual void SendInputDoubleRight(int,int,bool,bool);  virtual void SendInputMove(int,int);  virtual void NotitifyKeyPress(byte);  virtual void EnableWireFrameMode(bool);  virtual void SetMapCursorStatus(bool);  virtual void SetMapCursorProperties(float,float,float,bool);  virtual void LoadScenario(const char*,char**);  virtual void NewScenario(const char*,dword,dword);  virtual void SaveScenario(const char*,const char*);  virtual void UnLoadScenario();  virtual bool ScenarioLoaded();  virtual dword GetMapCount();  virtual const char* GetMapNamebyIndex(dword);  virtual void AddMap(const char*,dword,dword);  virtual void RemoveMap(const char*);  virtual void SwitchMapFocus(const char*);  virtual void RebuildGraphicsBuffers(int,int,int,int,bool);  virtual float GetTimePassed();  virtual short GetElevation(int,int);  virtual void SetElevation(int,int,short);  virtual float GetGroundLevel(float,float);  virtual void SetPrecip(int,int,byte,byte);  virtual byte GetPrecipDensity(int,int);  virtual byte GetSplatter(int,int,byte);  virtual void SetSplatter(int,int,byte,byte);  virtual void SetWater(int,int,const Mithrill_WaterProperties*);  virtual void GetWater(int,int,Mithrill_WaterProperties*);  virtual void SetGlobalLight(f3Point,f3Point,float,float,float);  virtual void GetGlobalLight(f3Point*,f3Point*,float*,float*,float*);  virtual void SetSkyTimeofDay(float);  virtual float GetSkyTimeofDay();  virtual void SetSkyColorPath(const char*);  virtual const char* GetSkyColorPath();  virtual void SetSkyStars(f3Point,float);  virtual void GetSkyStars(f3Point*,float*);  virtual void SetSkySunFlareIntensity(float);  virtual float GetSkySunFlareIntensity();  virtual void SetSkySatellitePath(int,const char*);  virtual const char* GetSkySatellitePath(int);  virtual void SetSkySatellitePosition(int,float,float);  virtual void GetSkySatellitePosition(int,float*,float*);  virtual void SetSkyCloudPath(const char*);  virtual const char* GetSkyCloudPath();  virtual void SetSkyCloudStretch(float);  virtual float GetSkyCloudStretch();  virtual void SetSkyCloudOpacity(float,float);  virtual void GetSkyCloudOpacity(float*,float*);  virtual void SetSkyCloudMovement(float,float);  virtual void GetSkyCloudMovement(float*,float*);  virtual void CreateCinematicCamera();  virtual void SetFlyMode(bool);  virtual void FlyModeRotate(dword,float);  virtual void FlyModeMove(float,float);  virtual float GetSplatterStretchFactor(dword);  virtual void SetSplatterStretchFactor(dword,float);  virtual const char* GetSplatterName(dword);  virtual void SetSplatterName(dword,const char*);  virtual const char* GetSplatterPath(dword);  virtual void SetSplatterPath(dword,const char*);  virtual int GetUnitCount();  virtual const char** GetTemplateNameList();  virtual dword GetTemplateNameListLength();  virtual void* CreateParticleEffect(const f3Point,const Mithrill_ParticleEffectProperties*);  virtual void DeleteParticleEffect(void*);  virtual void* GetParticleEffectUnderMouse(int,int);  virtual void SetParticleEffectPosition(const void*,const f3Point);  virtual f3Point GetParticleEffectPosition(const void*);  virtual float GetParticleEffectHover(const void*);  virtual void SetParticleEffectHover(const void*,float);  virtual void GetParticleEffectProperties(const void*,Mithrill_ParticleEffectProperties*);  virtual void SetParticleEffectProperties(const void*,const Mithrill_ParticleEffectProperties*);  virtual void RotateEffect(const void*, f3Point, float);  virtual dword GetParticleTextureCount();  virtual const char* GetParticleTextureName(dword);    virtual void* CreatePointLight(const f3Point,const float,const f3Point);  virtual void DeletePointLight(void*);  virtual void* GetPointLightUnderMouse(int,int);  virtual void SetPointLightPosition(const void*,const f3Point);  virtual f3Point GetPointLightPosition(const void*);  virtual void SetPointLightHover(const void*,const float);  virtual float GetPointLightHover(const void*);  virtual void SetPointLightRange(const void*,const float);  virtual float GetPointLightRange(const void*);  virtual void SetPointLightColor(const void*,const f3Point);  virtual f3Point GetPointLightColor(const void*);  virtual void SetUnitCursorType(const char*);  virtual void* GetCursorUnit();  virtual void* GetUnitUnderMouse(int,int);  virtual f3Point GetPositionUnderMouse(int,int,bool);  virtual void SetUnitPosition(void*,const f3Point);  virtual f3Point GetUnitPosition(const void*);  virtual void RotateUnit(void*,const f3Point,const float);  virtual void SetUnitRotation(void*,const float,const float,const float);  virtual void SetUnitScale(void*,const f3Point);  virtual f3Point GetUnitScale(const void*);  virtual void SetUnitPlayer(void*,byte);  virtual byte GetUnitPlayer(const void*,byte);  virtual void SetUnitHover(void*,const float);  virtual float GetUnitHover(const void*);  virtual f3Point GetUnitUpDirection(const void*);  virtual void ScaleUnit(void*,const f3Point);  virtual void* CreateUnitCursorClone();  virtual void* CreateUnit(const char*,const byte,const f3Point,const f3Point,const float,const float,const float,const float);  virtual void DeleteUnit(void*);  virtual void AutoAddWavesInRange(const int,const int,const int,float);  virtual void RemoveWavesInRange(const int,const int,const int);  virtual void SaveMeshReversed(void*);    virtual dword GetResolutionWidth();  virtual dword GetResolutionHeight();  virtual void SwitchMiniMap();  virtual void SaveMeshWithUnitModifications(void*);  virtual void SaveAnimationWithUnitModifications(void*);  virtual void UnitToNextMesh(void*);  virtual void UnitToNextAnimation(void*);  virtual void SaveAllWithUnitModifications(void*);  virtual void LoadModel_Mesh(const char*);  virtual void LoadModel_Texture(const char*);  virtual void LoadModel_Animation(const char*);  virtual const char* GetModel_Mesh_Name();  virtual const char* GetModel_Texture_Name();  virtual const char* GetModel_Animation_Name();  virtual void GetModel_Mesh_Info(dword*,dword*);  virtual void GetModel_Texture_Info(dword*,dword*);  virtual void GetModel_Animation_Info(dword*,dword*,float*);    virtual void ScreenShot();  virtual void SetUnitName(void*,const char*);  virtual const char* GetUnitName(void*);  virtual void* GetUnitByName(const char*);};
Quote:Original post by JHL
This is how I'm doing it the more COM like way (edited together for ease of displaying here) the exported functions seem to work fine its. The problem is when its calling the virtual class member functions, Metron may be right about it simply expecting different orders how can I find that out though, is there any way to force gcc to use the order I specify maybe like __attribute__((packed))

*** Source Snippet Removed ***


Hello,

The problem of your solution is that it heavily relies on the way objects are encoded and used by the compiler (do your compiler store this in ecx or on the stack? How does it pack the data? How does it treats the vtable? And so on. Since this is compiler dependant, you may experience very big problems - the kind of problem that even Dr. Wong Fei-Hung cannot resolve ;)

The way I found to solve the problem was to use the following structure:

// MyObject.hclass MyObject // private to the DLL{public:  MyObject();  int f();};// "export".htypedef void * MyObjectHandler;EXPORT MyObjectHandler MOH_create();EXPORT int MOH_f(MyObjectHandler moh);// "export".cppMyObjectHandler MOH_create(){  return reinterpret_cast<MyObjectHandler>(new MyObject());}int MOH_f(MyObjectHandler moh){   MyObject *p = reintrepret_cast<MyObject *>(moh);   return p->f();}


I agree with you, you loose the C++ interface since you use a C interface. But you ensure compiler compatibility while using an underlying C++ implementation.

Regards,
the main reason I didn't do pure functions in the first place was that I wanted it done dynamicly and I didn't wanna have to use get getprocaddress on dozens and dozens of functions.

My problem gets deeper though if I export only functions can this dll be used in C# as well

This topic is closed to new replies.

Advertisement