From 3e8a72122c990d1d757a8031c756e21e966eb875 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 17:38:56 -0500 Subject: [PATCH 01/19] build_msys2_mingw --- .github/workflows/main.yml | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9a8ee81ad..dc65ac8c6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,10 +13,44 @@ concurrency: cancel-in-progress: true jobs: + build_msys2_mingw: + runs-on: windows-2022 + timeout-minutes: &timeout-minutes 25 + defaults: + run: + shell: msys2 {0} + strategy: + matrix: + include: + - { sys: mingw64, env: x86_64 } + - { sys: mingw32, env: i686 } + steps: + - uses: actions/checkout@v4 + - uses: msys2/setup-msys2@v2 + with: + msystem: ${{matrix.sys}} + install: | + mingw-w64-${{matrix.env}}-toolchain + mingw-w64-${{matrix.env}}-python + mingw-w64-${{matrix.env}}-python-pip + mingw-w64-${{matrix.env}}-python-virtualenv + mingw-w64-${{matrix.env}}-cc + git + + - name: Build and install + run: pip install . -v --user + + - uses: actions/upload-artifact@v4 + # Upload artifacts even if tests fail + if: ${{ always() }} + with: + name: artifacts-${{ matrix.python-version }}-${{ matrix.python-architecture }} + path: dist/*.whl + if-no-files-found: error test: name: Build and test runs-on: ${{ matrix.os }} - timeout-minutes: &timeout-minutes 25 + timeout-minutes: *timeout-minutes strategy: fail-fast: false matrix: From b998d550db77877646e2665023e65487c12e92ea Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 17:40:26 -0500 Subject: [PATCH 02/19] temp comment out everything else --- .github/workflows/main.yml | 364 ++++++++++++++++++------------------- 1 file changed, 182 insertions(+), 182 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dc65ac8c6..d103ffdf4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,185 +47,185 @@ jobs: name: artifacts-${{ matrix.python-version }}-${{ matrix.python-architecture }} path: dist/*.whl if-no-files-found: error - test: - name: Build and test - runs-on: ${{ matrix.os }} - timeout-minutes: *timeout-minutes - strategy: - fail-fast: false - matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] - python-architecture: [x64, x86, arm64] - include: - - os: windows-2022 - - python-architecture: arm64 - os: windows-11-arm - exclude: - # actions/setup-python does not provide prebuilt arm64 Python before 3.11 - - python-architecture: arm64 - python-version: "3.9" - - python-architecture: arm64 - python-version: "3.10" - env: - # TODO: We can't yet run tests with PYTHONDEVMODE=1, let's emulated it as much as we can - # https://docs.python.org/3/library/devmode.html#effects-of-the-python-development-mode - PYTHONMALLOC: debug - PYTHONASYNCIODEBUG: 1 - PYTHONWARNINGS: always - # PYTHONFAULTHANDLER: 1 # This causes our tests to fail - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.python-architecture }} - check-latest: true - allow-prereleases: true - - - name: Build and install - run: pip install . -v --user - - # This needs to happen *after* installing pywin32 since - # AutoDuck/py2d.py currently relies on runtime imports for introspection - # This isn't included in the wheel (TODO: could we?) - # and only serves as a PR test for the docs.yaml workflow - - name: Generate PyWin32.chm help file - run: python AutoDuck/make.py - - # Smokescreen test to validate postinstall doesn't crash, dlls can be found, and both pathless invocation methods work - - name: Run postinstall install/remove - run: | - $UserSite = "$(python -m site --user-site)" - python -m win32.scripts.pywin32_postinstall -install -destination "$UserSite" - pywin32_postinstall -remove -destination "$UserSite" - - # Compilation and registration of the PyCOMTest server dll - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v2 - - - name: Build and register the PyCOMTest server dll - # Pass Silent flag to regsvr32 to avoid hanging on confirmation window - run: com/TestSources/PyCOMTest/buildAndRegister.bat /s - - - name: Run tests - # Run the tests directly from the source dir so support files (eg, .wav files etc) - # can be found - they aren't installed into the Python tree. - run: python win32/scripts/pywin32_testall.py -v -skip-adodbapi - - - name: Build wheels - run: pip wheel . -v --wheel-dir=dist - - - uses: actions/upload-artifact@v4 - # Upload artifacts even if tests fail - if: ${{ always() }} - with: - name: artifacts-${{ matrix.python-version }}-${{ matrix.python-architecture }} - path: dist/*.whl - if-no-files-found: error - - # actions/setup-python does not provide prebuilt arm64 Python before 3.11, so we cross-compile. - cross_compile_arm64: - name: Cross-compile ARM64 - runs-on: windows-2022 - timeout-minutes: *timeout-minutes - strategy: - fail-fast: false - matrix: - # pythonarm64 NuGet has no download for Python ~=3.9.11 - python-version: ["3.9.10", "3.10"] - steps: - - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: astral-sh/setup-uv@v7 - with: - python-version: ${{ matrix.python-version }} - activate-environment: true - - - name: Obtain ARM64 library files - run: python .github\workflows\download-arm64-libs.py ./arm64libs - - - name: Build wheels - run: uv build --wheel --config-setting=--build-option="build_ext -L./arm64libs --plat-name=win-arm64 build --plat-name=win-arm64 bdist_wheel --plat-name=win-arm64" - - - uses: actions/upload-artifact@v4 - with: - name: artifacts-${{ matrix.python-version }}-arm64 - path: dist/*.whl - if-no-files-found: error - - merge: - runs-on: ubuntu-latest - needs: [test, cross_compile_arm64] - steps: - - name: Merge Artifacts - uses: actions/upload-artifact/merge@v4 - with: - name: artifacts - pattern: artifacts-* - - name: Delete standalone Artifacts - uses: geekyeggo/delete-artifact@v5 - with: - name: artifacts-* - - # This job can be run locally by running `pre-commit run` - checkers: - runs-on: ubuntu-latest - timeout-minutes: *timeout-minutes - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v7 - with: - # This job only needs to target the oldest supported version - python-version: "3.9" - activate-environment: true - - run: uv pip install --group=checkers - - # !cancelled(): Show issues even if the previous steps failed. But still fail the job - - run: pycln . --config=pycln.toml --check - - - name: Run Ruff linter - uses: astral-sh/ruff-action@v3 - if: ${{ !cancelled() }} - - name: Run Ruff formatter - run: ruff format --check - if: ${{ !cancelled() }} - - # Too many files to fit in a single command, also exclude vendored Scintilla and MAPIStubLibrary - - run: | - clang-format --Werror --dry-run $(git ls-files '*.cpp' ':!:com/win32comext/mapi/src/MAPIStubLibrary/') - if ($LastExitCode -ne 0) { exit $LastExitCode } - shell: pwsh - if: ${{ !cancelled() }} - - run: | - clang-format --Werror --dry-run $(git ls-files '*.h' ':!:Pythonwin/Scintilla/' ':!:com/win32comext/mapi/src/MAPIStubLibrary/') - if ($LastExitCode -ne 0) { exit $LastExitCode } - shell: pwsh - if: ${{ !cancelled() }} - - type-checkers: - runs-on: ubuntu-latest - timeout-minutes: *timeout-minutes - strategy: - fail-fast: false - matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v7 - with: - python-version: ${{ matrix.python-version }} - activate-environment: true - - run: uv pip install --group=type-checkers - - - run: mypy . --python-version=${{ matrix.python-version }} - - - uses: jakebailey/pyright-action@v2 - with: - python-version: ${{ matrix.python-version }} - version: PATH - annotate: errors - if: ${{ !cancelled() }} # Show issues even if the previous steps failed. But still fail the job + # test: + # name: Build and test + # runs-on: ${{ matrix.os }} + # timeout-minutes: *timeout-minutes + # strategy: + # fail-fast: false + # matrix: + # python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + # python-architecture: [x64, x86, arm64] + # include: + # - os: windows-2022 + # - python-architecture: arm64 + # os: windows-11-arm + # exclude: + # # actions/setup-python does not provide prebuilt arm64 Python before 3.11 + # - python-architecture: arm64 + # python-version: "3.9" + # - python-architecture: arm64 + # python-version: "3.10" + # env: + # # TODO: We can't yet run tests with PYTHONDEVMODE=1, let's emulated it as much as we can + # # https://docs.python.org/3/library/devmode.html#effects-of-the-python-development-mode + # PYTHONMALLOC: debug + # PYTHONASYNCIODEBUG: 1 + # PYTHONWARNINGS: always + # # PYTHONFAULTHANDLER: 1 # This causes our tests to fail + + # steps: + # - uses: actions/checkout@v4 + + # - name: Set up Python ${{ matrix.python-version }} + # uses: actions/setup-python@v6 + # with: + # python-version: ${{ matrix.python-version }} + # architecture: ${{ matrix.python-architecture }} + # check-latest: true + # allow-prereleases: true + + # - name: Build and install + # run: pip install . -v --user + + # # This needs to happen *after* installing pywin32 since + # # AutoDuck/py2d.py currently relies on runtime imports for introspection + # # This isn't included in the wheel (TODO: could we?) + # # and only serves as a PR test for the docs.yaml workflow + # - name: Generate PyWin32.chm help file + # run: python AutoDuck/make.py + + # # Smokescreen test to validate postinstall doesn't crash, dlls can be found, and both pathless invocation methods work + # - name: Run postinstall install/remove + # run: | + # $UserSite = "$(python -m site --user-site)" + # python -m win32.scripts.pywin32_postinstall -install -destination "$UserSite" + # pywin32_postinstall -remove -destination "$UserSite" + + # # Compilation and registration of the PyCOMTest server dll + # - name: Add msbuild to PATH + # uses: microsoft/setup-msbuild@v2 + + # - name: Build and register the PyCOMTest server dll + # # Pass Silent flag to regsvr32 to avoid hanging on confirmation window + # run: com/TestSources/PyCOMTest/buildAndRegister.bat /s + + # - name: Run tests + # # Run the tests directly from the source dir so support files (eg, .wav files etc) + # # can be found - they aren't installed into the Python tree. + # run: python win32/scripts/pywin32_testall.py -v -skip-adodbapi + + # - name: Build wheels + # run: pip wheel . -v --wheel-dir=dist + + # - uses: actions/upload-artifact@v4 + # # Upload artifacts even if tests fail + # if: ${{ always() }} + # with: + # name: artifacts-${{ matrix.python-version }}-${{ matrix.python-architecture }} + # path: dist/*.whl + # if-no-files-found: error + + # # actions/setup-python does not provide prebuilt arm64 Python before 3.11, so we cross-compile. + # cross_compile_arm64: + # name: Cross-compile ARM64 + # runs-on: windows-2022 + # timeout-minutes: *timeout-minutes + # strategy: + # fail-fast: false + # matrix: + # # pythonarm64 NuGet has no download for Python ~=3.9.11 + # python-version: ["3.9.10", "3.10"] + # steps: + # - uses: actions/checkout@v4 + + # - name: Set up Python ${{ matrix.python-version }} + # uses: astral-sh/setup-uv@v7 + # with: + # python-version: ${{ matrix.python-version }} + # activate-environment: true + + # - name: Obtain ARM64 library files + # run: python .github\workflows\download-arm64-libs.py ./arm64libs + + # - name: Build wheels + # run: uv build --wheel --config-setting=--build-option="build_ext -L./arm64libs --plat-name=win-arm64 build --plat-name=win-arm64 bdist_wheel --plat-name=win-arm64" + + # - uses: actions/upload-artifact@v4 + # with: + # name: artifacts-${{ matrix.python-version }}-arm64 + # path: dist/*.whl + # if-no-files-found: error + + # merge: + # runs-on: ubuntu-latest + # needs: [test, cross_compile_arm64] + # steps: + # - name: Merge Artifacts + # uses: actions/upload-artifact/merge@v4 + # with: + # name: artifacts + # pattern: artifacts-* + # - name: Delete standalone Artifacts + # uses: geekyeggo/delete-artifact@v5 + # with: + # name: artifacts-* + + # # This job can be run locally by running `pre-commit run` + # checkers: + # runs-on: ubuntu-latest + # timeout-minutes: *timeout-minutes + # steps: + # - uses: actions/checkout@v4 + # - uses: astral-sh/setup-uv@v7 + # with: + # # This job only needs to target the oldest supported version + # python-version: "3.9" + # activate-environment: true + # - run: uv pip install --group=checkers + + # # !cancelled(): Show issues even if the previous steps failed. But still fail the job + # - run: pycln . --config=pycln.toml --check + + # - name: Run Ruff linter + # uses: astral-sh/ruff-action@v3 + # if: ${{ !cancelled() }} + # - name: Run Ruff formatter + # run: ruff format --check + # if: ${{ !cancelled() }} + + # # Too many files to fit in a single command, also exclude vendored Scintilla and MAPIStubLibrary + # - run: | + # clang-format --Werror --dry-run $(git ls-files '*.cpp' ':!:com/win32comext/mapi/src/MAPIStubLibrary/') + # if ($LastExitCode -ne 0) { exit $LastExitCode } + # shell: pwsh + # if: ${{ !cancelled() }} + # - run: | + # clang-format --Werror --dry-run $(git ls-files '*.h' ':!:Pythonwin/Scintilla/' ':!:com/win32comext/mapi/src/MAPIStubLibrary/') + # if ($LastExitCode -ne 0) { exit $LastExitCode } + # shell: pwsh + # if: ${{ !cancelled() }} + + # type-checkers: + # runs-on: ubuntu-latest + # timeout-minutes: *timeout-minutes + # strategy: + # fail-fast: false + # matrix: + # python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + # steps: + # - uses: actions/checkout@v4 + # - uses: astral-sh/setup-uv@v7 + # with: + # python-version: ${{ matrix.python-version }} + # activate-environment: true + # - run: uv pip install --group=type-checkers + + # - run: mypy . --python-version=${{ matrix.python-version }} + + # - uses: jakebailey/pyright-action@v2 + # with: + # python-version: ${{ matrix.python-version }} + # version: PATH + # annotate: errors + # if: ${{ !cancelled() }} # Show issues even if the previous steps failed. But still fail the job From 6396f1cd702258cdd2bb3059e69ee7e9e8b25c26 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 18:03:37 -0500 Subject: [PATCH 03/19] don't install in sys managed python --- .github/workflows/main.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d103ffdf4..6ff07e393 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,14 +32,12 @@ jobs: install: | mingw-w64-${{matrix.env}}-toolchain mingw-w64-${{matrix.env}}-python - mingw-w64-${{matrix.env}}-python-pip - mingw-w64-${{matrix.env}}-python-virtualenv + mingw-w64-${{matrix.env}}-python-build mingw-w64-${{matrix.env}}-cc git - name: Build and install - run: pip install . -v --user - + run: python -m build -v - uses: actions/upload-artifact@v4 # Upload artifacts even if tests fail if: ${{ always() }} From dcf210232171f036395890a7cf083caf13d56bc1 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 18:12:04 -0500 Subject: [PATCH 04/19] explicit plat-name --- .github/workflows/main.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6ff07e393..2b99b798c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,8 +22,9 @@ jobs: strategy: matrix: include: - - { sys: mingw64, env: x86_64 } - - { sys: mingw32, env: i686 } + - { sys: mingw64, env: x86_64, plat-name: win-amd64 } + - { sys: mingw32, env: i686, plat-name: win32 } + # No ARM yet, that currently requires using clang steps: - uses: actions/checkout@v4 - uses: msys2/setup-msys2@v2 @@ -34,15 +35,16 @@ jobs: mingw-w64-${{matrix.env}}-python mingw-w64-${{matrix.env}}-python-build mingw-w64-${{matrix.env}}-cc - git - name: Build and install - run: python -m build -v + # Having to specify plat-name here is definitely hacky, not sure why setuptools fails with + # error: --plat-name must be one of ('win32', 'win-amd64', 'win-arm32', 'win-arm64') + run: python -m build -v --config-setting=--build-option="build_ext --plat-name=${{matrix.plat-name}} build --plat-name=${{matrix.plat-name}} bdist_wheel --plat-name=${{matrix.plat-name}}" - uses: actions/upload-artifact@v4 # Upload artifacts even if tests fail if: ${{ always() }} with: - name: artifacts-${{ matrix.python-version }}-${{ matrix.python-architecture }} + name: artifacts-${{matrix.sys}}-${{matrix.env}}-${{matrix.plat-name}} path: dist/*.whl if-no-files-found: error # test: From a7b010094fc2143ac1cac983cb5fae59c4a566f1 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 18:36:31 -0500 Subject: [PATCH 05/19] avoid compiler hack in mingw --- .github/workflows/main.yml | 2 +- setup.py | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2b99b798c..42c79ce67 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,7 @@ jobs: matrix: include: - { sys: mingw64, env: x86_64, plat-name: win-amd64 } - - { sys: mingw32, env: i686, plat-name: win32 } + # - { sys: mingw32, env: i686, plat-name: win32 } # No ARM yet, that currently requires using clang steps: - uses: actions/checkout@v4 diff --git a/setup.py b/setup.py index 4ca367125..07a9efe36 100644 --- a/setup.py +++ b/setup.py @@ -50,9 +50,15 @@ from setuptools._distutils.command.install_data import install_data else: from distutils import ccompiler - from distutils._msvccompiler import MSVCCompiler from distutils.command.install_data import install_data + if "MINGW" in sys.version: + from setuptools._distutils.cygwinccompiler import ( + Mingw32CCompiler as MSVCCompiler, + ) + else: + from distutils._msvccompiler import MSVCCompiler + def my_new_compiler(**kw): if "compiler" in kw and kw["compiler"] in (None, "msvc"): From f2cc3c2633b0d7d43e34fa4e17855cdb633603f4 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 18:45:02 -0500 Subject: [PATCH 06/19] try improve mingw detection --- setup.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 07a9efe36..2ee792116 100644 --- a/setup.py +++ b/setup.py @@ -52,12 +52,12 @@ from distutils import ccompiler from distutils.command.install_data import install_data - if "MINGW" in sys.version: + if "MSC" in sys.version: + from distutils._msvccompiler import MSVCCompiler + else: from setuptools._distutils.cygwinccompiler import ( - Mingw32CCompiler as MSVCCompiler, + MingwCCompiler as MSVCCompiler, ) - else: - from distutils._msvccompiler import MSVCCompiler def my_new_compiler(**kw): @@ -172,7 +172,7 @@ def __init__( def finalize_options(self, build_ext): # distutils doesn't define this function for an Extension - it is # our own invention, and called just before the extension is built. - if not build_ext.mingw32: + if not build_ext.mingw: # bugger - add this to python! if build_ext.plat_name == "win32": self.extra_link_args.append("/MACHINE:x86") @@ -248,7 +248,7 @@ class WinExt_pythonwin_subsys_win(WinExt_pythonwin): def finalize_options(self, build_ext): WinExt_pythonwin.finalize_options(self, build_ext) - if build_ext.mingw32: + if build_ext.mingw: self.extra_link_args.append("-mwindows") else: self.extra_link_args.append("/SUBSYSTEM:WINDOWS") @@ -338,7 +338,7 @@ class WinExt_pythonservice(WinExt): def finalize_options(self, build_ext): WinExt.finalize_options(self, build_ext) - if build_ext.mingw32: + if build_ext.mingw: self.extra_link_args.append("-mconsole") self.extra_link_args.append("-municode") else: @@ -379,8 +379,8 @@ def finalize_options(self) -> None: # The pywintypes library is created in the build_temp # directory, so we need to add this to library_dirs self.library_dirs.append(self.build_temp) - self.mingw32 = self.compiler == "mingw32" # type: ignore[comparison-overlap] # compiler is a string until `run` is run - if self.mingw32: + self.mingw = "mingw" in self.compiler # type: ignore[comparison-overlap] # compiler is a string until `run` is run + if self.mingw: self.libraries.append("stdc++") self.excluded_extensions: list[tuple[WinExt, str]] = [] @@ -505,7 +505,7 @@ def _check_vc(self): if m: atlmfc_found = True # ATLMFC libs/includes already found by distutils - if not vcbase and not self.mingw32: + if not vcbase and not self.mingw: print("-- compiler.library_dirs:", self.compiler.library_dirs) # Error or warn? last hope would be a non-standard build environment print("-- Visual C base path not found !?") From a495ccb2287fbbb5476c882ad2a91f7f73e27c5a Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 18:49:02 -0500 Subject: [PATCH 07/19] don,t compiler hack on mingw --- setup.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index 2ee792116..5ed155a16 100644 --- a/setup.py +++ b/setup.py @@ -50,25 +50,20 @@ from setuptools._distutils.command.install_data import install_data else: from distutils import ccompiler + from distutils._msvccompiler import MSVCCompiler from distutils.command.install_data import install_data - if "MSC" in sys.version: - from distutils._msvccompiler import MSVCCompiler - else: - from setuptools._distutils.cygwinccompiler import ( - MingwCCompiler as MSVCCompiler, - ) - -def my_new_compiler(**kw): - if "compiler" in kw and kw["compiler"] in (None, "msvc"): - return my_compiler() - return orig_new_compiler(**kw) +if "MSC" in sys.version: + def my_new_compiler(**kw): + if "compiler" in kw and kw["compiler"] in (None, "msvc"): + return my_compiler() + return orig_new_compiler(**kw) -# No way to cleanly wedge our compiler sub-class in. -orig_new_compiler = ccompiler.new_compiler -ccompiler.new_compiler = my_new_compiler # type: ignore[assignment] # Assuming the caller will always use only kwargs + # No way to cleanly wedge our compiler sub-class in. + orig_new_compiler = ccompiler.new_compiler + ccompiler.new_compiler = my_new_compiler # type: ignore[assignment] # Assuming the caller will always use only kwargs # This import has to be delayed to AFTER the compiler hack From d90537483c76fe6683d4f3a94161794d1d58ee9e Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 18:57:51 -0500 Subject: [PATCH 08/19] keep tryign to improve mingw detection --- setup.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 5ed155a16..f78c8403d 100644 --- a/setup.py +++ b/setup.py @@ -53,9 +53,9 @@ from distutils._msvccompiler import MSVCCompiler from distutils.command.install_data import install_data +is_mingw = "MSC" not in sys.version -if "MSC" in sys.version: - +if not is_mingw: def my_new_compiler(**kw): if "compiler" in kw and kw["compiler"] in (None, "msvc"): return my_compiler() @@ -167,7 +167,7 @@ def __init__( def finalize_options(self, build_ext): # distutils doesn't define this function for an Extension - it is # our own invention, and called just before the extension is built. - if not build_ext.mingw: + if not is_mingw: # bugger - add this to python! if build_ext.plat_name == "win32": self.extra_link_args.append("/MACHINE:x86") @@ -243,7 +243,7 @@ class WinExt_pythonwin_subsys_win(WinExt_pythonwin): def finalize_options(self, build_ext): WinExt_pythonwin.finalize_options(self, build_ext) - if build_ext.mingw: + if is_mingw: self.extra_link_args.append("-mwindows") else: self.extra_link_args.append("/SUBSYSTEM:WINDOWS") @@ -333,7 +333,7 @@ class WinExt_pythonservice(WinExt): def finalize_options(self, build_ext): WinExt.finalize_options(self, build_ext) - if build_ext.mingw: + if is_mingw: self.extra_link_args.append("-mconsole") self.extra_link_args.append("-municode") else: @@ -374,8 +374,7 @@ def finalize_options(self) -> None: # The pywintypes library is created in the build_temp # directory, so we need to add this to library_dirs self.library_dirs.append(self.build_temp) - self.mingw = "mingw" in self.compiler # type: ignore[comparison-overlap] # compiler is a string until `run` is run - if self.mingw: + if is_mingw: self.libraries.append("stdc++") self.excluded_extensions: list[tuple[WinExt, str]] = [] @@ -500,7 +499,7 @@ def _check_vc(self): if m: atlmfc_found = True # ATLMFC libs/includes already found by distutils - if not vcbase and not self.mingw: + if not vcbase and not is_mingw: print("-- compiler.library_dirs:", self.compiler.library_dirs) # Error or warn? last hope would be a non-standard build environment print("-- Visual C base path not found !?") From 8032b414fd44ae9d6961c24168807ad74354faa0 Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 19 Feb 2026 19:48:44 -0500 Subject: [PATCH 09/19] Update some slash paths --- setup.py | 73 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/setup.py b/setup.py index f78c8403d..62d3eaf35 100644 --- a/setup.py +++ b/setup.py @@ -55,15 +55,14 @@ is_mingw = "MSC" not in sys.version -if not is_mingw: - def my_new_compiler(**kw): - if "compiler" in kw and kw["compiler"] in (None, "msvc"): - return my_compiler() - return orig_new_compiler(**kw) +def my_new_compiler(**kw): + if not is_mingw and "compiler" in kw and kw["compiler"] in (None, "msvc"): + return my_compiler() + return orig_new_compiler(**kw) - # No way to cleanly wedge our compiler sub-class in. - orig_new_compiler = ccompiler.new_compiler - ccompiler.new_compiler = my_new_compiler # type: ignore[assignment] # Assuming the caller will always use only kwargs +# No way to cleanly wedge our compiler sub-class in. +orig_new_compiler = ccompiler.new_compiler +ccompiler.new_compiler = my_new_compiler # type: ignore[assignment] # Assuming the caller will always use only kwargs # This import has to be delayed to AFTER the compiler hack @@ -423,7 +422,7 @@ def _why_cant_build_extension(self, ext): return None # no reason - it can be built! def _build_scintilla(self): - path = "pythonwin\\Scintilla" + path = "pythonwin/Scintilla" makefile = "makefile_pythonwin" makeargs = [] @@ -663,7 +662,7 @@ def build_extensions(self): def build_exefile(self, ext): suffix = "_d" if self.debug else "" logging.info("building exe '%s'", ext.name) - leaf_name = f"{ext.get_pywin32_dir()}\\{ext.name}{suffix}.exe" + leaf_name = f"{ext.get_pywin32_dir()}/{ext.name}{suffix}.exe" full_name = os.path.join(self.build_lib, leaf_name) sources = list(ext.sources) @@ -793,7 +792,7 @@ def find_swig(self): swig = os.environ["SWIG"] else: # We know where our swig is - swig = os.path.abspath("swig\\swig.exe") + swig = os.path.abspath("swig/swig.exe") lib = os.path.join(os.path.dirname(swig), "swig_lib") os.environ["SWIG_LIB"] = lib return swig @@ -1100,7 +1099,7 @@ def finalize_options(self): WinExt_win32( "win32evtlog", sources=""" - win32\\src\\win32evtlog_messages.mc win32\\src\\win32evtlog.i + win32/src/win32evtlog_messages.mc win32/src/win32evtlog.i """.split(), libraries="advapi32 oleaut32", delay_load_libraries="wevtapi", @@ -1213,29 +1212,29 @@ def finalize_options(self): ).split(), depends=( """ - {win32com}/include\\propbag.h {win32com}/include\\PyComTypeObjects.h - {win32com}/include\\PyFactory.h {win32com}/include\\PyGConnectionPoint.h - {win32com}/include\\PyGConnectionPointContainer.h - {win32com}/include\\PyGPersistStorage.h {win32com}/include\\PyIBindCtx.h - {win32com}/include\\PyICatInformation.h {win32com}/include\\PyICatRegister.h - {win32com}/include\\PyIDataObject.h {win32com}/include\\PyIDropSource.h - {win32com}/include\\PyIDropTarget.h {win32com}/include\\PyIEnumConnectionPoints.h - {win32com}/include\\PyIEnumConnections.h {win32com}/include\\PyIEnumFORMATETC.h - {win32com}/include\\PyIEnumGUID.h {win32com}/include\\PyIEnumSTATPROPSETSTG.h - {win32com}/include\\PyIEnumSTATSTG.h {win32com}/include\\PyIEnumString.h - {win32com}/include\\PyIEnumVARIANT.h {win32com}/include\\PyIExternalConnection.h - {win32com}/include\\PyIGlobalInterfaceTable.h {win32com}/include\\PyILockBytes.h - {win32com}/include\\PyIMoniker.h {win32com}/include\\PyIOleWindow.h - {win32com}/include\\PyIPersist.h {win32com}/include\\PyIPersistFile.h - {win32com}/include\\PyIPersistStorage.h {win32com}/include\\PyIPersistStream.h - {win32com}/include\\PyIPersistStreamInit.h {win32com}/include\\PyIRunningObjectTable.h - {win32com}/include\\PyIStorage.h {win32com}/include\\PyIStream.h - {win32com}/include\\PythonCOM.h {win32com}/include\\PythonCOMRegister.h - {win32com}/include\\PythonCOMServer.h {win32com}/include\\stdafx.h - {win32com}/include\\univgw_dataconv.h - {win32com}/include\\PyICancelMethodCalls.h {win32com}/include\\PyIContext.h - {win32com}/include\\PyIEnumContextProps.h {win32com}/include\\PyIClientSecurity.h - {win32com}/include\\PyIServerSecurity.h + {win32com}/include/propbag.h {win32com}/include/PyComTypeObjects.h + {win32com}/include/PyFactory.h {win32com}/include/PyGConnectionPoint.h + {win32com}/include/PyGConnectionPointContainer.h + {win32com}/include/PyGPersistStorage.h {win32com}/include/PyIBindCtx.h + {win32com}/include/PyICatInformation.h {win32com}/include/PyICatRegister.h + {win32com}/include/PyIDataObject.h {win32com}/include/PyIDropSource.h + {win32com}/include/PyIDropTarget.h {win32com}/include/PyIEnumConnectionPoints.h + {win32com}/include/PyIEnumConnections.h {win32com}/include/PyIEnumFORMATETC.h + {win32com}/include/PyIEnumGUID.h {win32com}/include/PyIEnumSTATPROPSETSTG.h + {win32com}/include/PyIEnumSTATSTG.h {win32com}/include/PyIEnumString.h + {win32com}/include/PyIEnumVARIANT.h {win32com}/include/PyIExternalConnection.h + {win32com}/include/PyIGlobalInterfaceTable.h {win32com}/include/PyILockBytes.h + {win32com}/include/PyIMoniker.h {win32com}/include/PyIOleWindow.h + {win32com}/include/PyIPersist.h {win32com}/include/PyIPersistFile.h + {win32com}/include/PyIPersistStorage.h {win32com}/include/PyIPersistStream.h + {win32com}/include/PyIPersistStreamInit.h {win32com}/include/PyIRunningObjectTable.h + {win32com}/include/PyIStorage.h {win32com}/include/PyIStream.h + {win32com}/include/PythonCOM.h {win32com}/include/PythonCOMRegister.h + {win32com}/include/PythonCOMServer.h {win32com}/include/stdafx.h + {win32com}/include/univgw_dataconv.h + {win32com}/include/PyICancelMethodCalls.h {win32com}/include/PyIContext.h + {win32com}/include/PyIEnumContextProps.h {win32com}/include/PyIClientSecurity.h + {win32com}/include/PyIServerSecurity.h """.format(**dirs) ).split(), libraries="oleaut32 ole32 user32 urlmon", @@ -1848,7 +1847,7 @@ def expand_modules(module_dir: str | os.PathLike[str]): # NOTE: somewhat counter-intuitively, a result list a-la: -# [('Lib/site-packages\\pythonwin', ('pythonwin/License.txt',)),] +# [('Lib/site-packages/pythonwin', ('pythonwin/License.txt',)),] # will 'do the right thing' in terms of installing License.txt into # 'Lib/site-packages/pythonwin/License.txt'. We exploit this to # get 'com/win32com/whatever' installed to 'win32com/whatever' @@ -1934,7 +1933,7 @@ def convert_optional_data_files(files): "adodbapi", ] -py_modules = [*expand_modules("win32\\lib"), "win32\\winxpgui"] +py_modules = [*expand_modules("win32/lib"), "win32/winxpgui"] ext_modules = ( win32_extensions + com_extensions + pythonwin_extensions + other_extensions ) From 2599fbd28524fd481fea31df7144056bda17d055 Mon Sep 17 00:00:00 2001 From: Avasam Date: Sun, 22 Feb 2026 18:36:56 -0500 Subject: [PATCH 10/19] try including cygwin --- .github/workflows/main.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 42c79ce67..caf3ecc19 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -20,6 +20,7 @@ jobs: run: shell: msys2 {0} strategy: + fail-fast: false matrix: include: - { sys: mingw64, env: x86_64, plat-name: win-amd64 } @@ -30,6 +31,8 @@ jobs: - uses: msys2/setup-msys2@v2 with: msystem: ${{matrix.sys}} + update: true + # TODO: check if toolchain and are needed install: | mingw-w64-${{matrix.env}}-toolchain mingw-w64-${{matrix.env}}-python @@ -47,6 +50,36 @@ jobs: name: artifacts-${{matrix.sys}}-${{matrix.env}}-${{matrix.plat-name}} path: dist/*.whl if-no-files-found: error + + build_cygwin: + runs-on: windows-2022 + timeout-minutes: *timeout-minutes + defaults: + run: + shell: bash -o igncr -eo pipefail '{0}' + steps: + - uses: actions/checkout@v4 + - uses: cygwin/cygwin-install-action@master + with: + platform: x86_64 + packages: >- + gcc-core + python3 + python3-build + - name: Disable CRLF line endings in git checkout + run: git config --global core.autocrlf input + - name: Build and install + # Having to specify plat-name here is definitely hacky, not sure why setuptools fails with + # error: --plat-name must be one of ('win32', 'win-amd64', 'win-arm32', 'win-arm64') + run: python -m build -v --config-setting=--build-option="build_ext --plat-name=win-amd64 build --plat-name=win-amd64 bdist_wheel --plat-name=win-amd64" + - uses: actions/upload-artifact@v4 + # Upload artifacts even if tests fail + if: ${{ always() }} + with: + name: artifacts-cygwin + path: dist/*.whl + if-no-files-found: error + # test: # name: Build and test # runs-on: ${{ matrix.os }} From d9c01669b6c1024a85b1714d71e6a0424c98d5e2 Mon Sep 17 00:00:00 2001 From: Avasam Date: Sun, 22 Feb 2026 18:48:13 -0500 Subject: [PATCH 11/19] python3-tomli --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index caf3ecc19..5845ab960 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,6 +66,7 @@ jobs: gcc-core python3 python3-build + python3-tomli - name: Disable CRLF line endings in git checkout run: git config --global core.autocrlf input - name: Build and install From 92932c50dea828f9f1aadec7e54be95da1017be8 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 25 Feb 2026 20:37:48 -0500 Subject: [PATCH 12/19] Monkeypatch MinGW32Compiler.initialize --- setup.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.py b/setup.py index 62d3eaf35..ba9da6509 100644 --- a/setup.py +++ b/setup.py @@ -48,10 +48,15 @@ from setuptools._distutils import ccompiler from setuptools._distutils._msvccompiler import MSVCCompiler from setuptools._distutils.command.install_data import install_data + from setuptools._distutils.compilers.C.cygwin import MinGW32Compiler else: from distutils import ccompiler from distutils._msvccompiler import MSVCCompiler from distutils.command.install_data import install_data + from distutils.compilers.C.cygwin import MinGW32Compiler + +# workaround until https://github.com/pypa/distutils/pull/399 is fixed +MinGW32Compiler.initialize = lambda _: None is_mingw = "MSC" not in sys.version From d5b80f15bcab97bc108e05cb49497e5c65a6fd56 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 25 Feb 2026 20:44:14 -0500 Subject: [PATCH 13/19] . --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ba9da6509..b744ac832 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ from distutils.compilers.C.cygwin import MinGW32Compiler # workaround until https://github.com/pypa/distutils/pull/399 is fixed -MinGW32Compiler.initialize = lambda _: None +MinGW32Compiler.initialize = lambda *_: None is_mingw = "MSC" not in sys.version From c4d57356ddeedfc1f1e4234fddabef5c643a5dbb Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 25 Feb 2026 20:52:25 -0500 Subject: [PATCH 14/19] don't access initialized on non MSVCCompiler --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b744ac832..78977a17f 100644 --- a/setup.py +++ b/setup.py @@ -550,7 +550,7 @@ def build_extensions(self): self.found_libraries = {} - if hasattr(self.compiler, "initialize") and not self.compiler.initialized: + if isinstance(self.compiler, MSVCCompiler) and not self.compiler.initialized: self.compiler.initialize() # XXX this distutils class var peek hack should become obsolete From 9b73e3cc2d990252106b5295cfde57cb76ddb5a0 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 25 Feb 2026 20:55:58 -0500 Subject: [PATCH 15/19] Is winreg / exchange sdk special path still needed ? --- setup.py | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/setup.py b/setup.py index 78977a17f..84059bfe6 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,6 @@ import re import shutil import sys -import winreg from abc import abstractmethod from collections.abc import Iterable from pathlib import Path @@ -276,49 +275,15 @@ def __init__(self, name, **kw): def get_pywin32_dir(self): return "win32comext/" + self.name - -# Exchange extensions get special treatment: -# * Look for the Exchange SDK in the registry. -# * Output directory is different than the module's basename. -# * Require use of the Exchange 2000 SDK - this works for both VC6 and 7 -# NOTE: sadly the old Exchange SDK does *not* include MAPI files - these used -# to be bundled with the Windows SDKs and/or Visual Studio, but no longer are. class WinExt_win32com_mapi(WinExt_win32com): def __init__(self, name, **kw): - # The Exchange 2000 SDK seems to install itself without updating - # LIB or INCLUDE environment variables. It does register the core - # directory in the registry tho - look it up - sdk_install_dir = None libs = kw.get("libraries", "") - keyname = r"SOFTWARE\Microsoft\Exchange\SDK" - flags = winreg.KEY_READ - try: - flags |= winreg.KEY_WOW64_32KEY - except AttributeError: - pass # this version doesn't support 64 bits, so must already be using 32bit key. - for root in winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER: - try: - keyob = winreg.OpenKey(root, keyname, 0, flags) - value, type_id = winreg.QueryValueEx(keyob, "INSTALLDIR") - if type_id == winreg.REG_SZ: - sdk_install_dir = value - break - except OSError: - pass - if sdk_install_dir is not None: - d = os.path.join(sdk_install_dir, "SDK", "Include") - if os.path.isdir(d): - kw.setdefault("include_dirs", []).insert(0, d) - d = os.path.join(sdk_install_dir, "SDK", "Lib") - if os.path.isdir(d): - kw.setdefault("library_dirs", []).insert(0, d) - # The stand-alone exchange SDK has these libs # Additional utility functions are only available for 32-bit builds. if not platform.machine() in ("AMD64", "ARM64"): libs += " version user32 advapi32 Ex2KSdk sadapi netapi32" kw["libraries"] = libs - WinExt_win32com.__init__(self, name, **kw) + super().__init__(name, **kw) def get_pywin32_dir(self): # 'win32com.mapi.exchange' is currently the only From 15202b2487d77c2855b397ebba9edfead1baf9b9 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 25 Feb 2026 21:31:46 -0500 Subject: [PATCH 16/19] Fix casing typos --- .github/workflows/main.yml | 4 +--- setup.py | 43 +++++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5845ab960..972032c9f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -70,9 +70,7 @@ jobs: - name: Disable CRLF line endings in git checkout run: git config --global core.autocrlf input - name: Build and install - # Having to specify plat-name here is definitely hacky, not sure why setuptools fails with - # error: --plat-name must be one of ('win32', 'win-amd64', 'win-arm32', 'win-arm64') - run: python -m build -v --config-setting=--build-option="build_ext --plat-name=win-amd64 build --plat-name=win-amd64 bdist_wheel --plat-name=win-amd64" + run: python -m build -v - uses: actions/upload-artifact@v4 # Upload artifacts even if tests fail if: ${{ always() }} diff --git a/setup.py b/setup.py index 84059bfe6..741d9d50c 100644 --- a/setup.py +++ b/setup.py @@ -239,7 +239,7 @@ def __init__(self, name, **kw): WinExt.__init__(self, name, **kw) def get_pywin32_dir(self): - return "pythonwin" + return "Pythonwin" class WinExt_pythonwin_subsys_win(WinExt_pythonwin): @@ -392,7 +392,7 @@ def _why_cant_build_extension(self, ext): return None # no reason - it can be built! def _build_scintilla(self): - path = "pythonwin/Scintilla" + path = "Pythonwin/Scintilla" makefile = "makefile_pythonwin" makeargs = [] @@ -451,7 +451,7 @@ def _build_scintilla(self): base_name = "scintilla.dll" self.copy_file( os.path.join(self.build_temp, "scintilla", base_name), - os.path.join(self.build_lib, "pythonwin"), + os.path.join(self.build_lib, "Pythonwin"), ) # find the VC base path corresponding to distutils paths, and @@ -539,7 +539,7 @@ def build_extensions(self): vcbase, vcverdir = self._check_vc() # Here we hack a "pywin32" directory (one of 'win32', 'win32com', - # 'pythonwin' etc), as distutils doesn't seem to like the concept + # 'Pythonwin' etc), as distutils doesn't seem to like the concept # of multiple top-level directories. assert self.package is None @@ -1708,7 +1708,7 @@ def finalize_options(self): "Pythonwin/ddemodule.cpp", "Pythonwin/ddeserver.cpp", ], - depends=["win32/src/stddde.h", "pythonwin/ddemodule.h"], + depends=["win32/src/stddde.h", "Pythonwin/ddemodule.h"], optional_headers=["afxres.h"], ), ] @@ -1817,15 +1817,18 @@ def expand_modules(module_dir: str | os.PathLike[str]): # NOTE: somewhat counter-intuitively, a result list a-la: -# [('Lib/site-packages/pythonwin', ('pythonwin/License.txt',)),] +# [('Lib/site-packages/pythonwin', ('Pythonwin/License.txt',)),] # will 'do the right thing' in terms of installing License.txt into -# 'Lib/site-packages/pythonwin/License.txt'. We exploit this to +# 'Lib/site-packages/Pythonwin/License.txt'. We exploit this to # get 'com/win32com/whatever' installed to 'win32com/whatever' def convert_data_files(files: Iterable[str]): ret: list[tuple[str, tuple[str]]] = [] for file in files: + print("file:", file) file = os.path.normpath(file) if file.find("*") >= 0: + print('if file.find("*") >= 0', True) + files_use = tuple( str(path) for path in Path(file).parent.rglob(os.path.basename(file)) @@ -1835,10 +1838,12 @@ def convert_data_files(files: Iterable[str]): if not files_use: raise RuntimeError("No files match '%s'" % file) else: + print('if file.find("*") >= 0', False) if not os.path.isfile(file): raise RuntimeError("No file '%s'" % file) files_use = (file,) for fname in files_use: + print("fname:", fname) path_use = os.path.dirname(fname).removeprefix("com\\") ret.append((path_use, (fname,))) return ret @@ -1971,7 +1976,7 @@ def convert_optional_data_files(files): package_dir={ "win32com": "com/win32com", "win32comext": "com/win32comext", - "pythonwin": "pythonwin", + "pythonwin": "Pythonwin", }, packages=packages, py_modules=py_modules, @@ -1979,10 +1984,10 @@ def convert_optional_data_files(files): + convert_data_files( [ "Pythonwin/start_pythonwin.pyw", - "pythonwin/pywin/*.cfg", - "pythonwin/pywin/Demos/*.py", - "pythonwin/pywin/Demos/app/*.py", - "pythonwin/pywin/Demos/ocx/*.py", + "Pythonwin/pywin/*.cfg", + "Pythonwin/pywin/Demos/*.py", + "Pythonwin/pywin/Demos/app/*.py", + "Pythonwin/pywin/Demos/ocx/*.py", "win32/scripts/*.py", "win32/test/*.py", "win32/test/win32rcparser/test.rc", @@ -1994,8 +1999,8 @@ def convert_optional_data_files(files): "com/win32com/readme.html", # Licenses "com/win32comext/mapi/NOTICE.md", - "pythonwin/License.txt", - "pythonwin/pywin/idle/*.txt", + "Pythonwin/License.txt", + "Pythonwin/pywin/idle/*.txt", "win32/License.txt", # win32com test utility files. "com/win32com/test/*.idl", @@ -2012,10 +2017,10 @@ def convert_optional_data_files(files): "com/win32comext/axscript/test/*.py", "com/win32comext/axscript/test/*.pys", "com/win32comext/axscript/test/*.vbs", - "com/win32comext/axscript/Demos/*.pys", - "com/win32comext/axscript/Demos/*.htm*", - "com/win32comext/axscript/Demos/*.gif", - "com/win32comext/axscript/Demos/*.asp", + "com/win32comext/axscript/demos/*.pys", + "com/win32comext/axscript/demos/*.htm*", + "com/win32comext/axscript/demos/*.gif", + "com/win32comext/axscript/demos/*.asp", "com/win32comext/mapi/demos/*.py", "com/win32comext/propsys/test/*.py", "com/win32comext/shell/test/*.py", @@ -2053,7 +2058,7 @@ def convert_optional_data_files(files): # And data files convert_data_files can't handle. + [ ("", (str(version_file_path),)), - ("pythonwin", (str(scintilla_licence_path),)), + ("Pythonwin", (str(scintilla_licence_path),)), ("win32comext/mapi", (str(mapi_stubs_licence_path),)), ("win32com", ("com/License.txt",)), ("win32comext", ("com/License.txt",)), From f632ce04ad6ec5d217a467fab5c22dd5e5c6b5d7 Mon Sep 17 00:00:00 2001 From: Avasam Date: Wed, 25 Feb 2026 22:21:49 -0500 Subject: [PATCH 17/19] Fix casing in includes --- .github/workflows/main.yml | 2 +- Pythonwin/Win32uiHostGlue.h | 2 +- Pythonwin/dllmain.cpp | 2 +- Pythonwin/doc/EmbeddingWin32ui.html | 4 ++-- Pythonwin/pythonwin.cpp | 2 +- Pythonwin/pywin/test/test_exe.py | 2 +- Pythonwin/stdafx.h | 4 ++-- Pythonwin/stdafxdde.h | 2 +- Pythonwin/stdafxole.h | 2 +- Pythonwin/win32oleDlgInsert.cpp | 4 ++-- Pythonwin/win32uimodule.cpp | 4 ++-- Pythonwin/win32uioledoc.cpp | 4 ++-- com/win32com/src/oleargs.cpp | 2 +- com/win32comext/adsi/src/PyADSIUtil.cpp | 2 +- com/win32comext/adsi/src/adsilib.i | 2 +- com/win32comext/directsound/src/PyDSBCAPS.cpp | 4 ++-- com/win32comext/directsound/src/PyDSBUFFERDESC.cpp | 4 ++-- isapi/src/PyExtensionObjects.cpp | 2 +- isapi/src/PyFilterObjects.cpp | 4 ++-- isapi/src/PythonEng.cpp | 4 ++-- isapi/src/pyISAPI.cpp | 4 ++-- win32/src/PerfMon/PyPerfMon.cpp | 2 +- win32/src/PyOVERLAPPED.cpp | 4 ++-- win32/src/PyTime.cpp | 2 +- win32/src/PyWAVEFORMATEX.cpp | 2 +- win32/src/PyWinTypes.h | 2 +- win32/src/PyWinTypesmodule.cpp | 4 ++-- win32/src/_winxptheme.i | 2 +- win32/src/timermodule.cpp | 2 +- win32/src/win32clipboardmodule.cpp | 2 +- win32/src/win32dynamicdialog.cpp | 4 ++-- win32/src/win32file.i | 2 +- win32/src/win32gui.i | 2 +- win32/src/win32inet.i | 4 ++-- win32/src/win32inet_winhttp.cpp | 4 ++-- win32/src/win32lzmodule.cpp | 2 +- win32/src/win32rasmodule.cpp | 2 +- win32/src/win32wnet/PyNCB.cpp | 4 ++-- win32/src/win32wnet/PyNetresource.cpp | 2 +- win32/src/win32wnet/win32wnet.cpp | 4 ++-- 40 files changed, 57 insertions(+), 57 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 972032c9f..167430119 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,7 +64,7 @@ jobs: platform: x86_64 packages: >- gcc-core - python3 + python3-dev python3-build python3-tomli - name: Disable CRLF line endings in git checkout diff --git a/Pythonwin/Win32uiHostGlue.h b/Pythonwin/Win32uiHostGlue.h index 163e7581b..17aaf35c8 100644 --- a/Pythonwin/Win32uiHostGlue.h +++ b/Pythonwin/Win32uiHostGlue.h @@ -5,7 +5,7 @@ // be in synch! Use a version number to check this. #define WIN32UIHOSTGLUE_VERSION 3 -#include "pywintypes.h" +#include "PyWinTypes.h" class Win32uiHostGlue : public CObject { public: diff --git a/Pythonwin/dllmain.cpp b/Pythonwin/dllmain.cpp index e319633e5..1d0b13b3d 100644 --- a/Pythonwin/dllmain.cpp +++ b/Pythonwin/dllmain.cpp @@ -3,7 +3,7 @@ #include "stdafx.h" #include "afxdllx.h" -#include "win32uiHostGlue.h" +#include "Win32uiHostGlue.h" static HWND GetConsoleHwnd(void); diff --git a/Pythonwin/doc/EmbeddingWin32ui.html b/Pythonwin/doc/EmbeddingWin32ui.html index 50996cd72..6382f5677 100644 --- a/Pythonwin/doc/EmbeddingWin32ui.html +++ b/Pythonwin/doc/EmbeddingWin32ui.html @@ -23,8 +23,8 @@

