[EditorBrowsable(EditorBrowsableState.Advanced)]
[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
public IAsyncResult BeginInvoke(Delegate method, params Object[] args) {
using (new MultithreadSafeCallScope()) {
Control marshaler = FindMarshalingControl();
return(IAsyncResult)marshaler.MarshaledInvoke(this, method, args, false);
}
}
private Control FindMarshalingControl() {
//
lock(this) {
Control c = this;
while (c != null && !c.IsHandleCreated) {
Control p = c.ParentInternal;
c = p;
}
if (c == null) {
// No control with a created handle. We
// just use our own control. MarshaledInvoke
// will throw an exception because there
// is no handle.
//
c = this;
}
else {
Debug.Assert(c.IsHandleCreated, "FindMarshalingControl chose a bad control.");
}
return(Control)c;
}
}
private Object MarshaledInvoke(Control caller, Delegate method, Object[] args, bool synchronous) {
// Marshaling an invoke occurs in three steps:
//
// 1. Create a ThreadMethodEntry that contains the packet of information
// about this invoke. This TME is placed on a linked list of entries because
// we have a gap between the time we PostMessage and the time it actually
// gets processed, and this gap may allow other invokes to come in. Access
// to this linked list is always synchronized.
//
// 2. Post ourselves a message. Our caller has already determined the
// best control to call us on, and we should almost always have a handle.
//
// 3. If we're synchronous, wait for the message to get processed. We don't do
// a SendMessage here so we're compatible with OLE, which will abort many
// types of calls if we're within a SendMessage.
//
if (!IsHandleCreated) {
throw new InvalidOperationException(SR.GetString(SR.ErrorNoMarshalingThread));
}
// We have to demand unmanaged code permission here for the control hosted in
// the browser case. Without this check, we will expose a security hole, because
// ActiveXImpl.OnMessage() will assert unmanaged code for everyone as part of
// its implementation.
// The right fix is to remove the Assert() on top of the ActiveXImpl class, and
// visit each method to see if it needs unmanaged code permission, and if so, add
// the permission just to that method(s).
//
ActiveXImpl activeXImpl = (ActiveXImpl)Properties.GetObject(PropActiveXImpl);
if (activeXImpl != null) {
IntSecurity.UnmanagedCode.Demand();
}
// We don't want to wait if we're on the same thread, or else we'll deadlock.
// It is important that syncSameThread always be false for asynchronous calls.
//
bool syncSameThread = false;
int pid; // ignored
if (SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, Handle), out pid) == SafeNativeMethods.GetCurrentThreadId()) {
if (synchronous)
syncSameThread = true;
}
// Store the compressed stack information from the thread that is calling the Invoke()
// so we can assign the same security context to the thread that will actually execute
// the delegate being passed.
//
ExecutionContext executionContext = null;
if (!syncSameThread) {
executionContext = ExecutionContext.Capture();
}
ThreadMethodEntry tme = new ThreadMethodEntry(caller, method, args, synchronous, executionContext);
lock (this) {
if (threadCallbackList == null) {
threadCallbackList = new Queue();
}
}
lock (threadCallbackList) {
if (threadCallbackMessage == 0) {
threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage");
}
threadCallbackList.Enqueue(tme);
}
if (syncSameThread) {
InvokeMarshaledCallbacks();
} else {
//
UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
}
if (synchronous) {
if (!tme.IsCompleted) {
WaitForWaitHandle(tme.AsyncWaitHandle);
}
if (tme.exception != null) {
throw tme.exception;
}
return tme.retVal;
}
else {
return(IAsyncResult)tme;
}
}
c#源码查看网址:
https://referencesource.microsoft.com/