Sun
Mar 25
2007

Formatting File Sizes

In Windows Explorer file sizes are displayed in two different formats. In the Properties page, file sizes are displayed in bytes, KB, MB, GB or TB depending on the size. The StrFormatByteSize() Win32 API can reproduce this format. The second format is used under the “Size” column when viewing a folder. File sizes are displayed in whole KB with thousands separators. I have not found a API call to reproduce this format. The StrFormatKBSize() function is close but differs (it displays two decimal places).

Here are two pure C# functions to reproduce these formats:

/// <summary>
/// Converts a number value into a string that represents the number 
/// expressed in whole kilobytes. This is a format similar to the 
///	Windows Explorer "Size" column.
/// </summary>
public static string FileSizeToStringKB(long fileSize)
{
	return string.Format("{0:n0} KB", Math.Ceiling((double)fileSize / 1024));
}
 
 
/// <summary>
/// Converts a numeric value into a string that represents the number 
///	expressed as a size value in bytes, kilobytes, megabytes, gigabytes, 
///	or terabytes depending on the size. Output is identical to 
///	StrFormatByteSize() in shlwapi.dll. This is a format similar to 
/// the Windows Explorer file Properties page. For example:
///	     532 ->  532 bytes
///     1240 -> 1.21 KB
///	  235606 ->  230 KB
///  5400016 -> 5.14 MB
/// </summary>
/// <remarks>
///	It was surprisingly difficult to emulate the StrFormatByteSize() function
/// due to a few quirks. First, the function only displays three digits:
///  - displays 2 decimal places for values under 10	(e.g. 2.12 KB)
///  - displays 1 decimal place for values under 100	(e.g. 88.2 KB)
///	 - displays 0 decimal places for values under 1000	(e.g. 532 KB)
///	 - jumps to the next unit of measure for values over 1000  (e.g. 0.97 MB)
/// The second quirk: insiginificant digits are truncated rather than 
/// rounded. The original function likely uses integer math.
/// This implementation was tested to 100 TB.
/// </remarks>
public static string FileSizeToString(long fileSize)
{
	double value;
	string unit;
 
	if (fileSize < 1024)
	{
		return string.Format("{0} bytes", fileSize);
	}
	else 
	{
		value = fileSize;
		value = value / 1024;
		unit = "KB";
		if (value >= 1000)
		{
			value = Math.Floor( value );
			value = value / 1024;
			unit = "MB";
		}
		if (value >= 1000)
		{
			value = Math.Floor( value );
			value = value / 1024;
			unit = "GB";
		}
		if (value >= 1000)
		{			value = Math.Floor( value );
			value = value / 1024;
			unit = "TB";
		}
 
		if (value < 10)
		{
			value = Math.Floor( value * 100 ) / 100;
			return string.Format("{0:f2} {1}", value, unit);
		}
		else if (value < 100)
		{
			value = Math.Floor( value * 10) / 10;
			return string.Format("{0:f1} {1}", value, unit);
		}
		else
		{
			value = Math.Floor( value * 1) / 1;
			return string.Format("{0:f0} {1}", value, unit);
		}
	}
}
Fri
Jan 19
2007

CLR Debugging

To get started with debugging the CLR see Tess Ferrandez’s post on getting .NET memory dumps and Associating Windbg with .dmp files. See her other posts for mining these dumps for useful information.

To debug ASP.Net worker process crashes, create a batch file named debug_crash_iis5.bat in windbg folder with:
cscript.exe adplus.vbs -crash -pn aspnet_wp.exe -FullOnFirst

To dump (non-crashing) exceptions from ASP.Net, create a batch file named debug_monitor_iis5.bat with:
cscript.exe adplus.vbs -pn aspnet_wp.exe -c TrackCLR.cfg

and another file named TrackCLR.cfg with:

<ADPLUS>
  <SETTINGS>
   <RUNMODE>CRASH</RUNMODE>
  </SETTINGS>
  <PRECOMMANDS>
   <CMD>!load clr10\sos</CMD>
  </PRECOMMANDS>
  <EXCEPTIONS>
   <OPTION>NoDumpOnFirstChance</OPTION>
   <OPTION>NoDumpOnSecondChance</OPTION>
   <CONFIG><!-- This is for the CLR exception -->
    <CODE>clr</CODE>
    <ACTIONS1>Log</ACTIONS1>
    <CUSTOMACTIONS1>!cen;!clrstack;.dump /ma /u c:\exceptiondump.dmp;gn </CUSTOMACTIONS1>
    <RETURNACTION1>GN</RETURNACTION1>
   </CONFIG>
  </EXCEPTIONS>
</ADPLUS>

After opening a .dmp file with windbg, the most useful commands are:
!clrstack
!dae
!help

Tue
Jan 16
2007

Recompile All Oracle Objects

exec dbms_utility.compile_schema(schema => 'MYSCHEMA', compile_all => FALSE);

          
Thu
Jan 11
2007

