88using System . Collections . Immutable ;
99using System . Linq ;
1010using System . Threading . Tasks . Dataflow ;
11+ #if DYNAMIC_VSProjectManaged
12+ using System . Reflection ;
13+ using System . Reflection . Emit ;
14+ using Expression = System . Linq . Expressions . Expression ;
15+ #endif
1116
1217// This isolation of Microsoft.VisualStudio.ProjectSystem dependencies into one file ensures compatibility
1318// across various Visual Studio installations. This is crucial because not all Visual Studio workloads
@@ -151,7 +156,7 @@ public void SetConfig(EnvDTE.Project project, string arguments, IDictionary<stri
151156 if ( baseLaunchProfile == null )
152157 return ;
153158
154- WritableLaunchProfile writableLaunchProfile = new WritableLaunchProfile ( baseLaunchProfile ) ;
159+ var writableLaunchProfile = WritableLaunchProfile . GetWritableLaunchProfile ( baseLaunchProfile ) ;
155160
156161 if ( arguments != null )
157162 writableLaunchProfile . CommandLineArgs = arguments ;
@@ -226,9 +231,8 @@ public void GetItemsFromConfig(EnvDTE.Project project, List<CmdItemJson> allArgs
226231 }
227232 }
228233 }
229-
230- class WritableLaunchProfile : ILaunchProfile
231- #if VS17
234+ public class WritableLaunchProfile : ILaunchProfile //must be public to avoid having to declare our dynamic assembly a friend
235+ #if VS17 && ! DYNAMIC_VSProjectManaged
232236 , IPersistOption
233237#endif
234238 {
@@ -245,7 +249,10 @@ class WritableLaunchProfile : ILaunchProfile
245249
246250 // IPersistOption
247251 public bool DoNotPersist { get ; set ; }
248-
252+ #if DYNAMIC_VSProjectManaged
253+ private static Func < ILaunchProfile , bool > LaunchProfileIsDoNotPersistFunc ;
254+ #endif
255+ private static Lazy < Type > IPersistOptionType = new Lazy < Type > ( ( ) => typeof ( ILaunchProfile ) . Assembly . GetType ( "Microsoft.VisualStudio.ProjectSystem.Debug.IPersistOption" ) ) ;
249256 public WritableLaunchProfile ( ILaunchProfile launchProfile )
250257 {
251258 // ILaunchProfile
@@ -259,12 +266,78 @@ public WritableLaunchProfile(ILaunchProfile launchProfile)
259266 EnvironmentVariables = launchProfile . EnvironmentVariables ;
260267 OtherSettings = launchProfile . OtherSettings ;
261268#if VS17
269+ #if DYNAMIC_VSProjectManaged
270+ if ( LaunchProfileIsDoNotPersistFunc == null )
271+ {
272+ if ( IPersistOptionType . Value == null )
273+ LaunchProfileIsDoNotPersistFunc = ( _ ) => false ;
274+ else
275+ {
276+ var instanceParam = Expression . Parameter ( typeof ( ILaunchProfile ) ) ;
277+ var asIPersist = Expression . TypeAs ( instanceParam , IPersistOptionType . Value ) ;
278+ var expr = Expression . Condition ( Expression . Equal ( asIPersist , Expression . Constant ( null ) ) , Expression . Constant ( false ) , Expression . Property ( asIPersist , nameof ( DoNotPersist ) ) ) ;
279+ LaunchProfileIsDoNotPersistFunc = Expression . Lambda < Func < ILaunchProfile , bool > > ( expr , instanceParam ) . Compile ( ) ;
280+ }
281+ }
282+ DoNotPersist = LaunchProfileIsDoNotPersistFunc ( launchProfile ) ;
283+
284+ #else
262285 if ( launchProfile is IPersistOption persistOptionLaunchProfile )
263286 {
264287 // IPersistOption
265288 DoNotPersist = persistOptionLaunchProfile . DoNotPersist ;
266289 }
290+ #endif
267291#endif
268292 }
293+
294+ private static Func < ILaunchProfile , WritableLaunchProfile > getWritableProfileFunc ;
295+ internal static WritableLaunchProfile GetWritableLaunchProfile ( ILaunchProfile profile )
296+ {
297+ #if DYNAMIC_VSProjectManaged
298+ if ( getWritableProfileFunc == null && IPersistOptionType . Value != null )
299+ {
300+ var ourType = typeof ( WritableLaunchProfile ) ;
301+ var asmName = new AssemblyName ( ) { Name = "SmartCLIArgsDynamicAsm" } ;
302+ asmName . SetPublicKey ( ourType . Assembly . GetName ( ) . GetPublicKey ( ) ) ;
303+ var assemBuilder = AssemblyBuilder . DefineDynamicAssembly ( asmName , AssemblyBuilderAccess . Run ) ;
304+
305+ var classBuilder = assemBuilder . DefineDynamicModule ( "SmartCLIArgsDynamicMod" ) . DefineType ( "DynamicWritableLaunchProfile" , TypeAttributes . NotPublic | TypeAttributes . Class , ourType ) ;
306+ classBuilder . AddInterfaceImplementation ( IPersistOptionType . Value ) ;
307+ // not sure why AssemblyBuilder is a baby true IL code doesn't define interface impelmentations that are just inherited
308+ var persist_get = classBuilder . DefineMethod ( "get_" + nameof ( DoNotPersist ) , MethodAttributes . Virtual | MethodAttributes . Public , typeof ( bool ) , Type . EmptyTypes ) ;
309+ var il = persist_get . GetILGenerator ( ) ;
310+ il . Emit ( OpCodes . Ldarg_0 ) ;
311+ il . EmitCall ( OpCodes . Callvirt , ourType . GetMethod ( persist_get . Name ) , null ) ;
312+ il . Emit ( OpCodes . Ret ) ;
313+
314+
315+ classBuilder . DefineMethodOverride ( persist_get , IPersistOptionType . Value . GetMethod ( persist_get . Name ) ) ;
316+
317+ var constructorArgTypes = new [ ] { typeof ( ILaunchProfile ) } ;
318+ var constructor = classBuilder . DefineConstructor ( MethodAttributes . Public , CallingConventions . Standard , constructorArgTypes ) ;
319+ var baseConstructor = ourType . GetConstructor ( constructorArgTypes ) ;
320+ il = constructor . GetILGenerator ( ) ;
321+ il . Emit ( OpCodes . Ldarg_0 ) ;
322+ il . Emit ( OpCodes . Ldarg_1 ) ;
323+ il . Emit ( OpCodes . Call , baseConstructor ) ;
324+ il . Emit ( OpCodes . Nop ) ;
325+ il . Emit ( OpCodes . Nop ) ;
326+ il . Emit ( OpCodes . Ret ) ;
327+ var DynamicWritableLaunchProfileType = classBuilder . CreateType ( ) ;
328+ var constructorInfo = DynamicWritableLaunchProfileType . GetConstructor ( constructorArgTypes ) ;
329+ var instanceParam = Expression . Parameter ( typeof ( ILaunchProfile ) ) ;
330+ var expr = Expression . TypeAs ( Expression . New ( constructorInfo , instanceParam ) , ourType ) ;
331+ getWritableProfileFunc = Expression . Lambda < Func < ILaunchProfile , WritableLaunchProfile > > ( expr , instanceParam ) . Compile ( ) ;
332+
333+ }
334+ if ( IPersistOptionType . Value != null )
335+ return getWritableProfileFunc ( profile ) ;
336+ #endif
337+ return new WritableLaunchProfile ( profile ) ;
338+
339+
340+ }
341+
269342 }
270343}
0 commit comments