DirectX creating problem with TimeSpan structure

V

Vibhesh

I am facing problem with TimeSpan structure when DirectX is used.
Following is the sample code that causes the problem:

***************************************************************************************************************
{
...........................
PrintTimeSpanProblem();
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
PrintTimeSpanProblem();
..............
}

public void TimeSpanProblem()
{
DateTime dt1970 = new DateTime(1970, 1, 1);
TimeSpan tss = DateTime.Now - dt1970;
uint nT11 = (uint)(tss.Ticks / TimeSpan.TicksPerSecond);
uint nT1 = (uint)tss.TotalSeconds;
uint nT2 = (uint)(tss.Ticks - (nT1 * TimeSpan.TicksPerSecond));
//Ideally nT11 and nT1 should be the same.
//After new Device is created, TimeSpan.TotalSeconds does not give
correct value.
if (nT1 != nT11)
{

Debug.WriteLine("********************************************************"
+ "\nPROBLEM!!"
+
"\n********************************************************"
+ "\nTicks =" + tss.Ticks.ToString()
+ "\nTotalSeconds(T1) =" + nT1
+ "\nT2 =" + nT2
+ "\nTicks/TicksPerSecond(T11)=" + nT11
+
"\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
else
{

Debug.WriteLine("********************************************************"
+ "\nEverything OK!!"
+
"\n********************************************************"
+ "\nTicks =" + tss.Ticks.ToString()
+ "\nTotalSeconds(T1) =" + nT1
+ "\nT2 =" + nT2
+ "\nTicks/TicksPerSecond(T11)=" + nT11
+
"\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
}

***************************************************************************************************************

In normal case (i.e. when TimeSpan behaves correctly), following would
be the output:
ts.Ticks =11792483786198544
nT1 =1179248378
nT2 =6198544
nT11 =1179248378

Note that, nT1 is first 10 digits of ts.Ticks, and nT2 is last 7
digits of ts.Ticks


After new Device(..) is getting called the output is following:
ts.Ticks =11792499480265504
nT1 =1179249920
nT2 =280265504
nT11 =1179249948

Note that, nT1 is not same as first 10 digits of ts.Ticks, and nT2 is
9 digits long and is not same as last 7 digits of ts.Ticks
THIS MEANS THAT VALUE OF ts.TotalSeconds DOES NOT CORRESPOND TO THE
VALUE OF ts.Ticks.


Please let me know if anyone of you have faced such a problem?

Regards,
Vibhesh.
 
P

Peter Duniho

[...]
Note that, nT1 is not same as first 10 digits of ts.Ticks, and nT2 is
9 digits long and is not same as last 7 digits of ts.Ticks
THIS MEANS THAT VALUE OF ts.TotalSeconds DOES NOT CORRESPOND TO THE
VALUE OF ts.Ticks.

Well, first of all, keep in mind that you are treating the fractional part
of the number as if it were an actual number. But it's not. It's just
the numerator of a fraction. The digit count will depend on how large the
numerator is, and leading zeros that can be seen in the original Ticks
value will be lost when you treat the numerator as a plain integer and
print it out that way.

As for the difference in the seconds portion, I don't really know. You
didn't offer a concise sample that would allow anyone to reproduce your
results, so it's not possible to examine the situation you have. I don't
see any reason that the act of calling any DirectX function would affect
the calculations you're doing.

Assuming the code you've posted is indeed the code you're using, it would
seem impossible to have the results you've claimed. In particular, I see
no reason that getting the TotalSeconds property from the TimeSpan value
would produce different results from calculating it based on the Ticks and
TicksPerSecond properties.

Note that in your "problematic" output, the only real problem is that the
value nT1 is calculated incorrectly. Given its value, the result for nT2
is correct, and of course the value for nT11 is correct given the Ticks
value being shown.

So, if I had to guess, I'd say that you have somehow gotten the wrong
value for tss.TotalSeconds for some reason. I doubt there's a problem
with the class itself, so that suggests you've done something wrong in
your own code. Whether that's using a different TimeSpan value to obtain
that property than you use elsewhere, or something more subtle like an
unprotected multi-threaded access to the value, I can't say. You didn't
post any code that shows what you're actually doing (that is, that is a
complete-but-concise example that reliably reproduces the problem), so
there's no way to comment on what you might be doing wrong.

Pete
 
V

Vibhesh

Here is a sample code that demonstrates the problem.
To build and run this code you will require DirectX SDK installed on
your system.

Follow the steps below to reproduce the problem.
1.) Create a new Windows Application project in Visual Studio 2003
(the code will also work in 2005)
2.) Open the default Form1 in 'Code View'
3.) Replace the code of Form1 with the code specified below
4.) Add references to DirectX, Direct3D, and Direct3DX dlls.
5.) Run the App
6.) Press TestTimeSpan button to see the output from TimeSpan
structure and my calculations.
7.) Press Create Device button to create a new DirectX device object.
8.) Again press TestTimeSpan button
HERE YOU WILL SEE THE PROBLEM IN THE TIMESPAN STRUCTURE.
NOTICE THE DIFFRENCE BETWEEN Ticks and TotalSeconds properties.


