Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

d3d9-nine: introduce forwarder DLL #155

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions d3d9-nine/d3d9-nine-forwarder.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
@ stdcall Direct3DShaderValidatorCreate9() d3d9-nine.Direct3DShaderValidatorCreate9
@ stdcall PSGPError() d3d9-nine.PSGPError
@ stdcall PSGPSampleTexture() d3d9-nine.PSGPSampleTexture
@ stdcall D3DPERF_BeginEvent(long wstr) d3d9-nine.D3DPERF_BeginEvent
@ stdcall D3DPERF_EndEvent() d3d9-nine.D3DPERF_EndEvent
@ stdcall D3DPERF_GetStatus() d3d9-nine.D3DPERF_GetStatus
@ stdcall D3DPERF_QueryRepeatFrame() d3d9-nine.D3DPERF_QueryRepeatFrame
@ stdcall D3DPERF_SetMarker(long wstr) d3d9-nine.D3DPERF_SetMarker
@ stdcall D3DPERF_SetOptions(long) d3d9-nine.D3DPERF_SetOptions
@ stdcall D3DPERF_SetRegion(long wstr) d3d9-nine.D3DPERF_SetRegion
@ stdcall DebugSetLevel() d3d9-nine.DebugSetLevel
@ stdcall DebugSetMute() d3d9-nine.DebugSetMute
@ stdcall Direct3DCreate9(long) d3d9-nine.Direct3DCreate9
@ stdcall Direct3DCreate9Ex(long ptr) d3d9-nine.Direct3DCreate9Ex
Binary file added d3d9-nine/d3d9-nine-forwarder32.dll
Binary file not shown.
Binary file added d3d9-nine/d3d9-nine-forwarder64.dll
Binary file not shown.
43 changes: 43 additions & 0 deletions d3d9-nine/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,46 @@ d3d9_fake = shared_library(
name_suffix : 'dll.fake',
install : true,
)

if wine_version.version_compare('>= 7.3')
d3d9_forwarder_builtin = shared_library(
'd3d9-nine-forwarder',
[
d3d9_res,
],
name_prefix : '',
name_suffix : 'dll.builtin',
install : false,
vs_module_defs : 'd3d9-nine-forwarder.spec',
objects : 'd3d9-nine-forwarder.spec',
link_args : [
'-Wb,--data-only',
'-Wb,--filename=d3d9',
],
)

# Wine checks for a string in the header to identify builtin DLLs.
# Work around this with a simple substitution.
d3d9_forwarder = custom_target(
'd3d9-nine-forwarder.dll',
input : d3d9_forwarder_builtin,
output : 'd3d9-nine-forwarder.dll',
install : false,
command : [
sed,
'-e', 's|Wine builtin DLL|Nine forwarder |',
'@INPUT@',
],
capture : true,
)
else
# Support for building data-only modules was added in wine 7.3.
# For binary releases, use a prebuilt version (without resources).
# This is a small (8KiB) and reproducible file that contains
# no executable code, so it shouldn't be a problem.
if target_machine.cpu_family() == 'x86_64'
d3d9_forwarder = files('d3d9-nine-forwarder64.dll')
else
d3d9_forwarder = files('d3d9-nine-forwarder32.dll')
endif
endif
12 changes: 11 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,20 @@ wrc = [
'-DNINE_REVISION=' + version[3],
'-DNINE_VERSION="v' + meson.project_version() + '"',
'-DNINE_PROJECT="' + meson.project_name() + '"',
'-i', '@INPUT@',
'-i', '@INPUT0@',
'-o', '@OUTPUT@',
]

wine_version = run_command(
[
find_program('winebuild'),
'--version',
],
check : true,
).stdout().split()[-1]

sed = find_program('sed')

if cc.has_function('dlopen')
dep_dl = null_dep
else
Expand Down
99 changes: 79 additions & 20 deletions ninewinecfg/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <wctype.h>

Expand All @@ -29,6 +30,13 @@
#include "resource.h"

static const char * const fn_nine_dll = "d3d9-nine.dll";
static const char * const fn_forwarder_dll = "d3d9-nine-forwarder.dll";
static const char * const fn_nine_symlinks[] = {
fn_forwarder_dll,
fn_nine_dll, /* Unix module installed to the prefix */
"d3d9-nine.dll.so", /* System install or WINEDLLPATH */
};
static const size_t fn_nine_symlinks_len = sizeof(fn_nine_symlinks) / sizeof(fn_nine_symlinks[0]);
static const char * const fn_backup_dll = "d3d9-nine.bak";
static const char * const fn_d3d9_dll = "d3d9.dll";
static const char * const fn_nine_exe = "ninewinecfg.exe";
Expand Down Expand Up @@ -245,6 +253,7 @@ static BOOL create_symlink(LPCSTR target, LPCSTR filename)

