27.12.09

Visual inheritance in WPF

My final year .NET project was a medium-weight WPF application which had some 8 windows in all. Creating the windows and customizing the interface in XAML was a breeze with Visual Studio 2008 and Expression Blend 2. Even coding up the window logic was not that tough, but halfway into the logic part, I realized that all my windows had some properties and methods in common. So the code could be shortened a great deal using inheritance.

Basically, the approach is simple. Create a class in a separate code file (say Blindow in Blindow.cs) which inherits from System.Windows.Window, add all the properties and method implementations and virtual methods you need to it, and make all your windows inherit from Blindow. So, our Blindow looks like this:


  1. namespace BlindApp.Windows
  2. {
  3. public class Blindow : Window
  4. {
  5. // all your properties and methods here
  6. }
  7. }


So, the class declarations for all the windows in the application now change from

public partial class Window1 : Window
to

public partial class Window1 : Blindow

All is fine and well, the code should compile correctly, but shockingly, it doesn't and throws up an error. Reason: Forgot the XAML. If you know WPF well, you must realize that the class declaration for Window1 in the codebehind is only partial. The remaining partial declaration lies in the XAML. So, this means one has to come up with a way to let XAML know that Window1 inherits from Blindow now.
The source of the error now lies here

<Window x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


So what we need to do to rectify the error is first add an XML namespace (with any name you like) for the CLR namespace. The CLR namespace for Window1 is BlindApp.Windows, so add a line as follows

<Window x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:blinder="clr-namespace:BlindApp.Windows">


You don't need to type out the clr-namespace: statement - Visual Studio 2008 provides IntelliSense for that. But, we are not done yet, an error will again pop up because we need to replace the first line itself. Now that the XML namespace has been created, this is how it's done:

<blinder:Blindow x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:blinder="clr-namespace:BlindApp.Windows">


Just like you could set Resources and Triggers with Window.Resources and Window.Triggers, you can do the same now with <blinder:blindow.resources> and <blinder:blindow.triggers>

20.12.09

MD5 and TripleDES encryption in .NET

The .NET Framework provides classes for MD5 hashing and TripleDES encryption, both of which, when used together with a good enough key, form a good cryptographic system for your application. There are a lot of scenarios one can think of where encryption can be put to good use in both Desktop and Web applications. The following code snippet provides functions for encryption and decryption using MD5 and TripleDES.

What you need to include in the usings list is System.Security.Cryptography and System.Text and you are good to go. Making the functions static is just one of the best practices.








  1. public class Utils
  2. {
  3. public static string Encrypt(string toEncrypt, string key, bool useHashing)
  4. {
  5. // Convert both strings to byte arrays - you can use encoding other than UTF8
  6. byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
  7. byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
  8. if (useHashing)
  9. {
  10. // Hash the key
  11. MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
  12. keyArray = hashmd5.ComputeHash(keyArray);
  13. hashmd5.Clear();
  14. }
  15. TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider
  16. {
  17. Key = keyArray,
  18. // The following line is controversial - follow the link below the snippet
  19. Mode = CipherMode.ECB,
  20. Padding = PaddingMode.PKCS7
  21. };
  22. ICryptoTransform cTransform = tdes.CreateEncryptor();
  23. // Transform and store in resultArray
  24. byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
  25. tdes.Clear();
  26. return Convert.ToBase64String(resultArray, 0, resultArray.Length);
  27. }
  28. public static string Decrypt(string toDecrypt, string key, bool useHashing)
  29. {
  30. byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
  31. byte[] toDecryptArray = Convert.FromBase64String(toDecrypt);

  32. if (useHashing)
  33. {
  34. MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
  35. keyArray = hashmd5.ComputeHash(keyArray);
  36. hashmd5.Clear();
  37. }
  38. TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider
  39. {
  40. Key = keyArray,
  41. Mode = CipherMode.ECB,
  42. Padding = PaddingMode.PKCS7
  43. };

  44. ICryptoTransform cTransform = tdes.CreateDecryptor();
  45. byte[] resultArray = cTransform.TransformFinalBlock(toDecryptArray, 0, toDecryptArray.Length);
  46. tdes.Clear();
  47. return UTF8Encoding.UTF8.GetString(resultArray);
  48. }
  49. }



