Wednesday, February 25, 2009

How to programaticaly detect .NET framework installed

There are two ways either by reading the registry or by browsing the file system. Both approaches have their benefits.
Reading the registry:
C++ example:
http://astebner.sts.winisp.net/Tools/detectFX.cpp.txt
C# example:
http://www.codeproject.com/KB/dotnet/frameworkversiondetection.aspx

Browsing the file system folder %systemroot%\Microsoft.NET\Framework:
http://msdn.microsoft.com/en-us/kb/kb00318785.aspx

Tuesday, February 24, 2009

Browsing trough files programaticaly

To browse trough the filesystem .net provides in System.IO namespace two very useful functions:  Directory.GetFiles  and Directory.GetDirectories. What those functions do is quite obvious. Simple example below.

Public Function SearchForFile(ByVal targetDirectory As String, ByVal fileToFind As String, ByVal recursive As Boolean) As String
    Dim fileName As String = String.Empty

    'ProcessFolder(targetDirectory)
    If fileToFind IsNot Nothing Then
      Dim fileEntries As String() = Directory.GetFiles(targetDirectory)
      ' Process the list of files found in the directory.

      For Each fileName In fileEntries
        If fileName.ToLower.Contains(fileToFind) Then
          Return fileName
        End If
      Next fileName

      If recursive Then
        Dim subdirectoryEntries As String() = Directory.GetDirectories(targetDirectory)
        ' Recurse into subdirectories of this directory.
        Dim subdirectory As String
        For Each subdirectory In subdirectoryEntries
          SearchForFile(subdirectory, fileToFind, recursive)
        Next subdirectory
      End If
    End If

    Return fileName

  End Function

Friday, February 20, 2009

How to set backgroud color of MDI

Since the property is not available at design time, all you need is a simple loop through controls (probably in load event) to set the background color of mdi window.

foreach (Control ctrl in Controls)
{
  if (!(ctrl is MdiClient)) continue;
  string colorName = ConfigurationManager.AppSettings["Dialog.BackColor"];
  if (colorName == null) continue;
  Color color = Color.FromName(colorName);
  //checks if color is transparent, mdiclient.backcolor doesn't support transparent colors
  if (color.A != 0)
       ctrl.BackColor = Color.FromName(colorName);
}

Monday, February 16, 2009

How to make an simple SMTP client

There is nothing to it. MSDN example does it all. All you need is to call System.Net library. Here is a simple implementation:

Imports System
Imports System.Net
Imports System.Net.Mail
Imports System.Net.Mime
Imports System.Threading
Imports System.ComponentModel

Module SimpleAsynchronousExample

  Dim mailSent As Boolean = False

  Private Sub SendCompletedCallback(ByVal sender As Object, ByVal e As AsyncCompletedEventArgs)

    'Get the unique identifier for this asynchronous operation.
    Dim token As String = CType(e.UserState, String)

    If (e.Cancelled) Then
      Console.WriteLine("[{0}] Send canceled.", token)
      If (e.Error IsNot Nothing) Then
        Console.WriteLine("[{0}] {1}", token, e.Error.ToString())
      Else
        Console.WriteLine("Message sent.")
      End If
      mailSent = True
    End If
  End Sub
  

  Sub Main(ByVal args As String())
    'Command line argument must the the SMTP host.
    Dim client As SmtpClient = New SmtpClient("hostname")
    '' Specify the e-mail sender.
    '' Create a mailing address that includes a UTF8 character
    '' in the display name.
    Dim from As MailAddress = New MailAddress("someone@test.com", "Some" + " One", System.Text.Encoding.UTF8)
    ' Set destinations for the e-mail message.
    Dim toAddress As MailAddress = New MailAddress("someone@test.com")
    '' Specify the message content.
    Dim message As MailMessage = New MailMessage(from, toAddress)
    message.Body = "This is a test e-mail message sent by an application. "
    ''Include some non-ASCII characters in body and subject.
    message.Body += Environment.NewLine + "This is a mail"
    message.BodyEncoding = System.Text.Encoding.UTF8
    message.Subject = "test message 1" + "test message"
    message.SubjectEncoding = System.Text.Encoding.UTF8
    ' Set the method that is called back when the send operation ends.
    AddHandler client.SendCompleted, AddressOf SendCompletedCallback
    ' The userState can be any object that allows your callback 
    ' method to identify this send operation.
    'For this example, the userToken is a string constant.
    Dim userState As String = "test message1"
    client.SendAsync(message, "this is me")
    Console.WriteLine("Sending message... press c to cancel mail. Press any other key to exit.")
    Dim answer As String = Console.ReadLine()
    '' If the user canceled the send, and mail hasn't been sent yet,
    '' then cancel the pending operation.
    If (answer.StartsWith("c") AndAlso mailSent <> False) Then
      client.SendAsyncCancel()
    End If
    ''Clean up.
    message.Dispose()
    Console.WriteLine("Goodbye.")
  End Sub

End Module

In order for example to work hostname of a SMTP server must be entered. Also make sure to have relay rules set. If you want no rule to apply set:

