Saturday, June 5, 2010

Migrating custom assemblies to SharePoint 2010

Introduction

Migrating to SharePoint 2010 requires several operations, you have to upgrade your existing SharePoint Farm at least with SharePoint SP2 if you attempt to perform an attach database migration and maybe move your Farms to support 64-bit if you have chosen an In place migration. Afterwards, you have to deal with  redeploying customizations and solutions in SharePoint 2010.

Although customizations for SharePoint come in many forms (Site templates , Site definition, Feature, Workflows and server controls, Event handler, Web Parts, Master pages and CSS files, etc.) I would like to focus now on the compiled code.
There were many questions I have read on Forums and Blogs about "Do we have to recompile or rewrite the code for a migration to SharePoint 2010 ?".

Architects, Developers, System Administrators benefits (the "why" part of the post)

This post will try to explain some important concepts to know when preparing to migrate your SharePoint custom dll to SharePoint 2010. We will examine:

  • The different platform available in Visual Studio build configuration and their impact on the migration
  • The x86 emulator WOW64 and its use with IIS 7 ie for both ASP .Net and SharePoint 2010
  • The tools you could use to facilitate the dll migration to SharePoint 2010

I will illustrate all these points by testing the migration of a custom Web Part to SharePoint 2010. 

1 -The different target platforms available in Visual Studio build configuration

I have prepared the Web Part component to migrate to SharePoint 2010 within Visual Studio 2008 and before to focus on the code let us examine the different options we have to compile it regarding the target platform.

here is the screenshot of Visual Studio 2008 showing three available options regarding target platform after having configured Visual Studio with the Configuration Manager, and the created corresponding debug folders. (I have omited Itanium on purpose because it is just a variation for a 64-bit platform).

You notice that the present configuration offers three options:

  1. X86: The package can be installed on any 32-bit platform; when installing to a 64-bit platform, files are installed to 32-bit folders.
  2. x64: The package is for machines supporting the AMD64 and EM64T instruction sets; when attempting to install to a 32-bit platform or any other 64-bit platform, an error is raised and installation is halted.
  3. Any CPU: compiles your assembly to run on any platform. It is the default option

sources : TargetPlatform Property, Output Platform

Conclusion, there is just ONE limitation : you cannot run a 64-bit package on a 32-bit platform but in our case we could imagine to build our component for any target platform and be allowed to deploy it for SharePoint 2010.
We will see later that it is actually true for a standard ASP .Net Web Site, but that we can use ONLY x64 and Any CPU option for SharePoint 2010, and I will clearly demonstrate and explain why.

But, first of all, let us compile our component and examine the ways of knowing what is its target platform afterward.

2 - How to know the target platform of an .Net assembly (managed code dll)

Dll deployed in the Global Assembly Cache 

Assume I have signed my assembly to deploy it in the Global Assembly Cache. If I open the Global Assembly Cache repository, I notice that the deployed Web Part was compiled for targeting 32-bit architecture, and that most of the other dll were compiled using the "Any CPU" option because they have the attribute "MSIL".

But what if the dll is not deployed in the GAC, and I want to know if it was compiled using te x86,  x64 or Any CPU option?

Dll deployed in the standard folders

You have two solutions:

- ILDASM utility

you can run the ILDASM utility provided in the .NET Framework SDK and located at:

C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin

Run the utility and open the dll file you want to check.

Then you have to do 2 operations.
First double click the manifest and check information after the "corflags" label.

Second click the Header item in the View menu

And in the headers locate the label PE Optional Header

Now, if we map these two information to the target platform:

For a dll compiled with Any CPU you will have :

.corflags 0x00000009 // ILONLY
 ----- PE Optional Header (32-bit):

For a dll compiled with x86 you will have :

.corflags 0x0000000b    //  ILONLY 32BITREQUIRED
 ----- PE Optional Header (32-bit):

For a dll compiled with x64 you will have :

.corflags 0x00000009    //  ILONLY
 ----- PE Optional Header (64-bit):

