Loading...
Searching...
No Matches
process_windows.f90
Go to the documentation of this file.
1!> @file
2!! @defgroup group_process_windows Windows process utilities
3!! Windows implementation of process inspection for FPX.
4!!
5!! Uses ToolHelp32 API to inspect running processes without external tools.
6!! No C wrappers, no shell calls.
7!!
8!! @ingroup group_process
9!! @cond
10#ifdef _WIN32
11module fpx_process_windows
12 use iso_c_binding
13 use iso_fortran_env
14
15 implicit none; private
16
17 public :: get_process_name_windows, &
18 get_parent_pid_windows
19
20 integer(c_int32_t), parameter :: TH32CS_SNAPPROCESS = int(z'00000002', c_int32_t)
21 integer(c_intptr_t), parameter :: INVALID_HANDLE = -1_c_intptr_t
22 integer, parameter :: MAX_PATH = 260
23
24 type, bind(C) :: PROCESSENTRY32W
25 integer(c_int32_t) :: dwSize
26 integer(c_int32_t) :: cntUsage
27 integer(c_int32_t) :: th32ProcessID
28 integer(c_intptr_t) :: th32DefaultHeapID
29 integer(c_int32_t) :: th32ModuleID
30 integer(c_int32_t) :: cntThreads
31 integer(c_int32_t) :: th32ParentProcessID
32 integer(c_int32_t) :: pcPriClassBase
33 integer(c_int32_t) :: dwFlags
34 integer(c_int16_t) :: szExeFile(MAX_PATH)
35 end type
36
37 interface
38 function getcurrentprocessid() bind(C, name='GetCurrentProcessId')
39 import; implicit none
40 integer(c_int32_t) :: GetCurrentProcessId
41 end function
42
43 function createtoolhelp32snapshot(flags, pid) bind(C, name='CreateToolhelp32Snapshot')
44 import; implicit none
45 integer(c_int32_t), value :: flags
46 integer(c_int32_t), value :: pid
47 integer(c_intptr_t) :: CreateToolhelp32Snapshot
48 end function
49
50 function process32firstw(hSnap, pe) bind(C, name='Process32FirstW')
51 import; implicit none
52 integer(c_intptr_t), value :: hSnap
53 type(PROCESSENTRY32W) :: pe
54 integer(c_int) :: Process32FirstW
55 end function
56
57 function process32nextw(hSnap, pe) bind(C, name='Process32NextW')
58 import; implicit none
59 integer(c_intptr_t), value :: hSnap
60 type(PROCESSENTRY32W) :: pe
61 integer(c_int32_t) :: Process32NextW
62 end function
63
64 function closehandle(h) bind(C, name='CloseHandle')
65 import; implicit none
66 integer(c_intptr_t), value :: h
67 integer(c_int32_t) :: CloseHandle
68 end function
69 end interface
70
71contains
72
73 function utf16_to_string(w) result(str)
74 integer(c_int16_t), intent(in) :: w(:)
75 character(:), allocatable :: str
76 !private
77 integer :: i, n
78
79 n = 0
80 do i = 1, size(w)
81 if (w(i) == 0) exit
82 n = n + 1
83 end do
84
85 allocate(character(n) :: str)
86
87 do i = 1, n
88 str(i:i) = achar(int(w(i)))
89 end do
90 end function
91
92 pure function strip_exe(name) result(out)
93 character(*), intent(in) :: name
94 character(:), allocatable :: out
95
96 if (len(name) > 4) then
97 if (name(len(name)-3:) == '.exe') then
98 out = name(:len(name)-4)
99 return
100 end if
101 end if
102
103 out = name
104 end function
105
106 integer(c_int32_t) function current_pid() result(pid)
107 pid = getcurrentprocessid()
108 end function
109
110 integer(c_int32_t) function get_parent_pid_windows() result(ppid)
111 !private
112 type(PROCESSENTRY32W), target :: pe
113 integer(c_intptr_t) :: snap
114 integer(c_int32_t) :: ios, pid
115
116 ppid = 0
117 pid = current_pid()
118
119 snap = createtoolhelp32snapshot(th32cs_snapprocess, 0)
120
121 if (snap == invalid_handle) return
122
123 pe%dwSize = c_sizeof(pe)
124
125 if (process32firstw(snap, pe) /= 0) then
126
127 do
128 if (pe%th32ProcessID == pid) then
129 ppid = pe%th32ParentProcessID
130 exit
131 end if
132
133 if (process32nextw(snap, pe) == 0) exit
134 end do
135
136 end if
137
138 ios = closehandle(snap)
139 end function
140
141 function get_process_name_windows(pid) result(name)
142 integer(c_int32_t), intent(in) :: pid
143 character(:), allocatable :: name
144 !private
145 type(PROCESSENTRY32W), target :: pe
146 integer(c_intptr_t) :: snap
147 integer(c_int32_t) :: ios
148
149 name = ''
150
151 snap = createtoolhelp32snapshot(th32cs_snapprocess, 0_c_int32_t)
152 if (snap == invalid_handle) return
153
154 pe%dwSize = c_sizeof(pe)
155
156 if (process32firstw(snap, pe) /= 0) then
157
158 do
159 if (pe%th32ProcessID == pid) then
160 name = utf16_to_string(pe%szExeFile)
161 exit
162 end if
163
164 if (process32nextw(snap, pe) == 0) exit
165 end do
166
167 end if
168
169 ios = closehandle(snap)
170
171 name = strip_exe(name)
172 end function
173end module
174#endif
175!! @endcond