Saturday, June 30, 2012

Generating sequential GUID

It is all over the place and there are many ways to do it. This small post is for my quick reference.

rpcrt4.dll 
is the Remote Procedure Call (RPC) API, used by Windows applications for network and Internet communication. This is an essential system process and should not be deleted.

UuidCreateSequential function
For security reasons, UuidCreate was modified so that it no longer uses a machine's MAC address to generate UUIDs. UuidCreateSequentialwas introduced to allow creation of UUIDs using the MAC address of a machine's Ethernet card.

The UuidCreateSequential function returns RPC_S_UUID_LOCAL_ONLY when the originating computer does not have an ethernet/token ring (IEEE 802.x) address. In this case, the generated UUID is a valid identifier, and is guaranteed to be unique among all UUIDs generated on the computer. However, the possibility exists that another computer without an ethernet/token ring address generated the identical UUID. Therefore you should never use this UUID to identify an object that is not strictly local to your computer. Computers with ethernet/token ring addresses generate UUIDs that are guaranteed to be globally unique.

Note:  The UuidCreateSequential function tends to be slightly faster than the UuidCreate function. When the performance of the generation of a UUID is a significant consideration, the UuidCreateSequential function may be used.

Implementation:

Declaration
using System.Runtime.InteropServices;

Initializing objects at class level
[DllImport("rpcrt4.dll", SetLastError = true)]
private static extern int UuidCreateSequential(out Guid value);

[Flags]
private enum RetUuidCodes : int
{
    RPC_S_OK = 0, //The call succeeded.
    RPC_S_UUID_LOCAL_ONLY = 1824, //The UUID is guaranteed to be unique to this computer only.
    RPC_S_UUID_NO_ADDRESS = 1739 //Cannot get Ethernet or token-ring hardware address for this computer.
}

Function to create sequencial Guid
public Guid CreateGuid()
{
   Guid guid;
   int result = UuidCreateSequential(out guid);
   if (result == (int)RetUuidCodes.RPC_S_OK)
      return guid;
   else
      return Guid.NewGuid();
}

In functions generate sequencial Guid using following
Guid uid = CreateGuid();
Reference
http://stackoverflow.com/questions/170346/what-are-the-performance-improvement-of-sequential-guid-over-standard-guid

Saturday, June 23, 2012

Creating Wizard using C# Form (Tab Control)

In one of the previous posting there is a Wizard implementation which used console application and multiple forms. But sometimes requirements are so that implementation needed to some sort of Wizard type but not with all pomp and show, even time constraint makes it hard to achieve an evolving application.

Creating Wizard using tab control is the other to do that, it is simple way to do that. It is a single form implementation with Wizard flavor. This implementation has following basic tweaks to achieve, rest of the implementations and functionality are user specific:

  1. Inherit TabControl and hide tabs by supressing TCM_ADJUSTRECT
  2. Then replace the instance of TabControl Class object initialisation with your class (in my case I names WizardTabControl). Do this replacement once you have completed the screen design and feature is complete.
  3. Set the dock property to Fill for TabPage

Implementation:
Following changes in Form.Designer.cs is the only thing needed. Add Following code at the end to inherit the TabControl class.
namespace System.Windows.Forms
{
    public class WizardTabControl : TabControl
    {
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x1328 && !DesignMode) // Hide tabs by trapping the TCM_ADJUSTRECT message
                m.Result = IntPtr.Zero;
            else
                base.WndProc(ref m);
        }
    }
}

Changes in Form class, replace the TabControl reference with WizardTabControl
private System.Windows.Forms.WizardTabControl tabControl1;
private void InitializeComponent()
{
    this.tabControl1 = new System.Windows.Forms.WizardTabControl();
}

Saturday, June 16, 2012

WiX Custom Action – delete files before installation

In this implementation before installing MSI need to achieve following task:

  1. Delete the files from specific folders like .log, .ini, .dll etc. but configurable. 
  2. List of files to delete need to be configurable so that in future if new files are identified then make the change in configuration file and it will work. This list is something that needs to be provided with installer but at the same time will be only delivering MSI and not config file. 
Steps in Implementation:

  1. Create simple XML file (let say ConfigXML.xml) for maintaining list of files to delete. 
  2. Add ConfigXML.xml in MSI as an external binary file which is not part of basic installer package. 
  3. In MSI installation process add custom action before installation to retrieve file and delete those files. To implement Custom Action used C# DLL with WiX 3.5.

In the example below reading files from XML and deleting it is not included that will be taken separately. File deletion implementation left to user to implement.