Friday, February 13, 2009

Pagging as concept part2

In addition to my previous post I would like to add that select presented in my previous post was just to demonstrate the concept. In reality select would look something like (in Oracle):

SELECT *
  FROM (SELECT ROWNUM row_num, column1, column2
          FROM (SELECT   column1, column2
                    FROM table
               )
         WHERE ROWNUM <= :page_num * :rec_count)
 WHERE row_num > (:page_num - 1) * :rec_count
Rec_count tells us how many records we want on a page, an page_num is the number of page we want.
I like this version more that maybe more used version:

SELECT *
  FROM (SELECT ROWNUM, table_name.*
          FROM (SELECT *
                  FROM table) table_name
         WHERE ROWNUM <= 200)
 WHERE ROWNUM <= 101

Whole point of doing sub select is to limit the number of results with inner select and then extract the rows required with outer select.

Simple implementation of SQL for paging modification would look something like:


 Public Function GetSQL(ByVal sqlin As String, ByVal sort As String, ByVal table As String, ByVal page As Integer, ByVal rec_count As Integer) As String
    Dim sql2 As String = " SELECT * FROM  (SELECT ROWNUM as ROW_NUM, " & table & ".* FROM "
    sql2 = sql2 & " ( " & sqlin & " " & sort & " )  " & table
    sql2 = sql2 & "  WHERE ROWNUM <= " & page & " * " & rec_count & ")  WHERE  ROW_NUM > (" & page & " - 1) *" & rec_count
    Return sql2
  End Function

Monday, February 9, 2009

Paging as a concept

Paging is yet another mysterious word used in by software developers. In principle it means that instead of downloading all the data returned by a query at once from database, we download subset (page)(first 100 rows) and when user browse through records, we fetch another page, and continue to do so until we have downloaded all the data. When applying this concept we presume that user will narrow its search when he cannot find what he was looking for in first n pages. If done correctly paging can have a significant impact on application performance.

Here is how we do it on all the databases that support rownum:  


SELECT * FROM  
(   SELECT rownum as row_num,
    column1,
    column2,
    column3,
    FROM 
    datatable
)
WHERE ROWNUM <= 201 and  ROW_NUM >= 300

Downside of paging is that it does not guaranty the coherence of data. If data in database is modified during the paging, duplicates or missing data my appear.

Wednesday, February 4, 2009

How to easily produce CSV files

It can be easily done either from dataset or datareader.

If dataset (datatable) is the source then:


Public Shared Sub ProduceCSV(ByVal dt As DataTable, ByVal file As System.IO.StreamWriter, ByVal WriteHeader As Boolean)
    Dim i As Int32
    Dim j As Int32
    Dim myCIintl As System.Globalization.CultureInfo
    myCIintl = System.Globalization.CultureInfo.CurrentCulture
    If (WriteHeader) Then
      Dim arr(dt.Columns.Count - 1) As String
      For i = 0 To dt.Columns.Count - 1
        arr(i) = dt.Columns(i).ColumnName
        arr(i) = GetWriteableValue(arr(i))
      Next
      file.WriteLine(String.Join(myCIintl.TextInfo.ListSeparator, arr))
    End If

    For j = 0 To dt.Rows.Count - 1
      Dim dataArr(dt.Columns.Count - 1) As String
      For i = 0 To dt.Columns.Count - 1
        Dim o As Object = dt.Rows(j)(i)
        dataArr(i) = GetWriteableValue(o)
      Next
      file.WriteLine(String.Join(myCIintl.TextInfo.ListSeparator, dataArr))
    Next
  End Sub

Making csv files from reader:


Public Shared Sub ProduceCSV(ByVal reader As DbDataReader, ByVal file As System.IO.StreamWriter, ByVal WriteHeader As Boolean)
    Dim i As Int32
    Dim myCIintl As System.Globalization.CultureInfo

    While reader.Read
      myCIintl = System.Globalization.CultureInfo.CurrentCulture
      If (WriteHeader) Then
        Dim arr(reader.FieldCount) As String
        For i = 0 To reader.FieldCount - 1
          arr(i) = reader.GetName(i)
          arr(i) = GetWriteableValue(arr(i))
        Next
        file.WriteLine(String.Join(myCIintl.TextInfo.ListSeparator, arr))
        WriteHeader = False ''header zapisemo samo enkrat
      End If

      Dim dataArr(reader.FieldCount - 1) As String
      For i = 0 To reader.FieldCount - 1
        Dim val As String
        'If reader.GetName(i).ToLower.Contains("stid") Then
        '  val = String.Format("""STID:{0}""", reader.Item(i))
        'Else
        val = GetWriteableValue(reader.Item(i))
        'End If

        dataArr(i) = val
      Next
      file.WriteLine(String.Join(myCIintl.TextInfo.ListSeparator, dataArr))
    End While
  End Sub

Since csv in my case contain millions of records I use reader as a source to limit memory usage and boost performance.

How to make binding to objects (classes) work