FYI, here is the controversy.
As you can see, both functions are quite similar except for precisely 2 lines. The Clear() function on both occasions are required because MD5CryptoServiceProvider and TripleDESCryptoServiceProvider classes are "managed wrappers around unmanaged resources". Putting the Encrypt and Decrypt functions to use in your application would look like this:

  1. string encrypted = Utils.Encrypt("Password", "Key", true);
  2. string original = Utils.Decrypt(encrypted, "Key", true);


Just make sure that you use the same key in both the lines, wherever the lines may be (they may be in two different applications referencing a common dll containing these functions) and the same hashing parameter as well. Happy encryption!

23.11.09

Using FileUpload control in ASP.NET 2.0

The FileUpload control in ASP.NET 2.0 allows users to upload files onto the server. It is a familiar control on social networking sites and signup pages where users are required to upload images as profile photos or album pics. So, how exactly does one code up the process of uploading to the server? Read on.

The FileUpload control in ASP.NET 2.0 uploads the specified file at the specified path on the user's machine to a specified path on the web server. There are two approaches to this:
  1. SaveAs() method

  2. The simpler, zero-effort approach is to use the SaveAs() method of the FileUpload control itself. What you need to do is write this single line of code in the event handler of the Upload button on your WebForm.


    fileupload1.SaveAs(@"Uploads\" + fileupload1.FileName);

    The above code uploads the file to the Uploads folder on the web server.

  3. HttpPostedFile object

  4. The PostedFile property of the FileUpload control returns an HttpPostedFile object which can be used to obtain additional information about the file uploaded such as length in bytes (ContentLength property) and MIME type (ContentType property). It also returns a Stream object through its InputStream property which is exactly the property useful in uploading. Take a look at the code.


    1. HttpPostedFile uploadedFile = fileupload1.PostedFile;

    2. // Read all data from the file into a byte array
    3. int len = uploadedFile.ContentLength;
    4. byte[] data = new byte[len];
    5. uploadedFile.InputStream.Read(data, 0, len);

    6. // Create a new file and stream the bytes to it
    7. FileStream file = new FileStream(Server.MapPath(@"Uploads\" +
    8. fileupload1.FileName, FileMode.Create);
    9. file.Write(data, 0 , len);
    10. file.Close();



    The latter method is the one I invented because I had not known the SaveAs() method of the FileUpload control when I first used it. As for you, the choice is entirely in your hands.

22.10.09

(Ab)using Registry classes in .NET

The .NET Framework provides wonderful classes in the Microsoft.Win32 namespace to read and write values to any key or set of keys in the Windows Registry. These classes are not only wonderful but also dangerous because they have the potential to cause nasty and possibly irreversible changes to Windows. The following piece of code is DANGEROUS for your PC. So, do not run this code in your primary Windows Administrator account. Instead, create a dummy Windows Administrator account and run this code there. It's fun! And in fact there's so much else to do with the Registry!
Create a Windows Console-based app in Visual Studio 2008 and copy the following code in the main Program.cs.



  1. using System;
  2. using Microsoft.Win32;

  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. Console.WriteLine("WELCOME TO NASTY APPLICATION");
  8. Console.WriteLine("\nThis application will do the following:");
  9. Console.WriteLine("1. Empty Start Menu");
  10. Console.WriteLine("2. Hide all drives");
  11. Console.WriteLine("3. Clean Windows Explorer");
  12. Console.WriteLine("4. Enforce restrictions in Internet Explorer");
  13. Console.WriteLine("5. Disable Task Manager");
  14. Console.WriteLine("\nPress any key to start");
  15. Console.ReadKey();

  16. using (RegistryKey r1 = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\
    Windows\CurrentVersion\Policies\Explorer"
    ))
  17. {
  18. Console.WriteLine("Emptying Start Menu...");
  19. r1.SetValue("NoSMMyDocs", 1);
  20. r1.SetValue("NoSMMyPictures", 1);
  21. r1.SetValue("NoStartMenuMyMusic", 1);
  22. r1.SetValue("NoStartMenuNetworkPlaces", 1);
  23. r1.SetValue("NoStartMenuPinnedList", 1);
  24. r1.SetValue("NoStartMenuMFUprogramsList", 1);
  25. r1.SetValue("NoFind", 1);
  26. r1.SetValue("NoControlPanel", 1);
  27. r1.SetValue("NoStartMenuMorePrograms", 1);
  28. r1.SetValue("NoClose", 1);
  29. r1.SetValue("StartMenuLogOff", 1);
  30. r1.SetValue("NoRun", 1);
  31. Console.WriteLine("Done");

  32. Console.WriteLine("Hiding all drives...");
  33. r1.SetValue("NoViewOnDrive", 255);
  34. r1.SetValue("NoDrives", 255);
  35. Console.WriteLine("Done");

  36. Console.WriteLine("Cleaning Windows Explorer...");
  37. r1.SetValue("NoTrayItemsDisplay", 1);
  38. r1.SetValue("NoDesktop", 1);
  39. r1.SetValue("NoSetTaskbar", 1);
  40. r1.SetValue("HideClock", 1);
  41. Console.WriteLine("Done");
  42. }
  43. Console.WriteLine("Disabling Task Manager...");
  44. using (RegistryKey r2 = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\
    Windows\CurrentVersion\Policies\System"
    ))
  45. {
  46. r2.SetValue("DisableTaskMgr", 1);
  47. }
  48. Console.WriteLine("Done");
  49. Console.WriteLine("Enforcing restrictions on IE...");
  50. using (RegistryKey ie = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Policies\Microsoft\
    Internet Explorer"
    ))
  51. {
  52. ie.CreateSubKey("Control Panel").SetValue("DisableDeleteBrowsingHistory", 1);
  53. ie.CreateSubKey("Control Panel").SetValue("FormSuggest Passwords", 1);
  54. ie.CreateSubKey("Control Panel").SetValue("FormSuggest", 1);
  55. ie.CreateSubKey("Control Panel").SetValue("History", 1);
  56. ie.CreateSubKey("LinksBar").SetValue("Enabled", 0);
  57. ie.CreateSubKey("Privacy").SetValue("EnableInPrivateBrowsing", 0);
  58. ie.CreateSubKey("Privacy").SetValue("CleanHistory", 0);
  59. ie.CreateSubKey("Restrictions").SetValue("NoBrowserOptions", 1);
  60. ie.CreateSubKey("Restrictions").SetValue("NoFavorites", 1);
  61. ie.CreateSubKey("Main").SetValue("Use FormSuggest", "no");
  62. }
  63. Console.WriteLine("Done!");

  64. Console.WriteLine("THANK YOU FOR YOUR PATIENCE");

  65. Console.WriteLine("A restart is necessary for the changes to take effect");
  66. Console.WriteLine("\nPress any key to restart");

  67. Console.ReadKey();
  68. Process.Start("shutdown.exe", "-r -t 00");
  69. }
  70. }


