Process X can't tell if Process Y is being managed debugged.

From the mail bag:

Is there a way to determine if a managed debugger is already attached to
a given process id?

It looks like ICorDebug.CanLaunchOrAttach might be the right API for this
(wouldn't it return FALSE if another debugger is already attached?).
However, it seems like this API always returns TRUE. I searched your blog at

https://blogs.msdn.com/jmstall/archive/category/7367.aspx but didn't find
something specific to this. Any insight would be appreciated.

I've had this a few times, and so I wanted to blog the answer.

In short: No. Process X can't tell if a managed-only debugger
is attached to process Y. Here are related APIs:

API: What it does
kernel32!IsDebuggerPresent Tells you if an native debugger is attached to the current process. This will also return true when interop-debugging.
kernel32!CheckRemoteDebuggerPresent Tells you if an native debugger is attached to an arbitrary process. This will also return true when interop-debugging.
mscorlib!System.Diagnostics.Debugger.IsAttached Tells you if a managed debugger is attached to the current process.

What about ICorDebug::CanLaunchOrAttach?

Note that ICorDebug::CanLaunchOrAttach() is distinct from the above APIs. It
gives a prediction about whether the ICorDebug instance it's called on can
handle a future managed launch / attached. This prediction is not necessarily
accurate. (I personally think that API is useless and we should never have
shipped it.). This prediction originally existed because we build the managed
eventing pipeline on top of

WaitForMultipleObjects, where each process we're debugging gets a object in
the wait set (an event handle to listen for debug events from the debuggee). The
OS limits the wait set to MAXIMUM_WAIT_OBJECTS (64) objects. Thus a single
ICorDebug instance can't handle more than 64 debug connections. That hard number
is entirely implementation dependent. For example, if each debuggee requires two
objects in the wait set, the number drops to 32.And there is also a fixed set of
overhead events in the wait set. This is just a very silly thing to bake into
our API.

It could also serve as a canary to sniff out if a kernel debugger is attached.

Recall that managed-only debugging is technically not native win32 debugging.
This is sort of an implementation detail but certainly has implications that can
be discoverable at the public interface level. We reserve the right to change
this in future versions of the CLR.