compobj.c 115 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 *	COMPOBJ library
 *
 *	Copyright 1995	Martin von Loewis
5
 *	Copyright 1998	Justin Bradford
6
 *      Copyright 1999  Francis Beaudet
7 8 9
 *      Copyright 1999  Sylvain St-Germain
 *      Copyright 2002  Marcus Meissner
 *      Copyright 2004  Mike Hearn
10
 *      Copyright 2005-2006 Robert Shearman (for CodeWeavers)
11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * 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
24
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Mike Hearn's avatar
Mike Hearn committed
25
 *
26 27 28 29
 * Note
 * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED
 *    Therefore do not test against COINIT_MULTITHREADED
 *
Mike Hearn's avatar
Mike Hearn committed
30 31 32 33
 * TODO list:           (items bunched together depend on each other)
 *
 *   - Implement the service control manager (in rpcss) to keep track
 *     of registered class objects: ISCM::ServerRegisterClsid et al
34
 *   - Implement the OXID resolver so we don't need magic endpoint names for
Mike Hearn's avatar
Mike Hearn committed
35 36
 *     clients and servers to meet up
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
37 38
 */

39
#include "config.h"
40

41
#include <stdarg.h>
42
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
43
#include <string.h>
44
#include <assert.h>
45

46
#define COBJMACROS
47 48
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
49

50
#include "windef.h"
51
#include "winbase.h"
52 53
#include "winerror.h"
#include "winreg.h"
54
#include "winuser.h"
55 56 57
#include "objbase.h"
#include "ole2.h"
#include "ole2ver.h"
58
#include "ctxtcall.h"
59

60
#include "compobj_private.h"
61

62
#include "wine/unicode.h"
63
#include "wine/debug.h"
64

65
WINE_DEFAULT_DEBUG_CHANNEL(ole);
66

67 68
#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))

69
/****************************************************************************
70
 * This section defines variables internal to the COM module.
71 72
 */

73 74 75
static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
                                            DWORD dwClsContext, LPUNKNOWN*  ppUnk);
static void COM_RevokeAllClasses(const struct apartment *apt);
76
static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv);
77

78
static APARTMENT *MTA; /* protected by csApartment */
79
static APARTMENT *MainApartment; /* the first STA apartment */
80
static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
81 82 83 84 85 86

static CRITICAL_SECTION csApartment;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
    0, 0, &csApartment,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
87
      0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") }
88 89
};
static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 };
Alexandre Julliard's avatar
Alexandre Julliard committed
90

91 92 93 94 95 96 97
struct registered_psclsid
{
    struct list entry;
    IID iid;
    CLSID clsid;
};

98 99 100 101 102
/*
 * This lock count counts the number of times CoInitialize is called. It is
 * decreased every time CoUninitialize is called. When it hits 0, the COM
 * libraries are freed
 */
103
static LONG s_COMLockCount = 0;
104 105
/* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
static LONG s_COMServerProcessReferences = 0;
106 107 108 109 110 111 112

/*
 * This linked list contains the list of registered class objects. These
 * are mostly used to register the factories for out-of-proc servers of OLE
 * objects.
 *
 * TODO: Make this data structure aware of inter-process communication. This
113
 *       means that parts of this will be exported to rpcss.
114 115 116
 */
typedef struct tagRegisteredClass
{
117
  struct list entry;
118
  CLSID     classIdentifier;
119
  OXID      apartment_id;
120 121 122 123
  LPUNKNOWN classObject;
  DWORD     runContext;
  DWORD     connectFlags;
  DWORD     dwCookie;
124
  LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
125
  void     *RpcRegistration;
126 127
} RegisteredClass;

128
static struct list RegisteredClassList = LIST_INIT(RegisteredClassList);
129

130 131 132 133 134
static CRITICAL_SECTION csRegisteredClassList;
static CRITICAL_SECTION_DEBUG class_cs_debug =
{
    0, 0, &csRegisteredClassList,
    { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList },
135
      0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredClassList") }
136 137 138
};
static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 };

139 140 141 142
/*****************************************************************************
 * This section contains OpenDllList definitions
 *
 * The OpenDllList contains only handles of dll loaded by CoGetClassObject or
143 144
 * other functions that do LoadLibrary _without_ giving back a HMODULE.
 * Without this list these handles would never be freed.
145
 *
146
 * FIXME: a DLL that says OK when asked for unloading is unloaded in the
147
 * next unload-call but not before 600 sec.
148
 */
149

150 151 152
typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);

153 154 155 156 157
typedef struct tagOpenDll
{
  LONG refs;
  LPWSTR library_name;
  HANDLE library;
158 159
  DllGetClassObjectFunc DllGetClassObject;
  DllCanUnloadNowFunc DllCanUnloadNow;
160
  struct list entry;
161 162
} OpenDll;

163
static struct list openDllList = LIST_INIT(openDllList);
164

165 166 167 168 169
static CRITICAL_SECTION csOpenDllList;
static CRITICAL_SECTION_DEBUG dll_cs_debug =
{
    0, 0, &csOpenDllList,
    { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList },
170
      0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") }
171 172 173
};
static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 };

174 175 176 177
struct apartment_loaded_dll
{
    struct list entry;
    OpenDll *dll;
178
    DWORD unload_time;
179
    BOOL multi_threaded;
180 181
};

182 183 184
static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ',
                                       '0','x','#','#','#','#','#','#','#','#',' ',0};
static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
185
static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
186
                                        BOOL apartment_threaded,
187
                                        REFCLSID rclsid, REFIID riid, void **ppv);
188
static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay);
189

190
static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret);
191
static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name);
192
static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry);
193

194 195
static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen);

196
static void COMPOBJ_InitProcess( void )
197
{
198
    WNDCLASSW wclass;
199

200 201 202
    /* Dispatching to the correct thread in an apartment is done through
     * window messages rather than RPC transports. When an interface is
     * marshalled into another apartment in the same process, a window of the
Austin English's avatar
Austin English committed
203
     * following class is created. The *caller* of CoMarshalInterface (i.e., the
204 205
     * application) is responsible for pumping the message loop in that thread.
     * The WM_USER messages which point to the RPCs are then dispatched to
206 207
     * apartment_wndproc by the user's code from the apartment in which the
     * interface was unmarshalled.
208
     */
209
    memset(&wclass, 0, sizeof(wclass));
210
    wclass.lpfnWndProc = apartment_wndproc;
211
    wclass.hInstance = hProxyDll;
212 213
    wclass.lpszClassName = wszAptWinClass;
    RegisterClassW(&wclass);
214 215
}

216
static void COMPOBJ_UninitProcess( void )
217
{
218
    UnregisterClassW(wszAptWinClass, hProxyDll);
219 220
}

221
static void COM_TlsDestroy(void)
222 223 224 225
{
    struct oletls *info = NtCurrentTeb()->ReservedForOle;
    if (info)
    {
226
        if (info->apt) apartment_release(info->apt);
227 228
        if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
        if (info->state) IUnknown_Release(info->state);
229
        if (info->spy) IUnknown_Release(info->spy);
230 231 232 233 234
        HeapFree(GetProcessHeap(), 0, info);
        NtCurrentTeb()->ReservedForOle = NULL;
    }
}

235 236 237
/******************************************************************************
 * Manage apartments.
 */
238

239
/* allocates memory and fills in the necessary fields for a new apartment
240
 * object. must be called inside apartment cs */
241
static APARTMENT *apartment_construct(DWORD model)
242
{
243
    APARTMENT *apt;
244

245
    TRACE("creating new apartment, model=%d\n", model);
246

247 248
    apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
    apt->tid = GetCurrentThreadId();
249

250 251
    list_init(&apt->proxies);
    list_init(&apt->stubmgrs);
252
    list_init(&apt->psclsids);
253
    list_init(&apt->loaded_dlls);
254 255 256 257 258
    apt->ipidc = 0;
    apt->refs = 1;
    apt->remunk_exported = FALSE;
    apt->oidc = 1;
    InitializeCriticalSection(&apt->cs);
259
    DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
260

261
    apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
262

263
    if (apt->multi_threaded)
264 265
    {
        /* FIXME: should be randomly generated by in an RPC call to rpcss */
266
        apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
267 268 269 270
    }
    else
    {
        /* FIXME: should be randomly generated by in an RPC call to rpcss */
271
        apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
272
    }
273

274
    TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
275

276
    list_add_head(&apts, &apt->entry);
277

278 279
    return apt;
}
280

281 282 283
/* gets and existing apartment if one exists or otherwise creates an apartment
 * structure which stores OLE apartment-local information and stores a pointer
 * to it in the thread-local storage */
284
static APARTMENT *apartment_get_or_create(DWORD model)
285 286
{
    APARTMENT *apt = COM_CurrentApt();
287

288 289
    if (!apt)
    {
290 291
        if (model & COINIT_APARTMENTTHREADED)
        {
292 293
            EnterCriticalSection(&csApartment);

294
            apt = apartment_construct(model);
295 296 297 298 299 300 301 302
            if (!MainApartment)
            {
                MainApartment = apt;
                apt->main = TRUE;
                TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
            }

            LeaveCriticalSection(&csApartment);
303 304 305

            if (apt->main)
                apartment_createwindowifneeded(apt);
306
        }
307 308
        else
        {
309 310 311 312 313 314 315 316
            EnterCriticalSection(&csApartment);

            /* The multi-threaded apartment (MTA) contains zero or more threads interacting
             * with free threaded (ie thread safe) COM objects. There is only ever one MTA
             * in a process */
            if (MTA)
            {
                TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
317
                apartment_addref(MTA);
318 319 320
            }
            else
                MTA = apartment_construct(model);
321

322
            apt = MTA;
323

324 325
            LeaveCriticalSection(&csApartment);
        }
326
        COM_CurrentInfo()->apt = apt;
327
    }
328

329 330 331
    return apt;
}

332
static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
333 334 335 336
{
    return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
}

337
DWORD apartment_addref(struct apartment *apt)
338
{
339
    DWORD refs = InterlockedIncrement(&apt->refs);
340
    TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
341
    return refs;
342 343
}

344
DWORD apartment_release(struct apartment *apt)
345
{
346 347
    DWORD ret;

348 349
    EnterCriticalSection(&csApartment);

350
    ret = InterlockedDecrement(&apt->refs);
351
    TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
352
    /* destruction stuff that needs to happen under csApartment CS */
353 354
    if (ret == 0)
    {
355
        if (apt == MTA) MTA = NULL;
356
        else if (apt == MainApartment) MainApartment = NULL;
357
        list_remove(&apt->entry);
358 359 360 361 362 363
    }

    LeaveCriticalSection(&csApartment);

    if (ret == 0)
    {
364 365
        struct list *cursor, *cursor2;

366
        TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
367

368 369 370
        /* Release the references to the registered class objects */
        COM_RevokeAllClasses(apt);

371 372 373
        /* no locking is needed for this apartment, because no other thread
         * can access it at this point */

374
        apartment_disconnectproxies(apt);
375

376
        if (apt->win) DestroyWindow(apt->win);
377
        if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0);
378

379
        LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
380
        {
381 382 383 384 385 386 387
            struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry);
            /* release the implicit reference given by the fact that the
             * stub has external references (it must do since it is in the
             * stub manager list in the apartment and all non-apartment users
             * must have a ref on the apartment and so it cannot be destroyed).
             */
            stub_manager_int_release(stubmgr);
388 389
        }

390 391 392 393 394 395
        LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
        {
            struct registered_psclsid *registered_psclsid =
                LIST_ENTRY(cursor, struct registered_psclsid, entry);

            list_remove(&registered_psclsid->entry);
396
            HeapFree(GetProcessHeap(), 0, registered_psclsid);
397 398
        }

399 400 401 402 403
        /* if this assert fires, then another thread took a reference to a
         * stub manager without taking a reference to the containing
         * apartment, which it must do. */
        assert(list_empty(&apt->stubmgrs));

404 405
        if (apt->filter) IUnknown_Release(apt->filter);

406
        /* free as many unused libraries as possible... */
407
        apartment_freeunusedlibraries(apt, 0);
408 409 410 411

        /* ... and free the memory for the apartment loaded dll entry and
         * release the dll list reference without freeing the library for the
         * rest */
412 413 414
        while ((cursor = list_head(&apt->loaded_dlls)))
        {
            struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
415
            COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
416 417 418 419
            list_remove(cursor);
            HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
        }

420
        DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
421
        DeleteCriticalSection(&apt->cs);
422

423
        HeapFree(GetProcessHeap(), 0, apt);
424 425
    }

426 427 428
    return ret;
}

429
/* The given OXID must be local to this process: 
430 431 432 433
 *
 * The ref parameter is here mostly to ensure people remember that
 * they get one, you should normally take a ref for thread safety.
 */
434
APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
435
{
436 437
    APARTMENT *result = NULL;
    struct list *cursor;
438 439

    EnterCriticalSection(&csApartment);
440 441 442 443 444 445
    LIST_FOR_EACH( cursor, &apts )
    {
        struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
        if (apt->oxid == oxid)
        {
            result = apt;
446
            if (ref) apartment_addref(result);
447 448 449
            break;
        }
    }
450
    LeaveCriticalSection(&csApartment);
451

452
    return result;
453 454
}

455 456 457
/* gets the apartment which has a given creator thread ID. The caller must
 * release the reference from the apartment as soon as the apartment pointer
 * is no longer required. */
458
APARTMENT *apartment_findfromtid(DWORD tid)
459 460 461 462 463 464 465 466 467 468 469
{
    APARTMENT *result = NULL;
    struct list *cursor;

    EnterCriticalSection(&csApartment);
    LIST_FOR_EACH( cursor, &apts )
    {
        struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
        if (apt->tid == tid)
        {
            result = apt;
470
            apartment_addref(result);
471 472 473 474 475 476 477 478
            break;
        }
    }
    LeaveCriticalSection(&csApartment);

    return result;
}

479
/* gets the main apartment if it exists. The caller must
480 481
 * release the reference from the apartment as soon as the apartment pointer
 * is no longer required. */
482
static APARTMENT *apartment_findmain(void)
483
{
484
    APARTMENT *result;
485 486

    EnterCriticalSection(&csApartment);
487

488 489
    result = MainApartment;
    if (result) apartment_addref(result);
490

491 492 493 494 495 496 497 498 499 500
    LeaveCriticalSection(&csApartment);

    return result;
}

struct host_object_params
{
    HKEY hkeydll;
    CLSID clsid; /* clsid of object to marshal */
    IID iid; /* interface to marshal */
501 502
    HANDLE event; /* event signalling when ready for multi-threaded case */
    HRESULT hr; /* result for multi-threaded case */
503
    IStream *stream; /* stream that the object will be marshaled into */
504
    BOOL apartment_threaded; /* is the component purely apartment-threaded? */
505 506
};

507 508
static HRESULT apartment_hostobject(struct apartment *apt,
                                    const struct host_object_params *params)