XML file (ConfigXML.xml)
<?xml version="1.0" ?>
<root>
  <Node Path="c:\abc">a1.log</Node>
  <Node Path="d:\abc">a2.ini</Node>
  <Node Path="f:\abc">a3.dll</Node>
</root>

Changes in the .wxs file
<Binary Id="TestxxxXML.xml" SourceFile="d:\TestCfgXML.xml"/>
<Binary Id="myActDLL" SourceFile="d:\MyAction.CA.dll"/>

<CustomAction Id="deleteAction" BinaryKey="myActDLL" DllEntry="DeleteFiles" Impersonate="no" Execute="deferred" Return="check" />

<InstallUISequence>
  <Custom Action="deleteAction" After="ValidateProductID" >NOT Installed</Custom>
</InstallUISequence>
<InstallExecuteSequence>
  <Custom Action="deleteAction" After="ValidateProductID" >NOT Installed</Custom>
</InstallExecuteSequence>

Custom Action DLL implementation
namespace MyAction
{
    public class CustomActionClass
    {
        [CustomAction]
        public static ActionResult DeleteFiles(Session session)
        {
            try
            {
                string sPath = Path.Combine(Path.GetTempPath(), "TestXML.xml");
                var f = File.Create(sPath);
                
                using (var view = session.Database.OpenView("SELECT `Data` FROM `Binary` WHERE `Name` = `TestxxxXML.xml`", "testbinary"))
                {
                    view.Execute();
                    var rec = view.Fetch();
                    var Strm = rec.GetStream("Data");
                    if (Strm != null)
                    {
                        using (f)
                        {
                            byte[] buf = new byte[Int32.MaxValue];
                            int len;
                            while ((len = Strm.Read(buf, 0, buf.Length)) > 0)
                            {
                                file.Write(buf, 0, len);
                            }
                        }
                    }
                }
                f.Close();
                // From here code the operation to read from XML and delete those files; I would suggest you to use PLINQ for it.
            }
            catch (Exception e)
            {
                return ActionResult.Failure;
            }
            return ActionResult.Success;
        }
    }
}

Saturday, June 9, 2012

Creating Wizard using C# Form and Console (multiple Forms)

This is a simple implementation of Wizard using multiple forms in C#. We can use Wizard templates available but sometimes to have flexibility and control over the operations we can use console application and build workflow to display forms.

For Wizard in order to maintain all the data you can have a separate data layer which if possibly build with Singleton design pattern. Following is the basic example of how to implement workflow of Forms in a console application. It is advisable to refer other examples on net which can be more efficient.

I will appreciate if you give suggestions for more improvement. Use comment section for it.

Implementation:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace SampleExe
{
    class Program
    {
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        [STAThread()]
        static void Main()
        {
            int iDlg = 0;
            // Hide console window
            IntPtr hWnd = FindWindow(null, Console.Title);
            if (hWnd != IntPtr.Zero)
                ShowWindow(hWnd, 0);

            // Initialize all the forms
            // For all the forms as required you need to have Next, Previous and Cancel button
            // Set Dialog Result property
            // Next button -> Yes
            // Previous button -> No
            // Cancel button -> Cancel 
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Form1 X1 = new Form1();
            Form2 X2 = new Form2();
            Form3 X3 = new Form3();
            Form4 X4 = new Form4();
            Form5 X5 = new Form5();
            DialogResult dlForm = DialogResult.Yes;
            while (dlForm != DialogResult.Cancel)
            {
                if (dlForm == DialogResult.Yes)
                {
                    iDlg++;
                    switch (iDlg)
                    {
                        case 1:
                            dlForm = X1.ShowDialog();
                            break;
                        case 2:
                            dlForm = X2.ShowDialog();
                            break;
                        case 3:
                            dlForm = X3.ShowDialog();
                            break;
                        case 4:
                            dlForm = X4.ShowDialog();
                            break;
                        case 5:
                            dlForm = X5.ShowDialog();
                            break;
                        default:
                            dlForm = DialogResult.Cancel;
                            break;
                    }
                }
                else if (dlForm == DialogResult.No)
                {
                    iDlg--;
                    switch (iDlg)
                    {
                        case 1:
                            dlForm = X1.ShowDialog();
                            break;
                        case 2:
                            dlForm = X2.ShowDialog();
                            break;
                        case 3:
                            dlForm = X3.ShowDialog();
                            break;
                        case 4:
                            dlForm = X4.ShowDialog();
                            break;
                        case 5:
                            dlForm = X5.ShowDialog();
                            break;
                        default:
                            dlForm = DialogResult.Cancel;
                            break;
                    }
                }
            }
        }
    }
}
reference:
http://stackoverflow.com/questions/2211514/suppress-command-window-from-started-command-line-application-with-net?rq=1

