Daniel Vasquez Lopez

Wednesday, March 31, 2004

The action being performed on this control is being called from the wrong thread.

"The action being performed on this control is being called from the wrong thread. You must marshal to the correct thread using Control.Invoke or Control.BeginInvoke to perform this action."
What does that Exception mean?
Window Forms Controls were not designed to be thread-safe. To be sure of that, check the member property Control.InvokeRequired of any control like the System.Windows.Forms.TreeView. If it is true, then you require to call the control from the thread where it was created by using Control.Invoke.
You will need to use
delegates. The following code declares a delegate that is used to marshal the call to the main thread:

private delegate void GeneralDelegate(object state);
private GeneralDelegate invoker;
private void MethodRunningInMainThread(object state)
{
treeView1.Nodes.Add(new TreeNode((string)state));
}
private void EventHandlerRunningInOtherThread(object sender, System.EventArgs e)
{
invoker = new GeneralDelegate(MethodRunningInMainThread);
treeView1.Invoke(invoker, new object[]{"Some Text"});
}

Instead of using the TreeView control in the EventHandlerRunningInOtherThread method, it creates a delegate (that could be created in the class contructor once) and calls the TreeView.Invoke method in order to marshal the values requiered ("Some Text") in the MethodRunningInMainThread method by the TreeView control.

Enabling XP Visual Style in Windows Forms

Back to the .NET Framework version 1.0, the requirement to enable Windows XP Visual Style in a Windows Forms Application was a little dull, adding a xml manifest file into the application resources (opening the assembly from VS.NET). Now in .NET Framework version 1.1, you just need to call the static method Application.EnableVisualStyles just before calling the method Application.Run in your Main method:

static void Main()
{
Application.EnableVisualStyles();
Application.Run(new frmMainForm());
}


You also need to change the standard flat sytle of all the Button controls in your form to FlatSytle.System:
btnSubmit.FlatStyle = System.Windows.Forms.FlatStyle.System;

Of course, you need any Windows XP version or above.

Tuesday, March 30, 2004

Marshal.SizeOf returns 1 for System.Char

As you might know, in .NET all strings are Unicode, because of that, the size of a System.Char type must be 2 bytes. When you try to get the size in bytes of a System.Char using the Marshal.SizeOf method, you will find that it return 1 instead of 2.
This is not a bug, Marshal.SizeOf was made for unmanaged types, not for managed types as System.Char. Marshal.SizeOf gets the size of the System.Char type declared in the mscorlib assembly, if you check its declaration using the "Lutz Roeder's .NET Reflector" you will notice that the System.Char type has the following modifiers:

Modifiers: Serializable BeforeFieldInit Ansi Auto

By this reason, the size of any Ansi character is 1. In order to get size of a character, you should use the value of Marshal.SystemDefaultCharSize.

How to recursively search a subdirectory or a file in a given directory

The question is a little tricky, because we immediately think about write a recursive method, but there are some issues that you might want to considerate; Think about the Call Stack, what if the directory is too deep, enough to run into a StackOverflowException exception, or simple as you are paying a performance penalty.

Instead, try to use a Stack to remember the directories to look up:

sealed class App {
static void Main() {
StringCollection results = FindDirectory("c:\\Development", "compressionsink.dll", "*");
foreach(string value in results)
Console.WriteLine(value);
}
public StringCollection FindDirectory(string root, string value, string searchPattern)
{
StringCollection results = new StringCollection();
Stack stack = new Stack();
stack.Push(root);
while(stack.Count > 0) {
string currentDir = stack.Pop().ToString();
if(0 == string.Compare(Path.GetFileName(currentDir), value, true, CultureInfo.InvariantCulture)) {
results.Add(currentDir);
}
foreach(string path in Directory.GetFiles(currentDir, searchPattern)) {
string ok = Path.GetFileName(path);
if(0 == string.Compare(ok, value, true, CultureInfo.InvariantCulture)) {
results.Add(path);
}
}
foreach(string dir in Directory.GetDirectories(currentDir)) {
stack.Push(dir);
}
}
return results;
}
}

Check if a local account is enabled or disabled in .NET

DirectoryEntry de = new DirectoryEntry("WinNT:///");
int value = Convert.ToInt32(de.Properties["UserFlags"][0]);
if((value & 0x002) == 0)
Console.WriteLine("This account is enabled.");

If is an AD Account, check the property userAccountControl instead.

Win32Exception class forgotten

It’s very common to see people (and books) declaring the FormatMessage Win32 API function in .NET in order to get the message of the Last Win32 Error Code.
In .NET, if you want to get the message error of the error code returned by the last unmanaged function called using Platform Invoke, use:

String message = (new System.ComponentModel.Win32Exception()).Message;

Instead of P/Invoke the FormatMessage Win32 API function, like:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
static extern int FormatMessage(int dwFlags,ref IntPtr lpSource,
int dwMessageId,int dwLanguageId,ref String lpBuffer,int nSize,
IntPtr Arguments)


Even the Microsoft Configuration Management Application Block for .NET (http://msdn.microsoft.com/library/en-us/dnbda/html/cmab.asp) declares FormatMessage in its DataProtection class and uses the following code instead of writing a simple line (new Win32Exception()).Message :

private static String GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr ptrlpSource = new IntPtr();
IntPtr prtArguments = new IntPtr();
int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref lpMsgBuf, messageSize, IntPtr.Zero );
if(0 == retVal)
{
throw new Exception( Resource.ResourceManager[ "Res_ExceptionFormattingMessage", errorCode ] );
}
return lpMsgBuf;
}