509 510 511 512
{
    IUnknown *object;
    HRESULT hr;
    static const LARGE_INTEGER llZero;
513
    WCHAR dllpath[MAX_PATH+1];
514

515
    TRACE("clsid %s, iid %s\n", debugstr_guid(&params->clsid), debugstr_guid(&params->iid));
516

517 518 519 520 521 522 523
    if (COM_RegReadPath(params->hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
    {
        /* failure: CLSID is not found in registry */
        WARN("class %s not registered inproc\n", debugstr_guid(&params->clsid));
        return REGDB_E_CLASSNOTREG;
    }

524 525
    hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
                                  &params->clsid, &params->iid, (void **)&object);
526 527 528 529 530 531 532 533 534 535 536
    if (FAILED(hr))
        return hr;

    hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
    if (FAILED(hr))
        IUnknown_Release(object);
    IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);

    return hr;
}

537
static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
538
{
539 540 541
    switch (msg)
    {
    case DM_EXECUTERPC:
542 543
        RPC_ExecuteCall((struct dispatch_params *)lParam);
        return 0;
544
    case DM_HOSTOBJECT:
545
        return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
546 547 548
    default:
        return DefWindowProcW(hWnd, msg, wParam, lParam);
    }
549
}
550

551 552 553 554 555 556 557
struct host_thread_params
{
    COINIT threading_model;
    HANDLE ready_event;
    HWND apartment_hwnd;
};

558 559
/* thread for hosting an object to allow an object to appear to be created in
 * an apartment with an incompatible threading model */
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
{
    struct host_thread_params *params = p;
    MSG msg;
    HRESULT hr;
    struct apartment *apt;

    TRACE("\n");

    hr = CoInitializeEx(NULL, params->threading_model);
    if (FAILED(hr)) return hr;

    apt = COM_CurrentApt();
    if (params->threading_model == COINIT_APARTMENTTHREADED)
    {
        apartment_createwindowifneeded(apt);
        params->apartment_hwnd = apartment_getwindow(apt);
    }
    else
        params->apartment_hwnd = NULL;

    /* force the message queue to be created before signaling parent thread */
    PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

    SetEvent(params->ready_event);
    params = NULL; /* can't touch params after here as it may be invalid */

    while (GetMessageW(&msg, NULL, 0, 0))
    {
        if (!msg.hwnd && (msg.message == DM_HOSTOBJECT))
        {
591 592 593
            struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
            obj_params->hr = apartment_hostobject(apt, obj_params);
            SetEvent(obj_params->event);
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    TRACE("exiting\n");

    CoUninitialize();

    return S_OK;
}

609 610 611 612 613 614
/* finds or creates a host apartment, creates the object inside it and returns
 * a proxy to it so that the object can be used in the apartment of the
 * caller of this function */
static HRESULT apartment_hostobject_in_hostapt(
    struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
    HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
615 616 617 618 619 620 621 622
{
    struct host_object_params params;
    HWND apartment_hwnd = NULL;
    DWORD apartment_tid = 0;
    HRESULT hr;

    if (!multi_threaded && main_apartment)
    {
623
        APARTMENT *host_apt = apartment_findmain();
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
        if (host_apt)
        {
            apartment_hwnd = apartment_getwindow(host_apt);
            apartment_release(host_apt);
        }
    }

    if (!apartment_hwnd)
    {
        EnterCriticalSection(&apt->cs);

        if (!apt->host_apt_tid)
        {
            struct host_thread_params thread_params;
            HANDLE handles[2];
            DWORD wait_value;

            thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED;
            handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
            thread_params.apartment_hwnd = NULL;
            handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid);
            if (!handles[1])
            {
                CloseHandle(handles[0]);
                LeaveCriticalSection(&apt->cs);
                return E_OUTOFMEMORY;
            }
            wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
            CloseHandle(handles[0]);
            CloseHandle(handles[1]);
            if (wait_value == WAIT_OBJECT_0)
                apt->host_apt_hwnd = thread_params.apartment_hwnd;
            else
            {
                LeaveCriticalSection(&apt->cs);
                return E_OUTOFMEMORY;
            }
        }

        if (multi_threaded || !main_apartment)
        {
            apartment_hwnd = apt->host_apt_hwnd;
            apartment_tid = apt->host_apt_tid;
        }

        LeaveCriticalSection(&apt->cs);
    }

    /* another thread may have become the main apartment in the time it took
     * us to create the thread for the host apartment */
    if (!apartment_hwnd && !multi_threaded && main_apartment)
    {
676
        APARTMENT *host_apt = apartment_findmain();
677 678 679 680 681 682 683 684 685 686 687 688 689
        if (host_apt)
        {
            apartment_hwnd = apartment_getwindow(host_apt);
            apartment_release(host_apt);
        }
    }

    params.hkeydll = hkeydll;
    params.clsid = *rclsid;
    params.iid = *riid;
    hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
    if (FAILED(hr))
        return hr;
690
    params.apartment_threaded = !multi_threaded;
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
    if (multi_threaded)
    {
        params.hr = S_OK;
        params.event = CreateEventW(NULL, FALSE, FALSE, NULL);
        if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)&params))
            hr = E_OUTOFMEMORY;
        else
        {
            WaitForSingleObject(params.event, INFINITE);
            hr = params.hr;
        }
        CloseHandle(params.event);
    }
    else
    {
        if (!apartment_hwnd)
        {
            ERR("host apartment didn't create window\n");
            hr = E_OUTOFMEMORY;
        }
        else
            hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
    }
    if (SUCCEEDED(hr))
        hr = CoUnmarshalInterface(params.stream, riid, ppv);
    IStream_Release(params.stream);
    return hr;
}

720 721
/* create a window for the apartment or return the current one if one has
 * already been created */
722 723
HRESULT apartment_createwindowifneeded(struct apartment *apt)
{
724
    if (apt->multi_threaded)
725 726 727 728 729 730
        return S_OK;

    if (!apt->win)
    {
        HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
                                  0, 0, 0, 0,
731
                                  HWND_MESSAGE, 0, hProxyDll, NULL);
732 733
        if (!hwnd)
        {
734
            ERR("CreateWindow failed with error %d\n", GetLastError());
735 736 737 738 739 740 741 742 743 744
            return HRESULT_FROM_WIN32(GetLastError());
        }
        if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
            /* someone beat us to it */
            DestroyWindow(hwnd);
    }

    return S_OK;
}

745
/* retrieves the window for the main- or apartment-threaded apartment */
746
HWND apartment_getwindow(const struct apartment *apt)
747
{
748
    assert(!apt->multi_threaded);
749 750 751
    return apt->win;
}

752 753 754 755 756 757
void apartment_joinmta(void)
{
    apartment_addref(MTA);
    COM_CurrentInfo()->apt = MTA;
}

758 759
/* gets the specified class object by loading the appropriate DLL, if
 * necessary and calls the DllGetClassObject function for the DLL */
760
static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
761
                                        BOOL apartment_threaded,
762 763
                                        REFCLSID rclsid, REFIID riid, void **ppv)
{
764
    static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
765 766 767
    HRESULT hr = S_OK;
    BOOL found = FALSE;
    struct apartment_loaded_dll *apartment_loaded_dll;
768

769 770 771 772 773 774 775 776 777 778 779 780 781
    if (!strcmpiW(dllpath, wszOle32))
    {
        /* we don't need to control the lifetime of this dll, so use the local
         * implementation of DllGetClassObject directly */
        TRACE("calling ole32!DllGetClassObject\n");
        hr = DllGetClassObject(rclsid, riid, ppv);

        if (hr != S_OK)
            ERR("DllGetClassObject returned error 0x%08x\n", hr);

        return hr;
    }

782
    EnterCriticalSection(&apt->cs);
783

784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
    LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
        if (!strcmpiW(dllpath, apartment_loaded_dll->dll->library_name))
        {
            TRACE("found %s already loaded\n", debugstr_w(dllpath));
            found = TRUE;
            break;
        }

    if (!found)
    {
        apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll));
        if (!apartment_loaded_dll)
            hr = E_OUTOFMEMORY;
        if (SUCCEEDED(hr))
        {
799
            apartment_loaded_dll->unload_time = 0;
800
            apartment_loaded_dll->multi_threaded = FALSE;
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
            hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll );
            if (FAILED(hr))
                HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
        }
        if (SUCCEEDED(hr))
        {
            TRACE("added new loaded dll %s\n", debugstr_w(dllpath));
            list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry);
        }
    }

    LeaveCriticalSection(&apt->cs);

    if (SUCCEEDED(hr))
    {
816 817 818 819 820
        /* one component being multi-threaded overrides any number of
         * apartment-threaded components */
        if (!apartment_threaded)
            apartment_loaded_dll->multi_threaded = TRUE;

821 822 823
        TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject);
        /* OK: get the ClassObject */
        hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv);
824

825 826 827
        if (hr != S_OK)
            ERR("DllGetClassObject returned error 0x%08x\n", hr);
    }
828 829 830 831

    return hr;
}

832 833
/* frees unused libraries loaded by apartment_getclassobject by calling the
 * DLL's DllCanUnloadNow entry point */
834
static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
835 836 837 838 839 840 841
{
    struct apartment_loaded_dll *entry, *next;
    EnterCriticalSection(&apt->cs);
    LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry)
    {
	if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK))
        {
842 843 844 845
            DWORD real_delay = delay;

            if (real_delay == INFINITE)
            {
846 847 848 849
                /* DLLs that return multi-threaded objects aren't unloaded
                 * straight away to cope for programs that have races between
                 * last object destruction and threads in the DLLs that haven't
                 * finished, despite DllCanUnloadNow returning S_OK */
850 851 852 853 854 855 856
                if (entry->multi_threaded)
                    real_delay = 10 * 60 * 1000; /* 10 minutes */
                else
                    real_delay = 0;
            }

            if (!real_delay || (entry->unload_time && (entry->unload_time < GetTickCount())))
857 858 859 860 861 862
            {
                list_remove(&entry->entry);
                COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
                HeapFree(GetProcessHeap(), 0, entry);
            }
            else
863
                entry->unload_time = GetTickCount() + real_delay;
864
        }
865 866
        else if (entry->unload_time)
            entry->unload_time = 0;
867 868 869 870
    }
    LeaveCriticalSection(&apt->cs);
}

871
/*****************************************************************************
872
 * This section contains OpenDllList implementation
Alexandre Julliard's avatar
Alexandre Julliard committed
873
 */
874

875
/* caller must ensure that library_name is not already in the open dll list */
876
static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
Alexandre Julliard's avatar
Alexandre Julliard committed
877
{
878 879 880
    OpenDll *entry;
    int len;
    HRESULT hr = S_OK;
881
    HANDLE hLibrary;
882 883
    DllCanUnloadNowFunc DllCanUnloadNow;
    DllGetClassObjectFunc DllGetClassObject;
Alexandre Julliard's avatar
Alexandre Julliard committed
884

885
    TRACE("\n");
886

887 888 889 890 891 892 893 894
    *ret = COMPOBJ_DllList_Get(library_name);
    if (*ret) return S_OK;

    /* do this outside the csOpenDllList to avoid creating a lock dependency on
     * the loader lock */
    hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
    if (!hLibrary)
    {
895
        ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
896 897 898 899
        /* failure: DLL could not be loaded */
        return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
    }

900
    DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
901
    /* Note: failing to find DllCanUnloadNow is not a failure */
902
    DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
903 904 905 906 907 908 909 910
    if (!DllGetClassObject)
    {
        /* failure: the dll did not export DllGetClassObject */
        ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name));
        FreeLibrary(hLibrary);
        return CO_E_DLLNOTFOUND;
    }

911 912
    EnterCriticalSection( &csOpenDllList );

913
    *ret = COMPOBJ_DllList_Get(library_name);
914 915 916 917 918 919 920
    if (*ret)
    {
        /* another caller to this function already added the dll while we
         * weren't in the critical section */
        FreeLibrary(hLibrary);
    }
    else
921 922 923 924 925 926 927 928 929 930
    {
        len = strlenW(library_name);
        entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
        if (entry)
            entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
        if (entry && entry->library_name)
        {
            memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR));
            entry->library = hLibrary;
            entry->refs = 1;
931 932
            entry->DllCanUnloadNow = DllCanUnloadNow;
            entry->DllGetClassObject = DllGetClassObject;
933
            list_add_tail(&openDllList, &entry->entry);
934
        }
935
        else
936
        {
937
            hr = E_OUTOFMEMORY;
938 939
            FreeLibrary(hLibrary);
        }
940
        *ret = entry;
941 942 943
    }

    LeaveCriticalSection( &csOpenDllList );
944 945 946 947 948 949 950 951 952 953 954

    return hr;
}

