sti.c 9.58 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 *    General still image implementation
 *
 * Copyright 2009 Damjan Jovanovic
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
22

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
#include "windef.h"
#include "winbase.h"
#define COBJMACROS
#include <initguid.h>
#include <sti.h>
#include <guiddef.h>
#include <devguid.h>
#include <stdio.h>

#include "wine/test.h"

static HMODULE sti_dll;
static HRESULT (WINAPI *pStiCreateInstance)(HINSTANCE,DWORD,PSTIW*,LPUNKNOWN);
static HRESULT (WINAPI *pStiCreateInstanceA)(HINSTANCE,DWORD,PSTIA*,LPUNKNOWN);
static HRESULT (WINAPI *pStiCreateInstanceW)(HINSTANCE,DWORD,PSTIW*,LPUNKNOWN);

39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
static BOOL aggregator_addref_called;

static HRESULT WINAPI aggregator_QueryInterface(IUnknown *iface, REFIID riid, void **ppvObject)
{
    return E_NOTIMPL;
}

static ULONG WINAPI aggregator_AddRef(IUnknown *iface)
{
    aggregator_addref_called = TRUE;
    return 2;
}

static ULONG WINAPI aggregator_Release(IUnknown *iface)
{
    return 1;
}

static struct IUnknownVtbl aggregator_vtbl =
{
    aggregator_QueryInterface,
    aggregator_AddRef,
    aggregator_Release
};

64 65
static BOOL init_function_pointers(void)
{
66
    sti_dll = LoadLibraryA("sti.dll");
67 68 69 70 71 72 73 74 75 76 77 78 79
    if (sti_dll)
    {
        pStiCreateInstance = (void*)
            GetProcAddress(sti_dll, "StiCreateInstance");
        pStiCreateInstanceA = (void*)
            GetProcAddress(sti_dll, "StiCreateInstanceA");
        pStiCreateInstanceW = (void*)
            GetProcAddress(sti_dll, "StiCreateInstanceW");
        return TRUE;
    }
    return FALSE;
}

80
static void test_version_flag_versus_aw(void)
81 82 83 84 85 86 87 88
{
    HRESULT hr;

    /* Who wins, the STI_VERSION_FLAG_UNICODE or the A/W function? And what about the neutral StiCreateInstance function? */

    if (pStiCreateInstance)
    {
        PSTIW pStiW;
89
        hr = pStiCreateInstance(GetModuleHandleA(NULL), STI_VERSION_REAL, &pStiW, NULL);
90 91 92 93 94 95 96 97 98 99 100 101
        if (SUCCEEDED(hr))
        {
            IUnknown *pUnknown;
            hr = IUnknown_QueryInterface((IUnknown*)pStiW, &IID_IStillImageW, (void**)&pUnknown);
            if (SUCCEEDED(hr))
            {
                ok(pUnknown == (IUnknown*)pStiW, "created interface was not IID_IStillImageW\n");
                IUnknown_Release(pUnknown);
            }
            IUnknown_Release((IUnknown*)pStiW);
        }
        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 105 106 107 108 109 110 111 112 113 114 115
        if (SUCCEEDED(hr))
        {
            IUnknown *pUnknown;
            hr = IUnknown_QueryInterface((IUnknown*)pStiW, &IID_IStillImageW, (void**)&pUnknown);
            if (SUCCEEDED(hr))
            {
                ok(pUnknown == (IUnknown*)pStiW, "created interface was not IID_IStillImageW\n");
                IUnknown_Release(pUnknown);
            }
            IUnknown_Release((IUnknown*)pStiW);
        }
        else
116
            ok(0, "could not create StillImageW, hr = 0x%X\n", hr);
117 118 119 120 121 122 123
    }
    else
        skip("No StiCreateInstance function\n");

    if (pStiCreateInstanceA)
    {
        PSTIA pStiA;
124
        hr = pStiCreateInstanceA(GetModuleHandleA(NULL), STI_VERSION_REAL | STI_VERSION_FLAG_UNICODE, &pStiA, NULL);
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
        if (SUCCEEDED(hr))
        {
            IUnknown *pUnknown;
            hr = IUnknown_QueryInterface((IUnknown*)pStiA, &IID_IStillImageA, (void**)&pUnknown);
            if (SUCCEEDED(hr))
            {
                ok(pUnknown == (IUnknown*)pStiA, "created interface was not IID_IStillImageA\n");
                IUnknown_Release(pUnknown);
            }
            IUnknown_Release((IUnknown*)pStiA);
        }
        else
            todo_wine ok(0, "could not create StillImageA, hr = 0x%X\n", hr);
    }
    else
        skip("No StiCreateInstanceA function\n");

    if (pStiCreateInstanceW)
    {
        PSTIW pStiW;
145
        hr = pStiCreateInstanceW(GetModuleHandleA(NULL), STI_VERSION_REAL, &pStiW, NULL);
146 147 148 149 150 151 152 153 154 155 156 157
        if (SUCCEEDED(hr))
        {
            IUnknown *pUnknown;
            hr = IUnknown_QueryInterface((IUnknown*)pStiW, &IID_IStillImageW, (void**)&pUnknown);
            if (SUCCEEDED(hr))
            {
                ok(pUnknown == (IUnknown*)pStiW, "created interface was not IID_IStillImageW\n");
                IUnknown_Release((IUnknown*)pUnknown);
            }
            IUnknown_Release((IUnknown*)pStiW);
        }
        else
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
            ok(0, "could not create StillImageW, hr = 0x%X\n", hr);
    }
    else
        skip("No StiCreateInstanceW function\n");
}