Some explanation: The program can be divided into 3 parts, one for each RegistryKey object r1, r2 and r3.

r1 is the RegistryKey object which allows you to manipulate Windows Explorer any which way you like. r1 provides access to a Registry key whose values affect Start Menu, Taskbar, Control Panel and My Computer. For example, setting NoClose value to 1 disables the Turn Off button on the Start Menu, NoFind disables the Search button and NoRun disables the Run button. The NoDrives and NoViewOnDrive keys deserve a bit more explanation. NoViewOnDrive makes drives disappear from My Computer, but the drives will be accessible elsewhere. NoDrives blocks access to the drives completely. The value passed to these keys determines the number and letters of drives affecte. Understand from this:
00000001 => 1 means only A: drive is affected.
00000011 => 3 means both A: and B: drives are affected.
00010100 => 20 means C: and E: drives are affected.
11111111 => 255 means all drives are affected.

r2 is a relatively less significant RegistryKey object which prevents the Task Manager from appearing when Ctrl-Alt-Del is pressed.

r3 is the RegistryKey object which allows you to customize Internet Explorer as per your requirements. The subkeys and their values set in the code are fairly self-explanatory. Some of them like InPrivate Browsing work only for IE 8.
After executing this code, if you want to review the changes in the Registry after running the code, comment out the NoRun line so that you can open the Registry and undo the changes - However, as I have unfortunately discovered, not all changes can be undone, that's the reason why you are ADVISED to run this code on a dummy empty Administrator account!

3.10.09

Get Web browser history in C#

