Skip to content

Commit

Permalink
Merge pull request #1649 from heinezen/fix/python-windows-dll
Browse files Browse the repository at this point in the history
Enhance DLL search on Windows
  • Loading branch information
TheJJ committed May 23, 2024
2 parents 1904244 + e5311c1 commit aff3f73
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 57 deletions.
30 changes: 11 additions & 19 deletions openage/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,27 +31,15 @@ def print_version():
sys.exit(0)


def add_dll_search_paths(dll_paths):
def add_dll_search_paths(dll_paths: list[str]):
"""
This function adds DLL search paths.
This function does nothing if current OS is not Windows.
"""
from .util.dll import DllDirectoryManager

def close_windows_dll_path_handles(dll_path_handles):
"""
This function calls close() method on each of the handles.
"""
for handle in dll_path_handles:
handle.close()
manager = DllDirectoryManager(dll_paths)

if sys.platform != 'win32' or dll_paths is None:
return

import atexit
win_dll_path_handles = []
for addtional_path in dll_paths:
win_dll_path_handles.append(os.add_dll_directory(addtional_path))
atexit.register(close_windows_dll_path_handles, win_dll_path_handles)
return manager


def main(argv=None):
Expand All @@ -62,11 +50,11 @@ def main(argv=None):
)

if sys.platform == 'win32':
import inspect
from .util.dll import default_paths
cli.add_argument(
"--add-dll-search-path", action='append', dest='dll_paths',
# use path of current openage executable as default
default=[os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: 0)))],
default=default_paths(),
help="(Windows only) provide additional DLL search path")