The corflags is also a name for a Visual Sutdio tool that can give us all the information in one place. This is our second solution to check the compilation mode without dropping the dll in the GAC.

- corflags utility

Open the a Visual Studio command promt.

then call the corflags.exe and pass it the dll as a parameter. (tip: you can drag and drop the dll in the command prompt windows)

So, now check the following parameters: PE and 32BIT

For a dll compiled with Any CPU you will have :

PE : PE32
32BIT : 0

For a dll compiled with x86 you will have :

PE : PE32
32BIT : 1

For a dll compiled with x64 you will have :

PE : PE32+
32BIT : 0

Getting the information from the running dll!

Now, maybe you are thinking, it would be great to execute the dll and that it gives us this information. That way, I can have all my SharePoint webparts telling me their target platform. And furthermore, if the Web Part could also tell me the process used, I could migrate my webparts to a 64-bit platform or straight to SharePoint 2010 step by step and know the migration status for each webpart at each step of my migration.

That is exactly what we are doing now, and as you notice, I have named my Web Part IsRunningon64-bit, and this Web part is aimed to give us this information and its target platform. So here is the code.

 

using System;

using System.Runtime.InteropServices;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Serialization;

using Microsoft.SharePoint;

using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.WebPartPages;

using System.Diagnostics;

using System.ComponentModel;

using System.Reflection;

 

namespace IsRunningOn64bit

{

 

    [Guid("5aa223b6-fd04-48c1-83e6-9531bf45ee08")]

    public class GetInformation : System.Web.UI.WebControls.WebParts.WebPart

    {     

 

        string _message = string.Empty;

 

        //This will fail under Win2000 and WinXP SP1 and earlier.

        //You need to check if the IsWow64Process() function exists before you call it,

        //because it was only introduced in XP SP2 and Vista/Win7

        [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]

        [return: MarshalAs(UnmanagedType.Bool)]

        public static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool lpSystemInfo);

 

        private string ProcessSize()

        {

            switch (IntPtr.Size)

            {

                case 4:

                    return "running on 32-bit";

                case 8:

                    return "running on 64-bit";

                default:

                    return "unknown";

            }

        }

 

        private string Wow64Using()

        {

            bool retVal;

            IsWow64Process(Process.GetCurrentProcess().Handle, out retVal);

            if (retVal)

            {

                return "using WOW64";

            }

            else

            {

                return "NOT using WOW64";

            }

        }

 

        public string Message

        {

            get

            {

                System.Reflection.PortableExecutableKinds PeKinds;

                System.Reflection.ImageFileMachine ImFileMach;

 

                Assembly myAssembly = Assembly.GetExecutingAssembly();

 

                myAssembly.ManifestModule.GetPEKind(out PeKinds, out ImFileMach);

 

                string strPeKinds = string.Empty;

                string strImFileMach = string.Empty;

 

                switch (PeKinds)

                {

                    case PortableExecutableKinds.ILOnly:

                        strPeKinds = PeKinds + ": The executable contains only Microsoft intermediate language (MSIL), and is therefore neutral with respect to 32-bit or 64-bit platforms. (compiled with Any CPU option)";

                        break;

                    case PortableExecutableKinds.NotAPortableExecutableImage:

                        strPeKinds = PeKinds + ": The file is not in portable executable (PE) file format.";

                        break;

                    case PortableExecutableKinds.PE32Plus:

                        strPeKinds = PeKinds.ToString() + "The executable requires a 64-bit platform. (compiled with x64 option)";

                        break;

                    case PortableExecutableKinds.Required32Bit:

                        strPeKinds = PeKinds + "The executable can be run on a 32-bit platform, or in the 32-bit Windows on Windows (WOW) environment on a 64-bit platform.";

                        break;

                    case PortableExecutableKinds.Unmanaged32Bit:

                        strPeKinds = PeKinds + "The executable contains pure unmanaged code.";

                        break;

                    default:

                        strPeKinds = PeKinds.ToString();

                        break;

                }

 

                switch (ImFileMach)

                {

                    case ImageFileMachine.AMD64:

                        strImFileMach = ImFileMach + ": Targets a 64-bit AMD processor.";

                        break;

                    case ImageFileMachine.I386:

                        strImFileMach = ImFileMach + ": Targets a 32-bit Intel processor.";

                        break;

                    case ImageFileMachine.IA64:

                        strImFileMach = ImFileMach + ": Targets a 64-bit Intel processor.";

                        break;

                    default:

                        strImFileMach = ImFileMach.ToString();

                        break;

                }

 

                _message += "<br>" + myAssembly.FullName;

                _message += "<br>" + strPeKinds;

                _message += "<br>" + strImFileMach;

 

                _message += "<br>" + ProcessSize();

                _message += "<br>" + Wow64Using();

 

                return _message;

            }

        }

 

