A Collection of C# .Net Sample Programs

Environment: VS7, C# .NET

This article contains a collection of C# programs that I wrote when I wanted to learn C# and .NET. I call these types of programs “Exploratory Programming.” This is not a tutorial, just the journey of a programmer trying to learn a new language and system interface. They are all short applications that demonstrate some part of .NET and the forms interface that I couldn’t find in any book I had. All the programs are simple interactive examples. I don’t take advantage of classes and the really advanced parts of the language. I’ll save that for my next set of programs.

The following are the applications included:

  • FileWatch: real-time monitoring of file system changes
  • Environment: An application exploring the .NET Environment class
  • RegistryTest: A simple Registry browser
  • HttpTest: An example of using HttpWebRequest and HttpWebResponse
  • WebPageGet: A HTTP page retriever, using System.Net, that displays the text and lists all hosts referenced in the page
  • CSDNS: A simple example of DNS name and address resolution

I believe in auditory debugging when necessary, putting a sound in routines so you know they were entered but don’t have to sit in the debugger setting break points unless you have to. .NET doesn’t seem to have the equivalent of the WIN32 MessageBeep(nn) function. The following will enable it from C#:

using System.Runtime.InteropServices;    //reference the name
                                         //space for use

public class
Form1 : System.Windows.Forms.Form    //or whatever you call the
                                     //class of your application

