x64位windows上程序开发的注意事项 分类: VC++ 2013-10-08 08:30 857人阅读 评论(0) 收藏

在Windows上面32位与64位的区别有:

1.指针大小的区别,sizeof(int *)在32bit下面是4个字节,在64bit下面是8个字节
2.size_t的区别,size_t在32bit下面是4个字节的范围,在64bit下面是8个字节的范围
3.地址空间的区别,在32bit下面,最大地址空间是4GB,在64bit下面是可以大于4GB的
4.32位程序在64位Windows上运行,是有一个Wow64子系统辅助其运行的,默认情况下,访问注册表和某些文件夹是被重定向的
5.指针的区别也意味着Handle的区别
6.唯一支持Windows原始64位编译的msvc编译器不支持64bit的内联汇编,如果要用汇编,需要单独编译再link
7.纯64bit程序的函数调用方式已经不再区分cdecl和stdcall方式,因为只有一种了。
8.64bit的程序不再使用esp,而是使用增加的几个64bit寄存器,因为esp不支持64bit空间的栈

最近的工作涉及到Linux的64位工作,发现当初对32位和64位区别的认识还不够:
1.long在Windows下面,不管是32bit还是64bit下,都是4个字节的,但在Linux下面,32bit下是4字节,在64bit下是8个字节。(long long在64bit下还是8个字节)
2.gcc在64bit下面,不再支持__attribute((cdecl))__和__attribute((stdcall))__,这点和Windows有点类似,开始以为是gcc的高版本不支持的,后来发现区别在x86和x64


64位下windows的开发建议:

1.避免System.BadImageFormatException

  通常,程序员碰到这种情况:“出现未处理的类型异常 ‘System.BadImageFormatException’”。如果你要深究该异常的细节信息,可能会发现系统提示:“试图加载的程序,格式不正确”。

  之所以会出现这样的问题是因为64位进程试图加载一个32位组件。虽然你在Windows x64上可以运行64位和32位进程,但是64位代码和32位代码不能在相同进程上运行。你的代码要么全部是64位,要么全部是32位。要加载的组件也要符合这一规律。

  VS 2005与.NET 2.0为编译.NET应用程序带来选择,将输入设置为“Any CPU”也具备了可选性。“Any CPU”是默认平台。如果组件以Any CPU作为平台进行编译,那么它将依据进程加载的情况以32位或64位方式运行。使用Any CPU,相同的组件可以在64位Windows上以32位或64位方式运行:它不是真正的指定了64位的CPU或操作系统,而是一个调用进程。

  为了解决不合格图像异常的问题,要改变到Any CPU的所有组件的目标平台。如果出于某种原因你无法做到这一点——或许某组件无法提供来源——那么要将所有组件设置成到达同一平台,可以是x86也可以 是x64。如果你拥有.NET 1.0或1.1组件,最好是用.NET 2.0对其重新进行编译。如果你不能编译.NET 1.0或1.1组件,那么编译其他代码,设置为到达x86平台,使之兼容。

 2.大小问题

  64位和32位Windows之间一个重要的区别是句柄的大小。如果你的代码中具备任意Windows API调用,那么你要确保你的说明对于64位Windows是正确的。如果代码是从VB6升级而来,那么你不能区分句柄和32位整数的概念,因此你必须寻 找源文件或标头文件。识别哪些参数和域是句柄,使用这些类型的IntPtr。通常情况下,文件将以INT_PTR或LONG_PTR将其识别或者用名称只 是某类句柄,如HWND。用前缀定义的参数,如PTR或LPTR通常是一些指示器,因此需被视为IntPtr或使用ByRef编组。要确定你运行的64位 还是32位,可以在运行时检查IntPtr.Size的值。