Subclass a Win32uiHostGlue class

You must instantiate a Win32uiHostGlue class. This class is used as a glue between win32ui.pyd and the host .exe, and is defined in Win32uiHostGlue.h

Currently, this consists of about 5 methods that must be called by your application. The principle is that the Application must hook certain handlers, and delegate them to the HostGlue class. This will ensure the appropriate Win32ui internals are called.

Embedding win32ui Architecture

-

win32uihostglue.h

-

The win32uihostglue.h module defines a class which makes interfacing fairly simple. This Win32uiHostGlue class is used as a glue between win32ui.pyd and the host .exe. In the most simple case, you need to instantiate one of the classes, and at certain key points in your CWinApp derived class, call the appropriate methods. You may choose to provide your own glue class derived from Win32uiHostGlue in certain cases.

+

Win32uiHostGlue.h

+

The Win32uiHostGlue.h module defines a class which makes interfacing fairly simple. This Win32uiHostGlue class is used as a glue between win32ui.pyd and the host .exe. In the most simple case, you need to instantiate one of the classes, and at certain key points in your CWinApp derived class, call the appropriate methods. You may choose to provide your own glue class derived from Win32uiHostGlue in certain cases.

Below is an example class, which overrides the "SetStatusText" method, so that status information displays in the applications status bar (this is only necessary if your application has a "non standard" status bar - normally you could omit this.).

