Archive for the ‘.NET C#’ Category.

SMTP Sink Links

Just some links that help with programming SMTP Sinks for IIS.

  1. SMTP Server Technical Articles Microsoft Windows 2000 SMTP Service Events
    <http://msdn.microsoft.com/en-us/library/ms998608.aspx>
  2. How to write an OnArrival-type SMTP event sink in managed code by using Visual Studio .NET 2003
    <http://support.microsoft.com/kb/894286>
  3. Managed IIS SMTP Sink Wrapper: Message.CopyContentToStream
    <http://codeka.com/blogs/index.php/2005/06/06/managed_iis_smtp_sink_wrapper_message_co>
  4. C# Catchall Onarrival Event sink
    <http://gsexdev.blogspot.com/2005/05/c-catchall-onarrival-event-sink.html>
  5. ESTMP Keywords and Verbs (commands) Define
    <http://smtpfilter.sourceforge.net/esmtp.html>
  6. How to get the IP of the SMTP client
    <http://codeka.com/blogs/index.php/2007/08/08/how_to_get_the_ip_of_the_smtp_client>
  7. Sample Sink
    <http://svn.vestris.com/filedetails.php?repname=Vestris+SVN&path=%2Fsncore%2FSnCore.MailSink%2FSnCore.DomainMail%2FSink.cs&rev=1289 >
  8. Creating a custom authentication sink for IIS SMTP or Exchange
    <http://blog.rednael.com/2008/08/13/CreatingACustomAuthenticationSinkForIISSMTPOrExchange.aspx>

Downloading Pictures From Your Digital Camera

Here is a program that I use to quickly get the images off my flash cards. It's a very simple program; you tell it where the photos are that you want and where you want to put them and it does the rest. It is pretty specific and it does not have much flexibility, so if you happen to like the way it organizes the photos then you'll be happy, but if you want some features added, shoot me an email and I will probably incorporate it.

You can pretty much see from the image below how the photos will be organized in your destination directory. Basically, it creates a "year" folder and a day folder within that. If the file already exists in the destination it will not copy it there. As it copies files it will check to see if it can find image orientation information and will rotate the file accordingly.

I like to use shoot raw together with a small jpeg file. I use the raw as the digital negative and the jpeg as a quick proof of the image. Generally I try to get it right in the camera, and it's also a lot quicker if I just want to take some snapshots and make them quickly available for viewing. Currently it only works with .raw and .jpg extensions, so if you need a different extension let me know and I will add it. I hope you find this useful even though it is a little limited.

Click on the thumbnails below for a closer look...

Download the Program here

TableScriptGen – C# 2 Console App

NOTE: This is a first draft, alpha code release.

Whenever you are working with Microsoft's SQL server you inevitably have to write some Transact SQL code.

I'm currently working on a data migration script and I found I'm using similar code over and over for the different tables found in the source database.

I've written a small utility that can help in this task. The code connects to the database, collects table information like the columns and column data types, and writes the script.

Below is a list of the current scripts that it creates. I've provided the code for you as well so that you can simply copy and paste into a new console app. You can also download the Visual Studio 2k5 Solution.


Example Usage:

tablescriptgen.exe /server:(local) /initialcatalog:mydb /tablename:mytable /tablealias:mytbl

List of Parameters:
Required

/server: sever to connect to; uses Windows Authentication
/initialcatalog: database name to use
/tablename: the table to retrieve data for
/tablealias: the tablename used in the sql statement
ex: "Select * from mytable as 'tablealias' "

Optional

/writefilefullname: full path with filename and extension of the file to write the script to; defaults to user's desktop
/overridedbname: the db name to use in the "USE" statement of the written script
/usefromlinkedtablename: create a cursor from the tablename that exists in a linked server

List of supported scripts:

WriteTableIterator()
Creates Transactsql code to iterate through the source table rows with a cursor.

WriteInsertStatement()
Creates the insert into statement

