How to watch NTFS Symbolic links changes with FileSystemWatcher

FileSystemWatcher does not observes changes in symbolic links targets and only way how to do that is to follow them also.

First we set up main FileSystemWatcher:

static void Main(string[] args)
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = Environment.CurrentDirectory + "\\"+"Observed";
    watcher.IncludeSubdirectories = true;
    watcher.Created += new FileSystemEventHandler(watcher_Created);
    watcher.EnableRaisingEvents = true;


And second part is to watch newly created symbolic links

static void watcher_Created(object sender, FileSystemEventArgs e)
        Console.WriteLine("Created: " + e.FullPath);
        FileAttributes attributes = File.GetAttributes(e.FullPath);
// Now, check whether directory is Reparse point or symbolic link
        if (attributes == (FileAttributes.Directory | FileAttributes.ReparsePoint))

            FileSystemWatcher watcher = new FileSystemWatcher();

            string path = JunctionPoint.GetTarget(e.FullPath);
            watcher.Path = path;
            watcher.Created += new FileSystemEventHandler(watcher_Created);
            watcher.IncludeSubdirectories = true;
            watcher.EnableRaisingEvents = true;
    catch (Exception ex)



For finding target of Symbolic links is used JunctionPoint library, which basically uses pInvoke from links below. Note, that that library does not works without changes for sybolic links, because it works only with reparse points. Problem with that library is that works only with reparse points and symbolic links uses different structure REPARSE_DATA_BUFFER (an extra field Flags) and also does not identifies correctly symbolic link reparse tag returned from DeviceIoControl function.

In attached sample is corrected version.

Sample here:



DeviceIoControl Function

JunctionPoint library (changed)

How to change hard drive in Latitude D630

Recently I have decided to upgrade my internal hdd to faster one. In my Latitude D630 there is a SATA Mobile II controller.
I have decided for ST9200420ASG (200 GB). It has following parameters:
and more details can be found here:
  • Spindle Speed 7,200 rpm
  • Average latency 4.17 msec
  • Random read seek time 11.0 msec

  • Random write seek time 13.0 msec
Now, the list of steps for change the drive, I have undertaken:
  1. Backup all the drivers (especially for NIC, WLAN, ..) and personal data
  2. Create Vista installation Flash Disk Drive
  3. Take out the drive from Notebook
  4. Bring a new drive on place
  5. Install Windows Vista and all the settings for a comfortable manner.

More detailed description of steps up:

1. For the first time, I have forget to backup bluetooth device driver (Dell bluetooth 360) and therefore I cannot access Internet for download them. I had to change drives back and backup drives from installation before (I have used Driver Genius for that) and go to the new installation with new drivers.

2. I have found that installation of Vista OS is not possible from old Windows PE (1.0), and it is only possible from Windows PE 2.0 (Windows 2003 and Vista created Preinstallation Environment). While I had no energy to create new Win PE environment, I have luckily found an easy guide how to install Windows Vista from Flash which is for example here.

More details are shown on these pictures:


InvalidOperationException when serializing SqlParameter after moving from .NET 1.1 to 2.0

Today, I had an strange exception
‘System.InvalidOperationException’ occurred in System.Xml.dll on a code, what was working without troubles in old Framework 1.1:

SqlParameter[] cmdParams = new SqlParameter[1];
cmdParams[0] = new SqlParameter("@result", SqlDbType.Int, 0, ParameterDirection.ReturnValue, false, 0, 0, "", DataRowVersion.Current, 0);

StringWriter sw = new StringWriter();
XmlSerializer xser = new XmlSerializer(cmdParams.GetType());
xser.Serialize(sw, cmdParams); // <- Exception

The exception message was:
{"The type System.Data.SqlTypes.SqlInt32 may not be used in this context. To use System.Data.SqlTypes.SqlInt32 as a parameter, return type, or member of a class or struct, the parameter, return type, or member must be declared as type System.Data.SqlTypes.SqlInt32 (it cannot be object). Objects of type System.Data.SqlTypes.SqlInt32 may not be used in un-typed collections, such as ArrayLists."}

