Archive for the ‘Operating Systems’ Category.

How read the 64 bit registry from a 32 bit application or vice versa

I found out that I needed to read the 64 bit registry from a 32 bit app today.
Why you might ask?
Well, I need to get the RegisteredOrganization value from HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion and unfortunately Microsoft has a bug where the WOW6432 version of this key always says Microsoft, so a 32 bit application would always return Microsoft as the RegisteredOrganization, regardless of what the user entered when they installed the OS. This is hardly desired.
Note: This is also why all Visual Studio projects created in Windows 7 64 bit have Microsoft in the project’s Assembly Information. Change the WOW6432 version of the RegisteredOrganization and you fix this Visual Studio issue.
Well, turns out C# doesn’t have functionality until .NET 4, so prior to .NET 4, to choose the 64 bit hive when running a 32 bit app, so we have to do use a DLLImport and use RegOpenKeyEx, RegCloseKey, and RegQueryValueEx.
I don’t have this well commented, and it is not very newbie proof, but here are three different ways to do this. Hopefully you can understand one or more of these.

Example 1 – .NET 4 Example

Here is how to do this in .NET 4.
using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = string.Empty;
            string value32 = string.Empty;

            RegistryKey localKey = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry64);
            localKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey != null)
            {
                value64 = localKey.GetValue("RegisteredOrganization").ToString();
            }
            RegistryKey localKey32 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, RegistryView.Registry32);
            localKey32 = localKey32.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey32 != null)
            {
                value32 = localKey32.GetValue("RegisteredOrganization").ToString();
            }
        }
    }
}

.NET 3.5 SP1 and Prior

This can also be done in .NET 3.5 and prior but it is not easy.
We have to do use a DLLImport and use RegOpenKeyEx, RegCloseKey, and RegQueryValueEx. Here are some examples.

Example 1 – A console application to read the 64 bit registry from a 32 bit application or vice versa

Here is the code in a simple one file project:
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            Console.WriteLine(value64);
            string value32 = GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            Console.WriteLine(value32);
        }

        public enum RegSAM
        {
            QueryValue = 0x0001,
            SetValue = 0x0002,
            CreateSubKey = 0x0004,
            EnumerateSubKeys = 0x0008,
            Notify = 0x0010,
            CreateLink = 0x0020,
            WOW64_32Key = 0x0200,
            WOW64_64Key = 0x0100,
            WOW64_Res = 0x0300,
            Read = 0x00020019,
            Write = 0x00020006,
            Execute = 0x00020019,
            AllAccess = 0x000f003f
        }

        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);

        #region Member Variables
        #region Read 64bit Reg from 32bit app
        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, string lpValueName,
            int lpReserved,
            ref uint lpType,
            System.Text.StringBuilder lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        static public string GetRegKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
        }

        static public string GetRegKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                uint lpType = 0;
                uint lpcbData = 1024;
                StringBuilder AgeBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
                string Age = AgeBuffer.ToString();
                return Age;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion
    }
}

Example 2 – A static class to read the 64 bit registry from a 32 bit application or vice versa

Or if you want this in its own separate class, here is a static class you can add to your project.
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    public enum RegSAM
    {
        QueryValue = 0x0001,
        SetValue = 0x0002,
        CreateSubKey = 0x0004,
        EnumerateSubKeys = 0x0008,
        Notify = 0x0010,
        CreateLink = 0x0020,
        WOW64_32Key = 0x0200,
        WOW64_64Key = 0x0100,
        WOW64_Res = 0x0300,
        Read = 0x00020019,
        Write = 0x00020006,
        Execute = 0x00020019,
        AllAccess = 0x000f003f
    }

    public static class RegHive
    {
        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);
    }

    public static class RegistryWOW6432
    {
        #region Member Variables
        #region Read 64bit Reg from 32bit app
        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, string lpValueName,
            int lpReserved,
            ref uint lpType,
            System.Text.StringBuilder lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        static public string GetRegKey64(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_64Key, inPropertyName);
        }

        static public string GetRegKey32(UIntPtr inHive, String inKeyName, String inPropertyName)
        {
            return GetRegKey64(inHive, inKeyName, RegSAM.WOW64_32Key, inPropertyName);
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(RegHive.HKEY_LOCAL_MACHINE, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                uint lpType = 0;
                uint lpcbData = 1024;
                StringBuilder AgeBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
                string Age = AgeBuffer.ToString();
                return Age;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion

        #region Enums
        #endregion
    }
}
Here is an example of using this class.
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = RegistryWOW6432.GetRegKey64(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
            string value32 = RegistryWOW6432.GetRegKey32(RegHive.HKEY_LOCAL_MACHINE, @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "RegisteredOrganization");
        }
    }
}

