Delete FriendAccessAllowedAttribute and associated dead code (#15101)
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Runtime / InteropServices / WindowsRuntime / WindowsRuntimeMarshal.cs
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.m_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
355             {
356                 internal object target;
357                 internal MethodInfo method;
358
359                 public override string ToString()
360                 {
361                     return "(" + target + ", " + method + ")";
362                 }
363             }
364
365             internal class EventCacheKeyEqualityComparer : IEqualityComparer<EventCacheKey>
366             {
367                 public bool Equals(EventCacheKey lhs, EventCacheKey rhs)
368                 {
369                     return (Object.Equals(lhs.target, rhs.target) && Object.Equals(lhs.method, rhs.method));
370                 }
371
372                 public int GetHashCode(EventCacheKey key)
373                 {
374                     return key.target.GetHashCode() ^ key.method.GetHashCode();
375                 }
376             }
377
378             //
379             // EventRegistrationTokenListWithCount
380             // 
381             // A list of EventRegistrationTokens that maintains a count
382             //
383             // The reason this needs to be a separate class is that we need a finalizer for this class
384             // If the delegate is collected, it will take this list away with it (due to dependent handles), 
385             // and we need to remove the PerInstancEntry from cache
386             // See ~EventRegistrationTokenListWithCount for more details
387             //
388             internal class EventRegistrationTokenListWithCount
389             {
390                 private TokenListCount _tokenListCount;
391                 private EventRegistrationTokenList _tokenList;
392
393                 internal EventRegistrationTokenListWithCount(TokenListCount tokenListCount, EventRegistrationToken token)
394                 {
395                     _tokenListCount = tokenListCount;
396                     _tokenListCount.Inc();
397
398                     _tokenList = new EventRegistrationTokenList(token);
399                 }
400
401                 ~EventRegistrationTokenListWithCount()
402                 {
403                     // Decrement token list count
404                     // This is need to correctly keep trace of number of tokens for EventCacheKey
405                     // and remove it from cache when the token count drop to 0
406                     // we don't need to take locks for decrement the count - we only need to take a global
407                     // lock when we decide to destroy cache for the IUnknown */type instance
408                     Log("[WinRT_Eventing] Finalizing EventRegistrationTokenList for " + _tokenListCount.Key + "\n");
409                     _tokenListCount.Dec();
410                 }
411
412                 public void Push(EventRegistrationToken token)
413                 {
414                     // Since EventRegistrationTokenListWithCount is a reference type, there is no need
415                     // to copy back. Ignore the return value
416                     _tokenList.Push(token);
417                 }
418
419                 public bool Pop(out EventRegistrationToken token)
420                 {
421                     return _tokenList.Pop(out token);
422                 }
423
424                 public void CopyTo(List<EventRegistrationToken> tokens)
425                 {
426                     _tokenList.CopyTo(tokens);
427                 }
428             }
429
430             //
431             // Maintains the number of tokens for a particular EventCacheKey
432             // TokenListCount is a class for two reasons:
433             // 1. Efficient update in the Dictionary to avoid lookup twice to update the value
434             // 2. Update token count without taking a global lock. Only takes a global lock when drop to 0
435             //
436             internal class TokenListCount
437             {
438                 private int _count;
439                 private EventCacheKey _key;
440
441                 internal TokenListCount(EventCacheKey key)
442                 {
443                     _key = key;
444                 }
445
446                 internal EventCacheKey Key
447                 {
448                     get { return _key; }
449                 }
450
451                 internal void Inc()
452                 {
453                     int newCount = Interlocked.Increment(ref _count);
454                     Log("[WinRT_Eventing] Incremented TokenListCount for " + _key + ", Value = " + newCount + "\n");
455                 }
456
457                 internal void Dec()
458                 {
459                     // Avoid racing with Add/Remove event entries into the cache
460                     // You don't want this removing the key in the middle of a Add/Remove
461                     s_eventCacheRWLock.AcquireWriterLock(Timeout.Infinite);
462                     try
463                     {
464                         int newCount = Interlocked.Decrement(ref _count);
465                         Log("[WinRT_Eventing] Decremented TokenListCount for " + _key + ", Value = " + newCount + "\n");
466                         if (newCount == 0)
467                             CleanupCache();
468                     }
469                     finally
470                     {
471                         s_eventCacheRWLock.ReleaseWriterLock();
472                     }
473                 }
474
475                 private void CleanupCache()
476                 {
477                     // Time to destroy cache for this IUnknown */type instance
478                     // because the total token list count has dropped to 0 and we don't have any events subscribed
479                     Debug.Assert(s_eventRegistrations != null);
480
481                     Log("[WinRT_Eventing] Removing " + _key + " from cache" + "\n");
482                     s_eventRegistrations.Remove(_key);
483                     Log("[WinRT_Eventing] s_eventRegistrations size = " + s_eventRegistrations.Count + "\n");
484                 }
485             }
486
487             internal struct EventCacheEntry
488             {
489                 // [Handler] -> Token
490                 internal ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTable;
491
492                 // Maintains current total count for the EventRegistrationTokenListWithCount for this event cache key
493                 internal TokenListCount tokenListCount;
494             }
495
496             // Mappings of delegates registered for events -> their registration tokens.
497             // These mappings are stored indexed by the remove method which can be used to undo the registrations.
498             //
499             // The full structure of this table is:
500             //   EventCacheKey (instanceKey, eventMethod) -> EventCacheEntry (Handler->tokens)
501             //   
502             // A InstanceKey is the IUnknown * or static type instance
503             //
504             // Couple of things to note:
505             // 1. We need to use IUnknown* because we want to be able to unscribe to the event for another RCW
506             // based on the same COM object. For example:
507             //    m_canvas.GetAt(0).Event += Func;
508             //    m_canvas.GetAt(0).Event -= Func;  // GetAt(0) might create a new RCW
509             // 
510             // 2. Handler->Token is a ConditionalWeakTable because we don't want to keep the delegate alive
511             // and we want EventRegistrationTokenListWithCount to be finalized after the delegate is no longer alive 
512             // 3. It is possible another COM object is created at the same address
513             // before the entry in cache is destroyed. More specifically, 
514             //   a. The same delegate is being unsubscribed. In this case we'll give them a 
515             //   stale token - unlikely to be a problem
516             //   b. The same delegate is subscribed then unsubscribed. We need to make sure give
517             //   them the latest token in this case. This is guaranteed by always giving the last token and always use equality to
518             //   add/remove event handlers
519             internal volatile static Dictionary<EventCacheKey, EventCacheEntry> s_eventRegistrations =
520                 new Dictionary<EventCacheKey, EventCacheEntry>(new EventCacheKeyEqualityComparer());
521
522             // Prevent add/remove handler code to run at the same with with cache cleanup code
523             private volatile static MyReaderWriterLock s_eventCacheRWLock = new MyReaderWriterLock();
524
525             // Get InstanceKey to use in the cache
526             private static object GetInstanceKey(Action<EventRegistrationToken> removeMethod)
527             {
528                 object target = removeMethod.Target;
529                 Debug.Assert(target == null || Marshal.IsComObject(target), "Must be null or a RCW");
530                 if (target == null)
531                     return removeMethod.Method.DeclaringType;
532
533                 // Need the "Raw" IUnknown pointer for the RCW that is not bound to the current context
534                 return (object)Marshal.GetRawIUnknownForComObjectNoAddRef(target);
535             }
536
537             private static object FindEquivalentKeyUnsafe(ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTable, object handler, out EventRegistrationTokenListWithCount tokens)
538             {
539                 foreach (KeyValuePair<object, EventRegistrationTokenListWithCount> item in registrationTable)
540                 {
541                     if (Object.Equals(item.Key, handler))
542                     {
543                         tokens = item.Value;
544                         return item.Key;
545                     }
546                 }
547                 tokens = null;
548                 return null;
549             }
550
551             internal static void AddEventHandler<T>(Func<T, EventRegistrationToken> addMethod,
552                                                   Action<EventRegistrationToken> removeMethod,
553                                                   T handler)
554             {
555                 // The instanceKey will be IUnknown * of the target object
556                 object instanceKey = GetInstanceKey(removeMethod);
557
558                 // Call addMethod outside of RW lock
559                 // At this point we don't need to worry about race conditions and we can avoid deadlocks 
560                 // if addMethod waits on finalizer thread
561                 // If we later throw we need to remove the method
562                 EventRegistrationToken token = addMethod(handler);
563
564                 bool tokenAdded = false;
565
566                 try
567                 {
568                     EventRegistrationTokenListWithCount tokens;
569
570                     //
571                     // The whole add/remove code has to be protected by a reader/writer lock
572                     // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time
573                     //
574                     s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite);
575                     try
576                     {
577                         // Add the method, and make a note of the delegate -> token mapping.
578                         TokenListCount tokenListCount;
579                         ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetOrCreateEventRegistrationTokenTable(instanceKey, removeMethod, out tokenListCount);
580                         lock (registrationTokens)
581                         {
582                             //
583                             // We need to find the key that equals to this handler
584                             // Suppose we have 3 handlers A, B, C that are equal (refer to the same object and method),
585                             // the first handler (let's say A) will be used as the key and holds all the tokens. 
586                             // We don't need to hold onto B and C, because the COM object itself will keep them alive,
587                             // and they won't die anyway unless the COM object dies or they get unsubscribed.
588                             // It may appear that it is fine to hold A, B, C, and add them and their corresponding tokens
589                             // into registrationTokens table. However, this is very dangerous, because this COM object
590                             // may die, but A, B, C might not get collected yet, and another COM object comes into life
591                             // with the same IUnknown address, and we subscribe event B. In this case, the right token
592                             // will be added into B's token list, but once we unsubscribe B, we might end up removing
593                             // the last token in C, and that may lead to crash.
594                             //
595                             object key = FindEquivalentKeyUnsafe(registrationTokens, handler, out tokens);
596                             if (key == null)
597                             {
598                                 tokens = new EventRegistrationTokenListWithCount(tokenListCount, token);
599                                 registrationTokens.Add(handler, tokens);
600                             }
601                             else
602                             {
603                                 tokens.Push(token);
604                             }
605
606                             tokenAdded = true;
607                         }
608                     }
609                     finally
610                     {
611                         s_eventCacheRWLock.ReleaseReaderLock();
612                     }
613
614                     Log("[WinRT_Eventing] Event subscribed for instance = " + instanceKey + ", handler = " + handler + "\n");
615                 }
616                 catch (Exception)
617                 {
618                     // If we've already added the token and go there, we don't need to "UNDO" anything
619                     if (!tokenAdded)
620                     {
621                         // Otherwise, "Undo" addMethod if any exception occurs
622                         // There is no need to cleanup our data structure as we haven't added the token yet
623                         removeMethod(token);
624                     }
625
626
627                     throw;
628                 }
629             }
630
631             private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetEventRegistrationTokenTableNoCreate(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount)
632             {
633                 Debug.Assert(instance != null);
634                 Debug.Assert(removeMethod != null);
635
636                 return GetEventRegistrationTokenTableInternal(instance, removeMethod, out tokenListCount, /* createIfNotFound = */ false);
637             }
638
639             private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetOrCreateEventRegistrationTokenTable(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount)
640             {
641                 Debug.Assert(instance != null);
642                 Debug.Assert(removeMethod != null);
643
644                 return GetEventRegistrationTokenTableInternal(instance, removeMethod, out tokenListCount, /* createIfNotFound = */ true);
645             }
646
647             // Get the event registration token table for an event.  These are indexed by the remove method of the event.
648             private static ConditionalWeakTable<object, EventRegistrationTokenListWithCount> GetEventRegistrationTokenTableInternal(object instance, Action<EventRegistrationToken> removeMethod, out TokenListCount tokenListCount, bool createIfNotFound)
649             {
650                 Debug.Assert(instance != null);
651                 Debug.Assert(removeMethod != null);
652                 Debug.Assert(s_eventRegistrations != null);
653
654                 EventCacheKey eventCacheKey;
655                 eventCacheKey.target = instance;
656                 eventCacheKey.method = removeMethod.Method;
657
658                 lock (s_eventRegistrations)
659                 {
660                     EventCacheEntry eventCacheEntry;
661                     if (!s_eventRegistrations.TryGetValue(eventCacheKey, out eventCacheEntry))
662                     {
663                         if (!createIfNotFound)
664                         {
665                             // No need to create an entry in this case
666                             tokenListCount = null;
667                             return null;
668                         }
669
670                         Log("[WinRT_Eventing] Adding (" + instance + "," + removeMethod.Method + ") into cache" + "\n");
671
672                         eventCacheEntry = new EventCacheEntry();
673                         eventCacheEntry.registrationTable = new ConditionalWeakTable<object, EventRegistrationTokenListWithCount>();
674                         eventCacheEntry.tokenListCount = new TokenListCount(eventCacheKey);
675
676                         s_eventRegistrations.Add(eventCacheKey, eventCacheEntry);
677                     }
678
679                     tokenListCount = eventCacheEntry.tokenListCount;
680
681                     return eventCacheEntry.registrationTable;
682                 }
683             }
684
685             internal static void RemoveEventHandler<T>(Action<EventRegistrationToken> removeMethod, T handler)
686             {
687                 object instanceKey = GetInstanceKey(removeMethod);
688
689                 EventRegistrationToken token;
690
691                 //
692                 // The whole add/remove code has to be protected by a reader/writer lock
693                 // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time
694                 //
695                 s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite);
696                 try
697                 {
698                     TokenListCount tokenListCount;
699                     ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod, out tokenListCount);
700                     if (registrationTokens == null)
701                     {
702                         // We have no information regarding this particular instance (IUnknown*/type) - just return
703                         // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance
704                         Log("[WinRT_Eventing] no registrationTokens found for instance=" + instanceKey + ", handler= " + handler + "\n");
705                         return;
706                     }
707
708                     lock (registrationTokens)
709                     {
710                         EventRegistrationTokenListWithCount tokens;
711
712                         // Note:
713                         // When unsubscribing events, we allow subscribing the event using a different delegate
714                         // (but with the same object/method), so we need to find the first delegate that matches
715                         // and unsubscribe it
716                         // It actually doesn't matter which delegate - as long as it matches
717                         // Note that inside TryGetValueWithValueEquality we assumes that any delegate 
718                         // with the same value equality would have the same hash code
719                         object key = FindEquivalentKeyUnsafe(registrationTokens, handler, out tokens);
720                         Debug.Assert((key != null && tokens != null) || (key == null && tokens == null),
721                                         "key and tokens must be both null or non-null");
722                         if (tokens == null)
723                         {
724                             // Failure to find a registration for a token is not an error - it's simply a no-op.
725                             Log("[WinRT_Eventing] no token list found for instance=" + instanceKey + ", handler= " + handler + "\n");
726                             return;
727                         }
728
729                         // Select a registration token to unregister
730                         // Note that we need to always get the last token just in case another COM object
731                         // is created at the same address before the entry for the old one goes away.
732                         // See comments above s_eventRegistrations for more details
733                         bool moreItems = tokens.Pop(out token);
734
735                         // If the last token is removed from token list, we need to remove it from the cache
736                         // otherwise FindEquivalentKeyUnsafe may found this empty token list even though there could be other
737                         // equivalent keys in there with non-0 token list
738                         if (!moreItems)
739                         {
740                             // Remove it from (handler)->(tokens)
741                             // NOTE: We should not check whether registrationTokens has 0 entries and remove it from the cache
742                             // (just like managed event implementation), because this might have raced with the finalizer of 
743                             // EventRegistrationTokenList
744                             registrationTokens.Remove(key);
745                         }
746
747                         Log("[WinRT_Eventing] Event unsubscribed for managed instance = " + instanceKey + ", handler = " + handler + ", token = " + token.m_value + "\n");
748                     }
749                 }
750                 finally
751                 {
752                     s_eventCacheRWLock.ReleaseReaderLock();
753                 }
754
755                 // Call removeMethod outside of RW lock
756                 // At this point we don't need to worry about race conditions and we can avoid deadlocks 
757                 // if removeMethod waits on finalizer thread
758                 removeMethod(token);
759             }
760
761             internal static void RemoveAllEventHandlers(Action<EventRegistrationToken> removeMethod)
762             {
763                 object instanceKey = GetInstanceKey(removeMethod);
764
765                 List<EventRegistrationToken> tokensToRemove = new List<EventRegistrationToken>();
766
767                 //
768                 // The whole add/remove code has to be protected by a reader/writer lock
769                 // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time
770                 //
771                 s_eventCacheRWLock.AcquireReaderLock(Timeout.Infinite);
772                 try
773                 {
774                     TokenListCount tokenListCount;
775                     ConditionalWeakTable<object, EventRegistrationTokenListWithCount> registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod, out tokenListCount);
776                     if (registrationTokens == null)
777                     {
778                         // We have no information regarding this particular instance (IUnknown*/type) - just return
779                         // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance
780                         return;
781                     }
782
783                     lock (registrationTokens)
784                     {
785                         // Copy all tokens to tokensToRemove array which later we'll call removeMethod on
786                         // outside this lock
787                         foreach (KeyValuePair<object, EventRegistrationTokenListWithCount> item in registrationTokens)
788                         {
789                             item.Value.CopyTo(tokensToRemove);
790                         }
791
792                         // Clear the table - at this point all event handlers are no longer in the cache
793                         // but they are not removed yet
794                         registrationTokens.Clear();
795                         Log("[WinRT_Eventing] Cache cleared for managed instance = " + instanceKey + "\n");
796                     }
797                 }
798                 finally
799                 {
800                     s_eventCacheRWLock.ReleaseReaderLock();
801                 }
802
803                 //
804                 // Remove all handlers outside the lock
805                 //
806                 Log("[WinRT_Eventing] Start removing all events for instance = " + instanceKey + "\n");
807                 CallRemoveMethods(removeMethod, tokensToRemove);
808                 Log("[WinRT_Eventing] Finished removing all events for instance = " + instanceKey + "\n");
809             }
810
811
812             internal class ReaderWriterLockTimedOutException : ApplicationException
813             {
814             }
815
816             /// Discussed @ https://blogs.msdn.microsoft.com/vancem/2006/03/29/analysis-of-reader-writer-lock/
817             ///
818             /// <summary>
819             /// A reader-writer lock implementation that is intended to be simple, yet very
820             /// efficient.  In particular only 1 interlocked operation is taken for any lock 
821             /// operation (we use spin locks to achieve this).  The spin lock is never held
822             /// for more than a few instructions (in particular, we never call event APIs
823             /// or in fact any non-trivial API while holding the spin lock).   
824             /// 
825             /// Currently this ReaderWriterLock does not support recursion, however it is 
826             /// not hard to add 
827             /// </summary>
828             internal class MyReaderWriterLock
829             {
830                 // Lock specifiation for myLock:  This lock protects exactly the local fields associted
831                 // instance of MyReaderWriterLock.  It does NOT protect the memory associted with the
832                 // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent).
833                 private int myLock;
834
835                 // Who owns the lock owners > 0 => readers
836                 // owners = -1 means there is one writer.  Owners must be >= -1.  
837                 private int owners;
838
839                 // These variables allow use to avoid Setting events (which is expensive) if we don't have to. 
840                 private uint numWriteWaiters;        // maximum number of threads that can be doing a WaitOne on the writeEvent 
841                 private uint numReadWaiters;         // maximum number of threads that can be doing a WaitOne on the readEvent
842
843                 // conditions we wait on. 
844                 private EventWaitHandle writeEvent;    // threads waiting to aquire a write lock go here.
845                 private EventWaitHandle readEvent;     // threads waiting to aquire a read lock go here (will be released in bulk)
846
847                 internal MyReaderWriterLock()
848                 {
849                     // All state can start out zeroed. 
850                 }
851
852                 internal void AcquireReaderLock(int millisecondsTimeout)
853                 {
854                     EnterMyLock();
855                     for (;;)
856                     {
857                         // We can enter a read lock if there are only read-locks have been given out
858                         // and a writer is not trying to get in.  
859                         if (owners >= 0 && numWriteWaiters == 0)
860                         {
861                             // Good case, there is no contention, we are basically done
862                             owners++;       // Indicate we have another reader
863                             break;
864                         }
865
866                         // Drat, we need to wait.  Mark that we have waiters and wait.  
867                         if (readEvent == null)      // Create the needed event 
868                         {
869                             LazyCreateEvent(ref readEvent, false);
870                             continue;   // since we left the lock, start over. 
871                         }
872
873                         WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout);
874                     }
875                     ExitMyLock();
876                 }
877
878                 internal void AcquireWriterLock(int millisecondsTimeout)
879                 {
880                     EnterMyLock();
881                     for (;;)
882                     {
883                         if (owners == 0)
884                         {
885                             // Good case, there is no contention, we are basically done
886                             owners = -1;    // indicate we have a writer.
887                             break;
888                         }
889
890                         // Drat, we need to wait.  Mark that we have waiters and wait.
891                         if (writeEvent == null)     // create the needed event.
892                         {
893                             LazyCreateEvent(ref writeEvent, true);
894                             continue;   // since we left the lock, start over. 
895                         }
896
897                         WaitOnEvent(writeEvent, ref numWriteWaiters, millisecondsTimeout);
898                     }
899                     ExitMyLock();
900                 }
901
902                 internal void ReleaseReaderLock()
903                 {
904                     EnterMyLock();
905                     Debug.Assert(owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken");
906                     --owners;
907                     ExitAndWakeUpAppropriateWaiters();
908                 }
909
910                 internal void ReleaseWriterLock()
911                 {
912                     EnterMyLock();
913                     Debug.Assert(owners == -1, "Calling ReleaseWriterLock when no write lock is held");
914                     owners++;
915                     ExitAndWakeUpAppropriateWaiters();
916                 }
917
918                 /// <summary>
919                 /// A routine for lazily creating a event outside the lock (so if errors
920                 /// happen they are outside the lock and that we don't do much work
921                 /// while holding a spin lock).  If all goes well, reenter the lock and
922                 /// set 'waitEvent' 
923                 /// </summary>
924                 private void LazyCreateEvent(ref EventWaitHandle waitEvent, bool makeAutoResetEvent)
925                 {
926                     Debug.Assert(myLock != 0, "Lock must be held");
927                     Debug.Assert(waitEvent == null, "Wait event must be null");
928
929                     ExitMyLock();
930                     EventWaitHandle newEvent;
931                     if (makeAutoResetEvent)
932                         newEvent = new AutoResetEvent(false);
933                     else
934                         newEvent = new ManualResetEvent(false);
935                     EnterMyLock();
936                     if (waitEvent == null)          // maybe someone snuck in. 
937                         waitEvent = newEvent;
938                 }
939
940                 /// <summary>
941                 /// Waits on 'waitEvent' with a timeout of 'millisceondsTimeout.  
942                 /// Before the wait 'numWaiters' is incremented and is restored before leaving this routine.
943                 /// </summary>
944                 private void WaitOnEvent(EventWaitHandle waitEvent, ref uint numWaiters, int millisecondsTimeout)
945                 {
946                     Debug.Assert(myLock != 0, "Lock must be held");
947
948                     waitEvent.Reset();
949                     numWaiters++;
950
951                     bool waitSuccessful = false;
952                     ExitMyLock();      // Do the wait outside of any lock 
953                     try
954                     {
955                         if (!waitEvent.WaitOne(millisecondsTimeout, false))
956                             throw new ReaderWriterLockTimedOutException();
957
958                         waitSuccessful = true;
959                     }
960                     finally
961                     {
962                         EnterMyLock();
963                         --numWaiters;
964                         if (!waitSuccessful)        // We are going to throw for some reason.  Exit myLock. 
965                             ExitMyLock();
966                     }
967                 }
968
969                 /// <summary>
970                 /// Determines the appropriate events to set, leaves the locks, and sets the events. 
971                 /// </summary>
972                 private void ExitAndWakeUpAppropriateWaiters()
973                 {
974                     Debug.Assert(myLock != 0, "Lock must be held");
975
976                     if (owners == 0 && numWriteWaiters > 0)
977                     {
978                         ExitMyLock();      // Exit before signaling to improve efficiency (wakee will need the lock)
979                         writeEvent.Set();   // release one writer. 
980                     }
981                     else if (owners >= 0 && numReadWaiters != 0)
982                     {
983                         ExitMyLock();    // Exit before signaling to improve efficiency (wakee will need the lock)
984                         readEvent.Set();  // release all readers. 
985                     }
986                     else
987                         ExitMyLock();
988                 }
989
990                 private void EnterMyLock()
991                 {
992                     if (Interlocked.CompareExchange(ref myLock, 1, 0) != 0)
993                         EnterMyLockSpin();
994                 }
995
996                 private void EnterMyLockSpin()
997                 {
998                     for (int i = 0; ; i++)
999                     {
1000                         if (i < 3 && Environment.ProcessorCount > 1)
1001                             Thread.SpinWait(20);    // Wait a few dozen instructions to let another processor release lock. 
1002                         else
1003                             Thread.Sleep(0);        // Give up my quantum.  
1004
1005                         if (Interlocked.CompareExchange(ref myLock, 1, 0) == 0)
1006                             return;
1007                     }
1008                 }
1009                 private void ExitMyLock()
1010                 {
1011                     Debug.Assert(myLock != 0, "Exiting spin lock that is not held");
1012                     myLock = 0;
1013                 }
1014             };
1015         }
1016
1017         //
1018         // Call removeMethod on each token and aggregate all exceptions thrown from removeMethod into one in case of failure
1019         //
1020         internal static void CallRemoveMethods(Action<EventRegistrationToken> removeMethod, List<EventRegistrationToken> tokensToRemove)
1021         {
1022             List<Exception> exceptions = new List<Exception>();
1023
1024             foreach (EventRegistrationToken token in tokensToRemove)
1025             {
1026                 try
1027                 {
1028                     removeMethod(token);
1029                 }
1030                 catch (Exception ex)
1031                 {
1032                     exceptions.Add(ex);
1033                 }
1034
1035                 Log("[WinRT_Eventing] Event unsubscribed for token = " + token.m_value + "\n");
1036             }
1037
1038             if (exceptions.Count > 0)
1039                 throw new AggregateException(exceptions.ToArray());
1040         }
1041
1042         internal static unsafe string HStringToString(IntPtr hstring)
1043         {
1044             Debug.Assert(Environment.IsWinRTSupported);
1045
1046             // There is no difference between a null and empty HSTRING
1047             if (hstring == IntPtr.Zero)
1048             {
1049                 return String.Empty;
1050             }
1051
1052             unsafe
1053             {
1054                 uint length;
1055                 char* rawBuffer = UnsafeNativeMethods.WindowsGetStringRawBuffer(hstring, &length);
1056                 return new String(rawBuffer, 0, checked((int)length));
1057             }
1058         }
1059
1060         internal static Exception GetExceptionForHR(int hresult, Exception innerException, string messageResource)
1061         {
1062             Exception e = null;
1063             if (innerException != null)
1064             {
1065                 string message = innerException.Message;
1066                 if (message == null && messageResource != null)
1067                 {
1068                     message = SR.GetResourceString(messageResource);
1069                 }
1070                 e = new Exception(message, innerException);
1071             }
1072             else
1073             {
1074                 string message = (messageResource != null ? SR.GetResourceString(messageResource): null);
1075                 e = new Exception(message);
1076             }
1077
1078             e.SetErrorCode(hresult);
1079             return e;
1080         }
1081
1082         internal static Exception GetExceptionForHR(int hresult, Exception innerException)
1083         {
1084             return GetExceptionForHR(hresult, innerException, null);
1085         }
1086
1087         private static bool s_haveBlueErrorApis = true;
1088
1089         private static bool RoOriginateLanguageException(int error, string message, IntPtr languageException)
1090         {
1091             if (s_haveBlueErrorApis)
1092             {
1093                 try
1094                 {
1095                     return UnsafeNativeMethods.RoOriginateLanguageException(error, message, languageException);
1096                 }
1097                 catch (EntryPointNotFoundException)
1098                 {
1099                     s_haveBlueErrorApis = false;
1100                 }
1101             }
1102
1103             return false;
1104         }
1105
1106         private static void RoReportUnhandledError(IRestrictedErrorInfo error)
1107         {
1108             if (s_haveBlueErrorApis)
1109             {
1110                 try
1111                 {
1112                     UnsafeNativeMethods.RoReportUnhandledError(error);
1113                 }
1114                 catch (EntryPointNotFoundException)
1115                 {
1116                     s_haveBlueErrorApis = false;
1117                 }
1118             }
1119         }
1120
1121         private static Guid s_iidIErrorInfo = new Guid(0x1CF2B120, 0x547D, 0x101B, 0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19);
1122
1123         /// <summary>
1124         /// Report that an exception has occurred which went user unhandled.  This allows the global error handler
1125         /// for the application to be invoked to process the error.
1126         /// </summary>
1127         /// <returns>true if the error was reported, false if not (ie running on Win8)</returns>
1128         // [FriendAccessAllowed]
1129         internal static bool ReportUnhandledError(Exception e)
1130         {
1131             // Only report to the WinRT global exception handler in modern apps
1132             if (!AppDomain.IsAppXModel())
1133             {
1134                 return false;
1135             }
1136
1137             // If we don't have the capability to report to the global error handler, early out
1138             if (!s_haveBlueErrorApis)
1139             {
1140                 return false;
1141             }
1142
1143             if (e != null)
1144             {
1145                 IntPtr exceptionIUnknown = IntPtr.Zero;
1146                 IntPtr exceptionIErrorInfo = IntPtr.Zero;
1147                 try
1148                 {
1149                     // Get an IErrorInfo for the current exception and originate it as a langauge error in order to have
1150                     // Windows generate an IRestrictedErrorInfo corresponding to the exception object.  We can then
1151                     // notify the global error handler that this IRestrictedErrorInfo instance represents an exception that
1152                     // went unhandled in managed code.
1153                     //
1154                     // Note that we need to get an IUnknown for the exception object and then QI for IErrorInfo since Exception
1155                     // doesn't implement IErrorInfo in managed code - only its CCW does.
1156                     exceptionIUnknown = Marshal.GetIUnknownForObject(e);
1157                     if (exceptionIUnknown != IntPtr.Zero)
1158                     {
1159                         Marshal.QueryInterface(exceptionIUnknown, ref s_iidIErrorInfo, out exceptionIErrorInfo);
1160                         if (exceptionIErrorInfo != IntPtr.Zero)
1161                         {
1162                             if (RoOriginateLanguageException(Marshal.GetHRForException_WinRT(e), e.Message, exceptionIErrorInfo))
1163                             {
1164                                 IRestrictedErrorInfo restrictedError = UnsafeNativeMethods.GetRestrictedErrorInfo();
1165                                 if (restrictedError != null)
1166                                 {
1167                                     RoReportUnhandledError(restrictedError);
1168                                     return true;
1169                                 }
1170                             }
1171                         }
1172                     }
1173                 }
1174                 finally
1175                 {
1176                     if (exceptionIErrorInfo != IntPtr.Zero)
1177                     {
1178                         Marshal.Release(exceptionIErrorInfo);
1179                     }
1180
1181                     if (exceptionIUnknown != IntPtr.Zero)
1182                     {
1183                         Marshal.Release(exceptionIUnknown);
1184                     }
1185                 }
1186             }
1187
1188             // If we got here, then some step of the marshaling failed, which means the GEH was not invoked
1189             return false;
1190         }
1191
1192 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1193         // Get an IActivationFactory * for a managed type
1194         internal static IntPtr GetActivationFactoryForType(Type type)
1195         {
1196             ManagedActivationFactory activationFactory = GetManagedActivationFactory(type);
1197             return Marshal.GetComInterfaceForObject(activationFactory, typeof(IActivationFactory));
1198         }
1199
1200         internal static ManagedActivationFactory GetManagedActivationFactory(Type type)
1201         {
1202             ManagedActivationFactory activationFactory = new ManagedActivationFactory(type);
1203
1204             // If the type has any associated factory interfaces (i.e. supports non-default activation
1205             // or has statics), the CCW for this instance of ManagedActivationFactory must support them.
1206             Marshal.InitializeManagedWinRTFactoryObject(activationFactory, (RuntimeType)type);
1207             return activationFactory;
1208         }
1209
1210
1211 #endif // FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1212
1213         //
1214         // Get activation factory object for a specified WinRT type
1215         // If the WinRT type is a native type, we'll always create a unique RCW for it,
1216         // This is necessary because WinRT factories are often implemented as a singleton, 
1217         // and getting back a RCW for such WinRT factory would usually get back a RCW from 
1218         // another apartment, even if the interface pointe returned from GetActivationFactory
1219         // is a raw pointer. As a result, user would randomly get back RCWs for activation
1220         // factories from other apartments and make transiton to those apartments and cause
1221         // deadlocks and create objects in incorrect apartments
1222         //
1223         public static IActivationFactory GetActivationFactory(Type type)
1224         {
1225             if (type == null)
1226                 throw new ArgumentNullException(nameof(type));
1227
1228             if (type.IsWindowsRuntimeObject && type.IsImport)
1229             {
1230                 return (IActivationFactory)Marshal.GetNativeActivationFactory(type);
1231             }
1232             else
1233             {
1234 #if FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
1235                 return GetManagedActivationFactory(type);
1236 #else 
1237                 // Managed factories are not supported so as to minimize public surface (and test effort)
1238                 throw new NotSupportedException();
1239 #endif
1240             }
1241         }
1242
1243         // HSTRING marshaling methods:
1244
1245         public static IntPtr StringToHString(String s)
1246         {
1247             if (!Environment.IsWinRTSupported)
1248                 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
1249
1250             if (s == null)
1251                 throw new ArgumentNullException(nameof(s));
1252
1253             unsafe
1254             {
1255                 IntPtr hstring;
1256                 int hrCreate = UnsafeNativeMethods.WindowsCreateString(s, s.Length, &hstring);
1257                 Marshal.ThrowExceptionForHR(hrCreate, new IntPtr(-1));
1258                 return hstring;
1259             }
1260         }
1261
1262         public static String PtrToStringHString(IntPtr ptr)
1263         {
1264             if (!Environment.IsWinRTSupported)
1265             {
1266                 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
1267             }
1268
1269             return HStringToString(ptr);
1270         }
1271
1272         public static void FreeHString(IntPtr ptr)
1273         {
1274             if (!Environment.IsWinRTSupported)
1275                 throw new PlatformNotSupportedException(SR.PlatformNotSupported_WinRT);
1276
1277             if (ptr != IntPtr.Zero)
1278             {
1279                 UnsafeNativeMethods.WindowsDeleteString(ptr);
1280             }
1281         }
1282
1283         [Conditional("_LOGGING")]
1284         private static void Log(string s)
1285         {
1286             // Internal.Console.WriteLine(s);
1287         }
1288     }
1289 }