예제 #1
0
        private object InvokeMethod(IxCoreColleague target, MethodInfo mi, object[] parameterList)
        {
            if (!ProcessMessages)
                return null;

            try
            {
                Trace.Indent();

                if (invokeSwitch.TraceInfo)
                {
                    if (parameterList.Length > 0 && parameterList[0] != null)
                        Trace.WriteLine(" Invoking Method: " + mi.Name + "('" + parameterList[0].ToString() + "')" + " on " + target.ToString(), invokeSwitch.DisplayName);
                    else
                        Trace.WriteLine(" Invoking Method: " + mi.Name + " on " + target.ToString(), invokeSwitch.DisplayName);
                }
            #if false
                string objName = "";
                objName = target.ToString() + target.GetHashCode().ToString();
                // DLH TESTING - not finished yet...
                if (IsDisposedColleague(objName))
                {
                    Debug.WriteLine("##Not Invoking disposed object:"+objName);
                    return null;
                }
            #endif
                /// *****************************************************************************
                /// Have seen a stack situation that the Mediator has been disposed of after
                /// returning from this call - IOW's the following call allows re-entrance.
                /// That's why the exception follows to handle a known case when processing the
                /// ExitApplication msg.
                /// *****************************************************************************
                object returnValue = mi.Invoke(target, parameterList);
                if (m_isDisposed)
                    throw new DisposedInAnotherFrameException();

                if (target == m_temporaryColleague && !mi.Name.StartsWith("OnDisplay"))
                {
                    RemoveColleague(m_temporaryColleague);
                    m_temporaryColleague = null;	// only keep one temporary colleague at a time (menu based)
                }

                Trace.Unindent();

                return returnValue;
            }
                //note that we don't want to catch just any kind of the exception here,
                //most exceptions will be invoked by the method that we actually called.
                //the only exceptions we want to catch are the ones that just mean that we failed to find
                //a suitable method. These we can report if in debug-mode, otherwise ignore.
            catch(System.ArgumentException error)
            {
                //I once spent close to an hour wondering what was causing the failure here.
                //The exception message was "Object type cannot be converted to target type."
                //the answer was that I had made the signature be a UIListDisplayProperties
                //when it should have been a UIItemDisplayProperties. The two can be pretty hard to
                //distinguish visually. (John Hatton)
                Debug.Fail("The method '"+mi.Name+"' was found but couldn't be invoked. Maybe has the wrong signature?", error.Message);
            }
            //			catch(ConfigurationException error)
            //			{
            //				throw error; //already has good user notification message in it
            //			}
            //			catch(RuntimeConfigurationException error)
            //			{
            //				throw error; //already has good user notification message in it
            //			}
            catch(TargetInvocationException error)
            {
                Exception inner = error.InnerException;	//unwrap, for example, a ConfigurationException
                // See LT-1629 "Closing one db while opening another crashes".  The following
                // two lines  appear to fix this bug, although I'm not too happy about this
                // asynchronous behavior appearing where we (or at least I) don't expect it.
                // Unfortunately, that's inherent with message handling architecture when
                // handling one message allows other messages to be handled before it finishes.
                // - SteveMc
                if (inner is System.NullReferenceException &&
                    mi.Name == "OnChooseLangProject")
                {
                    // We probably closed the target's window after choosing another project,
                    // but before getting to this point in processing the ChooseLP message.  So
                    // ignore the exception.
                    return null;
                }
                string s = "Something went wrong trying to invoke "+ target.ToString() +":"+ mi.Name +"().";
                //if we just send on the error, then the caller
                //will find it more easy to trap particular kind of exceptions. On the other hand,
                //if the exception makes it all the way to the user, then we will really want to see this extra string (s)
                //at the top level.

                throw new Exception(s, inner);

                //if we were to just bring up the green box), then that makes it impossible for the caller to catch
                //the exception. In particular, the link-jumping column can fail if the object it is trying to jump to
                //has been deleted. This is really not an "error", and if we let the exception get back to the
                //jumping code, then it can notify the user more calmly.
                //SIL.Utils.ErrorReporter.ReportException(new ApplicationException(s, inner));
            }
            return null;
        }