*****************************CODE
(form1.cs)****************************
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D = Microsoft.DirectX.Direct3D;
using System.Diagnostics;

namespace TestNamespace
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private System.Windows.Forms.Button btn_TestTimeSpan;
private System.Windows.Forms.Button btnCreateDevice;
private System.Windows.Forms.Button btnDisposeDevice;
private System.Windows.Forms.TextBox txtOutput;
private Device device = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btn_TestTimeSpan = new System.Windows.Forms.Button();
this.btnCreateDevice = new System.Windows.Forms.Button();
this.btnDisposeDevice = new System.Windows.Forms.Button();
this.txtOutput = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// btn_TestTimeSpan
//
this.btn_TestTimeSpan.Location = new System.Drawing.Point(0,
48);
this.btn_TestTimeSpan.Name = "btn_TestTimeSpan";
this.btn_TestTimeSpan.Size = new System.Drawing.Size(104,
32);
this.btn_TestTimeSpan.TabIndex = 0;
this.btn_TestTimeSpan.Text = "Test TimeSpan";
this.btn_TestTimeSpan.Click += new
System.EventHandler(this.btn_TestTimeSpan_Click);
//
// btnCreateDevice
//
this.btnCreateDevice.Location = new System.Drawing.Point(0,
8);
this.btnCreateDevice.Name = "btnCreateDevice";
this.btnCreateDevice.Size = new System.Drawing.Size(104, 32);
this.btnCreateDevice.TabIndex = 1;
this.btnCreateDevice.Text = "Create Device";
this.btnCreateDevice.Click += new
System.EventHandler(this.btnCreateDevice_Click);
//
// btnDisposeDevice
//
this.btnDisposeDevice.Location = new
System.Drawing.Point(112, 8);
this.btnDisposeDevice.Name = "btnDisposeDevice";
this.btnDisposeDevice.Size = new System.Drawing.Size(104,
32);
this.btnDisposeDevice.TabIndex = 2;
this.btnDisposeDevice.Text = "Dispose Device";
this.btnDisposeDevice.Click += new
System.EventHandler(this.btnDisposeDevice_Click);
//
// txtOutput
//
this.txtOutput.Location = new System.Drawing.Point(8, 96);
this.txtOutput.Multiline = true;
this.txtOutput.Name = "txtOutput";
this.txtOutput.ScrollBars =
System.Windows.Forms.ScrollBars.Both;
this.txtOutput.Size = new System.Drawing.Size(656, 408);
this.txtOutput.TabIndex = 3;
this.txtOutput.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(672, 518);
this.Controls.Add(this.txtOutput);
this.Controls.Add(this.btnDisposeDevice);
this.Controls.Add(this.btnCreateDevice);
this.Controls.Add(this.btn_TestTimeSpan);
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.SizableToolWindow;
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
try
{
using (Form1 frm = new Form1())
{
frm.Show();
Application.Run(frm);
}
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show("Problem in
application, will now exit. " + e.Message);
}
}

