Repository: pyinstaller/pyinstaller

Issue:
PyInstaller tries to load all project files as libraries and crashes with "win32ctypes.pywin32.pywintypes.error: (2, 'LoadLibraryExW', 'The system cannot find the file specified.')" when PySide2 is included
PyInstaller 3.5 and later seems to try to load every single file in project subdirectories as a library and finally crashes with the exception mentioned in the title when PySide2 is included as a depencendy.

I reproduced this with versions `3.5`, `4.0.dev0+3f57c9142`, and `4.0.dev0+g3f57c914` (current dev zip and current git head) and created [a minimal python project that exhibits this issue](https://github.com/Systemcluster/pyinstaller-crash).

This has previously been reported under #3916 with additional info posted in [this stackoverflow question](https://stackoverflow.com/questions/57932432/pyinstaller-win32ctypes-pywin32-pywintypes-error-2-loadlibraryexw-the-sys/58195896#58195896).

<details>
<summary>Here is a sample debug log output including traceback from one of the pyinstaller invokations.</summary>

```cmd
62 INFO: PyInstaller: 4.0.dev0+3f57c9142
62 INFO: Python: 3.7.4
73 INFO: Platform: Windows-10-10.0.18362-SP0
...
various similar outputs to the 4 following lines...
...
6530 DEBUG: Analyzing .venv\Lib\site-packages\pip\_vendor\chardet\__pycache__\jpcntx.cpython-37.pyc
6531 INFO: Cannot get manifest resource from non-PE file .venv\Lib\site-packages\pip\_vendor\chardet\__pycache__\jpcntx.cpython-37.pyc
6532 WARNING: Can not get binary dependencies for file: .venv\Lib\site-packages\pip\_vendor\chardet\__pycache__\jpcntx.cpython-37.pyc
6532 WARNING:   Reason: 'DOS Header magic not found.'
6532 DEBUG: Analyzing .git\objects\4f\cbd50d0fa5061722eaf8c4aace8d7f77ad6784
Traceback (most recent call last):
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\win32ctypes\pywin32\pywintypes.py", line 35, in pywin32error
    yield
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\win32ctypes\pywin32\win32api.py", line 43, in LoadLibraryEx
    return _dll._LoadLibraryEx(fileName, 0, flags)
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\win32ctypes\core\ctypes\_util.py", line 42, in check_null
    raise make_error(function, function_name)
OSError: [WinError 2] The system cannot find the file specified.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Chris\AppData\Local\Programs\Python\Python37\Lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Users\Chris\AppData\Local\Programs\Python\Python37\Lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\Chris\Development\w3modmanager\.venv\Scripts\pyinstaller.exe\__main__.py", line 9, in <module>

  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\__main__.py", line 112, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\__main__.py", line 63, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 732, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 679, in build
    exec(code, spec_namespace)
  File ".\w3modmanager.spec", line 25, in <module>
    noarchive=False,
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 242, in __init__
    self.__postinit__()
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\building\datastruct.py", line 158, in __postinit__
    self.assemble()
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 468, in assemble
    redirects=self.binding_redirects))
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\depend\bindepend.py", line 226, in Dependencies
    for ftocnm, fn in getAssemblyFiles(pth, manifest, redirects):
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\depend\bindepend.py", line 402, in getAssemblyFiles
    for assembly in getAssemblies(pth):
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\depend\bindepend.py", line 353, in getAssemblies
    res = GetManifestResources(pth)
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\utils\win32\winmanifest.py", line 1005, in GetManifestResources
    return winresource.GetResources(filename, [RT_MANIFEST], names, languages)
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\PyInstaller\utils\win32\winresource.py", line 168, in GetResources
    hsrc = win32api.LoadLibraryEx(filename, 0, LOAD_LIBRARY_AS_DATAFILE)
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\win32ctypes\pywin32\win32api.py", line 43, in LoadLibraryEx
    return _dll._LoadLibraryEx(fileName, 0, flags)
  File "C:\Users\Chris\AppData\Local\Programs\Python\Python37\Lib\contextlib.py", line 130, in __exit__
    self.gen.throw(type, value, traceback)
  File "c:\users\chris\development\w3modmanager\.venv\lib\site-packages\win32ctypes\pywin32\pywintypes.py", line 37, in pywin32error
    raise error(exception.winerror, exception.function, exception.strerror)
win32ctypes.pywin32.pywintypes.error: (2, 'LoadLibraryExW', 'The system cannot find the file specified.')

```
</details>

By modifying `win32api.py` and catching the exception inside `LoadLibraryEx` , I noticed a lot of similar stacktraces prior to the crash of type `OSError: [WinError 193] <no description>` related to various different files (e.g. `.json`, `.pyc`, etc.), which seemed to indicate that PyInstaller tries to load all the files inside the subdirectories as libraries. The file or type that generates `WinError 2`, which isn't caught, is not deterministic and changes each invocation.

Adding some log output to `build_main.py` before `self.binaries.extend(bindepend.Dependencies(self.binaries, redirects=self.binding_redirects))` reveals that `self.binaries` contains every single non-`.py` file inside `.git` and `.venv`.

Looking at the log output a bit more, I suspected it might be related to the `hook-PySide2.QtNetwork.py` hook. I was able to narrow it down to these lines:

```python
binaries += [
    # Per http://doc.qt.io/qt-5/ssl.html#enabling-and-disabling-ssl-support,
    # the SSL libraries are dynamically loaded, implying they exist in
    # the system path. Include these.
    (getfullnameof('libeay32.dll'), os.path.join(*rel_data_path)),
    (getfullnameof('ssleay32.dll'), os.path.join(*rel_data_path)),
]
``` 

Logging the result of these calls, I am seeing this output, which I am assuming is not a valid search path resulting in this issue.

```python
[
   ('C:\\Program Files\\Common Files\\Intel\\WirelessCommon\\libeay32.dll', '.'), 
   ('', '.')
]
```

These lines seem to have been copied over verbatim from the PyQt5 hook in [this commit](https://github.com/pyinstaller/pyinstaller/commit/5b5791285332003940f4bc70c32bb0cf10a32917) by @bjones1. Removing these lines fixes the issue, however I am not sure about the relevancy of these libraries regarding PySide2. 

[This commit](https://github.com/pyinstaller/pyinstaller/commit/47bd7f10de3b343270fd4d34b356f14617d5d3a1#diff-cfc3f87059223ae1b3d84abe9a90e8f0) changed the PyQt5.QtNetwork hook again, but the change didn't make it into the PySide2.QtNetwork hook. Porting this change over fixes the build as well.

As it stands, PySide2 support is broken in the latest version. It might be a very simple fix as described above, but I don't know enough about either the PySide2 requirements nor PyInstaller to verify.



Discussion:

Resolving patch:
diff --git a/PyInstaller/hooks/hook-PySide2.QtNetwork.py b/PyInstaller/hooks/hook-PySide2.QtNetwork.py
--- a/PyInstaller/hooks/hook-PySide2.QtNetwork.py
+++ b/PyInstaller/hooks/hook-PySide2.QtNetwork.py
@@ -12,7 +12,6 @@
 from PyInstaller.utils.hooks.qt import add_qt5_dependencies, \
     pyside2_library_info
 from PyInstaller.compat import is_win
-from PyInstaller.depend.bindepend import getfullnameof
 
 # Only proceed if PySide2 can be imported.
 if pyside2_library_info.version:
@@ -23,11 +22,10 @@
         from PySide2.QtNetwork import QSslSocket
         print(QSslSocket.supportsSsl())""")):
 
-        rel_data_path = ['.']
-        binaries += [
-            # Per http://doc.qt.io/qt-5/ssl.html#enabling-and-disabling-ssl-support,
-            # the SSL libraries are dynamically loaded, implying they exist in
-            # the system path. Include these.
-            (getfullnameof('libeay32.dll'), os.path.join(*rel_data_path)),
-            (getfullnameof('ssleay32.dll'), os.path.join(*rel_data_path)),
-        ]
+        binaries = []
+        for dll in ('libeay32.dll', 'ssleay32.dll', 'libssl-1_1-x64.dll',
+                    'libcrypto-1_1-x64.dllx'):
+            dll_path = os.path.join(
+                pyside2_library_info.location['BinariesPath'], dll)
+            if os.path.exists(dll_path):
+                binaries.append((dll_path, '.'))


Test patch: