前段时间一直弄关于32位到64位程序移植的问题, 终于结束了, 所以在这里做一下小结。

其实对于一般的32位应用程序64位操作系统都是兼容的, 只有一些特殊的需要与64位应用程序进行交互的才需要编译成64位, 不然会出现不兼容的问题。因为我移植的是输入法, 这里拿输入法来说。输入法实际上是一个DLL, 只不过是把.dll改为.ime, 它需要一个宿主程序才能启动(宿主程序如:记事本、IE等), 也就是说它是宿主程序的一部分, 那么它肯定要与宿主程序进行交互了, 如果宿主程序是32位的输入法也是32位的当然没问题, 但是如果我们用的是64位的操作系统, 输入法必然要与64位应用程序打交道。这样的话当输入法在64位程序中启动就会出现问题,微软也有描述:在64位的windows系统中,一个64位进程不能加载一个32位dll,同理一个32位进程也不能加载一个64位dll(不过它有解决办法——64位进程调用32位dll的方法 ,当然这种方法对输入法显然是不行的)。 所以我们需要将输入法的DLL编译成64位的, 至于编译成64位后, 32位的应用程序又怎么能调用到, 最后再说。

准备工作

首先,你的机器CPU需要支持64的操作系统(现在CPU一般都可以), 然后装64位的操作系统。之后就是编译器了, 我用的是VS2008, 最好完全安装这样省去很多不必要的麻烦。最后就是针对64位平台配置Visual C++项目 (这个地址有图:c/c++64位移植 )。

编译

由于输入法中有很多个dll, 所以我是先编译与主模块相关联的dll, 然后再编译主模块。这个时候原来的dll路径当然改变了, 新的dll会出现在新生成的x64目录下, 路径是必须要改的。编译中有许多配置方面的问题要注意, 可以参考这里
编译后出现问题主要有以下方面:

  • 内存方面: 因为32位下指针是4个字节, 64位下是8个字节, 在分配的时候要注意是不是分配了足够多的内存, 特别要注意sizeof(...)函数, WNDCLASS的额外内存分配(如果不为0的话), 还有取指针地址的时候, 以前只需4个字节就可以取到下一个地址, 现在需要8个字节。很多与平台有关的数据类型,在32位下是4个字节, 在64位下是8个字节(如:LONG_PTR), 关于这方面的内容可以参考这里
  • 函数方面:在64位下有的函数最好是换成支持64位的(如:SetWindowLong, GetWindowLong换成SetWindowLongPtr, GetWindowLongPtr)。
  • 错误与警告方面:有的错误显示没有某个宏或者什么, 可能它在64位下是另外一个名字(如在原来的基础上加了一个PTR什么的)。要注意警告里的数据截断与数据丢失。

x64中32位与64位程序兼容问题

在64位操作系统相对于32位多了一个系统目录SysWow64, 大家不要误会它用来支持64位的, 其实它是用来兼容32位的, 真正的64位的dll是放在System32里面的。从这里我们就知道要想输入法同时支持64位与32位的应用程序就需要2个IME,将64位的放在System32中,32位的放在SysWow64中。那么当我打开应用程序启动输入法的时候系统怎样知道是用哪个IME呢?其实这个和注册表有关, 将刚才那两个IME取相同的名字, 在注册的时候需要注册三个地方:

  1. ControlSet001是系统真实的配置信息;
  2. ControlSet002是“最近一次成功启动的配置信息;
  3. CurrentControlSet是ControlSet001的副本,我们对于计算机配置的所作的修改都是直接写入这里,在重启过程中,windows会用CurrentControlSet的内容覆盖掉ControlSet001,以保证这两个控件组一致;

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Keyboard Layouts是我们调用ImmInstallIME来创建的注册表项。 在你启动应用程序的时候系统会自动判断这个应用程序是多少位的, 32位的它会加载32位的IME, 64位的它会加载64位的IME。如果在System32和SysWow64中,只有其中一个目录有IME,那么在“文本服务和输入语言”里可以看到输入法名字后面有个(32)或者(64)表示只支持某个位数的应用程序。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

鄂ICP备17003086号. Copyright © 2016. All Rights Reserved.