(六):Winelib开发组件2

简介: 版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/49682313 话接上节!!(二):编译资源文件:wrc为了编译资源,你应该使用Wine资源编译器,简写为wrc,该编译器会生成一个二进制.res文件。
版权声明:您好,转载请留下本人博客的地址,谢谢 https://blog.csdn.net/hongbochen1223/article/details/49682313

话接上节!!

(二):编译资源文件:wrc

为了编译资源,你应该使用Wine资源编译器,简写为wrc,该编译器会生成一个二进制.res文件。当编译spec文件的时候,该资源文件会被winebuild使用。

winemaker生成的makefiles文件会帮你照料好。但是,如果你要编写自己的Makefile文件的话,你应该将下面的语句加上:

WRC=$(WINE_DIR)/tools/wrc/wrc
WINELIB_FLAGS=-I$(WINE_DIR)/include -DWINELIB -D_REENTRANT
WRCFLAGS = -r -L
.SUFFIXES: .rc .res
.rc.res:
     $(WRC) $(WRCFLAGS) $(WINELIB_FLAGS) -o $@ $<

资源文件中你可能会遇到两个问题:

第一个问题就是C库头文件问题。WRC不知道这些头文件在哪里。如果一个RC文件,他包含头文件的话,你将会得到一个”文件找不到”的错误。下面是解决这个问题的一些方法:

  • 被Winelib头文件传统上使用的解决办法就是在一个#ifndef RC_INVOKED语句上附上包含语句,RC_INVOKED是一个宏名称,是由wrc自动定义的。
  • 你也可以向wrc命令中添加一个或者是多个-I选项,这样他就能找到系统文件。举个例子,你可以添加-I/usr/include -I/usr/lib/gcc-lib/i386-linux/2.95.2/include来迎合C/C++头文件。

但这就会假设你知道这些头文件在哪里,这会降低你的makefile文件对其他平台的可移植性。或者是你可以使用C/C++编译器来运行预处理。为了能够这样做,你可以简单的修改你的makefile文件如下:

.rc.res:
    $(CC) $(CC_OPTS) -DRC_INVOKED -E -x c $< | $(WRC) -N $(WRCFLAGS) $(WINELIB_FLAGS) -o $@

第二个问题就是头文件可能会包含一些arc不能理解的结构。一个典型的例子就是一个返回const类型的函数。wrc期望的函数是两个标识符后跟一个左括号。如果带上const,就有三个标识符后跟一个左括号,因此wrc迷惑了(它实际上应该会忽略所有的windows资源编译器所做的事情)。解决的办法就是在#ifndef RC_INVOKED中添加一个违规语句。

在资源中使用GIF文件是有问题的。最好的结果就是,将他们转换成BMP文件或者是改变你的.res文件。

如果在你的资源文件中,你使用通用的控制/对话框的话,你需要在#include <windows.h>后面添加一个#include <commctrl.h>,这样wrc才能够明白控制专用标志的值。

(三):Spec文件

1:简介

在Windows中,应用和库包含了一些必要的使API能够工作的信息,例如GetProcAddress。所以说在Unix世界中,为了能够使Winelib应用和库以同样的API工作,重复这些数据结构是有必要的。

spec文件就是为了解决上面描述的语义上的差别的。他提供了从一个DLL提取出来的关于每一个API的信息,以使适当的表能够生成。后期这些信息被用于保存日志。

一个典型的spec文件看上去就像下面这样:

@ stdcall -private DllCanUnloadNow()
@ stdcall -private DllGetClassObject(ptr ptr ptr)
@ stdcall -private DllRegisterServer()
@ stdcall -private DllUnregisterServer()

2:更多细节

下面是对spec文件格式更加详细的描述。

# comment text

在’#’后面的任何数据都被认定为注释。

ORDINAL FUNCTYPE OPTIONS EXPORTNAME([ARGTYPE [ARGTYPE [...]]]) HANDLERNAME
@ stdcall CreateDesktopW(wstr wstr ptr long long ptr)
@ stdcall CM_Get_Parent(ptr long long) setupapi.CM_Get_Parent
@ cdecl -arch=x86_64 ceilf(float) MSVCRT_ceilf