Saturday, June 2, 2012

XML page using XSLT - one table page with different flavours

For some time now I am working on building a generic XSL which can be used to format different XML as per the defined standard. In this posting will be showing you the basic logic of building the XML and XSL. This has been created manually; will be working further to automate the XML generation as well as XSL generation.

Following screenshots of the webpage that has been generated and following objectives has been achieved in implementation.
  1. One standard XSL for generating formatting multiple XML. 
  2. Display all data in a single page in different ways. 
  3. XML should contain instructions of how data should get displayed and not XSL. 
Page when loaded:












Page when expanded:

Implementation:
I am not describing how it has been implemented but use both the XML and XSL to generate your page. Get your hands dirty and understand it and try to implement it the way you want. Basic things in implementation one Tag bifurcated by Type; how to display data depends upon Type (List/ Record/ Field)

Sample XML
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="TEST_XSL.xsl"?>
<Node Desc="XXX Screen" Type="ReplyScreen">
  <Node Type="List" Desc="General Header" DisplayINList="NO">
    <Node Type="Record" Desc="" BOLD="YES">
      <Node Type="Field">
        <Label1>Name</Label1>
        <Data1>Test Name</Data1>
        <Label2>Status</Label2>
        <Data2>Test Status</Data2>
      </Node>
      <Node Type="Field">
        <Label1>Code</Label1>
        <Data1>XYZ</Data1>
        <Label2>Number</Label2>
        <Data2>*********901</Data2>
      </Node>
    </Node>
  </Node>
  <Node Type="List" Desc="" DisplayINList="YES">
    <Node Type="Record" Desc="Other Details" BOLD="YES">
      <Node Type="Field">
        <Label1>Address Line 1</Label1>
        <Data1>1234 XXXX</Data1>
        <Label2>Address Line 2</Label2>
        <Data2>7890 YYYY</Data2>
      </Node>
      <Node Type="Field">
        <Label1>Name 1</Label1>
        <Data1>TEST NAME 1</Data1>
        <Label2>Name 2</Label2>
        <Data2>TEST NAME 2</Data2>
      </Node>
    </Node>
  </Node>
  <Node Type="List" Desc="XXX Details" DisplayINList="YES">
    <Node Type="Record" Desc="55 - 000003002009 Amount 10.00" BOLD="YES">
      <Node Type="Field">
        <Label1>Code</Label1>
        <Data1>55</Data1>
        <Label2>Number</Label2>
        <Data2>*********009</Data2>
      </Node>
      <Node Type="Field">
        <Label1>Date</Label1>
        <Data1>07/14/03</Data1>
        <Label2>Expire Date</Label2>
        <Data2>99/99/99</Data2>
      </Node>
    </Node>
    <Node Type="Record" Desc="00 - 000000000001 Amount 100.00" BOLD="YES">
      <Node Type="Field">
        <Label1>B1</Label1>
        <Data1>XXX 1</Data1>
        <Label2>B2</Label2>
        <Data2>XXX 2</Data2>
      </Node>
      <Node Type="Field">
        <Label1>B</Label1>
        <Data1>100207</Data1>
        <Label2>Date</Label2>
        <Data2>99/99/99</Data2>
      </Node>
    </Node>
  </Node>
  <Node Type="List" Desc="Name Details" DisplayINList="NO">
    <Node Type="Record" Desc="" BOLD="YES">
      <Node Type="Field">
        <Label1>A1</Label1>
        <Data1>Description 1</Data1>
        <Label2>@#$%^</Label2>
        <Data2>@#$%^</Data2>
      </Node>
      <Node Type="Field">
        <Label1>A2</Label1>
        <Data1>Description 2</Data1>
        <Label2>@#$%^</Label2>
        <Data2>@#$%^</Data2>
      </Node>
    </Node>
  </Node>
  <Node Type="List" Desc="Other Messages" DisplayINList="NO">
    <Node Type="Record" Desc="Message 1" BOLD="NO" />
    <Node Type="Record" Desc="Message 2" BOLD="NO" />
  </Node>
</Node>