GameApp NEAR theApp; // My existing CWinApp derived class.
 // HostGlue class.
diff --git a/Pythonwin/pythonwin.cpp b/Pythonwin/pythonwin.cpp
index b61d44b4e..78eff569c 100644
--- a/Pythonwin/pythonwin.cpp
+++ b/Pythonwin/pythonwin.cpp
@@ -3,7 +3,7 @@
 
 #include "stdafxpw.h"
 #include "pythonwin.h"
-#include "win32uiHostGlue.h"
+#include "Win32uiHostGlue.h"
 
 #ifdef _DEBUG
 #undef THIS_FILE
diff --git a/Pythonwin/pywin/test/test_exe.py b/Pythonwin/pywin/test/test_exe.py
index d545bc636..238e819f2 100644
--- a/Pythonwin/pywin/test/test_exe.py
+++ b/Pythonwin/pywin/test/test_exe.py
@@ -38,7 +38,7 @@ def setUp(self):
             # install w symlink. This works only when cwd is set to the dir of
             # python.exe / exec_prefix.
 
-            # XXX Pythonwin.exe / win32uihostglue.h could be improved to search
+            # XXX Pythonwin.exe / Win32uiHostGlue.h could be improved to search
             # the Python DLL itself via registry when local / relative search fails.
 
             pydll = f"Python{sys.version_info.major}{sys.version_info.minor}.dll"  # same for 32bit
