-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathComObject.cpp
More file actions
123 lines (97 loc) · 3.64 KB
/
ComObject.cpp
File metadata and controls
123 lines (97 loc) · 3.64 KB
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
122
123
/*
Copyright 2019 Michael Beckh
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/// @file
#include "m3c/ComObject.h"
#include "m3c/COM.h"
#include "m3c/Log.h"
#include "m3c/exception.h"
#include "m3c.events.h"
#include <windows.h>
#include <unknwn.h>
namespace m3c::internal {
HRESULT Unknown::UnknownImpl::QueryInterface(REFIID riid, _COM_Outptr_ void** const ppObject) noexcept {
return GetAbstractComObject()->QueryInterfaceNonDelegated(riid, ppObject);
}
ULONG Unknown::UnknownImpl::AddRef() noexcept {
return GetAbstractComObject()->AddRefNonDelegated();
}
ULONG Unknown::UnknownImpl::Release() noexcept {
return GetAbstractComObject()->ReleaseNonDelegated();
}
AbstractComObject* Unknown::UnknownImpl::GetAbstractComObject() noexcept {
static_assert(offsetof(Unknown, m_unknown) == 0);
#pragma warning(suppress : 26491) // valid as checked by static_assert
return static_cast<AbstractComObject*>(reinterpret_cast<Unknown*>(this)); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast): Pointer magic :-)
}
AbstractComObject::AbstractComObject() noexcept {
InterlockedIncrement(&COM::s_objectCount);
}
AbstractComObject::AbstractComObject(_In_opt_ IUnknown* const pOuter) noexcept
: m_pUnknown(pOuter ? pOuter : &m_unknown) {
InterlockedIncrement(&COM::s_objectCount);
}
AbstractComObject::~AbstractComObject() noexcept {
InterlockedDecrement(&COM::s_objectCount);
}
//
// Non-Delegated methods of IUnknown
//
HRESULT AbstractComObject::QueryInterfaceNonDelegated(REFIID riid, _COM_Outptr_ void** const ppObject) noexcept {
if (!ppObject) {
[[unlikely]];
return Log::TraceHResult(E_INVALIDARG, "hr={}, riid={}", riid);
}
if (IsEqualIID(riid, IID_IUnknown)) {
*ppObject = &m_unknown;
AddRefNonDelegated();
return Log::TraceHResult(S_OK, "hr={}, riid={}", riid);
}
*ppObject = FindInterfaceInternal(riid);
if (*ppObject) {
[[likely]];
static_cast<IUnknown*>(*ppObject)->AddRef();
return Log::TraceHResult(S_OK, "hr={}, riid={}", riid);
}
return Log::TraceHResult(E_NOINTERFACE, "hr={}, riid={}", riid);
}
ULONG AbstractComObject::AddRefNonDelegated() noexcept {
return Log::TraceResult(InterlockedIncrement(&m_refCount), "ref={}, this={}", static_cast<const void*>(this));
}
ULONG AbstractComObject::ReleaseNonDelegated() noexcept {
const void* const ths = this; // do not touch this after possible deletion
const ULONG refCount = InterlockedDecrement(&m_refCount);
if (!refCount) {
// Required as of https://docs.microsoft.com/en-us/windows/win32/com/aggregation
// Inner object might trigger calls to AddRef and Release on itself
InterlockedIncrement(&m_refCount);
delete this;
}
return Log::TraceResult(refCount, "ref={}, this={}, objects={}", ths, COM::s_objectCount);
}
//
// Custom methods
//
_Ret_notnull_ void* AbstractComObject::QueryInterface(REFIID riid) {
if (IsEqualIID(riid, IID_IUnknown)) {
AddRefNonDelegated();
return &m_unknown;
}
void* const pInterface = FindInterfaceInternal(riid);
if (pInterface) {
[[likely]];
static_cast<IUnknown*>(pInterface)->AddRef();
return pInterface;
}
throw com_error(E_NOINTERFACE) + evt::IUnknown_QueryInterface_H << riid;
}
} // namespace m3c::internal