compobj.c 120 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
#define USE_COM_CONTEXT_DEF
56 57 58
#include "objbase.h"
#include "ole2.h"
#include "ole2ver.h"
59
#include "ctxtcall.h"
60
#include "dde.h"
61

62
#include "initguid.h"
63
#include "compobj_private.h"
64
#include "moniker.h"
65

66
#include "wine/unicode.h"
67
#include "wine/debug.h"
68

69
WINE_DEFAULT_DEBUG_CHANNEL(ole);
70

71 72
#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))

73
/****************************************************************************
74
 * This section defines variables internal to the COM module.
75 76
 */

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

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

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

97 98 99 100 101
/*
 * 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
 */
102
static LONG s_COMLockCount = 0;
103 104
/* Reference count used by CoAddRefServerProcess/CoReleaseServerProcess */
static LONG s_COMServerProcessReferences = 0;
105 106 107 108 109 110 111

/*
 * 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
112
 *       means that parts of this will be exported to rpcss.
113 114 115
 */
typedef struct tagRegisteredClass
{
116
  struct list entry;
117
  CLSID     classIdentifier;
118
  OXID      apartment_id;
119 120 121 122
  LPUNKNOWN classObject;
  DWORD     runContext;
  DWORD     connectFlags;
  DWORD     dwCookie;
123
  LPSTREAM  pMarshaledData; /* FIXME: only really need to store OXID and IPID */
124
  void     *RpcRegistration;
125 126
} RegisteredClass;

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

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

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

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

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

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

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

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

181 182
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};
183

184 185 186
/*****************************************************************************
 * This section contains OpenDllList implementation
 */
187

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name)
{
    OpenDll *ptr;
    OpenDll *ret = NULL;
    EnterCriticalSection(&csOpenDllList);
    LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
    {
        if (!strcmpiW(library_name, ptr->library_name) &&
            (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */)
        {
            ret = ptr;
            break;
        }
    }
    LeaveCriticalSection(&csOpenDllList);
    return ret;
}
205

206 207
/* caller must ensure that library_name is not already in the open dll list */
static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret)
208
{
209 210 211 212 213 214
    OpenDll *entry;
    int len;
    HRESULT hr = S_OK;
    HANDLE hLibrary;
    DllCanUnloadNowFunc DllCanUnloadNow;
    DllGetClassObjectFunc DllGetClassObject;
215

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
    TRACE("\n");

    *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)
    {
        ERR("couldn't load in-process dll %s\n", debugstr_w(library_name));
        /* failure: DLL could not be loaded */
        return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
    }

    DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow");
    /* Note: failing to find DllCanUnloadNow is not a failure */
    DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject");
    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;
    }

    EnterCriticalSection( &csOpenDllList );

    *ret = COMPOBJ_DllList_Get(library_name);
    if (*ret)
    {
        /* another caller to this function already added the dll while we
         * weren't in the critical section */
        FreeLibrary(hLibrary);
    }
    else
    {
        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;
            entry->DllCanUnloadNow = DllCanUnloadNow;
            entry->DllGetClassObject = DllGetClassObject;
            list_add_tail(&openDllList, &entry->entry);
        }
        else
        {
            HeapFree(GetProcessHeap(), 0, entry);
            hr = E_OUTOFMEMORY;
            FreeLibrary(hLibrary);
        }
        *ret = entry;
    }

    LeaveCriticalSection( &csOpenDllList );

    return hr;
278 279
}

280 281 282
/* 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)
283
{
284 285 286 287 288 289 290 291 292 293 294 295
    if (!InterlockedDecrement(&entry->refs) && free_entry)
    {
        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);
    }
296 297
}

298 299
/* frees memory associated with active dll list */
static void COMPOBJ_DllList_Free(void)
300
{
301 302 303
    OpenDll *entry, *cursor2;
    EnterCriticalSection(&csOpenDllList);
    LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry)
304
    {
305 306 307 308
        list_remove(&entry->entry);

        HeapFree(GetProcessHeap(), 0, entry->library_name);
        HeapFree(GetProcessHeap(), 0, entry);
309
    }
310
    LeaveCriticalSection(&csOpenDllList);
311 312
}

313 314 315
/******************************************************************************
 * Manage apartments.
 */
316

317
static DWORD apartment_addref(struct apartment *apt)
318 319 320 321 322 323
{
    DWORD refs = InterlockedIncrement(&apt->refs);
    TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1);
    return refs;
}

324
/* allocates memory and fills in the necessary fields for a new apartment
325
 * object. must be called inside apartment cs */
326
static APARTMENT *apartment_construct(DWORD model)
327
{
328
    APARTMENT *apt;
329

330
    TRACE("creating new apartment, model=%d\n", model);
331

332 333
    apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt));
    apt->tid = GetCurrentThreadId();
334

335 336
    list_init(&apt->proxies);
    list_init(&apt->stubmgrs);
337
    list_init(&apt->psclsids);
338
    list_init(&apt->loaded_dlls);
339 340 341 342 343
    apt->ipidc = 0;
    apt->refs = 1;
    apt->remunk_exported = FALSE;
    apt->oidc = 1;
    InitializeCriticalSection(&apt->cs);
344
    DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment");
345

346
    apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
347

348
    if (apt->multi_threaded)
349 350
    {
        /* FIXME: should be randomly generated by in an RPC call to rpcss */
351
        apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
352 353 354 355
    }
    else
    {
        /* FIXME: should be randomly generated by in an RPC call to rpcss */
356
        apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
357
    }
358

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

361
    list_add_head(&apts, &apt->entry);
362

363 364
    return apt;
}
365

366 367 368
/* 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 */
369
static APARTMENT *apartment_get_or_create(DWORD model)
370 371
{
    APARTMENT *apt = COM_CurrentApt();
372

373 374
    if (!apt)
    {
375 376
        if (model & COINIT_APARTMENTTHREADED)
        {
377 378
            EnterCriticalSection(&csApartment);

379
            apt = apartment_construct(model);
380 381 382 383 384 385 386 387
            if (!MainApartment)
            {
                MainApartment = apt;
                apt->main = TRUE;
                TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
            }

            LeaveCriticalSection(&csApartment);
388 389 390

            if (apt->main)
                apartment_createwindowifneeded(apt);
391
        }
392 393
        else
        {
394 395 396 397 398 399 400 401
            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));
402
                apartment_addref(MTA);
403 404 405
            }
            else
                MTA = apartment_construct(model);
406

407
            apt = MTA;
408

409 410
            LeaveCriticalSection(&csApartment);
        }
411
        COM_CurrentInfo()->apt = apt;
412
    }
413

414 415 416
    return apt;
}

417
static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model)
418 419 420 421
{
    return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED));
}

422
static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
423
{
424
    list_remove(&curClass->entry);
425

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

429 430 431 432
    /*
     * Release the reference to the class object.
     */
    IUnknown_Release(curClass->classObject);
433

434
    if (curClass->pMarshaledData)
435
    {
436 437 438 439 440
        LARGE_INTEGER zero;
        memset(&zero, 0, sizeof(zero));
        IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
        CoReleaseMarshalData(curClass->pMarshaledData);
        IStream_Release(curClass->pMarshaledData);
441 442
    }

443 444
    HeapFree(GetProcessHeap(), 0, curClass);
}
445

446 447 448
static void COM_RevokeAllClasses(const struct apartment *apt)
{
  RegisteredClass *curClass, *cursor;
449

450
  EnterCriticalSection( &csRegisteredClassList );
451

452 453 454 455 456
  LIST_FOR_EACH_ENTRY_SAFE(curClass, cursor, &RegisteredClassList, RegisteredClass, entry)
  {
    if (curClass->apartment_id == apt->oxid)
      COM_RevokeRegisteredClassObject(curClass);
  }
457

458 459
  LeaveCriticalSection( &csRegisteredClassList );
}
460

461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
/***********************************************************************
 *           CoRevokeClassObject [OLE32.@]
 *
 * Removes a class object from the class registry.
 *
 * PARAMS
 *  dwRegister [I] Cookie returned from CoRegisterClassObject().
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
 * NOTES
 *  Must be called from the same apartment that called CoRegisterClassObject(),
 *  otherwise it will fail with RPC_E_WRONG_THREAD.
 *
 * SEE ALSO
 *  CoRegisterClassObject
 */
HRESULT WINAPI CoRevokeClassObject(
        DWORD dwRegister)
{
  HRESULT hr = E_INVALIDARG;
  RegisteredClass *curClass;
  APARTMENT *apt;
486

487
  TRACE("(%08x)\n",dwRegister);
488

489 490 491 492 493 494
  apt = COM_CurrentApt();
  if (!apt)
  {
    ERR("COM was not initialized\n");
    return CO_E_NOTINITIALIZED;
  }
495

496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 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 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
  EnterCriticalSection( &csRegisteredClassList );

  LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
  {
    /*
     * Check if we have a match on the cookie.
     */
    if (curClass->dwCookie == dwRegister)
    {
      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;
      }
      break;
    }
  }

  LeaveCriticalSection( &csRegisteredClassList );

  return hr;
}