In my final year .NET project, I had to code up a module to obtain the visited URL history of at least one web browser and delete some or all of the URLs from the history. A seemingly impossible job at first, I eventually managed to write (or rather get) some neat C# code for the purpose. Here is the outcome of some very good research.

  1. Internet Explorer

  2. This was the easiest browser whose URL history can be obtained and deleted at will. My research started off with a Registry discovery - URLs typed in the address box of IE are captured in the Registry key HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypedURLs. But that was way short of the purpose. Then, I came across the COM interface IUrlHistory on MSDN. But it was COM and writing a C# class wrapper or something was something I was not proficient in at all. So, I reluctantly began searching for ready code. And voila!

    An article on CodeProject was all it took to serve my purpose. It provides a UrlHistoryLibrary.dll file which provides type-safe classes to access and manipulate IE's browsing history. Details on how to use the classes are given in the article itself. However, this is how I used it.




    1. public class InternetExplorer
    2. {
    3. // List of URL objects
    4. public List<URL> URLs { get; set; }
    5. public IEnumerable<URL> GetHistory()
    6. {
    7. // Initiate main object
    8. UrlHistoryWrapperClass urlhistory = new UrlHistoryWrapperClass();

    9. // Enumerate URLs in History
    10. UrlHistoryWrapperClass.STATURLEnumerator enumerator =
    11. urlhistory.GetEnumerator();

    12. // Iterate through the enumeration
    13. while (enumerator.MoveNext())
    14. {
    15. // Obtain URL and Title
    16. string url = enumerator.Current.URL.Replace('\'', ' ');
    17. // In the title, eliminate single quotes to avoid confusion
    18. string title = string.IsNullOrEmpty(enumerator.Current.Title)
    19. ? enumerator.Current.Title.Replace('\'', ' ') : "";

    20. // Create new entry
    21. URL U = new URL(url, title, "Internet Explorer");

    22. // Add entry to list
    23. URLs.Add(U);
    24. }

    25. // Optional
    26. enumerator.Reset();

    27. // Clear URL History
    28. urlhistory.ClearHistory();

    29. return URLs;
    30. }
    31. }




    Notes:
    The code is fairly self-explanatory except for a few clarifications. The URL class used above is a simple class which has three string fields - URL, Title and BrowserName - and URLs is a List<URL>. Those little string.Replace functions are to eliminate single quotes in the URLs so that there are no problems inserting them into an SQL database.

  3. Mozilla Firefox

  4. The same thing for Mozilla Firefox was way tougher. First of all, it was difficult to locate where Firefox stores the browsing history. The answer came in the form of an SQLite database which is stored in the Application Data of the Windows user. So, I had a SQLite database at hand. First, I tried FileStream to the .sqlite file. I had opened the file in Notepad++ and seen that URLs were interspersed with quirky characters, so using the FileStream, I could manage to obtain the URLs, but obtaining the Titles was impossible. Moreover, I was never sure that a URL I come across was ever visited or was it a bookmark or what. So, again some code-googling later, I came across the ADO.NET Data Provider for SQLite.The download page is here.

    What is wonderful about this Provider is that not only it provided a .NET-native namespace (System.Data.SQLite), but also it provides full Visual Studio 2008 design-time support. So, without wasting more time, let me provide you the code.




    1. public class Firefox
    2. {
    3. public List<URL> URLs { get; set; }
    4. public IEnumerable<URL> GetHistory()
    5. {
    6. // Get Current Users App Data
    7. string documentsFolder = Environment.GetFolderPath
    8. (Environment.SpecialFolder.ApplicationData);

    9. // Move to Firefox Data
    10. documentsFolder += "\\Mozilla\\Firefox\\Profiles\\";

    11. // Check if directory exists
    12. if (Directory.Exists(documentsFolder))
    13. {
    14. // Loop each Firefox Profile
    15. foreach (string folder in Directory.GetDirectories
    16. (documentsFolder))
    17. {
    18. // Fetch Profile History
    19. return ExtractUserHistory(folder);
    20. }
    21. }
    22. return null;
    23. }

    24. IEnumerable<URL> ExtractUserHistory(string folder)
    25. {
    26. // Get User history info
    27. DataTable historyDT = ExtractFromTable("moz_places", folder);

    28. // Get visit Time/Data info
    29. DataTable visitsDT = ExtractFromTable("moz_historyvisits",
    30. folder);

    31. // Loop each history entry
    32. foreach (DataRow row in historyDT.Rows)
    33. {
    34. // Select entry Date from visits
    35. var entryDate = (from dates in visitsDT.AsEnumerable()
    36. where dates["place_id"].ToString() == row["id"].ToString()
    37. select dates).LastOrDefault();
    38. // If history entry has date
    39. if (entryDate != null)
    40. {
    41. // Obtain URL and Title strings
    42. string url = row["Url"].ToString();
    43. string title = row["title"].ToString();

    44. // Create new Entry
    45. URL u = new URL(url.Replace('\'', ' '),
    46. title.Replace('\'', ' '),
    47. "Mozilla Firefox");

    48. // Add entry to list
    49. URLs.Add(u);
    50. }
    51. }
    52. // Clear URL History
    53. DeleteFromTable("moz_places", folder);
    54. DeleteFromTable("moz_historyvisits", folder);

    55. return URLs;
    56. }
    57. void DeleteFromTable(string table, string folder)
    58. {
    59. SQLiteConnection sql_con;
    60. SQLiteCommand sql_cmd;

    61. // FireFox database file
    62. string dbPath = folder + "\\places.sqlite";

    63. // If file exists
    64. if (File.Exists(dbPath))
    65. {
    66. // Data connection
    67. sql_con = new SQLiteConnection("Data Source=" + dbPath +
    68. ";Version=3;New=False;Compress=True;");

    69. // Open the Conn
    70. sql_con.Open();

    71. // Delete Query
    72. string CommandText = "delete from " + table;

    73. // Create command
    74. sql_cmd = new SQLiteCommand(CommandText, sql_con);

    75. sql_cmd.ExecuteNonQuery();

    76. // Clean up
    77. sql_con.Close();
    78. }
    79. }

    80. DataTable ExtractFromTable(string table, string folder)
    81. {
    82. SQLiteConnection sql_con;
    83. SQLiteCommand sql_cmd;
    84. SQLiteDataAdapter DB;
    85. DataTable DT = new DataTable();

    86. // FireFox database file
    87. string dbPath = folder + "\\places.sqlite";

    88. // If file exists
    89. if (File.Exists(dbPath))
    90. {
    91. // Data connection
    92. sql_con = new SQLiteConnection("Data Source=" + dbPath +
    93. ";Version=3;New=False;Compress=True;");

    94. // Open the Connection
    95. sql_con.Open();
    96. sql_cmd = sql_con.CreateCommand();

    97. // Select Query
    98. string CommandText = "select * from " + table;

    99. // Populate Data Table
    100. DB = new SQLiteDataAdapter(CommandText, sql_con);
    101. DB.Fill(DT);

    102. // Clean up
    103. sql_con.Close();
    104. }
    105. return DT;
    106. }
    107. }



    So, while some of this code was taken from the mozillazine forums, some was written on my own and the combination worked perfectly well for me in my final year project. Hope it works for you, too!

