4

I have trying to make wrapper for winapi function GetWindowText. Function returns std::wstring but i don't know how to handle where error happen. I return NULL but i know it's wrong.

std::wstring GetWindowText(HWND handle)
{
    const int size = 1024;
    TCHAR wnd_text[size] = {0};

    HRESULT hr = ::GetWindowText(handle,
                    wnd_text, size);
    if(SUCCEEDED(hr))
        return std::wstring(wnd_text);
    else
        return NULL;    
}
0

7 Answers 7

7

Throw an exception instead.

std::wstring GetWindowText(HWND handle)
{
    const int size = 1024;
    TCHAR wnd_text[size] = {0};

    HRESULT hr = ::GetWindowText(handle,
                    wnd_text, size);
    if(SUCCEEDED(hr))
        return std::wstring(wnd_text);
    else
        throw std::runtime_error("insert error message here");    
}
Sign up to request clarification or add additional context in comments.

4 Comments

Don't think this is good Idea. Generaly winapi functions doesn't throw exceptions. It is better to set last error via SetLastError() msdn.microsoft.com/en-us/library/ms680627(v=vs.85).aspx
@Mihran: this is a C++ wrapper, so it's correct that it converts WinAPI idioms in C++ idioms. It would be even better if it encapsulated GetLastError value in a particular exception type.
In this case, he still has to return a value. What value should it be? Also, calling GetLastError after each call to this function is way uglier than just catching an exception.
I'd factor out the code to generate an error message from the failure code, but throwing an exception in response to an error case is exactly correct (given that it's not the OS interface itself which is doing this; there are some very good reasons for OSes to not throw exceptions themselves).
5

As an alternative to exceptions you could also return the string by reference in the argument list and indicate sucess by returning true or false i.e.

bool GetWindowText(HWND handle, std::wstring& windowText)
{
    const int size = 1024;
    TCHAR wnd_text[size] = {0};

    HRESULT hr = ::GetWindowText(handle,
                    wnd_text, size);
    if(SUCCEEDED(hr))
    {
        windowText = wnd_text;
        return true;
    }
    else
        return false;    
}

Another alternative which avoids the reference argument is to return an instance of a class that wraps a value but also lets you know whether a value is present e.g.

class ValueWrapper
{
public:
    ValueWrapper() : present( false ) {}
    ValueWrapper( const std::wstring& s ) : value( s ), present( true ) {}

    bool isPresent() const { return present; }
    const std::wstring& getValue() const { return value; }

private:
    std::wstring value;
    bool present;
};

Note that you can template this wrapper pretty easily. Your function would then be

ValueWrapper GetWindowText(HWND handle)
{
    const int size = 1024;
    TCHAR wnd_text[size] = {0};

    HRESULT hr = ::GetWindowText(handle,
                    wnd_text, size);
    if(SUCCEEDED(hr))
        return ValueWrapper( wnd_text );
    else
        return ValueWrapper();
}

2 Comments

Note that boost::optional<> is a preexisting, tested implementation of ValueWrapper.
Note that boost::optional<> has a name that is misleading in this case---the conventional name here is Fallible. (Also, it's possible to extend a Fallible so that it contains additional information concerning the error.)
1

Yet another solution (without throwing exceptions): use the Boost.Optional library.

Comments

0

NULL is definitely not ok for strings, you are specifically not allowed to pass a null pointer to the string constructor.

If you don't want to throw an exception, you can return the empty string, return std::wstring();.

2 Comments

But if the string in question is actually empty, it will lead to a fake error.
@Grigory - It might, yes, depending on what the interface is defined to be. However, std::wstring(NULL) is always an error as it violates the language standard!
0

WinApi designed so that it never throws exception. And to get reason of some unsuccessfull return of some function you in most cases have to get last error via GetLastError(). As I understand your function is going to be some addition to WinApi which will be easy to use. So I suggest keep their design as well. i.e. In case of failure return empty string and check what is last error if your function returns it.

Comments

0

First of all GetWindowText() does not return HRESULT so your code is just wrong in this respect.

And second, GetWindowTextW returns 0 on any error or number of characters if OK. So just return an empty string:

std::wstring GetWindowText(HWND handle)
{
    const int size = 1024;
    TCHAR wnd_text[size] = {0};

    INT n = ::GetWindowTextW(handle,
                    wnd_text, size);
    if(n > 0)
        return std::wstring(wnd_text,n);
    else
        return std::wstring();
}

Comments

0

Depending on your application, there are several appropriate solutions. The first is to throw an exception in case of an error: if you go this route, you should define a WindowsError exception (deriving from one of the standard exceptions), which includes all of the information available from GetLastError, and possibly additional information (name of the function which failed, etc.), in an easy to parse format. The other is to return some sort of Fallible; in this case, you may want to extend the classical Fallible idiom so that it can contain additional information concerning the cause of the error. Still another possibility is to return the value via an out parameter, and use a return code (again, possibly with additional information, and possibly with added code to ensure that it has been tested before being destructed).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.