AxServe is a server program and client interface that provides functionalities of COM or OCX components through a gRPC server.
There are many ways to integrate COM or OCX components, such as creating native apps or using other libraries or frameworks. But they all have their own strengths and weaknesses.
Options that I had considered so far were:
Library | Module | Based On | Maintainer | Language |
---|---|---|---|---|
Win32 | Microsoft | C/C++ | ||
MFC | Microsoft | C++ | ||
Qt5 | ActiveQt | Win32 | Qt Group | C++ |
Qt6 | ActiveQt | Win32 | Qt Group | C++ |
pywin32 | win32com.client | Win32 | Mark Hammond | Python |
pywin32 | pywin.mfc.activex | MFC | Mark Hammond | Python |
PyQt5 | PyQt5.QAxContainer | Qt5 | Riverbank Computing | Python |
PyQt6 | PyQt6.QAxContainer | Qt6 | Riverbank Computing | Python |
PySide2 | PySide2.QtAxContainer | Qt5 | Qt Group | Python |
PySide6 | PySide6.QtAxContainer | Qt6 | Qt Group | Python |
And Pros & Cons of each of these options that I had experienced while using some of them were as follows:
- Requires build step
- (-) C/C++ Language options require build step
- (+) Python Language options do not require built step
- Complexity in dependency resolution and installation
- (-) Python Language options may have no proper python version that supports all requirements like target architecture (x86/x64) and version support (3.x)
- (-) And Python Language options may require multiple python installations with some IPC (Inter-Process Communication) technique as workaround
- (+) C/C++ Language options only require single installation for each target architecture once built
- (-) But C/C++ Language options may have hard time in managing it's dependencies compared to python when it comes to installation and building
- Size of dependencies
- (+) Microsoft Maintainer options require no further dependencies
- (-) Other libraries and frameworks based options may require large amount of dependencies which might complicate things
- Ease of use, amount of learning materials and references, quality of documentation
- (+) Qt based Python bindings options are easy to use, have lots of materials and references
- (+) Qt based options have good documentation and sufficient references
- (-) Other options may have less materials, might be harder to use
- (+) Python Language options are generally considered as easy compared to C++
- Possibility of being deprecated or obsolete
- (-) Qt5 Based options will become deprecated/obsolete over time in favor of Qt6
- (+) Qt6 based options are latest version in Qt
- 32bit architecture support
- Applicability of acquired knowledge across domains
- (+) Qt based options can leverage learned skills to create other applications for platforms other than windows
- (-) Other options may be too platform specific
- License
- (-) PyQt Based options require GPLv3 license, unless commercial license is used
- (+) Qt Group Maintainer options (QtX and PySideX) require LGPLv3 license
- (+) Pywin32 based options generally considered as PSF-2.0 (issue)
- (+) Microsoft Maintainer options have less license implications
My personal goal was to use 32bit COM/OCX feature in python. So based on the analysis and my goal, my final decision was:
- Not to bring the COM/OCX part of dependency to the python side
- But make the dependency loose by supporting the functionality using an IPC technique with some libraries like gRPC
- Learn Qt6 and use that for development
- Build Qt6 for 32bit architecture support on my own
- Build single server executable and use that in python
- More specifically, run the server executable using
subprocess
and connect to that usinggrpcio
And this project is the outcome of those choices.
- Run the executable by double clicking.
- Type the required information.
- CLSID required to instantiate an Active-X or COM object.
- Address URI for gRPC server to bind.
- Press start button to start server.
If built with console support, give required options to run the server as cli argument:
.\axserve-x86-console-debug.exe --clsid="{A1574A0D-6BFA-4BD7-9020-DED88711818D}" --address="localhost:8080" --no-gui
That --no-gui
option makes the application run without GUI components. This can be useful for cases like embedding this executable in other things. FYI, technically it's not a pure non-gui application but just tries to hide or not to show the windows created internally.
The GUI version also accepts the same cli arguments. But note that it cannot print any messages since there is no console attached. FYI, the GUI version uses message boxes for that instead when needed (like printing errors).
Just started working on a Python client.
Check the following codes for more information, until relevant documentations are added:
- Example usage of it example_client.py
- Example usages from tests:
- Normal synchronous API: test_iexplorer.py
- Asynchronous API under
asyncio
framework: test_iexplorer_async.py
- Python client implementation stub.py
- Proto file for gRPC service definition active.proto
vs_buildtools.exe
--add "Microsoft.VisualStudio.Workload.VCTools"
--add "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"
--add "Microsoft.VisualStudio.Component.VC.CMake.Project"
--add "Microsoft.VisualStudio.Component.VC.ATL"
--add "Microsoft.VisualStudio.Component.VC.ATLMFC"
--includeRecommended
--passive
--norestart
https://chocolatey.org/install
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
choco install git.install
choco install nasm
choco install python311
choco install cmake
choco install ninja
cmake --list-presets
cmake --preset x86-win32-debug .
cmake --build .\build\x86-win32-debug --parallel
hatch build
hatch publish