21.9.09

Best free addins for Visual Studio 2008

Visual Studio 2008I have subscribed to the Microsoft Download Notifications weekly newsletter and it was only yesterday that I clicked something which I had never clicked in any newsletter before - Visual Studio Gallery. It is a list of addins - both free and free trials - for Visual Studio 2008 and if you are a .NET developer, you should not miss this!

Here's a list of the best 5 free addins I came across on that site. Hope you like them. Anyways, here's the site. Visual Studio Addins Gallery.

  1. Copy as HTML
    Forget SyntaxHighlighter and all other online JavaScript tools you'd require to paste code in your blog without giving up all the indents and formatting. After installing this lightweight addin a "Copy as HTML" item is added to the context menu on code selection in VS 2008. The generated HTML can be played around with, so you can provide your own custom feel to the markup. The only issue is that it copies < as &lt; and > likewise. So copying XAML code is an issue.

  2. WPF NotifyIcon
    This is the WPF equivalent of the WinForms NotifyIcon. With this, you do not need to initialize a system tray icon for your WPF application in code but in XAML itself.

  3. WPF AboutBox
    This is the WPF equivalent of the WinForms AboutBox. Detailed instructions on how to use it are available on the site itself.

  4. MRU Cleaner
    This add-in allows you to manage the MRU (Most Recently Used) list of projects which can get irritatingly long and unwieldy in Visual Studio 2008. However, positive reviews of this add-in have not been forthcoming on the Add-In Gallery site, so here is an alternative download link.
    Download MRU Cleaner

  5. The CodeProject Add-In
    Perhaps the best add-in in this list, the CodeProject add-in searches MSDN, CodeProject as well as the Web (Live Search) for articles based on what you enter in the search box. It may sound not too useful, but if you use it properly and to maximum advantage, you won't be able to code without it. Download link is here.
    Download The CodeProject Add-In