예제 #2
0
        //static System.Diagnostics.Stopwatch ttime = new Stopwatch();
        /// <summary>
        ///
        /// </summary>
        /// <param name="colleague"></param>
        /// <param name="methodName"></param>
        /// <param name="parameterTypes"></param>
        /// <param name="parameterList"></param>
        /// <param name="previous">to catch infinite loops</param>
        private bool InvokeRecursively(IxCoreColleague colleague, string methodName, Type[] parameterTypes,
			object[] parameterList, HashSet<object> previous, bool stopWhenHandled, bool justCheckingForReceivers)
        {
            if (!ProcessMessages)
                return true;

            bool handled = false;
            //			Trace.Indent();
            if (invokeSwitch.TraceVerbose)
            {
                Trace.WriteLine("InvokeRecursively: methodName=<" + methodName + "> colleague=<" + colleague.ToString() + ">", invokeSwitch.DisplayName);
            }
            m_invokeCount++;
            //////// THIS IS TESTING CODE ADDED AND COMMENTED AND NEEDS TO BE REVERTED WHEN DONE>>>>>>>>
            //////// ><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>
            ////////ttime.Start();
            ////////ttime.Stop();
            ////////if ((m_invokeCount % 1000) == 0)
            ////////{
            ////////	TimeSpan ts = ttime.Elapsed;
            ////////	string tsString = String.Format("{0:00}.{1:0000}({2})",
            ////////		ts.Seconds,	ts.Milliseconds, ts.Ticks );
            ////////	Trace.WriteLine(tsString + " ColleagueHasBeenDisposed(" + colleague.ToString() + ")="+chbDisposed.ToString());
            ////////	ttime.Reset();
            ////////}
            if (colleague.ShouldNotCall)
            {
                DebugMsg("_+_+_+_+ InvokeRecursively called on colleague that is disposed/disposing: " + colleague.ToString());
                return false;	// stop the processing
            }

            IxCoreColleague[] targets = colleague.GetMessageTargets();
            // Try following the 'Code Performance' guidelines which says that
            // .."foreach introduces both managed heap and virtual function overhead..
            // This can be a significant factor in performance-sensitive regions of your application."
            // This section of code is indeed a very performance-sensitive region!
            //
            for (int index = 0; index < targets.Length; index++) // foreach(IxCoreColleague target in targets)
            {
                if (!ProcessMessages)
                    return true;

                IxCoreColleague target = targets[index];
                if(target == null)
                {
                    //Debug.WriteLine("Warning, target null.");
                    continue;
                }

                //this section is the leaf of the search tree
                if (target == colleague)
                {
                    //Check to see whether we have encountered this target before.
                    //how can we encounter the same one twice?
                    //This will happen when more than one colleague includes some shared object as one of its children.
                    //in xWorks, this happens with the RecordClerk, which is not a top-level colleague on its own.
                    // The following is logically equivalent to
                    //if (previous.Contains(target))
                    //{
                    //	break;
                    //}
                    //previous.Add(target);
                    // but faster.
                    int oldCount = previous.Count;
                    previous.Add(target);
                    if (oldCount == previous.Count)
                        break; // it was already present, that is, we've processed it before.

                    MethodInfo mi = CheckForMatchingMessage(colleague, methodName, parameterTypes);
                    if (mi != null)
                    {
                        if (justCheckingForReceivers)
                        {
                            handled = true;
                            break;
                        }
                        else
                        {
                            if (methodName == "OnMasterRefresh")
                            {
                                InvokeMethod(target, mi, parameterList);
                                handled = true;
                            }
                            else
                            {
                                object o = InvokeMethod(target, mi, parameterList);
                                handled = (o != null) ? (bool) o : false;
                            }
                        }
                    }
                    else
                    {
                        m_SavedCalls++;
                    }
                }
                else //not at a leaf yet, keep going down the tree
                    handled = InvokeRecursively(target, methodName, parameterTypes, parameterList, previous, stopWhenHandled, justCheckingForReceivers);

                if(handled && stopWhenHandled)
                {
                    Trace.WriteLineIf(invokeSwitch.TraceVerbose, "-->handled=true And stopWhenHandled=true", invokeSwitch.DisplayName);
                    break;
                }
                else if(handled)
                    Trace.WriteLineIf(invokeSwitch.TraceVerbose, "-->handled=true", invokeSwitch.DisplayName);

            }
            //			TraceVerboseLine("}");
            //			Trace.Unindent();
            return handled;
        }
예제 #3
0
		/// <summary>
		///
		/// </summary>
		/// <param name="target"></param>
		/// <param name="methodName"></param>
		/// <param name="parameterTypes">Currently, use null here if you have a ref param</param>
		/// <param name="parameterList"></param>
		/// <returns>null or the MethodInfo if a matching one was found</returns>
		private MethodInfo CheckForMatchingMessage(IxCoreColleague target, string methodName, Type[] parameterTypes,
			object[] parameterList, Set<int> previous)
		{
#if false
			//tostring here is too expensive to leave lying around
			Trace.Indent();
			TraceVerboseLine(" Checking : "+ target.ToString());
#endif
			int x = target.GetHashCode();
			if (previous.Contains(x))
			{
				throw new ArgumentException("XCore Mediator encountered the same " + target.ToString() + " twice on check for " + methodName + ", as if there is a loop.");
			}
#if false
			TraceVerboseLine("Adding "+target.ToString()+":"+x.ToString());
#endif
			previous.Add(x);

			//NB: I did not think about these flags; I just copied them from an example
			BindingFlags flags =
				BindingFlags.NonPublic|BindingFlags.Public|BindingFlags.Instance;

			Type type = target.GetType();
			MethodInfo mi;
			//
			// By using the JetBrains dotTrace profiler, the addition of m_TypeMethodInfo is saving
			// a significant (>20%) amount of time by not having to make as many calls to the expensive
			// System.Type.GetMethod()
			//
			if (parameterTypes == null) // callers currently must use null here if they have a "ref" param (TODO)
			{
				string key = type.ToString() + "_" + methodName;
				if (m_TypeMethodInfo.ContainsKey(key))
				{
					mi = m_TypeMethodInfo[key];
				}
				else
				{
					mi = type.GetMethod(methodName, flags);
					m_TypeMethodInfo[key] = mi;
				}
			}
			else
			{
				string key2 = type.ToString() + "_" + methodName + "_" + parameterTypes.Length.ToString();
				if (m_TypeMethodInfo.ContainsKey(key2))
				{
					mi = m_TypeMethodInfo[key2];
				}
				else
				{
					mi= type.GetMethod(methodName, flags, null,	parameterTypes, null);
					m_TypeMethodInfo[key2] = mi;
				}
			}
#if false
			Trace.Unindent();
#endif
			return mi;
		}