(八):構建WineLib DLL

(一):介紹


出於某些原因,你可能會發現你想要和使用Windows DLL一樣使用你的Linux庫.對於這有一些原因如下:

  • 你正在支持一個使用多個第三方庫的大應用.該項目在Linux中是可用的,但是你還沒有準備直接鏈接到他作爲一個Linux共享庫.

  • 有一個定義好的可用的接口,並且有很多用於接口的解決辦法.

  • 你僅僅有一個二進制Windows應用,他可以通過插件擴展,例如文本編輯器或IDE.

處理這些問題的過程是非常簡單的.你需要編寫一個spec文件,該文件以相同的格式描述庫接口作爲一個DLL.當然,你可能希望爲庫編寫一個小的封裝.你組合他們形成一個Wine內置的鏈接到Linux庫的DLL.然後你在wine配置中修改theDllOverrides來確保這個新內置的DLL被調用,而不是任何的Windows版本.

在這個小節中,我們將會看到兩個例子程序.第一個例子是非常簡單的,並且在”baby steps”中引入主題.都二個例子是在Wine中ODBC的接口代理.我們將要位ODBC例子引用的文件位於Wine源碼的dlls/odbc32目錄中.

第一個例子是基於一個情況(例如,函數的名稱已經被改變了來保護無辜的函數).大量的Windows應用包含鏈接到第三方DLL的DLL.出於一些原因,第三方DLL在Wine中運行不是很好.然後,第三方庫在Linux環境中也是可用的.方便的是,DLL和Linux共享庫只有一小部分功能,並且應用只用使用其中的一個.

特別的,應用調用一個函數:

signed short WINAPI MyWinFunc (unsigned short a, void *b, void *c,unsigned long *d, void *e, int f, char g, unsigned char *h);

linux庫包含一個相應的函數:

signed short MyLinuxFunc (unsigned short a, void *b, void *c,unsigned short *d, void *e, char g, unsigned char *h);

(二):編寫spec文件


通過編寫spec文件開始.這個文件描述接口,好像他是DLL一樣.

在這個簡單的例子中,我們想要一個Wine內置的DLL和MyWin DLL相對應.spec文件是MyWin.dll.spec,並且看上去像這:

#
# File: MyWin.dll.spec
#
# some sort of copyright
#
# Wine spec file for the MyWin.dll built-in library (a minimal wrapper around the
# linux library libMyLinux)
#
# For further details of wine spec files see the Winelib documentation at
# www.winehq.org

2 stdcall MyWinFunc (long ptr ptr ptr ptr long long ptr) MyProxyWinFunc

# End of file

注意,參數被標記成了long,即使他們比那個要小.通過這個例子,我們將直接鏈接到Linux共享庫,而通過ODBC這個例子,我們將動態加載Linux共享庫.

在ODBC例子中,你可以在文件odbc32.spec中看到這些.

(三):編寫一個封裝


首先,我們將要看一個簡單的例子.這個例子主要的問題就是優點不同的參數列表.f參數不必傳遞給Linux函數,並且d參數理論上需要從unsigned long *unsigned short *之間轉換.這麼做是爲了確保高位的返回值被正確設置.也不像ODBC例子一樣,我們將要直接鏈接到Linux的共享庫上.

/*
 * File: MyWin.c
 *
 * Copyright (c) The copyright holder.
 *
 * Basic Wine wrapper for the Linux 3rd party library so that it can be
 * used by the application
 *
 * Currently this file makes no attempt to be a full wrapper for the 3rd
 * party library; it only exports enough for our own use.
 *
 * Note that this is a Unix file; please don't go converting it to DOS format
 * (e.g. converting line feeds to Carriage return/Line feed).
 *
 * This file should be built in a Wine environment as a Winelib library,
 * linked to the Linux 3rd party libraries (currently libxxxx.so and
 * libyyyy.so)
 */

#include <3rd party linux header>
#include <windef.h> /* Part of the Wine header files */

/* This declaration is as defined in the spec file.  It is deliberately not
 * specified in terms of 3rd party types since we are messing about here
 * between two operating systems (making it look like a Windows thing when
 * actually it is a Linux thing).  In this way the compiler will point out any
 * inconsistencies.
 * For example the fourth argument needs care
 */
signed short WINAPI MyProxyWinFunc (unsigned short a, void *b, void *c,unsigned long *d, void *e, int f, char g, unsigned char *h)
{
    unsigned short d1;
    signed short ret;

    d1 = (unsigned short) *d;
    ret = 3rd party linux function (a, b, c, &d1, e, g, h);
    *d = d1;

    return ret;
}

/* End of file */

對於一個更廣泛的情況,我們可以使用ODBC例子.這個被實現位一個頭文件(proxyodbc.h)和一個C源碼文件(proxyodbc.c).雖然文件非常長,但是在結構上非常簡單.

DllMain函數用於初始化DLL.在過程附加事件中,函數動態鏈接到期望的Linux ODBC庫中(因爲有若干個可用的),並且構建一系列的函數指針.在過程解附加事件中,他解除鏈接.

然後每一個函數通過在初始化過程中設置的函數指針調用適當的Linux函數.

(四):構建


那麼我們如何構建一個Wine內置的DLL呢?最簡單的方法就是使winemaker來爲我們做這些複雜的工作.舉個簡單例子,我們有兩個源碼文件(封裝和spec文件).我們也有第三方頭文件和庫文件.

將這兩個源文件放到一個合適的目錄中,然後使用winemaker來創建構建框架,包括配置腳本,makefile等等.你可能希望使用下面的選項:

  • --nosource-fix (需要winemaker的版本爲0.5或更新)來確保兩個文件未被修改(如果使用了一個較低版本,使這兩個文件只讀,並且忽略不能修改他們的投訴).

  • --dll --single-target MyWin --nomfc 來指定目標

  • --DMightNeedSomething -I3rd_party_include -L3rd_party_lib -lxxxx -lyyyy 這些頭文件的位置等

在運行winemaker之後,我可以僅僅在定義之前編輯Makefile,向其中添加一行CEXTRA = -Wall.

然後就是簡單的運行confugure和make即可.

(五):安裝


那麼我們如何安裝代理,並且確保每個事物都連接正確呢?在這個事情上有很大的靈活性,所以需要遵循的不是唯一可行的選項.

確保Linux共享對象放到了Linux系統能夠找到的地方.這就意味着他應該被放在在/etc/ld.so.conf文件中提及的目錄中的一箇中或者是在LD_LIBRARY_PATH指定的路徑下面.如果你能從Linux程序中鏈接到他,應該也是可以的.

講代理共享對象(MyWin.dll.so)放到相同的位置作爲內置DLL的其他部分.確保WINEDLLPATH包含有代理共享對象的目錄.

如果你既有Windows DLL也有一個Linux DLL/代理對,那麼你必須確保有正確的一個得到調用.最簡單的方法就是重命名Windows版本,使他不被檢測到.你可以使用winecfg設置一個DLL重寫,這樣內置版本就會被使用.

一旦你這樣做了,你就應該成功的使用Linux共享對象了.如果你有問題,然後在運行wine之前設置 WINEDEBUG=+module環境變量來查看真正發生了什麼.

(六):轉換文件名


假設你想要轉換傳入的DOS格式的文件名稱到他們等效的Unix格式.當然,在微軟的Windows API中沒有合適的函數,但是wine提供了一個用於這個工作的函數,並且從kernel32 DLL的拷貝中導出的.這個函數就是wine_get_unix_file_name(定義在winbase.h)中.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章