static BOOL is_nine_symlink(LPCSTR filename)
{
int i;
ssize_t ret;
char *fn = unix_filename(filename);
CHAR buf[MAX_PATH];
Expand All @@ -253,11 +262,22 @@ static BOOL is_nine_symlink(LPCSTR filename)
return FALSE;

ret = readlink(fn, buf, sizeof(buf));
if ((ret < strlen(fn_nine_dll)) || (ret == sizeof(buf)))
if (ret == sizeof(buf))
return FALSE;

buf[ret] = 0;
return !strcmp(buf + ret - strlen(fn_nine_dll), fn_nine_dll);

for (i = 0; i < fn_nine_symlinks_len; i++)
{
const char * const name = fn_nine_symlinks[i];
size_t len = strlen(name);
if (ret < len)
continue;

if (!strcmp(buf + ret - len, name))
return TRUE;
}

return FALSE;
}

static BOOL nine_get_system_path(CHAR *pOut, DWORD SizeOut)
Expand Down Expand Up @@ -345,6 +365,56 @@ static BOOL nine_get(void)
return is_nine_symlink(buf) && file_exist(buf, FALSE);
}

static BOOL nine_install_forwarder(void)
{
BOOL ret = TRUE;
HGLOBAL res_handle = NULL;
HRSRC res;
char * res_data;
DWORD res_size;
CHAR buf[MAX_PATH];
char * unix_path;
FILE * dll_handle;

if (!nine_get_system_path(buf, sizeof(buf)))
{
ERR("Failed to get system path\n");
return FALSE;
}
strcat(buf, "\\");
strcat(buf, fn_forwarder_dll);
unix_path = unix_filename(buf);
if (!unix_path)
return FALSE;

if (!(res = FindResourceA(NULL, MAKEINTRESOURCE(ID_FORWARDER_DLL), RT_RCDATA)))
abort();
if (!(res_handle = LoadResource(NULL, res)))
abort();
res_data = LockResource(res_handle);
res_size = SizeofResource(NULL, res);

if ((dll_handle = fopen(unix_path, "wb")) == NULL)
{
ERR("Failed to open %s (%s): %s\n", buf, unix_path, strerror(errno));
ret = FALSE;
goto done;
}

if (fwrite(res_data, 1, res_size, dll_handle) != res_size)
{
ERR("Failed to write forwarder: %s\n", strerror(errno));
ret = FALSE;
goto close_dll;
}

close_dll:
fclose(dll_handle);
done:
HeapFree(GetProcessHeap(), 0, unix_path);
return ret;
}

static void nine_set(BOOL status, BOOL NoOtherArch)
{
CHAR dst[MAX_PATH], dst_back[MAX_PATH];
Expand Down Expand Up @@ -386,7 +456,11 @@ static void nine_set(BOOL status, BOOL NoOtherArch)

if (status)
{
HMODULE hmod;
if (!nine_install_forwarder())
{
ERR("Failed to install forwarder\n");
return;
}

/* Sanity: Always recreate symlink */
if (file_exist(dst, TRUE))
Expand All @@ -397,22 +471,7 @@ static void nine_set(BOOL status, BOOL NoOtherArch)
remove_file(dst);
}

hmod = LoadLibraryExA(fn_nine_dll, NULL, DONT_RESOLVE_DLL_REFERENCES);
if (hmod)
{
Dl_info info;

if (dladdr(hmod, &info) && info.dli_fname)
create_symlink(info.dli_fname, dst);
else
ERR("dladdr failed to get file path\n");

FreeLibrary(hmod);
} else {
LPWSTR msg = load_message(GetLastError());
ERR("Couldn't load %s: %s\n", fn_nine_dll, nine_dbgstr_w(msg));
LocalFree(msg);
}
create_symlink(fn_forwarder_dll, dst);
} else {
if (is_nine_symlink(dst))
{
Expand Down
9 changes: 7 additions & 2 deletions ninewinecfg/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

ninewinecfg_res = custom_target(
'ninewinecfg.res',
input : 'ninewinecfg.rc',
input : [
'ninewinecfg.rc',
d3d9_forwarder,
],
output : 'ninewinecfg.res',
depend_files : [
'resource.h',
'ninewinecfg.manifest',
'nls/',
],
command : wrc,
command : wrc + [
'-D_FORWARDER_DLL="@INPUT1@"',
],
)

ninewinecfg_exe = executable(
Expand Down
2 changes: 2 additions & 0 deletions ninewinecfg/ninewinecfg.rc
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,5 @@ FILESUBTYPE VFT2_UNKNOWN
}

1 RT_MANIFEST ninewinecfg.manifest

ID_FORWARDER_DLL RCDATA _FORWARDER_DLL
2 changes: 2 additions & 0 deletions ninewinecfg/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,6 @@
#define IDS_ERR_OUTOFMEMORY 101
#define IDS_ERR_D3D_NOTAVAILABLE 102

#define ID_FORWARDER_DLL 200

#endif /* __NINECFG_RESOURCE_H */