使用winelib在linux下调用DLL
相信Wine这个工具对很多使用linux系统的人来说都不会陌生,它能帮你在Linux环境下直接运行windows程序(目前还不能做到100%支持)。但是很少有人知道wine所附带的开发工具winelib,它现在已经是用来编译Wine本身的工具了。使用winelib,我们可以编译可以使wine来加载的程序,这个程序既可以调用Linux下的POSIX库,也可以调用windows的system call。那么,我们就可以用winelib来编译一个需要调用windows环境的dll,但是在Linux环境下运行的程序。
使用winelib来编译调用了dll的程序在源代码上,与为windows环境写的那种是一样的,唯一不同的是其编译方式。在这里我们有一个dll文件junk.dll,使用winedump工具对其进行解析:
Contents of junk.dll: 14168 bytes
1 named symbols in DLL, 1 total, 1 unique (ordinal base = 1)
Done dumping junk.dll
Export 1 - 'HelloWorld' ... [Ignoring]
从winedump的运行结果可以看出,这个dll里面包含了一个名为HelloWorld的函数可供调用。同时会生成一份.spec文件(在这里就是junk.spec),里面记录了该DLL内可调用的函数名(不保含其原型)。
这个HelloWorld函数的实现是:
2 {
3 MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
4 printf("%s\n","Test");
5 }
也就是调用windows的消息框显示一段信息,之后在标准输出流打印出Test。
现在我们写一个调用该DLL并使用这个HelloWorld函数的演示程序,代码文件junk.c:
02 #include <stdio.h>
03 #include <windows.h>
04 int main(int argc, char* argv[])
05 {
06 char bufr[256];
07 HANDLE h;
08 void (/*WINAPI?*/ *say)(void);
09
10 gethostname(bufr, sizeof(bufr));
11 strcat(bufr, " says, 'Howdy World!'");
12 MessageBox(NULL, bufr, "Junk", MB_OK);
13
14 h = LoadLibrary("junk.dll");
15 if(!h) exit(1);
16 say = GetProcAddress(h, "HelloWorld");
17 //say = GetProcAddress(h, MAKEINTRESOURCE(1));
18
19 sprintf(bufr,"%d",say);
20 MessageBox(NULL, bufr, "Junk", MB_OK);
21 say();
22
23 return(0);
24 }
这里可以看到,这个程序加载了junk.dll,获取了HelloWorld这个函数的地址,并执行了这个程序。接下来让我们编译这个程序,使用这个命令:winegcc -o junk junk.c ,这样就生成了两个文件:junk.exe和junk.exe.so,其中junk.exe是一个shell脚本,它会调用wine来加载junk.exe.so,junk.exe.so就是wine所要加载的二进制程序,所以我们可以用两种方式来运行这个程序,一种就是直接命令调用:$./junk.exe,另一种就是通过wine加载调用:$wine junk.exe.so。如无意外,这个程序会弹出三个windows风格的消息框,一个用机器的名义和你say "Howdy World!",第二个输出HelloWorld这个函数的地址,最后一个是这个函数中调用的消息框。
这里说一下winegcc,它是winelib在gcc编译器上的一层封装,使其能编译出能给wine加载的二进制程序,用法和普通的gcc类似。而wineg++就是对g++编译器的封装,用法也和g++差不多。