        protected override void CreateChildControls()

        {

            base.CreateChildControls();

            Label label = new Label();

            string message = "";

 

            SPWeb myWeb = SPContext.Current.Web;

 

            message += "Web Site Title: " + myWeb.Title;

            message += this.Message;

 

            label.Text = message;

 

            this.Controls.Add(label);

        }

 

    }

}

 

And here is the result:

As you notice, the Web Part is telling us that it is running on a 32-bit process and that it was targeting for a 32-bit architecture. But what is WOW64 and how to know if the server where the Web part is running has a 32-bit or 64-bit architecture? That is we will explain now before migrating to a 64-bit server.

3 - The x86 emulator WOW64

As we found in Microsoft documentation, WOW64 is the x86 emulator that allows 32-bit Windows-based applications to run seamlessly on 64-bit Windows. WOW64 is provided with the operating system and does not have to be explicitly enabled. For more information, see WOW64 Implementation Details.

That is to mean, WOW64 is a part of the 64-bit OS that allows dll targeted to 32-bit platform to run "as if" they were on a 32-bit OS.  WOW64 for "Windows on Windows 64" or we could say "Windows 32-bit on Windows 64-bit". Thus, if a dll targeted to a 32-bit platform  is running on a 64-bit machine and that we check the process it will be indicate 32-bit!
So, how to know the real architecture of the machine while looking at the running 32-bit assembly?

The other good point is that we are allowed to use managed code to ask WOW64 if it is in use for the running process. This is the way to know if you are on a 64 bit system when running a 32-bit dll. If this dll is using the WOW64, that means it is running on a 64-bit machine. So in the previous screen shot, we were on a 32-bit machine.

Now, I would like to come back to the previous excerpt of the Microsoft documentation and focus to the following sentence : "...does not have to be explicitly enabled..."  Hum, it is not totally exact as we are going to see with IIS 7.

4 - WOW64 and IIS7

4.1 mounting a test solution and using WOW64

OK, now, we are going to leave the previous 32-bit machine where I took the previous screen shot, and going to a brand new Windows server 2008  R2 64-bit wiht IIS 7 activated on it.
We are not going to run the Web Part in SharePoint 2010 now, but I would like to take the code of this Web Part and place it in a standard class component (not a control server for ASP .Net) but will use it in an ASP .Net web site.

So, assume we call the component CustomCode and the class RunSomething. We are going to create a solution in Visual Studio 2010 and add a C# Class library project for the Custom Code Component and a Web Site to test it.
Then, we will add an .aspx page in the web site to test our component, let us call it: testComponent.aspx 
Here is the Visual Studio 2010 explorer view of the solution where you can see:

1- The CustomCode component dll
2- The testComponent.aspx page that will load it
3- The RunSomthing Class
4- The folders created by the Configuration manager of Visual Studio corresponding to the target platforms.
5- The Configuration Manager Dialog with the configuration  corresponding to the target platforms.

 Here is the code of the class:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.InteropServices;

using System.Diagnostics;

using System.ComponentModel;

using System.Reflection;

using System.Security;

using System.Security.Policy;

using System.Security.Permissions;

 

//using System.Runtime.ExceptionServices;

 

 