/* frees unused libraries loaded by apartment_getclassobject by calling the
 * DLL's DllCanUnloadNow entry point */
static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
{
    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))
        {
            DWORD real_delay = delay;

            if (real_delay == INFINITE)
            {
                /* 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 */
                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())))
            {
                list_remove(&entry->entry);
                COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE);
                HeapFree(GetProcessHeap(), 0, entry);
            }
            else
                entry->unload_time = GetTickCount() + real_delay;
        }
        else if (entry->unload_time)
            entry->unload_time = 0;
    }
    LeaveCriticalSection(&apt->cs);
}

DWORD apartment_release(struct apartment *apt)
{
    DWORD ret;

    EnterCriticalSection(&csApartment);

    ret = InterlockedDecrement(&apt->refs);
    TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret);
    /* destruction stuff that needs to happen under csApartment CS */
    if (ret == 0)
    {
        if (apt == MTA) MTA = NULL;
        else if (apt == MainApartment) MainApartment = NULL;
        list_remove(&apt->entry);
    }

    LeaveCriticalSection(&csApartment);

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

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

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

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

        apartment_disconnectproxies(apt);

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

        LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs)
        {
            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);
        }

        LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
        {
            struct registered_psclsid *registered_psclsid =
                LIST_ENTRY(cursor, struct registered_psclsid, entry);
614 615

            list_remove(&registered_psclsid->entry);
616
            HeapFree(GetProcessHeap(), 0, registered_psclsid);
617 618
        }

619 620 621 622 623
        /* 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));

624 625
        if (apt->filter) IUnknown_Release(apt->filter);

626
        /* free as many unused libraries as possible... */
627
        apartment_freeunusedlibraries(apt, 0);
628 629 630 631

        /* ... and free the memory for the apartment loaded dll entry and
         * release the dll list reference without freeing the library for the
         * rest */
632 633 634
        while ((cursor = list_head(&apt->loaded_dlls)))
        {
            struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry);
635
            COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE);
636 637 638 639
            list_remove(cursor);
            HeapFree(GetProcessHeap(), 0, apartment_loaded_dll);
        }

640
        DEBUG_CLEAR_CRITSEC_NAME(&apt->cs);
641
        DeleteCriticalSection(&apt->cs);
642

643
        HeapFree(GetProcessHeap(), 0, apt);
644 645
    }

646 647 648
    return ret;
}

649
/* The given OXID must be local to this process: 
650 651 652 653
 *
 * The ref parameter is here mostly to ensure people remember that
 * they get one, you should normally take a ref for thread safety.
 */
654
APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref)
655
{
656 657
    APARTMENT *result = NULL;
    struct list *cursor;
658 659

    EnterCriticalSection(&csApartment);
660 661 662 663 664 665
    LIST_FOR_EACH( cursor, &apts )
    {
        struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
        if (apt->oxid == oxid)
        {
            result = apt;
666
            if (ref) apartment_addref(result);
667 668 669
            break;
        }
    }
670
    LeaveCriticalSection(&csApartment);
671

672
    return result;
673 674
}

675 676 677
/* 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. */
678
APARTMENT *apartment_findfromtid(DWORD tid)
679 680 681 682 683 684 685 686 687 688 689
{
    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;
690
            apartment_addref(result);
691 692 693 694 695 696 697 698
            break;
        }
    }
    LeaveCriticalSection(&csApartment);

    return result;
}

699
/* gets the main apartment if it exists. The caller must
700 701
 * release the reference from the apartment as soon as the apartment pointer
 * is no longer required. */
702
static APARTMENT *apartment_findmain(void)
703
{
704
    APARTMENT *result;
705 706

    EnterCriticalSection(&csApartment);
707

708 709
    result = MainApartment;
    if (result) apartment_addref(result);
710

711 712 713 714 715
    LeaveCriticalSection(&csApartment);

    return result;
}

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
/* gets the multi-threaded apartment if it exists. The caller must
 * release the reference from the apartment as soon as the apartment pointer
 * is no longer required. */
static APARTMENT *apartment_find_multi_threaded(void)
{
    APARTMENT *result = NULL;
    struct list *cursor;

    EnterCriticalSection(&csApartment);

    LIST_FOR_EACH( cursor, &apts )
    {
        struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
        if (apt->multi_threaded)
        {
            result = apt;
            apartment_addref(result);
            break;
        }
    }

    LeaveCriticalSection(&csApartment);
    return result;
}

741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
/* gets the specified class object by loading the appropriate DLL, if
 * necessary and calls the DllGetClassObject function for the DLL */
static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
                                        BOOL apartment_threaded,
                                        REFCLSID rclsid, REFIID riid, void **ppv)
{
    static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
    HRESULT hr = S_OK;
    BOOL found = FALSE;
    struct apartment_loaded_dll *apartment_loaded_dll;

    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;
    }

    EnterCriticalSection(&apt->cs);

    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))
        {
            apartment_loaded_dll->unload_time = 0;
            apartment_loaded_dll->multi_threaded = FALSE;
            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))
    {
        /* one component being multi-threaded overrides any number of
         * apartment-threaded components */
        if (!apartment_threaded)
            apartment_loaded_dll->multi_threaded = TRUE;

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

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

    return hr;
}

/***********************************************************************
 *	COM_RegReadPath	[internal]
 *
 *	Reads a registry value and expands it when necessary
 */
static DWORD COM_RegReadPath(HKEY hkeyroot, const WCHAR *keyname, const WCHAR *valuename, WCHAR * dst, DWORD dstlen)
{
	DWORD ret;
	HKEY key;
	DWORD keytype;
	WCHAR src[MAX_PATH];
	DWORD dwLength = dstlen * sizeof(WCHAR);

	if((ret = RegOpenKeyExW(hkeyroot, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) {
          if( (ret = RegQueryValueExW(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) {
            if (keytype == REG_EXPAND_SZ) {
              if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA;
            } else {
833 834 835 836 837 838 839 840 841 842
              const WCHAR *quote_start;
              quote_start = strchrW(src, '\"');
              if (quote_start) {
                const WCHAR *quote_end = strchrW(quote_start + 1, '\"');
                if (quote_end) {
                  memmove(src, quote_start + 1,
                          (quote_end - quote_start - 1) * sizeof(WCHAR));
                  src[quote_end - quote_start - 1] = '\0';
                }
              }
843 844 845 846 847 848 849 850
              lstrcpynW(dst, src, dstlen);
            }
	  }
          RegCloseKey (key);
	}
	return ret;
}

851 852 853 854 855
struct host_object_params
{
    HKEY hkeydll;
    CLSID clsid; /* clsid of object to marshal */
    IID iid; /* interface to marshal */
856 857
    HANDLE event; /* event signalling when ready for multi-threaded case */
    HRESULT hr; /* result for multi-threaded case */
858
    IStream *stream; /* stream that the object will be marshaled into */
859
    BOOL apartment_threaded; /* is the component purely apartment-threaded? */
860 861
};

862 863
static HRESULT apartment_hostobject(struct apartment *apt,
                                    const struct host_object_params *params)
864 865 866 867
{
    IUnknown *object;
    HRESULT hr;
    static const LARGE_INTEGER llZero;
868
    WCHAR dllpath[MAX_PATH+1];
869

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

872 873 874 875 876 877 878
    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;
    }

879 880
    hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded,
                                  &params->clsid, &params->iid, (void **)&object);
881 882 883 884 885 886 887 888 889 890 891
    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;
}

892
static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
893
{
894 895 896
    switch (msg)
    {
    case DM_EXECUTERPC:
897 898
        RPC_ExecuteCall((struct dispatch_params *)lParam);
        return 0;
899
    case DM_HOSTOBJECT:
900
        return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam);
901 902 903
    default:
        return DefWindowProcW(hWnd, msg, wParam, lParam);
    }
904
}
905

906 907 908 909 910 911 912
struct host_thread_params
{
    COINIT threading_model;
    HANDLE ready_event;
    HWND apartment_hwnd;
};

913 914
/* thread for hosting an object to allow an object to appear to be created in
 * an apartment with an incompatible threading model */
915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
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))
        {
946 947 948
            struct host_object_params *obj_params = (struct host_object_params *)msg.lParam;
            obj_params->hr = apartment_hostobject(apt, obj_params);
            SetEvent(obj_params->event);
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }

    TRACE("exiting\n");

    CoUninitialize();

    return S_OK;
}

