1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #if defined(MOZILLA_INTERNAL_API)
8 # include "MainThreadUtils.h"
9 # include "mozilla/dom/ContentChild.h"
12 #include "mozilla/ArrayUtils.h"
13 #include "mozilla/mscom/COMWrappers.h"
14 #include "mozilla/DebugOnly.h"
15 #include "mozilla/mscom/Utils.h"
16 #include "mozilla/RefPtr.h"
24 extern "C" IMAGE_DOS_HEADER __ImageBase
;
30 bool IsCOMInitializedOnCurrentThread() {
32 APTTYPEQUALIFIER aptTypeQualifier
;
33 HRESULT hr
= wrapped::CoGetApartmentType(&aptType
, &aptTypeQualifier
);
34 return hr
!= CO_E_NOTINITIALIZED
;
37 bool IsCurrentThreadMTA() {
39 APTTYPEQUALIFIER aptTypeQualifier
;
40 HRESULT hr
= wrapped::CoGetApartmentType(&aptType
, &aptTypeQualifier
);
45 return aptType
== APTTYPE_MTA
;
48 bool IsCurrentThreadExplicitMTA() {
50 APTTYPEQUALIFIER aptTypeQualifier
;
51 HRESULT hr
= wrapped::CoGetApartmentType(&aptType
, &aptTypeQualifier
);
56 return aptType
== APTTYPE_MTA
&&
57 aptTypeQualifier
!= APTTYPEQUALIFIER_IMPLICIT_MTA
;
60 bool IsCurrentThreadImplicitMTA() {
62 APTTYPEQUALIFIER aptTypeQualifier
;
63 HRESULT hr
= wrapped::CoGetApartmentType(&aptType
, &aptTypeQualifier
);
68 return aptType
== APTTYPE_MTA
&&
69 aptTypeQualifier
== APTTYPEQUALIFIER_IMPLICIT_MTA
;
72 #if defined(MOZILLA_INTERNAL_API)
73 bool IsCurrentThreadNonMainMTA() {
74 if (NS_IsMainThread()) {
78 return IsCurrentThreadMTA();
80 #endif // defined(MOZILLA_INTERNAL_API)
82 bool IsProxy(IUnknown
* aUnknown
) {
87 // Only proxies implement this interface, so if it is present then we must
88 // be dealing with a proxied object.
89 RefPtr
<IClientSecurity
> clientSecurity
;
90 HRESULT hr
= aUnknown
->QueryInterface(IID_IClientSecurity
,
91 (void**)getter_AddRefs(clientSecurity
));
92 if (SUCCEEDED(hr
) || hr
== RPC_E_WRONG_THREAD
) {
98 bool IsValidGUID(REFGUID aCheckGuid
) {
99 // This function determines whether or not aCheckGuid conforms to RFC4122
100 // as it applies to Microsoft COM.
102 BYTE variant
= aCheckGuid
.Data4
[0];
103 if (!(variant
& 0x80)) {
107 if ((variant
& 0xE0) == 0xE0) {
108 // Reserved for future use
111 if ((variant
& 0xC0) == 0xC0) {
112 // Microsoft Reserved.
116 BYTE version
= HIBYTE(aCheckGuid
.Data3
) >> 4;
117 // Other versions are specified in RFC4122 but these are the two used by COM.
118 return version
== 1 || version
== 4;
121 uintptr_t GetContainingModuleHandle() {
122 HMODULE thisModule
= nullptr;
123 #if defined(_MSC_VER)
124 thisModule
= reinterpret_cast<HMODULE
>(&__ImageBase
);
126 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
127 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
128 reinterpret_cast<LPCTSTR
>(&GetContainingModuleHandle
),
133 return reinterpret_cast<uintptr_t>(thisModule
);
138 long BuildRegGuidPath(REFGUID aGuid
, const GuidType aGuidType
, wchar_t* aBuf
,
139 const size_t aBufLen
) {
140 constexpr wchar_t kClsid
[] = L
"CLSID\\";
141 constexpr wchar_t kAppid
[] = L
"AppID\\";
142 constexpr wchar_t kSubkeyBase
[] = L
"SOFTWARE\\Classes\\";
144 // We exclude null terminators in these length calculations because we include
145 // the stringified GUID's null terminator at the end. Since kClsid and kAppid
146 // have identical lengths, we just choose one to compute this length.
147 constexpr size_t kSubkeyBaseLen
= mozilla::ArrayLength(kSubkeyBase
) - 1;
148 constexpr size_t kSubkeyLen
=
149 kSubkeyBaseLen
+ mozilla::ArrayLength(kClsid
) - 1;
150 // Guid length as formatted for the registry (including curlies and dashes),
151 // but excluding null terminator.
152 constexpr size_t kGuidLen
= kGuidRegFormatCharLenInclNul
- 1;
153 constexpr size_t kExpectedPathLenInclNul
= kSubkeyLen
+ kGuidLen
+ 1;
155 if (aBufLen
< kExpectedPathLenInclNul
) {
156 // Buffer is too short
160 if (wcscpy_s(aBuf
, aBufLen
, kSubkeyBase
)) {
164 const wchar_t* strGuidType
= aGuidType
== GuidType::CLSID
? kClsid
: kAppid
;
165 if (wcscat_s(aBuf
, aBufLen
, strGuidType
)) {
169 int guidConversionResult
=
170 ::StringFromGUID2(aGuid
, &aBuf
[kSubkeyLen
], aBufLen
- kSubkeyLen
);
171 if (!guidConversionResult
) {
178 } // namespace detail
180 long CreateStream(const uint8_t* aInitBuf
, const uint32_t aInitBufSize
,
181 IStream
** aOutStream
) {
182 if (!aInitBufSize
|| !aOutStream
) {
186 *aOutStream
= nullptr;
189 RefPtr
<IStream
> stream
;
191 // If aInitBuf is null then initSize must be 0.
192 UINT initSize
= aInitBuf
? aInitBufSize
: 0;
193 stream
= already_AddRefed
<IStream
>(::SHCreateMemStream(aInitBuf
, initSize
));
195 return E_OUTOFMEMORY
;
199 // Now we'll set the required size
200 ULARGE_INTEGER newSize
;
201 newSize
.QuadPart
= aInitBufSize
;
202 hr
= stream
->SetSize(newSize
);
208 // Ensure that the stream is rewound
209 LARGE_INTEGER streamOffset
;
210 streamOffset
.QuadPart
= 0LL;
211 hr
= stream
->Seek(streamOffset
, STREAM_SEEK_SET
, nullptr);
216 stream
.forget(aOutStream
);
220 #if defined(MOZILLA_INTERNAL_API)
222 void GUIDToString(REFGUID aGuid
, nsAString
& aOutString
) {
223 // This buffer length is long enough to hold a GUID string that is formatted
224 // to include curly braces and dashes.
225 const int kBufLenWithNul
= 39;
226 aOutString
.SetLength(kBufLenWithNul
);
227 int result
= StringFromGUID2(aGuid
, char16ptr_t(aOutString
.BeginWriting()),
231 // Truncate the terminator
232 aOutString
.SetLength(result
- 1);
236 // Undocumented IIDs that are relevant for diagnostic purposes
237 static const IID IID_ISCMLocalActivator
= {
241 {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
242 static const IID IID_IRundown
= {
246 {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
247 static const IID IID_IRemUnknown
= {
251 {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
252 static const IID IID_IRemUnknown2
= {
256 {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
258 struct IIDToLiteralMapEntry
{
259 constexpr IIDToLiteralMapEntry(REFIID aIid
, nsLiteralCString
&& aStr
)
260 : mIid(aIid
), mStr(std::forward
<nsLiteralCString
>(aStr
)) {}
263 const nsLiteralCString mStr
;
267 * Given the name of an interface, the IID_ENTRY macro generates a pair
268 * containing a reference to the interface ID and a stringified version of
269 * the interface name.
273 * {IID_ENTRY(IUnknown)}
275 * {IID_IUnknown, "IUnknown"_ns}
279 # define IID_ENTRY_STRINGIFY(iface) #iface##_ns
280 # define IID_ENTRY(iface) IID_##iface, IID_ENTRY_STRINGIFY(iface)
283 // Mapping of selected IIDs to friendly, human readable descriptions for each
285 static constexpr IIDToLiteralMapEntry sIidDiagStrs
[] = {
286 {IID_ENTRY(IUnknown
)},
287 {IID_IRemUnknown
, "cross-apartment IUnknown"_ns
},
288 {IID_IRundown
, "cross-apartment object management"_ns
},
289 {IID_ISCMLocalActivator
, "out-of-process object instantiation"_ns
},
290 {IID_IRemUnknown2
, "cross-apartment IUnknown"_ns
}};
293 # undef IID_ENTRY_STRINGIFY
295 void DiagnosticNameForIID(REFIID aIid
, nsACString
& aOutString
) {
296 // If the IID matches something in sIidDiagStrs, output its string.
297 for (const auto& curEntry
: sIidDiagStrs
) {
298 if (curEntry
.mIid
== aIid
) {
299 aOutString
.Assign(curEntry
.mStr
);
304 // Otherwise just convert the IID to string form and output that.
306 GUIDToString(aIid
, strIid
);
308 aOutString
.AssignLiteral("IID ");
309 AppendUTF16toUTF8(strIid
, aOutString
);
314 void GUIDToString(REFGUID aGuid
,
315 wchar_t (&aOutBuf
)[kGuidRegFormatCharLenInclNul
]) {
316 DebugOnly
<int> result
=
317 ::StringFromGUID2(aGuid
, aOutBuf
, ArrayLength(aOutBuf
));
321 #endif // defined(MOZILLA_INTERNAL_API)
323 #if defined(MOZILLA_INTERNAL_API)
324 bool IsClassThreadAwareInprocServer(REFCLSID aClsid
) {
325 nsAutoString strClsid
;
326 GUIDToString(aClsid
, strClsid
);
328 nsAutoString
inprocServerSubkey(u
"CLSID\\"_ns
);
329 inprocServerSubkey
.Append(strClsid
);
330 inprocServerSubkey
.Append(u
"\\InprocServer32"_ns
);
332 // Of the possible values, "Apartment" is the longest, so we'll make this
333 // buffer large enough to hold that one.
334 wchar_t threadingModelBuf
[ArrayLength(L
"Apartment")] = {};
336 DWORD numBytes
= sizeof(threadingModelBuf
);
337 LONG result
= ::RegGetValueW(HKEY_CLASSES_ROOT
, inprocServerSubkey
.get(),
338 L
"ThreadingModel", RRF_RT_REG_SZ
, nullptr,
339 threadingModelBuf
, &numBytes
);
340 if (result
!= ERROR_SUCCESS
) {
341 // This will also handle the case where the CLSID is not an inproc server.
345 DWORD numChars
= numBytes
/ sizeof(wchar_t);
346 // numChars includes the null terminator
351 nsDependentString
threadingModel(threadingModelBuf
, numChars
- 1);
353 // Ensure that the threading model is one of the known values that indicates
354 // that the class can operate natively (ie, no proxying) inside a MTA.
355 return threadingModel
.LowerCaseEqualsLiteral("both") ||
356 threadingModel
.LowerCaseEqualsLiteral("free") ||
357 threadingModel
.LowerCaseEqualsLiteral("neutral");
359 #endif // defined(MOZILLA_INTERNAL_API)
362 } // namespace mozilla