Windows 64位平台和.Net Framework在64位平台上的一些Tips (二)

关键词: X64, x32子系统, .Net Framework, corflags.exe, Sysnative, gacutil.exe, sn.exe

 

本文适合的读者:

对64位Windows平台刚刚入门,并且对.Net Framework有一些了解的技术人员。

本篇除了继续上一篇的内容外,还会介绍一些在64位Windows系统中有用的工具软件。我将分条目列出我在64位系统上曾经遇到过的一些典型问题。

 

1. 使用Corflags.exe指定在32位环境下运行

CorFlags是.NET Framework中一个用于查看.NET 可执行文件(PE)的运行参数的非常有用的工具。(请注意,它不能用于非.Net格式的可执行文件。) 我们在上一篇中提到过,在64位环境下,一个用”Any CPU”编译的MSIL可执行文件默认是以64位的模式运行的。如果我们要让它以32位模式运行,通常的做法是把它放到32位子系统中去运行 -- 在WOW中打开它(即在C:/Windows/SysWOW64/cmd.exe中运行它)。利用Corflags工具,我们可以让可执行程序在任何情况下都默认以32位的模式运行。

“Any CPU”编译的MSIL可执行文件,例如名为MSIL.exe, 我们用Corflags去查看:

>corflags MSIL.exe

Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 4.0.20417.0

Copyright (c) Microsoft Corporation. All rights reserved.

Version : v2.0.50727

CLR Header: 2.5

PE : PE32

CorFlags : 1

ILONLY : 1

32BIT : 0

Signed : 0

先简单介绍一下输出结果,Version和CLR Header指出了.NetFramework和CLR文件头的版本。PE=PE32说明了它的文件格式。ILONLY=1说明MSIL.exe只含有MSIL中间语言,这也意味着它是从纯托管语言编译出来的。32BIT=0说明它并没有指定在32位模式下运行。结合这些信息,我们可以很容易推断出,MSIL.exe是用”Any CPU”从纯托管代码编译而来的。(Corflags输出的详细介绍请参看Corflags /?)

我们可以用corflags MSIL.exe /32bit+命令来修改MSIL.exe的32BIT标志位。如果MSIL.exe是被强签名的,则需要使用corflags MSIL.exe /32bit+ /force 命令。因为corflags修改了程序集本身,因此破坏了原来的强签名。修改后的Corflags输出结果如下:

>corflags MSIL.exe /32bit+

>corflags MSIL.exe

Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 4.0.20417.0

Copyright (c) Microsoft Corporation. All rights reserved.

Version : v2.0.50727

CLR Header: 2.5

PE : PE32

CorFlags : 3

ILONLY : 1

32BIT : 1

Signed : 0

我们可以看到32BIT标志位现在变成了1(整个程序集也仅仅只有这一个BIT发生了变化,我用二进制逐位比较验证了这一点),这样的Corflags结果和我们用x86编译出来的结果是完全一样的。如果我们这时候去在64位Windows中双击运行MSIL.exe, 你在Task Manager中会看到它的确是在32位模式下运行的:

Windows 64位平台和.Net Framework在64位平台上的一些Tips (二)_第1张图片

同样,我们也可以用Corflags MSIL.exe /32BIT- 再把32位标志位改回去;也可以用Corflags <程序集名> /32BIT- 把x86编译的程序集的32位标志位改写成0。使它运行以来就像MSIL程序集一样。

 

2. 隐藏的Sysnative

我曾经遇到过这样的不知所措的局面,在64位Windows中,我有一个在32位模式下运行的可执行程序A.exe要去启动一个在64位模式下运行的可执行程序B.exe。为了使B.exe顺利运行,我需要在A.exe中拷贝一个配置文件到C:/Windows/System32/rundll32.exe.config。于是我顺理成章地在A.exe中写了如下代码:

File.Copy("my.config", @"C:/Windows/System32/rundll32.exe.config");

出乎我意料的是,尽管我接下来在程序中做的种种检验都表明拷贝操作已经成功完成(我甚至可以打印出C:/Windows/System32/rundll32.exe.config的内容),但是我就是无法在C:/Windows/System32文件夹下找到rundll32.exe.config文件。这让我面对电脑几乎傻坐了半天。然后四处苦苦搜索后才找到答案。

原来在64位Windows上,在32位模式下运行的程序,文件系统操作如果遇到”System32”文件夹名, 就会把它自动翻译成”SysWOW64”。所以,我的文件其实是被拷贝到C:/Windows/SysWOW64目录中去了。正如我们在上一篇开头提到,Windows64中的32位子系统在试图向我们屏蔽64位Windows的事实。这有时候带来方便,有时候带来痛苦。这里的情况就是我之前提到的痛苦的一个例子。于是,在32位子系统中,”C:/Windows/System32”文件夹似乎成了未知的外部世界,无论如何都无法进入。为了解决这个问题,操作系统的设计者提供了一个特殊的文件夹名字:”Sysnative”, 用于解决这种特殊情况的需求。对于没有经历过这种痛苦的人,Sysnative是完全不可见的。因为他不是一个真正的文件名。一旦在32位子系统中碰到这个名字,系统就会将它自动翻译成”System32”。

C:/>cd C:/Windows/Sysnative

C:/Windows/Sysnative>