static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
{
    OpenDll *ptr;
    OpenDll *ret = NULL;
    EnterCriticalSection(&csOpenDllList);
    LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
    {
955 956
        if (!strcmpiW(library_name, ptr->library_name) &&
            (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
957 958 959 960 961 962 963 964 965
        {
            ret = ptr;
            break;
        }
    }
    LeaveCriticalSection(&csOpenDllList);
    return ret;
}

966 967 968
/* pass FALSE for free_entry to release a reference without destroying the
 * entry if it reaches zero or TRUE otherwise */
static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry)
969
{
970
    if (!InterlockedDecrement(&entry->refs) && free_entry)
971 972 973 974 975 976 977 978 979 980 981
    {
        EnterCriticalSection(&csOpenDllList);
        list_remove(&entry->entry);
        LeaveCriticalSection(&csOpenDllList);

        TRACE("freeing %p\n", entry->library);
        FreeLibrary(entry->library);

        HeapFree(GetProcessHeap(), 0, entry->library_name);
        HeapFree(GetProcessHeap(), 0, entry);
    }
982 983
}

984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
/* frees memory associated with active dll list */
static void COMPOBJ_DllList_Free(void)
{
    OpenDll *entry, *cursor2;
    EnterCriticalSection(&csOpenDllList);
    LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
    {
        list_remove(&entry->entry);

        HeapFree(GetProcessHeap(), 0, entry->library_name);
        HeapFree(GetProcessHeap(), 0, entry);
    }
    LeaveCriticalSection(&csOpenDllList);
}

999
/******************************************************************************
1000
 *           CoBuildVersion [OLE32.@]
1001 1002 1003 1004 1005
 *           CoBuildVersion [COMPOBJ.1]
 *
 * Gets the build version of the DLL.
 *
 * PARAMS
1006 1007 1008
 *
 * RETURNS
 *	Current build version, hiword is majornumber, loword is minornumber
Alexandre Julliard's avatar
Alexandre Julliard committed
1009
 */
1010 1011 1012 1013
DWORD WINAPI CoBuildVersion(void)
{
    TRACE("Returning version %d, build %d.\n", rmm, rup);
    return (rmm<<16)+rup;
Alexandre Julliard's avatar
Alexandre Julliard committed
1014 1015
}

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
/******************************************************************************
 *              CoRegisterInitializeSpy [OLE32.@]
 *
 * Add a Spy that watches CoInitializeEx calls
 *
 * PARAMS
 *  spy [I] Pointer to IUnknown interface that will be QueryInterface'd.
 *  cookie [II] cookie receiver
 *
 * RETURNS
 *  Success: S_OK if not already initialized, S_FALSE otherwise.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *   CoInitializeEx
 */
HRESULT WINAPI CoRegisterInitializeSpy(IInitializeSpy *spy, ULARGE_INTEGER *cookie)
{
    struct oletls *info = COM_CurrentInfo();
    HRESULT hr;

    TRACE("(%p, %p)\n", spy, cookie);

    if (!spy || !cookie || !info)
    {
        if (!info)
            WARN("Could not allocate tls\n");
        return E_INVALIDARG;
    }

    if (info->spy)
    {
        FIXME("Already registered?\n");
        return E_UNEXPECTED;
    }

    hr = IUnknown_QueryInterface(spy, &IID_IInitializeSpy, (void **) &info->spy);
    if (SUCCEEDED(hr))
    {
        cookie->QuadPart = (DWORD_PTR)spy;
        return S_OK;
    }
    return hr;
}

1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
/******************************************************************************
 *              CoRevokeInitializeSpy [OLE32.@]
 *
 * Remove a spy that previously watched CoInitializeEx calls
 *
 * PARAMS
 *  cookie [I] The cookie obtained from a previous CoRegisterInitializeSpy call
 *
 * RETURNS
 *  Success: S_OK if a spy is removed
 *  Failure: E_INVALIDARG
 *
 * SEE ALSO
 *   CoInitializeEx
 */
1076 1077 1078 1079 1080 1081 1082 1083 1084
HRESULT WINAPI CoRevokeInitializeSpy(ULARGE_INTEGER cookie)
{
    struct oletls *info = COM_CurrentInfo();
    TRACE("(%s)\n", wine_dbgstr_longlong(cookie.QuadPart));

    if (!info || !info->spy || cookie.QuadPart != (DWORD_PTR)info->spy)
        return E_INVALIDARG;

    IUnknown_Release(info->spy);
1085
    info->spy = NULL;
1086 1087 1088 1089
    return S_OK;
}


1090
/******************************************************************************
1091
 *		CoInitialize	[OLE32.@]
1092
 *
1093 1094
 * Initializes the COM libraries by calling CoInitializeEx with
 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1095
 *
1096 1097 1098 1099 1100 1101 1102
 * PARAMS
 *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
 *
 * RETURNS
 *  Success: S_OK if not already initialized, S_FALSE otherwise.
 *  Failure: HRESULT code.
 *
1103 1104
 * SEE ALSO
 *   CoInitializeEx
Alexandre Julliard's avatar
Alexandre Julliard committed
1105
 */
1106
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1107 1108 1109 1110
{
  /*
   * Just delegate to the newer method.
   */
1111
  return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
Alexandre Julliard's avatar
Alexandre Julliard committed
1112 1113
}

1114
/******************************************************************************
1115
 *		CoInitializeEx	[OLE32.@]
1116
 *
1117
 * Initializes the COM libraries.
1118
 *
1119 1120 1121
 * PARAMS
 *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
 *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
1122 1123
 *
 * RETURNS
1124 1125
 *  S_OK               if successful,
 *  S_FALSE            if this function was called already.
1126 1127
 *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
 *                     threading model.
1128
 *
1129 1130 1131 1132
 * NOTES
 *
 * The behavior used to set the IMalloc used for memory management is
 * obsolete.
1133
 * The dwCoInit parameter must specify one of the following apartment
1134 1135 1136 1137 1138 1139 1140
 * threading models:
 *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA).
 *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA).
 * The parameter may also specify zero or more of the following flags:
 *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support.
 *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed.
 *
1141 1142
 * SEE ALSO
 *   CoUninitialize
1143
 */
1144
HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1145
{
1146
  struct oletls *info = COM_CurrentInfo();
1147 1148
  HRESULT hr = S_OK;
  APARTMENT *apt;
1149

1150
  TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1151 1152 1153

  if (lpReserved!=NULL)
  {
1154
    ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1155 1156 1157 1158 1159
  }

  /*
   * Check the lock count. If this is the first time going through the initialize
   * process, we have to initialize the libraries.
1160 1161
   *
   * And crank-up that lock count.
1162
   */
1163
  if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1164 1165 1166 1167
  {
    /*
     * Initialize the various COM libraries and data structures.
     */
1168
    TRACE("() - Initializing the COM libraries\n");
1169

1170
    /* we may need to defer this until after apartment initialisation */
Noomen Hamza's avatar
Noomen Hamza committed
1171
    RunningObjectTableImpl_Initialize();
1172
  }
1173

1174 1175 1176 1177
  if (info->spy)
      IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);

  if (!(apt = info->apt))
1178
  {
1179
    apt = apartment_get_or_create(dwCoInit);
1180
    if (!apt) return E_OUTOFMEMORY;
1181
  }
1182
  else if (!apartment_is_model(apt, dwCoInit))
1183 1184 1185
  {
    /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine
       code then we are probably using the wrong threading model to implement that API. */
1186 1187 1188
    ERR("Attempt to change threading model of this apartment from %s to %s\n",
        apt->multi_threaded ? "multi-threaded" : "apartment threaded",
        dwCoInit & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded");
1189 1190
    return RPC_E_CHANGED_MODE;
  }
1191 1192
  else
    hr = S_FALSE;
1193

1194 1195 1196 1197
  info->inits++;

  if (info->spy)
      IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1198 1199

  return hr;
1200 1201
}

1202
/***********************************************************************
1203
 *           CoUninitialize   [OLE32.@]
1204
 *
1205 1206 1207 1208
 * This method will decrement the refcount on the current apartment, freeing
 * the resources associated with it if it is the last thread in the apartment.
 * If the last apartment is freed, the function will additionally release
 * any COM resources associated with the process.
1209
 *
1210 1211 1212 1213
 * PARAMS
 *
 * RETURNS
 *  Nothing.
1214 1215 1216
 *
 * SEE ALSO
 *   CoInitializeEx
1217
 */
1218
void WINAPI CoUninitialize(void)
1219
{
1220
  struct oletls * info = COM_CurrentInfo();
1221
  LONG lCOMRefCnt;
1222

1223
  TRACE("()\n");
1224

1225 1226 1227
  /* will only happen on OOM */
  if (!info) return;

1228 1229 1230
  if (info->spy)
      IInitializeSpy_PreUninitialize(info->spy, info->inits);

1231 1232 1233 1234
  /* sanity check */
  if (!info->inits)
  {
    ERR("Mismatched CoUninitialize\n");
1235 1236 1237

    if (info->spy)
        IInitializeSpy_PostUninitialize(info->spy, info->inits);
1238 1239 1240 1241 1242
    return;
  }

  if (!--info->inits)
  {
1243
    apartment_release(info->apt);
1244 1245
    info->apt = NULL;
  }
1246

1247 1248 1249 1250 1251
  /*
   * Decrease the reference count.
   * If we are back to 0 locks on the COM library, make sure we free
   * all the associated data structures.
   */
1252 1253
  lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
  if (lCOMRefCnt==1)
1254
  {
1255
    TRACE("() - Releasing the COM libraries\n");
1256

Noomen Hamza's avatar
Noomen Hamza committed
1257
    RunningObjectTableImpl_UnInitialize();
1258 1259 1260 1261 1262
  }
  else if (lCOMRefCnt<1) {
    ERR( "CoUninitialize() - not CoInitialized.\n" );
    InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
  }
1263 1264
  if (info->spy)
      IInitializeSpy_PostUninitialize(info->spy, info->inits);
1265
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1266

1267
/******************************************************************************
1268
 *		CoDisconnectObject	[OLE32.@]
1269 1270
 *
 * Disconnects all connections to this object from remote processes. Dispatches
1271
 * pending RPCs while blocking new RPCs from occurring, and then calls
1272 1273 1274 1275
 * IMarshal::DisconnectObject on the given object.
 *
 * Typically called when the object server is forced to shut down, for instance by
 * the user.
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
 *
 * PARAMS
 *  lpUnk    [I] The object whose stub should be disconnected.
 *  reserved [I] Reserved. Should be set to 0.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal
Alexandre Julliard's avatar
Alexandre Julliard committed
1287
 */
1288
HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
Alexandre Julliard's avatar
Alexandre Julliard committed
1289
{
1290 1291 1292 1293
    HRESULT hr;
    IMarshal *marshal;
    APARTMENT *apt;

1294
    TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307

    hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal);
    if (hr == S_OK)
    {
        hr = IMarshal_DisconnectObject(marshal, reserved);
        IMarshal_Release(marshal);
        return hr;
    }

    apt = COM_CurrentApt();
    if (!apt)
        return CO_E_NOTINITIALIZED;

1308
    apartment_disconnectobject(apt, lpUnk);
1309 1310 1311 1312 1313 1314

    /* Note: native is pretty broken here because it just silently
     * fails, without returning an appropriate error code if the object was
     * not found, making apps think that the object was disconnected, when
     * it actually wasn't */

Alexandre Julliard's avatar
Alexandre Julliard committed
1315
    return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1316 1317
}

1318
/******************************************************************************
1319
 *		CoCreateGuid [OLE32.@]
1320
 *		CoCreateGuid [COMPOBJ.73]
1321
 *
1322 1323
 * Simply forwards to UuidCreate in RPCRT4.
 *
1324 1325 1326 1327 1328 1329 1330
 * PARAMS
 *  pguid [O] Points to the GUID to initialize.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
1331 1332
 * SEE ALSO
 *   UuidCreate
Alexandre Julliard's avatar
Alexandre Julliard committed
1333
 */
1334 1335
HRESULT WINAPI CoCreateGuid(GUID *pguid)
{
1336 1337 1338
    DWORD status = UuidCreate(pguid);
    if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY) return S_OK;
    return HRESULT_FROM_WIN32( status );
Alexandre Julliard's avatar
Alexandre Julliard committed
1339
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1340

1341
/******************************************************************************
1342 1343
 *		CLSIDFromString	[OLE32.@]
 *		IIDFromString   [OLE32.@]
1344
 *
1345
 * Converts a unique identifier from its string representation into
Alexandre Julliard's avatar
Alexandre Julliard committed
1346
 * the GUID struct.
1347
 *
1348 1349 1350
 * PARAMS
 *  idstr [I] The string representation of the GUID.
 *  id    [O] GUID converted from the string.
1351
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1352
 * RETURNS
1353 1354
 *   S_OK on success
 *   CO_E_CLASSSTRING if idstr is not a valid CLSID
1355 1356 1357
 *
 * SEE ALSO
 *  StringFromCLSID
Alexandre Julliard's avatar
Alexandre Julliard committed
1358
 */
1359
static HRESULT __CLSIDFromString(LPCWSTR s, CLSID *id)
1360
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1361 1362 1363
  int	i;
  BYTE table[256];

1364
  if (!s) {
1365 1366 1367
    memset( id, 0, sizeof (CLSID) );
    return S_OK;
  }
1368

1369
  /* validate the CLSID string */
1370
  if (strlenW(s) != 38)
1371
    return CO_E_CLASSSTRING;
1372

1373 1374
  if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
    return CO_E_CLASSSTRING;
1375

1376 1377 1378 1379 1380 1381
  for (i=1; i<37; i++) {
    if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) continue;
    if (!(((s[i] >= '0') && (s[i] <= '9'))  ||
          ((s[i] >= 'a') && (s[i] <= 'f'))  ||
          ((s[i] >= 'A') && (s[i] <= 'F'))))
       return CO_E_CLASSSTRING;
1382
  }
1383

1384
  TRACE("%s -> %p\n", debugstr_w(s), id);
Alexandre Julliard's avatar
Alexandre Julliard committed
1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398

  /* quick lookup table */
  memset(table, 0, 256);

  for (i = 0; i < 10; i++) {
    table['0' + i] = i;
  }
  for (i = 0; i < 6; i++) {
    table['A' + i] = i+10;
    table['a' + i] = i+10;
  }

  /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */

1399 1400 1401 1402
  id->Data1 = (table[s[1]] << 28 | table[s[2]] << 24 | table[s[3]] << 20 | table[s[4]] << 16 |
               table[s[5]] << 12 | table[s[6]] << 8  | table[s[7]] << 4  | table[s[8]]);
  id->Data2 = table[s[10]] << 12 | table[s[11]] << 8 | table[s[12]] << 4 | table[s[13]];
  id->Data3 = table[s[15]] << 12 | table[s[16]] << 8 | table[s[17]] << 4 | table[s[18]];
Alexandre Julliard's avatar
Alexandre Julliard committed
1403 1404

  /* these are just sequential bytes */
1405 1406 1407 1408 1409 1410 1411 1412
  id->Data4[0] = table[s[20]] << 4 | table[s[21]];
  id->Data4[1] = table[s[22]] << 4 | table[s[23]];
  id->Data4[2] = table[s[25]] << 4 | table[s[26]];
  id->Data4[3] = table[s[27]] << 4 | table[s[28]];
  id->Data4[4] = table[s[29]] << 4 | table[s[30]];
  id->Data4[5] = table[s[31]] << 4 | table[s[32]];
  id->Data4[6] = table[s[33]] << 4 | table[s[34]];
  id->Data4[7] = table[s[35]] << 4 | table[s[36]];
Alexandre Julliard's avatar
Alexandre Julliard committed
1413

Alexandre Julliard's avatar
Alexandre Julliard committed
1414 1415 1416
  return S_OK;
}

1417 1418
/*****************************************************************************/

1419
HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id )
1420 1421
{
    HRESULT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1422

1423 1424 1425
    if (!id)
        return E_INVALIDARG;

1426
    ret = __CLSIDFromString(idstr, id);
1427 1428 1429
    if(ret != S_OK) { /* It appears a ProgID is also valid */
        ret = CLSIDFromProgID(idstr, id);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1430
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1431 1432
}

1433
/* Converts a GUID into the respective string representation. */
1434
HRESULT WINE_StringFromCLSID(
Alexandre Julliard's avatar
Alexandre Julliard committed
1435 1436 1437
	const CLSID *id,	/* [in] GUID to be converted */
	LPSTR idstr		/* [out] pointer to buffer to contain converted guid */
) {
1438
  static const char hex[] = "0123456789ABCDEF";
Alexandre Julliard's avatar
Alexandre Julliard committed
1439 1440 1441
  char *s;
  int	i;

Alexandre Julliard's avatar
Alexandre Julliard committed
1442
  if (!id)
1443
	{ ERR("called with id=Null\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1444 1445 1446
	  *idstr = 0x00;
	  return E_FAIL;
	}
1447

1448
  sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-",
Alexandre Julliard's avatar
Alexandre Julliard committed
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
	  id->Data1, id->Data2, id->Data3,
	  id->Data4[0], id->Data4[1]);
  s = &idstr[25];

  /* 6 hex bytes */
  for (i = 2; i < 8; i++) {
    *s++ = hex[id->Data4[i]>>4];
    *s++ = hex[id->Data4[i] & 0xf];
  }

  *s++ = '}';
  *s++ = '\0';

1462
  TRACE("%p->%s\n", id, idstr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1463

1464
  return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1465 1466
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1467

1468
/******************************************************************************
1469 1470
 *		StringFromCLSID	[OLE32.@]
 *		StringFromIID   [OLE32.@]
1471
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1472 1473
 * Converts a GUID into the respective string representation.
 * The target string is allocated using the OLE IMalloc.
1474
 *
1475 1476 1477 1478
 * PARAMS
 *  id    [I] the GUID to be converted.
 *  idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1479
 * RETURNS
1480 1481
 *   S_OK
 *   E_FAIL
1482 1483 1484
 *
 * SEE ALSO
 *  StringFromGUID2, CLSIDFromString
Alexandre Julliard's avatar
Alexandre Julliard committed
1485
 */
1486 1487
HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1488
	char            buf[80];
1489
	HRESULT       ret;
1490
	LPMALLOC	mllc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1491

1492
	if ((ret = CoGetMalloc(0,&mllc)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1493 1494 1495
		return ret;

	ret=WINE_StringFromCLSID(id,buf);
1496
	if (ret == S_OK) {
1497 1498 1499
            DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
            *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) );
            MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len );
Alexandre Julliard's avatar
Alexandre Julliard committed
1500 1501 1502 1503
	}
	return ret;
}

1504
/******************************************************************************
1505
 *		StringFromGUID2	[OLE32.@]
1506
 *		StringFromGUID2	[COMPOBJ.76]
Alexandre Julliard's avatar
Alexandre Julliard committed
1507
 *
1508 1509
 * Modified version of StringFromCLSID that allows you to specify max
 * buffer size.
Alexandre Julliard's avatar
Alexandre Julliard committed
1510
 *
1511 1512 1513 1514 1515
 * PARAMS
 *  id   [I] GUID to convert to string.
 *  str  [O] Buffer where the result will be stored.
 *  cmax [I] Size of the buffer in characters.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1516
 * RETURNS
1517 1518
 *	Success: The length of the resulting string in characters.
 *  Failure: 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
1519
 */
1520
INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1521
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1522 1523 1524 1525
  char		xguid[80];

  if (WINE_StringFromCLSID(id,xguid))
  	return 0;
1526
  return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax );
Alexandre Julliard's avatar
Alexandre Julliard committed
1527
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1528

1529 1530
/* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1531 1532 1533
{
    static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
    WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1534 1535 1536
    LONG res;
    HKEY key;

1537 1538
    strcpyW(path, wszCLSIDSlash);
    StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, keyname ? KEY_READ : access, &key);
    if (res == ERROR_FILE_NOT_FOUND)
        return REGDB_E_CLASSNOTREG;
    else if (res != ERROR_SUCCESS)
        return REGDB_E_READREGDB;

    if (!keyname)
    {
        *subkey = key;
        return S_OK;
    }

    res = RegOpenKeyExW(key, keyname, 0, access, subkey);
    RegCloseKey(key);
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
    if (res == ERROR_FILE_NOT_FOUND)
        return REGDB_E_KEYMISSING;
    else if (res != ERROR_SUCCESS)
        return REGDB_E_READREGDB;

    return S_OK;
}

/* open HKCR\\AppId\\{string form of appid clsid} key */
HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey)
{
    static const WCHAR szAppId[] = { 'A','p','p','I','d',0 };
    static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 };
    DWORD res;
    WCHAR buf[CHARS_IN_GUID];
    WCHAR keyname[ARRAYSIZE(szAppIdKey) + CHARS_IN_GUID];
    DWORD size;
    HKEY hkey;
    DWORD type;
    HRESULT hr;

    /* read the AppID value under the class's key */
1575
    hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1576 1577 1578 1579
    if (FAILED(hr))
        return hr;

    size = sizeof(buf);
1580
    res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1581 1582 1583 1584 1585 1586 1587 1588 1589
    RegCloseKey(hkey);
    if (res == ERROR_FILE_NOT_FOUND)
        return REGDB_E_KEYMISSING;
    else if (res != ERROR_SUCCESS || type!=REG_SZ)
        return REGDB_E_READREGDB;

    strcpyW(keyname, szAppIdKey);
    strcatW(keyname, buf);
    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, access, subkey);
1590 1591 1592 1593 1594 1595
    if (res == ERROR_FILE_NOT_FOUND)
        return REGDB_E_KEYMISSING;
    else if (res != ERROR_SUCCESS)
        return REGDB_E_READREGDB;

    return S_OK;
1596 1597
}

1598
/******************************************************************************
1599 1600
 *               ProgIDFromCLSID [OLE32.@]
 *
1601 1602 1603 1604
 * Converts a class id into the respective program ID.
 *
 * PARAMS
 *  clsid        [I] Class ID, as found in registry.
1605
 *  ppszProgID [O] Associated ProgID.
1606 1607 1608 1609 1610
 *
 * RETURNS
 *   S_OK
 *   E_OUTOFMEMORY
 *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1611
 */
1612
HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1613
{
1614 1615 1616
    static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
    HKEY     hkey;
    HRESULT  ret;
1617
    LONG progidlen = 0;
1618

1619 1620 1621 1622 1623 1624 1625
    if (!ppszProgID)
    {
        ERR("ppszProgId isn't optional\n");
        return E_INVALIDARG;
    }

    *ppszProgID = NULL;
1626 1627 1628 1629
    ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
    if (FAILED(ret))
        return ret;

1630
    if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1631 1632 1633 1634
      ret = REGDB_E_CLASSNOTREG;

    if (ret == S_OK)
    {
1635 1636
      *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
      if (*ppszProgID)
1637
      {
1638
        if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1639
          ret = REGDB_E_CLASSNOTREG;
1640
      }
1641 1642
      else
        ret = E_OUTOFMEMORY;
1643 1644
    }

1645 1646
    RegCloseKey(hkey);
    return ret;
1647 1648
}

1649
/******************************************************************************
1650
 *		CLSIDFromProgID	[OLE32.@]
1651
 *
1652 1653 1654 1655
 * Converts a program id into the respective GUID.
 *
 * PARAMS
 *  progid [I] Unicode program ID, as found in registry.
1656
 *  clsid  [O] Associated CLSID.
1657
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1658
 * RETURNS
1659 1660
 *	Success: S_OK
 *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
Alexandre Julliard's avatar
Alexandre Julliard committed
1661
 */
1662
HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1663 1664
{
    static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1665
    WCHAR buf2[CHARS_IN_GUID];
1666
    LONG buf2len = sizeof(buf2);
1667
    HKEY xhkey;
1668
    WCHAR *buf;
1669

1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
    if (!progid || !clsid)
    {
        ERR("neither progid (%p) nor clsid (%p) are optional\n", progid, clsid);
        return E_INVALIDARG;
    }

    /* initialise clsid in case of failure */
    memset(clsid, 0, sizeof(*clsid));

    buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) );
1680 1681 1682 1683 1684
    strcpyW( buf, progid );
    strcatW( buf, clsidW );
    if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
    {
        HeapFree(GetProcessHeap(),0,buf);
1685
        WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1686 1687 1688
        return CO_E_CLASSSTRING;
    }
    HeapFree(GetProcessHeap(),0,buf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1689

1690
    if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1691 1692
    {
        RegCloseKey(xhkey);
1693
        WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1694 1695 1696
        return CO_E_CLASSSTRING;
    }
    RegCloseKey(xhkey);
1697
    return __CLSIDFromString(buf2,clsid);
Alexandre Julliard's avatar
Alexandre Julliard committed
1698 1699
}

1700 1701

/*****************************************************************************
1702
 *             CoGetPSClsid [OLE32.@]
1703
 *
Robert Shearman's avatar
Robert Shearman committed
1704 1705
 * Retrieves the CLSID of the proxy/stub factory that implements
 * IPSFactoryBuffer for the specified interface.
1706
 *
1707 1708 1709 1710 1711 1712 1713
 * PARAMS
 *  riid   [I] Interface whose proxy/stub CLSID is to be returned.
 *  pclsid [O] Where to store returned proxy/stub CLSID.
 * 
 * RETURNS
 *   S_OK
 *   E_OUTOFMEMORY
Robert Shearman's avatar
Robert Shearman committed
1714
 *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1715 1716 1717
 *
 * NOTES
 *
1718 1719 1720 1721
 * The standard marshaller activates the object with the CLSID
 * returned and uses the CreateProxy and CreateStub methods on its
 * IPSFactoryBuffer interface to construct the proxies and stubs for a
 * given object.
1722 1723
 *
 * CoGetPSClsid determines this CLSID by searching the
1724 1725 1726
 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
 * in the registry and any interface id registered by
 * CoRegisterPSClsid within the current process.
1727
 *
1728
 * BUGS
1729
 *
1730
 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
Robert Shearman's avatar
Robert Shearman committed
1731 1732
 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
 * considered a bug in native unless an application depends on this (unlikely).
1733 1734 1735
 *
 * SEE ALSO
 *  CoRegisterPSClsid.
1736
 */
1737
HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1738
{
1739 1740 1741 1742
    static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0};
    static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0};
    WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)];
    WCHAR value[CHARS_IN_GUID];
1743
    LONG len;
1744
    HKEY hkey;
1745 1746
    APARTMENT *apt = COM_CurrentApt();
    struct registered_psclsid *registered_psclsid;
1747 1748 1749

    TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid);

1750 1751 1752 1753 1754 1755
    if (!apt)
    {
        ERR("apartment not initialised\n");
        return CO_E_NOTINITIALIZED;
    }

1756 1757 1758 1759 1760 1761
    if (!pclsid)
    {
        ERR("pclsid isn't optional\n");
        return E_INVALIDARG;
    }

1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
    EnterCriticalSection(&apt->cs);

    LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
        if (IsEqualIID(&registered_psclsid->iid, riid))
        {
            *pclsid = registered_psclsid->clsid;
            LeaveCriticalSection(&apt->cs);
            return S_OK;
        }

    LeaveCriticalSection(&apt->cs);

1774 1775 1776 1777
    /* Interface\\{string form of riid}\\ProxyStubClsid32 */
    strcpyW(path, wszInterface);
    StringFromGUID2(riid, path + ARRAYSIZE(wszInterface) - 1, CHARS_IN_GUID);
    strcpyW(path + ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1, wszPSC);
1778 1779

    /* Open the key.. */
1780
    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1781
    {
Robert Shearman's avatar
Robert Shearman committed
1782 1783
        WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
        return REGDB_E_IIDNOTREG;
1784 1785 1786
    }

    /* ... Once we have the key, query the registry to get the
1787
       value of CLSID as a string, and convert it into a
1788
       proper CLSID structure to be passed back to the app */
1789 1790
    len = sizeof(value);
    if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1791
    {
1792
        RegCloseKey(hkey);
Robert Shearman's avatar
Robert Shearman committed
1793
        return REGDB_E_IIDNOTREG;
1794
    }
1795
    RegCloseKey(hkey);
1796

Austin English's avatar
Austin English committed
1797 1798
    /* We have the CLSID we want back from the registry as a string, so
       let's convert it into a CLSID structure */
1799
    if (CLSIDFromString(value, pclsid) != NOERROR)
Robert Shearman's avatar
Robert Shearman committed
1800
        return REGDB_E_IIDNOTREG;
1801 1802

    TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
Robert Shearman's avatar
Robert Shearman committed
1803
    return S_OK;
1804 1805
}

1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866
/*****************************************************************************
 *             CoRegisterPSClsid [OLE32.@]
 *
 * Register a proxy/stub CLSID for the given interface in the current process
 * only.
 *
 * PARAMS
 *  riid   [I] Interface whose proxy/stub CLSID is to be registered.
 *  rclsid [I] CLSID of the proxy/stub.
 * 
 * RETURNS
 *   Success: S_OK
 *   Failure: E_OUTOFMEMORY
 *
 * NOTES
 *
 * This function does not add anything to the registry and the effects are
 * limited to the lifetime of the current process.
 *
 * SEE ALSO
 *  CoGetPSClsid.
 */
HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
{
    APARTMENT *apt = COM_CurrentApt();
    struct registered_psclsid *registered_psclsid;

    TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid));

    if (!apt)
    {
        ERR("apartment not initialised\n");
        return CO_E_NOTINITIALIZED;
    }

    EnterCriticalSection(&apt->cs);

    LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
        if (IsEqualIID(&registered_psclsid->iid, riid))
        {
            registered_psclsid->clsid = *rclsid;
            LeaveCriticalSection(&apt->cs);
            return S_OK;
        }

    registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
    if (!registered_psclsid)
    {
        LeaveCriticalSection(&apt->cs);
        return E_OUTOFMEMORY;
    }

    registered_psclsid->iid = *riid;
    registered_psclsid->clsid = *rclsid;
    list_add_head(&apt->psclsids, &registered_psclsid->entry);

    LeaveCriticalSection(&apt->cs);

    return S_OK;
}

1867

1868 1869 1870
/***
 * COM_GetRegisteredClassObject
 *
1871
 * This internal method is used to scan the registered class list to
1872 1873
 * find a class object.
 *
1874
 * Params:
1875 1876 1877 1878 1879 1880
 *   rclsid        Class ID of the class to find.
 *   dwClsContext  Class context to match.
 *   ppv           [out] returns a pointer to the class object. Complying
 *                 to normal COM usage, this method will increase the
 *                 reference count on this object.
 */
1881 1882
static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
                                            DWORD dwClsContext, LPUNKNOWN* ppUnk)
1883
{
1884
  HRESULT hr = S_FALSE;
1885
  RegisteredClass *curClass;
1886

1887
  EnterCriticalSection( &csRegisteredClassList );
1888

1889
  LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
1890 1891
  {
    /*
1892
     * Check if we have a match on the class ID and context.
1893
     */
1894 1895
    if ((apt->oxid == curClass->apartment_id) &&
        (dwClsContext & curClass->runContext) &&
1896
        IsEqualGUID(&(curClass->classIdentifier), rclsid))
1897 1898 1899 1900 1901 1902 1903 1904
    {
      /*
       * We have a match, return the pointer to the class object.
       */
      *ppUnk = curClass->classObject;

      IUnknown_AddRef(curClass->classObject);

1905
      hr = S_OK;
1906
      break;
1907 1908 1909
    }
  }

1910
  LeaveCriticalSection( &csRegisteredClassList );
1911

1912
  return hr;
1913 1914
}

1915
/******************************************************************************
1916
 *		CoRegisterClassObject	[OLE32.@]
1917
 *
1918 1919 1920
 * Registers the class object for a given class ID. Servers housed in EXE
 * files use this method instead of exporting DllGetClassObject to allow
 * other code to connect to their objects.
1921
 *
1922 1923 1924 1925 1926 1927 1928
 * PARAMS
 *  rclsid       [I] CLSID of the object to register.
 *  pUnk         [I] IUnknown of the object.
 *  dwClsContext [I] CLSCTX flags indicating the context in which to run the executable.
 *  flags        [I] REGCLS flags indicating how connections are made.
 *  lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject.
 *
1929
 * RETURNS
1930 1931
 *   S_OK on success,
 *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
1932 1933 1934 1935
 *   CO_E_OBJISREG if the object is already registered. We should not return this.
 *
 * SEE ALSO
 *   CoRevokeClassObject, CoGetClassObject
1936
 *
1937 1938 1939 1940 1941
 * NOTES
 *  In-process objects are only registered for the current apartment.
 *  CoGetClassObject() and CoCreateInstance() will not return objects registered
 *  in other apartments.
 *
1942 1943 1944
 * BUGS
 *  MSDN claims that multiple interface registrations are legal, but we
 *  can't do that with our current implementation.
Alexandre Julliard's avatar
Alexandre Julliard committed
1945
 */
1946
HRESULT WINAPI CoRegisterClassObject(
1947 1948 1949 1950 1951
    REFCLSID rclsid,
    LPUNKNOWN pUnk,
    DWORD dwClsContext,
    DWORD flags,
    LPDWORD lpdwRegister)