private void CreateDevice()
{
PresentParameters presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.AutoDepthStencilFormat = DepthFormat.D16;
presentParams.EnableAutoDepthStencil = true;

device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
}
private void DisposeDevice()
{
device.Dispose();
}
public void TimeSpanProblem(string strFrom)
{
DateTime dt1970 = new DateTime(1970, 1, 1);
//LoadVC();
System.TimeSpan tss = DateTime.Now - dt1970;
uint nT11 = (uint)(tss.Ticks / TimeSpan.TicksPerSecond);
uint nT1 = (uint)tss.TotalSeconds;
uint nT2 = (uint)(tss.Ticks - (nT1 *
TimeSpan.TicksPerSecond));
string displayStr = "@@@@@@@@@"+strFrom+"@@@@@@@@@";
if (nT1 != nT11)
{
displayStr += Environment.NewLine +
"********************************************************"
+ Environment.NewLine + "PROBLEM!! T1 != T11 (NOTICE
THAT THE DECIMALS ARE GONE FOR TotalSeconds)"
+ Environment.NewLine +
"********************************************************";
}
else
{
displayStr += Environment.NewLine +
"********************************************************"
+ Environment.NewLine + "Everything OK!!"
+ Environment.NewLine +
"********************************************************";
}

displayStr+=
Environment.NewLine + "------TimeSpan---------"
+ Environment.NewLine + "tss.Ticks
=
{0}"
+ Environment.NewLine + "tss.TotalSeconds
=
{1}"
+ Environment.NewLine + "------My Variables---------"
+ Environment.NewLine + "T1 = (uint)tss.TotalSeconds
= {2}"
+ Environment.NewLine + "T2 = (uint)(tss.Ticks - (nT1
* TimeSpan.TicksPerSecond)) = {3}"
+ Environment.NewLine + "T11 = (uint)(tss.Ticks /
TimeSpan.TicksPerSecond) = {4}"
+ Environment.NewLine +
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"+Environment.NewLine
+Environment.NewLine+Environment.NewLine;

txtOutput.Text +=
String.Format(displayStr,tss.Ticks,tss.TotalSeconds,nT1,nT2,nT11);
txtOutput.Select(txtOutput.Text.Length-2,1);
txtOutput.ScrollToCaret();
}

private void btn_TestTimeSpan_Click(object sender,
System.EventArgs e)
{
this.TimeSpanProblem("From btn_TestTimeSpan_Click");
}

private void btnCreateDevice_Click(object sender,
System.EventArgs e)
{
CreateDevice();
}

private void btnDisposeDevice_Click(object sender,
System.EventArgs e)
{
DisposeDevice();
}

}
}

*****************************CODE
END**********************************
 
V

Vibhesh

Vibhesh said:
I am facing problem with TimeSpan structure when DirectX is used.
Following is the sample code that causes the problem:

***************************************************************************************************************
{
..........................
PrintTimeSpanProblem();
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
PrintTimeSpanProblem();
.............
}

