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 46 static inline threadref *impl_from_IUnknown(IUnknown *iface) 47 { 48 return CONTAINING_RECORD(iface, threadref, IUnknown_iface); 49 } 50 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 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 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 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 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 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 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 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