964 965 966 967 968 969
/* 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)
970 971 972 973 974 975 976 977
{
    struct host_object_params params;
    HWND apartment_hwnd = NULL;
    DWORD apartment_tid = 0;
    HRESULT hr;

    if (!multi_threaded && main_apartment)
    {
978
        APARTMENT *host_apt = apartment_findmain();
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
        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)
    {
1031
        APARTMENT *host_apt = apartment_findmain();
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
        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;
1045
    params.apartment_threaded = !multi_threaded;
1046 1047 1048 1049 1050 1051 1052
    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
1053 1054 1055 1056 1057
        {
            WaitForSingleObject(params.event, INFINITE);
            hr = params.hr;
        }
        CloseHandle(params.event);
1058 1059
    }
    else
1060
    {
1061
        if (!apartment_hwnd)
1062
        {
1063
            ERR("host apartment didn't create window\n");
1064
            hr = E_OUTOFMEMORY;
1065
        }
1066 1067
        else
            hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
1068
    }
1069 1070 1071
    if (SUCCEEDED(hr))
        hr = CoUnmarshalInterface(params.stream, riid, ppv);
    IStream_Release(params.stream);
1072 1073 1074
    return hr;
}

1075 1076 1077
/* create a window for the apartment or return the current one if one has
 * already been created */
HRESULT apartment_createwindowifneeded(struct apartment *apt)
1078
{
1079 1080 1081 1082
    if (apt->multi_threaded)
        return S_OK;

    if (!apt->win)
1083
    {
1084 1085 1086 1087
        HWND hwnd = CreateWindowW(wszAptWinClass, NULL, 0,
                                  0, 0, 0, 0,
                                  HWND_MESSAGE, 0, hProxyDll, NULL);
        if (!hwnd)
1088
        {
1089 1090
            ERR("CreateWindow failed with error %d\n", GetLastError());
            return HRESULT_FROM_WIN32(GetLastError());
1091
        }
1092 1093 1094
        if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL))
            /* someone beat us to it */
            DestroyWindow(hwnd);
1095
    }
1096 1097

    return S_OK;
1098 1099
}

1100 1101
/* retrieves the window for the main- or apartment-threaded apartment */
HWND apartment_getwindow(const struct apartment *apt)
1102
{
1103 1104 1105
    assert(!apt->multi_threaded);
    return apt->win;
}
1106

1107 1108 1109 1110 1111
void apartment_joinmta(void)
{
    apartment_addref(MTA);
    COM_CurrentInfo()->apt = MTA;
}
1112

1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
static void COMPOBJ_InitProcess( void )
{
    WNDCLASSW wclass;

    /* 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
     * following class is created. The *caller* of CoMarshalInterface (i.e., the
     * application) is responsible for pumping the message loop in that thread.
     * The WM_USER messages which point to the RPCs are then dispatched to
     * apartment_wndproc by the user's code from the apartment in which the
     * interface was unmarshalled.
     */
    memset(&wclass, 0, sizeof(wclass));
    wclass.lpfnWndProc = apartment_wndproc;
    wclass.hInstance = hProxyDll;
    wclass.lpszClassName = wszAptWinClass;
    RegisterClassW(&wclass);
1131 1132
}

1133
static void COMPOBJ_UninitProcess( void )
1134
{
1135 1136
    UnregisterClassW(wszAptWinClass, hProxyDll);
}
1137

1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
static void COM_TlsDestroy(void)
{
    struct oletls *info = NtCurrentTeb()->ReservedForOle;
    if (info)
    {
        if (info->apt) apartment_release(info->apt);
        if (info->errorinfo) IErrorInfo_Release(info->errorinfo);
        if (info->state) IUnknown_Release(info->state);
        if (info->spy) IUnknown_Release(info->spy);
        if (info->context_token) IObjContext_Release(info->context_token);
        HeapFree(GetProcessHeap(), 0, info);
        NtCurrentTeb()->ReservedForOle = NULL;
1150 1151 1152
    }
}

1153
/******************************************************************************
1154
 *           CoBuildVersion [OLE32.@]
1155 1156 1157 1158
 *
 * Gets the build version of the DLL.
 *
 * PARAMS
1159 1160 1161
 *
 * RETURNS
 *	Current build version, hiword is majornumber, loword is minornumber
Alexandre Julliard's avatar
Alexandre Julliard committed
1162
 */
1163 1164 1165 1166
DWORD WINAPI CoBuildVersion(void)
{
    TRACE("Returning version %d, build %d.\n", rmm, rup);
    return (rmm<<16)+rup;
Alexandre Julliard's avatar
Alexandre Julliard committed
1167 1168
}

1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
/******************************************************************************
 *              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;
}

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
/******************************************************************************
 *              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
 */
1229 1230 1231 1232 1233 1234 1235 1236 1237
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);
1238
    info->spy = NULL;
1239 1240 1241 1242
    return S_OK;
}


1243
/******************************************************************************
1244
 *		CoInitialize	[OLE32.@]
1245
 *
1246 1247
 * Initializes the COM libraries by calling CoInitializeEx with
 * COINIT_APARTMENTTHREADED, ie it enters a STA thread.
1248
 *
1249 1250 1251 1252 1253 1254 1255
 * 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.
 *
1256 1257
 * SEE ALSO
 *   CoInitializeEx
Alexandre Julliard's avatar
Alexandre Julliard committed
1258
 */
1259
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
1260 1261 1262 1263
{
  /*
   * Just delegate to the newer method.
   */
1264
  return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
Alexandre Julliard's avatar
Alexandre Julliard committed
1265 1266
}

1267
/******************************************************************************
1268
 *		CoInitializeEx	[OLE32.@]
1269
 *
1270
 * Initializes the COM libraries.
1271
 *
1272 1273 1274
 * PARAMS
 *  lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL).
 *  dwCoInit   [I] One or more flags from the COINIT enumeration. See notes.
1275 1276
 *
 * RETURNS
1277 1278
 *  S_OK               if successful,
 *  S_FALSE            if this function was called already.
1279 1280
 *  RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another
 *                     threading model.
1281
 *
1282 1283 1284 1285
 * NOTES
 *
 * The behavior used to set the IMalloc used for memory management is
 * obsolete.
1286
 * The dwCoInit parameter must specify one of the following apartment
1287 1288 1289 1290 1291 1292 1293
 * 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.
 *
1294 1295
 * SEE ALSO
 *   CoUninitialize
1296
 */
1297
HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit)
1298
{
1299
  struct oletls *info = COM_CurrentInfo();
1300 1301
  HRESULT hr = S_OK;
  APARTMENT *apt;
1302

1303
  TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit);
1304 1305 1306

  if (lpReserved!=NULL)
  {
1307
    ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
1308 1309 1310 1311 1312
  }

  /*
   * Check the lock count. If this is the first time going through the initialize
   * process, we have to initialize the libraries.
1313 1314
   *
   * And crank-up that lock count.
1315
   */
1316
  if (InterlockedExchangeAdd(&s_COMLockCount,1)==0)
1317 1318 1319 1320
  {
    /*
     * Initialize the various COM libraries and data structures.
     */
1321
    TRACE("() - Initializing the COM libraries\n");
1322

1323
    /* we may need to defer this until after apartment initialisation */
Noomen Hamza's avatar
Noomen Hamza committed
1324
    RunningObjectTableImpl_Initialize();
1325
  }
1326

1327 1328 1329 1330
  if (info->spy)
      IInitializeSpy_PreInitialize(info->spy, dwCoInit, info->inits);

  if (!(apt = info->apt))
1331
  {
1332
    apt = apartment_get_or_create(dwCoInit);
1333
    if (!apt) return E_OUTOFMEMORY;
1334
  }
1335
  else if (!apartment_is_model(apt, dwCoInit))
1336 1337 1338
  {
    /* 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. */
1339 1340 1341
    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");
1342 1343
    return RPC_E_CHANGED_MODE;
  }
1344 1345
  else
    hr = S_FALSE;
1346

1347 1348 1349 1350
  info->inits++;

  if (info->spy)
      IInitializeSpy_PostInitialize(info->spy, hr, dwCoInit, info->inits);
1351 1352

  return hr;
1353 1354
}

1355
/***********************************************************************
1356
 *           CoUninitialize   [OLE32.@]
1357
 *
1358 1359 1360 1361
 * 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.
1362
 *
1363 1364 1365 1366
 * PARAMS
 *
 * RETURNS
 *  Nothing.
1367 1368 1369
 *
 * SEE ALSO
 *   CoInitializeEx
1370
 */
1371
void WINAPI CoUninitialize(void)
1372
{
1373
  struct oletls * info = COM_CurrentInfo();
1374
  LONG lCOMRefCnt;
1375

1376
  TRACE("()\n");
1377

1378 1379 1380
  /* will only happen on OOM */
  if (!info) return;

1381 1382 1383
  if (info->spy)
      IInitializeSpy_PreUninitialize(info->spy, info->inits);

1384 1385 1386 1387
  /* sanity check */
  if (!info->inits)
  {
    ERR("Mismatched CoUninitialize\n");
1388 1389 1390

    if (info->spy)
        IInitializeSpy_PostUninitialize(info->spy, info->inits);
1391 1392 1393 1394 1395
    return;
  }

  if (!--info->inits)
  {
1396
    apartment_release(info->apt);
1397 1398
    info->apt = NULL;
  }
1399

1400 1401 1402 1403 1404
  /*
   * Decrease the reference count.
   * If we are back to 0 locks on the COM library, make sure we free
   * all the associated data structures.
   */
1405 1406
  lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1);
  if (lCOMRefCnt==1)
