News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

object cannot be called error?

Started by Emil_halim, November 09, 2010, 08:40:49 PM

Previous topic - Next topic

Emil_halim

hi all

i am trying to implement a directx9 class , so that calling interface method is easy and readable.

i putted a macro inside the class , i get  object cannot be called error when calling that macro.

so what is wrong here?

here is the class code snippet

type
      Direct3D9:class
             
   var
        g_pD3D : pointer to IDirect3D9;
           procedure create;
           method CleanUp;
           #macro CreateDevice( args[] );
               mov( g_pD3D , eax);
           mov([eax], eax);
           (type IDirect3D9 [eax]).CreateDevice(args[]);
           #endmacro
     
      endclass;

static
vmt( Direct3D9 );
 
procedure Direct3D9.create;
begin create;

push( eax );
if( esi = 0 ) then

malloc( @size( Direct3D9 ));
mov( eax, esi );

endif;
mov( &Direct3D9._VMT_, this._pVMT_ );

mov(Direct3DCreate9(D3D_SDK_VERSION),this.g_pD3D);

pop( eax );
end create; 

method Direct3D9.CleanUp;
begin CleanUp;

if (this.g_pD3D <> NULL) then
DXCall(this.g_pD3D, Release);
endif;

end CleanUp;


here is the declaration and calling 

static
  g_pD3D : Direct3D9;

....

    g_pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
  hwnd,
  D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  &d3dpp, &g_pd3dDevice ) ;


the last line gives the error,
any help please?

Sevag.K

i'm not quiet sure what's going on here, it looks like you're recursively calling the macro without any object being created.

what exactly do you want your CreateDevice macro to do?

Emil_halim

actually , i have created the object by calling

g_pD3D.create();


ok, exactly i want to call the CreateDevice method of IDirect3D9 interface by calling a macro that
defined inside the class , instead of calling DXCall macro.

i.g

i want to call the CreateDevice just like that

g_pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,hwnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp, &g_pd3dDevice );


instead of calling

DXCall(g_pD3D, CreateDevice,D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hwnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&g_pd3dDevice);


i am using a macro instead of procedure , for the sake of speed.

hope things are more clear now.

Sevag.K

the DXCall macro implementation on HLA was designed to make it easier to access C++ classes from HLA.
you're mixing interfaces styled after C++ classes with HLA classes.  i can tell you, you're going to have a heap of problems with this approach.

the macro call isn't really going to help you with speed.  in your object for example, you're going to have to declare all the Direct3D9 methods you plan to call.  in the end, even if you figure it out, you'll end up with an object calling an object which will be significant hit on performance.

taking an interface for example:


IDirect3D9 :
record
QueryInterface : procedure;
AddRef : procedure(p:dword);
Release : procedure(p:dword);

/*** IDirect3D9 methods ***/
RegisterSoftwareDevice : procedure(p:dword) ;@stdcall;
GetAdapterCount : procedure(p:dword) ;@stdcall;
GetAdapterIdentifier : procedure(p:dword) ; @stdcall;
GetAdapterModeCount :procedure(p:dword) ;@stdcall;
EnumAdapterModes :procedure(p:dword) ;@stdcall;
GetAdapterDisplayMode:procedure(p:dword) ;@stdcall;
CheckDeviceType :procedure (p:dword);@stdcall;
CheckDeviceFormat :procedure(p:dword) ;@stdcall;
CheckDeviceMultiSampleType :procedure(p:dword) ;@stdcall;
CheckDepthStencilMatch :procedure (p:dword);@stdcall;
CheckDeviceFormatConversion :procedure(p:dword) ;@stdcall;
GetDeviceCaps :procedure (p:dword);@stdcall;
GetAdapterMonitor :procedure (p:dword);@stdcall;
CreateDevice : procedure(p:dword;a:dword;b:dword;c:dword;d:dword;var e:dword;var f:dword) ;@stdcall;
endrecord;


