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
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/win/com_init_util.h"
#include <windows.h>
#include <winternl.h>
#include <stdint.h>
#include "base/logging.h"
#include "base/notreached.h"
namespace base {
namespace win {
namespace {
#if DCHECK_IS_ON()
const char kComNotInitialized[] = "COM is not initialized on this thread.";
#endif // DCHECK_IS_ON()
// Derived from combase.dll.
struct OleTlsData {
enum ApartmentFlags {
LOGICAL_THREAD_REGISTERED = 0x2,
STA = 0x80,
MTA = 0x140,
};
uintptr_t thread_base;
uintptr_t sm_allocator;
DWORD apartment_id;
DWORD apartment_flags;
// There are many more fields than this, but for our purposes, we only care
// about |apartment_flags|. Correctly declaring the previous types allows this
// to work between x86 and x64 builds.
};
OleTlsData* GetOleTlsData() {
::TEB* teb = NtCurrentTeb();
return reinterpret_cast<OleTlsData*>(teb->ReservedForOle);
}
} // namespace
ComApartmentType GetComApartmentTypeForThread() {
OleTlsData* ole_tls_data = GetOleTlsData();
if (!ole_tls_data) {
return ComApartmentType::NONE;
}
if (ole_tls_data->apartment_flags & OleTlsData::ApartmentFlags::STA) {
return ComApartmentType::STA;
}
if ((ole_tls_data->apartment_flags & OleTlsData::ApartmentFlags::MTA) ==
OleTlsData::ApartmentFlags::MTA) {
return ComApartmentType::MTA;
}
return ComApartmentType::NONE;
}
#if DCHECK_IS_ON()
void AssertComInitialized(const char* message) {
if (GetComApartmentTypeForThread() != ComApartmentType::NONE) {
return;
}
// COM worker threads don't always set up the apartment, but they do perform
// some thread registration, so we allow those.
OleTlsData* ole_tls_data = GetOleTlsData();
if (ole_tls_data && (ole_tls_data->apartment_flags &
OleTlsData::ApartmentFlags::LOGICAL_THREAD_REGISTERED)) {
return;
}
NOTREACHED() << (message ? message : kComNotInitialized);
}
void AssertComApartmentType(ComApartmentType apartment_type) {
DCHECK_EQ(apartment_type, GetComApartmentTypeForThread());
}
#endif // DCHECK_IS_ON()
} // namespace win
} // namespace base
|