1407
  {
1408
    TRACE("() - Releasing the COM libraries\n");
1409

Noomen Hamza's avatar
Noomen Hamza committed
1410
    RunningObjectTableImpl_UnInitialize();
1411 1412 1413 1414 1415
  }
  else if (lCOMRefCnt<1) {
    ERR( "CoUninitialize() - not CoInitialized.\n" );
    InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */
  }
1416 1417
  if (info->spy)
      IInitializeSpy_PostUninitialize(info->spy, info->inits);
1418
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1419

1420
/******************************************************************************
1421
 *		CoDisconnectObject	[OLE32.@]
1422 1423
 *
 * Disconnects all connections to this object from remote processes. Dispatches
1424
 * pending RPCs while blocking new RPCs from occurring, and then calls
1425 1426 1427 1428
 * IMarshal::DisconnectObject on the given object.
 *
 * Typically called when the object server is forced to shut down, for instance by
 * the user.
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
 *
 * 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
1440
 */
1441
HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
Alexandre Julliard's avatar
Alexandre Julliard committed
1442
{
1443 1444 1445 1446
    HRESULT hr;
    IMarshal *marshal;
    APARTMENT *apt;

1447
    TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460

    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;

1461
    apartment_disconnectobject(apt, lpUnk);
1462 1463 1464 1465 1466 1467

    /* 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
1468
    return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1469 1470
}

1471
/******************************************************************************
1472
 *		CoCreateGuid [OLE32.@]
1473
 *
1474 1475
 * Simply forwards to UuidCreate in RPCRT4.
 *
1476 1477 1478 1479 1480 1481 1482
 * PARAMS
 *  pguid [O] Points to the GUID to initialize.
 *
 * RETURNS
 *  Success: S_OK.
 *  Failure: HRESULT code.
 *
1483 1484
 * SEE ALSO
 *   UuidCreate
Alexandre Julliard's avatar
Alexandre Julliard committed
1485
 */
1486 1487
HRESULT WINAPI CoCreateGuid(GUID *pguid)
{
1488 1489 1490
    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
1491
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1492

1493
/******************************************************************************
1494 1495
 *		CLSIDFromString	[OLE32.@]
 *		IIDFromString   [OLE32.@]
1496
 *
1497
 * Converts a unique identifier from its string representation into
Alexandre Julliard's avatar
Alexandre Julliard committed
1498
 * the GUID struct.
1499
 *
1500 1501 1502
 * PARAMS
 *  idstr [I] The string representation of the GUID.
 *  id    [O] GUID converted from the string.
1503
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1504
 * RETURNS
1505 1506
 *   S_OK on success
 *   CO_E_CLASSSTRING if idstr is not a valid CLSID
1507 1508 1509
 *
 * SEE ALSO
 *  StringFromCLSID
Alexandre Julliard's avatar
Alexandre Julliard committed
1510
 */
1511
static HRESULT __CLSIDFromString(LPCWSTR s, LPCLSID id)
1512
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1513 1514 1515
  int	i;
  BYTE table[256];

1516
  if (!s) {
1517 1518 1519
    memset( id, 0, sizeof (CLSID) );
    return S_OK;
  }
1520

1521
  /* validate the CLSID string */
1522
  if (strlenW(s) != 38)
1523
    return CO_E_CLASSSTRING;
1524

1525 1526
  if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}'))
    return CO_E_CLASSSTRING;
1527

1528 1529 1530 1531 1532 1533
  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;
1534
  }
1535

1536
  TRACE("%s -> %p\n", debugstr_w(s), id);
Alexandre Julliard's avatar
Alexandre Julliard committed
1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550

  /* 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} */

1551 1552 1553 1554
  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
1555 1556

  /* these are just sequential bytes */
1557 1558 1559 1560 1561 1562 1563 1564
  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
1565

Alexandre Julliard's avatar
Alexandre Julliard committed
1566 1567 1568
  return S_OK;
}

1569 1570
/*****************************************************************************/

1571
HRESULT WINAPI CLSIDFromString(LPCOLESTR idstr, LPCLSID id )
1572 1573
{
    HRESULT ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1574

1575 1576 1577
    if (!id)
        return E_INVALIDARG;

1578
    ret = __CLSIDFromString(idstr, id);
1579 1580 1581
    if(ret != S_OK) { /* It appears a ProgID is also valid */
        ret = CLSIDFromProgID(idstr, id);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1582
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1583 1584
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1585

1586
/******************************************************************************
1587 1588
 *		StringFromCLSID	[OLE32.@]
 *		StringFromIID   [OLE32.@]
1589
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1590 1591
 * Converts a GUID into the respective string representation.
 * The target string is allocated using the OLE IMalloc.
1592
 *
1593 1594 1595 1596
 * 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
1597
 * RETURNS
1598 1599
 *   S_OK
 *   E_FAIL
1600 1601 1602
 *
 * SEE ALSO
 *  StringFromGUID2, CLSIDFromString
Alexandre Julliard's avatar
Alexandre Julliard committed
1603
 */
1604 1605
HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr)
{
1606 1607 1608 1609 1610 1611 1612
    HRESULT ret;
    LPMALLOC mllc;

    if ((ret = CoGetMalloc(0,&mllc))) return ret;
    if (!(*idstr = IMalloc_Alloc( mllc, CHARS_IN_GUID * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
    StringFromGUID2( id, *idstr, CHARS_IN_GUID );
    return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
1613 1614
}

1615
/******************************************************************************
1616
 *		StringFromGUID2	[OLE32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
1617
 *
1618 1619
 * Modified version of StringFromCLSID that allows you to specify max
 * buffer size.
Alexandre Julliard's avatar
Alexandre Julliard committed
1620
 *
1621 1622 1623 1624 1625
 * 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
1626
 * RETURNS
1627 1628
 *	Success: The length of the resulting string in characters.
 *  Failure: 0.
Alexandre Julliard's avatar
Alexandre Julliard committed
1629
 */
1630
INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1631
{
1632 1633 1634 1635
    static const WCHAR formatW[] = { '{','%','0','8','X','-','%','0','4','X','-',
                                     '%','0','4','X','-','%','0','2','X','%','0','2','X','-',
                                     '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
                                     '%','0','2','X','%','0','2','X','}',0 };
1636
    if (!id || cmax < CHARS_IN_GUID) return 0;
1637 1638 1639 1640
    sprintfW( str, formatW, id->Data1, id->Data2, id->Data3,
              id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3],
              id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7] );
    return CHARS_IN_GUID;
Alexandre Julliard's avatar
Alexandre Julliard committed
1641
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1642

1643 1644
/* open HKCR\\CLSID\\{string form of clsid}\\{keyname} key */
HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY *subkey)
1645 1646 1647
{
    static const WCHAR wszCLSIDSlash[] = {'C','L','S','I','D','\\',0};
    WCHAR path[CHARS_IN_GUID + ARRAYSIZE(wszCLSIDSlash) - 1];
1648 1649 1650
    LONG res;
    HKEY key;

1651 1652
    strcpyW(path, wszCLSIDSlash);
    StringFromGUID2(clsid, path + strlenW(wszCLSIDSlash), CHARS_IN_GUID);
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
    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);
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688
    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 */
1689
    hr = COM_OpenKeyForCLSID(clsid, NULL, KEY_READ, &hkey);
1690 1691 1692 1693
    if (FAILED(hr))
        return hr;

    size = sizeof(buf);
1694
    res = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &size);
1695 1696 1697 1698 1699 1700 1701 1702 1703
    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);
1704 1705 1706 1707 1708 1709
    if (res == ERROR_FILE_NOT_FOUND)
        return REGDB_E_KEYMISSING;
    else if (res != ERROR_SUCCESS)
        return REGDB_E_READREGDB;

    return S_OK;
1710 1711
}

1712
/******************************************************************************
1713 1714
 *               ProgIDFromCLSID [OLE32.@]
 *
1715 1716 1717 1718
 * Converts a class id into the respective program ID.
 *
 * PARAMS
 *  clsid        [I] Class ID, as found in registry.
1719
 *  ppszProgID [O] Associated ProgID.
1720 1721 1722 1723 1724
 *
 * RETURNS
 *   S_OK
 *   E_OUTOFMEMORY
 *   REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID
1725
 */
