Sunday, October 2, 2011

WPF Collapsible Panel

In this article I have describe way to create a collapsible panel in WPF. This is one of the most common questions asked by many developers. Collapsible Panel can be used by user to collapse the content which he doesn't want to use and see only core information and hence keep the screen clean.
WPFCollapsiblePanel
This sample inherits the Expander control which is available in WPF. It support panel collapse in all the four directions (left, right, top and bottom).
public class CollapsiblePanel : Expander
{
static CollapsiblePanel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CollapsiblePanel), new FrameworkPropertyMetadata(typeof(CollapsiblePanel)));
}
}

Here is the XAML for CollapsiblePanel

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" 
xmlns:local="clr-namespace:CollapsiblePanelDemo">

<local:MultiplyConverter x:Key="multiplyConverter" />

<Style x:Key="ExpanderHeaderFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle SnapsToDevicePixels="true" Margin="0" Stroke="Black" StrokeDashArray="1 2" StrokeThickness="1" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="ExpanderUpHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<Grid.LayoutTransform>
<RotateTransform Angle="90"/>
</Grid.LayoutTransform>


<Path x:Name="trapazoid" Fill="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}"  HorizontalAlignment="Center"   VerticalAlignment="Center">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="0,0" >
<PathFigure.Segments>

<ArcSegment Size="25,25" RotationAngle="45" IsLargeArc="False" SweepDirection="Clockwise" Point="0,48"/>

</PathFigure.Segments>
</PathFigure >
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>



<Path x:Name="arrow" Data="M 1,1.5 L 9,9 L 1,16 1, 1" HorizontalAlignment="Center" SnapsToDevicePixels="false" Fill="{Binding Path=BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}" StrokeThickness="2" VerticalAlignment="Center"/>

</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Data" TargetName="arrow" Value="M 9,1 L 1,8 L 9,16, 9,1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="ExpanderLeftHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">



<Path x:Name="trapazoid" Fill="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}"  HorizontalAlignment="Center"   VerticalAlignment="Center">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="0,0" >
<PathFigure.Segments>

<ArcSegment Size="25,25" RotationAngle="45" IsLargeArc="False" SweepDirection="Clockwise" Point="0,48"/>

</PathFigure.Segments>
</PathFigure >
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path x:Name="arrow" Data="M 1,1.5 L 9,9 L 1,16 1, 1" HorizontalAlignment="Center" SnapsToDevicePixels="false" Fill="{Binding Path=BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}" StrokeThickness="2" VerticalAlignment="Center"/>

</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Data" TargetName="arrow" Value="M 9,1 L 1,8 L 9,16, 9,1"/>
</Trigger>

</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="ExpanderRightHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<Grid.LayoutTransform>
<RotateTransform Angle="180"/>
</Grid.LayoutTransform>

<Path x:Name="trapazoid" Fill="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}"  HorizontalAlignment="Center"   VerticalAlignment="Center">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="0,0" >
<PathFigure.Segments>

<ArcSegment Size="25,25" RotationAngle="45" IsLargeArc="False" SweepDirection="Clockwise" Point="0,48"/>

</PathFigure.Segments>
</PathFigure >
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path x:Name="arrow" Data="M 1,1.5 L 9,9 L 1,16 1, 1" HorizontalAlignment="Center" SnapsToDevicePixels="false" Fill="{Binding Path=BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}" StrokeThickness="2" VerticalAlignment="Center"/>

</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Data" TargetName="arrow" Value="M 9,1 L 1,8 L 9,16, 9,1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style x:Key="ExpanderDownHeaderStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<Grid.LayoutTransform>
<RotateTransform Angle="-90"/>
</Grid.LayoutTransform>


<Path x:Name="trapazoid" Fill="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}"  HorizontalAlignment="Center"   VerticalAlignment="Center">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="0,0" >
<PathFigure.Segments>

<ArcSegment Size="25,25" RotationAngle="45" IsLargeArc="False" SweepDirection="Clockwise" Point="0,48"/>

