Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suspend Windows processes recursively #227

Merged
merged 2 commits into from
Oct 3, 2024
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
53 changes: 53 additions & 0 deletions lib/native_platform/src/process/repository/src/win32/win32.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// ignore_for_file: non_constant_identifier_names, constant_identifier_names

import 'dart:convert';
import 'dart:ffi';

final _kernel32 = DynamicLibrary.open('kernel32.dll');

final CreateToolhelp32Snapshot =
_kernel32.lookupFunction<IntPtr Function(Uint32, Uint32), int Function(int, int)>(
'CreateToolhelp32Snapshot');

final Process32First = _kernel32.lookupFunction<
Int32 Function(IntPtr hSnapshot, Pointer<PROCESSENTRY32> lppe),
int Function(int hSnapshot, Pointer<PROCESSENTRY32> lppe)>('Process32First');

final Process32Next = _kernel32.lookupFunction<
Int32 Function(IntPtr hSnapshot, Pointer<PROCESSENTRY32> lppe),
int Function(int hSnapshot, Pointer<PROCESSENTRY32> lppe)>('Process32Next');

final class PROCESSENTRY32 extends Struct {
@Int32()
external int dwSize;
@Int32()
external int cntUsage;
@Int32()
external int th32ProcessID;
external Pointer<Uint32> th32DefaultHeapID;
@Int32()
external int th32ModuleID;
@Int32()
external int cntThreads;
@Int32()
external int th32ParentProcessID;
@Int32()
external int pcPriClassBase;
@Int32()
external int dwFlags;
@Array(260)
external Array<Uint8> _szExeFile;
String get szExeFile => _unwrap(_szExeFile);
}

String _unwrap(Array<Uint8> bytes) {
String buf = "";
int i = 0;
while (bytes[i] != 0) {
buf += utf8.decode([bytes[i]]);
i += 1;
}
return buf;
}

const TH32CS_SNAPPROCESS = 0x00000002;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:win32_suspend_process/win32_suspend_process.dart';

import '../../../../../logs/logs.dart';
import '../../process.dart';
import 'win32/win32.dart';

/// Provides interaction access with host system processes on Windows.
class Win32ProcessRepository extends ProcessRepository {
Expand Down Expand Up @@ -101,6 +102,15 @@ class Win32ProcessRepository extends ProcessRepository {
final successful = (result == 0);
log.i('Resuming $pid was successful: $successful');
CloseHandle(processHandle);

if (successful) {
// Resume child processes recursively.
final childPids = await _getChildProcesses(pid);
for (final childPid in childPids) {
await resume(childPid);
}
}

return successful;
}

Expand All @@ -116,9 +126,46 @@ class Win32ProcessRepository extends ProcessRepository {
final successful = (result == 0);
log.i('Suspending $pid was successful: $successful');
CloseHandle(processHandle);

if (successful) {
// Suspend child processes recursively.
final childPids = await _getChildProcesses(pid);
for (final childPid in childPids) {
await suspend(childPid);
}
}

return successful;
}

/// Returns a list of child processes for the provided [pid].
Future<List<int>> _getChildProcesses(int pid) async {
final childPids = <int>[];
final snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE) {
log.w('Failed to create snapshot: ${GetLastError()}');
return childPids;
}

final processEntry = calloc<PROCESSENTRY32>();
processEntry.ref.dwSize = sizeOf<PROCESSENTRY32>();

final isProcessFound = Process32First(snapshot, processEntry) == TRUE;
if (isProcessFound) {
do {
if (processEntry.ref.th32ParentProcessID == pid) {
childPids.add(processEntry.ref.th32ProcessID);
}
} while (Process32Next(snapshot, processEntry) == TRUE);
} else {
log.w('Failed to retrieve first process: ${GetLastError()}');
}

CloseHandle(snapshot);
calloc.free(processEntry);
return childPids;
}

/// Returns true if the process is suspended, false otherwise.
bool _isProcessSuspended(int pid) {
return _isProcessSuspendedNative(pid) == 1;
Expand Down
32 changes: 16 additions & 16 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ packages:
dependency: "direct dev"
description:
name: build_runner
sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
url: "https://pub.dev"
source: hosted
version: "2.4.12"
version: "2.4.13"
build_runner_core:
dependency: transitive
description:
Expand Down Expand Up @@ -210,10 +210,10 @@ packages:
dependency: transitive
description:
name: dart_style
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab"
url: "https://pub.dev"
source: hosted
version: "2.3.6"
version: "2.3.7"
dbus:
dependency: transitive
description:
Expand Down Expand Up @@ -640,10 +640,10 @@ packages:
dependency: transitive
description:
name: mime
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "1.0.6"
version: "2.0.0"
mockito:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -880,10 +880,10 @@ packages:
dependency: transitive
description:
name: shelf_static
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.1.3"
shelf_web_socket:
dependency: transitive
description:
Expand Down Expand Up @@ -1029,10 +1029,10 @@ packages:
dependency: "direct main"
description:
name: tray_manager
sha256: c9a63fd88bd3546287a7eb8ccc978d707eef82c775397af17dda3a4f4c039e64
sha256: bdc3ac6c36f3d12d871459e4a9822705ce5a1165a17fa837103bc842719bf3f7
url: "https://pub.dev"
source: hosted
version: "0.2.3"
version: "0.2.4"
typed_data:
dependency: transitive
description:
Expand Down Expand Up @@ -1077,10 +1077,10 @@ packages:
dependency: transitive
description:
name: url_launcher_macos
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
version: "3.2.1"
url_launcher_platform_interface:
dependency: transitive
description:
Expand Down Expand Up @@ -1173,18 +1173,18 @@ packages:
dependency: "direct main"
description:
name: win32
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
sha256: "4d45dc9069dba4619dc0ebd93c7cec5e66d8482cb625a370ac806dcc8165f2ec"
url: "https://pub.dev"
source: hosted
version: "5.5.4"
version: "5.5.5"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6"
sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852"
url: "https://pub.dev"
source: hosted
version: "1.1.4"
version: "1.1.5"
win32_suspend_process:
dependency: "direct main"
description:
Expand Down
7 changes: 6 additions & 1 deletion windows/flutter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake)
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")

# Set fallback configurations for older versions of the flutter tool.
if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
set(FLUTTER_TARGET_PLATFORM "windows-x64")
endif()

# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")

Expand Down Expand Up @@ -90,7 +95,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG>
${FLUTTER_TARGET_PLATFORM} $<CONFIG>
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
Expand Down
Loading