diff --git a/Pythonwin/stdafx.h b/Pythonwin/stdafx.h
index cd558624a..f2285d4d4 100644
--- a/Pythonwin/stdafx.h
+++ b/Pythonwin/stdafx.h
@@ -35,7 +35,7 @@ programmers who forget to use the new names. */
 #include "pythonrun.h"
 #include "import.h"  // Python: for dynamicattach routines.
 
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 // don't need all of these for all, but it can't hurt (and keep the speed up!)
 
 #include "win32ui.h"
@@ -48,6 +48,6 @@ programmers who forget to use the new names. */
 
 #include "win32assoc.h"
 #include "win32cmd.h"
-#include "win32app.h"
+#include "Win32app.h"
 
 // --- EOF --- //
diff --git a/Pythonwin/stdafxdde.h b/Pythonwin/stdafxdde.h
index 1019b093f..7d848b836 100644
--- a/Pythonwin/stdafxdde.h
+++ b/Pythonwin/stdafxdde.h
@@ -13,7 +13,7 @@
 
 // The Pythonwin stuff
 #include "oleauto.h"
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 #include "win32ui.h"
 #include "win32assoc.h"
 
diff --git a/Pythonwin/stdafxole.h b/Pythonwin/stdafxole.h
index 1731eb138..d30a6907e 100644
--- a/Pythonwin/stdafxole.h
+++ b/Pythonwin/stdafxole.h
@@ -30,7 +30,7 @@
 
 // don't need all of these for all, but it can't hurt (and keep the speed up!)
 
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 #include "win32ui.h"
 #include "win32assoc.h"
 #include "win32cmd.h"