3.COM可以是64位

  普遍存在的误解是认为COM和ActiveX仅限于32位,但是使用VB.NET,你可以使用64位COM和ActiveX控件。 Windows没有按照64位编译的控件,但是其中一个值得注意的例外是sysmon.ocx ActiveX 控件,该控件可以让你创建系统监测图。

  你可以使用Windows.Forms应用程序中的64位ActiveX控件,但是当涉及汇编的时候就存在缓冲。VS当前是32位的应用程序, 它在汇编的时候需要32位的ActiveX控件以便创建运行时可随时启用的COM组件包装。为了在VS中进行编译,你需要32位的版本。一旦程序被编译, 就只需要被选中的平台。

  在你没有32位版本或类似版本的情况下,你可以使用命令行来运行64位工具以便创建一个用于ActiveX控件的Interop程序集。见Tlblmp.exe文件以了解详情。

4.意识到问题

  32位应用程序运行于Windows 64中时,它与模拟器一起运行。模拟器被称为WOW64,是Windows On Windows64的缩写,可以让32位应用程序按照32位操作系统进行查看。WOW64模拟器加载了一个ntdll.dll的x86版本,提供了切入点 和替换程序,还会截取最重要的注册表和文件系统操作。

  WOW64模拟器也暴露出不同的适合32位应用程序的环境型变量。因此,32位应用程序将ProgramFiles环境型变量为 ProgramFiles(x86)。以64位运行的时候,如果你写出类似MsgBox(Environ(“ProgramFiles”))的代码,会获 得"C:\Program Files",如果你32位运行,则获得"C:\Program Files (x86)"。

  模拟器所做的事情与注册表和系统目录类似。出于兼容性和性能的考虑,%windir%\System32 文件夹是64位文件夹。也就是说,64位应用程序中不存在任何截取。重新定向的32位操作文件夹默认名为%windir%\SysWOW64。名称 SysWOW64指明它要被32位模拟器WOW64使用。这或许有些令人困惑。

  WOW64之下的注册表将重定向与反射结合使用。重定向存在于HKEY_LOCAL_MACHINE\SOFTWARE \Wow6432Node等Key之下。至少注册表中的命名式样更好。映射是32位进程和64位进程都可以编辑共同Key,如文件关联。另一方面讲,重定 向是为了确保将32位从64位隔离开。

  关键是执行不能影响你除非你打算从64位程序中获取32位程序的详细信息,反之亦然。通常汇编到同一目标要简单得多。例如,如果你想使用VS, 将程序锁定到x86,你不需要担心文件或注册表的模拟过程。如果你要以Any CPU运行程序,那么就取决于它是如何启动的,或许你要使用重定向,和类似GetSystemWow64Directory的API调用,并且使用 RegOpenKeyEx API,包括KEY_WOW64_32KEY的访问假象。它可能变成混乱而复杂的测试。这是目前为止对相同平台和锁定信息最好的汇编方式。

  其中笔者偶然发现的一个问题是注册表反射和Windows Vista UAC的结合。在用于写入许可的HKLM蜂巢中笔者开放了一个Key,API成功了,但是当笔者向Key写入时,却失败了。应用程序以32位方式运行于 Windows 64上,因此有问题的Key会被映射。笔者浪费了大量时间用于确定所发生的事情,因为注册表API不会向往常一样运作。最后,笔者通过往应用程序中包含运 载单使之正常运行。即便requestedExecutionLevel对asInvoker有级别设置,这一漏洞也可以被修复。

  UAC提供了注册表虚拟化,笔者认为WOW64重定向或反射与UAC虚拟化的结合太多了。现在笔者通常会确保应用程序中具备运载单。在VS 2008中,你可以从项目属性对话框中的程序标签中获取运载单。确保你包含了requestedExecutionLevel选项。

5.激活Edit和Continue

  虽然,你可以调试64位应用程序,那么就不能在调试期间使用Edit和Continue。这意味着你不能在调试的时候改变源代码,相反你要停 止,应用更改,重新编译并启动调试。但是你可以用32位程序使用Edit和Continue,即便是在64位Windows上。这是另一种手动构建配置的 示例。


  创建一个x86构建配置,并且在开发的时候使用这一配置,如此你就可以使用Edit和Continue。然后将配置切换称x64或Any CPU用于测试。

  使用Windows 32或Windows 64不如VB 8或VB 9中那样难。使用VS并且构建配置,任务会变得简单。

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2013-10-08 08:30  毛毛虫的薄刻  阅读(140)  评论(0编辑  收藏  举报