mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
Update check_deps.py
This commit is contained in:
@@ -1,57 +1,168 @@
|
|||||||
import subprocess
|
import ctypes
|
||||||
import sys
|
import ctypes.wintypes
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import struct
|
||||||
|
|
||||||
def check_dll_dependencies(dll_path):
|
# Windows API constants
|
||||||
"""Check DLL dependencies using objdump or dumpbin"""
|
LOAD_LIBRARY_AS_DATAFILE = 0x00000002
|
||||||
|
DONT_RESOLVE_DLL_REFERENCES = 0x00000001
|
||||||
|
|
||||||
|
def check_dll_architecture(dll_path):
|
||||||
|
"""Check if DLL is 32-bit or 64-bit"""
|
||||||
|
try:
|
||||||
|
with open(dll_path, 'rb') as f:
|
||||||
|
# Read DOS header
|
||||||
|
dos_header = f.read(64)
|
||||||
|
if dos_header[:2] != b'MZ':
|
||||||
|
return "Not a valid PE file"
|
||||||
|
|
||||||
|
# Get PE header offset
|
||||||
|
pe_offset = struct.unpack('<L', dos_header[60:64])[0]
|
||||||
|
f.seek(pe_offset)
|
||||||
|
|
||||||
|
# Read PE signature and COFF header
|
||||||
|
pe_sig = f.read(4)
|
||||||
|
if pe_sig != b'PE\x00\x00':
|
||||||
|
return "Not a valid PE file"
|
||||||
|
|
||||||
|
machine = struct.unpack('<H', f.read(2))[0]
|
||||||
|
|
||||||
|
if machine == 0x014c:
|
||||||
|
return "32-bit (i386)"
|
||||||
|
elif machine == 0x8664:
|
||||||
|
return "64-bit (AMD64)"
|
||||||
|
else:
|
||||||
|
return f"Unknown architecture (0x{machine:04x})"
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return f"Error reading file: {e}"
|
||||||
|
|
||||||
|
def check_dll_dependencies_windows(dll_path):
|
||||||
|
"""Check DLL dependencies using Windows API"""
|
||||||
|
|
||||||
print(f"Analyzing: {dll_path}")
|
print(f"Analyzing: {dll_path}")
|
||||||
|
|
||||||
# Try objdump first (from MinGW tools)
|
if not os.path.exists(dll_path):
|
||||||
objdump_cmd = "x86_64-w64-mingw32-objdump"
|
|
||||||
try:
|
|
||||||
result = subprocess.run([objdump_cmd, "-p", dll_path],
|
|
||||||
capture_output=True, text=True, check=True)
|
|
||||||
print("\n=== DLL Dependencies ===")
|
|
||||||
lines = result.stdout.split('\n')
|
|
||||||
in_imports = False
|
|
||||||
for line in lines:
|
|
||||||
if "DLL Name:" in line:
|
|
||||||
print(f" -> {line.strip()}")
|
|
||||||
elif "The Import Tables" in line:
|
|
||||||
in_imports = True
|
|
||||||
elif in_imports and line.strip().startswith("DLL Name:"):
|
|
||||||
print(f" -> {line.strip()}")
|
|
||||||
|
|
||||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
||||||
print("objdump not available, trying alternative methods...")
|
|
||||||
|
|
||||||
# Check if file exists and basic info
|
|
||||||
if os.path.exists(dll_path):
|
|
||||||
size = os.path.getsize(dll_path)
|
|
||||||
print(f"\nDLL Size: {size} bytes")
|
|
||||||
else:
|
|
||||||
print(f"ERROR: {dll_path} not found!")
|
print(f"ERROR: {dll_path} not found!")
|
||||||
|
return
|
||||||
|
|
||||||
def check_exports(dll_path):
|
# Check basic file info
|
||||||
"""Check exported functions"""
|
size = os.path.getsize(dll_path)
|
||||||
|
arch = check_dll_architecture(dll_path)
|
||||||
|
print(f"DLL Size: {size} bytes")
|
||||||
|
print(f"Architecture: {arch}")
|
||||||
|
|
||||||
|
# Try to load the DLL to check for missing dependencies
|
||||||
|
kernel32 = ctypes.windll.kernel32
|
||||||
|
|
||||||
|
print("\n=== Dependency Check ===")
|
||||||
|
|
||||||
|
# Try loading with DONT_RESOLVE_DLL_REFERENCES to avoid initializing
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(["x86_64-w64-mingw32-objdump", "-p", dll_path],
|
handle = kernel32.LoadLibraryExW(
|
||||||
capture_output=True, text=True, check=True)
|
ctypes.c_wchar_p(dll_path),
|
||||||
print("\n=== Exported Functions ===")
|
None,
|
||||||
lines = result.stdout.split('\n')
|
LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES
|
||||||
for line in lines:
|
)
|
||||||
if "[" in line and "]" in line and "(" not in line:
|
|
||||||
# This looks like an export entry
|
if handle:
|
||||||
print(f" {line.strip()}")
|
print("✓ DLL can be loaded as data file")
|
||||||
|
kernel32.FreeLibrary(handle)
|
||||||
|
else:
|
||||||
|
error = kernel32.GetLastError()
|
||||||
|
print(f"✗ Failed to load as data file. Error: 0x{error:x}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Exception during data file load: {e}")
|
||||||
|
|
||||||
|
# Try normal loading
|
||||||
|
try:
|
||||||
|
handle = kernel32.LoadLibraryW(ctypes.c_wchar_p(dll_path))
|
||||||
|
if handle:
|
||||||
|
print("✓ DLL loads successfully with full resolution")
|
||||||
|
kernel32.FreeLibrary(handle)
|
||||||
|
else:
|
||||||
|
error = kernel32.GetLastError()
|
||||||
|
print(f"✗ Failed to load DLL normally. Error: 0x{error:x}")
|
||||||
|
print_windows_error(error)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Exception during normal load: {e}")
|
||||||
|
|
||||||
|
def print_windows_error(error_code):
|
||||||
|
"""Print human-readable Windows error message"""
|
||||||
|
error_messages = {
|
||||||
|
0x7e: "The specified module could not be found",
|
||||||
|
0x57: "The parameter is incorrect",
|
||||||
|
0x7f: "The specified procedure could not be found",
|
||||||
|
0xc1: "The application cannot run in Win32 mode",
|
||||||
|
0x485: "Attempt to access invalid address",
|
||||||
|
}
|
||||||
|
|
||||||
|
if error_code in error_messages:
|
||||||
|
print(f" Meaning: {error_messages[error_code]}")
|
||||||
|
|
||||||
|
# Try to get system error message
|
||||||
|
try:
|
||||||
|
import ctypes.wintypes
|
||||||
|
kernel32 = ctypes.windll.kernel32
|
||||||
|
|
||||||
|
buffer = ctypes.create_unicode_buffer(512)
|
||||||
|
kernel32.FormatMessageW(
|
||||||
|
0x00001000, # FORMAT_MESSAGE_FROM_SYSTEM
|
||||||
|
None,
|
||||||
|
error_code,
|
||||||
|
0,
|
||||||
|
buffer,
|
||||||
|
512,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
if buffer.value:
|
||||||
|
print(f" System message: {buffer.value.strip()}")
|
||||||
|
|
||||||
except:
|
except:
|
||||||
print("Could not check exports")
|
pass
|
||||||
|
|
||||||
|
def check_python_architecture():
|
||||||
|
"""Check if Python is 32-bit or 64-bit"""
|
||||||
|
import platform
|
||||||
|
return platform.architecture()[0]
|
||||||
|
|
||||||
|
def test_cffi_loading(dll_path):
|
||||||
|
"""Test CFFI loading specifically"""
|
||||||
|
print("\n=== CFFI Loading Test ===")
|
||||||
|
|
||||||
|
try:
|
||||||
|
import cffi
|
||||||
|
ffi = cffi.FFI()
|
||||||
|
|
||||||
|
# Try to load without any function definitions
|
||||||
|
print("Testing CFFI dlopen...")
|
||||||
|
lib = ffi.dlopen(dll_path)
|
||||||
|
print("✓ CFFI can load the DLL")
|
||||||
|
|
||||||
|
# Test with a simple function definition
|
||||||
|
ffi.cdef("void list_host_apis(void);")
|
||||||
|
lib = ffi.dlopen(dll_path)
|
||||||
|
print("✓ CFFI can load with function definition")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ CFFI loading failed: {e}")
|
||||||
|
print(f" Error type: {type(e).__name__}")
|
||||||
|
return False
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
dll_path = "libaudio.dll"
|
dll_path = "libaudio.dll"
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
dll_path = sys.argv[1]
|
dll_path = sys.argv[1]
|
||||||
|
|
||||||
check_dll_dependencies(dll_path)
|
print(f"Python Architecture: {check_python_architecture()}")
|
||||||
check_exports(dll_path)
|
print()
|
||||||
|
|
||||||
|
check_dll_dependencies_windows(dll_path)
|
||||||
|
test_cffi_loading(dll_path)
|
||||||
|
|||||||
Reference in New Issue
Block a user