Tino Didriksen
Tino Didriksen

Reputation: 2255

COM out-ptr remains null in client

What would cause an IEnumString->Next() call to call the correct function but leave the client's pointer null? Everything is 64bit (Windows 10).

Data flow: My DLL -> MSSpellCheckingHost -> Client

In my code (Github link) everything checks out. The allocation and copy look fine. But the client sees a null pointer, but only when coming via ISpellCheckProvider->Suggest(); it works fine via ISpellCheckProviderFactory->get_SupportedLanguages()

Snippet from EnumString.hpp :

template<typename String>
inline void CoCopyWString(const String& in, PWSTR* out) {
    debugp p(__FUNCTION__);
    p(in, static_cast<void*>(*out));
    *out = reinterpret_cast<LPWSTR>(CoTaskMemAlloc(sizeof(wchar_t)*(in.size() + 1)));
    std::copy(in.begin(), in.end(), *out);
    (*out)[in.size()] = 0;
    p(std::wstring(*out), static_cast<void*>(*out));
}

class EnumString : public IEnumString {
public:
...
    IFACEMETHODIMP Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched) {
        debugp p(__FUNCTION__);
        p(celt);
        HRESULT hr = S_FALSE;

        ULONG i = 0;
        for (; i < celt && current < strings.size(); ++i, ++current) {
            p(i, current);
            CoCopyWString(strings[current], rgelt+i);
            p(static_cast<void*>(rgelt + i), static_cast<void*>(rgelt[i]));
        }

        if (celt > 1) {
            *pceltFetched = i;
        }
        if (i == celt) {
            hr = S_OK;
        }

        return hr;
    }
...
private:
    std::vector<std::wstring> strings;
    ULONG current = 0;
};

As shown, there's lots of debug prints, because attaching a debugger to MSSpellCheckingHost is quite an annoyance, and they yield the expected output of e.g.:

EnumString::Next
    1
    0 0
    CoCopyWString
        i-llu 0000000000000000
        i-llu 000001CC35682AE0
    ~CoCopyWString
    000001CC356A1F50 000001CC35682AE0
~EnumString::Next

...which shows the output pointer being set and the data pointed to is correct. And it works when SupportedLanguages is called - that returns the correct value to the enumerator and the value is used so it couldn't have been null. But when Suggest() is used, the results don't make it through.

All other functions that return structures allocated via CoTaskMemAlloc also work, so overall the host appears functional, except in that one case.

Upvotes: 0

Views: 63

Answers (1)

Tino Didriksen
Tino Didriksen

Reputation: 2255

As Hans Passant pointed out, the snippet

    if (celt > 1) {
        *pceltFetched = i;
    }

should instead be

    if (pceltFetched) {
        *pceltFetched = i;
    }

Upvotes: 1

Related Questions