1 /* Tests for Thread and SHGlobalCounter functions
3 * Copyright 2010 Detlef Riekenberg
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.
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.
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
32 #include "wine/test.h"
34 static HRESULT (WINAPI
*pSHCreateThreadRef
)(LONG
*, IUnknown
**);
35 static HRESULT (WINAPI
*pSHGetThreadRef
)(IUnknown
**);
36 static HRESULT (WINAPI
*pSHSetThreadRef
)(IUnknown
*);
38 static DWORD AddRef_called
;
42 IUnknown IUnknown_iface
;
46 static inline threadref
*impl_from_IUnknown(IUnknown
*iface
)
48 return CONTAINING_RECORD(iface
, threadref
, IUnknown_iface
);
51 static HRESULT WINAPI
threadref_QueryInterface(IUnknown
*iface
, REFIID riid
, LPVOID
*ppvObj
)
53 threadref
* This
= impl_from_IUnknown(iface
);
55 trace("unexpected QueryInterface(%p, %s, %p) called\n", This
, wine_dbgstr_guid(riid
), ppvObj
);
60 static ULONG WINAPI
threadref_AddRef(IUnknown
*iface
)
62 threadref
* This
= impl_from_IUnknown(iface
);
65 return InterlockedIncrement(This
->ref
);
68 static ULONG WINAPI
threadref_Release(IUnknown
*iface
)
70 threadref
* This
= impl_from_IUnknown(iface
);
72 trace("unexpected Release(%p) called\n", This
);
73 return InterlockedDecrement(This
->ref
);
77 static const IUnknownVtbl threadref_vt
=
79 threadref_QueryInterface
,
84 static void init_threadref(threadref
* iface
, LONG
*refcount
)
86 iface
->IUnknown_iface
.lpVtbl
= &threadref_vt
;
87 iface
->ref
= refcount
;
92 static void test_SHCreateThreadRef(void)
99 /* Not present before IE 6_XP_sp2 */
100 if (!pSHCreateThreadRef
) {
101 win_skip("SHCreateThreadRef not found\n");
105 /* start with a clean state */
106 hr
= pSHSetThreadRef(NULL
);
107 ok(hr
== S_OK
, "got 0x%x (expected S_OK)\n", hr
);
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",
116 /* the object is not automatic set as ThreadRef */
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
);
123 hr
= pSHSetThreadRef(pobj
);
124 ok(hr
== S_OK
, "got 0x%x (expected S_OK)\n", hr
);
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
);
133 /* free the ref from SHGetThreadRef */
135 hr
= IUnknown_Release(pobj
);
136 ok((hr
== 1) && (hr
== refcount
),
137 "got %d with %d (expected 1 with 1)\n", hr
, refcount
);
140 /* free the object */
142 hr
= IUnknown_Release(pobj
);
143 ok((hr
== 0) && (hr
== refcount
),
144 "got %d with %d (expected 0 with 0)\n", hr
, refcount
);
148 /* the ThreadRef has still the pointer,
149 but the object no longer exist after the *_Release */
151 hr
= pSHGetThreadRef(&punk
);
152 trace("got 0x%x and %p with %d\n", hr
, punk
, refcount
);
155 /* remove the dead object pointer */
156 hr
= pSHSetThreadRef(NULL
);
157 ok(hr
== S_OK
, "got 0x%x (expected S_OK)\n", hr
);
159 /* parameter check */
161 /* vista: E_INVALIDARG, XP: crash */
163 hr
= pSHCreateThreadRef(NULL
, &pobj
);
164 ok(hr
== E_INVALIDARG
, "got 0x%x (expected E_INVALIDARG)\n", hr
);
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",
176 static void test_SHGetThreadRef(void)
181 /* Not present before IE 5 */
182 if (!pSHGetThreadRef
) {
183 win_skip("SHGetThreadRef not found\n");
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
);
193 /* this crash on Windows */
194 pSHGetThreadRef(NULL
);
198 static void test_SHSetThreadRef(void)
205 /* Not present before IE 5 */
206 if (!pSHSetThreadRef
) {
207 win_skip("SHSetThreadRef not found\n");
211 /* start with a clean state */
212 hr
= pSHSetThreadRef(NULL
);
213 ok(hr
== S_OK
, "got 0x%x (expected S_OK)\n", hr
);
215 /* build and set out object */
216 init_threadref(&ref
, &refcount
);
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
);
224 /* read back our object */
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
);
233 /* clear the object pointer */
234 hr
= pSHSetThreadRef(NULL
);
235 ok(hr
== S_OK
, "got 0x%x (expected S_OK)\n", hr
);
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
);
246 HMODULE hshlwapi
= GetModuleHandleA("shlwapi.dll");
248 pSHCreateThreadRef
= (void *) GetProcAddress(hshlwapi
, "SHCreateThreadRef");
249 pSHGetThreadRef
= (void *) GetProcAddress(hshlwapi
, "SHGetThreadRef");
250 pSHSetThreadRef
= (void *) GetProcAddress(hshlwapi
, "SHSetThreadRef");
252 test_SHCreateThreadRef();
253 test_SHGetThreadRef();
254 test_SHSetThreadRef();