Problem: From my service I receive a class collection and when showing data in datagridview, there is no sorting posible, bindingsource functions like addnew do not work etc. After I have spended quite some time online to find an apropriate solution, i finally managed to produce staisfactory solution: Solution: first make a standard class that contains data.


Public  Class ListOfUnits
  Private  _ID As Integer
Public Property ID() As Integer
    Get
       Return _ID
    End Get
  Set(ByVal value As  Integer)
      _ID = value
   End Set
End Property
Private _UNIT As String
Public  Property UNIT() As String
  Get
      Return _UNIT
  End Get
  Set(ByVal value As String)
      _UNIT= value
  End Set
End Property
end  class

then make another class, that inherits from bindinglist(of T), where T is your class name


Public Class SortableListOfUnits
  Inherits BindingList(Of ListOfUnits)

  Private mIsSorted As Boolean

  Private m_SortDirection As ListSortDirection
  Private m_SortProperty As PropertyDescriptor
  Protected Overrides ReadOnly Property SortPropertyCore() As System.ComponentModel.PropertyDescriptor
    Get
      Return m_SortProperty
    End Get
  End Property
  Protected Overrides ReadOnly Property SortDirectionCore() As System.ComponentModel.ListSortDirection
    Get
      Return m_SortDirection
    End Get
  End Property
  Protected Overrides ReadOnly Property SupportsSortingCore() As Boolean
    Get
      Return True
    End Get
  End Property

  Protected Overrides Sub ApplySortCore(ByVal prop As System.ComponentModel.PropertyDescriptor, ByVal direction As System.ComponentModel.ListSortDirection)
    Dim items As System.Collections.Generic.List(Of ListOfUnits) = DirectCast(Me.Items, List(Of ListOfUnits))
    If Not IsNothing(items) Then
      m_SortDirection = direction
      m_SortProperty = prop
      items.Sort(New PropertyComparer(Of ListOfUnits)(prop.Name, direction))
      mIsSorted = True
    Else
      mIsSorted = False
    End If
    Me.OnListChanged(New ListChangedEventArgs(ListChangedType.Reset, -1))
  End Sub
  Protected Overrides ReadOnly Property IsSortedCore() As Boolean
    Get
      Return mIsSorted
    End Get
  End Property
  Protected Overrides Sub RemoveSortCore()
    mIsSorted = False
  End Sub
End Class

3) all you need now is a property comparer or in simple words a class that will implement a IComparer(Of T) interface if you want to make your own comparing logic. I have found a excelent implementation of icomparer online, that is generic, since i do not want to write comparer logic for every class.


Imports System.Reflection

Public Class PropertyComparer(Of T)
  Implements IComparer(Of T)

  Private FPropertyName As String = ""
  Private FDirection As SortDirection

  Public Sub New(ByVal propertyName As String)
    FPropertyName = propertyName
    FDirection = SortDirection.Ascending
  End Sub
  Public Sub New(ByVal propertyName As String, ByVal Direction As SortDirection)
    FPropertyName = propertyName
    FDirection = Direction
  End Sub
  ' Try to sort based on type using CompareTo method
  ' Multiple by FDirection to alternate sort direction
  Public Function Compare(ByVal x As T, ByVal y As T) _
     As Integer Implements System.Collections.Generic. _
        IComparer(Of T).Compare
    Dim propertyX As PropertyInfo = x.GetType().GetProperty(FPropertyName)
    Dim propertyY As PropertyInfo = y.GetType().GetProperty(FPropertyName)
    Dim px As Object = propertyX.GetValue(x, Nothing)
    Dim py As Object = propertyY.GetValue(y, Nothing)
    If (TypeOf px Is Integer) Then
      Return Compare(Of Integer)(CType(px, Integer), CType(py, Integer)) * FDirection
    End If
    If (TypeOf px Is Decimal) Then
      Return Compare(Of Decimal)(CType(px, Decimal), CType(py, Decimal)) * FDirection
    End If
    If (TypeOf px Is DateTime) Then
      Return Compare(Of DateTime)(CType(px, DateTime), CType(py, DateTime)) * FDirection
    End If
    If (TypeOf px Is Double) Then
      Return Compare(Of Double)(CType(px, Double), CType(py, Double)) * FDirection
    End If
    If (TypeOf px Is String) Then
      Return Compare(Of String)(CType(px, String), CType(py, String)) * FDirection
    End If
    If (TypeOf px Is Decimal) Then
      Return Compare(Of Decimal)(CType(px, Decimal), CType(py, Decimal)) * FDirection
    End If
    Dim methodX As MethodInfo = propertyX.GetType().GetMethod("CompareTo")
    If (methodX Is Nothing = False) Then
      Return CType(methodX.Invoke(px, New Object() {py}), _
         Integer) * FDirection
    Else
      Return 0
    End If
  End Function
  Private Function Compare(Of K As IComparable)(ByVal x As K, _
     ByVal y As K) As Integer
    Return x.CompareTo(y)
  End Function


  Public Enum SortDirection
    Descending = -1
    Ascending = 1
  End Enum

End Class