13.9.09

.NET Reflector

Occasionally, a .NET developer may feel the need to look through the source code for .NET base class libraries to know exactly what goes on behind the scenes. Unfortunately, (as far as I know) Visual Studio 2008 does not permit that - it only provides an object browser that merely shows the class names and its properties and method signatures. Enter .NET Reflector.

.NET Reflector is a free disassembler and analyzer tool for all the classes in the .NET assemblies. It provides an accurate representation of the .NET base classes hierarchy and disassembles in multiple languages including

  • C#
  • VB
  • IL
  • Chrome(!)
  • Delphi
  • MC++
Besides showing Disassembly and Analysis in different panes, it has some pretty solid features like Search, Options dialog, MSDN Search and Live Search It also supports add-ins developed specifically for the Reflector which can be downloaded from CodePlex. Download links for the Reflector and add-ins are below.

Download Red Gate's .NET Reflector
Download .NET Reflector Add-ins at CodePlex

26.8.09

Classes for files and folders in C#

The .NET Framework provides a comprehensive set of base classes to explore the entire file system, finding out files and folders that are present and listing their properties (and a whole lot of them). These base classes expose methods that allow file and folder operations as well, such as moving, copying, deleting and renaming. Here we go through the available classes.

  1. FileInfo and DirectoryInfo

  2. These are non-static classes in the System.IO namespace that allow you to get almost any kind of information about files and folders and also allow operations like Deleting, Creating, Copying, Moving, etc. They are located in the System.IO namespace. Their constructors take a string that specifies the full path of the directory or file concerned.

    1. DirectoryInfo main = new DirectoryInfo(@"C:\hello");
    2. FileInfo main = new FileInfo(@"C:\hello.txt");



    If the file or directory does not actually exist, an exception is not thrown - just the Exists property is set to false. Once the instance is set, one can read as well as write properties like LastAccessTime, LastWriteTime, CreationTime and Attributes. The methods of DirectoryInfo class are more for the purpose of browsing through the file system while FileInfo instances are more often used to open streams to the file in question. This may be the reason why DirectoryInfo lacks the Length property of FileInfo which returns the size in bytes. One can write a tiny extension method for a DirectoryInfo instance:

    1. public static long GetSize(this DirectoryInfo dir)
    2. {
    3. long length = 0;
    4. foreach (FileInfo nextfile in dir.GetFiles())
    5. length += nextfile.Exists ? nextfile.Length : 0;
    6. foreach (DirectoryInfo nextdir in dir.GetDirectories())
    7. length += nextdir.Exists ? nextdir.GetSize() : 0;
    8. return length;
    9. }

    Although these classes can be used to move and copy files and folders, they are less preferable than the FileSystem class which we'll discuss later in this post.

  3. DriveInfo

  4. This class allows you to access any information about any drive in the machine. It is also located in the System.IO namespace. It provides a crucial single static method called GetDrives() which returns all the drives in the machine as an array of DriveInfo instances. Each of the DriveInfo instances can then be used to obtain drive information in properties like AvailableFreeSpace, TotalFreeSpace, DriveFormat, DriveType, Name, TotalSize and VolumeLabel. Perhaps the most important of these is the DriveType property which is an enum that provides for as many as 7 drive types viz. CDRom, Fixed, Removable, Network, NoRootDirectory, Ram and Unknown.
    Here's a sample method to get names of all removable drives:

    1. public static IEnumerable<string> GetRemovableDrives()
    2. {
    3. return from p in DriveInfo.GetDrives()
    4. where p.DriveType == DriveType.Removable & p.IsReady == true
    5. select p.Name;
    6. }

  5. FileSystem class

  6. This class allows you to move and copy files and folders. Though this can also be achieved with the DirectoryInfo and FileInfo classes as well, the difference is that FileSystem class hands over the transfer to the OS, so the OS provides the standard progress bar UI and the application can proceed normally. With the Info classes, the application is responsible for the transfer and so does not proceed to the next instruction until the transfer is complete, resulting in undesirable UI latency especially if the file or folder involved is large.

    1. FileSystem.MoveDirectory(@"C:\hello", @"D:\hello", UIOption.AllDialogs);
    2. FileSystem.CopyDirectory(@"C:\hello", @"D:\hello", UIOption.AllDialogs);
    3. FileSystem.MoveFile(@"C:\hello.txt", @"D:\hello.txt", UIOption.AllDialogs);
    4. FileSystem.CopyFile(@"C:\hello.txt", @"D:\hello.txt", UIOption.AllDialogs);

    It is located in a completely disparate Microsoft.VisualBasic.FileIO namespace.
    Other than just transferring files and folders, the FileSystem class provides in fact a wide range of static methods that emulate the behavior of other classes like FileStream, FileInfo and DirectoryInfo. A quick view and you'll know what I mean.