Catching Unhandled ASP.Net Exceptions

Exceptions that occur off the worker process thread are silently swallowed by ASP.NET 1.1. Use the method described in MS article 911816 to create an HttpModule to catch the exceptions. The follow is adapted for ASP.NET 1.1 without requiring registration in the GAC and a strong name. It also logs to the EventLog as well as sending an email as

Add the following code to UnhandledExceptionModule.cs:

using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Web;
 
namespace WebMonitor {
    public class UnhandledExceptionModule: IHttpModule {
 
        static int _unhandledExceptionCount = 0;
 
        static string _sourceName = null;
        static object _initLock = new object();
        static bool _initialized = false;
        static string _mailServer = "mymailserver";
        static string _mailTo = "abc@xyz.com";
 
        public void Init(HttpApplication app) {
 
            // Do this one time for each AppDomain.
            if (!_initialized) {
                lock (_initLock) {
                    if (!_initialized) { 
 
                        _sourceName = string.Format(CultureInfo.InvariantCulture, "ASP.NET {0}.{1}.{2}.0",
							System.Environment.Version.Major, 
							System.Environment.Version.Minor,
							System.Environment.Version.Build);
 
                        if (!EventLog.SourceExists(_sourceName)) {
                            throw new Exception(String.Format(CultureInfo.InvariantCulture,
                                                              "There is no EventLog source named '{0}'.", 
                                                              _sourceName));
                        }
 
                        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException);
 
                        _initialized = true;
 
						LogMessage("UnhandledExceptionModule started", "", EventLogEntryType.Information);
 
                    }
                }
            }
        }
 
        public void Dispose() {
        }
 
        void OnUnhandledException(object o, UnhandledExceptionEventArgs e) {
            // Let this occur one time for each AppDomain.
            if (Interlocked.Exchange(ref _unhandledExceptionCount, 1) != 0)
                return;
 
            StringBuilder message = new StringBuilder("\r\n\r\nUnhandledException logged by UnhandledExceptionModule.dll:\r\n\r\nappId=");
 
            string appId = (string) AppDomain.CurrentDomain.GetData(".appId");
            if (appId != null) {
                message.Append(appId);
            }
 
            Exception currentException = null;
            for (currentException = (Exception)e.ExceptionObject; currentException != null; currentException = currentException.InnerException) {
                message.AppendFormat("\r\n\r\ntype={0}\r\n\r\nmessage={1}\r\n\r\nstack=\r\n{2}\r\n\r\n",
                                     currentException.GetType().FullName, 
                                     currentException.Message,
                                     currentException.StackTrace);
            }           
 
			LogMessage("UnhandledExceptionModule exception", message.ToString(), EventLogEntryType.Error);
        }
 
		void LogMessage(string subject, string message, EventLogEntryType severity)
		{
			try
			{
				EventLog Log = new EventLog();
				Log.Source = _sourceName;
				Log.WriteEntry(subject + "\n" + message, severity);
			}
			catch  {}
			try
			{
				System.Web.Mail.MailMessage msg = new System.Web.Mail.MailMessage();
				msg.Body = message;
				msg.To = _mailTo;
				msg.Subject = severity.ToString() + ": " + subject;
				msg.From = _mailTo;
 
				System.Web.Mail.SmtpMail.SmtpServer = _mailServer;
				System.Web.Mail.SmtpMail.Send(msg);
			}
			catch {}
		}
 
    }
}

Open a Visual Studio Command Prompt and run: csc /t:library /r:system.web.dll,system.dll UnhandledExceptionModule.cs

Place the DLL in your bin folder

Add following to your web.config:

<system.web>
  <httpModules>
    <add type="WebMonitor.UnhandledExceptionModule, UnhandledExceptionModule" name="UnhandledExceptionModule"/>
  </httpModules>
</system.web>

Here is sample code to trigger an unhandled exception

using System.Threading;
Timer t;
private void btnTest_Click(object sender, System.EventArgs e)
{
  t = new Timer(new TimerCallback(t_Elapsed), null, 250, Timeout.Infinite);
}
private void t_Elapsed(object state)
{
  throw new Exception("My unhandled exception");
}
Thu
Jan 4
2007

Could not load type ‘Namespace.Global’ with Network share

This occurs when running an ASP.Net website located on a network share. Configure .Net to trust assemblies from the network share. Solution from heromull.

1. Open .Net Framework 1.1 Configuration
2. Runtime security policy > machine > code groups > all_code
3. Right-click and create new.
4. Enter any name, URL, \\myserver\share\optionalfolder\* (note the * is important)
5. Restart IIS

Wed
Jan 3
2007

VSS Best Practices

Team Development with Visual Studio .NET and Visual SourceSafe

Sat
Dec 30
2006

Disable Infragistics WebGrid

To simulate a disabled grid:

