全部博文(326)
分类: LINUX
2005-12-26 22:30:53
Wine 是一个令人神往而且目标远大的开放源代码项目,它尝试去解决在 Linux 上运行 Windows 可执行文件的复杂问题。尽管 Wine 不是一个新项目,但是,人们对 Linux 桌面的期望以及对 Linux 应用程序的需求日益增加,使得它现在仍具有重要意义。本文对 Wine 进行了介绍,并提出了几种获得 Wine 内部操作经验的途径。
Wine 项目起始于 1993 年,它的根源可以追溯到 90 年代早期出现的用于 UNIX 的 DOS 和 Windows 模拟器。Wine 项目最初是将 16 位的应用程序移植到 Linux,而几年之后,已可以在 Linux 上运行 Microsoft Word 和 Excel。现在它有一百多万行代码。
人们一直认为,在桌面上采用 Linux 的主要障碍是应用程序不足。商用桌面应用程序供应商还不能确定他们是否应该投入时间和精力将他们的 Windows 应用程序移植到 Linux,他们基本上是在等待 Linux 大规模应用于桌面。另一方面,Linux 需要应用程序才能大规模应用于桌面。这是一个经典的先有鸡还是先有蛋的问题,而 Wine 通过在 Linux 上运行现有的 Windows 应用程序而解决了这一问题。
Wine
项目实际是一个二合一的项目。它们提供了一个名字叫做 Winelib 的开发工具包,用于将应用程序从 Windows 移植到 Linux(和
Unix);它们还提供了一个程序加载器,让 Windows 二进制文件可以在 Unix 和类 Unix 系统中运行。本文讨论的主要是后者;在 参考资料中有关于 Winelib 的更多资料的链接。
|
Wine 程序加载器让运行于 x86 上的 Linux 和其他类 Unix 操作系统可以加载并运行 Windows x86 可执行文件 -- 不过那只是它要解决的问题的一部分。因为 Windows 可执行文件总是会链接到其他的库,而这些库是 Windows 操作系统的一部分(如本文稍后图 1 中的 Dependency Walker 截图中可以看到),Wine 还最大可能限度地实现了那些 Windows 内部构件,即 Linux 上通常所指的 Win32 API5。
虽然 Windows 和 Linux 有很大的不同,但是就基本的层次而言,与任何现代操作系统一样,还是有很多类似之处的 -- 比较明显的包括,对文件和目录的支持,对同时运行多个程序的支持,类似的用户界面以及对多媒体的支持。
图中显示了 callDLL.exe 的依赖,这个可执行文件可以由本文提供的源代码编译得到。对一般的用户而言,依赖的复杂度可能是惊人的,但对任何一个系统程序员来说都不是这样,他们充分了解,哪怕是运行一个最简单的程序,操作系统也必须要做很多事情。
考 虑图 1 所示的可执行文件的第一个依赖 -- 对 USER32.DLL 的依赖。在 Windows 中,一个 DLL 就是一个动态链接库(dynamically linked library),类似于 Linux 中的一个共享对象(一个 .so 文件)。USER32.DLL 文件通常会由操作系统提供,位于 C:WINDOWSsystem32 或者 C:WINNTsystem32 目录下。这个文件中包含了 Windows API 中用于用户界面的函数实现。
我们的可执行文件调用 USER32.DLL 中的一些函数,USER32.DLL 然后去调用 NTDLL.DLL 中的其他函数,如此继续。这些函数大部分已经由 Microsoft 文档化 -- 但是还有很多没有被文档化。文档的缺乏对 Wine 来说是一个极大的障碍,本文稍后将更详细地讨论这一问题。
现在让我们来看我们的可执行文件的第二个依赖 -- 对 SIMPLEDLL.DLL 的依赖。这个 DLL 是在编译本文所附的源代码时创建的。这个 DLL 中实现了一些特别简单的函数;它作为常见于安装 CD 上的各种二进制文件的例子被包括进来。
如我们的例子所示,一般的 Windows 可执行文件有两种类型的依赖:一种是对操作系统提供的二进制文件的依赖,另一种是对作为应用程序一部分的二进制文件的依赖。
还需要特别注意的是,DLL 以难于管理而闻名,即使是在产生它们的 Windows 操作系统中也是如此(参见 参考资料)。值得一提的是,Wine 团队成功地创建了一个可以在 Linux 上运行很多商用 Windows 应用程序的框架。
当 前,开放源代码的 Wine 项目有一个健壮的平台来运行 Windows 二进制文件以及对 Win32 API 的部分实现。这个项目仍然处于最初的测试阶段(alpha),有很多部分还没有完成。尽管 Wine 提供了一些工具来帮助进行配置、安装以及运行应用程序,但是它们大部分都是面向程序员的,要让非技术用户也可以使用这些工具,还有很多事情需要去做。过去 的 Corel 以及现在的 CodeWeavers 为此提供了很多帮助。
|
既然我们已经理解了 Wine 的基本原理,让我们更详细地来研究 Wine 能够做什么。本文中,我们讨论的是 Wine 在纯 Linux 上的安装,没有任何 Windows 分区。
|
不
幸的是,很多用户发现 Wine 难于使用。诚然,在 Linux 上使用类似于 MS Office
这样的应用程序可能是困难的;在这里我们来看一些原因,为什么确实是这样。在开始之前,我们应该指出,CodeWeavers 提供的商用 Wine
已经解决了大部分此类问题(参阅 参考资料以获得链接)。假以时日,这些问题将可能在开放源代码的 Wine 中同样得到解决。
wine IEXPLORE.EXE
。尽管经验丰富的用户喜欢这样做,但初学者会发现这比较困难,而且不太可能懂得起别名等快捷方式。
unhide
选项,那么安装 CD 上的一些文件可能会无法找到,从而导致安装失败。
注意,这些并不是病症,而是举例说明了是哪些种类的事情导致对一般用户来说 Wine 看起来复杂而且困难。
看完 Wine 的可用性问题后,现在让我们来总结在尝试使用 Wine 时一些常见的技术问题。
有一些因素会减轻这些问题。一方面,您将会一个一个地遇到这些问 题,而不是一次遇到全部问题,这样处理起来要容易些。另外,您遇到的那些问题可能其他人曾遇到过并已经解决(而且解决方案已经公布出来)。Wine 用户组非常活跃,会提供许多帮助,每周一次的 Wine 时事通讯(参阅 参考资料)是极好的信息资源。
在
Wine 中,很多 Win32 API5 的函数是残缺不全的。最常见的原因是,相当多的 Win32 API
并没有被文档化。这就意味着一个特别的应用程序可能会调用某个函数,而完全没有关于此函数的可用资料。例如,我们在运行一个简单的 RPC
程序时发现了 RtlAnsiCharToUnicodeChar 这个函数。在 MSDN
上的搜索结果显示没有关于这个函数的资料,而且没有关于所有 RtlXXXX 类别函数的资料。因此,如果它们在 Wine
中的实现对一些应用程序来说至关重要,那么人们可能只有去猜测它们的行为了。
|
CodeWeavers 为 Wine 做了很多工作。多年来他们为 Wine 项目贡献了很多代码,他们出售商用版本的 Wine,其改进的用户界面解决了我们在本文中提出的很多问题。
例 如,CodeWeavers 的二进制安装文件会在用户的开始菜单中添加一个 Crossover 条目;安装后,绝大多数 Crossover 相关的任务可以通过开始菜单条目来完成。在开放源代码的 Wine 中,所有这些任务 -- 安装、程序执行以及其他任务 -- 都必须在命令行中执行。此外,CodeWeavers Crossover 将会尝试去为新安装的软件包配置一个合理的默认值,如果需要的话会在安装完成后自动重新引导,并以其他形式减轻用户的负担。
CodeWeavers 使用开放源代码的 Wine 作为他们的 Crossover 产品的基础,所以,除非遇到上面我们讨论过的可用性问题,否则,在其中一个产品中能运行的应用程序,在另一个产品中同样也能运行。要深入了解 CodeWeavers 和 Crossover,以及要获得可以在 Wine 上运行的应用程序列表,请参阅在 参考资料中列出的链接。
|
由
于 Wine 支持 Windows 可执行文件的运行,您会想当然地认为可以使用程序的安装程序从头安装,这是正常的。不幸的是,几乎不会那样。对
Windows 安装过程的理解将有助于解释原因。下面非常简单地描述了 Windows 安装程序通常要做的事情的(不必是这个次序):
因而,Wine 会遇到两种类型的问题,必须按顺序解决:
在 调试 Wine 安装的过程中,如果您同时有一个可用的 Windows 系统的话会非常有帮助。那样,您可以对 Windows 安装使用追踪器以确切断定哪些文件被拷贝,哪些注册表条目被添加或更新,哪个 INI 文件被修改,等等。记录安装步骤的顺序并与失败的 Wine 安装相比较,是故障诊断的好向导。
|
如果您正在使用 Red Hat 或者 SUSE,最简单的方法是从 CD 安装 Wine。不过,如果那些 CD 比较老,您可能需要通过源文件安装,因为 Wine 项目经常更新。如果通过源文件安装,您会发现 Wine 用户指南(参阅
参考资料以获得链接)是一份价值无法估量的资料。简化的安装过程如下:
tools
目录下以用户身份运行 ./tools/wineinstall。
winecheck
脚本来检查安装。您可能不会获得 100% 的成功,但只要没有关键问题就行。
~/.wine/config
文件中。这个文件很容易理解:它描述了您希望将 Linux 文件系统的哪部分看作是 Windows C 驱动器,以及 DLL 的加载次序等其他的细节。
您应该可以快速进行了。例如,要安装 WinZip 8.1,您可以下载安装程序并在命令行中运行
wine winzip81.exe
。
快速浏览一下图 2 可以了解很多内容:您可以看到 WinZip 在运行,它的文件浏览器组件显示出熟悉的 Windows 驱动器 C、软盘驱动器 A、一个 CD-ROM M 以及另外的 Z 驱动器。您可以猜到,所有这些都映射在我们上面提到的
~/.wine/config
文件中。下面是文件中与图 2 所示驱动器有关的片断:
|
从这里您可以看到,图 2 中的 M 驱动器实际上是 /mnt/cdrom;C 驱动器是 /home/aditya/aug14/3/c;等等。
|
技术上讲,使 Windows 可执行文件在 Wine 中运行并不是移植,但是经常被认为是移植。这也是测试一个应用程序是否适合使用 Winelib 进行移植的好办法。要获得关于使用 Wine Winelib 库编译来移植源代码的资料,请参阅
参考资料中关于 Winelib 用户指南的链接。
我 们已经整理了一个非常简单的应用程序,来说明 Windows 程序如何在 Wine 中运行。程序创建了一个窗口;从一个 DLL 中加载了两个函数,有一些对话框。我们将继续使用非常简单的例子;作为实际应用中的例子,我们非常鼓励您用 MS Office 等大型应用程序进行同样的尝试。
同时,这个例子可以通过让您体验代码的运行来入门。
示例 DLL 的源代码在 DLLCode 目录中,使用 DLL 的源代码在 callDll 目录中。要运行只需要将两者(DLL 文件和可执行文件)存放于同一目录下,并运行
callDll.exe
。winetests 文件夹中的 README.TXT 文件描述了如何在 Linux 上 Wine 中执行那个二进制程序。
如果您愿意,可以随意打开项目文件并进行修改。
DLLCode 项目正确编译后,您可以在 Debug 文件夹中看到 DLLSample.dll 文件。这个文件是 callDll 项目所需要的。为了您的方便,DLLSample.dll 已经存放于 callDll 中正确的位置。您可以回顾图 1 中举例说明的 callDll 中产生的可执行文件的依赖;您可以使用 Dependency Walker 来查看其他程序的依赖(参阅 参考资料)。
下面是对运行于 Windows XP 上的和运行于 Red Hat 的 GNOME 中的消息框(Message Box)视觉上的对比:
对应于此的 C 代码(callDll.cpp 中第 60 行):
MessageBox(NULL, "Wine test ending...", "", MB_OK);
这提出了一些有趣的观察:
既 然我们已经看过了一个 Win32 函数,让我们来看一下,当 simpleDLL.dll 中实现的我们自己的函数之一被调用时,幕后发生了什么。我们将展示追踪记录中的片断来说明何时 simpleDll.dll 被加载,哪些函数被导出,在哪一点 getTitle() 函数被调用(按 README 文件中的步骤生成完全的追踪记录):
|
|
|
分析一个更大的应用程序或多或少与此相似,不过您当然会得到多得多的细节,会遇到没有被实现的函数,等等。故障诊断通常大概是提供缺少的 DLL 和调整配置;偶尔,您将需要去实现或修复一个函数。
|
如果您正在寻找将现有的 Windows 应用程序转移到 Linux 的方法,开放源代码的 Wine 和来自 CodeWeavers 的商用产品都是极好的选择。应用程序可以运行于 Wine 之上,或者使用 Winelib 工具包进行移植。
Wine 还为那些希望介入开放源代码软件的人们提供了一个独一无二的机会。从特别困难的到适合初学者的,有大量的各种复杂程度的项目--而且 Wine 社区非常活跃并提供非常多的支持。
|