diff --git a/Pythonwin/win32oleDlgInsert.cpp b/Pythonwin/win32oleDlgInsert.cpp
index 8a312b4d0..9da5eb7d9 100644
--- a/Pythonwin/win32oleDlgInsert.cpp
+++ b/Pythonwin/win32oleDlgInsert.cpp
@@ -2,8 +2,8 @@
 
 #include "win32dlg.h"
 #include "win32oleDlgs.h"
-#include "pythoncom.h"
-#include "pywintypes.h"
+#include "PythonCOM.h"
+#include "PyWinTypes.h"
 // @doc
 
 // XXX - is this actually used?????????
diff --git a/Pythonwin/win32uimodule.cpp b/Pythonwin/win32uimodule.cpp
index e0207a2d0..fb2a916a8 100644
--- a/Pythonwin/win32uimodule.cpp
+++ b/Pythonwin/win32uimodule.cpp
@@ -12,7 +12,7 @@ generates Windows .hlp files.
 */
 #include "stdafx.h"
 #include 
-#include "win32uiHostGlue.h"
+#include "Win32uiHostGlue.h"
 #include "win32win.h"
 #include "win32control.h"
 #include "win32doc.h"
@@ -705,7 +705,7 @@ PyObject *Python_do_callback(PyObject *themeth, PyObject *thearglst)
     return result;
 }
 
