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
52 changes: 52 additions & 0 deletions Sources/Testing/Support/Additions/WinSDKAdditions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,56 @@ let STATUS_SIGNAL_CAUGHT_BITS = {

return result
}()

// MARK: - HMODULE members

extension HMODULE {
/// A helper type that manages state for ``HMODULE/all``.
private final class _AllState {
/// The toolhelp snapshot.
var snapshot: HANDLE?

/// The module iterator.
var me = MODULEENTRY32W()

deinit {
if let snapshot {
CloseHandle(snapshot)
}
}
}

/// All modules loaded in the current process.
///
/// - Warning: It is possible for one or more modules in this sequence to be
/// unloaded while you are iterating over it. To minimize the risk, do not
/// discard the sequence until iteration is complete. Modules containing
/// Swift code can never be safely unloaded.
static var all: some Sequence<Self> {
sequence(state: _AllState()) { state in
if let snapshot = state.snapshot {
// We have already iterated over the first module. Return the next one.
if Module32NextW(snapshot, &state.me) {
return state.me.hModule
}
} else {
// Create a toolhelp snapshot that lists modules.
guard let snapshot = CreateToolhelp32Snapshot(DWORD(TH32CS_SNAPMODULE), 0) else {
return nil
}
state.snapshot = snapshot

// Initialize the iterator for use by the resulting sequence and return
// the first module.
state.me.dwSize = DWORD(MemoryLayout.stride(ofValue: state.me))
if Module32FirstW(snapshot, &state.me) {
return state.me.hModule
}
}

// Reached the end of the iteration.
return nil
}
}
}
#endif
23 changes: 4 additions & 19 deletions Sources/Testing/Support/GetSymbol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,25 +70,10 @@ func symbol(in handle: ImageAddress? = nil, named symbolName: String) -> UnsafeR
}
}

// Find all the modules loaded in the current process. We assume there
// aren't more than 1024 loaded modules (as does Microsoft sample code.)
return withUnsafeTemporaryAllocation(of: HMODULE?.self, capacity: 1024) { hModules in
let byteCount = DWORD(hModules.count * MemoryLayout<HMODULE?>.stride)
var byteCountNeeded: DWORD = 0
guard K32EnumProcessModules(GetCurrentProcess(), hModules.baseAddress!, byteCount, &byteCountNeeded) else {
return nil
}

// Enumerate all modules looking for one containing the given symbol.
let hModuleCount = min(hModules.count, Int(byteCountNeeded) / MemoryLayout<HMODULE?>.stride)
let hModulesEnd = hModules.index(hModules.startIndex, offsetBy: hModuleCount)
for hModule in hModules[..<hModulesEnd] {
if let hModule, let result = GetProcAddress(hModule, symbolName) {
return unsafeBitCast(result, to: UnsafeRawPointer.self)
}
}
return nil
}
return HMODULE.all.lazy
.compactMap { GetProcAddress($0, symbolName) }
.map { unsafeBitCast($0, to: UnsafeRawPointer.self) }
.first
}
#else
#warning("Platform-specific implementation missing: Dynamic loading unavailable")
Expand Down