Announcement

Collapse
No announcement yet.

PowerBASIC and reference counting

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

  • PowerBASIC and reference counting

    Given this code
    Code:
    FUNCTION frameIOleInPlaceFrame_RemoveMenus(BYVAL pThis AS DWORD, BYVAL hmenuShared AS DWORD) AS LONG
    
      LOCAL riid            AS GUID
      LOCAL pCIFace         AS CIFace PTR
      LOCAL pCFrame         AS CFrame PTR
      LOCAL ptocd           AS OLECONTAINERDATA PTR
      LOCAL pTenant         AS Tenant PTR
      LOCAL hWndSite        AS DWORD
      LOCAL pUnk            AS DWORD
      LOCAL lParam          AS LONG
      LOCAL lpfnCallback    AS DWORD
      LOCAL hr              AS LONG
    
      pCIFace = pThis
      pCFrame = @pCIFace.pObject
    
      ' Tell the top-level window to remove its menus
      IF pCFrame THEN
        hWndSite = GetHostWindow(@pCFrame.m_pIOleIPActiveObject)
        IF IsWindow(hWndSite) THEN
          ptocd = GetWindowLong(hWndSite, 0)
          IF @ptocd.m_lpfnMenu THEN
            lpfnCallback = @ptocd.m_lpfnMenu
            lParam       = @ptocd.m_lParam
    
            riid = $IID_IUNKNOWN
            pTenant = @ptocd.m_pObject   
            IF pTenant THEN
              hr = IUnknown_QueryInterface(@pTenant.m_pIUnknown, riid, pUnk)
              IF hr = %S_OK THEN  
                ' Call the InsertMenus callback function
                ! push  ebx
                ! push  esi
                ! push  edi
                ! push  lParam
                ! push  %TRUE
                ! push  %NULL
                ! push  %NULL
                ! push  %NULL
                ! push  hmenuShared
                ! push  pUnk
                ! call  lpfnCallback
                ! pop   edi
                ! pop   esi
                ! pop   ebx
                IUnknown_Release pUnk
              END IF
            END IF  
          END IF
        END IF
      END IF
    
    	FUNCTION = %S_OK
    
    END FUNCTION
    And this version of the callback
    Code:
    FUNCTION InsertMenusCallback _
      ( _
        BYVAL oObject       AS IUNKNOWN, _                ' [in] IUnknown pointer to active object
        BYVAL hMenuShared   AS DWORD, _                   ' [in] shared menu
        BYVAL ptomgw        AS OLEMENUGROUPWIDTHS PTR, _  ' [out] array indicatiing number of items in each group
        BYVAL phMenuFrame   AS DWORD PTR, _               ' [out] points to the handle of the original frame menu
        BYVAL phMenuWindow  AS DWORD PTR, _               ' [out] points to the handle of the original window menu(MDI)
        BYVAL fRemove       AS LONG, _                    ' [in] true, items are being removed. False, items are being added
        BYVAL lParam        AS LONG _                     ' [in] application-defined value
      ) AS LONG
    
    END FUNCTION
    PowerBASIC calls Release on oObject an [in] parameter which, in my opinion, is a violation of the
    COM reference counting rules. The result is that the IUnknown pointer to the object, @pTenant.m_pIUnknown,
    is no longer valid after frameIOleInPlaceFrame_RemoveMenus returns.
    Dominic Mitchell
    Phoenix Visual Designer
    http://www.phnxthunder.com

  • #2
    No, because PB will call AddRef if you pass an object variable, and later Release. This guarantees that the object will be valid during the life of the function. But you are bypassing the mechanism by using assembler. Either declare oObject as DWORD, or call AddRef before the assembler code.
    Forum: http://www.jose.it-berater.org/smfforum/index.php

    Comment


    • #3
      You could also use this:

      Code:
      LOCAL pUnk AS IUnknown
      hr = IUnknown_QueryInterface(@pTenant.m_pIUnknown, riid, BYVAL VARPTR(pUnk))
      IF hr = %S_OK THEN  
         InsertMenusCallback(pUnk, hmenuShared, %NULL, %NULL, %NULL, %TRUE, lParam)
         pUnk = NOTHING
      END IF
      Forum: http://www.jose.it-berater.org/smfforum/index.php

      Comment


      • #4
        or call AddRef before the assembler code.
        Well QueryInterface plus an additional AddRef is not good for code maintenance and could lead to trouble with other compilers.
        I usually use this
        Code:
                riid = $IID_IUNKNOWN
                pTenant = @ptocd.m_pObject   
                IF pTenant THEN
                  hr = IUnknown_QueryInterface(@pTenant.m_pIUnknown, riid, pUnk)
                  IF hr = %S_OK THEN 
                    vObj.vt = %VT_DISPATCH 
                    vObj.vd.pdispVal = pUnk
                    pv = VARPTR(vObj)            
                    ! push  ebx
                    ! push  esi
                    ! push  edi
                    ! push  lParam
                    ! push  %TRUE
                    ! push  %NULL
                    ! push  %NULL
                    ! push  %NULL
                    ! push  hmenuShared
                    ! push  pv
                    ! call  lpfnCallback
                    ! pop   edi
                    ! pop   esi
                    ! pop   ebx
                    IUnknown_Release pUnk
                  END IF
                END IF
        and use dword for the object variable.

        Anyway, for this particular callback a reference to the object is not of any use, therefore, I have replaced it with the handle of the frame window.
        Dominic Mitchell
        Phoenix Visual Designer
        http://www.phnxthunder.com

        Comment


        • #5
          Code:
          LOCAL pUnk AS IUnknown
          hr = IUnknown_QueryInterface(@pTenant.m_pIUnknown, riid, BYVAL VARPTR(pUnk))
          IF hr = %S_OK THEN  
             InsertMenusCallback(pUnk, hmenuShared, %NULL, %NULL, %NULL, %TRUE, lParam)
             pUnk = NOTHING
          END IF
          That is not going to work. The code that calls the callback is in a DLL and InsertMenusCallback is not in the DLL.
          Dominic Mitchell
          Phoenix Visual Designer
          http://www.phnxthunder.com

          Comment


          • #6
            Using this
            Code:
            CALL DWORD @ptocd.m_lpfnMenu USING InsertMenusCallback(pUnk, hmenuShared, %NULL, %NULL, %NULL, %TRUE, lParam)
            will work.

            But it requires a declaration which I don't like doing. Object variables are also not allowed in this code.

            Thanks for the info on PowerBASIC's AddRef and Release calls. I was only seeing the release, that is why I thought it violated the rules.
            It will come in handy when dealing with events from an OCX and inserting a reference to the object in the events.
            Last edited by Dominic Mitchell; 30 Dec 2008, 03:26 AM.
            Dominic Mitchell
            Phoenix Visual Designer
            http://www.phnxthunder.com

            Comment

            Working...
            X