1952 1953 1954 1955
{
  RegisteredClass* newClass;
  LPUNKNOWN        foundObject;
  HRESULT          hr;
1956
  APARTMENT *apt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1957

1958
  TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
1959
	debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
1960 1961 1962 1963

  if ( (lpdwRegister==0) || (pUnk==0) )
    return E_INVALIDARG;

1964 1965
  apt = COM_CurrentApt();
  if (!apt)
1966 1967 1968 1969 1970
  {
      ERR("COM was not initialized\n");
      return CO_E_NOTINITIALIZED;
  }

1971 1972
  *lpdwRegister = 0;

1973 1974 1975 1976 1977
  /* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
   * differentiates the flag from REGCLS_MULTI_SEPARATE. */
  if (flags & REGCLS_MULTIPLEUSE)
    dwClsContext |= CLSCTX_INPROC_SERVER;

1978 1979 1980 1981
  /*
   * First, check if the class is already registered.
   * If it is, this should cause an error.
   */
1982
  hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
1983
  if (hr == S_OK) {
1984 1985 1986 1987 1988 1989
    if (flags & REGCLS_MULTIPLEUSE) {
      if (dwClsContext & CLSCTX_LOCAL_SERVER)
        hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
      IUnknown_Release(foundObject);
      return hr;
    }
1990
    IUnknown_Release(foundObject);
1991
    ERR("object already registered for class %s\n", debugstr_guid(rclsid));
1992 1993
    return CO_E_OBJISREG;
  }
1994

1995
  newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
1996 1997
  if ( newClass == NULL )
    return E_OUTOFMEMORY;
1998 1999

  newClass->classIdentifier = *rclsid;
2000
  newClass->apartment_id    = apt->oxid;
2001 2002
  newClass->runContext      = dwClsContext;
  newClass->connectFlags    = flags;
2003
  newClass->pMarshaledData  = NULL;
2004
  newClass->RpcRegistration = NULL;
2005

2006 2007
  /*
   * Use the address of the chain node as the cookie since we are sure it's
2008
   * unique. FIXME: not on 64-bit platforms.
2009
   */
2010 2011 2012
  newClass->dwCookie        = (DWORD)newClass;

  /*
2013
   * Since we're making a copy of the object pointer, we have to increase its
2014 2015 2016 2017 2018
   * reference count.
   */
  newClass->classObject     = pUnk;
  IUnknown_AddRef(newClass->classObject);

2019 2020
  EnterCriticalSection( &csRegisteredClassList );
  list_add_tail(&RegisteredClassList, &newClass->entry);
2021 2022
  LeaveCriticalSection( &csRegisteredClassList );

2023
  *lpdwRegister = newClass->dwCookie;
2024

2025
  if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2026 2027
      hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
      if (hr) {
2028
          FIXME("Failed to create stream on hglobal, %x\n", hr);
2029 2030 2031
          return hr;
      }
      hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
2032
                              newClass->classObject, MSHCTX_LOCAL, NULL,
2033 2034
                              MSHLFLAGS_TABLESTRONG);
      if (hr) {
2035
          FIXME("CoMarshalInterface failed, %x!\n",hr);
2036 2037 2038
          return hr;
      }

2039 2040
      hr = RPC_StartLocalServer(&newClass->classIdentifier,
                                newClass->pMarshaledData,
2041
                                flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2042
                                &newClass->RpcRegistration);
2043
  }
2044
  return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
2045 2046
}

2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064
static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
{
    list_remove(&curClass->entry);

    if (curClass->runContext & CLSCTX_LOCAL_SERVER)
        RPC_StopLocalServer(curClass->RpcRegistration);

    /*
     * Release the reference to the class object.
     */
    IUnknown_Release(curClass->classObject);

    if (curClass->pMarshaledData)
    {
        LARGE_INTEGER zero;
        memset(&zero, 0, sizeof(zero));
        IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
        CoReleaseMarshalData(curClass->pMarshaledData);
2065
        IStream_Release(curClass->pMarshaledData);
2066 2067 2068 2069 2070
    }

    HeapFree(GetProcessHeap(), 0, curClass);
}

2071
static void COM_RevokeAllClasses(const struct apartment *apt)
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085
{
  RegisteredClass *curClass, *cursor;

  EnterCriticalSection( &csRegisteredClassList );

  LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
  {
    if (curClass->apartment_id == apt->oxid)
      COM_RevokeRegisteredClassObject(curClass);
  }

  LeaveCriticalSection( &csRegisteredClassList );
}

2086
/***********************************************************************
2087
 *           CoRevokeClassObject [OLE32.@]
2088
 *
2089 2090 2091 2092
 * Removes a class object from the class registry.
 *
 * PARAMS
 *  dwRegister [I] Cookie returned from CoRegisterClassObject().
2093
 *
2094 2095 2096 2097
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
2098 2099 2100 2101
 * NOTES
 *  Must be called from the same apartment that called CoRegisterClassObject(),
 *  otherwise it will fail with RPC_E_WRONG_THREAD.
 *
2102 2103
 * SEE ALSO
 *  CoRegisterClassObject
2104
 */
2105
HRESULT WINAPI CoRevokeClassObject(
2106
        DWORD dwRegister)
2107
{
2108
  HRESULT hr = E_INVALIDARG;
2109
  RegisteredClass *curClass;
2110
  APARTMENT *apt;
2111

2112
  TRACE("(%08x)\n",dwRegister);
2113

2114 2115 2116 2117 2118 2119 2120
  apt = COM_CurrentApt();
  if (!apt)
  {
    ERR("COM was not initialized\n");
    return CO_E_NOTINITIALIZED;
  }

2121 2122
  EnterCriticalSection( &csRegisteredClassList );

2123
  LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2124 2125 2126 2127 2128 2129
  {
    /*
     * Check if we have a match on the cookie.
     */
    if (curClass->dwCookie == dwRegister)
    {
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140
      if (curClass->apartment_id == apt->oxid)
      {
          COM_RevokeRegisteredClassObject(curClass);
          hr = S_OK;
      }
      else
      {
          ERR("called from wrong apartment, should be called from %s\n",
              wine_dbgstr_longlong(curClass->apartment_id));
          hr = RPC_E_WRONG_THREAD;
      }
2141
      break;
2142
    }
2143 2144
  }

2145
  LeaveCriticalSection( &csRegisteredClassList );
2146

2147
  return hr;
2148 2149
}

2150
/***********************************************************************
2151
 *	COM_RegReadPath	[internal]
2152
 *
2153
 *	Reads a registry value and expands it when necessary
2154
 */
2155
static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
2156
{
2157
	DWORD ret;
2158 2159
	HKEY key;
	DWORD keytype;
2160 2161
	WCHAR src[MAX_PATH];
	DWORD dwLength = dstlen * sizeof(WCHAR);
2162

2163 2164
	if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
          if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
2165
            if (keytype == REG_EXPAND_SZ) {
2166
              if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
2167
            } else {
2168
              lstrcpynW(dst, src, dstlen);
2169 2170 2171 2172
            }
	  }
          RegCloseKey (key);
	}
2173
	return ret;
2174 2175
}

2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
static void get_threading_model(HKEY key, LPWSTR value, DWORD len)
{
    static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
    DWORD keytype;
    DWORD ret;
    DWORD dwLength = len * sizeof(WCHAR);

    ret = RegQueryValueExW(key, wszThreadingModel, NULL, &keytype, (LPBYTE)value, &dwLength);
    if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ))
        value[0] = '\0';
}

2188
static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2189 2190
                                       REFCLSID rclsid, REFIID riid,
                                       BOOL hostifnecessary, void **ppv)
2191 2192
{
    WCHAR dllpath[MAX_PATH+1];
2193
    BOOL apartment_threaded;
2194

2195
    if (hostifnecessary)
2196
    {
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230
        static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0};
        static const WCHAR wszFree[] = {'F','r','e','e',0};
        static const WCHAR wszBoth[] = {'B','o','t','h',0};
        WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];

        get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
        /* "Apartment" */
        if (!strcmpiW(threading_model, wszApartment))
        {
            apartment_threaded = TRUE;
            if (apt->multi_threaded)
                return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
        }
        /* "Free" */
        else if (!strcmpiW(threading_model, wszFree))
        {
            apartment_threaded = FALSE;
            if (!apt->multi_threaded)
                return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, hkeydll, rclsid, riid, ppv);
        }
        /* everything except "Apartment", "Free" and "Both" */
        else if (strcmpiW(threading_model, wszBoth))
        {
            apartment_threaded = TRUE;
            /* everything else is main-threaded */
            if (threading_model[0])
                FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
                    debugstr_w(threading_model), debugstr_guid(rclsid));

            if (apt->multi_threaded || !apt->main)
                return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, hkeydll, rclsid, riid, ppv);
        }
        else
            apartment_threaded = FALSE;
2231
    }
2232 2233
    else
        apartment_threaded = !apt->multi_threaded;
2234

2235 2236 2237 2238 2239 2240 2241
    if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)
    {
        /* failure: CLSID is not found in registry */
        WARN("class %s not registered inproc\n", debugstr_guid(rclsid));
        return REGDB_E_CLASSNOTREG;
    }

2242
    return apartment_getclassobject(apt, dllpath, apartment_threaded,
2243
                                    rclsid, riid, ppv);
2244 2245
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2246
/***********************************************************************
2247
 *           CoGetClassObject [OLE32.@]
2248
 *
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
 * Creates an object of the specified class.
 *
 * PARAMS
 *  rclsid       [I] Class ID to create an instance of.
 *  dwClsContext [I] Flags to restrict the location of the created instance.
 *  pServerInfo  [I] Optional. Details for connecting to a remote server.
 *  iid          [I] The ID of the interface of the instance to return.
 *  ppv          [O] On returns, contains a pointer to the specified interface of the object.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: HRESULT code.
 *
 * NOTES
 *  The dwClsContext parameter can be one or more of the following:
 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
 *
 * SEE ALSO
 *  CoCreateInstance()
Alexandre Julliard's avatar
Alexandre Julliard committed
2271
 */
2272 2273
HRESULT WINAPI CoGetClassObject(
    REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2274 2275
    REFIID iid, LPVOID *ppv)
{
2276 2277
    LPUNKNOWN	regClassObject;
    HRESULT	hres = E_UNEXPECTED;
2278
    APARTMENT  *apt;
2279

2280
    TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
Alexandre Julliard's avatar
Alexandre Julliard committed
2281

2282 2283 2284 2285 2286
    if (!ppv)
        return E_INVALIDARG;

    *ppv = NULL;

2287 2288
    apt = COM_CurrentApt();
    if (!apt)
2289 2290 2291 2292 2293
    {
        ERR("apartment not initialised\n");
        return CO_E_NOTINITIALIZED;
    }

2294 2295 2296 2297 2298
    if (pServerInfo) {
	FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
	FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
    }

2299
    /*
2300
     * First, try and see if we can't match the class ID with one of the
2301 2302
     * registered classes.
     */
2303 2304
    if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
                                             &regClassObject))
2305
    {
2306
      /* Get the required interface from the retrieved pointer. */
2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318
      hres = IUnknown_QueryInterface(regClassObject, iid, ppv);

      /*
       * Since QI got another reference on the pointer, we want to release the
       * one we already have. If QI was unsuccessful, this will release the object. This
       * is good since we are not returning it in the "out" parameter.
       */
      IUnknown_Release(regClassObject);

      return hres;
    }

2319 2320
    /* First try in-process server */
    if (CLSCTX_INPROC_SERVER & dwClsContext)
2321 2322 2323 2324
    {
        static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
        HKEY hkey;

2325 2326 2327
        if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
            return FTMarshalCF_Create(iid, ppv);

2328 2329
        hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
        if (FAILED(hres))
2330
        {
2331 2332
            if (hres == REGDB_E_CLASSNOTREG)
                ERR("class %s not registered\n", debugstr_guid(rclsid));
2333 2334
            else if (hres == REGDB_E_KEYMISSING)
            {
2335
                WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2336 2337
                hres = REGDB_E_CLASSNOTREG;
            }
2338 2339 2340 2341
        }

        if (SUCCEEDED(hres))
        {
2342 2343
            hres = get_inproc_class_object(apt, hkey, rclsid, iid,
                !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363
            RegCloseKey(hkey);
        }

        /* return if we got a class, otherwise fall through to one of the
         * other types */
        if (SUCCEEDED(hres))
            return hres;
    }

    /* Next try in-process handler */
    if (CLSCTX_INPROC_HANDLER & dwClsContext)
    {
        static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
        HKEY hkey;

        hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
        if (FAILED(hres))
        {
            if (hres == REGDB_E_CLASSNOTREG)
                ERR("class %s not registered\n", debugstr_guid(rclsid));
2364 2365
            else if (hres == REGDB_E_KEYMISSING)
            {
2366
                WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2367 2368
                hres = REGDB_E_CLASSNOTREG;
            }
2369
        }
2370

2371
        if (SUCCEEDED(hres))
2372
        {
2373 2374
            hres = get_inproc_class_object(apt, hkey, rclsid, iid,
                !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2375
            RegCloseKey(hkey);
2376
        }
2377 2378 2379 2380 2381

        /* return if we got a class, otherwise fall through to one of the
         * other types */
        if (SUCCEEDED(hres))
            return hres;
2382
    }
2383

2384
    /* Next try out of process */
2385 2386
    if (CLSCTX_LOCAL_SERVER & dwClsContext)
    {
2387 2388 2389
        hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
        if (SUCCEEDED(hres))
            return hres;
2390
    }
2391

2392
    /* Finally try remote: this requires networked DCOM (a lot of work) */
2393 2394 2395
    if (CLSCTX_REMOTE_SERVER & dwClsContext)
    {
        FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
2396
        hres = E_NOINTERFACE;
2397 2398
    }

2399
    if (FAILED(hres))
2400
        ERR("no class object %s could be created for context 0x%x\n",
2401
            debugstr_guid(rclsid), dwClsContext);
Alexandre Julliard's avatar
Alexandre Julliard committed
2402 2403
    return hres;
}
2404

2405
/***********************************************************************
2406
 *        CoResumeClassObjects (OLE32.@)
2407
 *
2408 2409 2410 2411 2412
 * Resumes all class objects registered with REGCLS_SUSPENDED.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
2413 2414 2415
 */
HRESULT WINAPI CoResumeClassObjects(void)
{
2416
       FIXME("stub\n");
2417 2418 2419
	return S_OK;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2420
/***********************************************************************
2421
 *           CoCreateInstance [OLE32.@]
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449
 *
 * Creates an instance of the specified class.
 *
 * PARAMS
 *  rclsid       [I] Class ID to create an instance of.
 *  pUnkOuter    [I] Optional outer unknown to allow aggregation with another object.
 *  dwClsContext [I] Flags to restrict the location of the created instance.
 *  iid          [I] The ID of the interface of the instance to return.
 *  ppv          [O] On returns, contains a pointer to the specified interface of the instance.
 *
 * RETURNS
 *  Success: S_OK
 *  Failure: HRESULT code.
 *
 * NOTES
 *  The dwClsContext parameter can be one or more of the following:
 *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
 *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
 *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
 *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
 *
 * Aggregation is the concept of deferring the IUnknown of an object to another
 * object. This allows a separate object to behave as though it was part of
 * the object and to allow this the pUnkOuter parameter can be set. Note that
 * not all objects support having an outer of unknown.
 *
 * SEE ALSO
 *  CoGetClassObject()
Alexandre Julliard's avatar
Alexandre Julliard committed
2450
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
2451 2452 2453 2454
HRESULT WINAPI CoCreateInstance(
	REFCLSID rclsid,
	LPUNKNOWN pUnkOuter,
	DWORD dwClsContext,
Alexandre Julliard's avatar
Alexandre Julliard committed
2455
	REFIID iid,
2456
	LPVOID *ppv)
2457
{
2458 2459
  HRESULT hres;
  LPCLASSFACTORY lpclf = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2460

2461
  TRACE("(rclsid=%s, pUnkOuter=%p, dwClsContext=%08x, riid=%s, ppv=%p)\n", debugstr_guid(rclsid),
2462 2463
        pUnkOuter, dwClsContext, debugstr_guid(iid), ppv);

2464 2465 2466 2467 2468 2469 2470 2471 2472 2473
  /*
   * Sanity check
   */
  if (ppv==0)
    return E_POINTER;

  /*
   * Initialize the "out" parameter
   */
  *ppv = 0;
2474

2475 2476 2477 2478 2479 2480
  if (!COM_CurrentApt())
  {
      ERR("apartment not initialised\n");
      return CO_E_NOTINITIALIZED;
  }

2481 2482 2483 2484 2485
  /*
   * The Standard Global Interface Table (GIT) object is a process-wide singleton.
   * Rather than create a class factory, we can just check for it here
   */
  if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
2486
    if (StdGlobalInterfaceTableInstance == NULL)
2487 2488 2489
      StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
    hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
    if (hres) return hres;
2490

2491 2492 2493
    TRACE("Retrieved GIT (%p)\n", *ppv);
    return S_OK;
  }
2494

2495 2496 2497 2498 2499 2500
  /*
   * Get a class factory to construct the object we want.
   */
  hres = CoGetClassObject(rclsid,
			  dwClsContext,
			  NULL,
2501
			  &IID_IClassFactory,
2502 2503
			  (LPVOID)&lpclf);

2504
  if (FAILED(hres))
2505 2506 2507 2508 2509
    return hres;

  /*
   * Create the object and don't forget to release the factory
   */
2510 2511
	hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
	IClassFactory_Release(lpclf);
2512
	if(FAILED(hres))
2513 2514 2515 2516 2517 2518
        {
          if (hres == CLASS_E_NOAGGREGATION && pUnkOuter)
              FIXME("Class %s does not support aggregation\n", debugstr_guid(rclsid));
          else
              FIXME("no instance created for interface %s of class %s, hres is 0x%08x\n", debugstr_guid(iid), debugstr_guid(rclsid),hres);
        }
2519

Alexandre Julliard's avatar
Alexandre Julliard committed
2520
	return hres;
Alexandre Julliard's avatar
Alexandre Julliard committed
2521 2522
}