static void test_stillimage_aggregation(void)
{
    if (pStiCreateInstanceW)
    {
        IUnknown aggregator = { &aggregator_vtbl };
        IStillImageW *pStiW;
        IUnknown *pUnknown;
        HRESULT hr;

        /* When aggregating, the outer object must get the non-delegating IUnknown to be
           able to control the inner object's reference count and query its interfaces.
           But StiCreateInstance* only take PSTI. So how does the non-delegating IUnknown
           come back to the outer object calling this function? */

178
        hr = pStiCreateInstanceW(GetModuleHandleA(NULL), STI_VERSION_REAL, &pStiW, &aggregator);
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
        if (SUCCEEDED(hr))
        {
            IStillImageW *pStiW2 = NULL;

            /* Does this interface delegate? */
            aggregator_addref_called = FALSE;
            IStillImage_AddRef(pStiW);
            ok(!aggregator_addref_called, "the aggregated IStillImageW shouldn't delegate\n");
            IStillImage_Release(pStiW);

            /* Tests show calling IStillImageW_WriteToErrorLog on the interface segfaults on Windows, so I guess it's an IUnknown.
               But querying for an IUnknown returns a different interface, which also delegates.
               So much for COM being reflexive...
               Anyway I doubt apps depend on any of this. */

            /* And what about the IStillImageW interface? */
            hr = IStillImage_QueryInterface(pStiW, &IID_IStillImageW, (void**)&pStiW2);
            if (SUCCEEDED(hr))
            {
                ok(pStiW != pStiW2, "the aggregated IStillImageW and its queried IStillImageW unexpectedly match\n");
                /* Does it delegate? */
                aggregator_addref_called = FALSE;
                IStillImage_AddRef(pStiW2);
                ok(aggregator_addref_called, "the created IStillImageW's IStillImageW should delegate\n");
                IStillImage_Release(pStiW2);
                IStillImage_Release(pStiW2);
            }
            else
                ok(0, "could not query for IID_IStillImageW, hr = 0x%x\n", hr);

            IStillImage_Release(pStiW);
        }
        else
            ok(0, "could not create StillImageW, hr = 0x%X\n", hr);

        /* Now do the above tests prove that STI.DLL isn't picky about querying for IUnknown
           in CoCreateInterface when aggregating? */
        hr = CoCreateInstance(&CLSID_Sti, &aggregator, CLSCTX_ALL, &IID_IStillImageW, (void**)&pStiW);
        ok(FAILED(hr), "CoCreateInstance unexpectedly succeeded when querying for IStillImageW during aggregation\n");
        if (SUCCEEDED(hr))
            IStillImage_Release(pStiW);
        hr = CoCreateInstance(&CLSID_Sti, &aggregator, CLSCTX_ALL, &IID_IUnknown, (void**)&pUnknown);
221 222 223
        ok(SUCCEEDED(hr) ||
            broken(hr == CLASS_E_NOAGGREGATION), /* Win 2000 */
                "CoCreateInstance unexpectedly failed when querying for IUnknown during aggregation, hr = 0x%x\n", hr);
224 225
        if (SUCCEEDED(hr))
            IUnknown_Release(pUnknown);
226 227 228 229 230
    }
    else
        skip("No StiCreateInstanceW function\n");
}

231 232 233 234 235 236 237 238 239 240 241 242
static void test_launch_app_registry(void)
{
    static WCHAR appName[] = {'w','i','n','e','s','t','i','t','e','s','t','a','p','p',0};
    IStillImageW *pStiW = NULL;
    HRESULT hr;

    if (pStiCreateInstanceW == NULL)
    {
        win_skip("No StiCreateInstanceW function\n");
        return;
    }

243
    hr = pStiCreateInstance(GetModuleHandleA(NULL), STI_VERSION_REAL | STI_VERSION_FLAG_UNICODE, &pStiW, NULL);
244 245 246
    if (SUCCEEDED(hr))
    {
        hr = IStillImage_RegisterLaunchApplication(pStiW, appName, appName);
247 248 249
        if (hr == E_ACCESSDENIED)
            skip("Not authorized to register a launch application\n");
        else if (SUCCEEDED(hr))
250 251 252 253
        {
            hr = IStillImage_UnregisterLaunchApplication(pStiW, appName);
            ok(SUCCEEDED(hr), "could not unregister launch application, error 0x%X\n", hr);
        }
254 255
        else
            ok(0, "could not register launch application, error 0x%X\n", hr);
256 257 258 259 260 261
        IStillImage_Release(pStiW);
    }
    else
        ok(0, "could not create StillImageW, hr = 0x%X\n", hr);
}

262 263 264 265 266 267 268
START_TEST(sti)
{
    if (SUCCEEDED(CoInitialize(NULL)))
    {
        if (init_function_pointers())
        {
            test_version_flag_versus_aw();
269
            test_stillimage_aggregation();
270
            test_launch_app_registry();
271 272 273 274 275 276 277 278 279
            FreeLibrary(sti_dll);
        }
        else
            skip("could not load sti.dll\n");
        CoUninitialize();
    }
    else
        skip("CoInitialize failed\n");
}