1 /* 2 * General still image implementation 3 * 4 * Copyright 2009 Damjan Jovanovic 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 23 #include "windef.h" 24 #include "winbase.h" 25 #define COBJMACROS 26 #include <initguid.h> 27 #include <sti.h> 28 #include <guiddef.h> 29 #include <devguid.h> 30 #include <stdio.h> 31 32 #include "wine/test.h" 33 34 static HMODULE sti_dll; 35 static HRESULT (WINAPI *pStiCreateInstance)(HINSTANCE,DWORD,PSTIW*,LPUNKNOWN); 36 static HRESULT (WINAPI *pStiCreateInstanceA)(HINSTANCE,DWORD,PSTIA*,LPUNKNOWN); 37 static HRESULT (WINAPI *pStiCreateInstanceW)(HINSTANCE,DWORD,PSTIW*,LPUNKNOWN); 38 39 static BOOL aggregator_addref_called; 40 41 static HRESULT WINAPI aggregator_QueryInterface(IUnknown *iface, REFIID riid, void **ppvObject) 42 { 43 return E_NOTIMPL; 44 } 45 46 static ULONG WINAPI aggregator_AddRef(IUnknown *iface) 47 { 48 aggregator_addref_called = TRUE; 49 return 2; 50 } 51 52 static ULONG WINAPI aggregator_Release(IUnknown *iface) 53 { 54 return 1; 55 } 56 57 static struct IUnknownVtbl aggregator_vtbl = 58 { 59 aggregator_QueryInterface, 60 aggregator_AddRef, 61 aggregator_Release 62 }; 63 64 static BOOL init_function_pointers(void) 65 { 66 sti_dll = LoadLibraryA("sti.dll"); 67 if (sti_dll) 68 { 69 pStiCreateInstance = (void*) 70 GetProcAddress(sti_dll, "StiCreateInstance"); 71 pStiCreateInstanceA = (void*) 72 GetProcAddress(sti_dll, "StiCreateInstanceA"); 73 pStiCreateInstanceW = (void*) 74 GetProcAddress(sti_dll, "StiCreateInstanceW"); 75 return TRUE; 76 } 77 return FALSE; 78 } 79 80 static void test_version_flag_versus_aw(void) 81 { 82 HRESULT hr; 83 84 /* Who wins, the STI_VERSION_FLAG_UNICODE or the A/W function? And what about the neutral StiCreateInstance function? */ 85 86 if (pStiCreateInstance) 87 { 88 PSTIW pStiW; 89 hr = pStiCreateInstance(GetModuleHandleA(NULL), STI_VERSION_REAL, &pStiW, NULL); 90 if (SUCCEEDED(hr)) 91 { 92 IUnknown *pUnknown; 93 hr = IUnknown_QueryInterface((IUnknown*)pStiW, &IID_IStillImageW, (void**)&pUnknown); 94 if (SUCCEEDED(hr)) 95 { 96 ok(pUnknown == (IUnknown*)pStiW, "created interface was not IID_IStillImageW\n"); 97 IUnknown_Release(pUnknown); 98 } 99 IUnknown_Release((IUnknown*)pStiW); 100 } 101 else 102 ok(0, "could not create StillImageA, hr = 0x%X\n", hr); 103 hr = pStiCreateInstance(GetModuleHandleA(NULL), STI_VERSION_REAL | STI_VERSION_FLAG_UNICODE, &pStiW, NULL); 104 if (SUCCEEDED(hr)) 105 { 106 IUnknown *pUnknown; 107 hr = IUnknown_QueryInterface((IUnknown*)pStiW, &IID_IStillImageW, (void**)&pUnknown); 108 if (SUCCEEDED(hr)) 109 { 110 ok(pUnknown == (IUnknown*)pStiW, "created interface was not IID_IStillImageW\n"); 111 IUnknown_Release(pUnknown); 112 } 113 IUnknown_Release((IUnknown*)pStiW); 114 } 115 else 116 ok(0, "could not create StillImageW, hr = 0x%X\n", hr); 117 } 118 else 119 skip("No StiCreateInstance function\n"); 120 121 if (pStiCreateInstanceA) 122 { 123 PSTIA pStiA; 124 hr = pStiCreateInstanceA(GetModuleHandleA(NULL), STI_VERSION_REAL | STI_VERSION_FLAG_UNICODE, &pStiA, NULL); 125 if (SUCCEEDED(hr)) 126 { 127 IUnknown *pUnknown; 128 hr = IUnknown_QueryInterface((IUnknown*)pStiA, &IID_IStillImageA, (void**)&pUnknown); 129 if (SUCCEEDED(hr)) 130 { 131 ok(pUnknown == (IUnknown*)pStiA, "created interface was not IID_IStillImageA\n"); 132 IUnknown_Release(pUnknown); 133 } 134 IUnknown_Release((IUnknown*)pStiA); 135 } 136 else 137 todo_wine ok(0, "could not create StillImageA, hr = 0x%X\n", hr); 138 } 139 else 140 skip("No StiCreateInstanceA function\n"); 141 142 if (pStiCreateInstanceW) 143 { 144 PSTIW pStiW; 145 hr = pStiCreateInstanceW(GetModuleHandleA(NULL), STI_VERSION_REAL, &pStiW, NULL); 146 if (SUCCEEDED(hr)) 147 { 148 IUnknown *pUnknown; 149 hr = IUnknown_QueryInterface((IUnknown*)pStiW, &IID_IStillImageW, (void**)&pUnknown); 150 if (SUCCEEDED(hr)) 151 { 152 ok(pUnknown == (IUnknown*)pStiW, "created interface was not IID_IStillImageW\n"); 153 IUnknown_Release(pUnknown); 154 } 155 IUnknown_Release((IUnknown*)pStiW); 156 } 157 else 158 ok(0, "could not create StillImageW, hr = 0x%X\n", hr); 159 } 160 else 161 skip("No StiCreateInstanceW function\n"); 162 } 163 164 static void test_stillimage_aggregation(void) 165 { 166 if (pStiCreateInstanceW) 167 { 168 IUnknown aggregator = { &aggregator_vtbl }; 169 IStillImageW *pStiW; 170 IUnknown *pUnknown; 171 HRESULT hr; 172 173 /* When aggregating, the outer object must get the non-delegating IUnknown to be 174 able to control the inner object's reference count and query its interfaces. 175 But StiCreateInstance* only take PSTI. So how does the non-delegating IUnknown 176 come back to the outer object calling this function? */ 177 178 hr = pStiCreateInstanceW(GetModuleHandleA(NULL), STI_VERSION_REAL, &pStiW, &aggregator); 179 if (SUCCEEDED(hr)) 180 { 181 IStillImageW *pStiW2 = NULL; 182 183 /* Does this interface delegate? */ 184 aggregator_addref_called = FALSE; 185 IStillImage_AddRef(pStiW); 186 ok(!aggregator_addref_called, "the aggregated IStillImageW shouldn't delegate\n"); 187 IStillImage_Release(pStiW); 188 189 /* Tests show calling IStillImageW_WriteToErrorLog on the interface segfaults on Windows, so I guess it's an IUnknown. 190 But querying for an IUnknown returns a different interface, which also delegates. 191 So much for COM being reflexive... 192 Anyway I doubt apps depend on any of this. */ 193 194 /* And what about the IStillImageW interface? */ 195 hr = IStillImage_QueryInterface(pStiW, &IID_IStillImageW, (void**)&pStiW2); 196 if (SUCCEEDED(hr)) 197 { 198 ok(pStiW != pStiW2, "the aggregated IStillImageW and its queried IStillImageW unexpectedly match\n"); 199 /* Does it delegate? */ 200 aggregator_addref_called = FALSE; 201 IStillImage_AddRef(pStiW2); 202 ok(aggregator_addref_called, "the created IStillImageW's IStillImageW should delegate\n"); 203 IStillImage_Release(pStiW2); 204 IStillImage_Release(pStiW2); 205 } 206 else 207 ok(0, "could not query for IID_IStillImageW, hr = 0x%x\n", hr); 208 209 IStillImage_Release(pStiW); 210 } 211 else 212 ok(0, "could not create StillImageW, hr = 0x%X\n", hr); 213 214 /* Now do the above tests prove that STI.DLL isn't picky about querying for IUnknown 215 in CoCreateInterface when aggregating? */ 216 hr = CoCreateInstance(&CLSID_Sti, &aggregator, CLSCTX_ALL, &IID_IStillImageW, (void**)&pStiW); 217 ok(FAILED(hr), "CoCreateInstance unexpectedly succeeded when querying for IStillImageW during aggregation\n"); 218 if (SUCCEEDED(hr)) 219 IStillImage_Release(pStiW); 220 hr = CoCreateInstance(&CLSID_Sti, &aggregator, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown); 221 ok(SUCCEEDED(hr) || 222 broken(hr == CLASS_E_NOAGGREGATION), /* Win 2000 */ 223 "CoCreateInstance unexpectedly failed when querying for IUnknown during aggregation, hr = 0x%x\n", hr); 224 if (SUCCEEDED(hr)) 225 IUnknown_Release(pUnknown); 226 } 227 else 228 skip("No StiCreateInstanceW function\n"); 229 } 230 231 static void test_launch_app_registry(void) 232 { 233 static WCHAR appName[] = {'w','i','n','e','s','t','i','t','e','s','t','a','p','p',0}; 234 IStillImageW *pStiW = NULL; 235 HRESULT hr; 236 237 if (pStiCreateInstanceW == NULL) 238 { 239 win_skip("No StiCreateInstanceW function\n"); 240 return; 241 } 242 243 hr = pStiCreateInstance(GetModuleHandleA(NULL), STI_VERSION_REAL | STI_VERSION_FLAG_UNICODE, &pStiW, NULL); 244 if (SUCCEEDED(hr)) 245 { 246 hr = IStillImage_RegisterLaunchApplication(pStiW, appName, appName); 247 if (hr == E_ACCESSDENIED) 248 skip("Not authorized to register a launch application\n"); 249 else if (SUCCEEDED(hr)) 250 { 251 hr = IStillImage_UnregisterLaunchApplication(pStiW, appName); 252 ok(SUCCEEDED(hr), "could not unregister launch application, error 0x%X\n", hr); 253 } 254 else 255 ok(0, "could not register launch application, error 0x%X\n", hr); 256 IStillImage_Release(pStiW); 257 } 258 else 259 ok(0, "could not create StillImageW, hr = 0x%X\n", hr); 260 } 261 262 START_TEST(sti) 263 { 264 if (SUCCEEDED(CoInitialize(NULL))) 265 { 266 if (init_function_pointers()) 267 { 268 test_version_flag_versus_aw(); 269 test_stillimage_aggregation(); 270 test_launch_app_registry(); 271 FreeLibrary(sti_dll); 272 } 273 else 274 skip("could not load sti.dll\n"); 275 CoUninitialize(); 276 } 277 else 278 skip("CoInitialize failed\n"); 279 } 280