</PathFigure.Segments>
</PathFigure >
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
<Path x:Name="arrow" Data="M 1,1.5 L 9,9 L 1,16 1, 1" HorizontalAlignment="Center" SnapsToDevicePixels="false" Fill="{Binding Path=BorderBrush, RelativeSource={RelativeSource FindAncestor, AncestorType=local:CollapsiblePanel}}" StrokeThickness="2" VerticalAlignment="Center"/>

</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="Data" TargetName="arrow" Value="M 9,1 L 1,8 L 9,16, 9,1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="{x:Type local:CollapsiblePanel}">
<Setter Property="Background" Value="LightGray"/>
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<Border SnapsToDevicePixels="true">
<DockPanel>

<ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="0" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" Style="{StaticResource ExpanderDownHeaderStyle}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>


<Grid  
x:Name="ExpandSiteContainer"  
Visibility="Visible"  
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"  
Margin="{TemplateBinding Padding}"  
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"  
DockPanel.Dock="Bottom"                                        
>

<Grid.Tag>
<sys:Double>0.0</sys:Double>
</Grid.Tag>
<ScrollViewer  
VerticalScrollBarVisibility="Hidden"  
HorizontalScrollBarVisibility="Hidden"  

>
<ContentPresenter  
x:Name="ExpandSite"  
Focusable="false"  
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
>
</ContentPresenter>
</ScrollViewer>
</Grid>
</DockPanel>
</Border>
<ControlTemplate.Triggers>

<Trigger Property="IsExpanded" Value="true">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName ="ExpandSiteContainer"   
Storyboard.TargetProperty ="Tag"  
To="1.0" Duration ="0:0:0.45" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName ="ExpandSiteContainer"   
Storyboard.TargetProperty ="Tag"  
To="0" Duration ="0:0:0.45"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>

<Trigger Property="ExpandDirection" Value="Down">
<Setter Property="Height" TargetName="ExpandSiteContainer">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpandSite"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Right">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderRightHeaderStyle}"/>
<Setter Property="Width" TargetName="ExpandSiteContainer">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualWidth" ElementName="ExpandSite"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Up">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderUpHeaderStyle}"/>
<Setter Property="Height" TargetName="ExpandSiteContainer">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualHeight" ElementName="ExpandSite"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ExpandDirection" Value="Left">
<Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
<Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
<Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderLeftHeaderStyle}"/>
<Setter Property="Width" TargetName="ExpandSiteContainer">
<Setter.Value>
<MultiBinding Converter="{StaticResource multiplyConverter}">
<Binding Path="ActualWidth" ElementName="ExpandSite"/>
<Binding Path="Tag" RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>

</Style>
</ResourceDictionary>


Following is the example of using CollapsiblePanel control in WPF.

<my:CollapsiblePanel Grid.Row="2" Grid.Column="1" Header="Toolbar Demo" ExpandDirection="Down" x:Name="Expander2" BorderBrush="Yellow" Background="{StaticResource ToggleButtonBrush}" IsExpanded="False">
<my:CollapsiblePanel.Content>
<Image Source="/CollapsiblePanelDemo;component/Images/Koala.jpg" Height="240"  Stretch="Fill"   />
</my:CollapsiblePanel.Content>
</my:CollapsiblePanel>

You can download complete source code from following link
Download Source Code

Sunday, July 31, 2011

Encrypt & Serialize an object

Serialization can be defined as the process of storing the state of an object instance to a storage medium. During this process, the public and private fields of the object and the name of the class, including the assembly containing the class, is converted to a stream of bytes, which is then written to a data stream. When the object is subsequently deserialized, an exact clone of the original object is created.

But many of the time we need to encrypt the object before saving it in the file, database, etc to protect from misuse. So we have first serialize the object into bytes and then we can encrypt the bytes using Cryptography.

Below is the code snippet to encrypt/decrypt the object in VB.net. Key in the code snippet is like a password which should be same during encryption and decryption.

Encrypt Code

Public Function Encrypt(Of T)(ByVal value As T, ByVal key As String) As Byte()

        Using strm As New MemoryStream
            Dim crypt As New TripleDESCryptoServiceProvider
            Dim slt() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
            Dim pdb As New Rfc2898DeriveBytes(key, slt)
            Dim bytDerivedKey() As Byte = pdb.GetBytes(24)
            crypt.Key = bytDerivedKey
            crypt.IV = pdb.GetBytes(8)

            Using cstream As New CryptoStream(strm, crypt.CreateEncryptor, CryptoStreamMode.Write)
                Dim bFormatter As New BinaryFormatter
                bFormatter.Serialize(cstream, value)
                cstream.Close()
                strm.Close()
            End Using

            Return strm.ToArray
        End Using
    End Function