public void TimeSpanProblem()
{
DateTime dt1970 = new DateTime(1970, 1, 1);
TimeSpan tss = DateTime.Now - dt1970;
uint nT11 = (uint)(tss.Ticks / TimeSpan.TicksPerSecond);
uint nT1 = (uint)tss.TotalSeconds;
uint nT2 = (uint)(tss.Ticks - (nT1 * TimeSpan.TicksPerSecond));
//Ideally nT11 and nT1 should be the same.
//After new Device is created, TimeSpan.TotalSeconds does not give
correct value.
if (nT1 != nT11)
{

Debug.WriteLine("********************************************************"
+ "\nPROBLEM!!"
+
"\n********************************************************"
+ "\nTicks =" + tss.Ticks.ToString()
+ "\nTotalSeconds(T1) =" + nT1
+ "\nT2 =" + nT2
+ "\nTicks/TicksPerSecond(T11)=" + nT11
+
"\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
else
{

Debug.WriteLine("********************************************************"
+ "\nEverything OK!!"
+
"\n********************************************************"
+ "\nTicks =" + tss.Ticks.ToString()
+ "\nTotalSeconds(T1) =" + nT1
+ "\nT2 =" + nT2
+ "\nTicks/TicksPerSecond(T11)=" + nT11
+
"\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
}

***************************************************************************************************************

In normal case (i.e. when TimeSpan behaves correctly), following would
be the output:
ts.Ticks =11792483786198544
nT1 =1179248378
nT2 =6198544
nT11 =1179248378

Note that, nT1 is first 10 digits of ts.Ticks, and nT2 is last 7
digits of ts.Ticks


After new Device(..) is getting called the output is following:
ts.Ticks =11792499480265504
nT1 =1179249920
nT2 =280265504
nT11 =1179249948

Note that, nT1 is not same as first 10 digits of ts.Ticks, and nT2 is
9 digits long and is not same as last 7 digits of ts.Ticks
THIS MEANS THAT VALUE OF ts.TotalSeconds DOES NOT CORRESPOND TO THE
VALUE OF ts.Ticks.


Please let me know if anyone of you have faced such a problem?

Regards,
Vibhesh.
 
P

Peter Duniho

Here is a sample code that demonstrates the problem.
To build and run this code you will require DirectX SDK installed on
your system. [...]

Huh. Well, I can confirm your problem. The exact same results occur on
my computer with your code.

But I have no good answer. Please note that you will probably have to
report this to Microsoft customer support (use the online form, there
should be no charge since it seems clear it's a bug in their own
software), and you may get a suitable resolution from them.

You might be able to learn more by stepping into the TotalSeconds property
getter (I haven't tried this, but it seems to me that if you are viewing
disassembly while you are debugging, you should be able to step into the
code) and seeing what it's doing. I would think it would just do the same
"divide by TicksPerSecond" that you do in your own example code, but
obviously it's not as simple as that.

In the meantime, since doing the conversion yourself directly is easy and
does work, it seems to me that's a perfectly suitable workaround.

Pete
 
W

Willy Denoyette [MVP]

Vibhesh said:
Here is a sample code that demonstrates the problem.
To build and run this code you will require DirectX SDK installed on
your system.

Follow the steps below to reproduce the problem.
1.) Create a new Windows Application project in Visual Studio 2003
(the code will also work in 2005)
2.) Open the default Form1 in 'Code View'
3.) Replace the code of Form1 with the code specified below
4.) Add references to DirectX, Direct3D, and Direct3DX dlls.
5.) Run the App
6.) Press TestTimeSpan button to see the output from TimeSpan
structure and my calculations.
7.) Press Create Device button to create a new DirectX device object.
8.) Again press TestTimeSpan button
HERE YOU WILL SEE THE PROBLEM IN THE TIMESPAN STRUCTURE.
NOTICE THE DIFFRENCE BETWEEN Ticks and TotalSeconds properties.


*****************************CODE
(form1.cs)****************************
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Direct3D = Microsoft.DirectX.Direct3D;
using System.Diagnostics;

namespace TestNamespace
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private System.Windows.Forms.Button btn_TestTimeSpan;
private System.Windows.Forms.Button btnCreateDevice;
private System.Windows.Forms.Button btnDisposeDevice;
private System.Windows.Forms.TextBox txtOutput;
private Device device = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btn_TestTimeSpan = new System.Windows.Forms.Button();
this.btnCreateDevice = new System.Windows.Forms.Button();
this.btnDisposeDevice = new System.Windows.Forms.Button();
this.txtOutput = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// btn_TestTimeSpan
//
this.btn_TestTimeSpan.Location = new System.Drawing.Point(0,
48);
this.btn_TestTimeSpan.Name = "btn_TestTimeSpan";
this.btn_TestTimeSpan.Size = new System.Drawing.Size(104,
32);
this.btn_TestTimeSpan.TabIndex = 0;
this.btn_TestTimeSpan.Text = "Test TimeSpan";
this.btn_TestTimeSpan.Click += new
System.EventHandler(this.btn_TestTimeSpan_Click);
//
// btnCreateDevice
//
this.btnCreateDevice.Location = new System.Drawing.Point(0,
8);
this.btnCreateDevice.Name = "btnCreateDevice";
this.btnCreateDevice.Size = new System.Drawing.Size(104, 32);
this.btnCreateDevice.TabIndex = 1;
this.btnCreateDevice.Text = "Create Device";
this.btnCreateDevice.Click += new
System.EventHandler(this.btnCreateDevice_Click);
//
// btnDisposeDevice
//
this.btnDisposeDevice.Location = new
System.Drawing.Point(112, 8);
this.btnDisposeDevice.Name = "btnDisposeDevice";
this.btnDisposeDevice.Size = new System.Drawing.Size(104,
32);
this.btnDisposeDevice.TabIndex = 2;
this.btnDisposeDevice.Text = "Dispose Device";
this.btnDisposeDevice.Click += new
System.EventHandler(this.btnDisposeDevice_Click);
//
// txtOutput
//
this.txtOutput.Location = new System.Drawing.Point(8, 96);
this.txtOutput.Multiline = true;
this.txtOutput.Name = "txtOutput";
this.txtOutput.ScrollBars =
System.Windows.Forms.ScrollBars.Both;
this.txtOutput.Size = new System.Drawing.Size(656, 408);
this.txtOutput.TabIndex = 3;
this.txtOutput.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(672, 518);
this.Controls.Add(this.txtOutput);
this.Controls.Add(this.btnDisposeDevice);
this.Controls.Add(this.btnCreateDevice);
this.Controls.Add(this.btn_TestTimeSpan);
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.SizableToolWindow;
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
try
{
using (Form1 frm = new Form1())
{
frm.Show();
Application.Run(frm);
}
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show("Problem in
application, will now exit. " + e.Message);
}
}

