summaryrefslogtreecommitdiffstats
path: root/ipc/mscom/oop/Factory.h
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/mscom/oop/Factory.h')
-rw-r--r--ipc/mscom/oop/Factory.h142
1 files changed, 142 insertions, 0 deletions
diff --git a/ipc/mscom/oop/Factory.h b/ipc/mscom/oop/Factory.h
new file mode 100644
index 0000000000..e95f1d2499
--- /dev/null
+++ b/ipc/mscom/oop/Factory.h
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_mscom_Factory_h
+#define mozilla_mscom_Factory_h
+
+#if defined(MOZILLA_INTERNAL_API)
+# error This code is NOT for internal Gecko use!
+#endif // defined(MOZILLA_INTERNAL_API)
+
+#include <objbase.h>
+#include <unknwn.h>
+
+#include <utility>
+
+#include "Module.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/StaticPtr.h"
+
+/* WARNING! The code in this file may be loaded into the address spaces of other
+ processes! It MUST NOT link against xul.dll or other Gecko binaries! Only
+ inline code may be included! */
+
+namespace mozilla {
+namespace mscom {
+
+template <typename T>
+class MOZ_NONHEAP_CLASS Factory : public IClassFactory {
+ template <typename... Args>
+ HRESULT DoCreate(Args&&... args) {
+ MOZ_DIAGNOSTIC_ASSERT(false, "This should not be executed");
+ return E_NOTIMPL;
+ }
+
+ template <typename... Args>
+ HRESULT DoCreate(HRESULT (*aFnPtr)(IUnknown*, REFIID, void**),
+ Args&&... args) {
+ return aFnPtr(std::forward<Args>(args)...);
+ }
+
+ public:
+ // IUnknown
+ STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override {
+ if (!aOutInterface) {
+ return E_INVALIDARG;
+ }
+
+ if (aIid == IID_IUnknown || aIid == IID_IClassFactory) {
+ RefPtr<IClassFactory> punk(this);
+ punk.forget(aOutInterface);
+ return S_OK;
+ }
+
+ *aOutInterface = nullptr;
+
+ return E_NOINTERFACE;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef() override {
+ Module::Lock();
+ return 2;
+ }
+
+ STDMETHODIMP_(ULONG) Release() override {
+ Module::Unlock();
+ return 1;
+ }
+
+ // IClassFactory
+ STDMETHODIMP CreateInstance(IUnknown* aOuter, REFIID aIid,
+ void** aOutInterface) override {
+ return DoCreate(&T::Create, aOuter, aIid, aOutInterface);
+ }
+
+ STDMETHODIMP LockServer(BOOL aLock) override {
+ if (aLock) {
+ Module::Lock();
+ } else {
+ Module::Unlock();
+ }
+ return S_OK;
+ }
+};
+
+template <typename T>
+class MOZ_NONHEAP_CLASS SingletonFactory : public Factory<T> {
+ public:
+ STDMETHODIMP CreateInstance(IUnknown* aOuter, REFIID aIid,
+ void** aOutInterface) override {
+ if (aOuter || !aOutInterface) {
+ return E_INVALIDARG;
+ }
+
+ RefPtr<T> obj(sInstance);
+ if (!obj) {
+ obj = GetOrCreateSingleton();
+ }
+
+ return obj->QueryInterface(aIid, aOutInterface);
+ }
+
+ RefPtr<T> GetOrCreateSingleton() {
+ if (!sInstance) {
+ RefPtr<T> object;
+ if (FAILED(T::Create(getter_AddRefs(object)))) {
+ return nullptr;
+ }
+
+ sInstance = object.forget();
+ }
+
+ return sInstance;
+ }
+
+ RefPtr<T> GetSingleton() { return sInstance; }
+
+ void ClearSingleton() {
+ if (!sInstance) {
+ return;
+ }
+
+ DebugOnly<HRESULT> hr = ::CoDisconnectObject(sInstance.get(), 0);
+ MOZ_ASSERT(SUCCEEDED(hr));
+ sInstance = nullptr;
+ }
+
+ private:
+ static StaticRefPtr<T> sInstance;
+};
+
+template <typename T>
+StaticRefPtr<T> SingletonFactory<T>::sInstance;
+
+} // namespace mscom
+} // namespace mozilla
+
+#endif // mozilla_mscom_Factory_h