1726
HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *ppszProgID)
1727
{
1728 1729 1730
    static const WCHAR wszProgID[] = {'P','r','o','g','I','D',0};
    HKEY     hkey;
    HRESULT  ret;
1731
    LONG progidlen = 0;
1732

1733 1734 1735 1736 1737 1738 1739
    if (!ppszProgID)
    {
        ERR("ppszProgId isn't optional\n");
        return E_INVALIDARG;
    }

    *ppszProgID = NULL;
1740 1741 1742 1743
    ret = COM_OpenKeyForCLSID(clsid, wszProgID, KEY_READ, &hkey);
    if (FAILED(ret))
        return ret;

1744
    if (RegQueryValueW(hkey, NULL, NULL, &progidlen))
1745 1746 1747 1748
      ret = REGDB_E_CLASSNOTREG;

    if (ret == S_OK)
    {
1749 1750
      *ppszProgID = CoTaskMemAlloc(progidlen * sizeof(WCHAR));
      if (*ppszProgID)
1751
      {
1752
        if (RegQueryValueW(hkey, NULL, *ppszProgID, &progidlen))
1753
          ret = REGDB_E_CLASSNOTREG;
1754
      }
1755 1756
      else
        ret = E_OUTOFMEMORY;
1757 1758
    }

1759 1760
    RegCloseKey(hkey);
    return ret;
1761 1762
}

1763
/******************************************************************************
1764
 *		CLSIDFromProgID	[OLE32.@]
1765
 *
1766 1767 1768 1769
 * Converts a program id into the respective GUID.
 *
 * PARAMS
 *  progid [I] Unicode program ID, as found in registry.
1770
 *  clsid  [O] Associated CLSID.
1771
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1772
 * RETURNS
1773 1774
 *	Success: S_OK
 *  Failure: CO_E_CLASSSTRING - the given ProgID cannot be found.
Alexandre Julliard's avatar
Alexandre Julliard committed
1775
 */
1776
HRESULT WINAPI CLSIDFromProgID(LPCOLESTR progid, LPCLSID clsid)
1777 1778
{
    static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 };
1779
    WCHAR buf2[CHARS_IN_GUID];
1780
    LONG buf2len = sizeof(buf2);
1781
    HKEY xhkey;
1782
    WCHAR *buf;
1783

1784 1785 1786 1787 1788 1789 1790 1791 1792 1793
    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) );
1794 1795 1796 1797 1798
    strcpyW( buf, progid );
    strcatW( buf, clsidW );
    if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey))
    {
        HeapFree(GetProcessHeap(),0,buf);
1799
        WARN("couldn't open key for ProgID %s\n", debugstr_w(progid));
1800 1801 1802
        return CO_E_CLASSSTRING;
    }
    HeapFree(GetProcessHeap(),0,buf);
Alexandre Julliard's avatar
Alexandre Julliard committed
1803

1804
    if (RegQueryValueW(xhkey,NULL,buf2,&buf2len))
1805 1806
    {
        RegCloseKey(xhkey);
1807
        WARN("couldn't query clsid value for ProgID %s\n", debugstr_w(progid));
1808 1809 1810
        return CO_E_CLASSSTRING;
    }
    RegCloseKey(xhkey);
1811
    return __CLSIDFromString(buf2,clsid);
Alexandre Julliard's avatar
Alexandre Julliard committed
1812 1813
}

1814 1815

/*****************************************************************************
1816
 *             CoGetPSClsid [OLE32.@]
1817
 *
Robert Shearman's avatar
Robert Shearman committed
1818 1819
 * Retrieves the CLSID of the proxy/stub factory that implements
 * IPSFactoryBuffer for the specified interface.
1820
 *
1821 1822 1823 1824 1825 1826 1827
 * 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
1828
 *   REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed
1829 1830 1831
 *
 * NOTES
 *
1832 1833 1834 1835
 * 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.
1836 1837
 *
 * CoGetPSClsid determines this CLSID by searching the
1838 1839 1840
 * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32
 * in the registry and any interface id registered by
 * CoRegisterPSClsid within the current process.
1841
 *
1842
 * BUGS
1843
 *
1844
 * Native returns S_OK for interfaces with a key in HKCR\Interface, but
Robert Shearman's avatar
Robert Shearman committed
1845 1846
 * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be
 * considered a bug in native unless an application depends on this (unlikely).
1847 1848 1849
 *
 * SEE ALSO
 *  CoRegisterPSClsid.
1850
 */
1851
HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
1852
{
1853 1854 1855 1856
    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];
1857
    LONG len;
1858
    HKEY hkey;
1859 1860
    APARTMENT *apt = COM_CurrentApt();
    struct registered_psclsid *registered_psclsid;
1861 1862 1863

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

1864 1865 1866 1867 1868 1869
    if (!apt)
    {
        ERR("apartment not initialised\n");
        return CO_E_NOTINITIALIZED;
    }

1870 1871 1872 1873 1874 1875
    if (!pclsid)
    {
        ERR("pclsid isn't optional\n");
        return E_INVALIDARG;
    }

1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887
    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);

1888 1889 1890 1891
    /* 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);
1892 1893

    /* Open the key.. */
1894
    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &hkey))
1895
    {
Robert Shearman's avatar
Robert Shearman committed
1896 1897
        WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid));
        return REGDB_E_IIDNOTREG;
1898 1899 1900
    }

    /* ... Once we have the key, query the registry to get the
1901
       value of CLSID as a string, and convert it into a
1902
       proper CLSID structure to be passed back to the app */
1903 1904
    len = sizeof(value);
    if (ERROR_SUCCESS != RegQueryValueW(hkey, NULL, value, &len))
1905
    {
1906
        RegCloseKey(hkey);
Robert Shearman's avatar
Robert Shearman committed
1907
        return REGDB_E_IIDNOTREG;
1908
    }
1909
    RegCloseKey(hkey);
1910

Austin English's avatar
Austin English committed
1911 1912
    /* We have the CLSID we want back from the registry as a string, so
       let's convert it into a CLSID structure */
1913
    if (CLSIDFromString(value, pclsid) != NOERROR)
Robert Shearman's avatar
Robert Shearman committed
1914
        return REGDB_E_IIDNOTREG;
1915 1916

    TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid));
Robert Shearman's avatar
Robert Shearman committed
1917
    return S_OK;
1918 1919
}

1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
/*****************************************************************************
 *             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;
}

1981

1982 1983 1984
/***
 * COM_GetRegisteredClassObject
 *
1985
 * This internal method is used to scan the registered class list to
1986 1987
 * find a class object.
 *
1988
 * Params:
1989 1990 1991 1992 1993 1994
 *   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.
 */
1995 1996
static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
                                            DWORD dwClsContext, LPUNKNOWN* ppUnk)
1997
{
1998
  HRESULT hr = S_FALSE;
1999
  RegisteredClass *curClass;
2000

2001
  EnterCriticalSection( &csRegisteredClassList );
2002

2003
  LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
2004 2005
  {
    /*
2006
     * Check if we have a match on the class ID and context.
2007
     */
2008 2009
    if ((apt->oxid == curClass->apartment_id) &&
        (dwClsContext & curClass->runContext) &&
2010
        IsEqualGUID(&(curClass->classIdentifier), rclsid))
2011 2012 2013 2014 2015 2016 2017 2018
    {
      /*
       * We have a match, return the pointer to the class object.
       */
      *ppUnk = curClass->classObject;

      IUnknown_AddRef(curClass->classObject);

2019
      hr = S_OK;
2020
      break;
2021 2022 2023
    }
  }

2024
  LeaveCriticalSection( &csRegisteredClassList );
2025

2026
  return hr;
2027 2028
}

2029
/******************************************************************************
2030
 *		CoRegisterClassObject	[OLE32.@]
2031
 *
2032 2033 2034
 * 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.
2035
 *
2036 2037 2038 2039 2040 2041 2042
 * 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.
 *
2043
 * RETURNS
2044 2045
 *   S_OK on success,
 *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
2046 2047 2048 2049
 *   CO_E_OBJISREG if the object is already registered. We should not return this.
 *
 * SEE ALSO
 *   CoRevokeClassObject, CoGetClassObject
2050
 *
2051 2052 2053 2054 2055
 * NOTES
 *  In-process objects are only registered for the current apartment.
 *  CoGetClassObject() and CoCreateInstance() will not return objects registered
 *  in other apartments.
 *
2056 2057 2058
 * 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
2059
 */
2060
HRESULT WINAPI CoRegisterClassObject(
2061 2062 2063 2064 2065
    REFCLSID rclsid,
    LPUNKNOWN pUnk,
    DWORD dwClsContext,
    DWORD flags,
    LPDWORD lpdwRegister)
2066
{
2067
  static LONG next_cookie;
2068 2069 2070
  RegisteredClass* newClass;
  LPUNKNOWN        foundObject;
  HRESULT          hr;
2071
  APARTMENT *apt;
Alexandre Julliard's avatar
Alexandre Julliard committed
2072

2073
  TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
2074
	debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);
2075 2076 2077 2078

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

2079 2080
  apt = COM_CurrentApt();
  if (!apt)
2081 2082 2083 2084 2085
  {
      ERR("COM was not initialized\n");
      return CO_E_NOTINITIALIZED;
  }

2086 2087
  *lpdwRegister = 0;

2088 2089 2090 2091 2092
  /* 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;

2093 2094 2095 2096
  /*
   * First, check if the class is already registered.
   * If it is, this should cause an error.
   */
2097
  hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