-// Copied from PyRecord.cpp, should move into pywintypes.h
+// Copied from PyRecord.cpp, should move into PyWinTypes.h
 // Unicode versions of '_Concat' etc have different sigs.  Make them the
 // same here...
 void PyWinCoreString_Concat(register PyObject **pv, register PyObject *w)
diff --git a/Pythonwin/win32uioledoc.cpp b/Pythonwin/win32uioledoc.cpp
index 3291c64e9..0c7049221 100644
--- a/Pythonwin/win32uioledoc.cpp
+++ b/Pythonwin/win32uioledoc.cpp
@@ -1,8 +1,8 @@
 #include "stdafxole.h"
-#include "win32app.h"
+#include "Win32app.h"
 #include "win32uioledoc.h"
 #include "win32template.h"
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 //
 // OLE Document Object
 //
diff --git a/com/win32com/src/oleargs.cpp b/com/win32com/src/oleargs.cpp
index 0e18d51d8..e19cd99c3 100644
--- a/com/win32com/src/oleargs.cpp
+++ b/com/win32com/src/oleargs.cpp
@@ -19,7 +19,7 @@ static PyObject *PyVariant_Type;
 // new array (old behaviour)
 #define BYREF_ARRAY_USE_EXISTING_ARRAY
 
-// Need to put this in pywintypes.h with rest of compatibility macros
+// Need to put this in PyWinTypes.h with rest of compatibility macros
 #define PYWIN_BUFFER_CHECK(obj) (PyBytes_Check(obj) || PyByteArray_Check(obj) || PyMemoryView_Check(obj))
 
 // A little helper just for this file
diff --git a/com/win32comext/adsi/src/PyADSIUtil.cpp b/com/win32comext/adsi/src/PyADSIUtil.cpp
index 9aecc2674..f42066804 100644
--- a/com/win32comext/adsi/src/PyADSIUtil.cpp
+++ b/com/win32comext/adsi/src/PyADSIUtil.cpp
@@ -1,7 +1,7 @@
 // @doc
 #include "Python.h"
 #include "pyerrors.h"  // for PyErr_Warn in 2.5...
-#include "Windows.h"
+#include "windows.h"
 #include "PyWinTypes.h"
 #include "PythonCOM.h"
 #include "PyADSIUtil.h"
diff --git a/com/win32comext/adsi/src/adsilib.i b/com/win32comext/adsi/src/adsilib.i
index fa74a61bd..86f0fac01 100644
--- a/com/win32comext/adsi/src/adsilib.i
+++ b/com/win32comext/adsi/src/adsilib.i
@@ -1,7 +1,7 @@
 /* ADSI SWIG Support */
 
 %{
-#include "pyadsiutil.h"
+#include "PyADSIUtil.h"
 
 extern PyObject *OleSetADSIError(HRESULT hr, IUnknown *pUnk, REFIID iid);
 %}