这个域可以出现0次或者是多次。每一个实例定义一个函数入口点。被EXPORTNAME([ARGTYPE[ARGTYPE[…]]])定义的原型指定了用于动态链接和参数格式的可用的名称。ORDINAL被与之相对应的功能的序号所代替,或者是使用@进行自动的序号分配(仅仅用于win32)。FUNCTYPE应该是下面的一个:

  • pascal
  • 用于一个Win16函数
  • stdcall
  • 用于一个普通的Win32函数
  • cdecl
  • 用于使用C调用公约的Win32函数
  • varargs
  • 用于一个采用可变数量的参数的Win32函数
  • thiscall
  • 用于使用C++调用公约的Win32函数

    ARGTYPE应该是下面的一个:

  • word
  • 一个16位字
  • s_word
  • 16位的符号字
  • segptr
  • 用于一个分段指针
  • segstr
  • 用于一个指向空结束字符串的分段指针
  • long
  • 一个32位的值
  • ptr
  • 一个线性指针
  • str
  • 用于指向一个空结束字符串的线性指针
  • wstr
  • 用于一个空结束16位编码的字符串的线性指针
  • int64
  • 一个64位数
  • int128
  • 一个128位数
  • float
  • 一个32位浮点数
  • double
  • 一个64位浮点数

对于Wine32函数word,s_word,segptr和segstr是无效的。HANDLERNAME是真实的以32位模式处理需求的Wine函数的名称。Strings应该一直会映射到str,宽字符串会映射到watr。作为一个常用的规则,他依赖于参数是IN,OUT或者是IN/OUT。

  • IN: str/wstr
  • OUT: ptr
  • IN/OUT: str/wstr

这个是用于调试信息的。如果参数是OUT,他将不会被初始化,因此他也不会作为一个字符串被打印。

为了能够在Win16中使用一定数量的参数来声明一个函数,指定函数为无参数。参数将会在CURRENT_STACK16->args中可用。在Win32中,在C文件中指定函数为varargs或者是以”…”作为参数声明。可以查看位于user32.spec文件中的wsprintf*函数作为一个例子。

ORDINAL stub EXPORTNAME

这个域可以出现零次后者是更多次。每一个实例定义了一个stub函数。他使得动态链接中的序号可用,如果函数被调用了,一旦遇到错误信息就会终止运行。

ORDINAL extern EXPORTNAME SYMBOLNAME

这个域可以出现零次或多次。每一个实例都定义了一个映射到一个Wine符号(变量或函数)的条目;EXPORTNAME将会指向在C代码中定义的符号SYMBOLNAME。这个类型仅仅在Win32上工作。


(四):将他们链接到一块

为了成一个可执行程序,你需要链接这些文件:你的对象文件,任何你的应用程序依赖的Windows库,例如gdi32,和你使用的其他附加库。你要链接的所有的库应该是作为.so库可用的。如何他们仅仅在.dll下是可用的,那么请想看“构建Winelib DLLs”这一节。

当你尝试链接你的可执行程序的时候,你才会发现你的当前库中是否丢失符号。在Windows上,帮你构建库的时候,链接器就会立即告诉你一个符号是否未定义。在Unix和Winelib中,不是这样的。符号会被默默的被标注为未定义,只有当你尝试去构建一个可执行程序的时候,链接器才会验证所有的符号。

当首次转换一个库到Winelib成功之前,你应该尝试把他联街道一个可执行程序中。在这个时候,你可能就会发现一些你认为已经实现的未被定义的符号。然后,进入到库源码进行修改。但是你也可能会发现丢失的符号是被定义了的,就像gdi32。这是因为你并没有将gdi32和库链接。修复他的一个方式就是链接这个可执行程序,另外一个方式就是带着gdi32来使用你的库。最好的方式就是回到你的库的Makefile中,显式的将他和gdi32链接起来。