Decrypt Code

Public Function Decrypt(Of T)(ByVal bytes() As Byte, ByVal key As String) As T
        Dim value As T

        Using strm As New MemoryStream(bytes)
            Dim crypt As New TripleDESCryptoServiceProvider
            Dim slt() As Byte = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
            Dim pdb As New Rfc2898DeriveBytes(key, slt)
            Dim bytDerivedKey() As Byte = pdb.GetBytes(24)
            crypt.Key = bytDerivedKey
            crypt.IV = pdb.GetBytes(8)

            Using cstream As New CryptoStream(strm, crypt.CreateDecryptor, CryptoStreamMode.Read)
                Dim bFormatter As New BinaryFormatter
                value = bFormatter.Deserialize(cstream)
                cstream.Close()
                strm.Close()
            End Using
        End Using
        Return value
    End Function

Example to use above functions

<Serializable()>
    Public ClassCustomer
      
Public PropertyCustomerID As Integer
        Public Property
CustomerName As String
    End Class

    Private Sub
SaveCustomer()
        Dim d As New Customer
       
d.CustomerID = 1
d.CustomerName = "GAURAV"
       
Dim bytes() As Byte = Encrypt(Of Customer)(d, "54321")
        My.Computer.FileSystem.WriteAllBytes("E:\Test.dat", bytes, False)
    End Sub

    Private Sub
LoadCustomer()
        Dim bytes() As Byte = My.Computer.FileSystem.ReadAllBytes("E:\Test.dat")
        Dim objCustomer As Customer = Decrypt(Of Customer)(bytes, "54321")
    End Sub


Thursday, May 5, 2011

ProcessCmdKey in Windows Form

Many time we need to trap the key pressed in Windows Form and based on it perform some operation. For example, stop user from closing the application when user press Alt+F4. Or want to stop user from moving from one child form to another child in a mdi form using Ctrl+Tab or stop user from moving from one tabpage to another tabpage in TabControl control. In this case ProcessCmdKey method is the best option.

ProcessCmdKey is a method in .NET which process the command key. This method is called during message preprocessing to handle command keys. Command keys are keys that always take precedence over regular input keys. The method return true to indicate that it has processed the command key, or false to indicate that the key is not a command key. This method is only called when the control is hosted in a Windows Forms application or as an ActiveX control.

The following example with stop user from closing the form when user press Alt+F4 and also stop user from navigate to another tabpage or child form by using Ctrl+Tab.

    Public Class Form1
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
If
keyData = (Keys.Alt Or Keys.F4) Then
Return True
ElseIf
keyData = (Keys.Control Or Keys.Tab) Then
Return True
Else
Return MyBase
.ProcessCmdKey(msg, keyData)
End If
End Function
End Class

Friday, April 29, 2011

Programmically toggling capslock button

VB.NET doesn’t contain any function through which we can On/Off capslock button in the keyboard. VB.NET has one function called My.Computer.Keyboard.CapsLock but it is readonly so we cannot change it. Capslock key also cannot be toggled by using SendKeys,Send() method. So only way to toggle the capslock key is by using WinAPIs. There is a function called keybd_event which can toggle the capslock key

Private Declare Sub keybd_event Lib "user32" (ByVal key As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)

    Private Sub ToggleCapslock()
        keybd_event(Keys.Capital, 0, 0, 0)
        keybd_event(Keys.Capital, 0, &H2, 0)
    End Sub

In the above example we have called the keybd_event function twice. First for Keydown and second time for KeyUp (&H2 is value for KeyUp). If we want the code to work only to set capslock Off then we can change the code as below

   Private Sub SetCapslockOff()
If My.Computer.Keyboard.CapsLock = True Then
keybd_event(Keys.Capital, 0, 0, 0)
keybd_event(Keys.Capital, 0, &H2, 0)
Else
'Already off
End If
End Sub