Sample XSL
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
    <head>
      <script language="JavaScript">
        <xsl:comment>
          <![CDATA[
 
         function GetElemParent(elem)
         {
          var ret = null;
          if(elem.level == 1)
           return ret;
          var prevSibling = elem.previousSibling;
          while(prevSibling)
          {
           if(parseInt(prevSibling.level) == (parseInt(elem.level) - 1))
           {
            ret = prevSibling;
            break;
           }
           prevSibling = prevSibling.previousSibling;
          }
          return ret;
         }
         
         function GetElemChildren(elem)
         {
          var ret = new Array();
          
          var index = 0;
          var nextSibling = elem.nextSibling;
          while(nextSibling)
          {
           if(parseInt(nextSibling.level) == (parseInt(elem.level) + 1))
           {
            ret[index] = nextSibling;
            index++;
           }
           else if(parseInt(nextSibling.level) == parseInt(elem.level))
            break;
           nextSibling = nextSibling.nextSibling;
          }
          return ret;
         }
         
         function ExpandElement(elem)
         {
          var children = GetElemChildren(elem);
          for(var i = 0; i < children.length; i++)
          {
           var child = children[i];
           ShowElement(child);
          }
         }
         
         function CollapseElement(elem)
         {
          var children = GetElemChildren(elem);
          for(var i = 0; i < children.length; i++)
          {
           var child = children[i];
           HideElement(child);
          }
         }
         
         function ShowElement(elem)
         {
          elem.style.display = "";
          if(IsElementExpanded(elem))
          {
           var children = GetElemChildren(elem);
           for(var i = 0; i < children.length; i++)
           {
            var child = children[i];
            ShowElement(child);
           }
          }
         }
         
         function IsElementExpanded(elem)
         {
          var expanded = elem.children(0).expanded;
          if(expanded == undefined)
           return true;
          return expanded;
         }
         
         function HideElement(elem)
         {
          elem.style.display = "none";
          var children = GetElemChildren(elem);
          for(var i = 0; i < children.length; i++)
          {
           var child = children[i];
           HideElement(child);
          }
         }
         
         function DoExpandClick(elem)
         {
          if(window.event.srcElement.tagName == "IMG")
          {
           if(elem.expanded)
           {
            var parent = elem.parentElement;
            CollapseElement(parent);
            
            elem.expanded = false;
            elem.rowSpan = "1";
            elem.getElementsByTagName("IMG")(0).src = "expand.gif";
           }
           else
           {
            var parent = elem.parentElement;
            ExpandElement(parent);
            
            elem.expanded = true;
            elem.rowSpan = elem.rowspancfg;
            elem.getElementsByTagName("IMG")(0).src = "collapse.gif";
           }
          }
         }
         function DoCollapseLoad(elem)
         {
          var children = elem.all;
          for(var i = 0; i < children.length; i++)
          {
           var child = children[i];
           if (child.nodeName == "IMG")
           {
            child.click();
           }
          }
         }
        ]]>//
        </xsl:comment>
      </script>
     <h2 align="center">
       <xsl:apply-templates select="//Node" mode="head"/>
     </h2>
    </head>
    <body style="background-color:#d0e4fe; font-family:'Arial';" onload="DoCollapseLoad(document.firstChild)">
      <table border="0" cellpadding="1" style="border: 1px solid green; border-collapse:collapse; border-separation=0px" cellspacing="0">
        <xsl:apply-templates select="//Node" mode="row"/>
      </table>
    </body>
  </html>
</xsl:template>

<xsl:template match="Node" mode="head">
  <xsl:if test ="@Type='ReplyScreen'">
    <xsl:value-of select="@Desc"/>
  </xsl:if>
</xsl:template>

<xsl:template match="Node" mode="row">
  <xsl:if test ="@Type='Record' and @Desc!=''">
    <tr level="1" style="border:1px solid green;">
      <xsl:apply-templates select="self::Node" mode="popcell"/>
    </tr>
  </xsl:if>
  <xsl:if test ="@Type='Field'">
    <tr level="2">
      <xsl:apply-templates select="self::Node" mode="popcell"/>
    </tr>
  </xsl:if>
  <xsl:if test ="@Type='List' and @Desc!=''">
    <tr level="1">
      <xsl:apply-templates select="self::Node" mode="popcell"/>
    </tr>
  </xsl:if>
</xsl:template>

