Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build_dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ env:

jobs:
build:
runs-on: windows-2019
runs-on: windows-2025

steps:
- uses: actions/checkout@v3
Expand All @@ -19,9 +19,9 @@ jobs:
working-directory: ${{github.workspace}}/backends/dotnet
run: |
mkdir build32
cmake -G "Visual Studio 16 2019" -A Win32 -B ${{github.workspace}}/backends/dotnet/build32
cmake -G "Visual Studio 17 2022" -A Win32 -B ${{github.workspace}}/backends/dotnet/build32
mkdir build64
cmake -G "Visual Studio 16 2019" -A x64 -B ${{github.workspace}}/backends/dotnet/build64
cmake -G "Visual Studio 17 2022" -A x64 -B ${{github.workspace}}/backends/dotnet/build64


- name: Build
Expand All @@ -31,7 +31,7 @@ jobs:
cmake --build ./build64 --target install --config ${{env.BUILD_TYPE}}

- name: Collecting artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: dotnet_bin
path: backends/dotnet/bin
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
*.i*86
*.x86_64
*.hex
backends/*.dll

# Debug files
*.dSYM/
Expand All @@ -49,3 +50,9 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf

# Build artifacts
*build_*

# editable package data
*.egg-info*
11 changes: 11 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Requirements for development purposes

* setuptools >= 65.5.1
* wheel >= 0.38.4
* .NET Framework Targeting Pack >= 4.8
* .NET Compiler Platform
* MSBuild
* MSVC >= 143
* cmake >= 3.26.3

**NOTE**: You may use PyCharm + Visual Studio with C++/C# components for development
3 changes: 2 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
BSD 3-Clause License

Copyright (c) 2018,
Copyright (c) 2025 Vasily Ryabov, Ilya Naumov, Boris Galochkin, Alexander Makarov
https://github.com/pywinauto/injected/graphs/contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
14 changes: 14 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
include injected/libs/dotnet/x86/bootstrap.dll
include injected/libs/dotnet/x86/Newtonsoft.Json.dll
include injected/libs/dotnet/x86/worker_wpf.dll

include injected/libs/dotnet/x64/bootstrap.dll
include injected/libs/dotnet/x64/Newtonsoft.Json.dll
include injected/libs/dotnet/x64/worker_wpf.dll


include injected/libs/hook/x86/pywinmsg32.dll
include injected/libs/hook/x86/pywinmsg32u.dll

include injected/libs/hook/x64/pywinmsg64.dll
include injected/libs/hook/x64/pywinmsg64u.dll
66 changes: 63 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,65 @@
# injected
Source code of DLLs / assemblies for injection into target process

usage:
py -2.7 example_injector.py \<Process name\> \<path to dll\>
injected is a Python package that allows you to inject DLLs into running
processes on Windows (32 or 64-bit).

This can be useful for various tasks, such as debugging or adding
functionality to existing applications.

This is initially created for desktop GUI automation purpose
(project pywinauto), because an injected DLL can access GUI widgets' text
properties with much better precision and coverage than standard OS APIs like
MS UI Automation API or Win32 API. Other use cases are potentially possible at
your own risk according to the law and the project license.

It contains:

* initial DLL to be injected which is written in C,
* server-side DLL that can exchange data between injected DLL (server) and
Python process (client),
* managed DLL which is able to get text properties of WPF applications,
* DLL which is able to get text properties of Qt applications,
* Python code to initiate the injection process,
* and client Python code for data exchange with an injected DLL.

Link to PyPi: <https://pypi.org/project/injected/>

## How to use

python.exe example_injector.py \<Process name\> \<path to dll\>

## Development

1. Clone repository: <https://github.com/pywinauto/injected.git>
2. Create new features or improve exiting (for the injected package)
3. After work run setup.py from project root to check standalone

python.exe setup.py bdist_wheel

## Requirements

### For use as package

* Python >= 3.7
* pywin32 >= 306

### For development purpose

* setuptools >= 65.5.1
* wheel >= 0.38.4
* .NET Framework Targeting Pack >= 4.8
* .NET Compiler Platform
* MSBuild
* MSVC >= 143
* cmake >= 3.26.3

**NOTE**: You may use PyCharm + Visual Studio with C++/C# components for
development

## License

This software is open-source under the BSD 3-Clause License.

See the LICENSE file in this repository.

Dependencies are licensed by their own licenses.
2 changes: 1 addition & 1 deletion backends/dotnet/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.15)
cmake_minimum_required(VERSION 3.10)
project(injected_dotnet LANGUAGES CXX CSharp)

set(BACKEND_BIN_DIR ${CMAKE_CURRENT_LIST_DIR}/bin)
Expand Down
2 changes: 1 addition & 1 deletion backends/dotnet/src/wpf/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(CMAKE_CSharp_FLAGS "/platform:x86")
endif()

set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "v4.0")
set(CMAKE_DOTNET_TARGET_FRAMEWORK_VERSION "v4.8")

file(GLOB_RECURSE SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/*.cs"
Expand Down
3 changes: 3 additions & 0 deletions backends/hook/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.10)
project(injected_hook)
add_subdirectory("src/winmsg_listener")
3 changes: 0 additions & 3 deletions backends/hook/src/CMakeLists.txt

This file was deleted.

2 changes: 2 additions & 0 deletions backends/hook/src/winmsg_listener/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
cmake_minimum_required(VERSION 3.10)

project( winmsg_cather CXX )

set( SOURCE_LIB dllmain.cpp )
set ( CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON )

if (CMAKE_SIZEOF_VOID_P EQUAL 8)
add_library( pywinmsg64 SHARED ${SOURCE_LIB} )
else ()
Expand Down
3 changes: 3 additions & 0 deletions backends/qt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.10)
project(Testfile)
add_subdirectory("src/winmsg_listener")
38 changes: 38 additions & 0 deletions backends/qt/src/winmsg_listener/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
cmake_minimum_required(VERSION 3.10)
project(qt_srv LANGUAGES CXX)

# Make Qt's moc run automatically for files with Q_OBJECT
set(CMAKE_AUTOMOC ON)

# Qt5/Qt6 compatible find_package
find_package(QT NAMES Qt5 COMPONENTS
Core
Network
Gui
Widgets
REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS
Core
Network
Gui
Widgets
REQUIRED)

add_library(qt_srv SHARED
dllmain.cpp
qt_server.h
qt_server.cpp
)

target_link_libraries(qt_srv PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Optional but nice: stable DLL name
set_target_properties(qt_srv PROPERTIES OUTPUT_NAME "qt_srv")
27 changes: 27 additions & 0 deletions backends/qt/src/winmsg_listener/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <windows.h>
#include <thread>
#include "qt_server.h"

// Keep DllMain small and start server in Qt GUI thread
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);

// Spawn a detached worker that will bootstrap on its own time.
std::thread([] {
QtHelloServer::bootstrap(); // waits for QCoreApplication, then queues start() on Qt thread
}).detach();
break;

case DLL_PROCESS_DETACH:
// Stop on the Qt thread
QtHelloServer::shutdown();
break;

default:
break;
}
return TRUE;
}

Loading