private void CreateDevice()
{
PresentParameters presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.AutoDepthStencilFormat = DepthFormat.D16;
presentParams.EnableAutoDepthStencil = true;

device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
}
private void DisposeDevice()
{
device.Dispose();
}
public void TimeSpanProblem(string strFrom)
{
DateTime dt1970 = new DateTime(1970, 1, 1);
//LoadVC();
System.TimeSpan tss = DateTime.Now - dt1970;
uint nT11 = (uint)(tss.Ticks / TimeSpan.TicksPerSecond);
uint nT1 = (uint)tss.TotalSeconds;
uint nT2 = (uint)(tss.Ticks - (nT1 *
TimeSpan.TicksPerSecond));
string displayStr = "@@@@@@@@@"+strFrom+"@@@@@@@@@";
if (nT1 != nT11)
{
displayStr += Environment.NewLine +
"********************************************************"
+ Environment.NewLine + "PROBLEM!! T1 != T11 (NOTICE
THAT THE DECIMALS ARE GONE FOR TotalSeconds)"
+ Environment.NewLine +
"********************************************************";
}
else
{
displayStr += Environment.NewLine +
"********************************************************"
+ Environment.NewLine + "Everything OK!!"
+ Environment.NewLine +
"********************************************************";
}

displayStr+=
Environment.NewLine + "------TimeSpan---------"
+ Environment.NewLine + "tss.Ticks
=
{0}"
+ Environment.NewLine + "tss.TotalSeconds
=
{1}"
+ Environment.NewLine + "------My Variables---------"
+ Environment.NewLine + "T1 = (uint)tss.TotalSeconds
= {2}"
+ Environment.NewLine + "T2 = (uint)(tss.Ticks - (nT1
* TimeSpan.TicksPerSecond)) = {3}"
+ Environment.NewLine + "T11 = (uint)(tss.Ticks /
TimeSpan.TicksPerSecond) = {4}"
+ Environment.NewLine +
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"+Environment.NewLine
+Environment.NewLine+Environment.NewLine;

txtOutput.Text +=
String.Format(displayStr,tss.Ticks,tss.TotalSeconds,nT1,nT2,nT11);
txtOutput.Select(txtOutput.Text.Length-2,1);
txtOutput.ScrollToCaret();
}

private void btn_TestTimeSpan_Click(object sender,
System.EventArgs e)
{
this.TimeSpanProblem("From btn_TestTimeSpan_Click");
}

private void btnCreateDevice_Click(object sender,
System.EventArgs e)
{
CreateDevice();
}

private void btnDisposeDevice_Click(object sender,
System.EventArgs e)
{
DisposeDevice();
}

}
}

*****************************CODE
END**********************************



I can confirm the issue. The problem is with DirectX resetting the X87
control word, more precisely, the CLR initially sets the FPU to double
precision mode (FCW = 27Fh), however, when DX initializes, it switches the
FPU to single precision mode by resetting the FCW to 7Fh.
The result is that TotalSeconds returns a wrong value, as this routine
expects the FPU to be in double precision mode. The point is who to blame?
DX or the CLR? I would suggest you to do as Peter said, file a bug. In the
mean time I would stay away from the TimeSpan class and use the StopWatch
class.

Willy.




Willy.
 
Top