2098
  if (hr == S_OK) {
2099 2100 2101 2102 2103 2104
    if (flags & REGCLS_MULTIPLEUSE) {
      if (dwClsContext & CLSCTX_LOCAL_SERVER)
        hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
      IUnknown_Release(foundObject);
      return hr;
    }
2105
    IUnknown_Release(foundObject);
2106
    ERR("object already registered for class %s\n", debugstr_guid(rclsid));
2107 2108
    return CO_E_OBJISREG;
  }
2109

2110
  newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
2111 2112
  if ( newClass == NULL )
    return E_OUTOFMEMORY;
2113 2114

  newClass->classIdentifier = *rclsid;
2115
  newClass->apartment_id    = apt->oxid;
2116 2117
  newClass->runContext      = dwClsContext;
  newClass->connectFlags    = flags;
2118
  newClass->pMarshaledData  = NULL;
2119
  newClass->RpcRegistration = NULL;
2120

2121 2122
  if (!(newClass->dwCookie = InterlockedIncrement( &next_cookie )))
      newClass->dwCookie = InterlockedIncrement( &next_cookie );
2123 2124

  /*
2125
   * Since we're making a copy of the object pointer, we have to increase its
2126 2127 2128 2129 2130
   * reference count.
   */
  newClass->classObject     = pUnk;
  IUnknown_AddRef(newClass->classObject);

2131 2132
  EnterCriticalSection( &csRegisteredClassList );
  list_add_tail(&RegisteredClassList, &newClass->entry);
2133 2134
  LeaveCriticalSection( &csRegisteredClassList );

2135
  *lpdwRegister = newClass->dwCookie;
2136

2137
  if (dwClsContext & CLSCTX_LOCAL_SERVER) {
2138 2139
      hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
      if (hr) {
2140
          FIXME("Failed to create stream on hglobal, %x\n", hr);
2141 2142
          return hr;
      }
2143
      hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IUnknown,
2144
                              newClass->classObject, MSHCTX_LOCAL, NULL,
2145 2146
                              MSHLFLAGS_TABLESTRONG);
      if (hr) {
2147
          FIXME("CoMarshalInterface failed, %x!\n",hr);
2148 2149 2150
          return hr;
      }

2151 2152
      hr = RPC_StartLocalServer(&newClass->classIdentifier,
                                newClass->pMarshaledData,
2153
                                flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
2154
                                &newClass->RpcRegistration);
2155
  }
2156
  return S_OK;
Alexandre Julliard's avatar
Alexandre Julliard committed
2157 2158
}

2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170
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';
}

2171
static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
2172 2173
                                       REFCLSID rclsid, REFIID riid,
                                       BOOL hostifnecessary, void **ppv)
2174 2175
{
    WCHAR dllpath[MAX_PATH+1];
2176
    BOOL apartment_threaded;
2177

2178
    if (hostifnecessary)
2179
    {
2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
        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;
2214
    }
2215 2216
    else
        apartment_threaded = !apt->multi_threaded;
2217

2218 2219 2220 2221 2222 2223 2224
    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;
    }

2225
    return apartment_getclassobject(apt, dllpath, apartment_threaded,
2226
                                    rclsid, riid, ppv);
2227 2228
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2229
/***********************************************************************
2230
 *           CoGetClassObject [OLE32.@]
2231
 *
2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253
 * 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
2254
 */
2255 2256
HRESULT WINAPI CoGetClassObject(
    REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
2257 2258
    REFIID iid, LPVOID *ppv)
{
2259 2260
    LPUNKNOWN	regClassObject;
    HRESULT	hres = E_UNEXPECTED;
2261
    APARTMENT  *apt;
2262
    BOOL release_apt = FALSE;
2263

2264
    TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
Alexandre Julliard's avatar
Alexandre Julliard committed
2265

2266 2267 2268 2269 2270
    if (!ppv)
        return E_INVALIDARG;

    *ppv = NULL;

2271
    if (!(apt = COM_CurrentApt()))
2272
    {
2273 2274 2275 2276 2277 2278
        if (!(apt = apartment_find_multi_threaded()))
        {
            ERR("apartment not initialised\n");
            return CO_E_NOTINITIALIZED;
        }
        release_apt = TRUE;
2279 2280
    }

2281
    if (pServerInfo) {
2282 2283
	FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
              debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
2284 2285
    }

2286
    /*
2287
     * First, try and see if we can't match the class ID with one of the
2288 2289
     * registered classes.
     */
2290 2291
    if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext,
                                             &regClassObject))
2292
    {
2293
      /* Get the required interface from the retrieved pointer. */
2294 2295 2296 2297 2298 2299 2300 2301
      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);
2302
      if (release_apt) apartment_release(apt);
2303 2304 2305
      return hres;
    }

2306 2307
    /* First try in-process server */
    if (CLSCTX_INPROC_SERVER & dwClsContext)
2308 2309 2310 2311
    {
        static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
        HKEY hkey;

2312
        if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler))
2313 2314
        {
            if (release_apt) apartment_release(apt);
2315
            return FTMarshalCF_Create(iid, ppv);
2316
        }
2317

2318 2319
        hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
        if (FAILED(hres))
2320
        {
2321 2322
            if (hres == REGDB_E_CLASSNOTREG)
                ERR("class %s not registered\n", debugstr_guid(rclsid));
2323 2324
            else if (hres == REGDB_E_KEYMISSING)
            {
2325
                WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
2326 2327
                hres = REGDB_E_CLASSNOTREG;
            }
2328 2329 2330 2331
        }

        if (SUCCEEDED(hres))
        {
2332 2333
            hres = get_inproc_class_object(apt, hkey, rclsid, iid,
                !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2334 2335 2336 2337 2338 2339
            RegCloseKey(hkey);
        }

        /* return if we got a class, otherwise fall through to one of the
         * other types */
        if (SUCCEEDED(hres))
2340 2341
        {
            if (release_apt) apartment_release(apt);
2342
            return hres;
2343
        }
2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356
    }

    /* 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));
2357 2358
            else if (hres == REGDB_E_KEYMISSING)
            {
2359
                WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
2360 2361
                hres = REGDB_E_CLASSNOTREG;
            }
2362
        }
2363

2364
        if (SUCCEEDED(hres))
2365
        {
2366 2367
            hres = get_inproc_class_object(apt, hkey, rclsid, iid,
                !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
2368
            RegCloseKey(hkey);
2369
        }
2370 2371 2372 2373

        /* return if we got a class, otherwise fall through to one of the
         * other types */
        if (SUCCEEDED(hres))
2374 2375
        {
            if (release_apt) apartment_release(apt);
2376
            return hres;
2377
        }
2378
    }
2379
    if (release_apt) apartment_release(apt);
2380

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

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

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
2417
/***********************************************************************
2418
 *           CoCreateInstance [OLE32.@]
2419 2420 2421 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
 *
 * 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
2447
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
2448 2449 2450 2451
HRESULT WINAPI CoCreateInstance(
	REFCLSID rclsid,
	LPUNKNOWN pUnkOuter,
	DWORD dwClsContext,
Alexandre Julliard's avatar
Alexandre Julliard committed
2452
	REFIID iid,
2453
	LPVOID *ppv)
2454
{
2455 2456
  HRESULT hres;
  LPCLASSFACTORY lpclf = 0;
2457
  APARTMENT *apt;
Alexandre Julliard's avatar
Alexandre Julliard committed
2458

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

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

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

2473
  if (!(apt = COM_CurrentApt()))
2474
  {
2475 2476
    if (!(apt = apartment_find_multi_threaded()))
    {
2477 2478
      ERR("apartment not initialised\n");
      return CO_E_NOTINITIALIZED;
2479 2480
    }
    apartment_release(apt);
2481 2482
  }

2483 2484 2485 2486 2487
  /*
   * 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)) {
2488
    if (StdGlobalInterfaceTableInstance == NULL)
2489 2490 2491
      StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
    hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
    if (hres) return hres;
2492

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

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

2506
  if (FAILED(hres))
2507 2508 2509 2510 2511
    return hres;

  /*
   * Create the object and don't forget to release the factory
   */
2512 2513
	hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
	IClassFactory_Release(lpclf);
2514
	if(FAILED(hres))
2515 2516 2517 2518 2519 2520
        {
          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);
        }
2521

Alexandre Julliard's avatar
Alexandre Julliard committed
2522
	return hres;
Alexandre Julliard's avatar
Alexandre Julliard committed
2523 2524
}

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

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

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

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

  /*
2560
   * Get the object and get its IUnknown pointer.
2561
   */
2562
  hr = CoCreateInstance(rclsid,
2563 2564 2565
			pUnkOuter,
			dwClsContext,
			&IID_IUnknown,
2566
			(VOID**)&pUnk);
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 2595 2596

  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;
}
2597

Ove Kaaven's avatar
Ove Kaaven committed
2598
/***********************************************************************
2599
 *           CoLoadLibrary (OLE32.@)
2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612
 *
 * 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
2613
 */
2614
HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree)
Ove Kaaven's avatar
Ove Kaaven committed
2615
{
2616
    TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree);
2617

