Tuesday, December 02, 2008

Visual Basic Divide operator

For non profressional Visual Basic developer it might not be apparent that VB has two divide operator.

The first divide operator which is more commonly used is '/'. This operator will return the result with decimal
if the number being divided (also call dividend)
cannot be fully divide by the divisor.

The second divide operator '\', which is also called integer division will always return the result (also call Quotient) in integer.

Labels: ,

Saturday, April 26, 2008

Parallelism, Concurrency and the free lunch

For anybody who is looking for ways of how to take advantage of the CPU capability to make their program run faster, I would suggest to look at the Parallel Framework Extension and download the PFX CTP to try it out.

I was just optimizing my program. On my dual core machine, the improved version of my program which use PFX give me an approximate of 18% performance improvement over the original program which use a conventional foreach loop. As my data set increase, the gain is up to about 35%.

Why this is a big deal?

As the silicon has reach its physics limit of getting more into the CPU chip, we cannot depend on Moore’s law to take care of performance for us anymore. The free lunch is pretty much over.

Instead, we can see emerging trend in parallelism and concurrency. People today are talking about multi core processors and how to make program run faster by utilizing all the cores they have in the computer; functional programming language is getting more attention; functional programming elements start to incorporated into mainstream imperative language (example is Linq); Software Transactional Memory is also getting more research effort.

I bet that concurrency is going to be one of the important topics in the next wave of programming paradigm.

Having say that, I dont mean concurrency is the ultimate to all problems. Concurrency is a tough subject and hard to get it right. You have to weight whether the overhead of locking is worth the benefits; You have to understand the side effects of state changes; You have to find a way to handle exception and etc. Concurrency is mean to be a way of tapping into the spare processing capacity, not a way to make slow code fast. You still have to understand where the bottleneck is in your code before you decide to settle on making things more concurrent. Use it with care.

Labels:

Wednesday, December 13, 2006

Calculating working days between 2 dates

Here is a function to calculate the number of working days given two dates. It assume the working days is from Monday to Friday, both dates are inclusive and no holidays in between.



static int CalculateWorkingDays(DateTime start, DateTime end)
{
DateTime firstSunday, lastSaturday;
int workDays = 0;

if (start.DayOfWeek != DayOfWeek.Sunday)
{
firstSunday = start.AddDays(7 - ((int)start.DayOfWeek));
workDays += (6 - (int)start.DayOfWeek);
}
else
firstSunday = start;


if (end.DayOfWeek != DayOfWeek.Saturday)
{
lastSaturday = end.AddDays(-((int)end.DayOfWeek) - 1);
workDays += (int)end.DayOfWeek;
}
else
lastSaturday = end;

TimeSpan ts = lastSaturday.Subtract(firstSunday);
workDays += ((ts.Days + 1) / 7) * 5;

return workDays;
}

Labels:

Sunday, October 16, 2005

Bad Error Message Hinder Productivity

I was writing an C# Console application which I use System.Web.Mail.SmtpMail to send
email out. System.Web.Mail.SmtpMail internally use CDO for Windows 200 (CDOSys) to
send the mail out.

While my application was running, I got an exception when calling the SmtpMail.Send()
method. The exception message was :

Could not access CDO.Message object.

At first thought, the exception could be due to one of the following reasons:

  • The CDOSys.dll component is not registered properly on the machine.
  • The application does not have enough permission to read the registry and instantiate the component.


So, I went on to search the MSDN for the possible cause and mitigation of error. I found a few KB articles and try the settings suggested in the articles and still not luck. I try a couple more things to try to get it work. After half an hour, still nothing was working.

So I decide to reference the CDOSys.dll using COM interop in my C# project and replace the original code with calls to CDO.Message directly. When I ran the application, the exception message I got was :

Unable to connect to SMTP server

Now, things become helpful.I check my SMTP server setting and found out that I gave the wrong IP. I type in the correct SMTP Server IP, ran the app again and everything work now. I move on to put back my original System.Web.Mail.SmtpMail code with the correct SMTP Server IP and get everything working. This whole process took me only 5 minutes.

If the System.Web.Mail.SmtpMail.Send() throw an exception with more precise message, it would have save me 30 minutes time for looking at the wrong thing.

The lesson here is :
If you does not return a meaningful exception/error message which precisely describe the error, you will drive your user nuts and mislead them into looking at the wrong remedy. This will essentially make your API/application less usable.