you'll need a method declaration for each of the methods you plan to use listed in this record, then you have to figure out how to deal with C++ object settlement with your method!

i think you would be better off declaring interface pointers and calling via DXCall.

i can offer you a little help on your macro.
           #macro CreateDevice( args[] );
               mov( g_pD3D , eax);
           mov([eax], eax);
           (type IDirect3D9 [eax]).CreateDevice(args[]);
           #endmacro


first, the reasons why it won't work.
g_pD3D is a class automatic variable, hla can't find it outside of class procedures/methods.
and you can't pass args[] argument in that way.  CreateDevice has a specific number of arguments, so declare them individually and pass them down to the procedure call, but again, since you need to do this from a class method/procedure, there is no point to the macro.

addendum: if you haven't seen it already, i have a directX demo on my site written by Bernd Kastenholtz that uses the interfaces.  it's a bit outdated, so if you download it, you'll have to add this line on top of every file that shows 'assign' error.

#include("macros/assign.hhf")

Emil_halim

i am agree with you , calling Object from object is killing the speed.

so the CleanUp method of me class does that , i.e call CleanUp which call interface by using DXCall.

so that i was trying to implement it by macro which emit the desired instructions directly to asm file,
so there is no calling object from another one.

already downloaded the directx demo from your site and included assign macro as you mentioned , the CreateDevice
macro was taken from DXCall and adapted by me.

if i made the g_pD3D as a static variable in my class, can i call it as a method or a procedure of the class?

i sow that , calling macro of a class , worked correctly in DemoFile.hla , see the calling of put macro.

finally , you know i came from c++ code style , and i preffer the class calling approach instead of
asm style , so i am thinking in another trick. which is.

instead of using a record to represent as interface , i will make an enumeration that holds the names
of interface methods , and calling them by the following macro


#macro CreateDevice( args[] );
       mov( g_pD3D , eax);
       mov([eax], eax);
       pushing all args
       call (type dword[eax+.CreateDevice]);
#endmacro 



and yes i will make a macro for each interface method ?

it is just an idea , i will try to make it , any suggestions are welcome.

Sevag.K

Quote from: Emil_halim on November 10, 2010, 09:34:46 PM
i am agree with you , calling Object from object is killing the speed.

so the CleanUp method of me class does that , i.e call CleanUp which call interface by using DXCall.

so that i was trying to implement it by macro which emit the desired instructions directly to asm file,
so there is no calling object from another one.

that's what the interface-records and DXCall macro are for :)

if you're going to use classes in hla, i don't think it can be done without having a wrapper object.  now that i've thought about it some more, you wouldn't really have objects calling objects, since the wrapper interface undercuts the C++ object interface by directly calling the methods.


Quote
already downloaded the directx demo from your site and included assign macro as you mentioned , the CreateDevice
macro was taken from DXCall and adapted by me.

if i made the g_pD3D as a static variable in my class, can i call it as a method or a procedure of the class?

if you made it static you can assess it from macros, but you will not have a unique g_pD3D for each object of the class, there will be only one g_pD3D for the entire class.  i don't know if this makes a difference, i'm not too experienced with directX.

Quote
i sow that , calling macro of a class , worked correctly in DemoFile.hla , see the calling of put macro.

finally , you know i came from c++ code style , and i preffer the class calling approach instead of
asm style , so i am thinking in another trick. which is.

instead of using a record to represent as interface , i will make an enumeration that holds the names
of interface methods , and calling them by the following macro


#macro CreateDevice( args[] );
       mov( g_pD3D , eax);
       mov([eax], eax);
       pushing all args
       call (type dword[eax+.CreateDevice]);
#endmacro 



and yes i will make a macro for each interface method ?

it is just an idea , i will try to make it , any suggestions are welcome.


i think the most robust way of doing this is also going to take the most work.  you would have to recreate the entire C++ class interface in hla class and call the C++ interface functions from your class procedures/methods.
so you were on the right track above, but instead of macros, you will declare methods for every interface and call the interface from your method by passing it the proper pointers.

