pythonnet / clr-loader

Loader for different .NET runtimes
MIT License
32 stars 23 forks source link

clr-loader failed to load dll if the assembly path contain Chinese #59

Closed link89 closed 1 year ago

link89 commented 1 year ago

Environment

Details

I find that everything just works fine if Python path doesn't contains any Chinese characters. But if the path contain some Chinese chars, let's said, start a python interactive shell via the following command:

D:\中文测试\CCInsight\python-3.8.10-embed-amd64\python.exe

And then when I run import clr, the following error will be raised.

>>> import clr
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\中文测试\CCInsight\python-3.8.10-embed-amd64\lib\site-packages\clr.py", line 6, in <module>
    load()
  File "D:\中文测试\CCInsight\python-3.8.10-embed-amd64\lib\site-packages\pythonnet\__init__.py", line 143, in load
    if func(b"") != 0:
  File "D:\中文测试\CCInsight\python-3.8.10-embed-amd64\lib\site-packages\clr_loader\types.py", line 64, in __call__
    return self._callable(ffi.cast("void*", buf_arr), len(buf_arr))
RuntimeError: cannot call null pointer pointer from cdata 'int(*)(void *, int)'

I delivery a software that provide a GUI depends on pythonnet, this become an annoy bug as user may choose their own installation location, which may contain Chinese chars. Hope to find a fix or a work around.

Update:

I try to narrow down the scope of code to

https://github.com/pythonnet/clr-loader/blob/master/clr_loader/netfx.py#L36-L44

It looks to me like the _get_callable failed to get the right callabe object by the following args

assembly_path:  d:\中文测试\CCInsight\python-3.8.10-embed-amd64\lib\site-packages\pythonnet\runtime\Python.Runtime.dll
typename:          Python.Runtime.Loader
funcname:          Initialize
AndersonBY commented 1 year ago

can fix by change the _get_callable() function to this

import locale

def _get_callable(self, assembly_path: StrOrPath, typename: str, function: str):
    encoding = "gbk" if locale.getpreferredencoding() == "cp936" else "utf8"
    func = _FW.pyclr_get_function(
        self._domain,
        str(Path(assembly_path)).encode(encoding),
        typename.encode("utf8"),
        function.encode("utf8"),
    )