namespace CustomCode

{

    public class RunSomething

    {

 

        string _message = string.Empty;

 

        //This will fail under Win2000 and WinXP SP1 and earlier.

        //You need to check if the IsWow64Process() function exists before you call it,

        //because it was only introduced in XP SP2 and Vista/Win7

        [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]

        [return: MarshalAs(UnmanagedType.Bool)]

        public static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool lpSystemInfo);

 

 

        private string ProcessSize()

        {

            switch (IntPtr.Size)

            {

                case 4:

                    return "running on 32-bit";

                case 8:

                    return "running on 64-bit";

                default:

                    return "unknown";

            }

        }

 

        private string Wow64Using()

        {

            bool retVal;

            IsWow64Process(Process.GetCurrentProcess().Handle, out retVal);

            if (retVal)

            {

                return "using WOW64";

            }

            else

            {

                return "NOT using WOW64";

            }

        }

 

        public string Message

        {

            get

            {

                System.Reflection.PortableExecutableKinds PeKinds;

                System.Reflection.ImageFileMachine ImFileMach;

 

                Assembly myAssembly = Assembly.GetExecutingAssembly();

 

                myAssembly.ManifestModule.GetPEKind(out PeKinds, out ImFileMach);

 

                string strPeKinds = string.Empty;

                string strImFileMach = string.Empty;

 

                switch (PeKinds)

                {

                    case PortableExecutableKinds.ILOnly:

                        strPeKinds = PeKinds + ": The executable contains only Microsoft intermediate language (MSIL), and is therefore neutral with respect to 32-bit or 64-bit platforms. (compiled with Any CPU option)";

                        break;

                    case PortableExecutableKinds.NotAPortableExecutableImage:

                        strPeKinds = PeKinds + ": The file is not in portable executable (PE) file format.";

                        break;

                    case PortableExecutableKinds.PE32Plus:

                        strPeKinds = PeKinds.ToString() + "The executable requires a 64-bit platform. (compiled with x64 option)";

                        break;

                    case PortableExecutableKinds.Required32Bit:

                        strPeKinds = PeKinds + "The executable can be run on a 32-bit platform, or in the 32-bit Windows on Windows (WOW) environment on a 64-bit platform.";

                        break;

                    case PortableExecutableKinds.Unmanaged32Bit:

                        strPeKinds = PeKinds + "The executable contains pure unmanaged code.";

                        break;

                    default:

                        strPeKinds = PeKinds.ToString();

                        break;

                }

 

                switch (ImFileMach)

                {

                    case ImageFileMachine.AMD64:

                        strImFileMach = ImFileMach + ": Targets a 64-bit AMD processor.";

                        break;

                    case ImageFileMachine.I386:

                        strImFileMach = ImFileMach + ": Targets a 32-bit Intel processor.";

                        break;

                    case ImageFileMachine.IA64:

                        strImFileMach = ImFileMach + ": Targets a 64-bit Intel processor.";

                        break;

                    default:

                        strImFileMach = ImFileMach.ToString();

                        break;

                }

 

                _message += "<br>" + myAssembly.FullName;

                _message += "<br>" + strPeKinds;

                _message += "<br>" + strImFileMach;

 

 

                _message += "<br>" + ProcessSize();

                _message += "<br>" + Wow64Using();

 

 

                return _message;

            }

        }

    }

}

 

 

 and here is the code of the testComponent.aspx page:

<%@ Page Language="C#" %>

<%@ Import Namespace="CustomCode" %>

 

 

<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">

<script runat="server">

 

</script>

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <title>Testing a Component</title>

</head>

<body>

<script runat="server">

 

    public void Page_load(object sender, EventArgs e)

    {

        RunSomething myProcess = new RunSomething();

        Response.Write("<br>testing the following: " + myProcess.Message);

    }

</script>

</body>

</html>

 

 And now, if we compile the component so that it is targeted to 32-bit architecture, then, call the page from Visual Studio we obtain this:

 Now, as we are on a 64-bit machine, and we are calling a component compiled for targeting a 32-bit system the WOW64 emulator is called.