2523
/***********************************************************************
2524
 *           CoCreateInstanceEx [OLE32.@]
2525 2526
 */
HRESULT WINAPI CoCreateInstanceEx(
2527
  REFCLSID      rclsid,
2528
  LPUNKNOWN     pUnkOuter,
2529
  DWORD         dwClsContext,
2530 2531 2532 2533 2534 2535 2536
  COSERVERINFO* pServerInfo,
  ULONG         cmq,
  MULTI_QI*     pResults)
{
  IUnknown* pUnk = NULL;
  HRESULT   hr;
  ULONG     index;
2537
  ULONG     successCount = 0;
2538 2539 2540 2541 2542 2543

  /*
   * Sanity check
   */
  if ( (cmq==0) || (pResults==NULL))
    return E_INVALIDARG;
2544

2545
  if (pServerInfo!=NULL)
2546
    FIXME("() non-NULL pServerInfo not supported!\n");
2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557

  /*
   * Initialize all the "out" parameters.
   */
  for (index = 0; index < cmq; index++)
  {
    pResults[index].pItf = NULL;
    pResults[index].hr   = E_NOINTERFACE;
  }

  /*
2558
   * Get the object and get its IUnknown pointer.
2559
   */
2560
  hr = CoCreateInstance(rclsid,
2561 2562 2563
			pUnkOuter,
			dwClsContext,
			&IID_IUnknown,
2564
			(VOID**)&pUnk);
2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594

  if (hr)
    return hr;

  /*
   * Then, query for all the interfaces requested.
   */
  for (index = 0; index < cmq; index++)
  {
    pResults[index].hr = IUnknown_QueryInterface(pUnk,
						 pResults[index].pIID,
						 (VOID**)&(pResults[index].pItf));

    if (pResults[index].hr == S_OK)
      successCount++;
  }

  /*
   * Release our temporary unknown pointer.
   */
  IUnknown_Release(pUnk);

  if (successCount == 0)
    return E_NOINTERFACE;

  if (successCount!=cmq)
    return CO_S_NOTALLINTERFACES;

  return S_OK;
}
2595

Ove Kaaven's avatar
Ove Kaaven committed
2596
/***********************************************************************
2597
 *           CoLoadLibrary (OLE32.@)
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610
 *
 * Loads a library.
 *
 * PARAMS
 *  lpszLibName [I] Path to library.
 *  bAutoFree   [I] Whether the library should automatically be freed.
 *
 * RETURNS
 *  Success: Handle to loaded library.
 *  Failure: NULL.
 *
 * SEE ALSO
 *  CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
Ove Kaaven's avatar
Ove Kaaven committed
2611
 */
2612
HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
Ove Kaaven's avatar
Ove Kaaven committed
2613
{
2614
    TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2615

2616 2617
    return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
}
2618

2619
/***********************************************************************
2620
 *           CoFreeLibrary [OLE32.@]
2621
 *
2622 2623 2624 2625 2626 2627 2628 2629 2630 2631
 * Unloads a library from memory.
 *
 * PARAMS
 *  hLibrary [I] Handle to library to unload.
 *
 * RETURNS
 *  Nothing
 *
 * SEE ALSO
 *  CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries
2632 2633 2634
 */
void WINAPI CoFreeLibrary(HINSTANCE hLibrary)
{
2635
    FreeLibrary(hLibrary);
2636 2637 2638 2639
}


/***********************************************************************
2640
 *           CoFreeAllLibraries [OLE32.@]
2641
 *
2642 2643 2644 2645 2646 2647 2648
 * Function for backwards compatibility only. Does nothing.
 *
 * RETURNS
 *  Nothing.
 *
 * SEE ALSO
 *  CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries
2649 2650 2651
 */
void WINAPI CoFreeAllLibraries(void)
{
2652
    /* NOP */
Ove Kaaven's avatar
Ove Kaaven committed
2653 2654
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2655
/***********************************************************************
2656
 *           CoFreeUnusedLibrariesEx [OLE32.@]
2657
 *
2658 2659 2660 2661 2662 2663 2664
 * Frees any previously unused libraries whose delay has expired and marks
 * currently unused libraries for unloading. Unused are identified as those that
 * return S_OK from their DllCanUnloadNow function.
 *
 * PARAMS
 *  dwUnloadDelay [I] Unload delay in milliseconds.
 *  dwReserved    [I] Reserved. Set to 0.
2665 2666 2667
 *
 * RETURNS
 *  Nothing.
2668
 *
2669 2670
 * SEE ALSO
 *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
Alexandre Julliard's avatar
Alexandre Julliard committed
2671
 */
2672
void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
Alexandre Julliard's avatar
Alexandre Julliard committed
2673
{
2674 2675 2676 2677 2678 2679 2680
    struct apartment *apt = COM_CurrentApt();
    if (!apt)
    {
        ERR("apartment not initialised\n");
        return;
    }

2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699
    apartment_freeunusedlibraries(apt, dwUnloadDelay);
}

/***********************************************************************
 *           CoFreeUnusedLibraries [OLE32.@]
 *           CoFreeUnusedLibraries [COMPOBJ.17]
 *
 * Frees any unused libraries. Unused are identified as those that return
 * S_OK from their DllCanUnloadNow function.
 *
 * RETURNS
 *  Nothing.
 *
 * SEE ALSO
 *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
 */
void WINAPI CoFreeUnusedLibraries(void)
{
    CoFreeUnusedLibrariesEx(INFINITE, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
2700 2701 2702
}

/***********************************************************************
2703
 *           CoFileTimeNow [OLE32.@]
2704 2705 2706 2707 2708 2709
 *           CoFileTimeNow [COMPOBJ.82]
 *
 * Retrieves the current time in FILETIME format.
 *
 * PARAMS
 *  lpFileTime [O] The current time.
Patrik Stridvall's avatar
Patrik Stridvall committed
2710
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2711
 * RETURNS
2712
 *	S_OK.
Alexandre Julliard's avatar
Alexandre Julliard committed
2713
 */
2714
HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime )
2715 2716 2717
{
    GetSystemTimeAsFileTime( lpFileTime );
    return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
2718
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2719

2720
/******************************************************************************
2721
 *		CoLockObjectExternal	[OLE32.@]
2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734
 *
 * Increments or decrements the external reference count of a stub object.
 *
 * PARAMS
 *  pUnk                [I] Stub object.
 *  fLock               [I] If TRUE then increments the external ref-count,
 *                          otherwise decrements.
 *  fLastUnlockReleases [I] If TRUE then the last unlock has the effect of
 *                          calling CoDisconnectObject.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
2735 2736 2737 2738
 *
 * NOTES
 *  If fLock is TRUE and an object is passed in that doesn't have a stub
 *  manager then a new stub manager is created for the object.
2739
 */
2740
HRESULT WINAPI CoLockObjectExternal(
2741 2742 2743
    LPUNKNOWN pUnk,
    BOOL fLock,
    BOOL fLastUnlockReleases)
2744
{
2745 2746 2747
    struct stub_manager *stubmgr;
    struct apartment *apt;

2748 2749
    TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
          pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
2750

2751 2752 2753 2754 2755 2756 2757 2758
    apt = COM_CurrentApt();
    if (!apt) return CO_E_NOTINITIALIZED;

    stubmgr = get_stub_manager_from_object(apt, pUnk);
    
    if (stubmgr)
    {
        if (fLock)
2759
            stub_manager_ext_addref(stubmgr, 1, FALSE);
2760
        else
2761
            stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
2762 2763
        
        stub_manager_int_release(stubmgr);
2764

2765
        return S_OK;
2766
    }
2767 2768 2769 2770 2771 2772
    else if (fLock)
    {
        stubmgr = new_stub_manager(apt, pUnk);

        if (stubmgr)
        {
2773
            stub_manager_ext_addref(stubmgr, 1, FALSE);
2774 2775 2776 2777 2778
            stub_manager_int_release(stubmgr);
        }

        return S_OK;
    }
2779 2780 2781 2782 2783 2784 2785 2786
    else
    {
        WARN("stub object not found %p\n", pUnk);
        /* Note: native is pretty broken here because it just silently
         * fails, without returning an appropriate error code, making apps
         * think that the object was disconnected, when it actually wasn't */
        return S_OK;
    }
2787 2788
}

2789
/***********************************************************************
2790
 *           CoInitializeWOW (OLE32.@)
2791 2792 2793 2794 2795 2796 2797 2798 2799
 *
 * WOW equivalent of CoInitialize?
 *
 * PARAMS
 *  x [I] Unknown.
 *  y [I] Unknown.
 *
 * RETURNS
 *  Unknown.
2800
 */
2801 2802
HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y)
{
2803
    FIXME("(0x%08x,0x%08x),stub!\n",x,y);
2804
    return 0;
2805 2806
}

2807
/***********************************************************************
2808
 *           CoGetState [OLE32.@]
2809
 *
2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
 * Retrieves the thread state object previously stored by CoSetState().
 *
 * PARAMS
 *  ppv [I] Address where pointer to object will be stored.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: E_OUTOFMEMORY.
 *
 * NOTES
 *  Crashes on all invalid ppv addresses, including NULL.
 *  If the function returns a non-NULL object then the caller must release its
 *  reference on the object when the object is no longer required.
 *
 * SEE ALSO
 *  CoSetState().
2826
 */
2827
HRESULT WINAPI CoGetState(IUnknown ** ppv)
2828
{
2829 2830
    struct oletls *info = COM_CurrentInfo();
    if (!info) return E_OUTOFMEMORY;
2831

2832
    *ppv = NULL;
2833

2834
    if (info->state)
2835
    {
2836 2837 2838
        IUnknown_AddRef(info->state);
        *ppv = info->state;
        TRACE("apt->state=%p\n", info->state);
2839
    }
2840

2841
    return S_OK;
2842
}
2843 2844

/***********************************************************************
2845
 *           CoSetState [OLE32.@]
2846
 *
2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857
 * Sets the thread state object.
 *
 * PARAMS
 *  pv [I] Pointer to state object to be stored.
 *
 * NOTES
 *  The system keeps a reference on the object while the object stored.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: E_OUTOFMEMORY.
2858
 */
2859
HRESULT WINAPI CoSetState(IUnknown * pv)
2860
{
2861 2862 2863
    struct oletls *info = COM_CurrentInfo();
    if (!info) return E_OUTOFMEMORY;

2864
    if (pv) IUnknown_AddRef(pv);
2865

2866
    if (info->state)
2867
    {
2868 2869
        TRACE("-- release %p now\n", info->state);
        IUnknown_Release(info->state);
2870
    }
2871

2872
    info->state = pv;
2873

2874
    return S_OK;
2875
}
2876

2877

2878
/******************************************************************************
2879
 *              CoTreatAsClass        [OLE32.@]
2880
 *
2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
 * Sets the TreatAs value of a class.
 *
 * PARAMS
 *  clsidOld [I] Class to set TreatAs value on.
 *  clsidNew [I] The class the clsidOld should be treated as.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoGetTreatAsClass
2893 2894 2895
 */
HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
{
2896 2897 2898 2899
    static const WCHAR wszAutoTreatAs[] = {'A','u','t','o','T','r','e','a','t','A','s',0};
    static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
    HKEY hkey = NULL;
    WCHAR szClsidNew[CHARS_IN_GUID];
2900
    HRESULT res = S_OK;
2901
    WCHAR auto_treat_as[CHARS_IN_GUID];
2902 2903
    LONG auto_treat_as_size = sizeof(auto_treat_as);
    CLSID id;
2904

2905 2906 2907
    res = COM_OpenKeyForCLSID(clsidOld, NULL, KEY_READ | KEY_WRITE, &hkey);
    if (FAILED(res))
        goto done;
2908
    if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) ))
2909
    {
2910
       if (!RegQueryValueW(hkey, wszAutoTreatAs, auto_treat_as, &auto_treat_as_size) &&
2911
           CLSIDFromString(auto_treat_as, &id) == S_OK)
2912
       {
2913
           if (RegSetValueW(hkey, wszTreatAs, REG_SZ, auto_treat_as, sizeof(auto_treat_as)))
2914 2915 2916 2917 2918 2919 2920
           {
               res = REGDB_E_WRITEREGDB;
               goto done;
           }
       }
       else
       {
2921
           RegDeleteKeyW(hkey, wszTreatAs);
2922 2923 2924
           goto done;
       }
    }
2925 2926
    else if (!StringFromGUID2(clsidNew, szClsidNew, ARRAYSIZE(szClsidNew)) &&
             !RegSetValueW(hkey, wszTreatAs, REG_SZ, szClsidNew, sizeof(szClsidNew)))