{

[DllImport("user32.dll")]

public static
extern bool
MessageBeep(int
Sound);

The following sections describe the programs.


FileWatch

This program shows a very interesting .NET class, FileSystemWatcher. It allows you to monitor the file system for changes. A single file, a directory, even all files can be monitored. Basically, you create the class, set the NotifyFilter, the starting path, the file name Filter, and event handlers for the events you want to monitor, then enable events. The event types are: changed, created, deleted, and renamed. The types of changes include changes to size, attributes, security settings, last write, and last access time. The file name Filter allows you to specify all files “”, a particular file “myfile.doc” or use wild cards such as “*.txt”. StartingDirectory is obvious. The only other parameter is a Boolean IncludeSubdirectories, also obvious. There are three types of event handlers: FileSystemEventHandler, RenamedEventHandler, and ErrorEventHandler.

// TODO: Add any constructor code after InitializeComponent call

m_starting_path.Text = "C:\\";

watcher = new FileSystemWatcher(); //---------------------------------------------------------------- //This routine fills in the FileWatcher instance with parameters. //It checks the CheckBoxes to see what files to report on and what //routines to use to handle the events. Then it enables raising //events, allowing file change notification. private void StartButtonClick(object sender, System.EventArgs e) { if (watcher.EnableRaisingEvents == true) { MessageBeep(100); return }

m_file_list.Items.Clear(); watcher.Path = m_starting_path.Text; watcher.Filter = m_filter.Text; watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Attributes | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size; if (cb_changed.Checked == true) watcher.Changed += new FileSystemEventHandler(OnFileEvent); else watcher.Changed -= new FileSystemEventHandler(OnFileEvent); if (cb_created.Checked == true) watcher.Created += new FileSystemEventHandler(OnFileEvent); else watcher.Created -= new FileSystemEventHandler(OnFileEvent); if (cb_deleted.Checked == true) watcher.Deleted += new FileSystemEventHandler(OnFileEvent); else watcher.Deleted -= new FileSystemEventHandler(OnFileEvent); if (cb_renamed.Checked == true) watcher.Renamed += new RenamedEventHandler(OnRenameEvent); else watcher.Renamed -= new RenamedEventHandler(OnRenameEvent); if (cb_subdirectory.Checked == true) watcher.IncludeSubdirectories = true; else watcher.IncludeSubdirectories = false; watcher.EnableRaisingEvents = true; //trigger event logging } //---------------------------------------------------------------- public void OnFileEvent(object source, FileSystemEventArgs fsea) { DateTime dt = new DateTime(); dt = System.DateTime.UtcNow; m_file_list.Items.Add(dt.ToLocalTime() + " " + fsea.ChangeType.ToString() + " " + fsea.FullPath ); } //---------------------------------------------------------------- public void OnRenameEvent(Object source, RenamedEventArgs rea) { DateTime dt = new DateTime(); dt = System.DateTime.UtcNow; m_file_list.Items.Add(dt.ToLocalTime() + " " + rea.ChangeType.ToString() + rea.OldFullPath+ " to " + " " + rea.FullPath); } //----------------------------------------------------------------

Environment

The .NET Framework takes a much different approach to the Environment than Windows. There is a class called Environment, part of the System namespace. The documentation states:

Use this class to retrieve the following information:

  • Command line arguments.
  • Exit codes.
  • Environment variable settings.
  • Contents of the call stack.
  • Time since last system boot.
  • Version of the common language runtime.

Besides getting all or a particular environment variable(s), there are other objects available. Most objects are read only, and there is no method to set or add a variable. As far as I can tell, only the CurrentDirectory and ExitCode can be changed. There is no method to add or modify the environment variables. The most interesting thing I noticed when coding the example C# program was the way GetEnvironmentVariables() worked. The method returns an IDictionary object that represents a collection of key-and-value pairs. Another interesting method is GetFolderPath, which retrieves paths to various system folders.

The following is a C# example of how to retrieve all environment variables.

case 0:
IDictionary id;
String sString;

ArrayList values = new ArrayList();

  m_env_list.Items.Clear ();
  id = Environment.GetEnvironmentVariables();
  foreach (DictionaryEntry myEntry in id)
  {
    sString = myEntry.Key.ToString();
    sString += "=";
    sString += myEntry.Value.ToString();
    m_env_list.Items.Add(sString);
  }
  m_env_list.SetSelected(0, true);
  m_env_list_SelectedIndexChanged(this,null);
  break;

RegistryTest

This application was as much a .NET forms learning experience as it was looking at how the system Registry is accessed from C# and .NET. The RegistryKey Class is part of the Microsoft Win32 class. This version of the application lists only the SubKeys and their values. There are also methods for adding, deleting, and modifying a SubKey, as well as deleting a SubKey tree. I have not finished these functions in this release. One thing to note, SubKeys are not case sensitive. This particular program taught me more about the forms interface and C# programming than any other here. Multi-column ListBoxes and C# were new to me. It is a working but incomplete program. I was going to add add/modify/delete functions but I didn’t have the spare time. When I need the functions I’ll write them and post them. The following is the main part of the application. We start listing the subkeys of HKEY_CURRENT_USER. Clicking on a subkey lists that subkey’s subkeys and values. Clicking on the up arrow removes a level of the tree and displays the new key.

//----------------------------------------------------------------
// A subkey has been clicked upon. Display the subkey's subkeys
// and values.
private void SubkeyListBoxIndexChanged(object sender,
             System.EventArgs e)
{
  String newkey =  m_subkey_list.SelectedItem.ToString();
  if (m_current_key.Text.Length == 0) m_current_key.Text = newkey;
  else
  m_current_key.Text =m_current_key.Text + "\\" + newkey;
  GetKeysAndValues();
}
//------------------------------------------------------------
// This routine is invoked when the up arrow is clicked on.
// It takes the listing to the nest higher level.
private void UpButtonClick(object sender, System.EventArgs e)
{
  String new_key = m_current_key.Text;
  int nDx        = new_key.LastIndexOf('\\');
  if (nDx == -1) m_current_key.Text = "";
  else           m_current_key.Text = new_key.Substring(0,nDx);
  GetKeysAndValues();
}
//----------------------------------------------------------------
private void RootKeyComboboxIndexChanged(object sender,
                                         System.EventArgs e)
{
  m_root_key_listbox.Text =
         m_root_key_listbox.SelectedItem.ToString();
  m_current_key.Text = "";    //we're at the root
  GetKeysAndValues();         //get top level keys
}
//----------------------------------------------------------------
void GetKeysAndValues()
{
  RegistryKey rkey =  GetSelectedKey();
try
{
  m_root_key_listbox.Text = rkey.Name.ToString();
  int nDx = m_root_key_listbox.Text.IndexOf('\\');
  if (nDx != -1) m_root_key_listbox.Text =
                 rkey.Name.Substring(0,nDx);

  m_subkey_list.Items.Clear();
  string[] sknames = rkey.GetSubKeyNames();
  foreach(String str in sknames ) {
    String vstring = (String) rkey.GetValue(str,
                      typeof(string).ToString());
    m_subkey_list.Items.Add(str);
  }
  m_status.Text = "OK";
  DisplayTypesAndValues(rkey);
  rkey.Close();
}
catch (Exception except)
{
  m_status.Text = "Exception occurred " + except.Message;
}
}
//----------------------------------------------------------------
RegistryKey GetSelectedKey()
{
RegistryKey rkey =  null;
try
{
  int nDx = m_root_key_listbox.SelectedIndex;
  switch (nDx)
{
case 0:
  rkey = Registry.ClassesRoot.OpenSubKey(m_current_key.Text);
break;
case 1:
  rkey = Registry.CurrentConfig.OpenSubKey(m_current_key.Text);
break;
case 2:
  rkey = Registry.CurrentUser.OpenSubKey(m_current_key.Text);
break;
case 3:
  rkey = Registry.LocalMachine.OpenSubKey(m_current_key.Text);
break;
case 4:
  rkey = Registry.Users.OpenSubKey(m_current_key.Text);
break;
default:
break;
}
}
catch (Exception except)
{
  m_status.Text = "Exception occured " + except.Message;
}
  return rkey;
}
//----------------------------------------------------------------
void DisplayTypesAndValues(RegistryKey rkey)
{
  listView1.Items.Clear();
  string[] SubKeys  = rkey.GetValueNames();
  foreach(String vstr in SubKeys ) {    //subkey value name
    object robj =  rkey.GetValue(vstr, typeof(string));
    String vstring  = "";
    String vtype = "";
    GetTypeAndValue(robj, ref vtype, ref vstring);
    ListViewItem item1 = new ListViewItem();
    if (vstr == "" ) item1.Text= "Default";
  else item1.Text= vstr;

    listView1.Items.Add(item1);
    item1.SubItems.Add(vtype);
    item1.SubItems.Add(vstring);
  }
}
//----------------------------------------------------------------
void GetTypeAndValue(object robj, ref String Type,
                                  ref String Value)
{
  Value  = robj.ToString();                   //get object value
  Type    = robj.GetType().ToString();        //get object type
  Type    = Type.Substring(7, Type.Length-7); //strip off "System."
//check if special formatting is necessary
  if (Type == "Byte[]") {
    Value = "";
    byte[] Bytes = (byte[]) robj;
    foreach(byte bt in Bytes) {
      string hexval = bt.ToString();
      if (hexval == "") hexval = "0";
      Value         = Value + hexval+ " ";
    }
  }
}
//----------------------------------------------------------------

httptest

I wrote this application to see what the HttpWebRequest and HttpWebResponse classes did. I am not a Web programmer and I’m not that familiar with HTTP or HTML, so I wanted to see what these function do. I’m sure someone else who has a more intimate knowledge of these protocols could do a lot more. I was unsure of what I was seeing, which is why I wrote WebPageGet.

private void GetButtonClick(object sender, System.EventArgs e)
{
HttpWebRequest httpReq;
HttpWebResponse httpResp;
Stream httpStream;

m_results.Text = "";
MessageBeep(100);
try
{
  ASCIIEncoding ASCII = new ASCIIEncoding();
  byte[] buf = new byte[ 128000 ];
  m_header_list.Items.Clear();
  httpReq    = (HttpWebRequest)WebRequest.Create(m_url.Text);
  httpResp   = (HttpWebResponse)httpReq.GetResponse();
  httpStream = httpResp.GetResponseStream();
  int count  = httpStream.Read(buf, 0, buf.Length);
  httpStream.Close();

  string tempstr = ASCII.GetString(buf, 0, count);
  ChangeLfToCrLf(ref tempstr);
  m_results.Text = tempstr;
  for(int i=0; i < httpResp.Headers.Count; ++i)
    m_header_list.Items.Add( httpResp.Headers.Keys[i] + " = " +
                             httpResp.Headers[i]);
  for(int i=0; i< httpResp.Cookies.Count; i++)
    m_cookie_list.Items.Add( httpResp.Cookies[i]);

}
catch (Exception except)
{
  m_results.Text = "Generic Exception: {0}"
                 + except.Message.ToString();
}
  MessageBeep(10000);
}
//----------------------------------------------------------------

WebGetPage

This program was inspired by httptest and another article I did, “DNSWatch”. In that article, I was looking for DNS names being looked up by browsers. In this program, I retrieve a Web page, display it, and list the hosts referenced in it. There are a lot of differences in Web pages, especially how they terminate a line and delineate embedded URLs. There are four main routines. GetHostAndPath is an interesting one. It uses the URI class (uniform resource identifier) to break out the host and path. GetWebPage is the actual network code, copied from an example and slightly modified. There are several ways to do this send and receive, I just chose this one. GetHosts searches the retrieved page for hosts referenced in it. ChangeLfToCrLf is needed because of how different Web pages are terminated in various ways.

//----------------------------------------------------------------
// This is the main routine for retrieving the contents of a Web
// page and displaying both the page itself plus all hostnames
// embedded in it.
private bool GoGetIt()
{
String host="", path="",  page = "";

  MessageBeep(16);
  String Tstring = m_urls.Text.ToLower();
  if (Tstring.StartsWith("http://") != true)
  m_urls.Text = "http://" + m_urls.Text;
  GetHostAndPath(m_urls.Text, ref host, ref path);
  bool ReturnValue = GetWebPage(host, path,ref page,80);
  m_results.Text = page;
  MessageBeep(32);
  GetHosts(page);
  return ReturnValue;
}
//----------------------------------------------------------------
// This is a lower-level function that uses the TcpClient and
// NetworkStream classes to retrieve a web page from a remote
// host.
bool GetWebPage(String Host, String Path, ref String Page,
                int Port)
{
NetworkStream ns;
byte[] bytes;
ASCIIEncoding ASCII = new ASCIIEncoding();

TcpClient tc = new TcpClient();
try
{
  tc.Connect(Host, Port);
  ns = tc.GetStream();
  if(ns.CanWrite && ns.CanRead) {
    tc.ReceiveBufferSize = 128000;

// Create http GET string. Modify for other options as necessary.
    Byte[] sendBytes = Encoding.ASCII.GetBytes(m_http_header.Text);
    ns.Write(sendBytes, 0, sendBytes.Length);

// Reads the NetworkStream into a byte buffer.
    bytes = new byte[tc.ReceiveBufferSize];
    int numBytesRead = 0;
    int numBytesToRead =  tc.ReceiveBufferSize;

    while (true) {
      int n = ns.Read(bytes, numBytesRead, numBytesToRead );
      if (n==0) break;
      numBytesRead += n;
      numBytesToRead -= n;
      Thread.Sleep (1000);    //wait a little, just in case
      if( ns.DataAvailable != true)break;
    }
    tc.Close();
    Page = ASCII.GetString(bytes);
    ChangeLfToCrLf(ref Page);
  }
}
catch (Exception except )
{
  Page = except.ToString();
  tc.Close();
  return false;
}
  return true;
}
//----------------------------------------------------------------
// This function is needed because some Web pages use <cr><lf>,
// some just <lf>.
// Some, like CNN, has both types in pages as well as two sets in
// a row.
void ChangeLfToCrLf ( ref String buf)
{
byte[] abuf = new byte[256000];
int abuf_index = 0;
ASCIIEncoding ASCII = new ASCIIEncoding();

  int crCount = buf.IndexOf("\r",0);
  if (crCount == -1) {    // No carriage returns
    buf = buf.Replace("\x0a", "\x0d\x0a");
    return;
  }
  int bufsize = buf.Length;
  for(int i=0; i<bufsize-1; i++) {
  char ch     = buf[i];
  char nextch = buf[i+1];
  if (ch == '\n') {
    if (nextch != '\r') {
      abuf[abuf_index++] = (byte) '\r';
      abuf[abuf_index++] = (byte) '\n';
    }
    else abuf[abuf_index++] = (byte) '\n';
  }
  else abuf[abuf_index++] = (byte) ch;
}
  buf = ASCII.GetString((byte[]) abuf);
}
//----------------------------------------------------------------
// This procedure uses the URI class (uniform resource identifier)
// to break out the hostname from the rest of the URL.
void GetHostAndPath( String uri, ref String Hostname,
                                 ref String Path)
{
try {
  Uri siteUri = new Uri(uri );
  Hostname    = siteUri.Host;
  Path        = siteUri.AbsolutePath;
}
catch{}
}
//----------------------------------------------------------------
//this procedure searches the page for "http://" to look for host
//names
public void GetHosts (String page)
{
try
{
String Tstring = page.ToLower();
m_url_list.Items.Clear();
int sDx = 0;
char[] chTerminators = new char[6];
  chTerminators[0] = '/';
  chTerminators[1] = '\'';
  chTerminators[2] = '"';
  chTerminators[3] = ' ';
  chTerminators[4] = '\t';
  chTerminators[5] = '\n';

  while(true) {
    sDx = Tstring.IndexOf("http://",sDx);
    if (sDx == -1) break;
    int nDx   = Tstring.IndexOfAny(chTerminators,sDx+8);
    String ts = Tstring.Substring(sDx, nDx-sDx);
    if (m_url_list.FindString(ts)== ListBox.NoMatches)
    m_url_list.Items.Add(ts);
    sDx = nDx;
  }
}
catch {}    //ignore
}
//----------------------------------------------------------------

CSDNS

This program is an example of using the DNS class to resolve host names to ipaddresses, and, where available, resolves host names from IP addresses. The methods for doing this are similar to the sockets functions gethostbyname and gethostbyaddr. Not all IP addresses resolve into host names; it depends on the DNS server, which may or may not have reverse mapping defined. There are also asynchronous methods for doing the same functions. There even is a method, Dns.Resolve, which determines if a IP address or host name is used and calls the appropriate method.

//----------------------------------------------------------------
private void HostNameButtonClick(object sender, System.EventArgs e)
{
  m_status.Text = "Trying....";
  m_status.Update();
try
{
  IPHostEntry hostInfo = Dns.GetHostByName(m_host_name.Text);
  m_ip_address.Text    = hostInfo.AddressList[0].ToString();
  m_status.Text        = "ok";
}
catch (Exception excpt)
{
  m_status.Text = excpt.Message;
  m_ip_address.Text = "";
}
MessageBeep(1000);
}
//----------------------------------------------------------------
private void IPAddressButtonClick(object sender,
                                  System.EventArgs e)
{
  IPAddress ipaddr =  IPAddress.Parse(m_ip_address.Text);
  m_status.Text    = "Trying....";
  m_status.Update();
try
{
  IPHostEntry hostInfo = Dns.GetHostByAddress (ipaddr);
  m_host_name.Text     = hostInfo.HostName;
  m_status.Text        = "ok";
}
catch (Exception excpt)
{
  m_status.Text    = excpt.Message;
  m_host_name.Text = "";
}
  MessageBeep(1000);
}
//----------------------------------------------------------------
private void ResolveButtonClick(object sender, System.EventArgs e)
{
  m_status.Text = "Trying....";
  m_status.Update();
try
{
  IPHostEntry hostInfo = Dns.Resolve(m_resolve_text.Text);
  m_ip_address.Text    = hostInfo.AddressList[0].ToString();
  m_host_name.Text     = hostInfo.HostName;
  m_status.Text        = "ok";
}
catch (Exception excpt)
{
  m_status.Text = excpt.Message;
  m_ip_address.Text = "";
}
  MessageBeep(1000);
}
//----------------------------------------------------------------

Downloads


Download demo project – 211 Kb


Download source – 18 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read