2618 2619
    return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
}
2620

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


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

Alexandre Julliard's avatar
Alexandre Julliard committed
2657
/***********************************************************************
2658
 *           CoFreeUnusedLibrariesEx [OLE32.@]
2659
 *
2660 2661 2662 2663 2664 2665 2666
 * 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.
2667 2668 2669
 *
 * RETURNS
 *  Nothing.
2670
 *
2671 2672
 * SEE ALSO
 *  CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary
Alexandre Julliard's avatar
Alexandre Julliard committed
2673
 */
2674
void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved)
Alexandre Julliard's avatar
Alexandre Julliard committed
2675
{
2676 2677 2678 2679 2680 2681 2682
    struct apartment *apt = COM_CurrentApt();
    if (!apt)
    {
        ERR("apartment not initialised\n");
        return;
    }

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

/***********************************************************************
 *           CoFreeUnusedLibraries [OLE32.@]
 *
 * 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
2701 2702 2703
}

/***********************************************************************
2704
 *           CoFileTimeNow [OLE32.@]
2705 2706 2707 2708 2709
 *
 * 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
    HRESULT res = S_OK;
    LONG len = sizeof(szClsidNew);

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

2964 2965
    res = COM_OpenKeyForCLSID(clsidOld, wszTreatAs, KEY_READ, &hkey);
    if (FAILED(res))
2966 2967
    {
        res = S_FALSE;
2968
        goto done;
2969
    }
2970
    if (RegQueryValueW(hkey, NULL, szClsidNew, &len))
2971 2972 2973 2974
    {
        res = S_FALSE;
	goto done;
    }
2975
    res = CLSIDFromString(szClsidNew,clsidNew);
2976
    if (FAILED(res))
2977
        ERR("Failed CLSIDFromStringA(%s), hres 0x%08x\n", debugstr_w(szClsidNew), res);
2978 2979 2980 2981
done:
    if (hkey) RegCloseKey(hkey);
    return res;
}
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 3009 3010
/******************************************************************************
 *		CoGetCurrentProcess	[OLE32.@]
 *
 * 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.
3011 3012 3013 3014 3015 3016 3017 3018 3019 3020
 *
 * 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.
3021 3022 3023 3024 3025
 */
HRESULT WINAPI CoRegisterMessageFilter(
    LPMESSAGEFILTER lpMessageFilter,
    LPMESSAGEFILTER *lplpMessageFilter)
{
3026 3027 3028 3029 3030 3031 3032 3033
    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 */
3034
    if (!apt || apt->multi_threaded)
3035
    {
3036
        WARN("can't set message filter in MTA or uninitialized apt\n");
3037
        return CO_E_NOT_SUPPORTED;
3038
    }
3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054

    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);

3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074
    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;
}

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

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

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

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

    TRACE("\n");

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

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

    return refs;
3151 3152 3153 3154
}

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

    TRACE("\n");

    EnterCriticalSection(&csRegisteredClassList);

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

    LeaveCriticalSection(&csRegisteredClassList);

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

    return refs;
3185
}
3186

3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204
/***********************************************************************
 *           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;
}
3205 3206 3207 3208 3209 3210 3211 3212 3213 3214

/***********************************************************************
 *           CoAllowSetForegroundWindow [OLE32.@]
 *
 */
HRESULT WINAPI CoAllowSetForegroundWindow(IUnknown *pUnk, void *pvReserved)
{
    FIXME("(%p, %p): stub\n", pUnk, pvReserved);
    return S_OK;
}
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 3247 3248
/***********************************************************************
 *           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))
3249
    {
3250 3251 3252 3253
        hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc,
                                          pAuthzSvc, ppServerPrincName,
                                          pAuthnLevel, pImpLevel, ppAuthInfo,
                                          pCapabilities);
3254 3255
        IClientSecurity_Release(pCliSec);
    }
3256

3257
    if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
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 3292 3293
    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))
3294
    {
3295 3296 3297 3298
        hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc,
                                        AuthzSvc, pServerPrincName,
                                        AuthnLevel, ImpLevel, pAuthInfo,
                                        Capabilities);
3299 3300
        IClientSecurity_Release(pCliSec);
    }
3301

3302
    if (FAILED(hr)) ERR("-- failed with 0x%08x\n", hr);
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 3329 3330
    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))
3331
    {
3332
        hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy);
3333 3334
        IClientSecurity_Release(pCliSec);
    }
3335

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


3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356
/***********************************************************************
 *           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)
{
3357
    struct oletls *info = COM_CurrentInfo();
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 3395 3396
    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;
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 3518 3519
}

/***********************************************************************
 *           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;
}

3520 3521
static BOOL COM_PeekMessage(struct apartment *apt, MSG *msg)
{
3522 3523
    /* 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) ||
3524
           /* next retrieve other messages necessary for the app to remain responsive */
3525 3526
           PeekMessageW(msg, NULL, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE|PM_NOYIELD) ||
           PeekMessageW(msg, NULL, 0, 0, PM_QS_PAINT|PM_QS_SENDMESSAGE|PM_REMOVE|PM_NOYIELD);
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 3552 3553 3554
/***********************************************************************
 *           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,
3555
    ULONG cHandles, LPHANDLE pHandles, LPDWORD lpdwindex)
3556 3557 3558
{
    HRESULT hr = S_OK;
    DWORD start_time = GetTickCount();
3559 3560
    APARTMENT *apt = COM_CurrentApt();
    BOOL message_loop = apt && !apt->multi_threaded;
3561

3562
    TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles,
3563 3564 3565 3566 3567 3568
        pHandles, lpdwindex);

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

3570
        if (now - start_time > dwTimeout)
3571 3572 3573 3574 3575
        {
            hr = RPC_S_CALLPENDING;
            break;
        }

3576 3577
        if (message_loop)
        {
3578 3579
            DWORD wait_flags = ((dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0) |
                    ((dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0);
3580 3581

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

3583 3584 3585
            res = MsgWaitForMultipleObjectsEx(cHandles, pHandles,
                (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now,
                QS_ALLINPUT, wait_flags);
3586

3587
            if (res == WAIT_OBJECT_0 + cHandles)  /* messages available */
3588
            {
3589
                MSG msg;
3590

3591 3592 3593 3594
                /* call message filter */

                if (COM_CurrentApt()->filter)
                {
3595 3596 3597
                    PENDINGTYPE pendingtype =
                        COM_CurrentInfo()->pending_call_count_server ?
                            PENDINGTYPE_NESTED : PENDINGTYPE_TOPLEVEL;
3598 3599
                    DWORD be_handled = IMessageFilter_MessagePending(
                        COM_CurrentApt()->filter, 0 /* FIXME */,
3600
                        now - start_time, pendingtype);
3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618
                    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;
                    }
                }

