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.
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
> 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
' ========================================================================================