1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include <windows.h>
7 #include <unknwn.h>
8 #include <stdio.h>
9 #include "nsISupports.h"
10 #include "nsIFactory.h"
11 
12 // unknwn.h is needed to build with WIN32_LEAN_AND_MEAN
13 #include <unknwn.h>
14 
15 #include "gtest/gtest.h"
16 
17 // {5846BA30-B856-11d1-A98A-00805F8A7AC4}
18 #define NS_ITEST_COM_IID                            \
19   {                                                 \
20     0x5846ba30, 0xb856, 0x11d1, {                   \
21       0xa9, 0x8a, 0x0, 0x80, 0x5f, 0x8a, 0x7a, 0xc4 \
22     }                                               \
23   }
24 
25 class nsITestCom : public nsISupports {
26  public:
27   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITEST_COM_IID)
28   NS_IMETHOD Test() = 0;
29 };
30 
31 NS_DEFINE_STATIC_IID_ACCESSOR(nsITestCom, NS_ITEST_COM_IID)
32 
33 /*
34  * nsTestCom
35  */
36 
37 class nsTestCom final : public nsITestCom {
38   NS_DECL_ISUPPORTS
39 
40  public:
nsTestCom()41   nsTestCom() {}
42 
Test()43   NS_IMETHOD Test() override { return NS_OK; }
44 
45   static int sDestructions;
46 
47  private:
~nsTestCom()48   ~nsTestCom() { sDestructions++; }
49 };
50 
51 int nsTestCom::sDestructions;
52 
NS_IMPL_QUERY_INTERFACE(nsTestCom,nsITestCom)53 NS_IMPL_QUERY_INTERFACE(nsTestCom, nsITestCom)
54 
55 MozExternalRefCountType nsTestCom::AddRef() {
56   nsrefcnt res = ++mRefCnt;
57   NS_LOG_ADDREF(this, mRefCnt, "nsTestCom", sizeof(*this));
58   return res;
59 }
60 
Release()61 MozExternalRefCountType nsTestCom::Release() {
62   nsrefcnt res = --mRefCnt;
63   NS_LOG_RELEASE(this, mRefCnt, "nsTestCom");
64   if (res == 0) {
65     delete this;
66   }
67   return res;
68 }
69 
70 class nsTestComFactory final : public nsIFactory {
~nsTestComFactory()71   ~nsTestComFactory() { sDestructions++; }
72   NS_DECL_ISUPPORTS
73  public:
nsTestComFactory()74   nsTestComFactory() {}
75 
76   NS_IMETHOD CreateInstance(nsISupports* aOuter, const nsIID& aIID,
77                             void** aResult);
78 
LockFactory(bool aLock)79   NS_IMETHOD LockFactory(bool aLock) override { return NS_OK; }
80 
81   static int sDestructions;
82 };
83 
84 int nsTestComFactory::sDestructions;
85 
NS_IMPL_ISUPPORTS(nsTestComFactory,nsIFactory)86 NS_IMPL_ISUPPORTS(nsTestComFactory, nsIFactory)
87 
88 nsresult nsTestComFactory::CreateInstance(nsISupports* aOuter,
89                                           const nsIID& aIID, void** aResult) {
90   if (aOuter != nullptr) {
91     return NS_ERROR_NO_AGGREGATION;
92   }
93 
94   nsTestCom* t = new nsTestCom();
95 
96   NS_ADDREF(t);
97   nsresult res = t->QueryInterface(aIID, aResult);
98   NS_RELEASE(t);
99 
100   return res;
101 }
102 
TEST(TestCOM,WindowsInterop)103 TEST(TestCOM, WindowsInterop)
104 {
105   nsTestComFactory* inst = new nsTestComFactory();
106 
107   // Test we can QI nsIFactory to an IClassFactory.
108   IClassFactory* iFactory = nullptr;
109   nsresult rv = inst->QueryInterface(NS_GET_IID(nsIFactory), (void**)&iFactory);
110   ASSERT_TRUE(NS_SUCCEEDED(rv));
111   ASSERT_TRUE(iFactory);
112 
113   // Test we can CreateInstance with an IUnknown.
114   IUnknown* iUnknown = nullptr;
115 
116   HRESULT hr = iFactory->LockServer(TRUE);
117   ASSERT_TRUE(SUCCEEDED(hr));
118   hr = iFactory->CreateInstance(nullptr, IID_IUnknown, (void**)&iUnknown);
119   ASSERT_TRUE(SUCCEEDED(hr));
120   ASSERT_TRUE(iUnknown);
121   hr = iFactory->LockServer(FALSE);
122   ASSERT_TRUE(SUCCEEDED(hr));
123 
124   // Test we can QI an IUnknown to nsITestCom.
125   nsITestCom* iTestCom = nullptr;
126   GUID testGUID = NS_ITEST_COM_IID;
127   hr = iUnknown->QueryInterface(testGUID, (void**)&iTestCom);
128   ASSERT_TRUE(SUCCEEDED(hr));
129   ASSERT_TRUE(iTestCom);
130 
131   // Make sure we can call our test function (and the pointer is valid).
132   rv = iTestCom->Test();
133   ASSERT_TRUE(NS_SUCCEEDED(rv));
134 
135   iUnknown->Release();
136   iTestCom->Release();
137   iFactory->Release();
138 
139   ASSERT_EQ(nsTestComFactory::sDestructions, 1);
140   ASSERT_EQ(nsTestCom::sDestructions, 1);
141 }
142