1 /* Tests for Thread and SHGlobalCounter functions
2  *
3  * Copyright 2010 Detlef Riekenberg
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include <stdio.h>
21 #include <stdarg.h>
22 
23 #define COBJMACROS
24 #define CONST_VTABLE
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winerror.h"
29 #include "ole2.h"
30 #include "shlwapi.h"
31 
32 #include "wine/test.h"
33 
34 static HRESULT (WINAPI *pSHCreateThreadRef)(LONG*, IUnknown**);
35 static HRESULT (WINAPI *pSHGetThreadRef)(IUnknown**);
36 static HRESULT (WINAPI *pSHSetThreadRef)(IUnknown*);
37 
38 static DWORD AddRef_called;
39 
40 typedef struct
41 {
42   IUnknown IUnknown_iface;
43   LONG  *ref;
44 } threadref;
45 
impl_from_IUnknown(IUnknown * iface)46 static inline threadref *impl_from_IUnknown(IUnknown *iface)
47 {
48   return CONTAINING_RECORD(iface, threadref, IUnknown_iface);
49 }
50 
threadref_QueryInterface(IUnknown * iface,REFIID riid,LPVOID * ppvObj)51 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj)
52 {
53     threadref * This = impl_from_IUnknown(iface);
54 
55     trace("unexpected QueryInterface(%p, %s, %p) called\n", This, wine_dbgstr_guid(riid), ppvObj);
56     *ppvObj = NULL;
57     return E_NOINTERFACE;
58 }
59 
threadref_AddRef(IUnknown * iface)60 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
61 {
62     threadref * This = impl_from_IUnknown(iface);
63 
64     AddRef_called++;
65     return InterlockedIncrement(This->ref);
66 }
67 
threadref_Release(IUnknown * iface)68 static ULONG WINAPI threadref_Release(IUnknown *iface)
69 {
70     threadref * This = impl_from_IUnknown(iface);
71 
72     trace("unexpected Release(%p) called\n", This);
73     return InterlockedDecrement(This->ref);
74 }
75 
76 /* VTable */
77 static const IUnknownVtbl threadref_vt =
78 {
79   threadref_QueryInterface,
80   threadref_AddRef,
81   threadref_Release
82 };
83 
init_threadref(threadref * iface,LONG * refcount)84 static void init_threadref(threadref* iface, LONG *refcount)
85 {
86   iface->IUnknown_iface.lpVtbl = &threadref_vt;
87   iface->ref = refcount;
88 }
89 
90 /* ##### */
91 
test_SHCreateThreadRef(void)92 static void test_SHCreateThreadRef(void)
93 {
94     IUnknown *pobj;
95     IUnknown *punk;
96     LONG refcount;
97     HRESULT hr;
98 
99     /* Not present before IE 6_XP_sp2 */
100     if (!pSHCreateThreadRef) {
101         win_skip("SHCreateThreadRef not found\n");
102         return;
103     }
104 
105     /* start with a clean state */
106     hr = pSHSetThreadRef(NULL);
107     ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
108 
109     pobj = NULL;
110     refcount = 0xdeadbeef;
111     hr = pSHCreateThreadRef(&refcount, &pobj);
112     ok((hr == S_OK) && pobj && (refcount == 1),
113         "got 0x%x and %p with %d (expected S_OK and '!= NULL' with 1)\n",
114         hr, pobj, refcount);
115 
116     /* the object is not automatic set as ThreadRef */
117     punk = NULL;
118     hr = pSHGetThreadRef(&punk);
119     ok( (hr == E_NOINTERFACE) && (punk == NULL),
120         "got 0x%x and %p (expected E_NOINTERFACE and NULL)\n", hr, punk);
121 
122     /* set the object */
123     hr = pSHSetThreadRef(pobj);
124     ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
125 
126     /* read back */
127     punk = NULL;
128     hr = pSHGetThreadRef(&punk);
129     ok( (hr == S_OK) && (punk == pobj) && (refcount == 2),
130         "got 0x%x and %p with %d (expected S_OK and %p with 2)\n",
131         hr, punk, refcount, pobj);
132 
133     /* free the ref from SHGetThreadRef */
134     if (SUCCEEDED(hr)) {
135         hr = IUnknown_Release(pobj);
136         ok((hr == 1) && (hr == refcount),
137             "got %d with %d (expected 1 with 1)\n", hr, refcount);
138     }
139 
140     /* free the object */
141     if (pobj) {
142         hr = IUnknown_Release(pobj);
143         ok((hr == 0) && (hr == refcount),
144             "got %d with %d (expected 0 with 0)\n", hr, refcount);
145     }
146 
147     if (0) {
148         /* the ThreadRef has still the pointer,
149            but the object no longer exist after the *_Release */
150         punk = NULL;
151         hr = pSHGetThreadRef(&punk);
152         trace("got 0x%x and %p with %d\n", hr, punk, refcount);
153     }
154 
155     /* remove the dead object pointer */
156     hr = pSHSetThreadRef(NULL);
157     ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
158 
159     /* parameter check */
160     if (0) {
161         /* vista: E_INVALIDARG, XP: crash */
162         pobj = NULL;
163         hr = pSHCreateThreadRef(NULL, &pobj);
164         ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr);
165 
166         refcount = 0xdeadbeef;
167         /* vista: E_INVALIDARG, XP: crash */
168         hr = pSHCreateThreadRef(&refcount, NULL);
169         ok( (hr == E_INVALIDARG) && (refcount == 0xdeadbeef),
170             "got 0x%x with 0x%x (expected E_INVALIDARG and oxdeadbeef)\n",
171             hr, refcount);
172     }
173 }
174 
175 
test_SHGetThreadRef(void)176 static void test_SHGetThreadRef(void)
177 {
178     IUnknown *punk;
179     HRESULT hr;
180 
181     /* Not present before IE 5 */
182     if (!pSHGetThreadRef) {
183         win_skip("SHGetThreadRef not found\n");
184         return;
185     }
186 
187     punk = NULL;
188     hr = pSHGetThreadRef(&punk);
189     ok( (hr == E_NOINTERFACE) && (punk == NULL),
190         "got 0x%x and %p (expected E_NOINTERFACE and NULL)\n", hr, punk);
191 
192     if (0) {
193         /* this crash on Windows */
194         pSHGetThreadRef(NULL);
195     }
196 }
197 
test_SHSetThreadRef(void)198 static void test_SHSetThreadRef(void)
199 {
200     threadref ref;
201     IUnknown *punk;
202     HRESULT hr;
203     LONG refcount;
204 
205     /* Not present before IE 5 */
206     if (!pSHSetThreadRef) {
207         win_skip("SHSetThreadRef not found\n");
208         return;
209     }
210 
211     /* start with a clean state */
212     hr = pSHSetThreadRef(NULL);
213     ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
214 
215     /* build and set out object */
216     init_threadref(&ref, &refcount);
217     AddRef_called = 0;
218     refcount = 1;
219     hr = pSHSetThreadRef(&ref.IUnknown_iface);
220     ok( (hr == S_OK) && (refcount == 1) && (!AddRef_called),
221         "got 0x%x with %d, %d (expected S_OK with 1, 0)\n",
222         hr, refcount, AddRef_called);
223 
224     /* read back our object */
225     AddRef_called = 0;
226     refcount = 1;
227     punk = NULL;
228     hr = pSHGetThreadRef(&punk);
229     ok( (hr == S_OK) && (punk == &ref.IUnknown_iface) && (refcount == 2) && (AddRef_called == 1),
230         "got 0x%x and %p with %d, %d (expected S_OK and %p with 2, 1)\n",
231         hr, punk, refcount, AddRef_called, &ref);
232 
233     /* clear the object pointer */
234     hr = pSHSetThreadRef(NULL);
235     ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
236 
237     /* verify, that our object is no longer known as ThreadRef */
238     hr = pSHGetThreadRef(&punk);
239     ok( (hr == E_NOINTERFACE) && (punk == NULL),
240         "got 0x%x and %p (expected E_NOINTERFACE and NULL)\n", hr, punk);
241 
242 }
243 
START_TEST(thread)244 START_TEST(thread)
245 {
246     HMODULE hshlwapi = GetModuleHandleA("shlwapi.dll");
247 
248     pSHCreateThreadRef = (void *) GetProcAddress(hshlwapi, "SHCreateThreadRef");
249     pSHGetThreadRef = (void *) GetProcAddress(hshlwapi, "SHGetThreadRef");
250     pSHSetThreadRef = (void *) GetProcAddress(hshlwapi, "SHSetThreadRef");
251 
252     test_SHCreateThreadRef();
253     test_SHGetThreadRef();
254     test_SHSetThreadRef();
255 
256 }
257