internal static void AddEventHandler <T>(Func <T, EventRegistrationToken> addMethod, Action <EventRegistrationToken> removeMethod, T handler) { Debug.Assert(addMethod != null); Debug.Assert(removeMethod != null); // Add the method, and make a note of the token -> delegate mapping. object instance = removeMethod.Target; #if !RHTESTCL Debug.Assert(instance != null && !(instance is __ComObject)); #endif System.Collections.Generic.Internal.Dictionary <object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod); EventRegistrationToken token = addMethod(handler); try { registrationTokens.LockAcquire(); EventRegistrationTokenList tokens; if (!registrationTokens.TryGetValue(handler, out tokens)) { tokens = new EventRegistrationTokenList(token); registrationTokens[handler] = tokens; } else { bool needCopy = tokens.Push(token); // You need to copy back this list into the dictionary (so that you don't lose change outside dictionary) if (needCopy) { registrationTokens[handler] = tokens; } } #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for managed instance = " + instance + ", handler = " + handler + "\n"); #endif } finally { registrationTokens.LockRelease(); } }
internal static void RemoveAllEventHandlers(Action <EventRegistrationToken> removeMethod) { Debug.Assert(removeMethod != null); object instance = removeMethod.Target; System.Collections.Generic.Internal.Dictionary <object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod); System.Collections.Generic.Internal.List <EventRegistrationToken> tokensToRemove = new System.Collections.Generic.Internal.List <EventRegistrationToken>(); try { registrationTokens.LockAcquire(); // Copy all tokens to tokensToRemove array which later we'll call removeMethod on // outside this lock foreach (EventRegistrationTokenList tokens in registrationTokens.Values) { tokens.CopyTo(tokensToRemove); } // Clear the dictionary - at this point all event handlers are no longer in the cache // but they are not removed yet registrationTokens.Clear(); #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instance + "\n"); #endif } finally { registrationTokens.LockRelease(); } // // Remove all handlers outside the lock // #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instance + "\n"); #endif CallRemoveMethods(removeMethod, tokensToRemove); #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instance + "\n"); #endif }
internal static CCWTemplateInfo GetCCWTemplateDataInfoFromTypeHandle(RuntimeTypeHandle typeHnd) { CCWTemplateInfo ccwTemplateInfo; try { s_runtimeTypeHandleToCCWTemplateInfoMap.LockAcquire(); if (!s_runtimeTypeHandleToCCWTemplateInfoMap.TryGetValue(typeHnd, out ccwTemplateInfo)) { ccwTemplateInfo = GetCCWTemplateDataInfoFromTypeHandleInternal(typeHnd); s_runtimeTypeHandleToCCWTemplateInfoMap.Add(typeHnd, ccwTemplateInfo); } } finally { s_runtimeTypeHandleToCCWTemplateInfoMap.LockRelease(); } return(ccwTemplateInfo); }
internal static McgInterfaceInfo GetInterfaceInfoByHandle(RuntimeTypeHandle typeHnd) { McgInterfaceInfo interfaceInfo; try { s_runtimeTypeHandleToMcgInterfaceInfoMap.LockAcquire(); if (!s_runtimeTypeHandleToMcgInterfaceInfoMap.TryGetValue(typeHnd, out interfaceInfo)) { interfaceInfo = GetInterfaceInfoByHandleInternal(typeHnd); s_runtimeTypeHandleToMcgInterfaceInfoMap.Add(typeHnd, interfaceInfo); } } finally { s_runtimeTypeHandleToMcgInterfaceInfoMap.LockRelease(); } return(interfaceInfo); }
internal static void RemoveEventHandler <T>(Action <EventRegistrationToken> removeMethod, T handler) { Debug.Assert(removeMethod != null); object instance = removeMethod.Target; // // Temporary static event support - this is bad for a couple of reasons: // 1. This will leak the event delegates. Our real implementation fixes that // 2. We need the type itself, but we don't have delegate.Method.DeclaringType ( // but I don't know what is the best replacement). Perhaps this isn't too bad // 3. Unsubscription doesn't work due to ConditionalWeakTable work on reference equality. // I can fix this but I figured it is easier to keep this broken so that we know we'll fix // this (rather than using the slower value equality version which we might forget to fix // later // @TODO - Remove this and replace with real static support (that was #ifdef-ed out) // if (instance == null) { // Because this code only operates for delegates to static methods, the output typehandle of GetFunctionPointer is not used RuntimeTypeHandle thDummy; instance = removeMethod.GetFunctionPointer(out thDummy); } System.Collections.Generic.Internal.Dictionary <object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod); EventRegistrationToken token; try { registrationTokens.LockAcquire(); EventRegistrationTokenList tokens; // Failure to find a registration for a token is not an error - it's simply a no-op. if (!registrationTokens.TryGetValue(handler, out tokens)) { #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instance + ", handler= " + handler + "\n"); #endif return; } // Select a registration token to unregister // We don't care which one but I'm returning the last registered token to be consistent // with native event registration implementation bool moreItems = tokens.Pop(out token); if (!moreItems) { // Remove it from cache if this list become empty // This must be done because EventRegistrationTokenList now becomes invalid // (mostly because there is no safe default value for EventRegistrationToken to express 'no token') // NOTE: We should try to remove registrationTokens itself from cache if it is empty, otherwise // we could run into a race condition where one thread removes it from cache and another thread adds // into the empty registrationToken table registrationTokens.Remove(handler); } } finally { registrationTokens.LockRelease(); } removeMethod(token); #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instance + ", handler = " + handler + ", token = " + token.m_value + "\n"); #endif }