- 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#CppNaiveApproach
C++ 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()