Announcement

Collapse
No announcement yet.

Using CALL DWORD with Property routines

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Michael Mattias
    replied
    Code:
      pAddr = OBJPTR(ox)
       workWithObj pAddr
       MSGBOX "x = " + STR$(ox.getX)
    END FUNCTION
    
    SUB workWithObj(BYVAL pAddr AS DWORD)
     ...
    ===>
    Code:
      pAddr = OBJPTR(ox)
       workWithObj   [B][COLOR="Red"]BYVAL pAddr[/COLOR][/B] 
      MSGBOX "x = " + STR$(ox.getX)
    END FUNCTION
    
    SUB workWithObj([BYREF] ox as  object_type)
    ...
    CALL "BYVAL ADDRESS" = CALL "BYREF"

    Or far more simply .... (a big on me)

    Code:
    ' DELETE   pAddr = OBJPTR(ox)    << REMOVE 
       workWithObj   ox
       MSGBOX "x = " + STR$(ox.getX)
    END FUNCTION
    
    SUB workWithObj([BYREF] ox as  object_type)
    ...


    MCM
    Last edited by Michael Mattias; 21 Feb 2009, 10:31 AM.

    Leave a comment:


  • Edwin Knoppert
    replied
    Oh and btw, i create custom controls and 'attach' an object pointer to the object created to the hWnd myself.
    And of course an extra Addref()
    The actual variable goes out of scope but the object remains until the window is destroyed (and Release() is called)

    I *always* check the release of the objects via it's class destroy method.
    Everybody should do that imo (during test/build).

    Leave a comment:


  • Edwin Knoppert
    replied
    Hmm, i don't see the need for PB objects to be called via pointers but for all other occasions we have been doing this for years. so what's up?

    @@pUnk[2] Using fRelease( pUnk )

    The only misfit but not a big deal in the example above is not using a form of addref()
    But then there must be a valid object already since it exists.

    Maybe i missed the clue but if you do it right it should not harm.
    But like i mentioned, why make it difficult with pointers anyway.

    Leave a comment:


  • jcfuller
    replied
    Originally posted by Charles Dietz View Post
    How about if my function is actually a callback function (which is actually the case I have) where the callback function needs the object. I could only think of two ways to get the object... define a global object or pass an object ptr to the callback. A global object defeats the whole idea of encapsulation, so that just left me with passing a pointer thru CONTROL SET USER.

    The object created in the callback gets an AddRef and is an automatic stack variable, so it should get released as the callback goes out of scope. So it doesn't seem like there should be a problem with reference counting, right?
    Charles,
    I've used both methods. With the GLOBAL I only have one, gApp, which is the main application class. It allows to dig down and get just about anything you need. I also use the method you presented. Do a search for some of my code and you will see how I do it.

    James

    Leave a comment:


  • Charles Dietz
    replied
    How about if my function is actually a callback function (which is actually the case I have) where the callback function needs the object. I could only think of two ways to get the object... define a global object or pass an object ptr to the callback. A global object defeats the whole idea of encapsulation, so that just left me with passing a pointer thru CONTROL SET USER.

    The object created in the callback gets an AddRef and is an automatic stack variable, so it should get released as the callback goes out of scope. So it doesn't seem like there should be a problem with reference counting, right?

    Leave a comment:


  • José Roca
    replied
    That kind of manipulation must be only used when there is no other choice. If used without concern of reference counting, will cause serious troubles.

    Better use:

    Code:
    FUNCTION PBMAIN
       LOCAL m, n AS LONG
       LOCAL oX AS iXX
       LOCAL pAddr AS DWORD
       ox = CLASS "cXX"
       workWithObj ox
       MSGBOX "x = " + STR$(ox.getX)
    END FUNCTION
    
    SUB workWithObj(BYVAL iobj AS iXX)
       iObj.setX = 24
       iObj.showX
    END SUB

    Leave a comment:


  • Charles Dietz
    replied
    Am I on safe ground with the following implementation of OBJPTR used to pass an object?

    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "WIN32API.INC"
    
    CLASS cXX
       INSTANCE x AS LONG
       INTERFACE iXX '---------------------------------------------------------------------
          INHERIT IUNKNOWN
    
          PROPERTY GET getX() AS LONG  'VFT(3)
             PROPERTY = x 
          END PROPERTY
          
          PROPERTY SET setX(BYVAL n AS LONG) 'VFT(4)
             MSGBOX "setX():  " + STR$(n)
             x = n
          END PROPERTY
          
          METHOD showX()  'VFT(5)
             MSGBOX "showX():  " + STR$(x)
          END METHOD
       END INTERFACE
    END CLASS
    
    FUNCTION PBMAIN
       LOCAL m, n AS LONG
       LOCAL oX AS iXX
       LOCAL pAddr AS DWORD
       ox = CLASS "cXX"
       pAddr = OBJPTR(ox)
       workWithObj pAddr
       MSGBOX "x = " + STR$(ox.getX)
    END FUNCTION
    
    SUB workWithObj(BYVAL pAddr AS DWORD)
       LOCAL iobj AS iXX
       POKE DWORD, VARPTR(iObj), pAddr
       IF ISOBJECT(iObj) THEN
          iObj.AddRef()
          iObj.setX = 24
          iObj.showX
       END IF
    END SUB

    Leave a comment:


  • Bob Zale
    replied
    I certainly have every respect for any person who wants to experiment a bit, use some ASM code to call other code, even some METHODS. The problem is this:

    1- CALL DWORD is a bit of a "black box"
    2- The DECLARES used with CALL DWORD are a bit of a "black box"
    3- Object Method Calls like: obj.method1(param) is a bit of a "black box".

    One is using a black box to be substituted for another black box using a third black box. The calling conventions are slightly different, reference counting is lost, there are memory leaks from differences in parameter cleanup, and more. This is guaranteed to fail miserably, even if not immediately, and even the black boxes are subject to change. If you must do this sort of thing, do it very carefully in ASM.

    Best regards,

    Bob Zale
    PowerBASIC Inc.

    Leave a comment:


  • colin glenn
    replied
    Anyone remember writing a List Of Lists TSR dependent program?

    Leave a comment:


  • Michael Mattias
    replied
    Fred, that "may" work... however, it is a documented restriction of CALL DWORD that "dwPointer" be the address of a procedure.

    When you go off the reservation you are on your own.

    And just on a more "ideological" plane ... why should you care about the memory layout at all? If you have been working in Windows for a while, you should be comfortable dealing with the fact that everything is 'virtual' anyway... accessed via whatever these "handle" thingies are.

    Ok, I used to concern myself with it, too. It can be fun.

    However, I learned the hard way that Thou Shalt Not Count On It Working The Same Way In The Next Release.


    MCM

    Leave a comment:


  • Bob Zale
    replied
    Wrong. Very wrong. There is no merit. Please do not post such examples again, as they all fail miserably. Reference counting. Memory leaks. Much more.

    Leave a comment:


  • Fred Harris
    replied
    Hi Charles!

    If you are referring to my ObjPtr() demo where I dumped the VTables with function pointers at...

    http://www.powerbasic.com/support/pb...ghlight=ObjPtr

    ...check out my comments at the end of the 3rd post where I showed a C++ version of the VTable dump. What appears to be happening in your program (I just took a quick look at it) is that you are ending up with an unbalanced stack because you are failing to set up an adequate function pointer prototype. The class pointer (me) is always 'pushed' as the 1st parameter of an object function call. Here, try this...

    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "WIN32API.INC"
    
    DECLARE FUNCTION getX(Byval Dword) AS LONG
    DECLARE SUB setX(Byval Dword, BYVAL LONG)
    DECLARE SUB showX(Byval Dword)
    
    CLASS cXX
       INSTANCE x AS LONG
       INTERFACE iXX '---------------------------------------------------------------------
          INHERIT IUNKNOWN
    
          PROPERTY GET getX() AS LONG  'VFT(3)
             PROPERTY = x
          END PROPERTY
    
          PROPERTY SET setX(BYVAL n AS LONG) 'VFT(4)
             MSGBOX "setX()  " + STR$(n)
             x = n
          END PROPERTY
    
          METHOD showX()  'VFT(5)
             MSGBOX "showX():  " + STR$(x)
          END METHOD
       END INTERFACE
    END CLASS
    
    FUNCTION PBMAIN
       LOCAL m, n AS LONG
       LOCAL oX AS iXX
       LOCAL pVFT, VFT AS DWORD PTR
       ox = CLASS "cXX"
       ox.setX = 20
       ox.showX
       MSGBOX "getX()  " + STR$(ox.getX)
    
       pVFT = OBJPTR(ox)
       VFT = @pVFT
       CALL DWORD @VFT[5] USING showX(pVFT)
       CALL DWORD @VFT[4] USING setX(pVFT,30)
       CALL DWORD @VFT[3] USING getX(pVFT) TO n
       MSGBOX "returned from getX():  " + STR$(n)
    END FUNCTION
    As Mr. Zale mentioned, this is a rather unusual thing to do, and its main merit consists in demonstrating for oneself that one's conception of memory layout is correct.

    Leave a comment:


  • Bob Zale
    replied
    You simply cannot ever, under any circumstaces, for any reason, unequivocally do such a thing. Did I mention Don't Do It?

    Call DWORD may be used only with Subs and Functions. Period. Only with Subs and Functions. Any other use is like begging to be beheaded.

    We can't list everything that is prohibited. So, if you don't find it documented, please Don't Do It!

    Did I mention "Don't Do It?"


    Warmest regards,

    Bob Zale
    PowerBASIC Inc.

    Leave a comment:


  • Michael Mattias
    replied
    I haven't found anything in the help that prohibits such use,
    HELP FILE:
    Purpose
    Invoke a procedure (Sub or Function) indirectly.

    Syntax
    CALL DWORD dwpointer [{BDECL | CDECL | SDECL} ()]
    CALL DWORD dwpointer USING abc([arguments]) [TO result_var]
    ....
    The CALL DWORD statement has the following parts:

    dwpointer
    A Double-word, Long-integer, or pointer variable that contains the address of the entry point of a procedure (Sub or Function).
    "Address of an interface property or method" is not the entry point of a (PowerBASIC) procedure.

    I won't even ask what's wrong with....
    Code:
        myVar = objectvar.property
    or
    Code:
       objectvar.method (params)
    .. because if I can't see the reason for trying to abuse CALL DWORD I guess I'm just not smart enough to 'get it.'

    MCM
    Last edited by Michael Mattias; 19 Feb 2009, 05:18 PM.

    Leave a comment:


  • Charles Dietz
    started a topic Using CALL DWORD with Property routines

    Using CALL DWORD with Property routines

    I am trying to learn about PB9 objects and in working with the OBJPTR function, I have run into some problems. The code below utilizes the CALL DWORD command, and it seems to work nicely with METHODS but not with PROPERTY routines. I haven't found anything in the help that prohibits such use, so I was wondering if I am just using them incorrectly. By the way, I have learned a lot from Fred Harris' related code in this forum.

    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "WIN32API.INC"
    
    DECLARE FUNCTION getX() AS LONG
    DECLARE SUB setX(BYVAL LONG)
    DECLARE SUB showX()
    
    CLASS cXX
       INSTANCE x AS LONG
       INTERFACE iXX '---------------------------------------------------------------------
          INHERIT IUNKNOWN
    
          PROPERTY GET getX() AS LONG  'VFT(3)
             PROPERTY = x 
          END PROPERTY
          
          PROPERTY SET setX(BYVAL n AS LONG) 'VFT(4)
             MSGBOX "setX()  " + STR$(n)
             x = n
          END PROPERTY
          
          METHOD showX()  'VFT(5)
             MSGBOX "showX():  " + STR$(x)
          END METHOD
       END INTERFACE
    END CLASS
    
    FUNCTION PBMAIN
       LOCAL m, n AS LONG
       LOCAL oX AS iXX
       LOCAL pVFT, VFT AS DWORD PTR
       ox = CLASS "cXX"
       ox.setX = 20
       ox.showX
       MSGBOX "getX()  " + STR$(ox.getX)
       
       pVFT = OBJPTR(ox)
       VFT = @pVFT 
       CALL DWORD @VFT[5] USING showX()
       CALL DWORD @VFT[4] USING setX(30)
       CALL DWORD @VFT[3] USING getX() TO n
       MSGBOX "returned from getX():  " + STR$(n)
    END FUNCTION
Working...
X