But, if we recompile it for both architecture now, using Any CPU option we will obtain this screen:

Well, but you might wondering, as we compiled for both architecture and we are on a 64 bit system, why it is still running using 32-bit within WOW64?
This is because there is at the present no 64-bit version of Visual Studio.

The proof of it? Compile now for a 64-bit target platform an try to call the .aspx page:

You get the

Could not load file or assembly xxxxxxxxx or one of its dependencies. An attempt was made to load a program with an incorrect format.

Exception associated with a BadImageFormatException that means a 32-bit process tried to load a 64-bit component (our case) or vice versa.


OK, but what if we want to test it using 64-bit?
We have to deploy the solution in a real IIS 7 web site. That is what we are going to do now.

4.2 Testing in a real IIS 7 web site

OK, let us mount a IIS 7 web site for this solution and deploy it. Here is the IIS 7 MMC view after having done it:

You can see:

1- the IIS Site (I made the mistake to create a sub apllication)
2- its application pool

Now try to call a dll compiled for targeting a 32-bit plaform. (you have to compile the component in Visual Studio with x86 configuration and paste the dll in the IIS 7 web site BIN folder)

Then you obtain the same BadImageFormatException, but this time, it is because a 64 bit process try to load a 32-bit assembly.
Hum, but where is WOW64 in this case?
That is the point : WOW64 in IIS 7 NEEDS to be activated.
Let us summarize. WOW64 allows 32-bit components to run on 64-bit system, but not a 64-bit process to load a 32 bit component in its process. When you are using WOW64 all must be running on 32-bit.

By default IIS 7 uses a 64-bit process on the 64-bit machine and if you want to use WOW64 to emulate a 32-bit internet site on a 64-bit computer, you have to change a configuration in the IIS 7 application pool advanced settings. So let us do it now.

Display the IIS 7 Application Pools and click on "Advanced Settings" on the right menu.
On the opening dialog set "Enable 32-bit Applications" to true.

Now the previous page will display properly and show that our IIS 7 web site is using a 32-bit process emulated on a 64-bit machine by WOW64 and that the page has loaded a component targeted to 32-bit plaform only.

Now, let the WOW64 activated and this time try a component compiled with any CPU option.

As in Visual Studio before, it is running on a 32-bit process using WOW64.

But, if we change the IIS 7 configuration for a 64-bit process...

The same page and the same component are now running on a 64-bit process and of course, WOW64 is not used anymore.

Last, let us show the same page with a component targeted for a 64-bit platform.

4.3 To Sumarize

The question is: when to use WOW64 within IIS 7 and when not to use?

As the default option of IIS 7 in the matter is to not to use it, you can take benefit of the 64-bit while letting your components compiled with the Any CPU option so that they can be used within all the servers of your company without worrying about the servers system architecture.

However, I would like to point out a major concern not discussed at all until now:
A major migration issue concerns 32-bit software components which cannot be migrated, perhaps because the source code is lost or one of the dependencies cannot be migrated.

Although a 64-bit process cannot load a 32-bit module into its process space there is a way of accessing 32-bit DLLs from 64-bit code , but it is not easy.
Thus, if you have a web application to deploy on a 64-bit machine and it uses or is planed to use that kind of 32-bit code that cannot be migrated, consider setting "Enable 32-bit Applications" to true.


Anyway, that option is only available for standard ASP .Net web sites, for SharePoint 2010, as we are going to see now, you have not the choice...

5 - Migrating assemblies to SharePoint 2010

Well, we can now go back to the main topic of the post, the migration of custom dll to SharePoint 2010.

First off all, never forget: "you CANNOT enable 32-bit applications within a SharePoint 2010 Web Application". When you try to do it by changing this configuration in the advanced settings of a SharePoint 2010 Application Pool the Application Pool service just STOPS.
Why?
Because SharePoint 2010 MUST run on 64-bit, since a part of the new features of the product are targeted to a 64-bit platform. And as we have seen before, if at least one dll of an application is targeted to 64-bit the all application needs to run using 64 bit.