Grid.Bands(0).RowStyle.BackColor = Color.LightGray
Grid.Bands(0).RowStyle.ForeColor = Color.DarkGray
Grid.Bands(0).RowAlternateStyle = Grid.Bands(0).RowStyle
Grid.Bands(0).SelectedRowStyle = Grid.Bands(0).RowStyle
Grid.Bands(0).HeaderStyle.ForeColor = Color.DarkGray
Grid.BackColor = Color.LightGray
Grid.DisplayLayout.ClientSideEvents.BeforeSelectChangeHandler = "Grid_BeforeSelectChange"
Grid.DisplayLayout.ClientSideEvents.BeforeRowActivateHandler = "Grid_BeforeRowActivate"

Add to aspx:

  <script language="javascript">
    // Prevent the user from changing the currently active row
    function Grid_BeforeRowActivate(gridName, id)
    {
        igtbl_cancelPostBack(gridName);
        return 1;
    }
    // Prevent the user from changing the currently selected row
    function Grid_BeforeSelectChange(gridName, id)
    {
        igtbl_cancelPostBack(gridName);
        return 1;
    }
    </script>

To restore:

Grid.Bands(0).RowStyle = Grid.DisplayLayout.RowStyleDefault
Grid.Bands(0).RowAlternateStyle = Grid.DisplayLayout.RowAlternateStyleDefault
Grid.Bands(0).SelectedRowStyle = Grid.DisplayLayout.SelectedRowStyleDefault
Grid.Bands(0).HeaderStyle = Grid.DisplayLayout.HeaderStyleDefault
Grid.BackColor = Color.Transparent
Grid.DisplayLayout.ClientSideEvents.BeforeSelectChangeHandler = ""
Grid.DisplayLayout.ClientSideEvents.BeforeRowActivateHandler = ""
Tue
Nov 14
2006

IE Quick Search

With this tweak you can search Google by type “g searchterms” into the IE address bar. Other shortcuts: gg (Google Groups), ggd (Google Groupe limited to dotnet newgroups), mskb (Microsoft Knowledgebase), wiki (Wikipedia). Save this to a .reg file and double-click.

REGEDIT4

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl]
“provider”=”"

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl\g]
@=”http://www.google.com/search?q=%s”
” “=”+”
“#”=”%23″
“&”=”%26″
“?”=”%3F”
“+”=”%2B”
“=”=”%3D”

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl\gg]
@=”http://groups.google.com/groups?q=%s”
” “=”+”
“#”=”%23″
“&”=”%26″
“?”=”%3F”
“+”=”%2B”
“=”=”%3D”

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl\ggd]
@=”http://groups.google.com/groups?q=%s&as_ugroup=*dotnet*”
” “=”+”
“#”=”%23″
“&”=”%26″
“?”=”%3F”
“+”=”%2B”
“=”=”%3D”

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl\kb]
@=”http://support.microsoft.com/default.aspx?scid=kb;EN-US;%s”
” “=”+”
“#”=”%23″
“&”=”%26″
“?”=”%3F”
“+”=”%2B”
“=”=”%3D”

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl\mskb]
@=”http://support.microsoft.com/default.aspx?scid=kb;EN-US;%s”
” “=”+”
“#”=”%23″
“&”=”%26″
“?”=”%3F”
“+”=”%2B”
“=”=”%3D”

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl\ms]
@=”http://support.microsoft.com/search/default.aspx?Query=%s&KeywordType=ALL&maxResults=150″
” “=”+”
“#”=”%23″
“&”=”%26″
“?”=”%3F”
“+”=”%2B”
“=”=”%3D”

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchUrl\wiki]
@=”http://en.wikipedia.org/wiki/Special:Search?search=%s&go=Go”
” “=”+”
“#”=”%23″
“&”=”%26″
“?”=”%3F”
“+”=”%2B”
“=”=”%3D”

Fri
Oct 27
2006

Redirect Tracing to a File

<system.diagnostics> 
	<trace autoflush="true" indentsize="4"> 
			<listeners> n
			<add 	name="FileListener" 
				type="System.Diagnostics.TextWriterTraceListener" 
				initializeData="TraceLog2.txt" /> 
		</listeners> 
	</trace> 
</system.diagnostics>
Wed
Oct 25
2006

Detect Password Expiry

See the original Usenet posting.

public static DateTime PasswordExpirationDate(string user, string domain)
{
	string connect = String.Format("WinNT://{0}/{1},user", domain, user);
	DirectoryEntry entry = new DirectoryEntry(connect);
 
	if (entry == null)
		Console.WriteLine("Failed to get Directory Entry.");
 
	int secondsRemaining = (int)entry.Properties["MaxPasswordAge"][0];
 
	// A policy setting of -1 means no expiration,
	// so return an 'infinite' date
	if (secondsRemaining > 0) 
	{
		secondsRemaining -= (int)entry.Properties["PasswordAge"][0];
		return DateTime.Now.AddSeconds(secondsRemaining);
	} 
	else 
	{ 
		return DateTime.MaxValue; 
	}
}

« Newer PostsOlder Posts »

© 2009 Brian Low. All rights reserved.