⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compobj.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
    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;
}


/***
 * COM_GetRegisteredClassObject
 *
 * This internal method is used to scan the registered class list to
 * find a class object.
 *
 * Params:
 *   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.
 */
static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
                                            DWORD dwClsContext, LPUNKNOWN* ppUnk)
{
  HRESULT hr = S_FALSE;
  RegisteredClass *curClass;

  /*
   * Sanity check
   */
  assert(ppUnk!=0);

  EnterCriticalSection( &csRegisteredClassList );

  LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry)
  {
    /*
     * Check if we have a match on the class ID and context.
     */
    if ((apt->oxid == curClass->apartment_id) &&
        (dwClsContext & curClass->runContext) &&
        IsEqualGUID(&(curClass->classIdentifier), rclsid))
    {
      /*
       * We have a match, return the pointer to the class object.
       */
      *ppUnk = curClass->classObject;

      IUnknown_AddRef(curClass->classObject);

      hr = S_OK;
      break;
    }
  }

  LeaveCriticalSection( &csRegisteredClassList );

  return hr;
}

/******************************************************************************
 *		CoRegisterClassObject	[OLE32.@]
 *
 * 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.
 *
 * 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.
 *
 * RETURNS
 *   S_OK on success,
 *   E_INVALIDARG if lpdwRegister or pUnk are NULL,
 *   CO_E_OBJISREG if the object is already registered. We should not return this.
 *
 * SEE ALSO
 *   CoRevokeClassObject, CoGetClassObject
 *
 * NOTES
 *  In-process objects are only registered for the current apartment.
 *  CoGetClassObject() and CoCreateInstance() will not return objects registered
 *  in other apartments.
 *
 * BUGS
 *  MSDN claims that multiple interface registrations are legal, but we
 *  can't do that with our current implementation.
 */
HRESULT WINAPI CoRegisterClassObject(
    REFCLSID rclsid,
    LPUNKNOWN pUnk,
    DWORD dwClsContext,
    DWORD flags,
    LPDWORD lpdwRegister)
{
  RegisteredClass* newClass;
  LPUNKNOWN        foundObject;
  HRESULT          hr;
  APARTMENT *apt;

  TRACE("(%s,%p,0x%08x,0x%08x,%p)\n",
	debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister);

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

  apt = COM_CurrentApt();
  if (!apt)
  {
      ERR("COM was not initialized\n");
      return CO_E_NOTINITIALIZED;
  }

  *lpdwRegister = 0;

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

  /*
   * First, check if the class is already registered.
   * If it is, this should cause an error.
   */
  hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject);
  if (hr == S_OK) {
    if (flags & REGCLS_MULTIPLEUSE) {
      if (dwClsContext & CLSCTX_LOCAL_SERVER)
        hr = CoLockObjectExternal(foundObject, TRUE, FALSE);
      IUnknown_Release(foundObject);
      return hr;
    }
    IUnknown_Release(foundObject);
    ERR("object already registered for class %s\n", debugstr_guid(rclsid));
    return CO_E_OBJISREG;
  }

  newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
  if ( newClass == NULL )
    return E_OUTOFMEMORY;

  newClass->classIdentifier = *rclsid;
  newClass->apartment_id    = apt->oxid;
  newClass->runContext      = dwClsContext;
  newClass->connectFlags    = flags;
  newClass->pMarshaledData  = NULL;
  newClass->RpcRegistration = NULL;

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

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

  EnterCriticalSection( &csRegisteredClassList );
  list_add_tail(&RegisteredClassList, &newClass->entry);
  LeaveCriticalSection( &csRegisteredClassList );

  *lpdwRegister = newClass->dwCookie;

  if (dwClsContext & CLSCTX_LOCAL_SERVER) {
      hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData);
      if (hr) {
          FIXME("Failed to create stream on hglobal, %x\n", hr);
          return hr;
      }
      hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory,
                              newClass->classObject, MSHCTX_LOCAL, NULL,
                              MSHLFLAGS_TABLESTRONG);
      if (hr) {
          FIXME("CoMarshalInterface failed, %x!\n",hr);
          return hr;
      }

      hr = RPC_StartLocalServer(&newClass->classIdentifier,
                                newClass->pMarshaledData,
                                flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
                                &newClass->RpcRegistration);
  }
  return S_OK;
}

static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass)
{
    list_remove(&curClass->entry);

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

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

    if (curClass->pMarshaledData)
    {
        LARGE_INTEGER zero;
        memset(&zero, 0, sizeof(zero));
        IStream_Seek(curClass->pMarshaledData, zero, STREAM_SEEK_SET, NULL);
        CoReleaseMarshalData(curClass->pMarshaledData);
    }

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

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

  EnterCriticalSection( &csRegisteredClassList );

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

  LeaveCriticalSection( &csRegisteredClassList );
}

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

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

  apt = COM_CurrentApt();
  if (!apt)
  {
    ERR("COM was not initialized\n");
    return CO_E_NOTINITIALIZED;
  }

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

/***********************************************************************
 *	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 {
              lstrcpynW(dst, src, dstlen);
            }
	  }
          RegCloseKey (key);
	}
	return ret;
}

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

static HRESULT get_inproc_class_object(APARTMENT *apt, HKEY hkeydll,
                                       REFCLSID rclsid, REFIID riid, void **ppv)
{
    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 dllpath[MAX_PATH+1];
    WCHAR threading_model[10 /* strlenW(L"apartment")+1 */];

    get_threading_model(hkeydll, threading_model, ARRAYSIZE(threading_model));
    /* "Apartment" */
    if (!strcmpiW(threading_model, wszApartment))
    {
        if (apt->multi_threaded)
            return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, hkeydll, rclsid, riid, ppv);
    }
    /* "Free" */
    else if (!strcmpiW(threading_model, wszFree))
    {
        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))
    {
        /* 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);
    }

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

    return apartment_getclassobject(apt, dllpath, rclsid, riid, ppv);
}

/***********************************************************************
 *           CoGetClassObject [OLE32.@]
 *
 * 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -