void ProcessRtdCalls() { if (_rtdCalls.Count == 0) { return; } // First, build a dictionary of what we saw, // and add any new active callers. Dictionary <ExcelReference, TopicIdList> callerTopicMap = new Dictionary <ExcelReference, TopicIdList>(); foreach (RtdCall call in _rtdCalls) { // find the corresponding RtdTopicInfo int topic; if (!_activeTopics.TryGetValue(call.TopicKey, out topic)) { Debug.Print("!!! Unknown Rtd Call: " + call.TopicKey); continue; } // This is a call to a topic we know // Check if we already have an entry for this caller in the callerTopicMap.... TopicIdList callerTopics; if (!callerTopicMap.TryGetValue(call.Caller, out callerTopics)) { // ... no - it's a new entry. // Add the caller, and the topic map callerTopics = new TopicIdList(); callerTopicMap[call.Caller] = callerTopics; } // Get the known callers ExcelReferenceSet callers = _activeTopicCallers[topic]; if (!callers.Contains(call.Caller)) { // Previously unknown caller for this topic - add to _activeTopicCallers callers.Add(call.Caller); // Add the Topic to the list of topic to watch for this caller TopicIdList topics; if (!_activeCallerTopics.TryGetValue(call.Caller, out topics)) { // Not seen this caller before for this topic - record for future use topics = new TopicIdList(); _activeCallerTopics[call.Caller] = topics; } // This is a caller we've dealt with before // This topic should not be in the list // TODO: What if it is called twice from a single formula...? Debug.Assert(!topics.Contains(topic)); topics.Add(topic); // NOTE: topics might include the orphans! } // One of the known callers // Anyway - record that we saw it in this calc callerTopics.Add(topic); } // Now figure out what to clean up // For each caller and its topics that we saw in this calc ... TopicIdList orphans = new TopicIdList(); foreach (KeyValuePair <ExcelReference, TopicIdList> callerTopics in callerTopicMap) { ExcelReference thisCalcCaller = callerTopics.Key; TopicIdList thisCalcTopics = callerTopics.Value; // ... Check the topics in the _activeCallerTopics list for this caller. TopicIdList activeTopics = _activeCallerTopics[thisCalcCaller]; TopicIdList activeTopicsToRemove = null; // Lazy initialize foreach (int activeTopic in activeTopics) { // If we've seen the topic in this calc, all is fine. if (thisCalcTopics.Contains(activeTopic)) { continue; } // ... Any topic not seen in this calc might be an orphan (so check if it has other callers). // ... ensure that the active topic also does not have the caller in its activeCallers list any more. ExcelReferenceSet activeCallers = _activeTopicCallers[activeTopic]; if (activeCallers.Remove(thisCalcCaller)) { // - now check if this topic is an orphan if (activeCallers.Count == 0) { orphans.Add(activeTopic); } } // The activeTopic was one of the topics for thisCalcCaller, but is no longer. // Should now be removed from the list of topics for this caller. if (activeTopicsToRemove == null) { activeTopicsToRemove = new TopicIdList(); } activeTopicsToRemove.Add(activeTopic); } if (activeTopicsToRemove != null) { foreach (int topicToRemove in activeTopicsToRemove) { activeTopics.Remove(topicToRemove); if (activeTopics.Count == 0) { // Unlikely...? (due to how the bug works - the caller should have a new topic) _activeCallerTopics.Remove(thisCalcCaller); } } } } // Clear our recording and disconnect the orphans _rtdCalls.Clear(); DisconnectOrphanedTopics(orphans); }
void ProcessRtdCalls() { if (_rtdCalls.Count == 0 && _rtdCompletes.Count == 0) { return; } // First, build a dictionary of what we saw, // and add any new active callers. Dictionary <ExcelReference, TopicIdList> callerTopicMap = new Dictionary <ExcelReference, TopicIdList>(); foreach (RtdCall call in _rtdCalls) { // find the corresponding RtdTopicInfo int topic; if (!_activeTopics.TryGetValue(call.TopicKey, out topic)) { Debug.Print("!!! Unknown Rtd Call: " + call.TopicKey); continue; } // This is a call to a topic we know // Check if we already have an entry for this caller in the callerTopicMap.... TopicIdList callerTopics; if (!callerTopicMap.TryGetValue(call.Caller, out callerTopics)) { // ... no - it's a new entry. // Add the caller, and the topic map callerTopics = new TopicIdList(); callerTopicMap[call.Caller] = callerTopics; } // Get the known callers ExcelReferenceSet callers = _activeTopicCallers[topic]; if (!callers.Contains(call.Caller)) { // Previously unknown caller for this topic - add to _activeTopicCallers callers.Add(call.Caller); // Add the Topic to the list of topic to watch for this caller TopicIdList topics; if (!_activeCallerTopics.TryGetValue(call.Caller, out topics)) { // Not seen this caller before for this topic - record for future use topics = new TopicIdList(); _activeCallerTopics[call.Caller] = topics; } // This is a caller we've dealt with before // This topic should not be in the list // TODO: What if it is called twice from a single formula...? Debug.Assert(!topics.Contains(topic)); topics.Add(topic); // NOTE: topics might include the orphans! } // One of the known callers // Anyway - record that we saw it in this calc callerTopics.Add(topic); } // Process calls that are 'complete' - we can record that we didn't see (i.e. call xlfRtd for) the topic in this call foreach (var call in _rtdCompletes) { // These callers were called, but not with the topics we expected (since there was no real RTD call) // find the corresponding RtdTopicInfo int topic; if (!_activeTopics.TryGetValue(call.TopicKey, out topic)) { Debug.Fail("!!! Unknown Rtd Call: " + call.TopicKey); continue; } // This is a call to a topic we know // Check if we already have an entry for this caller in the callerTopicMap.... TopicIdList callerTopics; if (!callerTopicMap.TryGetValue(call.Caller, out callerTopics)) { // This caller has no topics (in this calculation) // Note that it was called (but we'll add no topics...) // Otherwise it's fine - we've listed this as a caller to examine, but we won't put this topic in callerTopics = new TopicIdList(); callerTopicMap[call.Caller] = callerTopics; } if (callerTopics.Contains(topic)) { Debug.Fail("!!! Inconsistent Rtd Call (RtdCalls contains the RtdComplete call): " + call.TopicKey); } } // Now figure out what to clean up // For each caller and its topics that we saw in this calc ... TopicIdList orphans = new TopicIdList(); foreach (KeyValuePair <ExcelReference, TopicIdList> callerTopics in callerTopicMap) { ExcelReference thisCalcCaller = callerTopics.Key; TopicIdList thisCalcTopics = callerTopics.Value; // ... Check the topics in the _activeCallerTopics list for this caller. TopicIdList activeTopics = _activeCallerTopics[thisCalcCaller]; TopicIdList activeTopicsToRemove = null; // Lazy initialize foreach (int activeTopic in activeTopics) { // If we've seen the topic in this calc, all is fine. if (thisCalcTopics.Contains(activeTopic)) { continue; } // ... Any topic not seen in this calc might be an orphan (so check if it has other callers). // ... ensure that the active topic also does not have the caller in its activeCallers list any more. ExcelReferenceSet activeCallers = _activeTopicCallers[activeTopic]; if (activeCallers.Remove(thisCalcCaller)) { // - now check if this topic is an orphan if (activeCallers.Count == 0) { orphans.Add(activeTopic); } } // The activeTopic was one of the topics for thisCalcCaller, but is no longer. // Should now be removed from the list of topics for this caller. if (activeTopicsToRemove == null) { activeTopicsToRemove = new TopicIdList(); } activeTopicsToRemove.Add(activeTopic); } if (activeTopicsToRemove != null) { foreach (int topicToRemove in activeTopicsToRemove) { activeTopics.Remove(topicToRemove); if (activeTopics.Count == 0) { // This happens if we have completed the topic, and Excel might not disconnect // but the topic is no longer active. // I think Excel will try to Disconnect later, e.g. if we delete the formula or something. _activeCallerTopics.Remove(thisCalcCaller); } } } } // Clear our recording and disconnect the orphans _rtdCalls.Clear(); DisconnectOrphanedTopics(orphans); }