CWindow RC 20

Started by José Roca, September 06, 2016, 07:34:58 PM

Previous topic - Next topic

José Roca

CWindow Release Candidate 20

This version should be free of memory leaks.

The CBSTRSA and CBSTRDIC data types have been removed because they're no longer needed now that we have variants and safe arrays.

The memory leaks were caused by using initialized CBSTRs and CVARIANTs with OUT parameters. The COM methods with OUT BSTR or VARIANT parameters don't free the incoming BSTRs, and VARIANTS are freed if the method uses VariantCopy, but not if it uses a function like memcpy to copy the memory.

Therefore, to avoid memory leaks, either pass an uninitialized CBSTR / CVARIANT or, if you want to reuse already initialized variables, call the clear method, e.g. cbs.Clear, cv.Clear, before passing them. Be aware that clearing a CBSTR is not the same that setting it to "". The Clear method frees the undelying BSTR and sets the pointer to it to NULL. Setting the CBSTR = "" creates a valid empty BSTR. In the case of a CVARIANT, the clear method creates a VT_EMPTY variant.

CWSTR is our superfast dynamic unicode data type, but never use it with COM methods that expect a BSTR. The compiler will allow you to do it, because it has no idea of what a BSTR is, but many methods will fail. Don't be fooled if some methods work, this is because they treat it as a WSTRING, but others will try to get it's length with SysStringLen and will fail. Passing a pointer to a CWSTR to a COM method with an OUT parameter will always crash.

Marc Pons

Hi Jose, super job!

just noticed:
BOOLEAN constructor , cast and let operators are missing in CVariant.inc


    DECLARE CONSTRUCTOR (BYVAL bVal AS BOOLEAN)
    DECLARE OPERATOR Cast () AS BOOLEAN
    DECLARE OPERATOR Let (BYVAL bVal AS BOOLEAN)


and
' ========================================================================================
' Initializes a CVariant from a BOOLEAN variable
' Usage: DIM cvar AS CVariant = <BOOLEAN variable>
' --or-- DIM cvar AS CVariant = true or false
' --or-- DIM cvar AS CVariant =  0 or integer value
' ========================================================================================
PRIVATE CONSTRUCTOR CVariant (BYVAL bVal AS BOOLEAN)
   CVARIANT_DP("CVARIANT CONSTRUCTOR - BOOLEAN")
   ' // Load the PopsSys.DLL
   psLib = DyLibLoad("propsys.dll")
   ' // Initialize the variant
   V_VT(@vd) = VT_BOOL
   V_BOOL(@vd) = bVal
END CONSTRUCTOR
' ========================================================================================
' ========================================================================================
' Cast as BOOLEAN
' ========================================================================================
PRIVATE OPERATOR CVariant.Cast () AS BOOLEAN
   CVARIANT_DP("CVARIANT CAST BOOLEAN")
   DIM v AS VARIANT
   VariantChangeType(@v, @vd, 0, VT_BOOL)
   OPERATOR = v.boolVal
END OPERATOR
' ========================================================================================

' ========================================================================================
' Assigns a BOOLEAN
' ========================================================================================
PRIVATE OPERATOR CVariant.Let (BYVAL bVal AS BOOLEAN)
   CVARIANT_DP("CVARIANT LET = BOOLEAN")
   VariantClear(@vd)
   V_VT(@vd) = VT_BOOL
   V_BOOL(@vd) = bVal
END OPERATOR
' ========================================================================================


On the TypeLib Browser , i still do not know how to deal with vtable events , how to connect to the olecon....

for dispach events , you have shown it , so ok i think i can expand to generic
same with vtable type , and with abstract dispach type.

i will send you a sample directly

José Roca

> BOOLEAN constructor , cast and let operators are missing in CVariant.inc

Thanks for reporting it.

I'm preparing a template class for the WebBrowser and I'm replacing the ForwardMessage method with the AfxForwardMessage function. The reason is that the method is not handy to use if there is more than an instance of the OLE container.

The AfxForwardMessage function is generic and you just have to use it once, e.g.


   ' // Dispatch Windows messages
   DIM uMsg AS MSG
   WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
      IF AfxForwardMessage(GetFocus, @uMsg) = FALSE THEN
         IF IsDialogMessageW(hWndMain, @uMsg) = 0 THEN
            TranslateMessage(@uMsg)
            DispatchMessageW(@uMsg)
         END IF
      END IF
   WEND
   FUNCTION = uMsg.wParam


This is the function:


' ========================================================================================
' Forwards the message to the control. Active in-place objects must always be given the
' first chance at translating accelerator keystrokes. You can provide this opportunity by
' calling IOleInPlaceActiveObject.TranslateAccelerator from your container's message loop
' before doing any other translation. You should apply your own translation only when this
' method returns FALSE.
' Remarks: If the control is the WebBrowser control, TranslateAccelerator calls the namesake
' method of the IDocHostUIHandler interface.
' Usage example:
'   ' // Dispatch Windows messages
'   DIM uMsg AS MSG
'   WHILE (GetMessageW(@uMsg, NULL, 0, 0) <> FALSE)
'      IF AfxForwardMessage(GetFocus, @uMsg) = FALSE THEN
'         IF IsDialogMessageW(hWndMain, @uMsg) = 0 THEN
'            TranslateMessage(@uMsg)
'            DispatchMessageW(@uMsg)
'         END IF
'      END IF
'   WEND
'   FUNCTION = uMsg.wParam
' ========================================================================================
PRIVATE FUNCTION AfxForwardMessage (BYVAL hctl AS HWND, BYVAL pMsg AS tagMsg PTR) AS BOOLEAN
   IF pMsg->message >= WM_KEYFIRST AND pMsg->message <= WM_KEYLAST THEN
      ' // See if the window that has the focus is a child of our container window
      DIM wszClassName AS WSTRING * 260
      DIM hWndParent AS HWND, hWndTmp AS HWND
      hWndParent = hCtl
      DO
         hWndTmp = GetParent(hWndParent)
         IF hWndTmp = NULL THEN EXIT DO
         hWndParent = hWndTmp
         GetClassNameW hWndParent, wszClassName, SIZEOF(wszClassName)
         IF wszClassName = OC_CLASSNAME THEN EXIT DO
      LOOP
      IF wszClassName <> OC_CLASSNAME THEN RETURN FALSE
      ' // Get a pointer to the OLE container class
      DIM pOleCon AS COleCon PTR = cast(COleCon PTR, GetWindowLongPtrW(hwndParent, 0))
      IF pOleCon = NULL THEN RETURN FALSE
      IF pOlecon->m_pData->m_pOcx = NULL THEN RETURN FALSE
      ' // Translate the message
      DIM hr AS HRESULT, pActiveObject AS IOleInPlaceActiveObject PTR
      hr = IUnknown_QueryInterface(pOleCon->m_pData->m_pOcx, @IID_IOleInPlaceActiveObject, @pActiveObject)
      IF pActiveObject = NULL THEN RETURN FALSE
      hr = pActiveObject->lpvtbl->TranslateAccelerator(pActiveObject, pMsg)
      IUnknown_Release(pActiveObject)
      IF hr = S_OK THEN RETURN TRUE
   END IF
   RETURN FALSE
END FUNCTION
' ========================================================================================