Inside Wine; WINEDLLPATH

[目次] (https://qiita.com/Yutaka_Aoki/items/9d38ea98406f4096435b)

# Inside Wine; WINEDLLPATH

## WINEDLLPATH の不具合

調べてみると、/wine/libs/wine/loader.c の中の build_dll_path() 関数の中で、環境変数 WINEDLLPATH が、読み取られ、: を 0x00 に変えてから、dll_paths[] 配列に : で区切られたそれぞれの文字列の先頭アドレスを代入している。

しかし、その処理に入る前に、get_dlldir() 関数が NULL 以外を返した場合、dll_paths[0] にその関数が返した文字列のアドレスを入れてしまう。

そして、実際の get_dlldir() は、"/usr/local/bin/../lib/wine" という文字列を返してくるので、そっちのパスの方が、WINEDLLPATH の優先順位よりも上になってしまう。

get_dlldir() は、

```c:~/wine/libs/wine/config.c
/* retrieve the default dll dir */
const char *get_dlldir( const char **default_dlldir )
{
    *default_dlldir = DLLDIR;
    return dlldir;
}
```

となっているが、DLLDIR は、Makefile の中で、gcc に -D オプションによってコンパイル開始時の #define マクロ として文字列が渡されている。


## 修正箇所

`c:~/wine/libs/wine/loader.c` の build_dll_path() 関数を変更する。

make すると、`c:~/wine/libs/wine/` に `libwine.so.1.0`

が作成される。

これを、自分のアプリの場合にだけは使われるようにする。



## 旧関数

```c:~/wine/libs/wine/loader.c
/* build the dll load path from the WINEDLLPATH variable */
static void build_dll_path(void)
{
	int len, count = 0;
	char *p, *path = getenv( "WINEDLLPATH" );
	const char *dlldir = get_dlldir( &default_dlldir );

	if (path)
	{
		/* count how many path elements we need */
		path = strdup(path);
		p = path;
		while (*p)
		{
			while (*p == ':') p++;
			if (!*p) break;
			count++;
			while (*p && *p != ':') p++;
		}
	}

	dll_paths = malloc( (count+2) * sizeof(*dll_paths) );
	nb_dll_paths = 0;

	if (dlldir)
	{
		dll_path_maxlen = strlen(dlldir);
		dll_paths[nb_dll_paths++] = dlldir;
	}
	else if ((build_dir = wine_get_build_dir()))
	{
		dll_path_maxlen = strlen(build_dir) + sizeof("/programs");
	}

	if (count)
	{
		p = path;
		while (*p)
		{
			while (*p == ':') *p++ = 0;
			if (!*p) break;
			dll_paths[nb_dll_paths] = p;
			while (*p && *p != ':') p++;
			if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
				dll_path_maxlen = p - dll_paths[nb_dll_paths];
			nb_dll_paths++;
		}
	}

	/* append default dll dir (if not empty) to path */
	if ((len = strlen(default_dlldir)) > 0)
	{
		if (len > dll_path_maxlen) dll_path_maxlen = len;
		dll_paths[nb_dll_paths++] = default_dlldir;
	}
}
```

## 新関数

```c:~/wine/libs/wine/loader.c
/* build the dll load path from the WINEDLLPATH variable */
static void build_dll_path(void)
{
	int len, count = 0;
	char *p, *path = getenv( "WINEDLLPATH" );
	const char *dlldir = get_dlldir( &default_dlldir );
	
	if (path)
	{
		/* count how many path elements we need */
		path = strdup(path);
		p = path;
		while (*p)
		{
			while (*p == ':') p++;
			if (!*p) break;
			count++;
			while (*p && *p != ':') p++;
		}
	}

	dll_paths = malloc( (count+2) * sizeof(*dll_paths) );
	nb_dll_paths = 0;
	
	dll_path_maxlen		= 0;
	
	if (count)
	{
		p = path;
		while (*p)
		{
			while (*p == ':') *p++ = 0;
			if (!*p) break;
			dll_paths[nb_dll_paths] = p;
			while (*p && *p != ':') p++;
			if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
				dll_path_maxlen = p - dll_paths[nb_dll_paths];
			nb_dll_paths++;
		}
	}
	
	if (dlldir) {
		int		len		= strlen(dlldir);
		if ( len > dll_path_maxlen ) {
			dll_path_maxlen		= len;
		}
		dll_paths[nb_dll_paths++] = dlldir;
	}
	else if ((build_dir = wine_get_build_dir())) {
		int		len		= strlen(build_dir) + sizeof("/programs");
		if ( len > dll_path_maxlen ) {
			dll_path_maxlen		= len;
		}
	}
	
	/* append default dll dir (if not empty) to path */
	if ((len = strlen(default_dlldir)) > 0) {
		if (len > dll_path_maxlen) {
			dll_path_maxlen		= len;
		}
		dll_paths[nb_dll_paths++]	= default_dlldir;
	}
	
	#if 1
	int		cnt;
	for ( cnt = 0; cnt < nb_dll_paths; cnt++ ) {
		fprintf( stderr, "%d: %s\n", cnt, dll_paths[cnt] );
	}
	#endif
}
```


### 以下のようなスクリプトを作っておく。

自分のアプリを実行する前に、

```
$ . myenv
```

として、先頭に 「.」を付けて環境変数が設定されるようにする。

export LD_LIBRARY_PATH=.

によって、カレント・ディレクトリにある、`libwine.so.1`

が探されるようになる。

```
$ ln -s /media/Yyyy/my_winedev/wine/libs/wine/libwine.so.1.0 libwine.so.1
```

などとして、カレント・ディレクトリに本体へのリンクを作っておく。

パスに付いては、詳細は省略する。以下のスクリプトは自分の場合。

WINEDLLPATH の設定の仕方は、ソースを検索すると、英語だが、自然言語で書かれているので読む。


```sh:myenv
#!/bin/sh

#
# $ . myenv [ret]
#
# として読みこます事。冒頭の「. 」(ドットと空白) が重要
#

PATH=/media/Yyyy/my_winedev/bin2/bin:$PATH

DLL=/media/Yyyy/my_winedev/wine/dlls

WINEDLLPATH=$DLL/winex11.drv
WINEDLLPATH+=:$DLL/gdi32
WINEDLLPATH+=:$DLL/user32
WINEDLLPATH+=:/media/Yyyy/my_winedev/bin2/lib/wine

export WINEDLLPATH

export WINESERVER=/media/Yyyy/my_winedev/wine/server/wineserver

export LD_LIBRARY_PATH=.
```