So, I suppose I covered all the .NET classes for Directories and Files. I hope it is useful to you!

15.7.09

Everything is a class!

It is amazing how often I need to remind my friends with programming doubts that C# is object-oriented - there is no line of code in C# without a reference to a class or an object. There is a class for almost everything in the .NET Framework and its interoperability features make it the platform of choice for Windows applications.

And C# is just the right language for .NET. Although people have tried to convince me that VB.NET is also completely object-oriented, it just does not seem to be a true programmer's language of choice. Never mind the syntax, the lack of braces and the presence of keywords like My.Computer (!) make it simply an uncomfortable language to work with especially for a programmer with C background.

Coming back to my friends, I had a friend calling me yesterday with a DataGridView problem. He said he had a form (say Form1) on which if the user clicked a button, the DataGridView should display all the relevant data. The guy had made the button-click event handler to invoke a method from another class (say Class1) which is fine as he meant to segregate the UI classes from the database classes. The problems are here
  • The method initialized and filled a DataGridView which was a property of Class1.
  • The method returned void.
  • The method was called in the button-click event handler from an instance of Class1.
His code would look like

class Form1
{
......
...
private void Button1_Click(object sender, RoutedEventArgs e)
{
Class1 obj = new Class1();
obj.FillMyGridView();
}
.....
}
// The following class in another file, in another namespace
class Class1
{
......
...
public DataGridView Grid{ get; set;}

public void FillMyGridView()
{
Grid = // initialize and fill Grid
}
}

Now whether you are laughing at the guy already or empathizing with him depends on which level programmer you are. I told him that a void-returning method just won't do. Although I fairly convinced him why, he was just reluctant to make a method that returned a DataGridView or a even a DataBindingSource to the form.
Nevertheless, he had a keenness to learn and that is what, I feel, any programmer should have. Never be ashamed of what you do not know - there is always more to know no matter how much you already know and there is always a guy who knows less than you do.

4.7.09

All is fair in love and var

The var keyword in C# 3.0 has been the subject of much scorn recently, which I feel is uncalled for. It is really a matter of personal preference - I use the var keyword in LINQ queries, and I think there's no other good way of storing the output of a LINQ query. Implicit typing is just an equally strong typing convention as explicit typing as the compiler determines the actual type, never so wrongly.

Anonymous types are, to me, a blessing of LINQ, and there's no better way to save variables of anonymous types than in a var. Using the var keyword in any context other than LINQ, however, would be undesirable, as readability can be compromised and the code would unnecessarily be cluttered.

28.6.09

My first CP paper

I went through the ruins in my table today and found and tore away many useless things - hall tickets, application forms, document copies, etc. They were all taking up precious little space and my mind felt lighter with all of them gone - they brought back memories and I am tired of memorizing!

One thing which caught my attention was the CP question paper of my First Semester in Engineering. CP was a particularly tough paper back then, it was compulsory for all branches of Engineering (one of the very grave follies of the University because of which even Mechanical and Civil Engineering students had to go through it) and the language was C - Turbo C to be precise.

The programs in the first question were about computing compound interest and Ackerman's <(yes, they had spelled it wrong) function - a good testing combo for a compulsory question (Many wished it were easier!). This was the first time I had seen the Ackermann's function and the question had mentioned it was popular with lecturers and students of Computer Science! I finished them with ease and moved on to the next question.
Expected score: 15 out of 20

The programs in the second question were about finding four-digit perfect squares which are concatenations of two-digit perfect squares (e.g. 1681) and a weird convergence-to-1 algorithm.
The algorithm goes like this
  • If the number is odd, multiply by 3 and add 1.
  • If the number is even, divide by 2.
  • Repeat until number is 1.
Both were pieces of cake which I ate in a jiffy and went to the next question.
Expected score: 16 out of 20