2927
    {
2928
        res = REGDB_E_WRITEREGDB;
2929 2930 2931 2932 2933 2934
	goto done;
    }

done:
    if (hkey) RegCloseKey(hkey);
    return res;
2935
}
2936

2937
/******************************************************************************
2938
 *              CoGetTreatAsClass        [OLE32.@]
2939
 *
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951
 * Gets the TreatAs value of a class.
 *
 * PARAMS
 *  clsidOld [I] Class to get the TreatAs value of.
 *  clsidNew [I] The class the clsidOld should be treated as.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoSetTreatAsClass
2952 2953 2954
 */
HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
{
2955 2956 2957
    static const WCHAR wszTreatAs[] = {'T','r','e','a','t','A','s',0};
    HKEY hkey = NULL;
    WCHAR szClsidNew[CHARS_IN_GUID];
2958 2959 2960 2961
    HRESULT res = S_OK;
    LONG len = sizeof(szClsidNew);

    FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew);
2962
    *clsidNew = *clsidOld; /* copy over old value */
2963

2964 2965 2966 2967
    res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
    if (FAILED(res))
        goto done;
    if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2968 2969 2970 2971
    {
        res = S_FALSE;
	goto done;
    }
2972
    res = CLSIDFromString(szClsidNew,clsidNew);
2973
    if (FAILED(res))
2974
        ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2975 2976 2977 2978
done:
    if (hkey) RegCloseKey(hkey);
    return res;
}
2979

2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008
/******************************************************************************
 *		CoGetCurrentProcess	[OLE32.@]
 *		CoGetCurrentProcess	[COMPOBJ.34]
 *
 * Gets the current process ID.
 *
 * RETURNS
 *  The current process ID.
 *
 * NOTES
 *   Is DWORD really the correct return type for this function?
 */
DWORD WINAPI CoGetCurrentProcess(void)
{
	return GetCurrentProcessId();
}

/******************************************************************************
 *		CoRegisterMessageFilter	[OLE32.@]
 *
 * Registers a message filter.
 *
 * PARAMS
 *  lpMessageFilter [I] Pointer to interface.
 *  lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
3009 3010 3011 3012 3013 3014 3015 3016 3017 3018
 *
 * NOTES
 *  Both lpMessageFilter and lplpMessageFilter are optional. Passing in a NULL
 *  lpMessageFilter removes the message filter.
 *
 *  If lplpMessageFilter is not NULL the previous message filter will be
 *  returned in the memory pointer to this parameter and the caller is
 *  responsible for releasing the object.
 *
 *  The current thread be in an apartment otherwise the function will crash.
3019 3020 3021 3022 3023
 */
HRESULT WINAPI CoRegisterMessageFilter(
    LPMESSAGEFILTER lpMessageFilter,
    LPMESSAGEFILTER *lplpMessageFilter)
{
3024 3025 3026 3027 3028 3029 3030 3031
    struct apartment *apt;
    IMessageFilter *lpOldMessageFilter;

    TRACE("(%p, %p)\n", lpMessageFilter, lplpMessageFilter);

    apt = COM_CurrentApt();

    /* can't set a message filter in a multi-threaded apartment */
3032
    if (!apt || apt->multi_threaded)
3033
    {
3034
        WARN("can't set message filter in MTA or uninitialized apt\n");
3035
        return CO_E_NOT_SUPPORTED;
3036
    }
3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052

    if (lpMessageFilter)
        IMessageFilter_AddRef(lpMessageFilter);

    EnterCriticalSection(&apt->cs);

    lpOldMessageFilter = apt->filter;
    apt->filter = lpMessageFilter;

    LeaveCriticalSection(&apt->cs);

    if (lplpMessageFilter)
        *lplpMessageFilter = lpOldMessageFilter;
    else if (lpOldMessageFilter)
        IMessageFilter_Release(lpOldMessageFilter);

3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072
    return S_OK;
}

/***********************************************************************
 *           CoIsOle1Class [OLE32.@]
 *
 * Determines whether the specified class an OLE v1 class.
 *
 * PARAMS
 *  clsid [I] Class to test.
 *
 * RETURNS
 *  TRUE if the class is an OLE v1 class, or FALSE otherwise.
 */
BOOL WINAPI CoIsOle1Class(REFCLSID clsid)
{
  FIXME("%s\n", debugstr_guid(clsid));
  return FALSE;
}

3073
/***********************************************************************
3074
 *           IsEqualGUID [OLE32.@]
3075 3076 3077
 *
 * Compares two Unique Identifiers.
 *
3078 3079 3080 3081
 * PARAMS
 *  rguid1 [I] The first GUID to compare.
 *  rguid2 [I] The other GUID to compare.
 *
3082 3083 3084 3085 3086
 * RETURNS
 *	TRUE if equal
 */
#undef IsEqualGUID
BOOL WINAPI IsEqualGUID(
3087 3088
     REFGUID rguid1,
     REFGUID rguid2)
3089 3090 3091
{
    return !memcmp(rguid1,rguid2,sizeof(GUID));
}
3092 3093

/***********************************************************************
3094
 *           CoInitializeSecurity [OLE32.@]
3095 3096 3097 3098 3099 3100 3101
 */
HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc,
                                    SOLE_AUTHENTICATION_SERVICE* asAuthSvc,
                                    void* pReserved1, DWORD dwAuthnLevel,
                                    DWORD dwImpLevel, void* pReserved2,
                                    DWORD dwCapabilities, void* pReserved3)
{
3102
  FIXME("(%p,%d,%p,%p,%d,%d,%p,%d,%p) - stub!\n", pSecDesc, cAuthSvc,
3103 3104 3105 3106
        asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2,
        dwCapabilities, pReserved3);
  return S_OK;
}
3107 3108 3109

/***********************************************************************
 *           CoSuspendClassObjects [OLE32.@]
3110 3111 3112 3113 3114 3115 3116
 *
 * Suspends all registered class objects to prevent further requests coming in
 * for those objects.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
3117 3118 3119 3120 3121 3122
 */
HRESULT WINAPI CoSuspendClassObjects(void)
{
    FIXME("\n");
    return S_OK;
}
3123 3124 3125

/***********************************************************************
 *           CoAddRefServerProcess [OLE32.@]
3126 3127 3128 3129 3130 3131
 *
 * Helper function for incrementing the reference count of a local-server
 * process.
 *
 * RETURNS
 *  New reference count.
3132 3133 3134
 *
 * SEE ALSO
 *  CoReleaseServerProcess().
3135 3136 3137
 */
ULONG WINAPI CoAddRefServerProcess(void)
{
3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148
    ULONG refs;

    TRACE("\n");

    EnterCriticalSection(&csRegisteredClassList);
    refs = ++s_COMServerProcessReferences;
    LeaveCriticalSection(&csRegisteredClassList);

    TRACE("refs before: %d\n", refs - 1);

    return refs;
3149 3150 3151 3152
}

/***********************************************************************
 *           CoReleaseServerProcess [OLE32.@]
3153 3154 3155 3156 3157 3158
 *
 * Helper function for decrementing the reference count of a local-server
 * process.
 *
 * RETURNS
 *  New reference count.
3159 3160 3161 3162 3163 3164 3165
 *
 * NOTES
 *  When reference count reaches 0, this function suspends all registered
 *  classes so no new connections are accepted.
 *
 * SEE ALSO
 *  CoAddRefServerProcess(), CoSuspendClassObjects().
3166 3167 3168
 */
ULONG WINAPI CoReleaseServerProcess(void)
{
3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182
    ULONG refs;

    TRACE("\n");

    EnterCriticalSection(&csRegisteredClassList);

    refs = --s_COMServerProcessReferences;
    /* FIXME: if (!refs) COM_SuspendClassObjects(); */

    LeaveCriticalSection(&csRegisteredClassList);

    TRACE("refs after: %d\n", refs);

    return refs;
3183
}
3184

3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202
/***********************************************************************
 *           CoIsHandlerConnected [OLE32.@]
 *
 * Determines whether a proxy is connected to a remote stub.
 *
 * PARAMS
 *  pUnk [I] Pointer to object that may or may not be connected.
 *
 * RETURNS
 *  TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or
 *  FALSE otherwise.
 */
BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk)
{
    FIXME("%p\n", pUnk);

    return TRUE;
}
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212

/***********************************************************************
 *           CoAllowSetForegroundWindow [OLE32.@]
 *
 */
HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
{
    FIXME("(%p, %p): stub\n", pUnk, pvReserved);
    return S_OK;
}
3213
 
3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246
/***********************************************************************
 *           CoQueryProxyBlanket [OLE32.@]
 *
 * Retrieves the security settings being used by a proxy.
 *
 * PARAMS
 *  pProxy        [I] Pointer to the proxy object.
 *  pAuthnSvc     [O] The type of authentication service.
 *  pAuthzSvc     [O] The type of authorization service.
 *  ppServerPrincName [O] Optional. The server prinicple name.
 *  pAuthnLevel   [O] The authentication level.
 *  pImpLevel     [O] The impersonation level.
 *  ppAuthInfo    [O] Information specific to the authorization/authentication service.
 *  pCapabilities [O] Flags affecting the security behaviour.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoCopyProxy, CoSetProxyBlanket.
 */
HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc,
    DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel,
    DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities)
{
    IClientSecurity *pCliSec;
    HRESULT hr;

    TRACE("%p\n", pProxy);

    hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
    if (SUCCEEDED(hr))
3247
    {
3248 3249 3250 3251
        hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
                                          pAuthzSvc, ppServerPrincName,
                                          pAuthnLevel, pImpLevel, ppAuthInfo,
                                          pCapabilities);
3252 3253
        IClientSecurity_Release(pCliSec);
    }
3254

3255
    if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291
    return hr;
}

/***********************************************************************
 *           CoSetProxyBlanket [OLE32.@]
 *
 * Sets the security settings for a proxy.
 *
 * PARAMS
 *  pProxy       [I] Pointer to the proxy object.
 *  AuthnSvc     [I] The type of authentication service.
 *  AuthzSvc     [I] The type of authorization service.
 *  pServerPrincName [I] The server prinicple name.
 *  AuthnLevel   [I] The authentication level.
 *  ImpLevel     [I] The impersonation level.
 *  pAuthInfo    [I] Information specific to the authorization/authentication service.
 *  Capabilities [I] Flags affecting the security behaviour.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoQueryProxyBlanket, CoCopyProxy.
 */
HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc,
    DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel,
    DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities)
{
    IClientSecurity *pCliSec;
    HRESULT hr;

    TRACE("%p\n", pProxy);

    hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
    if (SUCCEEDED(hr))
3292
    {
3293 3294 3295 3296
        hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
                                        AuthzSvc, pServerPrincName,
                                        AuthnLevel, ImpLevel, pAuthInfo,
                                        Capabilities);
3297 3298
        IClientSecurity_Release(pCliSec);
    }
3299

3300
    if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
    return hr;
}

/***********************************************************************
 *           CoCopyProxy [OLE32.@]
 *
 * Copies a proxy.
 *
 * PARAMS
 *  pProxy [I] Pointer to the proxy object.
 *  ppCopy [O] Copy of the proxy.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoQueryProxyBlanket, CoSetProxyBlanket.
 */
HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy)
{
    IClientSecurity *pCliSec;
    HRESULT hr;

    TRACE("%p\n", pProxy);

    hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec);
    if (SUCCEEDED(hr))
3329
    {
3330
        hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3331 3332
        IClientSecurity_Release(pCliSec);
    }
3333

3334
    if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
3335 3336
    return hr;
}
3337 3338


3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354
/***********************************************************************
 *           CoGetCallContext [OLE32.@]
 *
 * Gets the context of the currently executing server call in the current
 * thread.
 *
 * PARAMS
 *  riid [I] Context interface to return.
 *  ppv  [O] Pointer to memory that will receive the context on return.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 */
HRESULT WINAPI CoGetCallContext(REFIID riid, void **ppv)
{
3355
    struct oletls *info = COM_CurrentInfo();
3356

3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394
    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);

    if (!info)
        return E_OUTOFMEMORY;

    if (!info->call_state)
        return RPC_E_CALL_COMPLETE;

    return IUnknown_QueryInterface(info->call_state, riid, ppv);
}

/***********************************************************************
 *           CoSwitchCallContext [OLE32.@]
 *
 * Switches the context of the currently executing server call in the current
 * thread.
 *
 * PARAMS
 *  pObject     [I] Pointer to new context object
 *  ppOldObject [O] Pointer to memory that will receive old context object pointer
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 */
HRESULT WINAPI CoSwitchCallContext(IUnknown *pObject, IUnknown **ppOldObject)
{
    struct oletls *info = COM_CurrentInfo();

    TRACE("(%p, %p)\n", pObject, ppOldObject);

    if (!info)
        return E_OUTOFMEMORY;

    *ppOldObject = info->call_state;
    info->call_state = pObject; /* CoSwitchCallContext does not addref nor release objects */

    return S_OK;
3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
}

/***********************************************************************
 *           CoQueryClientBlanket [OLE32.@]
 *
 * Retrieves the authentication information about the client of the currently
 * executing server call in the current thread.
 *
 * PARAMS
 *  pAuthnSvc     [O] Optional. The type of authentication service.
 *  pAuthzSvc     [O] Optional. The type of authorization service.
 *  pServerPrincName [O] Optional. The server prinicple name.
 *  pAuthnLevel   [O] Optional. The authentication level.
 *  pImpLevel     [O] Optional. The impersonation level.
 *  pPrivs        [O] Optional. Information about the privileges of the client.
 *  pCapabilities [IO] Optional. Flags affecting the security behaviour.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoImpersonateClient, CoRevertToSelf, CoGetCallContext.
 */
HRESULT WINAPI CoQueryClientBlanket(
    DWORD *pAuthnSvc,
    DWORD *pAuthzSvc,
    OLECHAR **pServerPrincName,
    DWORD *pAuthnLevel,
    DWORD *pImpLevel,
    RPC_AUTHZ_HANDLE *pPrivs,
    DWORD *pCapabilities)
{
    IServerSecurity *pSrvSec;
    HRESULT hr;

    TRACE("(%p, %p, %p, %p, %p, %p, %p)\n",
        pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel, pImpLevel,
        pPrivs, pCapabilities);

    hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
    if (SUCCEEDED(hr))
    {
        hr = IServerSecurity_QueryBlanket(
            pSrvSec, pAuthnSvc, pAuthzSvc, pServerPrincName, pAuthnLevel,
            pImpLevel, pPrivs, pCapabilities);
        IServerSecurity_Release(pSrvSec);
    }

    return hr;
}

/***********************************************************************
 *           CoImpersonateClient [OLE32.@]
 *
 * Impersonates the client of the currently executing server call in the
 * current thread.
 *
 * PARAMS
 *  None.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * NOTES
 *  If this function fails then the current thread will not be impersonating
 *  the client and all actions will take place on behalf of the server.
 *  Therefore, it is important to check the return value from this function.
 *
 * SEE ALSO
 *  CoRevertToSelf, CoQueryClientBlanket, CoGetCallContext.
 */
HRESULT WINAPI CoImpersonateClient(void)
{
    IServerSecurity *pSrvSec;
    HRESULT hr;

    TRACE("\n");

    hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
    if (SUCCEEDED(hr))
    {
        hr = IServerSecurity_ImpersonateClient(pSrvSec);
        IServerSecurity_Release(pSrvSec);
    }

    return hr;
}