Labels: ,

Sunday, March 13, 2005

Moving Winform by Clicking on Client Area

When your winform is a custom shape form and doesn't have the title bar, you might want to allow the user to move the form by clicking on the client area.

Here is a code snippet of how to do it :

public class Form1 : System.Windows.Forms.Form
{
private Point offset;

private void Form1_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Point loc = this.Location;
Point mp = Control.MousePosition;

offset = new Point(-(mp.X - loc.X), -(mp.Y - loc.Y));
}

private void Form1_MouseMove(object sender,
System.Windows.Forms.MouseEventArgs e)
{
if(e.Button == MouseButtons.Left)
{
Point mousePos = Control.MousePosition;
mousePos.Offset(offset.X, offset.Y);
Location = mousePos;
}
}
}


Other winform code details has been omitted for code clarity here.

Labels:

Sunday, December 26, 2004

Storing user preference for application.

Often, your application allow user to set certain option that control the behavior of your application. If you do so, remember NOT to save this setting under the application installed folder.

There are 2 consequence if you do so.

First, you can only have one setting for all users. Individual user cannot have their specific config.

Second, if the application is under \program files\, non admin user will not be able to write to this folder, thus cannot save the setting.

Instead, write to the application data folder. Each user in your Windows have their own app data folder. Use the Environment.GetFolderPath() to get the user's application data folder.

Labels: ,

Wednesday, August 11, 2004

Getting Desktop DC


Finally finish my screen capture program yesterday night. Now have to go back to the code to clean up some rubbish and refactor certain code base.

Thanks to one on my friend who pointed out to me that in order to get the desktop DC that you can draw on it, you have to use

GetDC(0)

or in managed code use

GetDC(IntPtr.Zero)

instead of the normal

GetDC(GetDesktopWindow())


Labels:

Tuesday, August 03, 2004

Draw with Inverse Color


After some research and testing, finally has figure out how to draw a rectangle using a color that is the inverse of its drawing surface. The code make use of PInvoke to GDI32 functions.

Here is the sample code :

public sealed class GDI32
{
public const int R2_NOT = 6;

public const int NULL_BRUSH = 5;
public const int HOLLOW_BRUSH = NULL_BRUSH;

[DllImport("gdi32.dll", EntryPoint="SetROP2")]
public static extern int SetROP2(IntPtr hDc, int fnDrawMode);

[DllImport("gdi32.dll", EntryPoint="SelectObject")]
public static extern IntPtr SelectObject(IntPtr hdc,IntPtr bmp);

[DllImport("gdi32.dll", EntryPoint="Rectangle")]
public static extern bool Rectangle(IntPtr hdc,int x, int y, int x2, int y2);

[DllImport("gdi32.dll", EntryPoint="GetStockObject")]
public static extern IntPtr GetStockObject(int fnObject);
}

public sealed class USER32
{
[DllImport("user32.dll",EntryPoint="GetDC")]
public static extern IntPtr GetDC(IntPtr ptr);

}


IntPtr p = USER32.GetDC(this.Handle); // System.Windows.Forms.Form.Handle
GDI32.SetROP2(p, GDI32.R2_NOT);
GDI32.SelectObject(p, GDI32.GetStockObject(GDI32.HOLLOW_BRUSH));
GDI32.Rectangle(p, sx, sy, cx, cy);


However, calling the code intensively will cause a performance hit. I use the code in the Winform's MouseMove event to draw the rectangle, and the performance degrades is evident. I have do some work to minimize the PInvoke call but it is still a slow code.

Labels: ,

Tuesday, July 20, 2004

GDI+ Doesn't XOR

Recently I am writing a screen capture program capture in C#. I notice GDI+ is missing one very important function.

It doesn't support drawing using XOR mode. What a big limitation! That mean now I got to research into how to do that using PInvoke. There is a SetROP2 function in GDI32 but using that with manage code pose a new set of complexities on its own.

The other workaround is that I have to save the state of the drawing surface into a Bitmap. But using this technique to draw a wireframe everytime the mouse move on the drawing surface is going to cause my app a big GC hit as everytime the mouse move, I got to dispose and create new Bitmap object to save the state of the drawing surface.

Any of you guys have any solution to this XOR problem?

Labels: ,