summaryrefslogtreecommitdiff
path: root/zen/com_util.h
blob: ac73356612e5b1daa07ad154cdfbff7621328feb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html       *
// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved        *
// **************************************************************************

#ifndef COM_UTILITY_HEADER
#define COM_UTILITY_HEADER

#include "com_ptr.h"
#include <string>
#include <cassert>

namespace zen
{
//get an enumeration interface as a std::vector of bound(!) ComPtr(s)
template <class T, class U>
std::vector<ComPtr<T> > convertEnum(const ComPtr<U>& enumObj); //enumObj: must have the "_NewEnum" property that supports the IEnumUnknown interface

/*
extract text from com object member function returning a single BSTR:	HRESULT ComInterface::MemFun([out]  BSTR *pbstr);
	Example: ComPtr<...> comObj =...;
			 std::wstring description = getText(comObj, &IUPnPDevice::get_Description);
*/
template <class T, class MemFun>
std::wstring getText(ComPtr<T> comObj, MemFun memFun);


//RAII class handling BSTR
class Bstring
{
public:
    Bstring(const std::wstring& str) { str_ = ::SysAllocStringLen(str.data(), str.length()); } //string::data() returns unmodified string potentially containing 0-values
    ~Bstring() { if (str_) ::SysFreeString(str_); }

    const BSTR get() const { return str_; }

private:
    Bstring(const Bstring&);            //not implemented
    Bstring& operator=(const Bstring&); //

    BSTR str_;
};

























//############################ inline implemenatation ##################################
template <class T, class U> inline
std::vector<ComPtr<T> > convertEnum(const ComPtr<U>& enumObj)
{
    std::vector<ComPtr<T> > output;

    if (enumObj)
    {
        ComPtr<IUnknown> unknown;
        enumObj->get__NewEnum(unknown.init());
        ComPtr<IEnumUnknown> enumUnknown = com_dynamic_cast<IEnumUnknown>(unknown);

        assert(enumUnknown); //IEnumUnknown must be supported!
        if (enumUnknown)
        {
            ComPtr<IUnknown> itemTmp;
            while (enumUnknown->Next(1, itemTmp.init(), nullptr) == S_OK) //returns S_FALSE == 1 when finished! Don't use SUCCEEDED()!!!
            {
                ComPtr<T> itemNew = com_dynamic_cast<T>(itemTmp);
                if (itemNew)
                    output.push_back(itemNew);
            }
        }
    }

    return output;
}


template <class T, class MemFun> inline
std::wstring getText(ComPtr<T> comObj, MemFun memFun)
{
    std::wstring text;
    {
        if (!comObj)
            return std::wstring();

        BSTR bstr = nullptr;
        if (FAILED((comObj.get()->*memFun)(&bstr)))
            return std::wstring();

        if (bstr) //nullptr means "no text"
        {
            text = std::wstring(bstr, ::SysStringLen(bstr)); //correctly copy 0-characters
            ::SysFreeString(bstr);
        }
    }
    return text;
}
}


#endif //COM_UTILITY_HEADER
bgstack15