/***********************************************************************
 *           CoRevertToSelf [OLE32.@]
 *
 * Ends the impersonation of the client of the currently executing server
 * call in the current thread.
 *
 * PARAMS
 *  None.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  CoImpersonateClient, CoQueryClientBlanket, CoGetCallContext.
 */
HRESULT WINAPI CoRevertToSelf(void)
{
    IServerSecurity *pSrvSec;
    HRESULT hr;

    TRACE("\n");

    hr = CoGetCallContext(&IID_IServerSecurity, (void **)&pSrvSec);
    if (SUCCEEDED(hr))
    {
        hr = IServerSecurity_RevertToSelf(pSrvSec);
        IServerSecurity_Release(pSrvSec);
    }

    return hr;
}

3518 3519
static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
{
3520 3521
    /* first try to retrieve messages for incoming COM calls to the apartment window */
    return PeekMessageW(msg, apt->win, WM_USER, WM_APP - 1, PM_REMOVE|PM_NOYIELD) ||
3522
           /* next retrieve other messages necessary for the app to remain responsive */
3523
           PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_POSTMESSAGE|PM_REMOVE|PM_NOYIELD);
3524 3525
}

3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551
/***********************************************************************
 *           CoWaitForMultipleHandles [OLE32.@]
 *
 * Waits for one or more handles to become signaled.
 *
 * PARAMS
 *  dwFlags   [I] Flags. See notes.
 *  dwTimeout [I] Timeout in milliseconds.
 *  cHandles  [I] Number of handles pointed to by pHandles.
 *  pHandles  [I] Handles to wait for.
 *  lpdwindex [O] Index of handle that was signaled.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: RPC_S_CALLPENDING on timeout.
 *
 * NOTES
 *
 * The dwFlags parameter can be zero or more of the following:
 *| COWAIT_WAITALL - Wait for all of the handles to become signaled.
 *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait.
 *
 * SEE ALSO
 *  MsgWaitForMultipleObjects, WaitForMultipleObjects.
 */
HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout,
3552
    ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3553 3554 3555
{
    HRESULT hr = S_OK;
    DWORD start_time = GetTickCount();
3556 3557
    APARTMENT *apt = COM_CurrentApt();
    BOOL message_loop = apt && !apt->multi_threaded;
3558

3559
    TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3560 3561 3562 3563 3564 3565
        pHandles, lpdwindex);

    while (TRUE)
    {
        DWORD now = GetTickCount();
        DWORD res;
3566

3567
        if (now - start_time > dwTimeout)
3568 3569 3570 3571 3572
        {
            hr = RPC_S_CALLPENDING;
            break;
        }

3573 3574
        if (message_loop)
        {
3575 3576
            DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
                    ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3577 3578

            TRACE("waiting for rpc completion or window message\n");
3579

3580 3581 3582
            res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
                (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
                QS_ALLINPUT, wait_flags);
3583

3584
            if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
3585
            {
3586
                MSG msg;
3587

3588 3589 3590 3591
                /* call message filter */

                if (COM_CurrentApt()->filter)
                {
3592 3593 3594
                    PENDINGTYPE pendingtype =
                        COM_CurrentInfo()->pending_call_count_server ?
                            PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3595 3596
                    DWORD be_handled = IMessageFilter_MessagePending(
                        COM_CurrentApt()->filter, 0 /* FIXME */,
3597
                        now - start_time, pendingtype);
3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615
                    TRACE("IMessageFilter_MessagePending returned %d\n", be_handled);
                    switch (be_handled)
                    {
                    case PENDINGMSG_CANCELCALL:
                        WARN("call canceled\n");
                        hr = RPC_E_CALL_CANCELED;
                        break;
                    case PENDINGMSG_WAITNOPROCESS:
                    case PENDINGMSG_WAITDEFPROCESS:
                    default:
                        /* FIXME: MSDN is very vague about the difference
                         * between WAITNOPROCESS and WAITDEFPROCESS - there
                         * appears to be none, so it is possibly a left-over
                         * from the 16-bit world. */
                        break;
                    }
                }

3616 3617 3618 3619 3620
                /* note: using "if" here instead of "while" might seem less
                 * efficient, but only if we are optimising for quick delivery
                 * of pending messages, rather than quick completion of the
                 * COM call */
                if (COM_PeekMessage(apt, &msg))
3621
                {
3622 3623 3624 3625 3626 3627 3628 3629 3630 3631
                    TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message);
                    TranslateMessage(&msg);
                    DispatchMessageW(&msg);
                    if (msg.message == WM_QUIT)
                    {
                        TRACE("resending WM_QUIT to outer message loop\n");
                        PostQuitMessage(msg.wParam);
                        /* no longer need to process messages */
                        message_loop = FALSE;
                    }
3632
                }
3633
                continue;
3634 3635
            }
        }
3636 3637 3638 3639 3640 3641 3642 3643 3644 3645
        else
        {
            TRACE("waiting for rpc completion\n");

            res = WaitForMultipleObjectsEx(cHandles, pHandles,
                (dwFlags & COWAIT_WAITALL) ? TRUE : FALSE,
                (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
                (dwFlags & COWAIT_ALERTABLE) ? TRUE : FALSE);
        }

3646
        if (res < WAIT_OBJECT_0 + cHandles)
3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658
        {
            /* handle signaled, store index */
            *lpdwindex = (res - WAIT_OBJECT_0);
            break;
        }
        else if (res == WAIT_TIMEOUT)
        {
            hr = RPC_S_CALLPENDING;
            break;
        }
        else
        {
3659
            ERR("Unexpected wait termination: %d, %d\n", res, GetLastError());
3660 3661 3662 3663
            hr = E_UNEXPECTED;
            break;
        }
    }
3664
    TRACE("-- 0x%08x\n", hr);
3665 3666
    return hr;
}
3667

3668 3669 3670 3671

/***********************************************************************
 *           CoGetObject [OLE32.@]
 *
3672
 * Gets the object named by converting the name to a moniker and binding to it.
3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719
 *
 * PARAMS
 *  pszName      [I] String representing the object.
 *  pBindOptions [I] Parameters affecting the binding to the named object.
 *  riid         [I] Interface to bind to on the objecct.
 *  ppv          [O] On output, the interface riid of the object represented
 *                   by pszName.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * SEE ALSO
 *  MkParseDisplayName.
 */
HRESULT WINAPI CoGetObject(LPCWSTR pszName, BIND_OPTS *pBindOptions,
    REFIID riid, void **ppv)
{
    IBindCtx *pbc;
    HRESULT hr;

    *ppv = NULL;

    hr = CreateBindCtx(0, &pbc);
    if (SUCCEEDED(hr))
    {
        if (pBindOptions)
            hr = IBindCtx_SetBindOptions(pbc, pBindOptions);

        if (SUCCEEDED(hr))
        {
            ULONG chEaten;
            IMoniker *pmk;

            hr = MkParseDisplayName(pbc, pszName, &chEaten, &pmk);
            if (SUCCEEDED(hr))
            {
                hr = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppv);
                IMoniker_Release(pmk);
            }
        }

        IBindCtx_Release(pbc);
    }
    return hr;
}

3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739
/***********************************************************************
 *           CoRegisterChannelHook [OLE32.@]
 *
 * Registers a process-wide hook that is called during ORPC calls.
 *
 * PARAMS
 *  guidExtension [I] GUID of the channel hook to register.
 *  pChannelHook  [I] Channel hook object to register.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 */
HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChannelHook)
{
    TRACE("(%s, %p)\n", debugstr_guid(guidExtension), pChannelHook);

    return RPC_RegisterChannelHook(guidExtension, pChannelHook);
}

3740 3741 3742
typedef struct Context
{
    const IComThreadingInfoVtbl *lpVtbl;
3743
    const IContextCallbackVtbl  *lpCallbackVtbl;
3744 3745 3746 3747
    LONG refs;
    APTTYPE apttype;
} Context;

3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758
static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
{
        return (Context *)((char*)iface - FIELD_OFFSET(Context, lpVtbl));
}

static inline Context *impl_from_IContextCallback( IContextCallback *iface )
{
        return (Context *)((char*)iface - FIELD_OFFSET(Context, lpCallbackVtbl));
}

static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3759 3760 3761 3762 3763 3764
{
    *ppv = NULL;

    if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
        IsEqualIID(riid, &IID_IUnknown))
    {
3765 3766 3767 3768 3769 3770 3771 3772 3773
        *ppv = &iface->lpVtbl;
    } else if (IsEqualIID(riid, &IID_IContextCallback))
    {
        *ppv = &iface->lpCallbackVtbl;
    }

    if (*ppv)
    {
        IUnknown_AddRef((IUnknown*)*ppv);
3774 3775 3776 3777 3778 3779 3780
        return S_OK;
    }

    FIXME("interface not implemented %s\n", debugstr_guid(riid));
    return E_NOINTERFACE;
}

3781
static ULONG Context_AddRef(Context *This)
3782 3783 3784 3785
{
    return InterlockedIncrement(&This->refs);
}

3786
static ULONG Context_Release(Context *This)
3787 3788 3789 3790 3791 3792 3793
{
    ULONG refs = InterlockedDecrement(&This->refs);
    if (!refs)
        HeapFree(GetProcessHeap(), 0, This);
    return refs;
}

3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812
static HRESULT WINAPI Context_CTI_QueryInterface(IComThreadingInfo *iface, REFIID riid, LPVOID *ppv)
{
    Context *This = impl_from_IComThreadingInfo(iface);
    return Context_QueryInterface(This, riid, ppv);
}

static ULONG WINAPI Context_CTI_AddRef(IComThreadingInfo *iface)
{
    Context *This = impl_from_IComThreadingInfo(iface);
    return Context_AddRef(This);
}

static ULONG WINAPI Context_CTI_Release(IComThreadingInfo *iface)
{
    Context *This = impl_from_IComThreadingInfo(iface);
    return Context_Release(This);
}

static HRESULT WINAPI Context_CTI_GetCurrentApartmentType(IComThreadingInfo *iface, APTTYPE *apttype)
3813
{
3814
    Context *This = impl_from_IComThreadingInfo(iface);
3815 3816 3817 3818 3819 3820 3821

    TRACE("(%p)\n", apttype);

    *apttype = This->apttype;
    return S_OK;
}

3822
static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3823
{
3824
    Context *This = impl_from_IComThreadingInfo(iface);
3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840

    TRACE("(%p)\n", thdtype);

    switch (This->apttype)
    {
    case APTTYPE_STA:
    case APTTYPE_MAINSTA:
        *thdtype = THDTYPE_PROCESSMESSAGES;
        break;
    default:
        *thdtype = THDTYPE_BLOCKMESSAGES;
        break;
    }
    return S_OK;
}

3841
static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3842 3843 3844 3845 3846
{
    FIXME("(%p): stub\n", logical_thread_id);
    return E_NOTIMPL;
}

3847
static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3848 3849 3850 3851 3852 3853 3854
{
    FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
    return E_NOTIMPL;
}

static const IComThreadingInfoVtbl Context_Threading_Vtbl =
{
3855 3856 3857 3858 3859 3860 3861
    Context_CTI_QueryInterface,
    Context_CTI_AddRef,
    Context_CTI_Release,
    Context_CTI_GetCurrentApartmentType,
    Context_CTI_GetCurrentThreadType,
    Context_CTI_GetCurrentLogicalThreadId,
    Context_CTI_SetCurrentLogicalThreadId
3862 3863
};

3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899
static HRESULT WINAPI Context_CC_QueryInterface(IContextCallback *iface, REFIID riid, LPVOID *ppv)
{
    Context *This = impl_from_IContextCallback(iface);
    return Context_QueryInterface(This, riid, ppv);
}

static ULONG WINAPI Context_CC_AddRef(IContextCallback *iface)
{
    Context *This = impl_from_IContextCallback(iface);
    return Context_AddRef(This);
}

static ULONG WINAPI Context_CC_Release(IContextCallback *iface)
{
    Context *This = impl_from_IContextCallback(iface);
    return Context_Release(This);
}

static HRESULT WINAPI Context_CC_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL pCallback,
                            ComCallData *param, REFIID riid, int method, IUnknown *punk)
{
    Context *This = impl_from_IContextCallback(iface);

    FIXME("(%p/%p)->(%p, %p, %s, %d, %p)\n", This, iface, pCallback, param, debugstr_guid(riid), method, punk);
    return E_NOTIMPL;
}

static const IContextCallbackVtbl Context_Callback_Vtbl =
{
    Context_CC_QueryInterface,
    Context_CC_AddRef,
    Context_CC_Release,
    Context_CC_ContextCallback
};


3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932
/***********************************************************************
 *           CoGetObjectContext [OLE32.@]
 *
 * Retrieves an object associated with the current context (i.e. apartment).
 *
 * PARAMS
 *  riid [I] ID of the interface of the object to retrieve.
 *  ppv  [O] Address where object will be stored on return.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 */
HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv)
{
    APARTMENT *apt = COM_CurrentApt();
    Context *context;
    HRESULT hr;

    TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);

    *ppv = NULL;
    if (!apt)
    {
        ERR("apartment not initialised\n");
        return CO_E_NOTINITIALIZED;
    }

    context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
    if (!context)
        return E_OUTOFMEMORY;

    context->lpVtbl = &Context_Threading_Vtbl;
3933
    context->lpCallbackVtbl = &Context_Callback_Vtbl;
3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947
    context->refs = 1;
    if (apt->multi_threaded)
        context->apttype = APTTYPE_MTA;
    else if (apt->main)
        context->apttype = APTTYPE_MAINSTA;
    else
        context->apttype = APTTYPE_STA;

    hr = IUnknown_QueryInterface((IUnknown *)&context->lpVtbl, riid, ppv);
    IUnknown_Release((IUnknown *)&context->lpVtbl);

    return hr;
}

3948 3949 3950 3951 3952 3953

/***********************************************************************
 *           CoGetContextToken [OLE32.@]
 */
HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
{
3954
    struct oletls *info = COM_CurrentInfo();
3955 3956
    static int calls;
    if(!(calls++)) FIXME( "stub\n" );
3957 3958 3959
    if (!info)
        return E_OUTOFMEMORY;
    if (token) *token = info->context_token;
3960 3961 3962 3963
    return E_NOTIMPL;
}


3964 3965 3966 3967 3968
/***********************************************************************
 *		DllMain (OLE32.@)
 */
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
{
3969
    TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
3970 3971 3972

    switch(fdwReason) {
    case DLL_PROCESS_ATTACH:
3973
        hProxyDll = hinstDLL;
3974 3975 3976 3977 3978 3979
        COMPOBJ_InitProcess();
	if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1);
	break;

    case DLL_PROCESS_DETACH:
        if (TRACE_ON(ole)) CoRevokeMallocSpy();
3980
        OLEDD_UnInitialize();
3981
        COMPOBJ_UninitProcess();
3982
        RPC_UnregisterAllChannelHooks();
3983
        COMPOBJ_DllList_Free();
3984 3985 3986 3987 3988 3989 3990 3991 3992 3993
	break;

    case DLL_THREAD_DETACH:
        COM_TlsDestroy();
        break;
    }
    return TRUE;
}

/* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */