# 30 Ocak 2007 Salı
Last week, Edward Bakker started summarizing some notes and resources on Software Factories, then Jezz Santos added this one on "When would you build one". (Their latest posts have a cyclic dependency, by the way :) I don't know if people (apart from these two guys. They're already into it to their neck :) are more talkative on SF notion lately or my doors of perception are more open to this kind of posts since I'm trying to build one myself, but I started seeing more and more on this subject.

I remember seeing a discussion between Grady (an IBM Fellow, as his blog says) and Greenfield, Cook, Wills and Kent on the UML vs SF kind of debate (and I assure you I didn't have a clue back then how important things they're talking on). Then I interested in code generation. Then I had to use NHibernate for a little project. Then I wanted to generate .hbm.xml documents in VS. Then I thought I prefer attribute decorations rather than XML declarations. Then I found out DSL Tools in this post (Sequence ended in mid 2006. Quite late for me, huh?).

Now, with DSL Tools in hand, I feel like I can take over the world :) Seriously, check the comments for this post. People want tools for their everyday needs. Put some guidance in, integrate with the IDE and they're willing to do the rest. Learning curve might be a little steep but anybody dreaming a tool to generate some code or project instruments or a custom domain intelligent enough to do some repetitive / predefined work may start building it right now or use existing ones, be it DSL Tools, GAT / GAX or one of the available software factories.

posted on 30 Ocak 2007 Salı 00:23:29 UTC  #   
# 29 Ocak 2007 Pazartesi
It sometimes get frustrating when you debug your project through another instance of Visual Studio, especially if you manipulate the "active" DTE within your debug project. I somehow ended up to the following when getting a reference to DTE:

System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.8.0");


It worked most of the time, but "not all the time" means you may add a project to the solution where your code resides (the parent VS instance), rather than where the debugging session is. So, after some research, DTE code turned into this:

[DllImport("ole32.dll")]

public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);


[DllImport("ole32.dll")]

public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);


[CLSCompliant(false)]

public static DTE GetDTE(string processID)

{

    IRunningObjectTable prot;

    IEnumMoniker pMonkEnum;

 

    string progID = "!VisualStudio.DTE.8.0:" + processID;

 

    GetRunningObjectTable(0, out prot);

    prot.EnumRunning(out pMonkEnum);

    pMonkEnum.Reset();

 

    IntPtr fetched = IntPtr.Zero;

    IMoniker[] pmon = new IMoniker[1];

    while (pMonkEnum.Next(1, pmon, fetched) == 0)

    {

        IBindCtx pCtx;

        CreateBindCtx(0, out pCtx);

        string str;

        pmon[0].GetDisplayName(pCtx, null, out str);

        if (str == progID)

        {

            object objReturnObject;

            prot.GetObject(pmon[0], out objReturnObject);

            DTE ide = (DTE)objReturnObject;

            return ide;

        }

    }

 

    return null;

}

posted on 29 Ocak 2007 Pazartesi 22:17:43 UTC  #   
I was trying to solve the Custom Tool property issue with .actiw files in ActiveWriter, as suggested by Bogdan Pietroiu months ago, and spent a clear hour trying to figure how to inject my own registry keys into WiX setup project of DSL Tools. I modified the .vstemplate for .actiw files to include the following:

...

<CustomParameters>

  <CustomParameter Name="$itemproperties$" Value="CustomTool" />

  <CustomParameter Name="$CustomTool$" Value="ActiveWriterCodeGenerator" />

</CustomParameters>

...


and thought that the file, when added to the project, will have Custom Tool property already set. I was appearently wrong (documentation says it should work).

Bogdan's suggestion was to have a key named after the file extension under Generators\{Language}, and I manually confirmed that it works great. So, how to automate the process of adding this reg key through the setup? WiX Toolkit documentation shows the way, so I copied Registry.wxs to have my own key registered.

<?xml version="1.0" encoding="utf-8"?>

<Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'>

  <Fragment Id="CustomToolFragment">

    <FeatureRef Id="DefaultFeature">

      <ComponentRef Id="_ActiveWriterCTReg" />

    </FeatureRef>

    <DirectoryRef Id="TARGETDIR">

      <Component Id="_ActiveWriterCTReg" Guid="{some GUID}">

        <Registry Root='HKLM' Key='Software\Microsoft\VisualStudio\8.0\Generators\{164b10b9-b200-11d0-8c61-00a0c91e29d5}\.actiw' Id='{some GUID}' Type='string' Value='ActiveWriterCodeGenerator' />

        <Registry Root='HKLM' Key='Software\Microsoft\VisualStudio\8.0\Generators\{fae04ec1-301f-11d3-bf4b-00c04f79efbc}\.actiw' Id='{some GUID}' Type='string' Value='ActiveWriterCodeGenerator' />

      </Component>

    </DirectoryRef>

  </Fragment>

</Wix>


<Registry> elements define the key to be added, as you may have guessed. Anyway, although I changed the build action on the .wxs and although it seems that Candle and Light picked up the file, the installer didn't add the registry key. So? Orca to the rescue. You should check Component and Registry tables in .msi file to check if your key slipped in, and Orca shows them quite detailed. In my case, though, it shows the absence of my additions.

Long story (not so) short, it seems that I should examine Registry.tt as the first step, but didn't. To include your ComponentRef in DefaultFeature, you should have your Fragment as FragmentRef in Main.wxs . So, you should add each of your custom fragment in the list defined in customFragmentIds in InstallerDefinitions.dslsetup as shown below:

<installerDefinition xmlns="http://schemas.microsoft.com/VisualStudio/2005/DslTools/InstallerDefinitionModel"

  ...

  customFragmentIds="CustomToolFragment">

I hope this info helps someone.

posted on 29 Ocak 2007 Pazartesi 21:13:31 UTC  #   
# 08 Aralık 2006 Cuma

At work, I'm devoting a fair amount of my time to SQL BI concepts lately. One of the exciting concepts (there are many, believe me) of SSAS on SQL 2005 is Key Performance Indicators. A KPI is the creme de la creme of all the data aggregations. It's the final display of knowledge extracted from the vast amount of data to answer questions like "Based on such and such criteria, are we profitable?".



Since KPIs are mostly for non-techies, it's best to display them in a dashboard like scenario, where SharePoint is a good example. A handy newcomer in dashboard scene is Vista Sidebar, and displaying KPI data on the Sidebar was the most logical exercise for Sidebar development for me with the release of Vista:



Without perfecting that, WPF/E came out and I wondered if I can display KPIs in a Sidebar gadget using WPF/E. Result? I CAN'T. I don't know if it's the security settings or is it the WPF'E engine's fault but, the javascript method in Loaded event does not get called for a .xaml file if it's run in a Sidebar.

<Canvas xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Loaded="javascript:OnLoaded">
  <Canvas x:Name="kpiCanvas" />
</Canvas>

Here's the code for the WPF/E thing (gadget? applet? app?). Note that, everything's fine in IE:
KPIDS.rar (7.21 KB)



Notes:
  • WPF/E currently doesn't like .gif images in IMAGE tags. <Image Source="star.png" /> is fine but  <Image Source="star.gif" /> fails without an error, or it's the case for me.
  • I lost (accidentally overriden) the source for KPI sidebar gadget (the one without WPF/E, two images above) but you can easily build one from the given source. Change "createKPI" in kpiLibrary.js to render to html instead of xaml.
  • createFromXaml is a nice method but, we'll have programmatic access to the object model won't we?
  • Although the current form of WPF/E is nice, I won't touch another CTP of it untill I can code in C# against it. JavaScript is sooooo boooring.
  • Follow the steps below to setup remote XMLA access to SSAS through web services. It's required to access KPI data remotely:
    Configuring HTTP Access to SQL Server 2005 Analysis Services on Microsoft Windows Server 2003.
posted on 08 Aralık 2006 Cuma 23:00:36 UTC  #   
# 01 Kasım 2006 Çarşamba
Go visit www.castleproject.org and get the lates bits.

The amount of information there is increadible, MonoRail getting started docs are extremely helpful for me. After seeing "Getting Started with ActiveRecord" topic, you will have no excuse not to use ActiveRecord in your next project. And API documentation is just what I need for ActiveWriter's properties window documentation :)

The question is, will I manage to release something new with ActiveWriter to celebrate the Castle release and the hard work these guys doing? Let's see:



Although implementing the toolwindow above turned out to be harder than I thought, I was actually referring to generics support in ActiveWriter, which is still waiting my attention. So, I'll try to hurry++ and sleep--;
posted on 01 Kasım 2006 Çarşamba 19:58:57 UTC  #   
# 11 Ekim 2006 Çarşamba
I can't dechiper legal documents even in Turkish, how can I decide if I'm allowed to release the source code or not by looking at the VS DSK license? If Microsoft has a department or something to ask "would you get angry if I release this?", I want to know.

Anyway, you can download the source of ActiveWriter Preview here. I have removed some .tt files copyrighted by Microsoft, but instructions are available in the download to add them from an empty DSL Tools project. Lack of .tt files will prevent any "just extract and open" scenario, sorry about that.

Back to the license adventure. I have asked in DSL Tools forum if it's possible to release the source, and directed to the SDK license. Then I found a post on Interop blog, saying that "It is possible to release extensions to Visual Studio under open source licenses" with an IANAL notice. I have convinced that I can, until I notice copyright notes on all over the .tt files, which are very much the core of the code generation on DSL Tools part. So I followed the next best approach, removed copyrighted stuff.

Having copyright notices in .tt files, for Microsoft, is a bit silly, by the way. They don't include notices in AssemblyInfo or config files (or any other template generated solution files), what's different with .tt's?

Update:

Gareth Jones from DSL Tools team replied, saying that .tt files are considered to be samples and developers may customize them with whatever license statements they have. This is extremely good. I'll re-release the source with all the .tt files included.

And for those who don't know what a .tt file is for; they are input files for the text templating engine of DSL Tools. They have ASP.NET like <# #> syntax to generate output as VS solution files. Very handy, but I prefered a more classic approach in ActiveWriter. CodeGenerationHelper is much nicer in plain C# than .tt syntax.

ActiveWriterReport.tt file:

<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" debug="true"#>
<#@ output extension=".%EXT%" #>
<#@ ActiveWriter processor="ActiveWriterDirectiveProcessor" requires="fileName='%MODELFILE%'" #>
<#@ import namespace="Altinoren.ActiveWriter.CodeGeneration" #>
<#
    CodeGenerationHelper helper = new CodeGenerationHelper(this.Model, "%NAMESPACE%");
    this.Write(helper.Generate());
#>

and the usage:

protected override byte[] GenerateCode(string inputFileName, string inputFileContent)

{

    ResourceManager manager =

        new ResourceManager("Altinoren.ActiveWriter.VSPackage",

                            typeof (ActiveWriterTemplatedCodeGenerator).Assembly);

    FileInfo fi = new FileInfo(inputFileName);

    inputFileContent =

        manager.GetObject("ActiveWriterReport").ToString().Replace("%MODELFILE%", fi.Name).Replace(

            "%NAMESPACE%", FileNameSpace).Replace("%EXT%", "cs"); // TODO: Get file extension from the project model

 

    byte[] data = base.GenerateCode(inputFileName, inputFileContent);

    return data;

}


posted on 11 Ekim 2006 Çarşamba 09:59:00 UTC  #   
# 30 Eylül 2006 Cumartesi

Help and download available here.

If you missed the announcement, it is a visual designer, an addin for Visual Studio 2005, to design a domain model and to generate code decorated with ActiveRecord attributes.

Please send bugs, suggestions and feature request through the Navigation pane of the site.

Thanks To

ActiveRecord team for the great and well supported library, NHibernate and Hibernate community for making this chain-reaction possible, Microsoft DSL Tools team for making DSL modelling this easy, everyone at DSL Tools forum, and my wife Damla for her patience.

Pluralization code is simplified version of Damian Conway's algorithm in paper An Algorithmic Approach to English Pluralization
Server Explorer integration greatly inspired from Ted Glaza's post here.
posted on 30 Eylül 2006 Cumartesi 18:12:03 UTC  #   
# 15 Eylül 2006 Cuma

Head to the VSIP member site to download. I'm %46 done right now.

Since DSL Tools v1 is bundled with this final release, and since I'll finally be able to include redistributables with ActiveWriter installer, I'm twice excited right now :)

My plan is:

    Compile ActiveWriter against DSL Tools v1
    Fix things broken by the v1
    Add one2one support (Just manual modelling. No heuristics for drag-drop. Will complete that later)
    Test & release.

 And about the current state of the project:

    Handles many-to-one, both in manual design and drag-drop.
    Handles many-to-many, both in manual design and drag-drop.
    Primary keys, properties, fields.
    Composite keys: Writes the attribute as well as a separate composite key class :) Yup.
    Some more model validators (If PrimaryKeyType.Sequence, then sequence name should be defined etc.)
    Versions and Timestamps.
posted on 15 Eylül 2006 Cuma 12:31:35 UTC  #   
# 28 Ağustos 2006 Pazartesi
I use CodeDom to generate ActiveRecord classes in ActiveWriter. Quite fancy, but gets complicated easily. To generate something like this:

        public override bool Equals(object obj)

        {

            if (obj == this) return true;

            if (obj == null || obj.GetType() != this.GetType()) return false;

            MyCompositeKey test = (MyCompositeKey)obj;

            return (_keyA == test.KeyA || (_keyA != null && _keyA.Equals(test.KeyA))) &&

              (_keyB == test.KeyB || (_keyB != null && _keyB.Equals(test.KeyB)));

        }


you code this:

        private CodeTypeMember GetCompositeClassEqualsMethod(string className,  List<CodeMemberField> fields)

        {

            CodeMemberMethod equals = new CodeMemberMethod();

            equals.Attributes = MemberAttributes.Public | MemberAttributes.Override;

            equals.ReturnType = new CodeTypeReference(typeof(Boolean));

            equals.Name = "Equals";

 

            CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(Object), "obj");

            equals.Parameters.Add(param);

 

            equals.Statements.Add(new CodeConditionStatement(

                                      new CodeBinaryOperatorExpression(

                                          new CodeFieldReferenceExpression(null, "obj"),

                                          CodeBinaryOperatorType.ValueEquality, new CodeThisReferenceExpression()

                                          ), new CodeMethodReturnStatement(new CodePrimitiveExpression(true))

                                      )

                );

 

            equals.Statements.Add(new CodeConditionStatement

                                      (

                                      new CodeBinaryOperatorExpression

                                          (

                                          new CodeBinaryOperatorExpression(

                                              new CodeFieldReferenceExpression(null, "obj"),

                                              CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(null)),

                                          CodeBinaryOperatorType.BooleanOr,

                                          new CodeBinaryOperatorExpression(

                                              new CodeMethodInvokeExpression(new CodeFieldReferenceExpression(null, "obj"), "GetType"),

                                              CodeBinaryOperatorType.IdentityInequality,

                                              new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "GetType"))

                                          )

                                      , new CodeMethodReturnStatement(new CodePrimitiveExpression(false))

                                      )

                );

 

            equals.Statements.Add(

                new CodeVariableDeclarationStatement(new CodeTypeReference(className), "test",

                                                    new CodeCastExpression(new CodeTypeReference(className),

                                                                            new CodeFieldReferenceExpression(null, "obj"))));

 

            List<CodeExpression> expressions = new List<CodeExpression>();

            foreach (CodeMemberField field in fields)

            {

                expressions.Add(

                    new CodeBinaryOperatorExpression(

                        //_keyA == test.KeyA

                        new CodeBinaryOperatorExpression(

                            new CodeFieldReferenceExpression(null, field.Name),

                            CodeBinaryOperatorType.ValueEquality,

                            new CodeFieldReferenceExpression(new CodeFieldReferenceExpression(null, "test"), field.Name)),

                        CodeBinaryOperatorType.BooleanOr, // ||

                        new CodeBinaryOperatorExpression(

                            //_keyA != null

                            new CodeBinaryOperatorExpression(

                                new CodeFieldReferenceExpression(null, field.Name),

                                CodeBinaryOperatorType.IdentityInequality,

                                new CodePrimitiveExpression(null)

                                ),

                            CodeBinaryOperatorType.BooleanAnd, // &&

                            // _keyA.Equals( test.KeyA )  

                            new CodeMethodInvokeExpression(

                                new CodeFieldReferenceExpression(null, field.Name), "Equals",

                                new CodeFieldReferenceExpression(

                                    new CodeFieldReferenceExpression(null, "test"), field.Name))

                            )

                        )

                    );

            }

 

            CodeExpression expression = null;

            if (expressions.Count > 2)

                expression =

                    new CodeBinaryOperatorExpression(expressions[0], CodeBinaryOperatorType.BooleanAnd, GetBooleanAnd(expressions, 1));

            else

                expression = new CodeBinaryOperatorExpression(expressions[0], CodeBinaryOperatorType.BooleanAnd, expressions[1]);

 

 

            equals.Statements.Add(new CodeMethodReturnStatement(expression));

 

            return equals;

        }


Strangely, there's no CodeBinaryOperatorType.ValueInequality operator defined. (a==b)==false will do the trick, but how about not having an XOR? I find CodeDom's lack of completeness... disturbing.

posted on 28 Ağustos 2006 Pazartesi 21:46:29 UTC  #