diff --git a/com/win32comext/directsound/src/PyDSBCAPS.cpp b/com/win32comext/directsound/src/PyDSBCAPS.cpp
index 0f4100afa..af1326da5 100644
--- a/com/win32comext/directsound/src/PyDSBCAPS.cpp
+++ b/com/win32comext/directsound/src/PyDSBCAPS.cpp
@@ -113,9 +113,9 @@ PyTypeObject PyDSBCAPSType = {
                                                          // application not using DirectSound. In this situation, the
                                                          // application's normal buffers are muted, but the sticky focus
                                                          // buffers are still audible. This is useful for nongame
-                                                         // applications, such as movie playback (DirectShow™), when the
+                                                         // applications, such as movie playback (DirectShow�), when the
                                                          // user wants to hear the soundtrack while typing in Microsoft
-                                                         // Word or Microsoft® Excel, for example. However, if the user
+                                                         // Word or Microsoft� Excel, for example. However, if the user
                                                          // switches to another DirectSound application, all sound
                                                          // buffers, both normal and sticky focus, in the previous
                                                          // application are muted.
diff --git a/com/win32comext/directsound/src/PyDSBUFFERDESC.cpp b/com/win32comext/directsound/src/PyDSBUFFERDESC.cpp
index 169d8121d..794c8066d 100644
--- a/com/win32comext/directsound/src/PyDSBUFFERDESC.cpp
+++ b/com/win32comext/directsound/src/PyDSBUFFERDESC.cpp
@@ -103,8 +103,8 @@ PyTypeObject PyDSBUFFERDESCType = {
     // IDirectSound::CreateSoundBuffer call. With this flag set, an application using DirectSound can continue to play
     // its sticky focus buffers if the user switches to another application not using DirectSound. In this situation,
     // the application's normal buffers are muted, but the sticky focus buffers are still audible. This is useful for
-    // nongame applications, such as movie playback (DirectShow™), when the user wants to hear the soundtrack while
-    // typing in Microsoft Word or Microsoft® Excel, for example. However, if the user switches to another DirectSound
+    // nongame applications, such as movie playback (DirectShow�), when the user wants to hear the soundtrack while
+    // typing in Microsoft Word or Microsoft� Excel, for example. However, if the user switches to another DirectSound
     // application, all sound buffers, both normal and sticky focus, in the previous application are muted.
     // @flag DSBCAPS_GLOBALFOCUS|The buffer is a global sound buffer. With this flag set, an application using
     // DirectSound can continue to play its buffers if the user switches focus to another application, even if the new
diff --git a/isapi/src/PyExtensionObjects.cpp b/isapi/src/PyExtensionObjects.cpp
index fd309a1da..d142c9ffd 100644
--- a/isapi/src/PyExtensionObjects.cpp
+++ b/isapi/src/PyExtensionObjects.cpp
@@ -25,7 +25,7 @@
 
 // #define PY_SSIZE_T_CLEAN  // defined by isapi\src\StdAfx.h
 #include "stdafx.h"
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 #include "Utils.h"
 #include "PyExtensionObjects.h"
 #include "PythonEng.h"
diff --git a/isapi/src/PyFilterObjects.cpp b/isapi/src/PyFilterObjects.cpp
index 917420297..7dce4414f 100644
--- a/isapi/src/PyFilterObjects.cpp
+++ b/isapi/src/PyFilterObjects.cpp
@@ -25,9 +25,9 @@
 
 // #define PY_SSIZE_T_CLEAN  // defined by isapi\src\StdAfx.h
 #include "stdafx.h"
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 #include "Utils.h"
-#include "pyFilterObjects.h"
+#include "PyFilterObjects.h"
 
 // @doc
 
diff --git a/isapi/src/PythonEng.cpp b/isapi/src/PythonEng.cpp
index f58deea79..0827c8877 100644
--- a/isapi/src/PythonEng.cpp
+++ b/isapi/src/PythonEng.cpp
@@ -29,8 +29,8 @@
 #include "stdafx.h"
 #include "Utils.h"
 #include "PythonEng.h"
-#include "pyExtensionObjects.h"
-#include "pyFilterObjects.h"
+#include "PyExtensionObjects.h"
+#include "PyFilterObjects.h"
 #include "pyISAPI_messages.h"
 
 extern HINSTANCE g_hInstance;
diff --git a/isapi/src/pyISAPI.cpp b/isapi/src/pyISAPI.cpp
index 12c789cb5..6838fc213 100644
--- a/isapi/src/pyISAPI.cpp
+++ b/isapi/src/pyISAPI.cpp
@@ -28,8 +28,8 @@
 
 #include "stdafx.h"
 #include "pyISAPI.h"
-#include "pyExtensionObjects.h"
-#include "pyFilterObjects.h"
+#include "PyExtensionObjects.h"
+#include "PyFilterObjects.h"
 
 static const char *name_ext_factory = "__ExtensionFactory__";
 static const char *name_ext_init = "GetExtensionVersion";
diff --git a/win32/src/PerfMon/PyPerfMon.cpp b/win32/src/PerfMon/PyPerfMon.cpp
index fc4decfc7..e4e29957e 100644
--- a/win32/src/PerfMon/PyPerfMon.cpp
+++ b/win32/src/PerfMon/PyPerfMon.cpp
@@ -13,7 +13,7 @@ generates Windows .hlp files.
 ******************************************************************/
 
 #include "PyWinTypes.h"
-#include "Pyperfmon.h"
+#include "pyperfmon.h"
 #include "tchar.h"
 
 extern PyObject *PerfmonMethod_NewPERF_COUNTER_DEFINITION(PyObject *self, PyObject *args);
diff --git a/win32/src/PyOVERLAPPED.cpp b/win32/src/PyOVERLAPPED.cpp
index 5a5af5a8d..272392ae0 100644
--- a/win32/src/PyOVERLAPPED.cpp
+++ b/win32/src/PyOVERLAPPED.cpp
@@ -110,7 +110,7 @@ PYWINTYPES_EXPORT PyTypeObject PyOVERLAPPEDType = {
     {"Offset", T_ULONG,
      OFF(m_overlapped.Offset)},  // @prop integer|Offset|Specifies a file position at which to start the transfer. The
                                  // file position is a byte offset from the start of the file. The calling process sets
-                                 // this member before calling the ReadFile or WriteFile function. This member is
+                                 // this member before calling the ReadFile�or WriteFile function. This member is
                                  // ignored when reading from or writing to named pipes and communications devices.
     {"OffsetHigh", T_ULONG, OFF(m_overlapped.OffsetHigh)},  // @prop integer|OffsetHigh|Specifies the high word of the
                                                             // byte offset at which to start the transfer.
@@ -123,7 +123,7 @@ PYWINTYPES_EXPORT PyTypeObject PyOVERLAPPEDType = {
     {"hEvent", T_OBJECT, OFF(obDummy)},  // @prop |hEvent|Identifies an event set to the signaled state when
                                          // the transfer has been completed. The calling process sets this member before
                                          // calling the , , , or  function.
+                                         // win32pipe.ConnectNamedPipe>, or �function.
     {"Internal", T_OBJECT,
      OFF(obDummy)},  // @prop integer|Internal|Reserved for operating system use. (pointer-sized value)
     {"InternalHigh", T_OBJECT,
diff --git a/win32/src/PyTime.cpp b/win32/src/PyTime.cpp
index e728c3ff0..00524f9bc 100644
--- a/win32/src/PyTime.cpp
+++ b/win32/src/PyTime.cpp
@@ -417,7 +417,7 @@ PyObject *PyWinTimeObject_Fromtime_t(time_t t)
 }
 
 // Converts a TimeStamp, which is in 100 nanosecond units like a FILETIME
-// See comments in pywintypes.h re LARGE_INTEGER vs TimeStamp
+// See comments in PyWinTypes.h re LARGE_INTEGER vs TimeStamp
 PyObject *PyWinObject_FromTimeStamp(const LARGE_INTEGER &ts)
 {
     FILETIME ft;
diff --git a/win32/src/PyWAVEFORMATEX.cpp b/win32/src/PyWAVEFORMATEX.cpp
index e7f89462c..4f1520ab9 100644
--- a/win32/src/PyWAVEFORMATEX.cpp
+++ b/win32/src/PyWAVEFORMATEX.cpp
@@ -112,7 +112,7 @@ PYWINTYPES_EXPORT PyTypeObject PyWAVEFORMATEXType = {
                                                        // nBlockAlign should be equal to the product of nChannels and
                                                        // wBitsPerSample divided by 8 (bits per byte). For non-PCM
                                                        // formats, this member must be computed according to the
-                                                       // manufacturer’s specification of the format tag.
+                                                       // manufacturer�s specification of the format tag.
     {"wBitsPerSample", T_SHORT, OFF(m_wfx.wBitsPerSample), 0,
      "Bits per sample for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be "
      "equal to 8 or 16."},  // @prop integer|wBitsPerSample|Bits per sample for the wFormatTag format type. If
diff --git a/win32/src/PyWinTypes.h b/win32/src/PyWinTypes.h
index 36b39b958..e0f592000 100644
--- a/win32/src/PyWinTypes.h
+++ b/win32/src/PyWinTypes.h
@@ -4,7 +4,7 @@
 
 // If building under a GCC, tweak what we need.
 #if defined(__GNUC__) && defined(_POSIX_C_SOURCE)
-// python.h complains if _POSIX_C_SOURCE is already defined
+// Python.h complains if _POSIX_C_SOURCE is already defined
 #undef _POSIX_C_SOURCE
 #endif
 
diff --git a/win32/src/PyWinTypesmodule.cpp b/win32/src/PyWinTypesmodule.cpp
index d348ec2a0..4579019b6 100644
--- a/win32/src/PyWinTypesmodule.cpp
+++ b/win32/src/PyWinTypesmodule.cpp
@@ -71,7 +71,7 @@ PyObject *PyBuffer_FromMemory(void *buf, Py_ssize_t size)
     return PyMemoryView_FromBuffer(&info);
 }
 
-// See comments in pywintypes.h for why we need this!
+// See comments in PyWinTypes.h for why we need this!
 void PyWin_MakePendingCalls()
 {
     while (1) {
@@ -633,7 +633,7 @@ BOOL PyWinObject_AsSimplePARAM(PyObject *ob, WPARAM *wparam)
 
 // Converts for WPARAM and LPARAM: int or str (WCHAR*) or buffer (pointer to its locked memory)
 // (WPARAM is defined as UINT_PTR, and LPARAM is defined as LONG_PTR - see
-// pywintypes.h for inline functions to resolve this)
+// PyWinTypes.h for inline functions to resolve this)
 BOOL PyWinObject_AsPARAM(PyObject *ob, PyWin_PARAMHolder *holder)
 {
     assert(!PyErr_Occurred());  // lingering exception?
diff --git a/win32/src/_winxptheme.i b/win32/src/_winxptheme.i
index 29ac97105..cffa3ce28 100644
--- a/win32/src/_winxptheme.i
+++ b/win32/src/_winxptheme.i
@@ -16,7 +16,7 @@
 
 %{
 #undef PyHANDLE
-#include "pywinobjects.h"
+#include "PyWinObjects.h"
 #include "windows.h"
 #include "Uxtheme.h"
 #include "CommCtrl.h"
diff --git a/win32/src/timermodule.cpp b/win32/src/timermodule.cpp
index 733689747..7f2a5d29a 100644
--- a/win32/src/timermodule.cpp
+++ b/win32/src/timermodule.cpp
@@ -8,7 +8,7 @@
 
 // @doc - Contains autoduck comments for documentation
 
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 // #include "abstract.h"
 
 static PyObject *timer_id_callback_map = NULL;
diff --git a/win32/src/win32clipboardmodule.cpp b/win32/src/win32clipboardmodule.cpp
index 65077657c..699199b75 100644
--- a/win32/src/win32clipboardmodule.cpp
+++ b/win32/src/win32clipboardmodule.cpp
@@ -15,7 +15,7 @@
 
 #define PY_SSIZE_T_CLEAN  // this should be Py_ssize_t clean!
 
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 
 #define CHECK_NO_ARGS2(args, fnName)              \
     do {                                          \
diff --git a/win32/src/win32dynamicdialog.cpp b/win32/src/win32dynamicdialog.cpp
index 2b1992d67..a1543b27a 100644
--- a/win32/src/win32dynamicdialog.cpp
+++ b/win32/src/win32dynamicdialog.cpp
@@ -37,8 +37,8 @@
 #include "CommCtrl.h"
 #include "windowsx.h"  // For edit control hacks.
 
-#include "pywintypes.h"
-#include "pywinobjects.h"
+#include "PyWinTypes.h"
+#include "PyWinObjects.h"
 #include "tchar.h"
 
 #define BASED_CODE
diff --git a/win32/src/win32file.i b/win32/src/win32file.i
index fec0e8bb0..5a203c0e3 100644
--- a/win32/src/win32file.i
+++ b/win32/src/win32file.i
@@ -42,7 +42,7 @@
 
 #include "winsock2.h"
 #include "mswsock.h"
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 #include "winbase.h"
 #include "assert.h"
 #include 
diff --git a/win32/src/win32gui.i b/win32/src/win32gui.i
index d7c36cd65..8cff6650a 100644
--- a/win32/src/win32gui.i
+++ b/win32/src/win32gui.i
@@ -8,7 +8,7 @@
 
 %{
 #undef PyHANDLE
-#include "pywinobjects.h"
+#include "PyWinObjects.h"
 #include "winuser.h"
 #include "CommCtrl.h"
 #include "windowsx.h" // For edit control hacks.
diff --git a/win32/src/win32inet.i b/win32/src/win32inet.i
index 3093dab4f..24d1018de 100644
--- a/win32/src/win32inet.i
+++ b/win32/src/win32inet.i
@@ -2,7 +2,7 @@
 // @doc
 %module win32inet // An interface to the Windows internet (wininet) API
 %{
-#include "Windows.h"
+#include "windows.h"
 #include "WinInet.h"
 #undef BOOLAPI // wininet.h defines this!
 %}
@@ -12,7 +12,7 @@
 
 %{
 #undef PyHANDLE // undef earlier define, so we are back to the class.
-#include "pywinobjects.h"
+#include "PyWinObjects.h"
 
 void CALLBACK PyHINTERNET_StatusChange(
 	HINTERNET hInternet,
diff --git a/win32/src/win32inet_winhttp.cpp b/win32/src/win32inet_winhttp.cpp
index a3292da67..2c7b0ea1a 100644
--- a/win32/src/win32inet_winhttp.cpp
+++ b/win32/src/win32inet_winhttp.cpp
@@ -6,8 +6,8 @@
 // The intent is to only wrap stuff which isn't otherwise doable from
 // Python, such as the proxy stuff.
 
-#include "pywintypes.h"
-#include "pywinobjects.h"
+#include "PyWinTypes.h"
+#include "PyWinObjects.h"
 #include "winhttp.h"
 
 // @doc
diff --git a/win32/src/win32lzmodule.cpp b/win32/src/win32lzmodule.cpp
index 651bdcfc8..9ac540638 100644
--- a/win32/src/win32lzmodule.cpp
+++ b/win32/src/win32lzmodule.cpp
@@ -11,7 +11,7 @@ generates Windows .hlp files.
 
 ******************************************************************/
 
-#include "Pywintypes.h"
+#include "PyWinTypes.h"
 #include "lzexpand.h"
 
 static PyObject *obHandleMap = NULL;
diff --git a/win32/src/win32rasmodule.cpp b/win32/src/win32rasmodule.cpp
index d8207009f..2b6d859e5 100644
--- a/win32/src/win32rasmodule.cpp
+++ b/win32/src/win32rasmodule.cpp
@@ -11,7 +11,7 @@ generates Windows .hlp files.
 
 ******************************************************************/
 
-#include "pywintypes.h"
+#include "PyWinTypes.h"
 #include "ras.h"
 #include "raserror.h"
 
diff --git a/win32/src/win32wnet/PyNCB.cpp b/win32/src/win32wnet/PyNCB.cpp
index e2290be5d..ee73e803c 100644
--- a/win32/src/win32wnet/PyNCB.cpp
+++ b/win32/src/win32wnet/PyNCB.cpp
@@ -17,9 +17,9 @@
  ******************************************************************/
 // @doc
 
-#include "Pywintypes.h"
+#include "PyWinTypes.h"
 #include 
-#include "python.h"
+#include "Python.h"
 #include "PyNCB.h"
 
 #include 
diff --git a/win32/src/win32wnet/PyNetresource.cpp b/win32/src/win32wnet/PyNetresource.cpp
index 9d928b326..8e258aeb3 100644
--- a/win32/src/win32wnet/PyNetresource.cpp
+++ b/win32/src/win32wnet/PyNetresource.cpp
@@ -18,7 +18,7 @@
 // @doc
 
 #include "PyWinTypes.h"
-#include "netres.h"  // C++ header file for NETRESOURCE object
+#include "Netres.h"  // C++ header file for NETRESOURCE object
 
 static PyObject *NETRESOURCE_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
diff --git a/win32/src/win32wnet/win32wnet.cpp b/win32/src/win32wnet/win32wnet.cpp
index fe5c6ccb1..a57ff9d89 100644
--- a/win32/src/win32wnet/win32wnet.cpp
+++ b/win32/src/win32wnet/win32wnet.cpp
@@ -38,8 +38,8 @@
 
 #include "PyWinTypes.h"
 #include "PyWinObjects.h"  // for the PyHANDLE impl.
-#include "netres.h"        // NETRESOURCE Type
-#include "pyncb.h"
+#include "Netres.h"        // NETRESOURCE Type
+#include "PyNCB.h"
 
 /****************************************************************************
         HELPER FUNCTIONS

From e64725b1e328b4073e1234ff13f5b8f78669b69d Mon Sep 17 00:00:00 2001
From: Avasam 
Date: Wed, 25 Feb 2026 22:25:39 -0500
Subject: [PATCH 18/19] Add more matrix

---
 .github/workflows/main.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 167430119..bd6f60b30 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -24,7 +24,8 @@ jobs:
       matrix:
         include:
           - { sys: mingw64, env: x86_64, plat-name: win-amd64 }
-          # - { sys: mingw32, env: i686, plat-name: win32  }
+          - { sys: mingw32, env: i686, plat-name: win32  }
+          - { sys: ucrt64,  env: ucrt-x86_64, plat-name: win-amd64 }
           # No ARM yet, that currently requires using clang
     steps:
       - uses: actions/checkout@v4

From daab1c170b9b4c6b26ab71c2b73aa6c3ed181f7f Mon Sep 17 00:00:00 2001
From: Avasam 
Date: Wed, 25 Feb 2026 23:14:45 -0500
Subject: [PATCH 19/19] Add helpful mingw build script

---
 build_mingw.ps1 | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 build_mingw.ps1

diff --git a/build_mingw.ps1 b/build_mingw.ps1
new file mode 100644
index 000000000..5d130701d
--- /dev/null
+++ b/build_mingw.ps1
@@ -0,0 +1,13 @@
+#!/usr/bin/env pwsh
+if (-not $IsLinux) {
+    Write-Error "Linux required: use MSYS2 on Windows for native MinGW builds"
+    exit 1
+}
+
+$Env:CC       = 'x86_64-w64-mingw32-gcc'
+$Env:CXX      = 'x86_64-w64-mingw32-g++'
+$Env:AR       = 'x86_64-w64-mingw32-ar'
+$Env:RANLIB   = 'x86_64-w64-mingw32-ranlib'
+$Env:LDSHARED = 'x86_64-w64-mingw32-gcc -shared'
+
+uv pip install . --force-reinstall