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