PhoneShellThunks.cs 7.1 KB

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