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 "mozilla/dom/ContentChild.h"
11 #if defined(ACCESSIBILITY)
12 # include "mozilla/mscom/Registration.h"
13 # if defined(MOZILLA_INTERNAL_API)
14 # include "nsTArray.h"
18 #include "mozilla/mscom/Objref.h"
19 #include "mozilla/mscom/Utils.h"
20 #include "mozilla/RefPtr.h"
21 #include "mozilla/WindowsVersion.h"
29 extern "C" IMAGE_DOS_HEADER __ImageBase
;
35 bool IsCOMInitializedOnCurrentThread() {
37 APTTYPEQUALIFIER aptTypeQualifier
;
38 HRESULT hr
= CoGetApartmentType(&aptType
, &aptTypeQualifier
);
39 return hr
!= CO_E_NOTINITIALIZED
;
42 bool IsCurrentThreadMTA() {
44 APTTYPEQUALIFIER aptTypeQualifier
;
45 HRESULT hr
= CoGetApartmentType(&aptType
, &aptTypeQualifier
);
50 return aptType
== APTTYPE_MTA
;
53 bool IsCurrentThreadExplicitMTA() {
55 APTTYPEQUALIFIER aptTypeQualifier
;
56 HRESULT hr
= CoGetApartmentType(&aptType
, &aptTypeQualifier
);
61 return aptType
== APTTYPE_MTA
&&
62 aptTypeQualifier
!= APTTYPEQUALIFIER_IMPLICIT_MTA
;
65 bool IsCurrentThreadImplicitMTA() {
67 APTTYPEQUALIFIER aptTypeQualifier
;
68 HRESULT hr
= CoGetApartmentType(&aptType
, &aptTypeQualifier
);
73 return aptType
== APTTYPE_MTA
&&
74 aptTypeQualifier
== APTTYPEQUALIFIER_IMPLICIT_MTA
;
77 bool IsProxy(IUnknown
* aUnknown
) {
82 // Only proxies implement this interface, so if it is present then we must
83 // be dealing with a proxied object.
84 RefPtr
<IClientSecurity
> clientSecurity
;
85 HRESULT hr
= aUnknown
->QueryInterface(IID_IClientSecurity
,
86 (void**)getter_AddRefs(clientSecurity
));
87 if (SUCCEEDED(hr
) || hr
== RPC_E_WRONG_THREAD
) {
93 bool IsValidGUID(REFGUID aCheckGuid
) {
94 // This function determines whether or not aCheckGuid conforms to RFC4122
95 // as it applies to Microsoft COM.
97 BYTE variant
= aCheckGuid
.Data4
[0];
98 if (!(variant
& 0x80)) {
102 if ((variant
& 0xE0) == 0xE0) {
103 // Reserved for future use
106 if ((variant
& 0xC0) == 0xC0) {
107 // Microsoft Reserved.
111 BYTE version
= HIBYTE(aCheckGuid
.Data3
) >> 4;
112 // Other versions are specified in RFC4122 but these are the two used by COM.
113 return version
== 1 || version
== 4;
116 uintptr_t GetContainingModuleHandle() {
117 HMODULE thisModule
= nullptr;
118 #if defined(_MSC_VER)
119 thisModule
= reinterpret_cast<HMODULE
>(&__ImageBase
);
121 if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
|
122 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
,
123 reinterpret_cast<LPCTSTR
>(&GetContainingModuleHandle
),
128 return reinterpret_cast<uintptr_t>(thisModule
);
131 uint32_t CreateStream(const uint8_t* aInitBuf
, const uint32_t aInitBufSize
,
132 IStream
** aOutStream
) {
133 if (!aInitBufSize
|| !aOutStream
) {
137 *aOutStream
= nullptr;
140 RefPtr
<IStream
> stream
;
142 if (IsWin8OrLater()) {
143 // SHCreateMemStream is not safe for us to use until Windows 8. On older
144 // versions of Windows it is not thread-safe and it creates IStreams that do
145 // not support the full IStream API.
147 // If aInitBuf is null then initSize must be 0.
148 UINT initSize
= aInitBuf
? aInitBufSize
: 0;
149 stream
= already_AddRefed
<IStream
>(::SHCreateMemStream(aInitBuf
, initSize
));
151 return E_OUTOFMEMORY
;
155 // Now we'll set the required size
156 ULARGE_INTEGER newSize
;
157 newSize
.QuadPart
= aInitBufSize
;
158 hr
= stream
->SetSize(newSize
);
164 HGLOBAL hglobal
= ::GlobalAlloc(GMEM_MOVEABLE
, aInitBufSize
);
166 return HRESULT_FROM_WIN32(::GetLastError());
169 // stream takes ownership of hglobal if this call is successful
170 hr
= ::CreateStreamOnHGlobal(hglobal
, TRUE
, getter_AddRefs(stream
));
172 ::GlobalFree(hglobal
);
176 // The default stream size is derived from ::GlobalSize(hglobal), which due
177 // to rounding may be larger than aInitBufSize. We forcibly set the correct
179 ULARGE_INTEGER streamSize
;
180 streamSize
.QuadPart
= aInitBufSize
;
181 hr
= stream
->SetSize(streamSize
);
188 hr
= stream
->Write(aInitBuf
, aInitBufSize
, &bytesWritten
);
193 if (bytesWritten
!= aInitBufSize
) {
199 // Ensure that the stream is rewound
200 LARGE_INTEGER streamOffset
;
201 streamOffset
.QuadPart
= 0LL;
202 hr
= stream
->Seek(streamOffset
, STREAM_SEEK_SET
, nullptr);
207 stream
.forget(aOutStream
);
211 uint32_t CopySerializedProxy(IStream
* aInStream
, IStream
** aOutStream
) {
212 if (!aInStream
|| !aOutStream
) {
216 *aOutStream
= nullptr;
218 uint32_t desiredStreamSize
= GetOBJREFSize(WrapNotNull(aInStream
));
219 if (!desiredStreamSize
) {
223 RefPtr
<IStream
> stream
;
224 HRESULT hr
= CreateStream(nullptr, desiredStreamSize
, getter_AddRefs(stream
));
229 ULARGE_INTEGER numBytesToCopy
;
230 numBytesToCopy
.QuadPart
= desiredStreamSize
;
231 hr
= aInStream
->CopyTo(stream
, numBytesToCopy
, nullptr, nullptr);
236 LARGE_INTEGER seekTo
;
237 seekTo
.QuadPart
= 0LL;
238 hr
= stream
->Seek(seekTo
, STREAM_SEEK_SET
, nullptr);
243 stream
.forget(aOutStream
);
247 #if defined(MOZILLA_INTERNAL_API)
249 void GUIDToString(REFGUID aGuid
, nsAString
& aOutString
) {
250 // This buffer length is long enough to hold a GUID string that is formatted
251 // to include curly braces and dashes.
252 const int kBufLenWithNul
= 39;
253 aOutString
.SetLength(kBufLenWithNul
);
254 int result
= StringFromGUID2(aGuid
, char16ptr_t(aOutString
.BeginWriting()),
258 // Truncate the terminator
259 aOutString
.SetLength(result
- 1);
263 #endif // defined(MOZILLA_INTERNAL_API)
265 #if defined(ACCESSIBILITY)
267 static bool IsVtableIndexFromParentInterface(TYPEATTR
* aTypeAttr
,
268 unsigned long aVtableIndex
) {
269 MOZ_ASSERT(aTypeAttr
);
271 // This is the number of functions declared in this interface (excluding
272 // parent interfaces).
273 unsigned int numExclusiveFuncs
= aTypeAttr
->cFuncs
;
275 // This is the number of vtable entries (which includes parent interfaces).
276 // TYPEATTR::cbSizeVft is the entire vtable size in bytes, so we need to
277 // divide in order to compute the number of entries.
278 unsigned int numVtblEntries
= aTypeAttr
->cbSizeVft
/ sizeof(void*);
280 // This is the index of the first entry in the vtable that belongs to this
281 // interface and not a parent.
282 unsigned int firstVtblIndex
= numVtblEntries
- numExclusiveFuncs
;
284 // If aVtableIndex is less than firstVtblIndex, then we're asking for an
285 // index that may belong to a parent interface.
286 return aVtableIndex
< firstVtblIndex
;
289 bool IsVtableIndexFromParentInterface(REFIID aInterface
,
290 unsigned long aVtableIndex
) {
291 RefPtr
<ITypeInfo
> typeInfo
;
292 if (!RegisteredProxy::Find(aInterface
, getter_AddRefs(typeInfo
))) {
296 TYPEATTR
* typeAttr
= nullptr;
297 HRESULT hr
= typeInfo
->GetTypeAttr(&typeAttr
);
302 bool result
= IsVtableIndexFromParentInterface(typeAttr
, aVtableIndex
);
304 typeInfo
->ReleaseTypeAttr(typeAttr
);
308 # if defined(MOZILLA_INTERNAL_API)
310 bool IsCallerExternalProcess() {
311 MOZ_ASSERT(XRE_IsContentProcess());
314 * CoGetCallerTID() gives us the caller's thread ID when that thread resides
315 * in a single-threaded apartment. Since our chrome main thread does live
316 * inside an STA, we will therefore be able to check whether the caller TID
317 * equals our chrome main thread TID. This enables us to distinguish
318 * between our chrome thread vs other out-of-process callers. We check for
319 * S_FALSE to ensure that the caller is a different process from ours, which
320 * is the only scenario that we care about.
323 if (::CoGetCallerTID(&callerTid
) != S_FALSE
) {
327 // Now check whether the caller is our parent process main thread.
328 const DWORD parentMainTid
=
329 dom::ContentChild::GetSingleton()->GetChromeMainThreadId();
330 return callerTid
!= parentMainTid
;
333 bool IsInterfaceEqualToOrInheritedFrom(REFIID aInterface
, REFIID aFrom
,
334 unsigned long aVtableIndexHint
) {
335 if (aInterface
== aFrom
) {
339 // We expect this array to be length 1 but that is not guaranteed by the API.
340 AutoTArray
<RefPtr
<ITypeInfo
>, 1> typeInfos
;
342 // Grab aInterface's ITypeInfo so that we may obtain information about its
343 // inheritance hierarchy.
344 RefPtr
<ITypeInfo
> typeInfo
;
345 if (RegisteredProxy::Find(aInterface
, getter_AddRefs(typeInfo
))) {
346 typeInfos
.AppendElement(std::move(typeInfo
));
350 * The main loop of this function searches the hierarchy of aInterface's
351 * parent interfaces, searching for aFrom.
353 while (!typeInfos
.IsEmpty()) {
354 RefPtr
<ITypeInfo
> curTypeInfo(typeInfos
.PopLastElement());
356 TYPEATTR
* typeAttr
= nullptr;
357 HRESULT hr
= curTypeInfo
->GetTypeAttr(&typeAttr
);
362 bool isFromParentVtable
=
363 IsVtableIndexFromParentInterface(typeAttr
, aVtableIndexHint
);
364 WORD numParentInterfaces
= typeAttr
->cImplTypes
;
366 curTypeInfo
->ReleaseTypeAttr(typeAttr
);
369 if (!isFromParentVtable
) {
370 // The vtable index cannot belong to this interface (otherwise the IIDs
371 // would already have matched and we would have returned true). Since we
372 // now also know that the vtable index cannot possibly be contained inside
373 // curTypeInfo's parent interface, there is no point searching any further
374 // up the hierarchy from here. OTOH we still should check any remaining
375 // entries that are still in the typeInfos array, so we continue.
379 for (WORD i
= 0; i
< numParentInterfaces
; ++i
) {
381 hr
= curTypeInfo
->GetRefTypeOfImplType(i
, &refCookie
);
386 RefPtr
<ITypeInfo
> nextTypeInfo
;
387 hr
= curTypeInfo
->GetRefTypeInfo(refCookie
, getter_AddRefs(nextTypeInfo
));
392 hr
= nextTypeInfo
->GetTypeAttr(&typeAttr
);
397 IID nextIid
= typeAttr
->guid
;
399 nextTypeInfo
->ReleaseTypeAttr(typeAttr
);
402 if (nextIid
== aFrom
) {
406 typeInfos
.AppendElement(std::move(nextTypeInfo
));
413 # endif // defined(MOZILLA_INTERNAL_API)
415 #endif // defined(ACCESSIBILITY)
417 #if defined(MOZILLA_INTERNAL_API)
418 bool IsClassThreadAwareInprocServer(REFCLSID aClsid
) {
419 nsAutoString strClsid
;
420 GUIDToString(aClsid
, strClsid
);
422 nsAutoString
inprocServerSubkey(u
"CLSID\\"_ns
);
423 inprocServerSubkey
.Append(strClsid
);
424 inprocServerSubkey
.Append(u
"\\InprocServer32"_ns
);
426 // Of the possible values, "Apartment" is the longest, so we'll make this
427 // buffer large enough to hold that one.
428 wchar_t threadingModelBuf
[ArrayLength(L
"Apartment")] = {};
430 DWORD numBytes
= sizeof(threadingModelBuf
);
431 LONG result
= ::RegGetValueW(HKEY_CLASSES_ROOT
, inprocServerSubkey
.get(),
432 L
"ThreadingModel", RRF_RT_REG_SZ
, nullptr,
433 threadingModelBuf
, &numBytes
);
434 if (result
!= ERROR_SUCCESS
) {
435 // This will also handle the case where the CLSID is not an inproc server.
439 DWORD numChars
= numBytes
/ sizeof(wchar_t);
440 // numChars includes the null terminator
445 nsDependentString
threadingModel(threadingModelBuf
, numChars
- 1);
447 // Ensure that the threading model is one of the known values that indicates
448 // that the class can operate natively (ie, no proxying) inside a MTA.
449 return threadingModel
.LowerCaseEqualsLiteral("both") ||
450 threadingModel
.LowerCaseEqualsLiteral("free") ||
451 threadingModel
.LowerCaseEqualsLiteral("neutral");
453 #endif // defined(MOZILLA_INTERNAL_API)
456 } // namespace mozilla