I plan on adding more as as I need them and if you add enhancements please shoot me a copy. (contact #ATT# deciacco #DOTT# com)

/*
 * http://www.deciacco.com/blog/
 *
 * TableScriptGen Program: Generates sql script for a given
 * MS Sql Server table
 *
 * Authors:		Deciacco.com
 * Contributors:
 * Created:		15 June 2007
 * Modified:		15 June 2007
 *
 * Version:		1.0
 * Arguments:		See below in the Arguments class for valid format
 *
 * Notes:			As of modified date above this program works with
 *			both SQL Server 2k and 2k5
 *
 * License:		This program is free and distributed 'AS IS' and without
 *			any warranty. If you make enhacements, please send a copy
 *			to contact #ATT# deciacco #DOTT# com.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Collections.Specialized;
using System.Text.RegularExpressions;

namespace TableScriptGen
{
	///
	/// Main program
	///
	class Program
	{
		#region Fields
		static string _server = string.Empty;
		static string _initialcatalog = string.Empty;
		static string _tablealias = string.Empty;
		static string _tablename = string.Empty;

		static DataSet _tabledata_ds = null;
		static SqlConnectionStringBuilder _sconnbldr = null;
		static SqlConnection _conx = null;
		static SqlDataAdapter _da = null;

		static string _getinfosql = string.Empty;

		static string _writefilefullname = string.Empty;
		static string _overridedbname = string.Empty;
		static string _usefromlinkedtablename = string.Empty;

		#endregion

		static void Main(string[] args)
		{
			try
			{
				// get the arguments
				Arguments cmargs = new Arguments(args);

				if (cmargs["server"] == null ||
					cmargs["initialcatalog"] == null ||
					cmargs["tablealias"] == null ||
					cmargs["tablename"] == null)
					throw new Exception("Invalid Arguments");

				// set the variables
				Program._server = cmargs["server"];
				Program._initialcatalog = cmargs["initialcatalog"];
				Program._tablealias = cmargs["tablealias"];
				Program._tablename = cmargs["tablename"];
				Program._writefilefullname = Environment.GetFolderPath(
						Environment.SpecialFolder.DesktopDirectory).ToString() +
						@"\" + Program._tablename + ".txt";

				// optional arguments
				if(cmargs["writefilefullname"] != null)
					Program._writefilefullname = cmargs["writefilefullname"];

				if(cmargs["overridedbname"] != null)
					Program._overridedbname = cmargs["overridedbname"];

				if(cmargs["usefromlinkedtablename"] != null)
					Program._usefromlinkedtablename = cmargs["usefromlinkedtablename"];

				// set the sql statement to get table information from the db
				Program._getinfosql = "select table_name, column_name, column_default, data_type, ";
				Program._getinfosql += "character_maximum_length, is_nullable ";
				Program._getinfosql += "from information_schema.columns ";
				Program._getinfosql += "where table_name in ";
				Program._getinfosql += "(select table_name ";
				Program._getinfosql += "from information_schema.tables ";
				Program._getinfosql += "where table_type = 'base table')";
				Program._getinfosql += "and ";
				Program._getinfosql += "table_name = '" + Program._tablename + "'";

				// create the connection string builder object and set its properties
				Program._sconnbldr = new SqlConnectionStringBuilder();
				Program._sconnbldr.DataSource = Program._server;
				Program._sconnbldr.InitialCatalog = Program._initialcatalog;
				Program._sconnbldr.IntegratedSecurity = true;

				// create the connection object
				Program._conx = new SqlConnection(Program._sconnbldr.ToString());

				// open the connection and get the data
				Program._conx.Open();
				Program._da = new SqlDataAdapter(Program._getinfosql, Program._conx);

				Program._tabledata_ds = new DataSet(Program._tablealias);

				Program._da.Fill(Program._tabledata_ds, Program._tablealias);

				// process table data
				// this is a good place to add other functions to do other
				// scripts
				Program.WriteTableIterator(Program._writefilefullname, false,
					Program._overridedbname, Program._usefromlinkedtablename);

				Program.WriteInsertStatement(Program._writefilefullname, true);

			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Message);
			}
			finally
			{
				// if the connection object has been set and the error
				// occured after it was open, lets close the connection
				if(Program._conx != null)
					if (Program._conx.State == ConnectionState.Open)
					{
						Program._conx.Close();
						Program._conx.Dispose();
					}
			}
		}

		static void WriteTableIterator(string p_writefilefullname, bool p_appendtofile,
				string p_overridedbname, string p_usefromlinkedtablename)
		{
			TextWriter tw = new StreamWriter(p_writefilefullname, p_appendtofile);
			DataRowCollection drw = Program._tabledata_ds.Tables[Program._tablealias].Rows;

			string dataTypes = "varchar";
			int cnt;

			if (p_overridedbname != string.Empty)
				tw.WriteLine("use " + p_overridedbname + Environment.NewLine + "go" + Environment.NewLine);
			else
				tw.WriteLine("use " + Program._initialcatalog + Environment.NewLine + "go" + Environment.NewLine);

			tw.Write("declare ");
			for (cnt = 0; cnt < drw.Count; cnt++)
			{
				DataRow dr = drw[cnt];

				if (dr["data_type"].ToString() == "text") //Can't use text for local variable
				{
					dr["data_type"] = "varchar";
					dr["character_maximum_length"] = 1000;
				}

				tw.Write("@" + Program._tablealias + dr["column_name"] + " " + dr["data_type"]);

				if (dataTypes.IndexOf(dr["data_type"].ToString()) >= 0)
					tw.Write("(" + dr["character_maximum_length"] + ")");

				if (cnt != drw.Count - 1)
					tw.Write(",");
				else
					tw.Write(Environment.NewLine);

				tw.Write(Environment.NewLine);
			}

			tw.WriteLine("declare " + Program._tablealias +
				"_cursor cursor forward_only read_only" + Environment.NewLine + "for");

			tw.Write("select ");
			for (cnt = 0; cnt < drw.Count; cnt++)
			{
				DataRow dr = drw[cnt];

				tw.Write(Program._tablealias + "." + dr["column_name"] + " as _" + Program._tablealias + dr["column_name"]);

				if (cnt != drw.Count - 1)
					tw.Write(", ");

				if ((cnt + 1) % 4 == 0)
					tw.Write(Environment.NewLine);
			}

			if (p_usefromlinkedtablename != string.Empty)
				tw.WriteLine(Environment.NewLine + "from " + p_usefromlinkedtablename + " as " + Program._tablealias);
			else
				tw.WriteLine(Environment.NewLine + "from " + Program._tablename + " as " + Program._tablealias);

			tw.Write(Environment.NewLine + "open " + Program._tablealias + "_cursor " + Environment.NewLine +
					Environment.NewLine + "fetch next from " + Program._tablealias + "_cursor " + Environment.NewLine +
					"into ");

			for (cnt = 0; cnt < drw.Count; cnt++)
			{
				DataRow dr = drw[cnt];

				tw.Write("@" + Program._tablealias + dr["column_name"]);

				if (cnt != drw.Count - 1)
					tw.Write(",");
				else
					tw.Write(Environment.NewLine);

				tw.Write(Environment.NewLine);
			}

			tw.WriteLine("while @@fetch_status = 0" + Environment.NewLine + "begin" + Environment.NewLine);
			tw.WriteLine(Environment.NewLine + "--start your code here" +
				Environment.NewLine + Environment.NewLine);

			tw.WriteLine("fetch next from " + Program._tablealias + "_cursor");
			tw.Write("into ");

			for (cnt = 0; cnt < drw.Count; cnt++)
			{
				DataRow dr = drw[cnt];

				tw.Write("@" + Program._tablealias + dr["column_name"]);

				if (cnt != drw.Count - 1)
					tw.Write(",");
				else
					tw.Write(Environment.NewLine);

				tw.Write(Environment.NewLine);
			}

			tw.WriteLine("end");

			tw.WriteLine("close " + Program._tablealias + "_cursor");
			tw.WriteLine("deallocate " + Program._tablealias + "_cursor");
			tw.Write("go");
			tw.WriteLine();
			tw.WriteLine();

			tw.Close();
			tw.Dispose();
		}

		static void WriteInsertStatement(string p_writefilefullname, bool p_appendtofile)
		{
			int cnt;

			TextWriter tw = new StreamWriter(p_writefilefullname, p_appendtofile);
			DataRowCollection drw = Program._tabledata_ds.Tables[Program._tablealias].Rows;

			tw.Write("insert into " + Program._tablename + " (");

			for (cnt = 0; cnt < drw.Count; cnt++)
			{
				DataRow dr = drw[cnt];

				tw.Write(dr["column_name"]);

				if (cnt != drw.Count - 1)
					tw.Write(", ");

				if ((cnt + 1) % 4 == 0)
					tw.Write(Environment.NewLine);
			}

			tw.WriteLine(")");

			tw.WriteLine("values (");
			for (cnt = 0; cnt < drw.Count; cnt++)
			{
				DataRow dr = drw[cnt];

				tw.Write("@" + Program._tablealias + dr["column_name"]);

				if (cnt != drw.Count - 1)
					tw.Write(",");

				if ((cnt + 1) % 4 == 0)
					tw.Write(Environment.NewLine);
			}

			tw.WriteLine(")");

			tw.WriteLine();
			tw.WriteLine();

			tw.Close();
			tw.Dispose();
		}
	}

/*
 * http://www.codeproject.com/csharp/command_line.asp
 * See below for valid parameter forms
 *
 * Arguments class: application arguments interpreter
 *
 * Authors:			R. LOPES
 * Contributors:	R. LOPES
 * Created:			25 October 2002
 * Modified:		28 October 2002
 *
 * Version:			1.0
 *
 */
    ///
    /// Arguments class
    ///
    public class Arguments{
        // Variables
        private StringDictionary Parameters;

        // Constructor
        public Arguments(string[] Args)
        {
            Parameters = new StringDictionary();
            Regex Spliter = new Regex(@"^-{1,2}|^/|=|:",
                RegexOptions.IgnoreCase|RegexOptions.Compiled);

            Regex Remover = new Regex(@"^['""]?(.*?)['""]?$",
                RegexOptions.IgnoreCase|RegexOptions.Compiled);

            string Parameter = null;
            string[] Parts;

            // Valid parameters forms:
            // {-,/,--}param{ ,=,:}((",')value(",'))
            // Examples:
            // -param1 value1 --param2 /param3:"Test-:-work"
            //   /param4=happy -param5 '--=nice=--'
            foreach(string Txt in Args)
            {
                // Look for new parameters (-,/ or --) and a
                // possible enclosed value (=,:)
                Parts = Spliter.Split(Txt,3);

                switch(Parts.Length){
                // Found a value (for the last parameter
                // found (space separator))
                case 1:
                    if(Parameter != null)
                    {
                        if(!Parameters.ContainsKey(Parameter))
                        {
                            Parts[0] =
                                Remover.Replace(Parts[0], "$1");

                            Parameters.Add(Parameter, Parts[0]);
                        }
                        Parameter=null;
                    }
                    // else Error: no parameter waiting for a value (skipped)
                    break;

                // Found just a parameter
                case 2:
                    // The last parameter is still waiting.
                    // With no value, set it to true.
                    if(Parameter!=null)
                    {
                        if(!Parameters.ContainsKey(Parameter))
                            Parameters.Add(Parameter, "true");
                    }
                    Parameter=Parts[1];
                    break;

                // Parameter with enclosed value
                case 3:
                    // The last parameter is still waiting.
                    // With no value, set it to true.
                    if(Parameter != null)
                    {
                        if(!Parameters.ContainsKey(Parameter))
                            Parameters.Add(Parameter, "true");
                    }

                    Parameter = Parts[1];

                    // Remove possible enclosing characters (",')
                    if(!Parameters.ContainsKey(Parameter))
                    {
                        Parts[2] = Remover.Replace(Parts[2], "$1");
                        Parameters.Add(Parameter, Parts[2]);
                    }

                    Parameter=null;
                    break;
                }
            }
            // In case a parameter is still waiting
            if(Parameter != null)
            {
                if(!Parameters.ContainsKey(Parameter))
                    Parameters.Add(Parameter, "true");
            }
        }

        // Retrieve a parameter value if it exists
        // (overriding C# indexer property)
        public string this [string Param]
        {
            get
            {
                return(Parameters[Param]);
            }
        }
    }
}