cli.add_argument("--version", "-V", action='store_true', dest='print_version',
Expand Down Expand Up @@ -141,8 +129,10 @@ def main(argv=None):

args = cli.parse_args(argv)

dll_manager = None
if sys.platform == 'win32':
add_dll_search_paths(args.dll_paths)
dll_manager = add_dll_search_paths(args.dll_paths)
dll_manager.add_directories()

if args.print_version:
print_version()
Expand All @@ -151,6 +141,8 @@ def main(argv=None):
# the user didn't specify a subcommand. default to 'main'.
args = main_cli.parse_args(argv)

args.dll_manager = dll_manager

# process the shared args
set_loglevel(verbosity_to_level(args.verbose - args.quiet))

Expand Down
69 changes: 32 additions & 37 deletions openage/convert/processor/export/media_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import os
import multiprocessing
import queue
import sys

from openage.convert.entity_object.export.texture import Texture
from openage.convert.service import debug_info
Expand All @@ -27,6 +28,7 @@
from openage.convert.value_object.read.media.colortable import ColorTable
from openage.convert.value_object.init.game_version import GameVersion
from openage.util.fslike.path import Path
from openage.util.dll import DllDirectoryManager


class MediaExporter:
Expand Down Expand Up @@ -126,7 +128,8 @@ def export(
handle_outqueue_func,
itargs,
kwargs,
args.jobs
args.jobs,
args.dll_manager,
)

if args.debug_info > 5:
Expand Down Expand Up @@ -198,6 +201,7 @@ def _export_singlethreaded(
idx,
source_data,
single_queue,
None,
request.source_filename,
target_path,
*itargs,
Expand Down Expand Up @@ -225,7 +229,8 @@ def _export_multithreaded(
handle_outqueue_func: typing.Callable | None,
itargs: tuple,
kwargs: dict,
job_count: int = None
job_count: int = None,
dll_manager: DllDirectoryManager = None,
):
"""
Export media files in multiple threads.
Expand All @@ -241,15 +246,7 @@ def _export_multithreaded(
:param itargs: Arguments for the export function.
:param kwargs: Keyword arguments for the export function.
:param job_count: Number of worker processes to use.
:type requests: list[MediaExportRequest]
:type sourcedir: Path
:type exportdir: Path
:type read_data_func: typing.Callable
:type export_func: typing.Callable
:type handle_outqueue_func: typing.Callable
:type itargs: tuple
:type kwargs: dict
:type job_count: int
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
"""
worker_count = job_count
if worker_count is None:
Expand Down Expand Up @@ -297,6 +294,7 @@ def error_callback(exception: Exception):
idx,
source_data,
outqueue,
dll_manager,
request.source_filename,
target_path,
*itargs
Expand Down Expand Up @@ -625,6 +623,7 @@ def _export_blend(
request_id: int,
blendfile_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str, # pylint: disable=unused-argument
targetdir: Path,
target_filename: str,
Expand All @@ -633,15 +632,16 @@ def _export_blend(
"""
Convert and export a blending mode.
:param request_id: ID of the export request.
:param blendfile_data: Raw file data of the blending mask.
:param outqueue: Queue for passing metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param target_path: Path to the resulting image file.
:param blend_mode_count: Number of blending modes extracted from the source file.
:type blendfile_data: bytes
:type outqueue: multiprocessing.Queue
:type target_path: openage.util.fslike.path.Path
:type blend_mode_count: int
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

blend_data = Blendomatic(blendfile_data, blend_mode_count)

from .texture_merge import merge_frames
Expand All @@ -661,20 +661,23 @@ def _export_sound(
request_id: int,
sound_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str, # pylint: disable=unused-argument
target_path: Path,
**kwargs # pylint: disable=unused-argument
) -> None:
"""
Convert and export a sound file.
:param request_id: ID of the export request.
:param sound_data: Raw file data of the sound file.
:param outqueue: Queue for passing metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param target_path: Path to the resulting sound file.
:type sound_data: bytes
:type outqueue: multiprocessing.Queue
:type target_path: openage.util.fslike.path.Path
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

from ...service.export.opus.opusenc import encode
encoded = encode(sound_data)

Expand All @@ -691,6 +694,7 @@ def _export_terrain(
request_id: int,
graphics_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str,
target_path: Path,
palettes: dict[int, ColorTable],
Expand All @@ -700,21 +704,19 @@ def _export_terrain(
"""
Convert and export a terrain graphics file.
:param request_id: ID of the export request.
:param graphics_data: Raw file data of the graphics file.
:param outqueue: Queue for passing the image metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param source_filename: Filename of the source file.
:param target_path: Path to the resulting image file.
:param palettes: Palettes used by the game.
:param compression_level: PNG compression level for the resulting image file.
:param game_version: Game edition and expansion info.
:type graphics_data: bytes
:type outqueue: multiprocessing.Queue
:type source_filename: str
:type target_path: openage.util.fslike.path.Path
:type palettes: dict
:type compression_level: int
:type game_version: GameVersion
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

file_ext = source_filename.split('.')[-1].lower()
if file_ext == "slp":
from ...value_object.read.media.slp import SLP
Expand Down Expand Up @@ -758,6 +760,7 @@ def _export_texture(
request_id: int,
graphics_data: bytes,
outqueue: multiprocessing.Queue,
dll_manager: DllDirectoryManager,
source_filename: str,
target_path: Path,
palettes: dict[int, ColorTable],
Expand All @@ -770,20 +773,16 @@ def _export_texture(
:param request_id: ID of the export request.
:param graphics_data: Raw file data of the graphics file.
:param outqueue: Queue for passing the image metadata to the main process.
:param dll_manager: Adds DLL search paths for the subrocesses (Windows-only).
:param source_filename: Filename of the source file.
:param target_path: Path to the resulting image file.
:param palettes: Palettes used by the game.
:param compression_level: PNG compression level for the resulting image file.
:param cache_info: Media cache information with compression parameters from a previous run.
:type request_id: int
:type graphics_data: bytes
:type outqueue: multiprocessing.Queue
:type source_filename: str
:type target_path: openage.util.fslike.path.Path
:type palettes: dict
:type compression_level: int
:type cache_info: tuple
"""
if sys.platform == "win32" and dll_manager is not None:
dll_manager.add_directories()

file_ext = source_filename.split('.')[-1].lower()
if file_ext == "slp":
from ...value_object.read.media.slp import SLP
Expand Down Expand Up @@ -844,10 +843,6 @@ def _save_png(
:param target_path: Path to the resulting image file.
:param compression_level: PNG compression level used for the resulting image file.
:param dry_run: If True, create the PNG but don't save it as a file.
:type texture: Texture
:type target_path: openage.util.fslike.path.Path
:type compression_level: int
:type dry_run: bool
"""
from ...service.export.png import png_create

Expand Down
8 changes: 7 additions & 1 deletion openage/convert/tool/singlefile.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Copyright 2015-2023 the openage authors. See copying.md for legal info.
# Copyright 2015-2024 the openage authors. See copying.md for legal info.

"""
Convert a single slp/wav file from some drs archive to a png/opus file.
"""
from __future__ import annotations

import sys

from pathlib import Path

Expand Down Expand Up @@ -59,6 +60,11 @@ def main(args, error):
file_path = Path(args.filename)
file_extension = file_path.suffix[1:].lower()

if sys.platform == "win32":
from openage.util.dll import DllDirectoryManager, default_paths
dll_manager = DllDirectoryManager(default_paths())
dll_manager.add_directories()

if not (args.mode in ("sld", "drs-wav", "wav") or file_extension in ("sld", "wav")):
if not args.palettes_path:
raise RuntimeError("palettes-path needs to be specified for "
Expand Down
1 change: 1 addition & 0 deletions openage/util/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_py_modules(
bytequeue.py
context.py
decorators.py
dll.py
files.py
fsprinting.py
hash.py
Expand Down

0 comments on commit aff3f73

Please sign in to comment.