Example 3 – Adding extension methods to the managed RegistryKey object that read the 64 bit registry from a 32 bit application or vice versa

You know what else is a cool idea? Making it an extension class to the normal managed registry C# code. So you can create a regular managed RegistryKey and then just call an extension function off it.
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    /// <summary>
    /// An extension class to allow a registry key to allow it to get the
    /// registry in the 32 bit (Wow6432Node) or 64 bit regular registry key
    /// </summary>
    public static class RegistryWOW6432
    {
        #region Member Variables
        #region Read 64bit Reg from 32bit app
        public static UIntPtr HKEY_LOCAL_MACHINE = new UIntPtr(0x80000002u);
        public static UIntPtr HKEY_CURRENT_USER = new UIntPtr(0x80000001u);

        [DllImport("Advapi32.dll")]
        static extern uint RegOpenKeyEx(
            UIntPtr hKey,
            string lpSubKey,
            uint ulOptions,
            int samDesired,
            out int phkResult);

        [DllImport("Advapi32.dll")]
        static extern uint RegCloseKey(int hKey);

        [DllImport("advapi32.dll", EntryPoint = "RegQueryValueEx")]
        public static extern int RegQueryValueEx(
            int hKey, string lpValueName,
            int lpReserved,
            ref uint lpType,
            System.Text.StringBuilder lpData,
            ref uint lpcbData);
        #endregion
        #endregion

        #region Functions
        public static string GetRegKey64(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') +1);
            return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_64Key, inPropertyName);
        }

        public static string GetRegKey32(this RegistryKey inKey, String inPropertyName)
        {
            string strKey = inKey.ToString();
            string regHive = strKey.Split('\\')[0];
            string regPath = strKey.Substring(strKey.IndexOf('\\') + 1);
            return GetRegKey64(GetRegHiveFromString(regHive), regPath, RegSAM.WOW64_32Key, inPropertyName);
        }

        private static UIntPtr GetRegHiveFromString(string inString)
        {
            if (inString == "HKEY_LOCAL_MACHINE")
                return HKEY_LOCAL_MACHINE;
            if (inString == "HKEY_CURRENT_USER")
                return HKEY_CURRENT_USER;
            return UIntPtr.Zero;
        }

        static public string GetRegKey64(UIntPtr inHive, String inKeyName, RegSAM in32or64key, String inPropertyName)
        {
            //UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)0x80000002;
            int hkey = 0;

            try
            {
                uint lResult = RegOpenKeyEx(inHive, inKeyName, 0, (int)RegSAM.QueryValue | (int)in32or64key, out hkey);
                if (0 != lResult) return null;
                uint lpType = 0;
                uint lpcbData = 1024;
                StringBuilder AgeBuffer = new StringBuilder(1024);
                RegQueryValueEx(hkey, inPropertyName, 0, ref lpType, AgeBuffer, ref lpcbData);
                string Age = AgeBuffer.ToString();
                return Age;
            }
            finally
            {
                if (0 != hkey) RegCloseKey(hkey);
            }
        }
        #endregion

        #region Enums
        public enum RegSAM
        {
            QueryValue = 0x0001,
            SetValue = 0x0002,
            CreateSubKey = 0x0004,
            EnumerateSubKeys = 0x0008,
            Notify = 0x0010,
            CreateLink = 0x0020,
            WOW64_32Key = 0x0200,
            WOW64_64Key = 0x0100,
            WOW64_Res = 0x0300,
            Read = 0x00020019,
            Write = 0x00020006,
            Execute = 0x00020019,
            AllAccess = 0x000f003f
        }
        #endregion
    }
}
Here is an example of using these extension functions.
using System;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;

namespace Read64bitRegistryFrom32bitApp
{
    class Program
    {
        static void Main(string[] args)
        {
            string value64 = string.Empty;
            string value32 = string.Empty;
            RegistryKey localKey = Registry.LocalMachine;
            localKey = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
            if (localKey != null)
            {
                value32 = localKey.GetRegKey32("RegisteredOrganization");
                value64 = localKey.GetRegKey64("RegisteredOrganization");
            }
        }
    }
}
If anything is confusing please comment.
Resources:
  • RegOpenKeyEx Function – http://msdn.microsoft.com/en-us/library/ms724897%28v=VS.85%29.aspx
  • RegQueryValueEx Function – http://msdn.microsoft.com/en-us/library/ms724911%28VS.85%29.aspx
  • http://www.pinvoke.net/default.aspx/advapi32/RegQueryValueEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegOpenKeyEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegCreateKeyEx.html
  • http://www.pinvoke.net/default.aspx/advapi32/RegCloseKey.html
  • http://stackoverflow.com/questions/1470770/accessing-registry-using-net
  • http://connect.microsoft.com/VisualStudio/feedback/details/400597/registeredorganization-reg-key-on-x64-vista-7

