PhoneShellThunks.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. #if WINDOWSPHONE7
  5. #if !DEBUG_NO_AGENT_SUPPORT
  6. //
  7. // The Windows Phone Marketplace Test Kit disallows usage of types
  8. // in the Microsoft.Phone.Shell namespace, determined by static code
  9. // analysis, for background agents.
  10. //
  11. // However, with a null check for PhoneApplicationService.Current,
  12. // we can safely use this the lifecycle events for dormant state
  13. // transitions. In a background agent this property will be null;
  14. // trying to create an instance of PhoneApplicationService throws
  15. // a ComException and is required to set the Current property.
  16. //
  17. // In order to access the PhoneApplicationService functionality for
  18. // non-background agent assemblies, we build a late bound wrapper
  19. // around the APIs.
  20. //
  21. // See appplat\src\Frameworks\Microsoft\Phone\PhoneApplicationService.cs
  22. // for implementation details of the class we use.
  23. //
  24. namespace System.Reactive.PlatformServices.Phone.Shell
  25. {
  26. using System;
  27. using System.Collections.Generic;
  28. using System.Linq.Expressions;
  29. using System.Reflection;
  30. using Microsoft.Phone;
  31. class PhoneApplicationService
  32. {
  33. private static readonly object s_gate = new object();
  34. internal static readonly Assembly s_phshAsm;
  35. private static readonly Type s_pasType;
  36. private static readonly PropertyInfo s_curProp;
  37. private static readonly EventInfo s_actdEvt;
  38. private static readonly EventInfo s_deacEvt;
  39. private readonly object _target;
  40. static PhoneApplicationService()
  41. {
  42. s_phshAsm = typeof(BackgroundAgent).Assembly; // Has to be in Microsoft.Phone.dll.
  43. s_pasType = s_phshAsm.GetType("Microsoft.Phone.Shell.PhoneApplicationService");
  44. s_curProp = s_pasType.GetProperty("Current", BindingFlags.Public | BindingFlags.Static);
  45. s_actdEvt = s_curProp.PropertyType.GetEvent("Activated", BindingFlags.Public | BindingFlags.Instance);
  46. s_deacEvt = s_curProp.PropertyType.GetEvent("Deactivated", BindingFlags.Public | BindingFlags.Instance);
  47. }
  48. private PhoneApplicationService(object target)
  49. {
  50. _target = target;
  51. }
  52. private static PhoneApplicationService s_current;
  53. public static PhoneApplicationService Current
  54. {
  55. get
  56. {
  57. lock (s_gate)
  58. {
  59. if (s_current == null)
  60. {
  61. var current = s_curProp.GetValue(null, null);
  62. if (current == null)
  63. return null;
  64. //
  65. // Current provides a singleton. The constructor
  66. // of PhoneApplicationService guarantees this,
  67. // throwing an InvalidOperationException if more
  68. // than one instance is created.
  69. //
  70. s_current = new PhoneApplicationService(current);
  71. }
  72. }
  73. return s_current;
  74. }
  75. }
  76. private Dictionary<object, object> _actdHandlers = new Dictionary<object, object>();
  77. public event EventHandler<ActivatedEventArgs> Activated
  78. {
  79. add
  80. {
  81. AddHandler<ActivatedEventArgs>(s_actdEvt, _actdHandlers, value);
  82. }
  83. remove
  84. {
  85. RemoveHandler(s_actdEvt, _actdHandlers, value);
  86. }
  87. }
  88. private Dictionary<object, object> _deacHandlers = new Dictionary<object, object>();
  89. public event EventHandler<DeactivatedEventArgs> Deactivated
  90. {
  91. add
  92. {
  93. AddHandler<DeactivatedEventArgs>(s_deacEvt, _deacHandlers, value);
  94. }
  95. remove
  96. {
  97. RemoveHandler(s_deacEvt, _deacHandlers, value);
  98. }
  99. }
  100. private void AddHandler<TEventArgs>(EventInfo evt, Dictionary<object, object> map, object handler)
  101. where TEventArgs : EventArgs
  102. {
  103. var h = GetHandler<TEventArgs>(evt, handler);
  104. var add = evt.GetAddMethod();
  105. lock (s_gate)
  106. {
  107. map.Add(handler, h);
  108. add.Invoke(_target, new object[] { h });
  109. }
  110. }
  111. private void RemoveHandler(EventInfo evt, Dictionary<object, object> map, object handler)
  112. {
  113. var rem = evt.GetRemoveMethod();
  114. lock (s_gate)
  115. {
  116. var h = default(object);
  117. if (map.TryGetValue(handler, out h))
  118. {
  119. //
  120. // We assume only one handler will be attached to
  121. // the event, hence we shouldn't worry about having
  122. // multiple delegate instances with the same target
  123. // being attached. This guarantee is made by the
  124. // reference counting in HostLifecycleService.
  125. //
  126. // The use of a dictionary allows for reuse with
  127. // multiple distinct handlers going forward.
  128. //
  129. map.Remove(handler);
  130. rem.Invoke(_target, new object[] { h });
  131. }
  132. }
  133. }
  134. private static object GetHandler<TEventArgsThunk>(EventInfo evt, object call)
  135. where TEventArgsThunk : EventArgs
  136. {
  137. var ht = evt.EventHandlerType;
  138. var hp = ht.GetMethod("Invoke").GetParameters();
  139. var po = Expression.Parameter(hp[0].ParameterType, hp[0].Name);
  140. var pe = Expression.Parameter(hp[1].ParameterType, hp[1].Name);
  141. var h = Expression.Lambda(
  142. ht,
  143. Expression.Invoke(
  144. Expression.Constant(call),
  145. po,
  146. Expression.New(
  147. typeof(TEventArgsThunk).GetConstructor(new[] { typeof(object) }),
  148. pe
  149. )
  150. ),
  151. po,
  152. pe
  153. );
  154. return h.Compile();
  155. }
  156. }
  157. class ActivatedEventArgs : EventArgs
  158. {
  159. private static readonly Type s_aeaType;
  160. private static readonly PropertyInfo s_aipProp;
  161. private readonly object _target;
  162. static ActivatedEventArgs()
  163. {
  164. s_aeaType = PhoneApplicationService.s_phshAsm.GetType("Microsoft.Phone.Shell.ActivatedEventArgs");
  165. s_aipProp = s_aeaType.GetProperty("IsApplicationInstancePreserved", BindingFlags.Public | BindingFlags.Instance);
  166. }
  167. public ActivatedEventArgs(object target)
  168. {
  169. _target = target;
  170. }
  171. public bool IsApplicationInstancePreserved
  172. {
  173. get
  174. {
  175. return (bool)s_aipProp.GetValue(_target, null);
  176. }
  177. }
  178. }
  179. class DeactivatedEventArgs : EventArgs
  180. {
  181. public DeactivatedEventArgs(object target)
  182. {
  183. }
  184. }
  185. }
  186. #endif
  187. #endif