Cetting lpVtbl of COM

BlitzMax Forums/BlitzMax Programming/Cetting lpVtbl of COM

Vertex(Posted 2006) [#1]
For example, the Interace in pub.mod/directx.mod/d3d7.bmx called IDirect3DDevice7.

How I can get the lpVtbl? lpVtbl is a Pointer(I think), of the table contains all adresses of the interface methods of IDirect3DDevice7 like Method SetRenderState(renderstate,value).

So I can get acces like MyDevice.lpVtbl.SetRenderState(MyDevice, D3DRENDERSTATE_LIGHTING, True)

Or it must be like:
Global Function SetRenderState:Int(MyDevice:IDirect3DDevice7, RenderStateType:Int, RenderState:Int)

SetRenderState = MyDevice.lpTbl[XYZ]
SetRenderState(MyDevice, D3DRENDERSTATE_LIGHTING, True)

But there are only methods defined in the IDirect3DDevice7 Interface not a member lpVtbl .

I hope you understand me :) need this, to overload some DirectX methods by changing the entry in the table to my own method/function.

cu olli

Edit: Oh, "Getting" as "Cetting" *rolleyes*


DStastny(Posted 2006) [#2]
I understand what your asking but never thought of really trying what your attempting but dont think it will work.

That considered the VTable pointer is the interface. So if you consider the IDirect3DDevice7 interface that is the VTable. So get instance of IDirect3Device7 and cast that to Int Ptr.

Here is what I am think although untested, that BMax can pull it off.

ie.
local d3d:IDirect3DDevice7= driver.GetDevice.. or something

local vtable:Int Ptr = Int Ptr(d3d)


You then have the Vtable as array of Int's. The offset to the function would be count the number of entries. Then cast that as a function pointer that matches the signature of the VTable exactly which means you have to handle THIS as impled first paramater.

vtable[22]=MySetRenderState(d3d:IDirect3DDevice7,RenderStateType:Int, RenderState:Int)

I just really dont think this will work, as I think the VTable is stored in a code segment and might not modifiable, I could be wrong as I never thought to try this.

Good luck.

Doug Stastny


Vertex(Posted 2006) [#3]
Ohh, the instance is the vtable. Hehe, yes thats very simple :)

Thank you!

I will post, if it work...

cu olli


DStastny(Posted 2006) [#4]
I made a slight mistake, the instances first pointer is to the VTables. So

say we have a Instance D3DDevice

local Vtable:Int Ptr = Int Ptr(Int Ptr(D3DDevice)[0]).

The first address of instance points to the Vtable. Sorry was late when I wrote that forgot the double dereference.

Doug Stastny


Vertex(Posted 2006) [#5]
Yeha, this works fine!

renderstate.bmx:
SuperStrict

Framework PUB.DirectX

' Don't remove this main function!
Function DllMain:Int(hinstDLL:Byte Ptr,fdwReason:Int,lpvReserved:Byte Ptr)"win32"
	Select fdwReason
		Case 1 ' DLL_PROCESS_ATTACH
		Case 2 ' DLL_THREAD_ATTACH
		Case 3 ' DLL_THREAD_DETACH
		Case 0 ' DLL_PROCESS_DETACH
	End Select

	Return True
End Function

' Don't remove the EXPORT comment!
Function ChangeShading:Int(Device:IDirect3DDevice7, Mode:Int) "win32" 'EXPORT
	Local VirtualTable:Int Ptr
	Local SetRenderState:Int(This:IDirect3DDevice7, RenderStateType:Int, ..
	      RenderState:Int) "win32"

	VirtualTable = Int Ptr(Int Ptr(Byte Ptr(Device))[0])
	SetRenderState = Byte Ptr(VirtualTable[20])
	Return SetRenderState(Device, D3DRS_SHADEMODE, Mode)
End Function

Function ChangeShading2:Int(Device:IDirect3DDevice7, Mode:Int) "win32" 'EXPORT
	Device.SetRenderState(D3DRS_SHADEMODE, Mode)
End Function


MakeDLL renderstate.bmx D:\BlitzMax


renderstate.decls:
.lib "renderstate.dll"
ChangeShading%(D3DDevice%, Mode%) : "ChangeShading"


Const D3DSHADE_FLAT    = 1
Const D3DSHADE_GOURAUD = 2
Const D3DSHADE_PHONG   = 3

Graphics3D 800,600,32,2

Global Device = Int(SystemProperty("Direct3DDevice7"))

Camera = CreateCamera()
PositionEntity Camera, 0, 0, -4.0

Light = CreateLight()
RotateEntity Light, 60, 30, 0
Sphere = CreateSphere()

While Not KeyHit(1)
   If KeyHit(2) ChangeShading Device, D3DSHADE_FLAT
   If KeyHit(3) ChangeShading Device, D3DSHADE_GOURAUD
   If KeyHit(4) ChangeShading Device, D3DSHADE_PHONG
   
   RenderWorld()
   Text 0, 0, "Press 1,2 or 3 to change the Render Style"
   Flip()
Wend

End


Now I will test, if I can overload this method.

And one question: How can I find out, what index has a method in the vtable?

cu olli

Edit: Get I right, when I say, that I must 3 + Method Place?
3 stands for the methods of IUnknown(QueryInterface, AddRef and Release). In IDirect3DDevice7 is SetRenderState the 18th Method has also an Index of 17. So the entry is 3 + 17 -> 20 and works fine. The same for IDirectDraw7 with CreateSurface.


DStastny(Posted 2006) [#6]
Very cool! I see you got to the vtable. The code you wrote BTW is how you deal with COM Objects in straight C code.

Well to see if it works try to stuff function pointer back into the VTABLE. I still thank that may cause a WEP error on systems that support WEP.

Oh what was MAKEDLL? I saw there is some code for making DLLs added to BMAX but havent seen MAKESDLL. Looks like it parses the Export comment?

I have played with making DLLs by manually linking but a tool that sets up the link instead of my batch file would be nice.

Doug Stastny


Vertex(Posted 2006) [#7]
MakeDLL: http://www.svenberra.net/MakeDLL.zip
Very nice and simple tool :)

Here is a test to overload SetRenderState.
DX7Overloader.bmx
SuperStrict

Framework PUB.DirectX

Const MB_OK              : Int   = $0
Const MB_ICONEXCLAMATION : Int   = $30

Extern "win32"
	Function MessageBoxA:Int(hWnd:Int, lpText$z, lpCaption$z, uType:Int)
End Extern

Const VTBL_SETRENDERSTATE : Int = 20

Global VirtualTable      : Int Ptr
Global OrgSetRenderState : Int(This:IDirect3DDevice7, RenderStateType:Int, RenderState:Int)

Function DllMain:Int(hinstDLL:Byte Ptr, fdwReason:Int, lpvReserved:Byte Ptr) "win32"
	Select fdwReason
		Case 1 ' DLL_PROCESS_ATTACH
		Case 2 ' DLL_THREAD_ATTACH
		Case 3 ' DLL_THREAD_DETACH
		Case 0 ' DLL_PROCESS_DETACH
	End Select

	Return True
End Function

Function StartRecording(Device:IDirect3DDevice7) "win32" 'EXPORT
	' Get virtual table from interface/instance
	VirtualTable = Int Ptr(Int Ptr(Byte Ptr(Device))[0])
	
	' Get original method
	OrgSetRenderState = Byte Ptr(VirtualTable[VTBL_SETRENDERSTATE])
	
	' Overload with own method
	VirtualTable[VTBL_SETRENDERSTATE] = Int(Byte Ptr(SetRenderState))
End Function

Function StopRecording:Int() "win32" 'EXPORT
	' Rewrite original method
	VirtualTable[VTBL_SETRENDERSTATE] = Int(Byte Ptr(OrgSetRenderState))
End Function

Function SetRenderState:Int(This:IDirect3DDevice7, RenderStateType:Int, RenderState:Int)
	' Display some information
	MessageBoxA(0, "RSType: "+RenderStateType+"; RS: "+RenderState, ..
	            "Overloaded method", MB_OK | MB_ICONEXCLAMATION)
	
	' Use original method
	Return OrgSetRenderState(This, RenderStateType, RenderState)
End Function


make.bat
MakeDLL DX7Overloader.bmx D:\BlitzMax
Pause


DX7Overloader.decls
.lib "DX7Overload.dll"
StartRecording(Device%)
StopRecording()


Test.bb
Graphics3D 640, 480, 0, 2

Global Device = Int(SystemProperty("Direct3DDevice7"))

Camera = CreateCamera()
PositionEntity(Camera, 0.0, 0.0, -4.0)

Light = CreateLight(2, Camera)

Cube = CreateCube()
RotateEntity Cube, 0.0, 45.0, 0.0

StartRecording(Device)
RenderWorld()
StopRecording()
Flip()

WaitKey()
End


It shows at first a message box with "RSType: 7; RS: 0" and than comes a memory access violation.

cu olli

Edit: If I forget: This is the idea of Tom(alias Tomspeed?)

Edit2: Global OrgSetRenderState : Int(This:IDirect3DDevice7, RenderStateType:Int, RenderState:Int) "win32" display 2 messageboxes and than comes the memory access violation


DStastny(Posted 2006) [#8]
This
Global OrgSetRenderState : Int(This:IDirect3DDevice7, RenderStateType:Int, RenderState:Int)


needs to be
Global OrgSetRenderState : Int(This:IDirect3DDevice7, RenderStateType:Int, RenderState:Int) "win32"


Doug Stastny


ozak(Posted 2006) [#9]
I thought such use of unholy magic was forbidden by the council long time ago :)


Vertex(Posted 2006) [#10]
Oh fuck, I forget "win32" 2x here this working example:
SuperStrict

Framework PUB.DirectX

Const MB_OK              : Int   = $0
Const MB_ICONEXCLAMATION : Int   = $30

Extern "win32"
	Function MessageBoxA:Int(hWnd:Int, lpText$z, lpCaption$z, uType:Int)
End Extern

Const VTBL_SETRENDERSTATE : Int = 20

Global VirtualTable      : Int Ptr
Global OrgSetRenderState : Int(This:IDirect3DDevice7, RenderStateType:Int, RenderState:Int) "win32"

Function DllMain:Int(hinstDLL:Byte Ptr, fdwReason:Int, lpvReserved:Byte Ptr) "win32"
	Select fdwReason
		Case 1 ' DLL_PROCESS_ATTACH
		Case 2 ' DLL_THREAD_ATTACH
		Case 3 ' DLL_THREAD_DETACH
		Case 0 ' DLL_PROCESS_DETACH
	End Select

	Return True
End Function

Function StartRecording(Device:IDirect3DDevice7) "win32" 'EXPORT
	' Get virtual table from interface/instance
	VirtualTable = Int Ptr(Int Ptr(Byte Ptr(Device))[0])
	
	' Get original method
	OrgSetRenderState = Byte Ptr(VirtualTable[VTBL_SETRENDERSTATE])
	
	' Overload with own method
	VirtualTable[VTBL_SETRENDERSTATE] = Int(Byte Ptr(SetRenderState))
End Function

Function StopRecording:Int() "win32" 'EXPORT
	' Rewrite original method
	VirtualTable[VTBL_SETRENDERSTATE] = Int(Byte Ptr(OrgSetRenderState))
End Function

Function SetRenderState:Int(This:IDirect3DDevice7, RenderStateType:Int, RenderState:Int)
	' Display some information
	MessageBoxA(0, "RSType: "+RenderStateType+"; RS: "+RenderState, ..
	            "Overloaded method", MB_OK | MB_ICONEXCLAMATION)
	
	' Use original method
	Return OrgSetRenderState(This, RenderStateType, RenderState)
End Function


Thaaaaaank youuuuuuu! :)

cu olli


DStastny(Posted 2006) [#11]
All that crazy voodoo. Everyday I am more impressed with what can be pulled off in BlitzMax.

Here is sample for those who want to interface C++ objects. It usings simple reference counted interfacing techniques. This also plays with VTable like Vertexes.

Still not sure if this is Vtable messing with is safe with all processors but the interfaced objects are fine. Need to try it out on a AMD Processor i think the have support for WEP.

C++ Code
#include <stdio.h>
// Sample interfaced class  cppobject.cpp
// Delecare an Interface for class
// note we using reference counting to implement cleanup
class IObject 
{
	public:
	    virtual int  _AddRef()=0;
	    virtual int  _Release()=0;
		virtual int  Add(int X,int Y)=0;  // This is important to be pure interface
};


// Class that implements the interface

class TestObject: public IObject
{
  private: 
	int refCount;
  public:
    TestObject() 
    { 
      refCount=1; 
      printf("Created TestObject\n");
	  fflush(stdout );
    }
    ~TestObject() 
    {
    	printf("Destroyed TestObject\n");
 	    fflush(stdout );
    }
    virtual int  _AddRef() { refCount++; return refCount; }
    virtual int  _Release() 
    { 
	  refCount--;
      if (refCount==0) delete this;
      return refCount;        
    
    }
	virtual int Add(int X,int Y)
	{
		return (X+Y);
	}

};

extern "C" {
  IObject* CreateTestObject() { return new TestObject(); }
}



BMax code to use the Interfaced Object
Superstrict
Import "cppobject.cpp"


Extern "C"
  Type IObject 
    Method _AddRef:int()
	Method _Release:Int()
	Method Add:Int(X:Int,Y:Int)
  End Type	  
  Function CreateTestObject:IObject()
End Extern

Function MyAdd:Int(obj:IObject , X:Int,Y:Int)
    Print "Subclassed-Subtracting"
	return X-Y
End Function


local _saveAdd:Int(obj:IObject , X:Int,Y:Int)
Print "Testing Interfaced C++ Object"
local obj:IObject= CreateTestObject()
print "1. Adding 1+2="+obj.Add(1,2)
local vtable:Int Ptr= Int Ptr(Int Ptr(Byte Ptr(obj))[0])
_saveAdd=Byte Ptr(vtable[2])
vtable[2]=Int(Byte Ptr(MyAdd))
print "2. Adding 1+2="+Obj.Add(1,2)
obj._Release()
obj:IObject= CreateTestObject()
print "3. Adding 1+2="+Obj.Add(1,2)
vtable[2]=Int(Byte Ptr(_saveAdd))
print "4. Adding 1+2="+Obj.Add(1,2)
obj._Release()
obj=null
print "Done"


All kinds of fun stuff. Can be done with this :)
I have some code on my HD somewhere that implements an interface by creating a VTable in code and passing it back to C++. It allows C++ code to call BlitzMax Objects. Cant marshal BMAX objects to C++ but can marshal an interface constructed in BMAX.

I need to look for it.

Doug Stastny


gman(Posted 2006) [#12]
greetings all :) Budman! hope all is well its been a while :) my interest is definately piqued by this vtable stuff for potential use in the Irrlicht mod.

if im understanding this correctly, you can essentially override a method by changing the vtable pointer to point to a BMAX function. is this a correct statement?

when trying the above code im getting an unhandled memory exception on the line:
vtable[2]=Int(Byte Ptr(MyAdd))

any thoughts on what i might be doing wrong? P4 with XP Pro.

is the vtable cross platform?

the only problem i see with the above is getting access to the object itself from within the remapped function. have you found a way to do this Budman?

thank you :)


DStastny(Posted 2006) [#13]
Hey GMAN!

Not sure why you are getting the Access Violation other than maybe your CPU supports DEP. Mis spoke and said WEP above(Duh! thinking wireless). I retried my posted code and it still works on my machine P4 xppro(What version of P4 do you have?). What version of BMax you using? Maybe somethings changed in regards to casting resoultion in BMAX, dont think the C++ compiler will mater.

Now I dont think hooking into the VTable at runtime is a good idea. I was just was helping with technically how it could be done. Not that I think its good idea :)

The part more usefull is the technique for interfaces. It should be cross platform. As its standard C++ implementaion of interfaces, however platform compilers may deal with it differently implementaion wise by platform. I have tested technique on MS Visual Studio DLL and GCC DLL, direct CPP in BMAX like above on windows and works fine. Havent booted the Linux box in a while.

As for VTables and getting Bmax Objects into C++. I think I know what your wanting to do with that in regards to Irrlicht. Infact I was looking at Irrlicht source the other day and noticed most of the interfaces for the objects are PURE so theorically your wrapper can be much easier. As I think you can remove alot of the wrapping layers to improve performance.

I do have code that implements a C++ interface in BMAX then passes the BlitzMax Objects interface back to the C++ code so the C++ calls the BMAX objects methods. So the area of Irrlicht that you want to derive scene nodes in BMAX should be quite doable. Mark and Skid might not like it, but it works and is hugely faster than handles and TMAP. And can be encapsulated enough to maintain if they decide to change the object implementation as it messes with the internals of the Garbage collection.

I havent shared it since its one thing to maintain my code another to give novices a tool to shoot themselves in head and complain to Mark and Skid, that 3rd party code broke when the updated the compiler.

If your around this weekend I can try and get togther example for you. As I am still lost trying to determine what 3d engine to use. If we can get the technique to work in Irrlicht I might swing back to that.

Doug Stastny


gman(Posted 2006) [#14]
hey Budman :) sorry for the delay. im deep into upgrading the Irrlicht mods and a few other minor things.

Not sure why you are getting the Access Violation other than maybe your CPU supports DEP.


that was it. went in through system properties and allowed the application. that fixed it. the fix in itself though makes this concept unviable IMO.

noticed most of the interfaces for the objects are PURE so theorically your wrapper can be much easier.


you are correct. i have not done this because i lose flexibility. you can only derive other externed types from externed types and you cant override any methods at all. there are cases where i change the parameters some to make it easier for BMAX. given that, im sure there are still some i could do that way.

If your around this weekend I can try and get togther example for you.


my apologies for not getting back quicker. i think the concept is good and id be interested in seeing it in action... but as always im pretty leery about changing anything in the BMAX base mods because it causes everyone using it to have that change.


DStastny(Posted 2006) [#15]
GMAN,

I figured as much with the DEP problem. Hopefully Vertex will read this thread so he sees what he was trying to do is not practicaly for deployment. Since all new processors support DEP. My old 3ghz doesnt which is why I coulndt reproduce, Although I think there is some windows API commands that can work around this.

As for my VTable stuff,

My solution doesnt change anything in Base Mods. Estentailly it works by defining a C++ PURE Interface and creating a VTABLE by hand then passing that VTable back into the C++ code. I am curious about DEP though. The trickery is helper function to get to the object that maps to the vtable. Would be easy if MAX had Object Ptr but Mark is pretty insitent that us meager programmers cant handle that, so we are faced with implementing our own.

I think Irrlicht if I remmber uses ISceneNode and you created a wrapper in C++ that refelcts back to a BlitzMax Object that can then be overriden.

This is estentailly the same thing where except you implement the interface with Blitz Max and create the VTABLE which you pass back to C++. You can then override the object in BMAX that creates the VTable.

My big concern and problem that I have been having with all the wrappers is speed hits due to context switching of the wrapping layers. What I mean by this is the overhead of all the procedure calls. Every time you call a method/function the processor has to save the context of the registers and stack so that when the procedure returns it gets restored. This is very expensive in CPU utilization. For example look at the Vector Library in Irrlicht. Just adding two vectors togther with BlitzMax is slow and even slower with the wrapper in place.

Only way to implement effective vector operations in Blitz Max Currently is to code the operations out in inline. ie. X,Y,Z,X1,Y1,Z1,X2,Y2,Z2. X=X1+X1,... etc.

This is PIA, and mistake driven not to mention hard to read.

I'll try to get togther example with Blitz Max implmenting a C++ Interface, and maybe you can test it out with DEP and see if it will help or not.


Doug Stastny


gman(Posted 2006) [#16]

I'll try to get togther example with Blitz Max implmenting a C++ Interface, and maybe you can test it out with DEP and see if it will help or not.


would be very much appreciated thank you.


DStastny(Posted 2006) [#17]
GMAN

Ok here is the sample I promised. Let me know if it works with DEP. If not I will recode the VTable implmentation. Since I am unsure if it has to be marked executable or not.

C++ Code.
#include <stdio.h>

extern "C" {
/* Simple Functions to get Object from Pointer and Back */                        
void* ObjectFrompVtbl(void* Vtbl) { return (void*)(*(((int*)Vtbl)+1));}
}


// Sample interfaced class  cppobject.cpp
// Delecare an Interface for class
// note we using reference counting to implement cleanup
class IObject 
{
	public:
	    virtual int  _AddRef()=0;
	    virtual int  _Release()=0;
		virtual int  Add(int X,int Y)=0;  // This is important to be pure interface
};

// Some Test functions to pass our BMAX interfaced object too
static IObject* instance=0;

extern "C" {
	void SetInstance(IObject* io) 
	{ 
		if (instance) instance->_Release();
		instance=0;
		if (io)
		{
			instance=io; 
			instance->_AddRef(); 
		}	
	}
	int AddInstance(int X,int Y)
	{
		if (instance)
		{
			return instance->Add(X,Y);
		}
		else return 0;
	}	

}


BMax Code
Superstrict
Import "cppobject.cpp"


Rem 
  Help Function to Tranlate VPtr to Object Handle
  This can be changed around to play with TMAP Handles but that is too slow
  This works and is based upon the structure of the Object in BMAX,  has been this way 
  since version 1.  Use to be able to do with Object Ptr but removed
end Rem

Extern "C"
  Function ObjectFrompVtbl:Object(pVtbl: Byte Ptr)
End Extern


Rem
	This is Blitz Max interface definition corrosponding to C++ Interface Definition
	
End Rem

Extern "C"
  Type IObject 
    Method _AddRef:int()
	Method _Release:Int()
	Method Add:Int(X:Int,Y:Int)
  End Type	  
End Extern

Rem
   This is our definitoon of the VTable
   Since I cant test this on machine with DEP, might need to implment differently
   not a big deal to change to work with DEP just need to make OS Specific calls to allocate 
   executeable chunk of memory   
End Rem

Type TIObjectVTable
 	Field _AddRef:Int(pVtbl:Byte Ptr)=vAddRef
	Field _Release:Int(pVtbl:Byte Ptr)=vRelease
	Field Add:Int(pVtbl:Byte Ptr,x:Int,Y:Int)=vAdd
End Type

Rem
	These functions implment the VTable and fixup the calls to the 
	Objects,  ideally this would be inline ASM to use a JMP instead of CALL but 
	here we are SOL so we need to deal with overhead of CALL 
End Rem

Function vAddRef:int(pVtbl:Byte Ptr)
	Return TIObject(ObjectFrompVtbl(pVtbl))._AddRef()
End Function
Function vRelease:Int(pVtbl:Byte Ptr)
	Return TIObject(ObjectFrompVtbl(pVtbl))._Release()
End Function
Function vAdd:Int(pVtbl:Byte Ptr,X:Int,Y:Int)
	Return TIObject(ObjectFrompVtbl(pVtbl)).Add(x,y)
End Function

Rem
   Only need one instance of VTABLE for all instances of Object 
End Rem
Global IObjectVTableVtblInstance:TIObjectVTable=New TIObjectVTable


Rem 
  Here is our base definition of the object that implments the VTABLE
End Rem

Type TIObject
    Field _Vtable: Byte Ptr ' these two variables must be in sequence
    Field _Handle: TIObject ' this allows us to implment multiple interfaces the fixup code gets the instance handle 
	Field _RefCount: Int    ' since we are interfaced _Ref counting is good idea to track our external allocations
	Method New()
	  Print "Created"
		 _Vtable= Byte Ptr(IObjectVTableVtblInstance)
	End Method
	Method Delete()
	  Print "Deleted"
	End Method
	Method IObject:IObject() Final
	    ' this code looks tricky but not too bad  IObject is not Blitz Object its a pointer
	    ' we are stuffing the VTable value into it and returning it
		Local u:IObject 
		Local b:Byte Ptr=Varptr(u)
		Int Ptr(b)[0]=Int(Varptr(_Vtable))
		' Add Ref since we gave out our VTable Ref we should add one to it
		' careful use here required since as soon as we give out object it sets count to 1
		_AddRef()
		Return u		
	End Method

	
	Method _AddRef:Int()  Final	
	    ' if we are giving out externa ref set our handle
	    ' this prevents GC as well as allows interface to be cracked
		If _RefCount=0 Then _Handle=Self
		_RefCount:+1	
		Print "RefCount"+_RefCount		
		Return _RefCount
	End Method
	Method _Release:Int() Final
		_RefCount:-1	
		' No more external references then we set handle to null for clean up
		If _RefCount=0 Then _Handle=Null
		Print "RefCount"+_RefCount
		Return _RefCount
	End Method
	Method Add:Int(x:Int,Y:Int)
		Return X+Y
	End Method
End Type


Type TIObjectSubtract extends TIObject
    Method Add:Int(X:Int,Y:Int)
		return X-Y
	End Method
End Type

' Test it
Extern "C"
	Function SetInstance(io:IObject) 
	Function AddInstance:Int(X:Int,Y:Int)
end Extern


Print "Test One"
Print "We play with interface locally in BMAX"
Print "Note: we dont have variable of TIObject but the interface"
global obj : IObject= (new TIObject).IObject()
Print "1+2="+obj.Add(1,2)
Print "Try to collect it"
GCCollect()
Print "Nope!"
Print "Release our Interface"
obj._Release()
Print "Released it so now should collect"
GCCollect()
Print "Success"
Print ""
Print "Test Two" 
Print "Externally with C"
obj =(new TIObject).IObject()
Print "Setting to external C Variable"
SetInstance(obj)
Print "3+4="+AddInstance(3,4)
Print "Release External Ref"
SetInstance(null)
Print "Release our local ref"
obj._Release()
GCCollect()
Print "Success"

Print "Test Three"
Print "Extending BMAX Object"
obj= (new TIObjectSubtract).IObject()
SetInstance(obj)
Print "Release our local we dont need anymore"
obj._Release()
GCCollect()
Print "Still alive since external reference valid"
Print "5+4="+AddInstance(3,4)
Print "Release our external Ref"
SetInstance(null)
GCCollect()
Print "Success"


Now the function that translates the VTable to Object can be changed to use handles but that layer of using TMAP with ObjecttoHandle HandletoObject plan and simple sucks. Mark really cant change this to fail and as long as used with the pattern here it cant fail or leak.

Let me know about the DEP issue though as that has me really curious as I have an OGRE wrapper that I have been working off and on using this interface technique to override OGRE Classes, and if the DEP causes a problem I will have to recode the allocation of the VTables.

Doug Stastny


gman(Posted 2006) [#18]
thank you very much for the detailed example. it did run fine on the machine that had the issue and interestingly enough, i didnt have to select the EXE to allow it as i did the other one. i would like to toggle the option again and try it one more time on that machine. will have to wait a couple days though until im at that machine again.

i have not done a deep analysis of the code yet, but i do have a question. what if there are methods on the underlying object you dont want to override but still be able to run the default code? ISceneNode from Irrlicht for example, has base methods on the interface that i would want to keep.


Defoc8(Posted 2006) [#19]
erm..perhaps im mistaken - but i thought making dll's with
bmax was forbidden? - hmmm...if that is infact what your
doing, you might want to check up with BRL to make sure..

..anyhoO..back to playing about in fasm ;)


DStastny(Posted 2006) [#20]
Gman, cool thanks for the test. I figured it wouldnt have the same problem as the allocated memory should be ok. I think the issue as I understand with DEP is that the datasegments produced by the compilers VTABLE are marked readonly hence the DEP when messing with the VTable.

As for dealing with Irrlicht, I was looking at it again today and the objects although he calls them interfaces there not PURE. He has destructors and such.

What I was thinking for Irrlicht would be to use the interface as a callback mechinism to a base object you create like you do now, but instead of all the function mapping you use the interface as delagte style implementation.



Defoc8, I am not making the DLL with BMAX, I am passing interfaces to my BMAX objects back to my DLLs and C++ Objects in obj file. It allows me to for implement delgate patterns to my own engine code based upon OGRE. This allows for a true OOP interaction with OGRE not a function based wrapper.

I think BRL is going to change the DLL license thing as they have been inconsistent. The license changed after release, my orignal license had no stipulation and think the issue is not with writting DLLs but wrapping thier code and selling a DLL. ie. wrapping Max2d and selling it as your own code. If you look at the change log in Appstub.c youll see there is comments for adding support for DLLs.

Prior to that change the Garbage collector was not being initialized so DLLs made with MAX that used objects would leak. but simple function DLLs would be fine.

Oh and if you get a fast otimized matrix library written in ASM I might be interested :)

Doug Stastny