Merge pull request #3442 from lateralusX/jlorenss/win-atexit-commands
[mono.git] / mcs / class / referencesource / mscorlib / system / runtime / interopservices / windowsruntime / windowsruntimemarshal.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 //
7 // <OWNER>[....]</OWNER>
8 // <OWNER>[....]</OWNER>
9 // <OWNER>[....]</OWNER>
10
11 using System;
12 using System.Collections.Generic;
13 using System.Diagnostics.Contracts;
14 using System.Reflection;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Threading;
18 using System.Security;
19
20 namespace System.Runtime.InteropServices.WindowsRuntime
21 {
22     // Helper functions to manually marshal data between .NET and WinRT
23     public static class WindowsRuntimeMarshal
24     {
25         // Add an event handler to a Windows Runtime style event, such that it can be removed via a delegate
26         // lookup at a later time.  This method adds the handler to the add method using the supplied
27         // delegate.  It then stores the corresponding token in a dictionary for easy access by RemoveEventHandler
28         // later.  Note that the dictionary is indexed by the remove method that will be used for RemoveEventHandler
29         // so the removeMethod given here must match the remove method supplied there exactly.
30         [SecurityCritical]
31         public static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod,
32                                               Action<EventRegistrationToken> removeMethod,
33                                               T handler)
34         {
35             if (addMethod == null)
36                 throw new ArgumentNullException("addMethod");
37             if (removeMethod == null)
38                 throw new ArgumentNullException("removeMethod");
39             Contract.EndContractBlock();
40
41             // Managed code allows adding a null event handler, the effect is a no-op.  To match this behavior
42             // for WinRT events, we simply ignore attempts to add null.
43             if (handler == null)
44             {
45                 return;
46             }
47
48             // Delegate to managed event registration implementation or native event registration implementation
49             // They have completely different implementation because native side has its own unique problem to solve -
50             // there could be more than one RCW for the same COM object
51             // it would be more confusing and less-performant if we were to merge them together
52             object target = removeMethod.Target;
53             if (target == null || Marshal.IsComObject(target))
54                 NativeOrStaticEventRegistrationImpl.AddEventHandler<T>(addMethod, removeMethod, handler);
55             else
56                 ManagedEventRegistrationImpl.AddEventHandler<T>(addMethod, removeMethod, handler);
57         }
58
59         // Remove the delegate handler from the Windows Runtime style event registration by looking for
60         // its token, previously stored via AddEventHandler<T>
61         [SecurityCritical]
62         public static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler)
63         {
64             if (removeMethod == null)
65                 throw new ArgumentNullException("removeMethod");
66             Contract.EndContractBlock();
67
68             // Managed code allows removing a null event handler, the effect is a no-op.  To match this behavior
69             // for WinRT events, we simply ignore attempts to remove null.
70             if (handler == null)
71             {
72                 return;
73             }
74
75             // Delegate to managed event registration implementation or native event registration implementation
76             // They have completely different implementation because native side has its own unique problem to solve -
77             // there could be more than one RCW for the same COM object
78             // it would be more confusing and less-performant if we were to merge them together
79             object target = removeMethod.Target;
80             if (target == null || Marshal.IsComObject(target))
81                 NativeOrStaticEventRegistrationImpl.RemoveEventHandler<T>(removeMethod, handler);
82             else
83                 ManagedEventRegistrationImpl.RemoveEventHandler<T>(removeMethod, handler);            
84         }
85         
86         [SecurityCritical]
87         public static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod)
88         {
89             if (removeMethod == null)
90                 throw new ArgumentNullException("removeMethod");
91             Contract.EndContractBlock();
92
93             // Delegate to managed event registration implementation or native event registration implementation
94             // They have completely different implementation because native side has its own unique problem to solve -
95             // there could be more than one RCW for the same COM object
96             // it would be more confusing and less-performant if we were to merge them together
97             object target = removeMethod.Target;
98             if (target == null || Marshal.IsComObject(target))
99                 NativeOrStaticEventRegistrationImpl.RemoveAllEventHandlers(removeMethod);
100             else
101                 ManagedEventRegistrationImpl.RemoveAllEventHandlers(removeMethod);
102         }
103
104         // Returns the total cache size
105         // Used by test only to verify we don't leak event cache
106         internal static int GetRegistrationTokenCacheSize()
107         {
108             int count = 0;
109
110             if (ManagedEventRegistrationImpl.s_eventRegistrations != null)
111             {
112                 lock (ManagedEventRegistrationImpl.s_eventRegistrations)
113                 {
114                     count += ManagedEventRegistrationImpl.s_eventRegistrations.Keys.Count;
115                 }
116             }
117             
118             if (NativeOrStaticEventRegistrationImpl.s_eventRegistrations != null)
119             {
120                 lock (NativeOrStaticEventRegistrationImpl.s_eventRegistrations)
121                 {
122                     count += NativeOrStaticEventRegistrationImpl.s_eventRegistrations.Count;
123                 }
124             }
125             
126             return count;
127         }
128
129         //
130         // Optimized version of List of EventRegistrationToken
131         // It is made a struct to reduce overhead
132         //
133         internal struct EventRegistrationTokenList 
134         {
135             private EventRegistrationToken          firstToken;     // Optimization for common case where there is only one token
136             private List<EventRegistrationToken>    restTokens;     // Rest of the tokens
137             
138             internal EventRegistrationTokenList(EventRegistrationToken token)
139             {
140                 firstToken = token;
141                 restTokens = null;
142             }
143
144             internal EventRegistrationTokenList(EventRegistrationTokenList list)
145             {
146                 firstToken = list.firstToken;
147                 restTokens = list.restTokens;
148             }
149
150             // Push a new token into this list
151             // Returns true if you need to copy back this list into the dictionary (so that you 
152             // don't lose change outside the dictionary). false otherwise.
153             public bool Push(EventRegistrationToken token)
154             {
155                 bool needCopy = false;
156                 
157                 if (restTokens == null)
158                 {
159                     restTokens = new List<EventRegistrationToken>();
160                     needCopy = true;
161                 }
162                 
163                 restTokens.Add(token);
164
165                 return needCopy;
166             }
167         
168             // Pops the last token
169             // Returns false if no more tokens left, true otherwise
170             public bool Pop(out EventRegistrationToken token)
171             {
172                 // Only 1 token in this list and we just removed the last token
173                 if (restTokens == null || restTokens.Count == 0)
174                 {
175                     token = firstToken;
176                     return false;
177                 }
178         
179                 int last = restTokens.Count - 1;
180                 token = restTokens[last];
181                 restTokens.RemoveAt(last);
182                 
183                 return true;
184             }
185         
186             public void CopyTo(List<EventRegistrationToken> tokens)
187             {
188                 tokens.Add(firstToken);
189                 if (restTokens != null)
190                     tokens.AddRange(restTokens);
191             }
192         }
193
194         //
195         // Event registration support for managed objects events & static events
196         //
197         internal static class ManagedEventRegistrationImpl
198         {            
199             // Mappings of delegates registered for events -> their registration tokens.
200             // These mappings are stored indexed by the remove method which can be used to undo the registrations.
201             //
202             // The full structure of this table is:
203             //   object the event is being registered on ->
204             //      Table [RemoveMethod] -> 
205             //        Table [Handler] -> Token
206             //
207             // Note: There are a couple of optimizations I didn't do here because they don't make sense for managed events:
208             // 1.  Flatten the event cache (see EventCacheKey in native WinRT event implementation below)
209             //
210             //     This is because managed events use ConditionalWeakTable to hold Objects->(Event->(Handler->Tokens)), 
211             //     and when object goes away everything else will be nicely cleaned up. If I flatten it like native WinRT events, 
212             //     I'll have to use Dictionary (as ConditionalWeakTable won't work - nobody will hold the new key alive anymore) 
213             //     instead, and that means I'll have to add more code from native WinRT events into managed WinRT event to support 
214             //     self-cleanup in the finalization, as well as reader/writer lock to protect against ----s in the finalization, 
215             //     which adds a lot more complexity and doesn't really worth it.
216             // 
217             // 2.  Use conditionalWeakTable to hold Handler->Tokens. 
218             // 
219             //     The reason is very simple - managed object use dictionary (see EventRegistrationTokenTable) to hold delegates alive. 
220             //     If the delegates aren't alive, it means either they have been unsubscribed, or the object itself is gone, 
221             //     and in either case, they've been already taken care of.
222             // 
223             internal volatile static 
224                 ConditionalWeakTable<object, Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>>> s_eventRegistrations = 
225                     new ConditionalWeakTable<object, Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>>>();
226     
227             [SecurityCritical]
228             internal static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod,
229                                                   Action<EventRegistrationToken> removeMethod,
230                                                   T handler)
231             {
232                 Contract.Requires(addMethod != null);
233                 Contract.Requires(removeMethod != null);
234
235                 // Add the method, and make a note of the token -> delegate mapping.
236                 object instance = removeMethod.Target;
237                 Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod);
238                 EventRegistrationToken token = addMethod(handler);
239                 lock (registrationTokens)
240                 {
241                     EventRegistrationTokenList tokens;
242                     if (!registrationTokens.TryGetValue(handler, out tokens))
243                     {
244                         tokens = new EventRegistrationTokenList(token);
245                         registrationTokens[handler] = tokens;
246                     }
247                     else
248                     {
249                         bool needCopy = tokens.Push(token);
250
251                         // You need to copy back this list into the dictionary (so that you don't lose change outside dictionary)
252                         if (needCopy)
253                             registrationTokens[handler] = tokens;
254                     }
255                     
256                     BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for managed instance = " + instance + ", handler = " + handler + "\n");
257                 }
258             }
259     
260             // Get the event registration token table for an event.  These are indexed by the remove method of the event.
261             private static Dictionary<object, EventRegistrationTokenList> GetEventRegistrationTokenTable(object instance, Action<EventRegistrationToken> removeMethod)
262             {
263                 Contract.Requires(instance != null);
264                 Contract.Requires(removeMethod != null);
265                 Contract.Requires(s_eventRegistrations != null);    
266     
267                 lock (s_eventRegistrations)
268                 {
269                     Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>> instanceMap = null;
270                     if (!s_eventRegistrations.TryGetValue(instance, out instanceMap))
271                     {
272                         instanceMap = new Dictionary<MethodInfo, Dictionary<object, EventRegistrationTokenList>>();
273                         s_eventRegistrations.Add(instance, instanceMap);
274                     }
275     
276                     Dictionary<object, EventRegistrationTokenList> tokens = null;
277                     if (!instanceMap.TryGetValue(removeMethod.Method, out tokens))
278                     {
279                         tokens = new Dictionary<object, EventRegistrationTokenList>();
280                         instanceMap.Add(removeMethod.Method, tokens);
281                     }
282     
283                     return tokens;
284                 }
285             }
286
287             [SecurityCritical]
288             internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler)
289             {
290                 Contract.Requires(removeMethod != null);
291
292                 object instance = removeMethod.Target;
293                 Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod);
294                 EventRegistrationToken token;
295     
296                 lock (registrationTokens)
297                 {
298                     EventRegistrationTokenList tokens;
299     
300                     // Failure to find a registration for a token is not an error - it's simply a no-op.
301                     if (!registrationTokens.TryGetValue(handler, out tokens))
302                     {
303                         BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instance + ", handler= " + handler + "\n"); 
304                         
305                         return;
306                     }
307     
308                     // Select a registration token to unregister
309                     // We don't care which one but I'm returning the last registered token to be consistent
310                     // with native event registration implementation                    
311                     bool moreItems = tokens.Pop(out token);
312                     if (!moreItems)
313                     {
314                         // Remove it from cache if this list become empty
315                         // This must be done because EventRegistrationTokenList now becomes invalid 
316                         // (mostly because there is no safe default value for EventRegistrationToken to express 'no token')
317                         // NOTE: We should try to remove registrationTokens itself from cache if it is empty, otherwise
318                         // we could run into a race condition where one thread removes it from cache and another thread adds
319                         // into the empty registrationToken table
320                         registrationTokens.Remove(handler);
321                     }
322                 }
323     
324                 removeMethod(token);
325
326                 BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instance + ", handler = " + handler + ", token = " + token.m_value + "\n");                
327             }
328
329             [SecurityCritical]
330             internal static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod)
331             {
332                 Contract.Requires(removeMethod != null);                                        
333
334                 object instance = removeMethod.Target;
335                 Dictionary<object, EventRegistrationTokenList> registrationTokens = GetEventRegistrationTokenTable(instance, removeMethod);
336
337                 List<EventRegistrationToken> tokensToRemove = new List<EventRegistrationToken>();
338                 
339                 lock (registrationTokens)
340                 {                
341                     // Copy all tokens to tokensToRemove array which later we'll call removeMethod on
342                     // outside this lock
343                     foreach (EventRegistrationTokenList tokens in registrationTokens.Values)
344                     {
345                         tokens.CopyTo(tokensToRemove);
346                     }
347
348                     // Clear the dictionary - at this point all event handlers are no longer in the cache
349                     // but they are not removed yet
350                     registrationTokens.Clear();
351                     BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instance + "\n");
352                 }
353
354                 //
355                 // Remove all handlers outside the lock
356                 //
357                 BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instance + "\n");                    
358                 CallRemoveMethods(removeMethod, tokensToRemove);
359                 BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instance + "\n");                    
360             }
361         }
362
363         //
364         // WinRT event registration implementation code
365         //
366         internal static class NativeOrStaticEventRegistrationImpl
367         {     
368             //
369             // Key = (target object, event)
370             // We use a key of object+event to save an extra dictionary
371             //
372             internal struct EventCacheKey
373             {
374                 internal object      target;
375                 internal MethodInfo  method;
376
377                 public override string ToString()
378                 {
379                     return "(" + target + ", " + method + ")";
380                 }
381             }
382
383             internal class EventCacheKeyEqualityComparer : IEqualityComparer<EventCacheKey>
384             {
385                 public bool Equals(EventCacheKey lhs, EventCacheKey rhs)
386                 {
387                     return (Object.Equals(lhs.target, rhs.target) && Object.Equals(lhs.method, rhs.method));
388                 }
389
390                 public int GetHashCode(EventCacheKey key)
391                 {
392                     return key.target.GetHashCode() ^ key.method.GetHashCode();
393                 }
394             }
395             
396             //
397             // EventRegistrationTokenListWithCount
398             // 
399             // A list of EventRegistrationTokens that maintains a count
400             //
401             // The reason this needs to be a separate class is that we need a finalizer for this class
402             // If the delegate is collected, it will take this list away with it (due to dependent handles), 
403             // and we need to remove the PerInstancEntry from cache
404             // See ~EventRegistrationTokenListWithCount for more details
405             //
406             internal class EventRegistrationTokenListWithCount
407             {
408                 private TokenListCount          _tokenListCount;
409                 EventRegistrationTokenList      _tokenList;
410                 
411                 internal EventRegistrationTokenListWithCount(TokenListCount tokenListCount, EventRegistrationToken token)
412                 {
413                     _tokenListCount = tokenListCount;
414                     _tokenListCount.Inc();
415
416                     _tokenList = new EventRegistrationTokenList(token);
417                 }
418                 
419                 ~EventRegistrationTokenListWithCount()
420                 {   
421                     // Decrement token list count
422                     // This is need to correctly keep trace of number of tokens for EventCacheKey
423                     // and remove it from cache when the token count drop to 0
424                     // we don't need to take locks for decrement the count - we only need to take a global
425                     // lock when we decide to destroy cache for the IUnknown */type instance
426                     BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finalizing EventRegistrationTokenList for " + _tokenListCount.Key + "\n");                
427                     _tokenListCount.Dec();
428                 }
429                 
430                 public void Push(EventRegistrationToken token)
431                 {
432                     // Since EventRegistrationTokenListWithCount is a reference type, there is no need
433                     // to copy back. Ignore the return value
434                     _tokenList.Push(token);
435                 }
436             
437                 public bool Pop(out EventRegistrationToken token)
438                 {
439                     return _tokenList.Pop(out token);
440                 }
441             
442                 public void CopyTo(List<EventRegistrationToken> tokens)
443                 {
444                     _tokenList.CopyTo(tokens);
445                 }
446             }
447
448             //
449             // Maintains the number of tokens for a particular EventCacheKey
450             // TokenListCount is a class for two reasons:
451             // 1. Efficient update in the Dictionary to avoid lookup twice to update the value
452             // 2. Update token count without taking a global lock. Only takes a global lock when drop to 0
453             //
454             internal class TokenListCount
455             {
456                 private int             _count;
457                 private EventCacheKey   _key;
458
459                 internal TokenListCount(EventCacheKey key)
460                 {
461                     _key = key;
462                 }
463
464                 internal EventCacheKey Key
465                 {
466
467                     get { return _key; }
468                 }
469                 
470                 internal void Inc()
471                 {
472                     int newCount = Interlocked.Increment(ref _count);
473                     BCLDebug.Log("INTEROP", "[WinRT_Eventing] Incremented TokenListCount for " + _key + ", Value = " + newCount + "\n");           
474                 }
475
476                 internal void Dec()
477                 {
478                     // Avoid racing with Add/Remove event entries into the cache
479                     // You don't want this removing the key in the middle of a Add/Remove
480                     s_eventCacheRWLock.AcquireWriterLock(Timeout.Infinite);
481                     try
482                     {
483                         int newCount = Interlocked.Decrement(ref _count);
484                         BCLDebug.Log("INTEROP", "[WinRT_Eventing] Decremented TokenListCount for " + _key + ", Value = " + newCount + "\n");                           
485                         if (newCount == 0)
486                             CleanupCache();
487                     }
488                     finally
489                     {
490                         s_eventCacheRWLock.ReleaseWriterLock();
491                     }
492                 }
493
494                 private void CleanupCache()
495                 {
496                     // Time to destroy cache for this IUnknown */type instance
497                     // because the total token list count has dropped to 0 and we don't have any events subscribed
498                     Contract.Requires(s_eventRegistrations != null);
499
500                     BCLDebug.Log("INTEROP", "[WinRT_Eventing] Removing " + _key + " from cache" + "\n");                
501                     s_eventRegistrations.Remove(_key);
502                     BCLDebug.Log("INTEROP", "[WinRT_Eventing] s_eventRegistrations size = " + s_eventRegistrations.Count + "\n");
503                 }
504             }
505
506             internal struct EventCacheEntry
507             {
508                 // [Handler] -> Token
509                 internal ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTable;
510
511                 // Maintains current total count for the EventRegistrationTokenListWithCount for this event cache key
512                 internal TokenListCount tokenListCount;
513             }
514
515             // Mappings of delegates registered for events -> their registration tokens.
516             // These mappings are stored indexed by the remove method which can be used to undo the registrations.
517             //
518             // The full structure of this table is:
519             //   EventCacheKey (instanceKey, eventMethod) -> EventCacheEntry (Handler->tokens)
520             //   
521             // A InstanceKey is the IUnknown * or static type instance
522             //
523             // Couple of things to note:
524             // 1. We need to use IUnknown* because we want to be able to unscribe to the event for another RCW
525             // based on the same COM object. For example:
526             //    m_canvas.GetAt(0).Event += Func;
527             //    m_canvas.GetAt(0).Event -= Func;  // GetAt(0) might create a new RCW
528             // 
529             // 2. Handler->Token is a ConditionalWeakTable because we don't want to keep the delegate alive
530             // and we want EventRegistrationTokenListWithCount to be finalized after the delegate is no longer alive 
531             // 3. It is possible another COM object is created at the same address
532             // before the entry in cache is destroyed. More specifically, 
533             //   a. The same delegate is being unsubscribed. In this case we'll give them a 
534             //   stale token - unlikely to be a problem
535             //   b. The same delegate is subscribed then unsubscribed. We need to make sure give
536             //   them the latest token in this case. This is guaranteed by always giving the last token and always use equality to
537             //   add/remove event handlers
538             internal volatile static Dictionary<EventCacheKey, EventCacheEntry> s_eventRegistrations = 
539                 new Dictionary<EventCacheKey, EventCacheEntry>(new EventCacheKeyEqualityComparer());
540
541             // Prevent add/remove handler code to run at the same with with cache cleanup code
542             private volatile static MyReaderWriterLock s_eventCacheRWLock = new MyReaderWriterLock();
543
544             // Get InstanceKey to use in the cache
545             [SecuritySafeCritical]
546             private static object GetInstanceKey(Action<EventRegistrationToken> removeMethod)
547             {
548                 object target = removeMethod.Target;
549                 Contract.Assert(target == null || Marshal.IsComObject(target), "Must be null or a RCW");
550                 if (target == null)
551                     return removeMethod.Method.DeclaringType;
552                 
553                 // Need the "Raw" IUnknown pointer for the RCW that is not bound to the current context
554                 return (object) Marshal.GetRawIUnknownForComObjectNoAddRef(target);
555             }
556             
557             [SecurityCritical]
558             internal static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod,
559                                                   Action<EventRegistrationToken> removeMethod,
560                                                   T handler)
561             {
562                 // The instanceKey will be IUnknown * of the target object
563                 object instanceKey = GetInstanceKey(removeMethod);
564
565                 // Call addMethod outside of RW lock
566                 // At this point we don't need to worry about race conditions and we can avoid deadlocks 
567                 // if addMethod waits on finalizer thread
568                 // If we later throw we need to remove the method
569                 EventRegistrationToken token = addMethod(handler);
570
571                 bool tokenAdded = false;
572                 
573                 try
574                 {
575                     EventRegistrationTokenListWithCount tokens;
576                     
577                     //
578                     // The whole add/remove code has to be protected by a reader/writer lock
579                     // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time
580                     //
581                     s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite);
582                     try
583                     {
584                         // Add the method, and make a note of the delegate -> token mapping.
585                         TokenListCount tokenListCount;
586                         ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetOrCreateEventRegistrationTokenTable(instanceKey, removeMethod, out tokenListCount);
587                         lock (registrationTokens)
588                         {
589                             //
590                             // We need to find the key that equals to this handler
591                             // Suppose we have 3 handlers A, B, C that are equal (refer to the same object and method),
592                             // the first handler (let's say A) will be used as the key and holds all the tokens. 
593                             // We don't need to hold onto B and C, because the COM object itself will keep them alive,
594                             // and they won't die anyway unless the COM object dies or they get unsubscribed.
595                             // It may appear that it is fine to hold A, B, C, and add them and their corresponding tokens
596                             // into registrationTokens table. However, this is very dangerous, because this COM object
597                             // may die, but A, B, C might not get collected yet, and another COM object comes into life
598                             // with the same IUnknown address, and we subscribe event B. In this case, the right token
599                             // will be added into B's token list, but once we unsubscribe B, we might end up removing
600                             // the last token in C, and that may lead to crash.
601                             //
602                             object key = registrationTokens.FindEquivalentKeyUnsafe(handler, out tokens);
603                             if (key == null)
604                             {
605                                 tokens = new EventRegistrationTokenListWithCount(tokenListCount, token);
606                                 registrationTokens.Add(handler, tokens);
607                             }
608                             else
609                             {
610                                 tokens.Push(token);
611                             }
612                             
613                             tokenAdded = true;                            
614                         }
615                     }
616                     finally
617                     {
618                         s_eventCacheRWLock.ReleaseReaderLock();
619                     }
620
621                     BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for instance = " + instanceKey + ", handler = " + handler + "\n");                    
622                 }
623                 catch(Exception)
624                 {   
625                     // If we've already added the token and go there, we don't need to "UNDO" anything
626                     if (!tokenAdded)
627                     {
628                         // Otherwise, "Undo" addMethod if any exception occurs
629                         // There is no need to cleanup our data structure as we haven't added the token yet
630                         removeMethod(token);
631                     }
632
633                 
634                     throw;                    
635                 }
636             }
637
638             private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetEventRegistrationTokenTableNoCreate(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount)
639             {
640                 Contract.Requires(instance != null);
641                 Contract.Requires(removeMethod != null);
642
643                 return GetEventRegistrationTokenTableInternal(instance, removeMethod, out tokenListCount, /* createIfNotFound = */ false);
644             }
645
646             private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetOrCreateEventRegistrationTokenTable(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount)
647             {
648                 Contract.Requires(instance != null);
649                 Contract.Requires(removeMethod != null);
650
651                 return GetEventRegistrationTokenTableInternal(instance, removeMethod, out tokenListCount, /* createIfNotFound = */ true);
652             }
653             
654             // Get the event registration token table for an event.  These are indexed by the remove method of the event.
655             private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetEventRegistrationTokenTableInternal(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount, bool createIfNotFound)
656             {
657                 Contract.Requires(instance != null);
658                 Contract.Requires(removeMethod != null);
659                 Contract.Requires(s_eventRegistrations != null);    
660
661                 EventCacheKey eventCacheKey;
662                 eventCacheKey.target = instance;
663                 eventCacheKey.method = removeMethod.Method;
664                 
665                 lock (s_eventRegistrations)
666                 {
667                     EventCacheEntry eventCacheEntry;
668                     if (!s_eventRegistrations.TryGetValue(eventCacheKey, out eventCacheEntry))
669                     {
670                         if (!createIfNotFound)
671                         {
672                             // No need to create an entry in this case
673                             tokenListCount = null;
674                             return null;
675                         }
676                         
677                         BCLDebug.Log("INTEROP", "[WinRT_Eventing] Adding (" + instance + "," + removeMethod.Method + ") into cache" + "\n");
678                     
679                         eventCacheEntry = new EventCacheEntry();
680                         eventCacheEntry.registrationTable = new ConditionalWeakTable<object, EventRegistrationTokenListWithCount>();
681                         eventCacheEntry.tokenListCount = new TokenListCount(eventCacheKey);
682                         
683                         s_eventRegistrations.Add(eventCacheKey, eventCacheEntry);
684                     }
685                     
686                     tokenListCount = eventCacheEntry.tokenListCount;
687                     
688                     return eventCacheEntry.registrationTable;
689                 }
690             }
691
692             [SecurityCritical]
693             internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler)
694             {
695                 object instanceKey = GetInstanceKey(removeMethod);
696
697                 EventRegistrationToken token;
698                 
699                 //
700                 // The whole add/remove code has to be protected by a reader/writer lock
701                 // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time
702                 //
703                 s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite);
704                 try
705                 {
706                     TokenListCount tokenListCount;
707                     ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod, out tokenListCount);
708                     if (registrationTokens == null)
709                     {
710                         // We have no information regarding this particular instance (IUnknown*/type) - just return
711                         // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance
712                         BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instanceKey + ", handler= " + handler + "\n"); 
713                         return;
714                     }
715                     
716                     lock (registrationTokens)
717                     {
718                         EventRegistrationTokenListWithCount tokens;
719
720                         // Note:
721                         // When unsubscribing events, we allow subscribing the event using a different delegate
722                         // (but with the same object/method), so we need to find the first delegate that matches
723                         // and unsubscribe it
724                         // It actually doesn't matter which delegate - as long as it matches
725                         // Note that inside TryGetValueWithValueEquality we assumes that any delegate 
726                         // with the same value equality would have the same hash code
727                         object key = registrationTokens.FindEquivalentKeyUnsafe(handler, out tokens);
728                         Contract.Assert((key != null && tokens != null) || (key == null && tokens == null), 
729                                         "key and tokens must be both null or non-null");
730                         if (tokens == null)
731                         {
732                             // Failure to find a registration for a token is not an error - it's simply a no-op.
733                             BCLDebug.Log("INTEROP", "[WinRT_Eventing] no token list found for instance=" + instanceKey + ", handler= " + handler + "\n"); 
734                             return;
735                         }
736
737                         // Select a registration token to unregister
738                         // Note that we need to always get the last token just in case another COM object
739                         // is created at the same address before the entry for the old one goes away.
740                         // See comments above s_eventRegistrations for more details
741                         bool moreItems = tokens.Pop(out token);
742                         
743                         // If the last token is removed from token list, we need to remove it from the cache
744                         // otherwise FindEquivalentKeyUnsafe may found this empty token list even though there could be other
745                         // equivalent keys in there with non-0 token list
746                         if (!moreItems)
747                         {
748                             // Remove it from (handler)->(tokens)
749                             // NOTE: We should not check whether registrationTokens has 0 entries and remove it from the cache
750                             // (just like managed event implementation), because this might ---- with the finalizer of 
751                             // EventRegistrationTokenList
752                             registrationTokens.Remove(key);
753                         }
754                         
755                         BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instanceKey + ", handler = " + handler + ", token = " + token.m_value + "\n");                
756                     }
757                 }
758                 finally
759                 {
760                     s_eventCacheRWLock.ReleaseReaderLock();
761                 }
762
763                 // Call removeMethod outside of RW lock
764                 // At this point we don't need to worry about race conditions and we can avoid deadlocks 
765                 // if removeMethod waits on finalizer thread
766                 removeMethod(token);            
767             }
768
769             [SecurityCritical]
770             internal static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod)
771             {
772                 object instanceKey = GetInstanceKey(removeMethod);
773
774                 List<EventRegistrationToken> tokensToRemove = new List<EventRegistrationToken>();
775                 
776                 //
777                 // The whole add/remove code has to be protected by a reader/writer lock
778                 // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time
779                 //
780                 s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite);
781                 try
782                 {
783                     TokenListCount tokenListCount;
784                     ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod, out tokenListCount);
785                     if (registrationTokens == null)
786                     {
787                         // We have no information regarding this particular instance (IUnknown*/type) - just return
788                         // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance
789                         return;
790                     }
791                     
792                     lock (registrationTokens)
793                     {
794                         // Copy all tokens to tokensToRemove array which later we'll call removeMethod on
795                         // outside this lock
796                         foreach (EventRegistrationTokenListWithCount tokens in registrationTokens.Values)
797                         {
798                             tokens.CopyTo(tokensToRemove);
799                         }
800
801                         // Clear the table - at this point all event handlers are no longer in the cache
802                         // but they are not removed yet
803                         registrationTokens.Clear();
804                         BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instanceKey + "\n");                    
805                     }
806                 }
807                 finally
808                 {
809                     s_eventCacheRWLock.ReleaseReaderLock();
810                 }
811
812                 //
813                 // Remove all handlers outside the lock
814                 //
815                 BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instanceKey + "\n");                    
816                 CallRemoveMethods(removeMethod, tokensToRemove);
817                 BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instanceKey + "\n");                    
818             }
819             
820
821             internal class ReaderWriterLockTimedOutException : ApplicationException
822             {
823             }
824
825             /// I borrowed Vance's reader writer lock implementation from his blog as ReaderWriterLockSlim is
826             /// available in System.Core.dll!
827             ///
828             /// <summary>
829             /// A reader-writer lock implementation that is intended to be simple, yet very
830             /// efficient.  In particular only 1 interlocked operation is taken for any lock 
831             /// operation (we use spin locks to achieve this).  The spin lock is never held
832             /// for more than a few instructions (in particular, we never call event APIs
833             /// or in fact any non-trivial API while holding the spin lock).   
834             /// 
835             /// Currently this ReaderWriterLock does not support recurision, however it is 
836             /// not hard to add 
837             /// </summary>
838             internal class MyReaderWriterLock
839             {
840                 // Lock specifiation for myLock:  This lock protects exactly the local fields associted
841                 // instance of MyReaderWriterLock.  It does NOT protect the memory associted with the
842                 // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent).
843                 int myLock;
844
845                 // Who owns the lock owners > 0 => readers
846                 // owners = -1 means there is one writer.  Owners must be >= -1.  
847                 int owners;
848
849                 // These variables allow use to avoid Setting events (which is expensive) if we don't have to. 
850                 uint numWriteWaiters;        // maximum number of threads that can be doing a WaitOne on the writeEvent 
851                 uint numReadWaiters;         // maximum number of threads that can be doing a WaitOne on the readEvent
852
853                 // conditions we wait on. 
854                 EventWaitHandle writeEvent;    // threads waiting to aquire a write lock go here.
855                 EventWaitHandle readEvent;     // threads waiting to aquire a read lock go here (will be released in bulk)
856
857                 internal MyReaderWriterLock()
858                 {
859                     // All state can start out zeroed. 
860                 }
861
862                 internal void AcquireReaderLock(int millisecondsTimeout)
863                 {
864                     EnterMyLock();
865                     for (; ; )
866                     {
867                         // We can enter a read lock if there are only read-locks have been given out
868                         // and a writer is not trying to get in.  
869                         if (owners >= 0 && numWriteWaiters == 0)
870                         {
871                             // Good case, there is no contention, we are basically done
872                             owners++;       // Indicate we have another reader
873                             break;
874                         }
875
876                         // Drat, we need to wait.  Mark that we have waiters and wait.  
877                         if (readEvent == null)      // Create the needed event 
878                         {
879                             LazyCreateEvent(ref readEvent, false);
880                             continue;   // since we left the lock, start over. 
881                         }
882
883                         WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout);
884                     }
885                     ExitMyLock();
886                 }
887
888                 internal void AcquireWriterLock(int millisecondsTimeout)
889                 {
890                     EnterMyLock();
891                     for (; ; )
892                     {
893                         if (owners == 0)
894                         {
895                             // Good case, there is no contention, we are basically done
896                             owners = -1;    // indicate we have a writer.
897                             break;
898                         }
899
900                         // Drat, we need to wait.  Mark that we have waiters and wait.
901                         if (writeEvent == null)     // create the needed event.
902                         {
903                             LazyCreateEvent(ref writeEvent, true);
904                             continue;   // since we left the lock, start over. 
905                         }
906
907                         WaitOnEvent(writeEvent, ref numWriteWaiters, millisecondsTimeout);
908                     }
909                     ExitMyLock();
910                 }
911
912                 internal void ReleaseReaderLock()
913                 {
914                     EnterMyLock();
915                     Contract.Assert(owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken");
916                     --owners;
917                     ExitAndWakeUpAppropriateWaiters();
918                 }
919
920                 internal void ReleaseWriterLock()
921                 {
922                     EnterMyLock();
923                     Contract.Assert(owners == -1, "Calling ReleaseWriterLock when no write lock is held");
924                     owners++;
925                     ExitAndWakeUpAppropriateWaiters();
926                 }
927
928                 /// <summary>
929                 /// A routine for lazily creating a event outside the lock (so if errors
930                 /// happen they are outside the lock and that we don't do much work
931                 /// while holding a spin lock).  If all goes well, reenter the lock and
932                 /// set 'waitEvent' 
933                 /// </summary>
934                 private void LazyCreateEvent(ref EventWaitHandle waitEvent, bool makeAutoResetEvent) {
935                     Contract.Assert(myLock != 0, "Lock must be held");
936                     Contract.Assert(waitEvent == null, "Wait event must be null");
937
938                     ExitMyLock();
939                     EventWaitHandle newEvent;
940                     if (makeAutoResetEvent) 
941                         newEvent = new AutoResetEvent(false);
942                     else 
943                         newEvent = new ManualResetEvent(false);
944                     EnterMyLock();
945                     if (waitEvent == null)          // maybe someone snuck in. 
946                         waitEvent = newEvent;
947                 }
948
949                 /// <summary>
950                 /// Waits on 'waitEvent' with a timeout of 'millisceondsTimeout.  
951                 /// Before the wait 'numWaiters' is incremented and is restored before leaving this routine.
952                 /// </summary>
953                 private void WaitOnEvent(EventWaitHandle waitEvent, ref uint numWaiters, int millisecondsTimeout)
954                 {
955                     Contract.Assert(myLock != 0, "Lock must be held");
956
957                     waitEvent.Reset();
958                     numWaiters++;
959
960                     bool waitSuccessful = false;
961                     ExitMyLock();      // Do the wait outside of any lock 
962                     try
963                     {
964                         if (!waitEvent.WaitOne(millisecondsTimeout, false))
965                             throw new ReaderWriterLockTimedOutException();
966                         
967                         waitSuccessful = true;
968                     }
969                     finally
970                     {
971                         EnterMyLock();
972                         --numWaiters;
973                         if (!waitSuccessful)        // We are going to throw for some reason.  Exit myLock. 
974                             ExitMyLock();
975                     }
976                 }
977
978                 /// <summary>
979                 /// Determines the appropriate events to set, leaves the locks, and sets the events. 
980                 /// </summary>
981                 private void ExitAndWakeUpAppropriateWaiters()
982                 {
983                     Contract.Assert(myLock != 0, "Lock must be held");
984
985                     if (owners == 0 && numWriteWaiters > 0)
986                     {
987                         ExitMyLock();      // Exit before signaling to improve efficiency (wakee will need the lock)
988                         writeEvent.Set();   // release one writer. 
989                     }
990                     else if (owners >= 0 && numReadWaiters != 0)
991                     {
992                         ExitMyLock();    // Exit before signaling to improve efficiency (wakee will need the lock)
993                         readEvent.Set();  // release all readers. 
994                     }
995                     else
996                         ExitMyLock();
997                 }
998
999                 private void EnterMyLock() {
1000                     if (Interlocked.CompareExchange(ref myLock, 1, 0) != 0)
1001                         EnterMyLockSpin();
1002                 }
1003
1004                 private void EnterMyLockSpin()
1005                 {
1006                     for (int i = 0; ;i++)
1007                     {
1008                         if (i < 3 && Environment.ProcessorCount > 1)
1009                             Thread.SpinWait(20);    // Wait a few dozen instructions to let another processor release lock. 
1010                         else 
1011                             Thread.Sleep(0);        // Give up my quantum.  
1012
1013                         if (Interlocked.CompareExchange(ref myLock, 1, 0) == 0)
1014                             return;
1015                     }
1016                 }
1017                 private void ExitMyLock()
1018                 {
1019                     Contract.Assert(myLock != 0, "Exiting spin lock that is not held");
1020                     myLock = 0;
1021                 }
1022             };            
1023         }
1024
1025         //
1026         // Call removeMethod on each token and aggregate all exceptions thrown from removeMethod into one in case of failure
1027         //
1028         internal static void CallRemoveMethods(Action<EventRegistrationToken> removeMethod, List<EventRegistrationToken> tokensToRemove)
1029         {
1030
1031             List<Exception> exceptions = new List<Exception>();
1032         
1033             foreach (EventRegistrationToken token in tokensToRemove)
1034             {
1035                 try
1036                 {
1037                     removeMethod(token);
1038                 }
1039                 catch(Exception ex)
1040                 {
1041                     exceptions.Add(ex);
1042                 }
1043                 
1044                 BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for token = " + token.m_value + "\n");
1045             }        
1046
1047             if (exceptions.Count > 0)
1048                 throw new AggregateException(exceptions.ToArray());
1049         }
1050         
1051         [SecurityCritical]
1052         internal static unsafe string HStringToString(IntPtr hstring)
1053         {
1054             Contract.Requires(Environment.IsWinRTSupported);
1055
1056             // There is no difference between a null and empty HSTRING
1057             if (hstring == IntPtr.Zero)
1058             {
1059                 return String.Empty;
1060             }
1061
1062             unsafe
1063             {
1064                 uint length;
1065                 char* rawBuffer = UnsafeNativeMethods.WindowsGetStringRawBuffer(hstring, &length);
1066                 return new String(rawBuffer, 0, checked((int)length));
1067             }
1068         }
1069
1070         internal static Exception GetExceptionForHR(int hresult, Exception innerException, string messageResource)
1071         {
1072             Exception e = null;
1073             if (innerException != null)
1074             {
1075                 string message = innerException.Message;
1076                 if (message == null && messageResource != null)
1077                 {
1078                     message = Environment.GetResourceString(messageResource);
1079                 }
1080                 e = new Exception(message, innerException);
1081             }
1082             else
1083             {
1084                 string message = (messageResource != null ? Environment.GetResourceString(messageResource) : null);
1085                 e = new Exception(message);
1086             }
1087
1088             e.SetErrorCode(hresult);
1089             return e;
1090         }
1091
1092         internal static Exception GetExceptionForHR(int hresult, Exception innerException)
1093         {
1094             return GetExceptionForHR(hresult, innerException, null);
1095         }
1096
1097         private static bool s_haveBlueErrorApis = true;
1098
1099         [SecurityCritical]
1100         private static bool RoOriginateLanguageException(int error, string message, IntPtr languageException)
1101         {
1102             if (s_haveBlueErrorApis)
1103             {
1104                 try
1105                 {
1106                     return UnsafeNativeMethods.RoOriginateLanguageException(error, message, languageException);
1107                 }
1108                 catch (EntryPointNotFoundException)
1109                 {
1110                     s_haveBlueErrorApis = false;
1111                 }
1112             }
1113
1114             return false;
1115         }
1116
1117         [SecurityCritical]
1118         private static void RoReportUnhandledError(IRestrictedErrorInfo error)
1119         {
1120             if (s_haveBlueErrorApis)
1121             {
1122                 try
1123                 {
1124                     UnsafeNativeMethods.RoReportUnhandledError(error);
1125                 }
1126                 catch (EntryPointNotFoundException)
1127                 {
1128                     s_haveBlueErrorApis = false;
1129                 }
1130             }
1131         }
1132
1133         private static Guid s_iidIErrorInfo = new Guid(0x1CF2B120, 0x547D, 0x101B, 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19);
1134         
1135         /// <summary>
1136         /// Report that an exception has occured which went user unhandled.  This allows the global error handler
1137         /// for the application to be invoked to process the error.
1138         /// </summary>
1139         /// <returns>true if the error was reported, false if not (ie running on Win8)</returns>
1140         [FriendAccessAllowed]
1141         [SecuritySafeCritical]
1142         internal static bool ReportUnhandledError(Exception e)
1143         {
1144             // Only report to the WinRT global exception handler in modern apps
1145             if (!AppDomain.IsAppXModel())
1146             {
1147                 return false;
1148             }
1149
1150             // If we don't have the capability to report to the global error handler, early out
1151             if (!s_haveBlueErrorApis)
1152             {
1153                 return false;
1154             }
1155
1156             if (e != null)
1157             {
1158                 IntPtr exceptionIUnknown = IntPtr.Zero;
1159                 IntPtr exceptionIErrorInfo = IntPtr.Zero;
1160                 try
1161                 {
1162                     // Get an IErrorInfo for the current exception and originate it as a langauge error in order to have
1163                     // Windows generate an IRestrictedErrorInfo corresponding to the exception object.  We can then
1164                     // notify the global error handler that this IRestrictedErrorInfo instance represents an exception that
1165                     // went unhandled in managed code.
1166                     //
1167                     // Note that we need to get an IUnknown for the exception object and then QI for IErrorInfo since Exception
1168                     // doesn't implement IErrorInfo in managed code - only its CCW does.
1169                     exceptionIUnknown = Marshal.GetIUnknownForObject(e);
1170                     if (exceptionIUnknown != IntPtr.Zero)
1171                     {
1172                         Marshal.QueryInterface(exceptionIUnknown, ref s_iidIErrorInfo, out exceptionIErrorInfo);
1173                         if (exceptionIErrorInfo != IntPtr.Zero)
1174                         {
1175                             if (RoOriginateLanguageException(Marshal.GetHRForException_WinRT(e), e.Message, exceptionIErrorInfo))
1176                             {
1177                                 IRestrictedErrorInfo restrictedError = UnsafeNativeMethods.GetRestrictedErrorInfo();
1178                                 if (restrictedError != null)
1179                                 {
1180                                     RoReportUnhandledError(restrictedError);
1181                                     return true;
1182                                 }
1183                             }
1184                         }
1185                     }
1186                 }
1187                 finally
1188                 {
1189                     if (exceptionIErrorInfo != IntPtr.Zero)
1190                     {
1191                         Marshal.Release(exceptionIErrorInfo);
1192                     }
1193
1194                     if (exceptionIUnknown != IntPtr.Zero)
1195                     {
1196                         Marshal.Release(exceptionIUnknown);
1197                     }
1198                 }
1199             }
1200
1201             // If we got here, then some step of the marshaling failed, which means the GEH was not invoked
1202             return false;
1203         }
1204
1205 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1206         // Get an IActivationFactory * for a managed type
1207         [SecurityCritical]
1208         internal static IntPtr GetActivationFactoryForType(Type type)
1209         {
1210             ManagedActivationFactory activationFactory = GetManagedActivationFactory(type); 
1211             return Marshal.GetComInterfaceForObject(activationFactory, typeof(IActivationFactory));
1212         }        
1213
1214         [SecurityCritical]
1215         internal static ManagedActivationFactory GetManagedActivationFactory(Type type)
1216         {
1217             ManagedActivationFactory activationFactory = new ManagedActivationFactory(type);
1218             
1219             // If the type has any associated factory interfaces (i.e. supports non-default activation
1220             // or has statics), the CCW for this instance of ManagedActivationFactory must support them.
1221             Marshal.InitializeManagedWinRTFactoryObject(activationFactory, (RuntimeType)type);
1222             return activationFactory;
1223         }
1224
1225 #if FEATURE_COMINTEROP_WINRT_DESKTOP_HOST
1226         // Currently we use only a single class activator since we have a requirement that all class activations come from the same
1227         // app base and we haven't sorted through the various code sharing implications of spinning up multiple AppDomains.  This
1228         // holds the IWinRTClassActivator* that is used for the process
1229         private static IntPtr s_pClassActivator = IntPtr.Zero;
1230
1231         [SecurityCritical]
1232         internal static IntPtr GetClassActivatorForApplication(string appBase)
1233         {
1234             if (s_pClassActivator == IntPtr.Zero)
1235             {
1236                 AppDomainSetup hostDomainSetup = new AppDomainSetup()
1237                 {
1238                     ApplicationBase = appBase,
1239                 };
1240
1241                 AppDomain hostDomain = AppDomain.CreateDomain(Environment.GetResourceString("WinRTHostDomainName", appBase), null, hostDomainSetup);
1242                 WinRTClassActivator activator = (WinRTClassActivator)hostDomain.CreateInstanceAndUnwrap(typeof(WinRTClassActivator).Assembly.FullName, typeof(WinRTClassActivator).FullName);
1243                 IntPtr pActivator = activator.GetIWinRTClassActivator();
1244
1245                 if (Interlocked.CompareExchange(ref s_pClassActivator, pActivator, IntPtr.Zero) != IntPtr.Zero)
1246                 {
1247                     Marshal.Release(pActivator);
1248                     activator = null;
1249
1250                     try
1251                     {
1252                         AppDomain.Unload(hostDomain);
1253                     }
1254                     catch (CannotUnloadAppDomainException) { }
1255                 }
1256             }
1257
1258             Marshal.AddRef(s_pClassActivator);
1259             return s_pClassActivator;
1260         }
1261 #endif // FEATURE_COMINTEROP_WINRT_DESKTOP_HOST
1262
1263 #endif // FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1264
1265         //
1266         // Get activation factory object for a specified WinRT type
1267         // If the WinRT type is a native type, we'll always create a unique RCW for it,
1268         // This is necessary because WinRT factories are often implemented as a singleton, 
1269         // and getting back a RCW for such WinRT factory would usually get back a RCW from 
1270         // another apartment, even if the interface pointe returned from GetActivationFactory
1271         // is a raw pointer. As a result, user would randomly get back RCWs for activation
1272         // factories from other apartments and make transiton to those apartments and cause
1273         // deadlocks and create objects in incorrect apartments
1274         //
1275         [SecurityCritical]
1276         public static IActivationFactory GetActivationFactory(Type type)
1277         {
1278             if (type == null)
1279                 throw new ArgumentNullException("type");
1280
1281 #if FEATURE_COMINTEROP || MONO_COM
1282             if (type.IsWindowsRuntimeObject && type.IsImport)
1283             {
1284                 return (IActivationFactory)Marshal.GetNativeActivationFactory(type);
1285             }
1286             else
1287 #endif
1288             {
1289 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1290                 return GetManagedActivationFactory(type);
1291 #else 
1292                 // Managed factories are not supported so as to minimize public surface (and test effort)
1293                 throw new NotSupportedException();
1294 #endif
1295             }
1296         }
1297
1298         // HSTRING marshaling methods:
1299
1300         [SecurityCritical]
1301         public static IntPtr StringToHString(String s)
1302         {
1303             if (!Environment.IsWinRTSupported)
1304                 throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_WinRT"));
1305
1306             if (s == null)
1307                 throw new ArgumentNullException("s");
1308
1309             unsafe
1310             {
1311                 IntPtr hstring;
1312                 int hrCreate = UnsafeNativeMethods.WindowsCreateString(s, s.Length, &hstring);
1313                 Marshal.ThrowExceptionForHR(hrCreate, new IntPtr(-1));
1314                 return hstring;
1315             }
1316         }
1317
1318         [SecurityCritical]
1319         public static String PtrToStringHString(IntPtr ptr)
1320         {
1321             if (!Environment.IsWinRTSupported)
1322             {
1323                 throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_WinRT"));
1324             }
1325
1326             return HStringToString(ptr);
1327         }
1328
1329         [SecurityCritical]
1330         public static void FreeHString(IntPtr ptr)
1331         {
1332             if (!Environment.IsWinRTSupported)
1333                 throw new PlatformNotSupportedException(Environment.GetResourceString("PlatformNotSupported_WinRT"));
1334
1335             if (ptr != IntPtr.Zero)
1336             {
1337                 UnsafeNativeMethods.WindowsDeleteString(ptr);
1338             }
1339         }
1340     }
1341 }