something like this;

   Direct3D9:class
             
      var
        g_pD3D : pointer to IDirect3D9;
      procedure create;
      method CleanUp;
      method CreateDevice( a:dword;b:dword;c:dword;d:dword;var e:dword;var f:dword);
     
   endclass;
     
   ...
   
   method Direct3D9.CreateDevice( a:dword;b:dword;c:dword;d:dword;var e:dword;var f:dword);
   begin CreateDevice;
      mov( this.g_pD3D, eax );
      mov( [eax], eax );
      ( type IDirect3D9[eax]).CreateDevice( a, b, c, d, e, f );
   end CreateDevice;


consider the above pseudo code as i'm just tossing ideas, i don't know how well they'll work.


if you're going to use generic macros with a static g_pD3D pointer, you might as well stick with the DXcall macro, unless you're happy with having 1 g_pD3D pointer shared by all the objects of the class.

Emil_halim

oh......no.........

that drive me crazy!!!!!!!!!!!!

i really did not understand how to put a macro inside a class then call that macro as you make with
a procedure or a method, as mentioned in hla manual ??

so i am trying it in the following code

program macroClass;

#include( "stdlib.hhf" );

type

    Counte:
            class
   
                static
                    Cnt:int32 := 0;
                   
                procedure create;
                               
                #macro Display;
                       stdout.put( "Count=", Counte.Cnt, nl );
                #endmacro
               
            endclass;

    procedure Counte.create; @nodisplay; @noframe;
    begin create;

        push( eax );
        if( esi = 0 ) then
       
            malloc( @size( Counte ));
            mov( eax, esi );
           
        endif;
        mov( &Counte._VMT_, this._pVMT_ );
        inc( this.Cnt );
        pop( eax );
        ret();
       
    end create;
   
static
   vmt( Counte );


static
    b:  Counte;
     
begin macroClass;
   
    b.create();   
    Counte.Display();

end macroClass;


but it does not compiled , gives undefined symbol. Near: << Display >>

in the DemoFile it declare f as a file class , then it call the put macro as a calling procedure 

program DemoFile;
#include( "stdlib.hhf" );

static
f:file;       
   
begin DemoFile;

f.create(); // Constructor for file class.
f.openNew( "Data.txt" );
f.put( "Hello World" nl );
f.close();

f.open( "Data.txt", fileio.r );
f.a_gets();
stdout.put( "String=", (type string eax) );
strfree( eax );
f.close();

       
end DemoFile;



so why it complies ok in democlass and gives undefined symbol in my class , i declare the macro
inside my class just like the file_t class declare a put macro inside it , see fileio.hhf header. 

can any one supply an example that show how to make that.

Sevag.K


macro calling has different rules from procedure calling.  if there are no macro arguments, you don't put in the empty brackets.

also, declare the macro before the class procedures/methods.


program macroClass;

#include( "stdlib.hhf" );

type

    Counte:
            class
   
                static
                    Cnt:int32 := 0;

                #macro Display;
                       stdout.put( "Count=", Counte.Cnt, nl );
                #endmacro
                   
                procedure create;
                               
               
            endclass;

    procedure Counte.create; @nodisplay; @noframe;
    begin create;

        push( eax );
        if( esi = 0 ) then
       
            malloc( @size( Counte ));
            mov( eax, esi );
           
        endif;
        mov( &Counte._VMT_, this._pVMT_ );
        inc( this.Cnt );
        pop( eax );
        ret();
       
    end create;
   
static
   vmt( Counte );


static
    b:  Counte;
     
begin macroClass;
   
    b.create();   
    Counte.Display;

end macroClass;



Emil_halim


ok , thank you very much .

but where can i get that rolls , i.e declare the macro before the class procedures/methods.

i am confused , in  fileclass_hhf  header file the put macro was declare after the procedures , which break the roll you have mentioned.

what really going on here  ?

Sevag.K


it might be a bug, you should be able to declare it after procedure/method declarations.  i'll mention it to randally hyde.