After simulating the problem in a different small project, I have discovered, that problem is caused by setting value parameter (last one in SqlParameter constructor I am using).
While, this is ReturnValue parameter, i can easy change the value (of type object) to null, and with this small change, everything works correctly and XmlSerialization is done properly.

Corrected code:

SqlParameter[] cmdParams = new SqlParameter[1];
cmdParams[0] = new SqlParameter("@result", SqlDbType.Int, 0, ParameterDirection.ReturnValue, false, 0, 0, "", DataRowVersion.Current, null);

StringWriter sw = new StringWriter();
XmlSerializer xser = new XmlSerializer(cmdParams.GetType());
xser.Serialize(sw, cmdParams);


Error in Guidance Automation Toolkit VS 2008 installation

In some of project in one of my C# solutions, I have run while clicking Calculate Code Metrics into an error message: An error occurred while calculating code metrics, while the build was successful and runtime behavior was allright.

Error message

What to do now ?. I have noticed that in Output window, there are some error messages also:

C:\…\Microsoft.CSharp.targets : warning MSB3042: A namespace or class definition was found within a conditional compilation directive in the file "XXX.cs". This may lead to an incorrect choice for the manifest resource name for resource "XXX.resx".

As the message says, I have found that construction that is preventing correct Code Metrics Calculation is ussage of conditional symbols before class (or namespaces).
Wrong code sample:

namespace TestingNamespace
// .. Working Code here

The next steps are now to remove conditional symbols and use some logic to do the same logic instead. After replacing all the symbols reported in error messages, everything is fine and Metrics are calculated correctly 🙂

I have found during my attempts to compute metrics, these important tips:
1. When Calculation of Metrics finishes with error message, it is good to do Code Analysis before. This will usually show you the exact place where the problem lies.
2. When you have strongly named assembly (signed with a key), it cannot be linked to another (not signed one) in Code Analysis and in Metrics Calculation.


Multiple Language for non-Unicode programs settings on one computer

Maybe you have the same problem. You have non-Unicode program, for example an old Visual Basic 6 application drives it’s Resources, data formats, ets by this important settings in your Control panels.
You probably know, that when you need to change this settings to a different language, you are asked to restart your computer.
Of course, if you work with different language specific applications, it is quite bothering to do that all the time.
Solution to do this is as following
1. Create a local computer user with Administrator rights, we can call him "RUUser"
(we will set Russian Locales)
2. Log off and Log in as newly created user (we have RUUser)
3. Go to control panels/Regional and Language Settings/Administrative/Change system locale and change your locales to language you need. (We can try Russian for example)
4. You will probably need to do restart, do it this time
5. Now login as your original user and set your Regional Settings back to your default language, you will need to restart another time.
6. That is all
What do we have now ? We have a new user (RUUser in our example), who has his locales set to Russian. You can continue working with your default user and Locales (lets say English). When we need to start an non-unicode application, you will need to start it under your user with different Locales.
There is a simple command in Windows, how to do that easily. Syntax is:
runas /savecred /user:domain\user your_command.exe
After this command starts. You will be asked for password for this user. (Oh I didn’t adwised you to do that ?) And the password will be saved in credential cache persistently on your computer, so, next time, when you start this command, you wont be asked for password.
if you need more application under different Locales, you can create more users, set them Locales the same way.

How to change users Environment variables persistenty without UI

Hallo, are you also borried with all the changes of your User variables or System variables in:

Computer > Properties > Advanced System settings > System Properties > Advanced > Environment variables

Here is how it looks like in UI

Less known receipt how to do that is to use setx command line:

setx variable_name variable_content

for example:

setx Hello World


which sets Hello variable to World string.

Immediatelly, you can check how it looks now in Environment Variables dialog:

And you will see there a new wanted value 🙂

Good luck