That is the reason why, when building code for SharePoint 2010, we can ONLY use x64 and Any CPU option.
That is the other reason why, you can only deploy SharePoint 2010 on a 64-bit computer.

If we want to check which are the SharePoint 2010 components targeted to 64-bit, we can look in the Global Assembly Cache.

So, it seems to have only the Sandbox, the whole Search and the part linked to Office involved...maybe the part requiring the most memory space.

Now is the time to compile the previous Web Part with the only two allowed options and to test it in SharePoint 2010.

For the Any CPU version

and the x64 version

By the way, I tried to compile the Web Part using x64 configuration on my 32-bit machine and could not deploy it in SharePoint 2010. I had for succeeding to build it on my 64-bit machine.
I had another weird behaviour for another Web Part.
It was built using Any CPU option on my 32-bit machine and ran perfectly well on SharePoint 2010. When I tried to recompile it with Visual Studio 2010 to check if there was obsolete classes used within the code, the Web Part stopped working because there was a call to the SPWeb object inside the Web Part Constructor.
However the same code with the call inside the constructor is working perfectly in SharePoint 2010 with the version built on my 32-bit MOSS 2007 machine.
I will try to update this post with warnings about the migration of custom code to SharePoint 2010 if I encounter another issues.

This is a good transition to conclude and give some direction about migrating the custom assemblies to SharePoint 2010.

6 - Conclusion

I would like to refer to 2 Microsoft documentation posts that give the "philosophy" to have in mind when approaching the concern of the custom code migration to SharePoint 2010.

Migrate an existing server farm to a 64-bit environment (Office SharePoint Server 2007)

[...

You must recompile existing 32-bit applications and custom assemblies (for example, Web Parts and event receivers) to run on the 64-bit architecture because the 64-bit edition of SharePoint cannot load a 32-bit assembly. Before you recompile existing applications or custom assemblies, verify that they are compiled to run on both architectures. If this is the case, do not compile them for a single architecture. (In Microsoft Visual Studio this build option is AnyCPU.)

If the existing applications are third-party applications, check with the third-party vendor regarding 64-bit versions and compatibility. In the case of custom contracted solutions for which you do not have the source, verify the solutions in a test 64-bit environment to ensure compatibility.

...]

Because the changes to the API in the upgrades are backward compatible, you should not have to make any changes to your Windows SharePoint Services 3.0 or Office SharePoint Server 2007 custom solutions before you redeploy them in either SharePoint Foundation 2010 or SharePoint Server 2010. Some classes and namespaces are obsolete, but they will continue to work as expected. If you want to start upgrading your applications so that they use the most current classes and methods, recompile your code. The compiler warnings will tell you which elements of the object model are obsolete, and which newer alternatives you should use. Figure 3 shows an example compiler warning and the corresponding mouse-over warning in Visual Studio 2010.

Reading that, the philosophy may be:

you can migrate a dll compiled for SharePoint 2007 using "Any CPU" option on a SharePoint 2010 server and it will work, but you should try to recompile it with the new object model to optimize your code.
You must recompile the dll compiled with the x86 option.

7 - Aknowledgements and useful links

Thanks to Paul A. Jungwirth for his post Sorting Out the Confusion: 32- vs. 64-Bit, CLR vs. Native, C# vs. C++ 

Thanks to Chris Crowe for his post Could not load file or assembly 'Name' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Thanks to all people having participated to this forum thread: How to detect Windows 64-bit platform with .net?

to go further...

Migrating 32-bit Managed Code to 64-bit

Accessing 32-bit DLLs from 64-bit code

Use ILDASM.exe to force an application compiled to MSIL (Any CPU) to run on the 32-bit CLR of a 64-bit machine

By the way, regarding unmanaged code, here is a SharePoint 2007 application page that allows to check the target platform of an unmanaged dll.

 