在WOW中输入以上以上命令,你会看到自己来到了C:/Windows/Sysnative文件夹。但你会发现在C:/Windows下面其实根本没有这样一个文件夹。你来到的其实是C:/Windows/System32文件夹。

于是,我只要把我原先的拷贝代码换成下面的代码就可以如我所愿了:

File.Copy("my.config", @"C:/Windows/Sysnative/rundll32.exe.config");

 

3. 使用gacutil.exe分析程序集加载失败(assembly loading failure)

Gacutil.exe也许是我们最常用的.Net工具了。在64位Windows上,它更是显得不可或缺。如果你已经很熟悉用gacutil.exe处理多平台问题了,这一条也许对你来说就显得废话连篇了。你可以直接跳过它。

在64位机器上,我们很常见的程序异常是DLL加载失败。很多情况下这是由于32位/64位的程序兼容性引起的。例如下图中,这个Microsoft svcConfigEditor.exe的异常窗口告诉我们,程序没有能够成功加载mscorcfg.dll。

Windows 64位平台和.Net Framework在64位平台上的一些Tips (二)_第2张图片

在类似这种情况下,gacutil往往能派上用场。下面是我在这台x64机器上运行gacutil -l mscorcfg

的结果:

>gacutil -l mscorcfg

Microsoft (R) .NET Global Assembly Cache Utility. Version 4.0.20417.0

Copyright (c) Microsoft Corporation. All rights reserved.

The Global Assembly Cache contains the following assemblies:

mscorcfg,Version=3.5.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a,processorArchitecture=x86

mscorcfg,Version=4.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a,processorArchitecture=x86

Number of items = 2

我找到了另一台svcConfigEditor能正常运行的x64机器运行同样的命令(两台机器安装的.Net Framework的版本是不一样的):

>gacutil -l mscorcfg

Microsoft (R) .NET Global Assembly Cache Utility. Version 3.5.30729.1

Copyright (c) Microsoft Corporation. All rights reserved.

The Global Assembly Cache contains the following assemblies:

mscorcfg,Version=3.5.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a,processorArchitecture=AMD64

mscorcfg,Version=3.5.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a,processorArchitecture=x86

mscorcfg, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Number of items = 3

通过比较我们很容易看出来,出问题的机器上只有processorArchitecture=x86的mscorcfg.dll被添加到GAC里了。而以64位模式运行的svcConfigEditor.exe只能加载processorArchitecture=AMD64或者processorArchitecture=MSIL的DLL(在AMD64的机器上).所以发生了加载失败。于是,解决的方法自然就是在GAC中添加适用于64位环境的mscorcfg.dll

 

4. 注意区分平台的sn.exe

我曾经遇到过这样的困境,在一台x64机器上,我有一个延迟签名(DelaySign)的COM+组件COMPlusSample.dll,为了避免在注册或者使用它时遇到强签名检查失败的问题(延迟签名的dll在很多情况下通不过强签名检查),我用sn.exe –Vr把它加入到跳过强签名检查的列表中:

C:/>sn -Vr COMPlusSample.dll,a624f987ec175a75

Microsoft (R) .NET Framework Strong Name Utility Version 4.0.20417.0

Copyright (c) Microsoft Corporation. All rights reserved.

Verification entry added for assembly 'COMPlusSample.dll,a624f987ec175a75'

C:/>sn -Vl

Microsoft (R) .NET Framework Strong Name Utility Version 4.0.20417.0

Copyright (c) Microsoft Corporation. All rights reserved.

Assembly/Strong Name Users

===========================================

*,03689116d3a4ae33 All users

*,31bf3856ad364e35 All users

*,33aea4d316916803 All users

*,8143d71cff648ea2 All users

*,b03f5f7f11d50a3a All users

*,b77a5c561934e089 All users

COMPlusSample.dll,a624f987ec175a75 All users

如上所示,一切都显得很正常,sn –Vl给出的列表表示系统将会跳过COMPlusSample.dll的强签名检查。然而,在我试图把这个dll注册到comexp.msc中去的时候,仍然因为强签名的问题而失败了。而我换了一台x86的机器重复同样的步骤却一点问题都没有。那么问题出在哪里呢?

原来,.Net为64位系统提供了两份sn.exe, 分别用于32位程序集和64位程序集。他们在我的系统中分别位于:

C:/Program Files/Microsoft SDKs/Windows/v7.0/Bin/sn.exe

C:/Program Files/Microsoft SDKs/Windows/v7.0/Bin/x64/sn.exe

这两个sn.exe分别维护着各自不同的强签名检查省略列表。32位程序使用32位sn.exe的列表,64为程序则使用64位sn.exe的列表。有趣的是,如果在Visual Studio的命令行提示工具中不指明路径使用sn,默认调用的却是32位的sn.exe,而不是64位的版本。这要么是SDK工具集的设计者没有和Visual Studio命令行工具的设计者达成默契,要么就是他们有其他的考虑。总之,当我使用了x64文件夹下面的sn.exe后,我的问题就解决了。

Sn.exe只是这一类问题的一个代表,如果你查看x64文件夹和它的上层文件夹中的文件,你会发现还有很多其他常用的工具被保存了两份。他们同样有平台的区别,使用的时候要注意。

你可能感兴趣的:(Windows 64位平台和.Net Framework在64位平台上的一些Tips (二))