3619 3620 3621 3622 3623
                /* 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))
3624
                {
3625 3626 3627 3628 3629 3630 3631 3632 3633 3634
                    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;
                    }
3635
                }
3636
                continue;
3637 3638
            }
        }
3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
        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);
        }

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

3671 3672 3673 3674

/***********************************************************************
 *           CoGetObject [OLE32.@]
 *
3675
 * Gets the object named by converting the name to a moniker and binding to it.
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 3720 3721 3722
 *
 * 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;
}

3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742
/***********************************************************************
 *           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);
}

3743 3744
typedef struct Context
{
3745 3746 3747
    IComThreadingInfo IComThreadingInfo_iface;
    IContextCallback IContextCallback_iface;
    IObjContext IObjContext_iface;
3748 3749 3750 3751
    LONG refs;
    APTTYPE apttype;
} Context;

3752 3753
static inline Context *impl_from_IComThreadingInfo( IComThreadingInfo *iface )
{
3754
        return CONTAINING_RECORD(iface, Context, IComThreadingInfo_iface);
3755 3756 3757 3758
}

static inline Context *impl_from_IContextCallback( IContextCallback *iface )
{
3759
        return CONTAINING_RECORD(iface, Context, IContextCallback_iface);
3760 3761
}

3762 3763
static inline Context *impl_from_IObjContext( IObjContext *iface )
{
3764
        return CONTAINING_RECORD(iface, Context, IObjContext_iface);
3765 3766
}

3767
static HRESULT Context_QueryInterface(Context *iface, REFIID riid, LPVOID *ppv)
3768 3769 3770 3771 3772 3773
{
    *ppv = NULL;

    if (IsEqualIID(riid, &IID_IComThreadingInfo) ||
        IsEqualIID(riid, &IID_IUnknown))
    {
3774
        *ppv = &iface->IComThreadingInfo_iface;
3775 3776
    }
    else if (IsEqualIID(riid, &IID_IContextCallback))
3777
    {
3778
        *ppv = &iface->IContextCallback_iface;
3779
    }
3780 3781
    else if (IsEqualIID(riid, &IID_IObjContext))
    {
3782
        *ppv = &iface->IObjContext_iface;
3783
    }
3784 3785 3786 3787

    if (*ppv)
    {
        IUnknown_AddRef((IUnknown*)*ppv);
3788 3789 3790 3791 3792 3793 3794
        return S_OK;
    }

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

3795
static ULONG Context_AddRef(Context *This)
3796 3797 3798 3799
{
    return InterlockedIncrement(&This->refs);
}

3800
static ULONG Context_Release(Context *This)
3801 3802 3803 3804 3805 3806 3807
{
    ULONG refs = InterlockedDecrement(&This->refs);
    if (!refs)
        HeapFree(GetProcessHeap(), 0, This);
    return refs;
}

3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826
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)
3827
{
3828
    Context *This = impl_from_IComThreadingInfo(iface);
3829 3830 3831 3832 3833 3834 3835

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

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

3836
static HRESULT WINAPI Context_CTI_GetCurrentThreadType(IComThreadingInfo *iface, THDTYPE *thdtype)
3837
{
3838
    Context *This = impl_from_IComThreadingInfo(iface);
3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854

    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;
}

3855
static HRESULT WINAPI Context_CTI_GetCurrentLogicalThreadId(IComThreadingInfo *iface, GUID *logical_thread_id)
3856 3857 3858 3859 3860
{
    FIXME("(%p): stub\n", logical_thread_id);
    return E_NOTIMPL;
}

3861
static HRESULT WINAPI Context_CTI_SetCurrentLogicalThreadId(IComThreadingInfo *iface, REFGUID logical_thread_id)
3862 3863 3864 3865 3866 3867 3868
{
    FIXME("(%s): stub\n", debugstr_guid(logical_thread_id));
    return E_NOTIMPL;
}

static const IComThreadingInfoVtbl Context_Threading_Vtbl =
{
3869 3870 3871 3872 3873 3874 3875
    Context_CTI_QueryInterface,
    Context_CTI_AddRef,
    Context_CTI_Release,
    Context_CTI_GetCurrentApartmentType,
    Context_CTI_GetCurrentThreadType,
    Context_CTI_GetCurrentLogicalThreadId,
    Context_CTI_SetCurrentLogicalThreadId
3876 3877
};

3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912
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
};

3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021
static HRESULT WINAPI Context_OC_QueryInterface(IObjContext *iface, REFIID riid, LPVOID *ppv)
{
    Context *This = impl_from_IObjContext(iface);
    return Context_QueryInterface(This, riid, ppv);
}

static ULONG WINAPI Context_OC_AddRef(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    return Context_AddRef(This);
}

static ULONG WINAPI Context_OC_Release(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    return Context_Release(This);
}

static HRESULT WINAPI Context_OC_SetProperty(IObjContext *iface, REFGUID propid, CPFLAGS flags, IUnknown *punk)
{
    Context *This = impl_from_IObjContext(iface);

    FIXME("(%p/%p)->(%s, %x, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_OC_RemoveProperty(IObjContext *iface, REFGUID propid)
{
    Context *This = impl_from_IObjContext(iface);

    FIXME("(%p/%p)->(%s)\n", This, iface, debugstr_guid(propid));
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_OC_GetProperty(IObjContext *iface, REFGUID propid, CPFLAGS *flags, IUnknown **punk)
{
    Context *This = impl_from_IObjContext(iface);

    FIXME("(%p/%p)->(%s, %p, %p)\n", This, iface, debugstr_guid(propid), flags, punk);
    return E_NOTIMPL;
}

static HRESULT WINAPI Context_OC_EnumContextProps(IObjContext *iface, IEnumContextProps **props)
{
    Context *This = impl_from_IObjContext(iface);

    FIXME("(%p/%p)->(%p)\n", This, iface, props);
    return E_NOTIMPL;
}

static void WINAPI Context_OC_Reserved1(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    FIXME("(%p/%p)\n", This, iface);
}

static void WINAPI Context_OC_Reserved2(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    FIXME("(%p/%p)\n", This, iface);
}

static void WINAPI Context_OC_Reserved3(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    FIXME("(%p/%p)\n", This, iface);
}

static void WINAPI Context_OC_Reserved4(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    FIXME("(%p/%p)\n", This, iface);
}

static void WINAPI Context_OC_Reserved5(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    FIXME("(%p/%p)\n", This, iface);
}

static void WINAPI Context_OC_Reserved6(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    FIXME("(%p/%p)\n", This, iface);
}

static void WINAPI Context_OC_Reserved7(IObjContext *iface)
{
    Context *This = impl_from_IObjContext(iface);
    FIXME("(%p/%p)\n", This, iface);
}

static const IObjContextVtbl Context_Object_Vtbl =
{
    Context_OC_QueryInterface,
    Context_OC_AddRef,
    Context_OC_Release,
    Context_OC_SetProperty,
    Context_OC_RemoveProperty,
    Context_OC_GetProperty,
    Context_OC_EnumContextProps,
    Context_OC_Reserved1,
    Context_OC_Reserved2,
    Context_OC_Reserved3,
    Context_OC_Reserved4,
    Context_OC_Reserved5,
    Context_OC_Reserved6,
    Context_OC_Reserved7
};
4022

4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046
/***********************************************************************
 *           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)
    {
4047 4048 4049 4050 4051 4052
        if (!(apt = apartment_find_multi_threaded()))
        {
            ERR("apartment not initialised\n");
            return CO_E_NOTINITIALIZED;
        }
        apartment_release(apt);
4053 4054 4055 4056 4057 4058
    }

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

4059 4060 4061
    context->IComThreadingInfo_iface.lpVtbl = &Context_Threading_Vtbl;
    context->IContextCallback_iface.lpVtbl = &Context_Callback_Vtbl;
    context->IObjContext_iface.lpVtbl = &Context_Object_Vtbl;
4062 4063 4064 4065 4066 4067 4068 4069
    context->refs = 1;
    if (apt->multi_threaded)
        context->apttype = APTTYPE_MTA;
    else if (apt->main)
        context->apttype = APTTYPE_MAINSTA;
    else
        context->apttype = APTTYPE_STA;

4070 4071
    hr = IUnknown_QueryInterface((IUnknown *)&context->IComThreadingInfo_iface, riid, ppv);
    IUnknown_Release((IUnknown *)&context->IComThreadingInfo_iface);
4072 4073 4074 4075

    return hr;
}

4076 4077 4078 4079 4080 4081

/***********************************************************************
 *           CoGetContextToken [OLE32.@]
 */
HRESULT WINAPI CoGetContextToken( ULONG_PTR *token )
{
4082
    struct oletls *info = COM_CurrentInfo();
4083 4084 4085

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

4086 4087
    if (!info)
        return E_OUTOFMEMORY;
4088 4089

    if (!info->apt)
4090 4091 4092 4093 4094 4095 4096 4097 4098
    {
        APARTMENT *apt;
        if (!(apt = apartment_find_multi_threaded()))
        {
            ERR("apartment not initialised\n");
            return CO_E_NOTINITIALIZED;
        }
        apartment_release(apt);
    }
4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116

    if (!token)
        return E_POINTER;

    if (!info->context_token)
    {
        HRESULT hr;
        IObjContext *ctx;

        hr = CoGetObjectContext(&IID_IObjContext, (void **)&ctx);
        if (FAILED(hr)) return hr;
        info->context_token = ctx;
    }

    *token = (ULONG_PTR)info->context_token;
    TRACE("apt->context_token=%p\n", info->context_token);

    return S_OK;
4117 4118
}

4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145
HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
    static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
    HKEY hkey;
    HRESULT hres;

    hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
    if (SUCCEEDED(hres))
    {
        WCHAR dllpath[MAX_PATH+1];

        if (COM_RegReadPath(hkey, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) == ERROR_SUCCESS)
        {
            static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0};
            if (!strcmpiW(dllpath, wszOle32))
            {
                RegCloseKey(hkey);
                return HandlerCF_Create(rclsid, riid, ppv);
            }
        }
        else
            WARN("not creating object for inproc handler path %s\n", debugstr_w(dllpath));
        RegCloseKey(hkey);
    }

    return CLASS_E_CLASSNOTAVAILABLE;
}
4146

4147 4148 4149 4150 4151
/***********************************************************************
 *		DllMain (OLE32.@)
 */
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
{
4152
    TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
4153 4154 4155

    switch(fdwReason) {
    case DLL_PROCESS_ATTACH:
4156
        hProxyDll = hinstDLL;
4157 4158 4159 4160 4161
        COMPOBJ_InitProcess();
	break;

    case DLL_PROCESS_DETACH:
        COMPOBJ_UninitProcess();
4162
        RPC_UnregisterAllChannelHooks();
4163
        COMPOBJ_DllList_Free();
4164 4165 4166 4167 4168 4169 4170 4171 4172
	break;

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

4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187
/***********************************************************************
 *		DllRegisterServer (OLE32.@)
 */
HRESULT WINAPI DllRegisterServer(void)
{
    return OLE32_DllRegisterServer();
}

/***********************************************************************
 *		DllUnregisterServer (OLE32.@)
 */
HRESULT WINAPI DllUnregisterServer(void)
{
    return OLE32_DllUnregisterServer();
}