Accessing a 64 bit WMI provider from a 32 bit application running on a 64 bit client

Ordinarily, if you create a 64 bit WMI provider to run on a server, you will create a corresponding 32 bit provider as well. In some instances, only a 64 bit WMI provider exists. This creates an interesting dilemma. Consider the scenario where a 32 bit exe running in WOW64 on a 64 bit client is attempting to request instances from the 64 bit provider on the 64 bit server. The server will return a WBEM_E_INVALID_CLASS error back to the client. This is because WMI on the 64 bit server assumes that the 32 bit application is requesting an instance provided by a 32 bit provider on the server. Since there is no 32 bit provider for the class on the 64 bit server, the WBEM_E_INVALID_CLASS error will be returned.

 

WMI provides a way to avoid this error by allowing the client to provide some context information to the a WMI object instance execution method. The following link provides more detail on how WMI can be used to communicate between the two different architectures.

 

    msdn.microsoft.com/en-us/library/aa393067(VS.85).aspx

 

How about a more practical example. Let’s suppose you have a 64 bit exchange server and you are interested in retrieving information on the Win32_PerfRawData_EXOLEDB_MSEchangeWebMail counter. This counter is only available from the 64 bit provider running on the 64 bit exchange server. You need to support 32 bit as well as 64 bit architectures from a single code base. These applications could be installed on either 64 or 32 bit clients. You decide to write a single 32 bit C# exe to access the counter. The question is, how can you apply the information provided in the link above in your C# code?

 

Below is a simple C# application that illustrates how to setup a context object to request counter information from the 64 bit provider on the exchange server. If you create a C# console application, you can replace the main method contents with the main method contents below. Be sure to add the System.Management namespace to the references for the project and include the “using System.Management;” in the using namespaces section.

 

 

     using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Management;
     
    namespace _32exeon64to64
    {
        class Program
        {
            static void Main(string[] args)
            {
                //
                // First, setup the context information to request the 64 bit architecture
                // and require the 64 bit provider as described in the MSDN link
                //msdn.microsoft.com/en-us/library/aa393067(VS.85).aspx
                //
                ManagementNamedValueCollection mContext = new ManagementNamedValueCollection();
                mContext.Add( "__ProviderArchitecture", 64);
                mContext.Add( "__RequiredArchitecture", true);
                //
                // Second, setup create a connectionOption structure with the
                // credentials for the connection.  In this example, the user ID
                // and password are hardcoded.  There are a number of ways this information
                // can be encrypted and stored so that is it not easily hacked from the binary.
                //
                ConnectionOptions co = new ConnectionOptions();
                co.Username = @"myserver\administrator";
                co.Password = @"AdminPassword";
                //
                // Add our context object to the connection options.
                //
                co.Context = mContext;
                //
                // Create a management scope and then connect to the remote
                // machine.
                //
                ManagementScope ms = new ManagementScope(@"\\ExchangeServer\root\CIMV2", co);
                ms.Connect();
                //
                // Create a query object, associate it with a searcher object and our management scope…
                //
                ObjectQuery oq = new ObjectQuery("SELECT * FROM Win32_PerfRawData_EXOLEDB_MSExchangeWebMail");
                ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(ms, oq);
                //
                // Execute the query.
                //
                ManagementObjectCollection oReturnCollection = oSearcher.Get();
                //
                // Loop through the counters.
                //
                foreach (ManagementObject oReturn in oReturnCollection)
                {
                    //
                    //  display the Counter name 
                    //
                    Console.WriteLine("Name : " + oReturn["Name"].ToString());
                } 
            }
        }
    }