Sunday, April 10, 2011

Tab key work as an Enter key in Datagridview

To make the Tab key work as Enter key, we have to inherit DataGridView controls and override two methods ProcessDataGridViewKey and ProcessDialogKey. In both the methods if the user has click Tab then we have to ProcessEnterKey of Datagridview.

Public Class NewDataGridView
Inherits DataGridView

Protected Overrides Function ProcessDataGridViewKey(ByVal e As System.Windows.Forms.KeyEventArgs) As Boolean
If e.KeyCode = Keys.Tab Then
Me.ProcessEnterKey(e.KeyData)
Return True
End If
Return MyBase.ProcessDataGridViewKey(e)
End Function

Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
If keyData = Keys.Tab Then
Me.ProcessEnterKey(keyData)
Return True
End If
Return MyBase.ProcessDialogKey(keyData)
End Function
End Class

Thursday, March 3, 2011

HttpWebRequest AddRange with Long values

HttpWebRequest contains a method called AddRange which is very useful when we want to download a file in segments or want to resume the download from where it was stopped previously. But HttpWebRequest.AddRange has one drawback, the parameters for range of bytes is in integer which means only range upto approximately 2 GB is allowed. So we cannot use this method if we want to use it for downloading files in Range greater than 2 GB. If we try to add value greater than “2147483647”  we will get following exception.

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

So the solution for this problem is to extend the AddRange method with support for long parameters. HttpWebRequest has a private function AddRange which have three string parameters which we can use with Reflection classes.

Private Function AddRange(ByVal rangeSpecifier As String, ByVal fromValue As String, ByVal toValue As String) As Boolean

So now we can use Reflection and add two method with parameter in Long to allow larger value.

Imports System.Reflection
Imports System.Net
Imports System.Runtime.CompilerServices 

Public Module MyModule
#Region "HttpWebRequest AddRange"

    <Extension()> _
    Public Sub AddRange(ByVal request As HttpWebRequest, ByVal from As Long, ByVal [to] As Long)
        Dim info As MethodInfo = Nothing
        Dim methods() As MethodInfo = GetType(Net.HttpWebRequest).GetMethods(BindingFlags.Instance Or BindingFlags.NonPublic)

        For Each mi As MethodInfo In methods
            If mi.Name = "AddRange" Then
                info = mi
                Exit For
            End If
        Next
        If info IsNot Nothing Then
            Dim parameters(2) As Object
            parameters(0) = "bytes"
            parameters(1) = from.ToString
            parameters(2) = [to].ToString
            info.Invoke(request, parameters)
        End If
    End Sub

    <Extension()> _
    Public Sub AddRange(ByVal request As HttpWebRequest, ByVal from As Long)
        Dim info As MethodInfo = Nothing
        Dim methods() As MethodInfo = GetType(Net.HttpWebRequest).GetMethods(BindingFlags.Instance Or BindingFlags.NonPublic)
        For Each mi As MethodInfo In methods
            If mi.Name = "AddRange" Then
                info = mi
                Exit For
            End If
        Next

        If info IsNot Nothing Then
            Dim parameters(2) As Object
            parameters(0) = "bytes"
            parameters(1) = from.ToString
            parameters(2) = String.Empty
            info.Invoke(request, parameters)
        End If
    End Sub
#End Region
End Module

After adding above code in the project, two new HttpWebRequest.AddRange method will get added with long parameter.

HttpWebRequest.AddRange(byval from as Long)
HttpWebRequest.AddRange(byval from as Long,byval to as Long)

Now you can use this methods as shown in following code

Dim startPosition As Long = Integer.MaxValue
Dim endPosition As Long = startPosition + 1000
Dim request As HttpWebRequest = WebRequest.Create("Url")
request.AddRange(startPosition, endPosition)

Tuesday, March 1, 2011

Review: Crypto Obfuscator for .NET 2011