Click here to download the C# 2 Source (Visual Studio 2k5) (45.2k)

BatchRun – .NET C# 2 App

NOTE: This is a first draft, alpha code release.

This application was written to run multiple sql scripts files against an MS Sql server database. I wrote it to learn more about .NET C# 2 Windows application development.

It is pretty much a work in progress, but it’s at a usable point so I decided to release it.

Please download the source below. If you learn from it or find it useful in any way, please leave me a comment. Also, if you enhance it, I’d like a copy.

Screenshots:

Click here to download the C# 2 Source (Visual Studio 2k5) (1.2Mb)

Google Wallpaper Fixed

One of my favorite programmers on the net, The Software Jedi, has this cool program called Google Wallpaper. It runs as a systray app, and basically downloads images and sets them as your desktop background based on a predefined list of keywords. It's a great app, but due to recent changes on Google's site, it stopped working.

Here is the broken code in GoogleImageSearch.cs

public string[] DoSearch()
{
    string url = @"http://images.google.com/images?lr=&imgsz=xxlarge&safe="+(_safe?"on":"off")+"&q=" + _keyword;
    WebClient wc = new WebClient();
    string html = wc.DownloadString(url);
    string[] pieces = html.Split(new string[] { "

This is the new code...

public string[] DoSearch()
{
    string url = @"http://images.google.com/images?lr=&imgsz=xxlarge&safe=" + (_safe ? "on" : "off") + "&q=" + _keyword;
    WebClient wc = new WebClient();
    string html = wc.DownloadString(url);
    string[] images;

    try
    {
        //Use regular expression to find all the urls to jpg files.
        //Google changed their html, and all image urls are in javascript code.
        Regex RegexObj = new Regex("\\b(https?|ftp|file)://[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|](.jpg)", RegexOptions.IgnoreCase);
        MatchCollection RegexMatches = RegexObj.Matches(html);

        images = new string[RegexMatches.Count];

        for (int i = 0; i < RegexMatches.Count; i++)
        {
            // Add each image url string to the string array.
            images[i] = RegexMatches[i].Value;
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }

    return images;
}

Binary + Source (.NET Framework 2.0 Required to run)
Download the .Net 2 Framework here

Please visit The Software Jedi's site for more cool apps!!

C# .NET 2.0 Web Service — Sync + Async

I wanted to learn how to use web services in .NET with C#, so I created this tiny program that goes out and gets the "Dilbert of the Day" comic strip and puts it on your desktop in the form of a jpeg file.

There are two versions to this program. One calls the web service synchronously, while the other calls the web services asynchronously. Synchronous calls are what most programmers would be familiar with. When a synchronous function/method is called it doesn't return control back to the calling program until it's finished, while an asynchronous function/method returns control immediately while it runs in a separate thread.

The synchronous version of this program is much simpler than the asynchronous version, but the later allows for more flexibility. For example, in the asynchronous version the program can display a progress indicator while it's waiting for the call to complete.

You could use the synchronous call to the web service and put it in a separate thread yourself. You would achieve the same result as the asynchronous call. It just makes the code a little longer and slightly more complex. I'm not great with threading in C# just yet, so if you want to write this yourself, I'd be glad to post it here and give you credit, of course.

Posted below are both version of the program. You can download the source and the exe separately. Just keep in mind that if you want to run the exe by itself you will need to make sure you have the .NET Framework 2.0 installed.

Any suggestions/comments welcome.

Synchronous Code

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using DilbertADay.com.esynaps.www;

namespace DilbertADay
{
    class Program
    {
        public static void Main(string[] args)
        {
            DailyDilbert wsDd;
            Byte[] imageData;
            MemoryStream strm;
            Bitmap bmp;           

            try
            {
                wsDd = new DailyDilbert();
                imageData = wsDd.DailyDilbertImage();
                strm = new MemoryStream(imageData);
                bmp = new Bitmap(strm);
                bmp.Save(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
                    + "\\dilbert.jpg",ImageFormat.Jpeg);
                bmp.Dispose();
                strm.Close();
                wsDd.Dispose();
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
        }
    }
}

Asynchronous Code

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using DilbertADay.com.esynaps.www;

namespace DilbertADay
{
    class Program
    {
        public static int isCompleted = 0;
        public static Byte[] imgData;
        public static int timeout = 10000;

        public static void Main(string[] args)
        {
            DailyDilbert wsDd;
            MemoryStream strm;
            Bitmap bmp;

            int start, currentSecond;

            try
            {
                wsDd = new DailyDilbert();
                wsDd.DailyDilbertImageCompleted += new DailyDilbertImageCompletedEventHandler(
                    Program.DailyDilbertImageCompleted_Handler);
                wsDd.DailyDilbertImageAsync();

                start = DateTime.Now.Millisecond;
                currentSecond = start;

                Console.WriteLine("Sending request");
                while (Program.isCompleted == 0 && (currentSecond - start) < Program.timeout)
                {
                    if (currentSecond < DateTime.Now.Millisecond)
                    {
                        currentSecond = DateTime.Now.Millisecond;
                        Console.Write(".");
                    }
                }
                Console.Write("\n");

                if (Program.isCompleted == 1)
                {
                    Console.WriteLine("Generating image");
                    strm = new MemoryStream(Program.imgData);
                    bmp = new Bitmap(strm);
                    bmp.Save(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
                        + "\\dilbert.jpg", ImageFormat.Jpeg);

                    bmp.Dispose();
                    strm.Close();
                    wsDd.Dispose();
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
        }

        public static void DailyDilbertImageCompleted_Handler(object sender, DailyDilbertImageCompletedEventArgs args)
        {
            try
            {
                Program.imgData = args.Result;
                Program.isCompleted = 1;
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                Program.isCompleted = 2;
            }
        }
    }
}

Executable (dilbertaday.exe) (24k)
Source Code / VS 2005 Solution (dilbertaday.zip) (81k)