<xsl:template match="Node" mode="popcell">
  <xsl:if test ="@Type='Record' and ../@DisplayINList='YES'">
    <td valign="top"  expanded="true" onclick="DoExpandClick(this)">
      <xsl:if test="count(@Desc)>0">
        <xsl:variable name="rowspancount" select="count(child::Node) + 1"/>
        <xsl:attribute name ="rowspan">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
        <xsl:attribute name="rowspancfg">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="count(@Desc)=0">
        <xsl:variable name="rowspancount" select="count(child::Node)"/>
        <xsl:attribute name ="rowspan">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
        <xsl:attribute name="rowspancfg">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
      </xsl:if>
      <img src="./collapse.gif"/>
    </td>
    <xsl:if test="count(@Desc)>0">
      <xsl:if test="@BOLD='YES'">
        <td width="100%" valign="top" style="font-weight: bold; font-size:11pt; border:1px solid green;" colspan="4" bgcolor="#BDBDBD">
          <xsl:value-of select="@Desc"/>
        </td>
      </xsl:if>
      <xsl:if test="@BOLD='NO'">
        <td width="100%" valign="top" colspan="4" bgcolor="#F2F2F2" style="font-size:11pt; border:1px dotted green;"><!--assuming that data will display--> 
          <xsl:value-of select="@Desc"/>
        </td>
      </xsl:if>
    </xsl:if>
  </xsl:if>
  <xsl:if test ="@Type='Record' and ../@DisplayINList='NO'">
    <td valign="top"  expanded="true">
      <xsl:if test="@Desc!=''">
        <xsl:variable name="rowspancount" select="count(child::Node) + 1"/>
        <xsl:attribute name ="rowspan">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
        <xsl:attribute name="rowspancfg">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
      </xsl:if>
      <xsl:if test="@Desc=''">
        <xsl:variable name="rowspancount" select="count(child::Node)"/>
        <xsl:attribute name ="rowspan">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
        <xsl:attribute name="rowspancfg">
          <xsl:value-of select="$rowspancount"/>
        </xsl:attribute>
      </xsl:if>
    </td>
    <xsl:if test="@Desc!=''">
      <xsl:if test="@BOLD='YES'">
        <td width="100%" valign="top" colspan="4" bgcolor="#BDBDBD" style="font-weight: bold; font-size:11pt; border:1px solid green;">
          <xsl:value-of select="@Desc"/>
        </td>
      </xsl:if>
      <xsl:if test="@BOLD='NO'">
        <td width="100%" valign="top" colspan="4" bgcolor="#F2F2F2" style="font-size:11pt; border:1px dotted green;">
          <xsl:value-of select="@Desc"/>
        </td>
      </xsl:if>
    </xsl:if>
  </xsl:if>
  <xsl:if test ="@Type='Field'">
    <xsl:if test ="Label1[.!=''] and Data1[.!=''] and Label2[.!=''] and Label2[.!='@#$%^'] and Data2[.!=''] and Data2[.!='@#$%^']">
 <xsl:if test ="../@Type='Record' and ../@Desc=''">
  <td></td>
 </xsl:if>
      
   <td width="25%" valign="top" bgcolor="#D8D8D8" style="font-weight: bold; font-size:11pt; border:1px solid green;">
        <xsl:value-of select="Label1"/>
      </td>
      <td width="25%" valign="top" bgcolor="#F2F2F2" style="font-size:11pt; border:1px solid green;">
        <xsl:value-of select="Data1"/>
      </td>
      <td width="25%" valign="top" bgcolor="#D8D8D8" style="font-weight: bold; font-size:11pt; border:1px solid green;">
        <xsl:value-of select="Label2"/>
      </td>
      <td width="25%" valign="top" bgcolor="#F2F2F2" style="font-size:11pt; border:1px solid green;">
        <xsl:value-of select="Data2"/>
      </td>
    </xsl:if>
    <xsl:if test ="Label1[.!=''] and Data1[.!=''] and Label2[.='@#$%^'] and Data2[.='@#$%^']">
 <xsl:if test ="../@Type='Record' and ../@Desc=''">
  <td></td>
 </xsl:if>
      
   <td width="25%" valign="top" bgcolor="#D8D8D8" style="font-weight: bold; font-size:11pt; border:1px solid green;">
        <xsl:value-of select="Label1"/>
      </td>
      <td width="75%" valign="top" bgcolor="#F2F2F2" colspan="3" style="font-size:11pt; border:1px solid green;">
        <xsl:value-of select="Data1"/>
      </td>
    </xsl:if>
  </xsl:if>
  <xsl:if test ="@Type='List'">
    <td></td>
    <td width="100%" valign="top" style="font-weight: bold; font-size:11pt; border:1px solid green;" colspan="4" bgcolor="#A9BCF5">
      <xsl:value-of select="@Desc"/>
    </td>
  </xsl:if>
</xsl:template>
</xsl:stylesheet>