All .NET codes written in .Net language when compiled are converted to MSIL. But there are many decompilers available through which we can reverse engineer the code, which means software licensing code, copy protection mechanisms, proprietary business logic, passwords, etc. get accessible to everyone. So to protect from code from misuse Obfuscator are available that provides for seamless renaming of symbols in assemblies as well as other tricks to foil decompilers. Properly applied obfuscation can increase the protection against decompilation by many orders of magnitude, while leaving the application intact.
There are many .NET obfuscators available today. Crypto Obfuscator For .Net is one of the great obfuscator which supports all versions of the .Net framework from v1.0 to v4.0. It also supports the .Net Compact Framework, Silverlight and XNA. It can protect assemblies created with any .Net language including C#, VB.Net, Managed C++, J#, etc.
Following are few key features available in “Crypto Obfuscator for .NET 2011”
Symbol Renaming – Crypto Obfuscator renames all your class, field, method, properties, methods, parameter and generic parameter names to totally different strings. It is impossible to determine the original names from the new names. This makes it impossible for someone to try to determine the purpose or functionality of the renamed entity from its name.
String Encryption – Literal strings often contain sensitive information such as login information, passwords, SQL queries, algorithm parameters. They also facilitate reverse-engineering of your .Net code. Crypto Obfuscator solves all these issues by encrypting all literal strings in your .Net code.
Anti-Reflection Protection – Many decompilers, dissassemblers and memory dumpers use Reflection to extract information about a .Net assembly. Crypto Obfuscator can modify the assembly in such a way that such tools will fail when trying to work on your assembly.
Anti-Decompiler Protection – Advanced decompilers such as the freely available .Net Reflector are your enemy in the battle against the hackers, crackers and competitors. Crypto Obfuscator can modify your assembly in such a way that such tools fail to work on your assembly – many times they are not even able to open your assembly, let alone examine it.
Advanced Tamper Detection – Crypto Obfuscator can perform strong name verification of the assembly itself even if strong-name verification has been turned OFF on the machine on which the assembly is running or if the assembly has been registered in the verification ’skip-list’ – this is typically done by hackers or crackers. Furthermore, the strong name verification is done using the original key used to sign the assembly when it was processed by Crypto Obfuscator. Thus, strong name verification fails even if the key is removed or replaced – again something typically done by hackers or crackers.
Advanced Anti-Debug + Anti-Tracer Protection – Crypto Obfuscator’s performs more than 10 advanced heuristic tests to detect if your software is running under a debugger or tracer. If detected, an exception is throw and your software will terminate. Both managed as well as native/unmanaged debuggers (including advanced debuggers such as OllyDbg) are detected. This provides a strong defense against crackers and hackers trying to debug or trace your software for various malicious purposes.
Advanced Overload Renaming – Crypto Obfuscator can also rename fields or methods with different signatures to the same name. For example two fields having types int and boolean will be given the same name. Similarly two methods will different parameters will be given the same name. In the case of methods, the method return type is also used in the signature even though high-level languages such as C# and VB.Net do not support overloading by return type. The .Net runtime is able to differentiate between the fields/methods without any problem since the signatures are different. Needless to say, this scheme makes it even harder to reverse-engineer your code.
Control Flow Obfuscation – Many advanced decompilers can reconstruct the code in your methods including the exact structure of your loops, if-else statements, method calls, try-catch blocks, etc. This makes it very easy to revere-engineer your code. Crypto Obfuscator changes the structure of your code into spaghetti code while maintaining 100% the logic and output of the code. The result is that decompilers are unable to reconstruct the code structure and most of the times they crash while trying to do so.
Watermarking – Crypto Obfuscator can embed watermark strings into your deployed assemblies. This can be used to track each assembly instance – this is commonly used for licensing by embedding user name and license codes as watermarks to deter license violations. The watermarks embedded in the assembly can be used in literal strings and constants to be used in your UI, message boxes, etc.
ILDASM Protection – ILDASM (Microsoft IL Dissassembler) is a free tool to disassembly any .Net assembly into MSIL (Microsoft Intermediate Language). Crypto Obfuscator can modify the assembly in such a way that ILDASM refuses to disassemble the assembly.
Metadata Reduction – Crypto Obfuscator can remove unnecessary or redundant information such as parameter names, property/event placeholders, etc from your .Net assembly . During symbol-renaming, Crypto Obfuscator will often assign extremely short (often single-character names) to your classes, fields, methods, etc. All these features can reduce the size of your .Net assembly considerably.