- CFF Explorer VIII: http://www.ntcore.com/
 - PureBasic 5.11 beta 1 (x86)
 - Visual Studio 2010 Ultimate (x86)
 
Warnning: This is not meant to be a tutorial!
This is how i demangle C++ symbols:

This is the Helper.pbi you see being included:
Code: Select all
#DLL_PATH = #PB_Compiler_FilePath + "C_PLUS\Release\"
#DLL_NAME = #DLL_PATH + "C_PLUS.dll"
; http://msdn.microsoft.com/en-us/library/ek8tkfbw%28v=vs.80%29.aspx
Macro thiscall_inline(this)
  EnableASM
  MOV ECX, this
  DisableASM
EndMacro
Macro thiscall_var(this)
  !mov ecx, [p.v_#this]
EndMacro
Macro thiscall_ptr(this)
  !mov ecx, [p.p_#this]
EndMacro
; more info here -> http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL#CppNaiveApproachC++ DLL:
Code: Select all
/************************************************************************/
/* Example 1                                                            */
/************************************************************************/
class __declspec(dllexport) CMath
{
public:
	CMath() {};
	~CMath() 
	{ 
		char buf[1000];
		sprintf(buf , "Hello from destructor\nthis: 0x%X", this);
		MessageBoxA(0, buf, "hi", 0); 
	};
	int add(int a, int b) { return a + b; };
	int subtract(int a, int b) { return a - b; };
	void MsgBox(char * Title)
	{
		char buf[1000];
		sprintf(buf , "this: 0x%X", this);
		MessageBoxA(0, buf, Title, 0);
	}
private:
	int someval;
};Code: Select all
XIncludeFile "Helper.pbi"
Prototype.i P_New_CMath()
Prototype  P_Free_CMath()
Prototype.l P_CMath_add(a.l, b.l)
Prototype.l P_CMath_subtract(a.l, b.l)
Prototype P_CMath_MsgBox(Title.p-ascii)
Global New_CMath.P_New_CMath
Global Free_CMath.P_Free_CMath
Global CMath_add.P_CMath_add
Global CMath_subtract.P_CMath_subtract
Global CMath_MsgBox.P_CMath_MsgBox
Procedure.i LoadCDLL(Filename.s)
  Protected hLib.i
  
  hLib = OpenLibrary(#PB_Any, Filename)
  If hLib
    New_CMath = GetFunction(hLib, "??0CMath@@QAE@XZ")
    Free_CMath = GetFunction(hLib, "??1CMath@@QAE@XZ")
                             
    CMath_add = GetFunction(hLib, "?add@CMath@@QAEHHH@Z")
    CMath_subtract = GetFunction(hLib, "?subtract@CMath@@QAEHHH@Z")
    CMath_MsgBox = GetFunction(hLib, "?MsgBox@CMath@@QAEXPAD@Z")
  EndIf
  
  ProcedureReturn hLib
EndProcedure
Procedure Test_CMath()
  Protected pCMath.i
  Protected resu.l
  
  pCMath = New_CMath()
  Debug "pCMath: "+Hex(pCMath)
  
  ; let's test the add method
  thiscall_var(pCMath)
  resu = CMath_add(5, 9)
  Debug "resu - CMath_add(5, 5) : "+Str(resu)
  
  ; let's test the subtract method
  thiscall_var(pCMath)
  resu = CMath_subtract(5, 2)
  Debug "resu -  CMath_subtract(5, 2) : "+Str(resu)
  
  ; let's test the MsgBox Method
  thiscall_var(pCMath)
  CMath_MsgBox("hello world!")
  
  ; let's call the destructor
  thiscall_var(pCMath)
  Free_CMath()
  
  Debug "Test Complete!"
EndProcedure
If Not LoadCDLL(#DLL_NAME)
  Debug "Failed to load: "+Chr(34)+#DLL_NAME+Chr(34)
  CallDebugger
EndIf
Test_CMath()C++ DLL:
Code: Select all
/************************************************************************/
/* Example 2                                                            */
/************************************************************************/
class CPosition
{
public:
	CPosition() {};
	CPosition(float x, float y, float z) : x(x), y(y), z(z) {};
	~CPosition() {};
	float GetX() { return x; };
	float GetY() { return y; };
	float GetZ() { return z; };
private:
	float x, y, z;
};
// Interface DLL
class CPlayer
{
public:
	CPlayer() {
		strcpy(Name, "Player1");
		score = 5;
	};
	virtual ~CPlayer() 
	{ 
		char buf[1000];
		sprintf(buf , "Hello from destructor\nthis: 0x%X", this);
		MessageBoxA(0, buf, "hi", 0); 
	};
	virtual CPosition GetPosRandom() { return CPosition(5.0, 3.0, 2.0); };
	virtual char * GetPlayerName() { return Name; };
	virtual int SetPlayerName(char * NewName) 
	{
		strcpy(Name, NewName);
		return 1;
	};
	virtual int GetScore() { return score; };
private:
	char Name[256];
	int score;
};
extern "C" __declspec(dllexport) CPlayer * __stdcall CreatePlayerInterface()
{
	return new CPlayer;
}Code: Select all
XIncludeFile "Helper.pbi"
Prototype.i P_CreatePlayerInterface()
Prototype P_CPlayer_Destructor(unknown.a=1)
Prototype.i P_CPlayer_GetPosRandom(*OutPos)
Prototype.i P_CPlayer_GetPlayerName()
Prototype.l P_CPlayer_SetPlayerName(*NewName) ; ascii
Prototype.l P_CPlayer_GetScore()
Global CreatePlayerInterface.P_CreatePlayerInterface
Structure CPlayer_vTable Align #PB_Structure_AlignC
  Destructor.P_CPlayer_Destructor
  GetPosRandom.P_CPlayer_GetPosRandom
  GetPlayerName.P_CPlayer_GetPlayerName
  SetPlayerName.P_CPlayer_SetPlayerName
  GetScore.P_CPlayer_GetScore
EndStructure
Structure CPlayer Align #PB_Structure_AlignC
  *vTable.CPlayer_vTable
  Name.a[256]
  score.l
EndStructure
Structure CPosition Align #PB_Structure_AlignC
  x.f : y.f : z.f
EndStructure
Procedure.i LoadCDLL(Filename.s)
  Protected hLib.i
  
  hLib = OpenLibrary(#PB_Any, Filename)
  If hLib
    CreatePlayerInterface = GetFunction(hLib, "_CreatePlayerInterface@0")
  EndIf
  
  ProcedureReturn hLib
EndProcedure
Procedure Test_CPlayer()
  Protected *pCPlayer.CPlayer
  Protected resu.I
  Protected MyPos.CPosition
  
  *pCPlayer = CreatePlayerInterface()
  Debug "*pCPlayer: "+Hex(*pCPlayer)
  
  ; let's get the player position
  thiscall_ptr(pCPlayer)
  *pCPlayer\vTable\GetPosRandom(@MyPos)
  
  Debug "My Position: x: "+StrF(MyPos\x) + " | y: "+StrF(MyPos\y)+ " | z: "+StrF(MyPos\z)
  
  ; let's get the player name
  thiscall_ptr(pCPlayer)
  resu = *pCPlayer\vTable\GetPlayerName()
  
  Debug "Player Name: "+PeekS(resu, -1, #PB_Ascii)
  
  ; let's set a new player name
  thiscall_ptr(pCPlayer)
  *pCPlayer\vTable\SetPlayerName(@"Toni6")
  
  ; let's print the new name directly from the structure
  Debug "New Player Name: "+PeekS(@*pCPlayer\Name, -1, #PB_Ascii)
  
  ; now let's get the player score
  thiscall_ptr(pCPlayer)
  resu = *pCPlayer\vTable\GetScore()
  
  Debug "Player score: "+Str(resu)
  
  ; let's call the destructor to free the memory
  ;thiscall_ptr(pCPlayer)
  thiscall_inline(*pCPlayer)
  *pCPlayer\vTable\Destructor()
  
  Debug "Test Complete!"
EndProcedure
If Not LoadCDLL(#DLL_NAME)
  Debug "Failed to load: "+Chr(34)+#DLL_NAME+Chr(34)
  CallDebugger
EndIf
Test_CPlayer()C++ DLL:
Code: Select all
/************************************************************************/
/* Example 3                                                            */
/************************************************************************/
class __declspec(dllexport) CPlayerEx
{
public:
	CPlayerEx() : kills(0) {
		strcpy(Name, "Player9");
	};
	virtual ~CPlayerEx() 
	{ 
		char buf[1000];
		sprintf(buf , "Hello from destructor\nthis: 0x%X", this);
		MessageBoxA(0, buf, "hi", 0); 
	};
	int GetKills() { return kills; };
	virtual void SetKills(int val) { kills = val; };
	void KillPlayer() {
		MessageBoxA(0, "Player killed!", "dead", 0); 
	};
private:
	char Name[256];
	int kills;
};Code: Select all
XIncludeFile "Helper.pbi"
Prototype.i P_CPlayerEx_New()
Prototype P_CPlayerEx_Destructor(unknown.a=1)
Prototype.l P_CPlayerEx_GetKills()
Prototype P_CPlayerEx_SetKills(val.l)
Prototype P_CPlayerEx_KillPlayer()
Structure CPlayerEx_vTable Align #PB_Structure_AlignC
  Destructor.P_CPlayerEx_Destructor
  SetKills.P_CPlayerEx_SetKills
EndStructure
Structure CPlayerEx Align #PB_Structure_AlignC
  *vTable.CPlayerEx_vTable
  Name.a[256]
  kills.l
EndStructure
Global CPlayerEx_New.P_CPlayerEx_New
Global CPlayerEx_GetKills.P_CPlayerEx_GetKills
Global CPlayerEx_KillPlayer.P_CPlayerEx_KillPlayer
Procedure.i LoadCDLL(Filename.s)
  Protected hLib.i
  
  hLib = OpenLibrary(#PB_Any, Filename)
  If hLib
    CPlayerEx_New = GetFunction(hLib, "??0CPlayerEx@@QAE@XZ")
    CPlayerEx_GetKills = GetFunction(hLib, "?GetKills@CPlayerEx@@QAEHXZ")
    CPlayerEx_KillPlayer = GetFunction(hLib, "?KillPlayer@CPlayerEx@@QAEXXZ")
  EndIf
  
  ProcedureReturn hLib
EndProcedure
Procedure Test_CPlayerEx()
  Protected *pCPlayerEx.CPlayerEx
  Protected resu.i
  
  *pCPlayerEx = CPlayerEx_New()
  Debug "*pCPlayerEx: "+Hex(*pCPlayerEx)
  
  ; set the player kills
  thiscall_ptr(pCPlayerEx)
  *pCPlayerEx\vTable\SetKills(9)
  
  ; get the player kills
  thiscall_ptr(pCPlayerEx)
  resu = CPlayerEx_GetKills()
  Debug "Player Kills: "+Str(resu)
  
  ; kill the player
  thiscall_ptr(pCPlayerEx)
  CPlayerEx_KillPlayer()
  
  ; show the player name
  Debug PeekS(@*pCPlayerEx\Name, -1, #PB_Ascii) + " has been killed!"
  
  ; now let's free the class
  thiscall_ptr(pCPlayerEx)
  *pCPlayerEx\vTable\Destructor()
  
  Debug "Test Complete!"
EndProcedure
If Not LoadCDLL(#DLL_NAME)
  Debug "Failed to load: "+Chr(34)+#DLL_NAME+Chr(34)
  CallDebugger
EndIf
Test_CPlayerEx()C++ DLL:
Code: Select all
/************************************************************************/
/* Example 4                                                            */
/************************************************************************/
class CDog
{
public:
	CDog() : m_nAge(123) {};
	virtual __stdcall ~CDog()
	{
		char buf[1000];
		sprintf(buf , "Hello from destructor\nthis: 0x%X", this);
		MessageBoxA(0, buf, "hi", 0); 
	}
	virtual void __stdcall SetAge(int age) { m_nAge = age; } ;
	virtual int __stdcall GetAge() { return m_nAge; };
	virtual void __stdcall Kill() { MessageBoxA(0,"The dog is dead!", "Dead", 0); };
private:
	int m_nAge;
};
extern "C" __declspec(dllexport) CDog * __stdcall CreateDogInterface()
{
	return new CDog;
}
Code: Select all
XIncludeFile "Helper.pbi"
Interface CDog
  Destructor()
  SetAge(age.l)
  GetAge.l()
  Kill()
EndInterface
Prototype P_CreateDogInterface()
Global CreateDogInterface.P_CreateDogInterface
Procedure.i LoadCDLL(Filename.s)
  Protected hLib.i
  
  hLib = OpenLibrary(#PB_Any, Filename)
  If hLib
    CreateDogInterface = GetFunction(hLib, "_CreateDogInterface@0")
  EndIf
  
  ProcedureReturn hLib
EndProcedure
Procedure Test_CDog()
  Protected myDog.CDog
  
  myDog = CreateDogInterface()
  Debug "myDog: "+Hex(myDog)
  
  ; let's set the dog age
  myDog\SetAge(9)
  
  ; get the dog age
  Debug "Dog age: "+Str(myDog\GetAge())
  
  ; kill the poor dog...
  myDog\Kill()
  Debug "The doog his dead!"
  
  ; let's get age directly from memory
  Debug "The doog has died at: "+Str(PeekL(myDog + 4))
  
  ; free the class
  myDog\Destructor()
  
  Debug "Test Complete!"
EndProcedure
If Not LoadCDLL(#DLL_NAME)
  Debug "Failed to load: "+Chr(34)+#DLL_NAME+Chr(34)
  CallDebugger
EndIf
Test_CDog()

