dotnet/maui · error · InvalidOperationException

IConnectionPoint::Advise returned an invalid cookie.

Error message

IConnectionPoint::Advise returned an invalid cookie.

What it means

SafeConnectionPointCookie constructor throws InvalidOperationException("IConnectionPoint::Advise returned an invalid cookie.") when COM's IConnectionPoint.Advise returns a dwCookie of 0 after FindConnectionPoint succeeded. Cookie 0 is an invalid advisory cookie, meaning the COM event subscription did not actually register the sink, so subsequent event delivery would silently fail.

Source

Thrown at src/Compatibility/Core/src/WPF/Microsoft.Windows.Shell/Standard/NativeMethods.cs:1642

		[SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IConnectionPoint")]
		public SafeConnectionPointCookie(IConnectionPointContainer target, object sink, Guid eventId)
			: base(true)
		{
			Verify.IsNotNull(target, "target");
			Verify.IsNotNull(sink, "sink");
			Verify.IsNotDefault(eventId, "eventId");

			handle = IntPtr.Zero;

			IConnectionPoint cp = null;
			try
			{
				int dwCookie;
				target.FindConnectionPoint(ref eventId, out cp);
				cp.Advise(sink, out dwCookie);
				if (dwCookie == 0)
				{
					throw new InvalidOperationException("IConnectionPoint::Advise returned an invalid cookie.");
				}
				handle = new IntPtr(dwCookie);
				_cp = cp;
				cp = null;
			}
			finally
			{
				Utility.SafeRelease(ref cp);
			}
		}

		[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
		public void Disconnect()
		{
			ReleaseHandle();
		}

		[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]

View on GitHub (pinned to f377ff1c5e)

Solutions

  1. Verify the sink object is COM-visible and matches the expected dispatch interface.
  2. Ensure the calling thread's apartment (STA/MTA) matches the COM component's requirements.
  3. Subscribe before the component is disposed and unsubscribe cleanly to avoid teardown races.
  4. If the source component is in a bad state, recreate it before retrying Advise.

Example fix

// before
var cookie = new SafeConnectionPointCookie((IConnectionPointContainer)comObj, sink, eventId);

// after
comObj.SetApartmentState(ApartmentState.STA);
if (sink is IComVisible)
    var cookie = new SafeConnectionPointCookie((IConnectionPointContainer)comObj, sink, eventId);
else
    throw new InvalidOperationException("sink is not COM-visible");
Defensive patterns

Strategy: validation

Validate before calling

if (sink == null || !sink.GetType().IsCOMVisible) throw new ArgumentException("sink must be COM-visible");
var cookie = new SafeConnectionPointCookie(container, sink, eventId);

Type guard

static bool IsValidSink(object sink) => sink != null && sink.GetType().IsCOMVisible;

Try / catch

try { var cookie = new SafeConnectionPointCookie(container, sink, eventId); }
catch (InvalidOperationException ex) when (ex.Message.Contains("invalid cookie"))
{ /* recreate COM component, fix apartment, then retry Advise */ }

Prevention

When it happens

Trigger: Subscribing to COM connection-point events (e.g. shell or DWebBrowserEvents) where Advise returns 0; passing a sink that the source rejected; race between Advise and connection-point teardown.

Common situations: Hosting a COM component (WebBrowser, shell, automation) whose connection point is in a bad state; passing a non-com-visible sink; subscribing during shutdown; COM apartment mismatches causing Advise to fail.

Related errors


AI-assisted analysis of dotnet/maui@f377ff1c5e (2026-08-13). Data as JSON: /api/errors/fe82f6598cd0a32e. Report an issue: GitHub.