The programs in the third question were about neat tabular display of marks of 50 students and computing mean, variance and standard deviation (The formulas for each of them were given!). Again, good for me, but surprisingly, it was taking longer than expected because it was the first time I was writing full-fledged programs. My answer-sheet was getting dirtier with scribblings, cancellations, so I resorted to rough work.
Expected score: 14 out of 20

The programs in the fourth question were tricky - a program to compute and display tip speeds for a set of shank speeds against an input value of diameter (Whoa!) and a program to find minimax values in a 2-D array. It took a while for me to comprehend the first question though it turned out to be a simple program, but the second program caught me - I was not particularly good at functions at the time and this program had to do exactly that. So, I took an arduous, far less intuitive way out and the program turned out to be so large, I was assured it would not fetch me any marks!
Expected score: 10 out of 20

The programs in the fifth question were about structures - a point structure program and an employee structure program. The employee structure program was long as it required searching and sorting. Good, but time-consuming.
Expected score: 13 out of 20

So, I expected 68 out of a good first-time CP paper. I could be more intuitive with the programs, but for lack of time. Many others had struggled, because they expected "standard" programs and not out-of-the-box ones. The results came out later and many failed (CP is tough for many, even in IT and CS streams!), and I scored 45 - dismal and pathetic compared to my expectations. I applied for revaluation, but nothing came through it. I never got discouraged though - I had found programming interesting and fun, and I felt I had chosen the perfectly right career path. I have the copy of my answer-sheet with me till now, which I read through sometimes to brush up on programming basics!

25.6.09

.NET Framework - an addiction

I seriously do not know Java. No matter how much I try, I have never managed to code up a page in Java, let alone an entire application. On the other hand, my first application in .NET was so quick and easily done that I felt I am a .NET pro since ages!
The first languages I learned were HTML and ASP-VBScript, and I never managed to come out of the Web markup mode for quite some time.

I have Eclipse and JCreator installed at home - the Add or Remove Programs list terms them as 'rarely' used. The first programming language I learnt was C and believe me, C is beautiful. All the includes, conditions, loops, functions, structs, arrays, pointers got me hooked on to C big time and I thought C is the best language in the world. Then came C++, and OOP was revealed to me. For some time, I still preferred C, but eventually, for want of better programming experience, I embraced C++.

Java was introduced to me after a considerable period of time, and frankly, I never got round to it. Java was never meant for me and it always took me quite some time to code up a line. I always felt there must be something like Java, yet different from it. This is certainly not it.

And then came the big one - C#. It was just C all grown up, and I forgot all about Java. I must thank Visual Studio 2008 here for introducing me to all the beauties of C#, and believe me, Visual Studio 2008 is a great IDE. I could have used it to learn VB (mind you, VB 2008 is not IN ANY WAY like VB 6 of old), but I preferred C# due to my firm grounding in C and C++. The environment allowed me to learn C# well and fast, and applications were developed in no time. In fact, my final year project was a dazzling WPF application, which was supposed to be developed over a year, but being the quintessential engineering student, I started in the last 2 weeks and finished it just before the deadline. After all, the .NET Framework is just meant for RAD (Rapid Application Development).

Microsoft managed to wean away many Java developers like me towards the .NET Framework, not just because it gained significant mileage over a short period of time, but because it has some sound principles running behind it, original and otherwise. Platform Independence through Intermediate Language, Garbage Collection, Language Interoperability are just some of the principles guiding the .NET Framework and they go a long way in keeping developers loyal to .NET. However, the .NET Framework is so popular maybe only because of the Visual Studio, an excellent IDE which has evolved from its 2005 version to its 2008 version as the .NET Framework has evolved from its 2.0 version to 3.5. With new technologies like WPF, WCF, LINQ and WF (of which I have 'mastered' WPF as yet) in its latest 3.5 version, .NET is indeed attractive.
(.NET 4.0 and correspondingly, Visual Studio 2010 to be released later this year)

Java is still preferred by the 'pure' programmers - people who require complete control over each and every aspect of their application and leave nothing at the mercy of their IDE. That is precisely the reason why Java does not assist much in laying out a good UI for your application - Java programmers still grapple with the SetBounds function for different UI elements in their application. .NET, on the other hand, just says, Do not stress yourself out, lemme help you! .NET is as powerful as Java, but easier to learn and more addictive than Java.