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 "precomp.h" 21 22 static HRESULT (WINAPI *pSHCreateThreadRef)(LONG*, IUnknown**); 23 static HRESULT (WINAPI *pSHGetThreadRef)(IUnknown**); 24 static HRESULT (WINAPI *pSHSetThreadRef)(IUnknown*); 25 26 static DWORD AddRef_called; 27 28 typedef struct 29 { 30 IUnknown IUnknown_iface; 31 LONG *ref; 32 } threadref; 33 34 static inline threadref *impl_from_IUnknown(IUnknown *iface) 35 { 36 return CONTAINING_RECORD(iface, threadref, IUnknown_iface); 37 } 38 39 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj) 40 { 41 threadref * This = impl_from_IUnknown(iface); 42 43 trace("unexpected QueryInterface(%p, %s, %p) called\n", This, wine_dbgstr_guid(riid), ppvObj); 44 *ppvObj = NULL; 45 return E_NOINTERFACE; 46 } 47 48 static ULONG WINAPI threadref_AddRef(IUnknown *iface) 49 { 50 threadref * This = impl_from_IUnknown(iface); 51 52 AddRef_called++; 53 return InterlockedIncrement(This->ref); 54 } 55 56 static ULONG WINAPI threadref_Release(IUnknown *iface) 57 { 58 threadref * This = impl_from_IUnknown(iface); 59 60 trace("unexpected Release(%p) called\n", This); 61 return InterlockedDecrement(This->ref); 62 } 63 64 /* VTable */ 65 static const IUnknownVtbl threadref_vt = 66 { 67 threadref_QueryInterface, 68 threadref_AddRef, 69 threadref_Release 70 }; 71 72 static void init_threadref(threadref* iface, LONG *refcount) 73 { 74 iface->IUnknown_iface.lpVtbl = &threadref_vt; 75 iface->ref = refcount; 76 } 77 78 /* ##### */ 79 80 static void test_SHCreateThreadRef(void) 81 { 82 IUnknown *pobj; 83 IUnknown *punk; 84 LONG refcount; 85 HRESULT hr; 86 87 /* Not present before IE 6_XP_sp2 */ 88 if (!pSHCreateThreadRef) { 89 win_skip("SHCreateThreadRef not found\n"); 90 return; 91 } 92 93 /* start with a clean state */ 94 hr = pSHSetThreadRef(NULL); 95 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); 96 97 pobj = NULL; 98 refcount = 0xdeadbeef; 99 hr = pSHCreateThreadRef(&refcount, &pobj); 100 ok((hr == S_OK) && pobj && (refcount == 1), 101 "got 0x%x and %p with %d (expected S_OK and '!= NULL' with 1)\n", 102 hr, pobj, refcount); 103 104 /* the object is not automatic set as ThreadRef */ 105 punk = NULL; 106 hr = pSHGetThreadRef(&punk); 107 ok( (hr == E_NOINTERFACE) && (punk == NULL), 108 "got 0x%x and %p (expected E_NOINTERFACE and NULL)\n", hr, punk); 109 110 /* set the object */ 111 hr = pSHSetThreadRef(pobj); 112 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); 113 114 /* read back */ 115 punk = NULL; 116 hr = pSHGetThreadRef(&punk); 117 ok( (hr == S_OK) && (punk == pobj) && (refcount == 2), 118 "got 0x%x and %p with %d (expected S_OK and %p with 2)\n", 119 hr, punk, refcount, pobj); 120 121 /* free the ref from SHGetThreadRef */ 122 if (SUCCEEDED(hr)) { 123 hr = IUnknown_Release(pobj); 124 ok((hr == 1) && (hr == refcount), 125 "got %d with %d (expected 1 with 1)\n", hr, refcount); 126 } 127 128 /* free the object */ 129 if (pobj) { 130 hr = IUnknown_Release(pobj); 131 ok((hr == 0) && (hr == refcount), 132 "got %d with %d (expected 0 with 0)\n", hr, refcount); 133 } 134 135 if (0) { 136 /* the ThreadRef has still the pointer, 137 but the object no longer exist after the *_Release */ 138 punk = NULL; 139 hr = pSHGetThreadRef(&punk); 140 trace("got 0x%x and %p with %d\n", hr, punk, refcount); 141 } 142 143 /* remove the dead object pointer */ 144 hr = pSHSetThreadRef(NULL); 145 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); 146 147 /* parameter check */ 148 if (0) { 149 /* vista: E_INVALIDARG, XP: crash */ 150 pobj = NULL; 151 hr = pSHCreateThreadRef(NULL, &pobj); 152 ok(hr == E_INVALIDARG, "got 0x%x (expected E_INVALIDARG)\n", hr); 153 154 refcount = 0xdeadbeef; 155 /* vista: E_INVALIDARG, XP: crash */ 156 hr = pSHCreateThreadRef(&refcount, NULL); 157 ok( (hr == E_INVALIDARG) && (refcount == 0xdeadbeef), 158 "got 0x%x with 0x%x (expected E_INVALIDARG and oxdeadbeef)\n", 159 hr, refcount); 160 } 161 } 162 163 164 static void test_SHGetThreadRef(void) 165 { 166 IUnknown *punk; 167 HRESULT hr; 168 169 /* Not present before IE 5 */ 170 if (!pSHGetThreadRef) { 171 win_skip("SHGetThreadRef not found\n"); 172 return; 173 } 174 175 punk = NULL; 176 hr = pSHGetThreadRef(&punk); 177 ok( (hr == E_NOINTERFACE) && (punk == NULL), 178 "got 0x%x and %p (expected E_NOINTERFACE and NULL)\n", hr, punk); 179 180 if (0) { 181 /* this crash on Windows */ 182 pSHGetThreadRef(NULL); 183 } 184 } 185 186 static void test_SHSetThreadRef(void) 187 { 188 threadref ref; 189 IUnknown *punk; 190 HRESULT hr; 191 LONG refcount; 192 193 /* Not present before IE 5 */ 194 if (!pSHSetThreadRef) { 195 win_skip("SHSetThreadRef not found\n"); 196 return; 197 } 198 199 /* start with a clean state */ 200 hr = pSHSetThreadRef(NULL); 201 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); 202 203 /* build and set out object */ 204 init_threadref(&ref, &refcount); 205 AddRef_called = 0; 206 refcount = 1; 207 hr = pSHSetThreadRef(&ref.IUnknown_iface); 208 ok( (hr == S_OK) && (refcount == 1) && (!AddRef_called), 209 "got 0x%x with %d, %d (expected S_OK with 1, 0)\n", 210 hr, refcount, AddRef_called); 211 212 /* read back our object */ 213 AddRef_called = 0; 214 refcount = 1; 215 punk = NULL; 216 hr = pSHGetThreadRef(&punk); 217 ok( (hr == S_OK) && (punk == &ref.IUnknown_iface) && (refcount == 2) && (AddRef_called == 1), 218 "got 0x%x and %p with %d, %d (expected S_OK and %p with 2, 1)\n", 219 hr, punk, refcount, AddRef_called, &ref); 220 221 /* clear the object pointer */ 222 hr = pSHSetThreadRef(NULL); 223 ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr); 224 225 /* verify, that our object is no longer known as ThreadRef */ 226 hr = pSHGetThreadRef(&punk); 227 ok( (hr == E_NOINTERFACE) && (punk == NULL), 228 "got 0x%x and %p (expected E_NOINTERFACE and NULL)\n", hr, punk); 229 230 } 231 232 START_TEST(thread) 233 { 234 HMODULE hshlwapi = GetModuleHandleA("shlwapi.dll"); 235 236 pSHCreateThreadRef = (void *) GetProcAddress(hshlwapi, "SHCreateThreadRef"); 237 pSHGetThreadRef = (void *) GetProcAddress(hshlwapi, "SHGetThreadRef"); 238 pSHSetThreadRef = (void *) GetProcAddress(hshlwapi, "SHSetThreadRef"); 239 240 test_SHCreateThreadRef(); 241 test_SHGetThreadRef(); 242 test_SHSetThreadRef(); 243 244 } 245