Copyright ® Rhyous.com – Linking to this post is allowed without permission and as many as ten lines of this page can be used along with this link. Any other use of this page is allowed only by permission of Rhyous.com.

Russian Government going Open Source…and the future

Well, I have seen governments claim they are going to open source before, but not from Russia, and not with such a realistic plan to migrate over a few years.

Here is a link to the article via Google translate:

Putin ordered the transfer of power on Linux

The now

Business drives software development.  Open Source communities help, but even today much of the ongoing development for Linux is driven by businesses such as Red Hat and Novell and others.  If you think your Linux code is being written by unpaid developers in their spare time, you are somewhat correct but only partially.  Most changes are made by developers who are paid.

While communities are nice, they can’t match the hours or output of experienced developers working forty to sixty hours a week.

Looking Ahead…the Apps…and C# (Mono)

The more open source is used in business, the more development power it will have.  But it is not the open source Operatings Systems that prevent people from moving to Linux or BSD.  Ubuntu, SUSE, Fedora, CentOS, PC-BSD, and numerous others are all very usable desktops that are user friendly.  It is the software that runs on them that everyone is waiting for.

The market is already there to make millions extra if you application runs cross platform, one Windows, MAC, Linux, and BSD.

But most the applications written for Windows, the business desktop of today, are using .NET Framework. So naturally those companies are going to want to make their code cross platform.  And they are going to find it is easier than they thought to move their applications between platforms using C#.  I have recently decided that C# is the future of applications on all platforms.

Some MAC and Linux users don’t like Microsoft and will fight off the idea of a Microsoft provided development platform such as C# (Mono) on their systems.  But when a corporation decides that you must run software X, and software X requires .NET, and you have to either give up your MAC or Linux box for a Windows box, or use C# (Mono), then users will come around.

If you are a company writing software for Windows only today and using C#, you need to take a look at Mono. Even if the return on investment of developing a C# (Mono) based version of your product is a slight loss to break even, it is an investment in the future.  Once written, maintenance costs will be less than the original development costs and that slight loss to break even margin will turn to a small profit.  And with the experience, you next app will migrate to C# (Mono) that much easier and soon, all you apps will run anywhere that C# (Mono) can run.

This is going to take off in a way Java hasn’t because developers for windows prefer and will continue to prefer .NET over Java.  And when it comes to business apps, Java just isn’t the language of choice.  Business applications are written in C#.

Adding an alias in Windows 7 or making ls = dir in a command prompt

Hey all,

I don’t know about you but I switch between FreeBSD and Windows a lot.  So it drives me crazy when I type the command ls on windows and get the error message.

C:\Windows\system32>ls
‘ls’ is not recognized as an internal or external command,
operable program or batch file.

So I want this to go away.

I looked for the alias command in Windows and couldn’t find one.  So I made a batch file that solves this.

Windows doesn’t seem to have the equivalent of a .shrc or .cshrc or .bashrc. I couldn’t find a .profile either.  So I decided to go with the batch file route.

Creating a batch file as an alias

I created an .bat file that just forwards calls the original file and forwards all parameters passed when making the call.

Here is how it works.

Create a file called ls.bat. Add the following text.

ls.bat

@ECHO OFF
REM
REM Run a command with as many parameters as are passed.
REM This is used as a wrapper for any command.
REM It may also be used to alias a command.
REMREM Change this variable to equal the command you want to alias.
SET RealCMDPath=dir:getparams
SET cmdparams=%1
shift
:addparams
SET cmdparams=%cmdparams% %1
SHIFT
IF NOT %1.==. GOTO addparams

:runcmd
%RealCMDPath% %cmdparams%

Copy this batch file to your C:\Windows\System32 directory. Now you can type in ls on a windows box at the command prompt and it works.

How does this work to make your aliased command?

  1. Name the batch file the name of the alias.  I want to alias ls to dir, so my batch file is named ls.bat.
  2. In the batch file, set the RealCMDPath variable to the proper value, in my case it is dir.

So if you want to alias cp to copy, you do this:

  1. Copy the file and name it cp.bat.
  2. Edit the file and set this line:
    SET RealCMDPath=dir

Now you have an alias for both ls and cp.

Using different versions of msbuild.exe

You can also use this so you don’t have to add a path.

I need to use C:\Windows\Microsoft.NET\Framework\v3.5\msbuild.exe but sometimes I want to use C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe. Both files are named the same. So I can easily use my alias command.

  1. Create two files in C:\Windows\System32: one named msbuild35.bat and one named msbuild40.bat.
  2. Change the line in each file to have the appropriate paths for the RealCMDPath.

Anyway, this is really a useful batch file.