<%@ Page Language="C#" AutoEventWireup="true" %>

 

<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"

    Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Register TagPrefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Import Namespace="Microsoft.SharePoint" %>

<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>

<%@ Import Namespace="System.Data" %>

<%@ Import Namespace="System.IO" %>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

    <title></title>

</head>

<body>

 

    <script runat="server">

       

        public enum MachineType : ushort

        {

            IMAGE_FILE_MACHINE_UNKNOWN = 0x0,

            IMAGE_FILE_MACHINE_AM33 = 0x1d3,

            IMAGE_FILE_MACHINE_AMD64 = 0x8664,

            IMAGE_FILE_MACHINE_ARM = 0x1c0,

            IMAGE_FILE_MACHINE_EBC = 0xebc,

            IMAGE_FILE_MACHINE_I386 = 0x14c,

            IMAGE_FILE_MACHINE_IA64 = 0x200,

            IMAGE_FILE_MACHINE_M32R = 0x9041,

            IMAGE_FILE_MACHINE_MIPS16 = 0x266,

            IMAGE_FILE_MACHINE_MIPSFPU = 0x366,

            IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466,

            IMAGE_FILE_MACHINE_POWERPC = 0x1f0,

            IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1,

            IMAGE_FILE_MACHINE_R4000 = 0x166,

            IMAGE_FILE_MACHINE_SH3 = 0x1a2,

            IMAGE_FILE_MACHINE_SH3DSP = 0x1a3,

            IMAGE_FILE_MACHINE_SH4 = 0x1a6,

            IMAGE_FILE_MACHINE_SH5 = 0x1a8,

            IMAGE_FILE_MACHINE_THUMB = 0x1c2,

            IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169,

        }

 

        void CheckConfig(object sender, EventArgs e)

        {

            lblresult.Text = "dll config is: " + UnmanagedDllIs64Bit(txtFilePath.Text);

        }

 

        public MachineType GetDllMachineType(string dllPath)

        {

            //see http://download.microsoft.com/download/9/c/5/

            //             9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.doc

            //offset to PE header is always at 0x3C

            //PE header starts with "PE\0\0" =  0x50 0x45 0x00 0x00

            //followed by 2-byte machine type field (see document above for enum)

            FileStream fs = new FileStream(dllPath, FileMode.Open);

            BinaryReader br = new BinaryReader(fs);

            fs.Seek(0x3c, SeekOrigin.Begin);

            Int32 peOffset = br.ReadInt32();

            fs.Seek(peOffset, SeekOrigin.Begin);

            UInt32 peHead = br.ReadUInt32();

            if (peHead != 0x00004550) // "PE\0\0", little-endian

                throw new Exception("Can't find PE header");

            MachineType machineType = (MachineType)br.ReadUInt16();

            br.Close();

            fs.Close();

            return machineType;

        }

 

        // returns true if the dll is 64-bit, false if 32-bit, and null if unknown

        public string UnmanagedDllIs64Bit(string dllPath)

        {

            MachineType machineType = GetDllMachineType(dllPath);

 

 

            switch (machineType)

            {

                case MachineType.IMAGE_FILE_MACHINE_AMD64:

 

                case MachineType.IMAGE_FILE_MACHINE_IA64:

 

                    return "x64";

                case MachineType.IMAGE_FILE_MACHINE_I386:

                    return "x86";

                default:

                    return machineType.ToString();

            }

        }

 

    </script>

    <form runat="server">

    <asp:TextBox runat="server" ID="txtFilePath" Columns="120"></asp:TextBox>

    <br />

    <asp:LinkButton ID="lbProcess" runat="server" Text="Check Config" OnClick="CheckConfig"></asp:LinkButton>

    <br />

    <br />

    <asp:Label ID="lblresult" runat="server"></asp:Label>

    <br />

    </form>

</body>

</html>

Source: How can I programmatically tell in C# if an unmanaged dll is x86 or x64?

1 comment:

Anonymous said...

Excellent, what a blog it is! This website provides helpful facts to us, keep it up.