Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
A little more refactoring
  • Loading branch information
jkoritzinsky authored and github-actions committed Jan 7, 2025
commit 3251a822e5655ad7f1f15626df4e68078c1dc94a
Original file line number Diff line number Diff line change
Expand Up @@ -492,11 +492,11 @@ internal unsafe class NativeObjectWrapper
{
private IntPtr _externalComObject;
private IntPtr _inner;
private readonly ComWrappers _comWrappers;
private ComWrappers _comWrappers;
private GCHandle _proxyHandle;
private GCHandle _proxyHandleTrackingResurrection;
internal readonly bool _aggregatedManagedObjectWrapper;
private bool _maybeCached;
private readonly bool _uniqueInstance;

static NativeObjectWrapper()
{
Expand Down Expand Up @@ -524,7 +524,7 @@ protected NativeObjectWrapper(IntPtr externalComObject, IntPtr inner, ComWrapper
_externalComObject = externalComObject;
_inner = inner;
_comWrappers = comWrappers;
_maybeCached = !flags.HasFlag(CreateObjectFlags.UniqueInstance);
_uniqueInstance = !flags.HasFlag(CreateObjectFlags.UniqueInstance);
_proxyHandle = GCHandle.Alloc(comProxy, GCHandleType.Weak);

// We have a separate handle tracking resurrection as we want to make sure
Expand All @@ -549,13 +549,14 @@ protected NativeObjectWrapper(IntPtr externalComObject, IntPtr inner, ComWrapper
internal IntPtr ExternalComObject => _externalComObject;
internal ComWrappers ComWrappers => _comWrappers;
internal GCHandle ProxyHandle => _proxyHandle;
internal bool IsUniqueInstance => _uniqueInstance;

public virtual void Release()
{
if (_maybeCached)
if (!_uniqueInstance && _comWrappers is not null)
{
_comWrappers._rcwCache.Remove(_externalComObject, this);
_maybeCached = false;
_comWrappers = null;
}

if (_proxyHandle.IsAllocated)
Expand Down Expand Up @@ -955,15 +956,8 @@ private unsafe bool TryGetOrCreateObjectForComInstanceInternal(
// and return.
if (flags.HasFlag(CreateObjectFlags.UniqueInstance))
{
retValue = CreateObject(identity, flags);
if (retValue == null)
{
// If ComWrappers instance cannot create wrapper, we can do nothing here.
return false;
}

retValue = RegisterObjectForComInstance(identity, inner, retValue, flags);
return true;
retValue = CreateAndRegisterObjectForComInstance(identity, inner, flags);
return retValue is not null;
}

// If we have a live cached wrapper currently,
Expand Down Expand Up @@ -1012,24 +1006,22 @@ private unsafe bool TryGetOrCreateObjectForComInstanceInternal(
}
}

retValue = CreateObject(identity, flags);
if (retValue == null)
{
// If ComWrappers instance cannot create wrapper, we can do nothing here.
return false;
}
// If the user didn't provide a wrapper and couldn't unwrap a managed object wrapper,
// create a new wrapper.
retValue = CreateAndRegisterObjectForComInstance(identity, inner, flags);
return retValue is not null;
}

// Now that we've called into user code to create the user object wrapper,
// another thread may have beaten us to creating a cached wrapper for the same identity.
// Check the cache again to avoid creating a NativeObjectWrapper when we don't need to.
if (_rcwCache.FindProxyForComInstance(identity) is object cachedWrapper)
private object? CreateAndRegisterObjectForComInstance(IntPtr identity, IntPtr inner, CreateObjectFlags flags)
{
object? retValue = CreateObject(identity, flags);
if (retValue is null)
{
retValue = cachedWrapper;
return true;
// If ComWrappers instance cannot create wrapper, we can do nothing here.
return null;
}

retValue = RegisterObjectForComInstance(identity, inner, retValue, flags);
return true;
return RegisterObjectForComInstance(identity, inner, retValue, flags);
}

private object RegisterObjectForComInstance(IntPtr identity, IntPtr inner, object comProxy, CreateObjectFlags flags)
Expand All @@ -1043,7 +1035,7 @@ private object RegisterObjectForComInstance(IntPtr identity, IntPtr inner, objec

object actualProxy = comProxy;
NativeObjectWrapper actualWrapper = nativeObjectWrapper;
if (!flags.HasFlag(CreateObjectFlags.UniqueInstance))
if (!nativeObjectWrapper.IsUniqueInstance)
{
// Add our entry to the cache here, using an already existing entry if someone else beat us to it.
(actualWrapper, actualProxy) = _rcwCache.GetOrAddProxyForComInstance(identity, nativeObjectWrapper, comProxy);
Expand All @@ -1065,20 +1057,21 @@ private object RegisterObjectForComInstance(IntPtr identity, IntPtr inner, objec

private void RegisterWrapperForObject(NativeObjectWrapper wrapper, object comProxy)
{
// When we call into RegisterWrapperForObject, there is only one valid wrapper for a given
// COM instance. If we find a wrapper in the table that is a different NativeObjectWrapper instance
// When we call into RegisterWrapperForObject, there is only one valid non-"unique instance" wrapper for a given
// COM instance, which is already registered in the RCW cache.
// If we find a wrapper in the table that is a different NativeObjectWrapper instance
// then it must be for a different COM instance.
// It's possible that we could race here with another thread that is trying to register the same comProxy
// for the same COM instance, but in that case we'll be pased the same NativeObjectWrapper instance
// for both threads. In that case, it doesn't matter which thread adds the entry to the NativeObjectWrapper table
// as the entry is always the same pair.
Debug.Assert(wrapper.ProxyHandle.Target == comProxy);
Debug.Assert(wrapper.IsUniqueInstance || _rcwCache.FindProxyForComInstance(wrapper.ExternalComObject) == comProxy);

if (s_nativeObjectWrapperTable.TryGetValue(comProxy, out NativeObjectWrapper? registeredWrapper)
&& registeredWrapper != wrapper)
{
Debug.Assert(registeredWrapper.ExternalComObject != wrapper.ExternalComObject);
_rcwCache.Remove(wrapper.ExternalComObject, wrapper);
wrapper.Release();
throw new NotSupportedException();
}
Expand All @@ -1087,7 +1080,6 @@ private void RegisterWrapperForObject(NativeObjectWrapper wrapper, object comPro
if (registeredWrapper != wrapper)
{
Debug.Assert(registeredWrapper.ExternalComObject != wrapper.ExternalComObject);
_rcwCache.Remove(wrapper.ExternalComObject, wrapper);
wrapper.Release();
throw new NotSupportedException();
}
Expand Down