[Kde-bindings] KDE/kdebindings

Richard Dale rdale at foton.es
Wed Jun 11 15:37:42 UTC 2008


On Wednesday 11 June 2008 16:13:34 Arno Rehn wrote:
> Am Mittwoch 11 Juni 2008 11:25:02 schrieb Richard Dale:
> > On Tuesday 10 June 2008 13:21:54 Arno Rehn wrote:
> > > Am Montag 09 Juni 2008 20:49:25 schrieb Richard Dale:
> > > > On Monday 09 June 2008 18:13:43 Arno Rehn wrote:
> > > > > Am Montag 09 Juni 2008 15:28:21 schrieb Richard Dale:
> > > > > > On Monday 09 June 2008 13:28:13 Arno Rehn wrote:
> > > > > > > > The only thing I don't like is subclassing SmokeInvocation
> > > > > > > > and giving it a different name in the generated code. That
> > > > > > > > seems pointless and ugly to me any old static constructor
> > > > > > > > will load the smoke lib. In the soprano bindings I had a
> > > > > > > > source called 'Soprano.cs' with this:
> > > > > > > >
> > > > > > > > namespace Soprano {
> > > > > > > >       using Qyoto;
> > > > > > > >       using System;
> > > > > > > >       using System.Runtime.InteropServices;
> > > > > > > >
> > > > > > > >       public class InitSoprano {
> > > > > > > >               [DllImport("libsoprano-sharp",
> > > > > > > > CharSet=CharSet.Ansi)] static extern void Init_soprano();
> > > > > > > >
> > > > > > > >               static InitSoprano() {
> > > > > > > >                       Init_soprano();
> > > > > > > >               }
> > > > > > > >       }
> > > > > > > > }
> > > > > > > >
> > > > > > > > And just left SmokeInvocation as it was in the generated
> > > > > > > > code. So I think we should have a Kimono.cs source with the
> > > > > > > > same thing in it.
> > > > > > >
> > > > > > > My intention was to simplify the code for those who actually
> > > > > > > use the C# bindings. And a static constructor is called when
> > > > > > > the class that defines it is used for the first time. Since
> > > > > > > SmokeInvocation is always used before any other thing, it makes
> > > > > > > sure that the smoke lib is always loaded. If we put that code
> > > > > > > into another class that is completely unrelated to the binding,
> > > > > > > we will always have to call InitFoo() if we want to use it. So
> > > > > > > subclassing SmokeInvocation for the different bindings seemed
> > > > > > > to be the best solution to me.
> > > > > >
> > > > > > OK, I understand the problem now, but I still think the solution
> > > > > > of renaming SmokeInvocation is ugly. I found this after a bit of
> > > > > > googling:
> > > > > >
> > > > > > "Note, however, that you *can* put code in your AppDomain to
> > > > > > execute when *another* DLL loads. (The AppDomain.AssemblyLoad
> > > > > > event.) That means you can write your code once, and so long as
> > > > > > that event handler is added before the other assemblies are
> > > > > > loaded, you can do all the appropriate things."
> > > > > >
> > > > > > http://osdir.com/ml/windows.devel.dotnet.cx/2004-01/msg00064.html
> > > > > >
> > > > > > So is the Qyoto dll in an AppDomain, or can we put it in one?
> > > > >
> > > > > Yes, of couse the Qyoto dll is always in an AppDomain. So we'd have
> > > > > to define a standard class class name, whoch holds a method to do
> > > > > the initialization. Whenever an assembly is loaded, we have to look
> > > > > for that class via reflection and call the initialization method.
> > > >
> > > > I've read a bit more about this, and it seems quite straightforward
> > > > to implement - you just set up a static delegate that receives the
> > > > dll loaded event and then do what you say. So I would prefer doing it
> > > > this way - an app domain called 'Qyoto' and an initialize class
> > > > called InitSmoke in each dll for instance.
> > >
> > > Ok, I just tested this and it doesn't quite work out. Consider this:
> > >
> > > using System;
> > > using Qyoto;
> > >
> > > class MainClass {
> > > 	public static void AssemblyLoad(object sender, AssemblyLoadEventArgs
> > > args) { Console.WriteLine(args.LoadedAssembly.FullName);
> > > 	}
> > >
> > > 	public static void Main(string[] args) {
> > > 		AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoad;
> > > // 		System.Reflection.Assembly.Load("qt-dotnet, Version=4.4.0.0,
> > > Culture=neutral, PublicKeyToken=194a23ba31c08164");
> > > 	}
> > > }
> > >
> > > This will do nothing, since we add the event handler _after_ the
> > > assembly is loaded. The same will happen if we define such an event
> > > handler in the Qyoto runtime. If we load the assembly dynamically, it
> > > will work well. So going via AppDomain.AssemblyLoad is not really an
> > > option, I think.
> >
> > So when Qyoto.Qyoto.Init_qyoto() is called in the SmokeInvocation static
> > constructor all the assemblies are already loaded?
> >
> > If that is so, I think we just need to add a custom Attribute to the
> > Qyoto assemblies (apart from the qt dll):
> >
> > 	[AttributeUsage(AttributeTargets.Assembly)]
> > 	public class AssemblySmokeInitializer : Attribute
> > 	{
> > 		public string initializer;
> >
> > 		public string Initializer {
> > 			get {
> > 				return initializer;
> > 			}
> > 		}
> >
> > 		public AssemblySmokeInitializer(string initializer) {
> > 			this.initializer = initializer;
> > 		}
> > 	}
> >
> > Then in each AssemblyInfo.cs:
> >
> > // The class to initialize the smoke library used by this assembly
> > // Type.GetType("Soprano.InitSoprano")
> > [assembly: AssemblySmokeInitializer("Soprano.InitSoprano")]
> >
> > Does Type.GetType() load the class? If so, it should called the init
> > method for the smoke lib in the InitSoprano class:
> >
> > namespace Soprano {
> > 	using Qyoto;
> > 	using System;
> > 	using System.Runtime.InteropServices;
> >
> > 	public class InitSoprano {
> > 		[DllImport("libsoprano-sharp", CharSet=CharSet.Ansi)]
> > 		static extern void Init_soprano();
> >
> > 		static InitSoprano() {
> > 			Init_soprano();
> > 		}
> > 	}
> > }
> >
> > In the SmokeInvocation static constructor we need to iterate though the
> > loaded assemblies looking for AssemblySmokeInitializer attributes and
> > load the named classes.
>
> Ah, ok, I see. This can be done even easier if we put the code for
> initializing the smoke lib into the static constructor of the Attribute,
> like this
>
> using System;
> using System.Reflection;
>
> [assembly: TestAttribute]
>
> [AttributeUsage(AttributeTargets.Assembly)]
> class TestAttribute : Attribute {
> 	static TestAttribute() {
> 		Console.WriteLine("foo bar");
> 	}
> }
>
> class MainClass {
> 	public static void Main(string[] args) {
> 		foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
> 			a.GetCustomAttributes(true);
> 	}
> }
>
> As soon as we call Assembly.GetCustomAttributes() the static constructor
> will be invoked. We can place the calls to initialize the smoke lib there.
> This is less work and cleaner than creating an extra initialization class
> and passing the name or type of it to another attribute, IMHO.
But doesn't that mean we have a different custom attribute for each dll? It 
seems more elegant to me to know the name of the custom attribute in advance 
and query the assembly metadata just for it, rather than all custom 
attributes. I don't think the small initialization class is much work - about 
the same as implementing a new attribute class I would have thought.

Either way I prefer doing something like this over renaming the 
SmokeInvocation class for each dll.

-- Richard





More information about the Kde-bindings mailing list