正如你要注意到的,对于Winelib所属库来说并没有完全实现。所以如果一个程序必须要链接ole32的话,你也需要和advapi32,rpcrt4和其他库链接,即使你并不直接使用他们。

为了成一个可执行程序,你需要链接这些文件:你的对象文件,任何你的应用程序依赖的Windows库,例如gdi32,和你使用的其他附加库。你要链接的所有的库应该是作为.so库可用的。如何他们仅仅在.dll下是可用的,那么请想看“构建Winelib DLLs”这一节。

当你尝试链接你的可执行程序的时候,你才会发现你的当前库中是否丢失符号。在Windows上,帮你构建库的时候,链接器就会立即告诉你一个符号是否未定义。在Unix和Winelib中,不是这样的。符号会被默默的被标注为未定义,只有当你尝试去构建一个可执行程序的时候,链接器才会验证所有的符号。

当首次转换一个库到Winelib成功之前,你应该尝试把他联街道一个可执行程序中。在这个时候,你可能就会发现一些你认为已经实现的未被定义的符号。然后,进入到库源码进行修改。但是你也可能会发现丢失的符号是被定义了的,就像gdi32。这是因为你并没有将gdi32和库链接。修复他的一个方式就是链接这个可执行程序,另外一个方式就是带着gdi32来使用你的库。最好的方式就是回到你的库的Makefile中,显式的将他和gdi32链接起来。

正如你要注意到的,对于Winelib所属库来说并没有完全实现。所以如果一个程序必须要链接ole32的话,你也需要和advapi32,rpcrt4和其他库链接,即使你并不直接使用他们。

目录
相关文章
|
1月前
|
监控 前端开发 数据可视化
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
@icraft/player-react 是 iCraft Editor 推出的 React 组件库,旨在简化3D数字孪生场景的前端集成。它支持零配置快速接入、自定义插件、丰富的事件和方法、动画控制及实时数据接入,帮助开发者轻松实现3D场景与React项目的无缝融合。
116 8
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
|
3月前
|
JavaScript
从零开始写一套广告组件【一】搭建基础框架并配置UI组件库
其实这个从零有点歧义,因为本质上是要基于`tdesign-vue-next`来进行二次封装为一套广告UI组件库,现在让我们在一起快乐的搭建自己的广告UI库之前,先对以下内容做出共识:
103 0
从零开始写一套广告组件【一】搭建基础框架并配置UI组件库
|
5月前
|
开发框架 前端开发 JavaScript
使用BootstrapVue相关组件,构建Vue项目界面
使用BootstrapVue相关组件,构建Vue项目界面
|
5月前
|
存储 开发框架 前端开发
Vue&Element开发框架中增加工作流处理,工作流的各个管理页面的界面处理
Vue&Element开发框架中增加工作流处理,工作流的各个管理页面的界面处理
|
5月前
|
Java 测试技术 开发者
开发与运维组件问题之开发组件的时候,对于插槽中需要使用到组件上下文的情况如何解决
开发与运维组件问题之开发组件的时候,对于插槽中需要使用到组件上下文的情况如何解决
|
7月前
|
前端开发 JavaScript
uniapp 创建组件
uniapp 创建组件
uniapp 创建组件
|
7月前
|
前端开发 JavaScript UED
前端UI组件
前端UI组件
125 0
|
JavaScript
【Vue】模板语法,事件处理器及综合案例、自定义组件、组件通信
组件(Component)是Vue最强大的功能之一组件可以扩展HTML元素,封装可重用的代码组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树。
|
移动开发 开发框架 JavaScript
什么是组件,以及前端各种框架组件的使用方法
什么是组件,以及前端各种框架组件的使用方法
579 1
|
人工智能 JavaScript 前端开发
如何开发一个人人爱的组件?
本篇文章类似一个菜谱,比较零碎的记录一些组件设计的内容,作者分别按照 1~5 星 区分其重要性。