Search code examples
c++comreturn-valueidl

Return multiple values from a function in COM Interfaces


I did a research and implemented a wrapper function for GetWindowRect API, and it works fine. But it can currently only return window coordinates via a SAFEARRAY. But I am thinking about how can I also return its actual return value.

I declared it like this:

[id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out, retval] SAFEARRAY(VARIANT) *lpRect);

STDMETHOD(WinAPI_GetWindowRect)(VARIANT hWnd, SAFEARRAY **lpRect);

And implementation:

STDMETHODIMP CWinAPI::WinAPI_GetWindowRect(VARIANT hWnd, SAFEARRAY **lpRect {

    CComSafeArray<VARIANT> CCSA_RECT;
    RECT Rect;
    HRESULT HResult;

    if (!lpRect) { return E_INVALIDARG; }

    *lpRect = nullptr;

    int Result = (int)GetWindowRect(VariantToHWND(hWnd), &Rect);
    //   ^ I ALSO WANT TO RETURN THIS RESULT TOO

    if (Result != 0)
    {
        HResult = CCSA_RECT.Create(4, 0);
        assert(HResult == S_OK);

        CCSA_RECT[0] = Rect.left;
        CCSA_RECT[1] = Rect.top;
        ...
    }
    else
    { ... }
}

But, as I already know, there cannot be multiple [out, retval] values, so any suggestions on how to return this value (Result) are highly appreciated.

UPDATE

When I try to return it like this:

[id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out] SAFEARRAY(VARIANT) *lpRect, [out, retval] VARIANT *Result);

STDMETHOD(WinAPI_GetWindowRect)(VARIANT hWnd, SAFEARRAY **lpRect, VARIANT *Result);

Assigning it like:

Result->intVal = (int)GetWindowRect(VariantToHWND(hWnd), &Rect);

I am getting a Type mismatch error in below VBScript line when try to use it:

Dim lpRect, Result: Result = WINAPI.WinAPI_GetWindowRect(AutoItX3.WinGetHandle("[CLASS:ConsoleWindowClass]"), lpRect)

I want this SAFEARRAY to be [out] parameter and Result to be return value.


Solution

  • I solved the problem to a some extent by using a VARIANT as [out] parameter like this:

    [id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out] VARIANT *Result, [out, retval] SAFEARRAY(VARIANT) *lpRect);
    
    STDMETHOD(WinAPI_GetWindowRect)(VARIANT hWnd, VARIANT *Result, SAFEARRAY **lpRect);
    

    New implementation:

    STDMETHODIMP CWinAPI::WinAPI_GetWindowRect(VARIANT hWnd, VARIANT *Result, SAFEARRAY **lpRect) {
    
        CComSafeArray<VARIANT> CCSA_RECT;
        RECT Rect;
        HRESULT HResult;
    
        if (!lpRect) { return E_INVALIDARG; }
    
        *lpRect = nullptr;
    
        VariantInit(Result);
        Result->vt = VT_I2;
    
        Result->intVal = (int)GetWindowRect(VariantToHWND(hWnd), &Rect);
    
        if (Result->intVal != 0)
        {...}
        else
        {...}
    
    }
    

    This has been tested using the following VBScript:

    Dim AutoItX3: Set AutoItX3 = WScript.CreateObject("AutoItX3.Control")
    Dim WINAPI: Set WINAPI = WScript.CreateObject("WinAPIWrapperLib.WINAPI")
    
    Dim lpRect, Result: lpRect = WINAPI.WinAPI_GetWindowRect(AutoItX3.WinGetHandle("[CLASS:ConsoleWindowClass]"), Result)
    
    WScript.Echo "GetWindowRect returned: " + CStr(Result)
    
    If CInt(Result) <> 0 Then
        For iNum = 0 To UBound(lpRect)
            WScript.Echo CStr(lpRect(iNum))
        Next
    End If
    
    WScript.Echo(CStr(WINAPI.WinAPI_GetLastErrorMessage))
    

    But, I still cannot use SAFEARRAY as an [out] only parameter, using it as [out] only parameter and using Result as [out, retval] member in following way:

    [id(10)] HRESULT WinAPI_GetWindowRect([in] VARIANT hWnd, [out] SAFEARRAY(VARIANT) *lpRect, [out, retval] VARIANT *Result);
    

    still causes the Type mismatch error.