VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/testdriver/winbase.py@ 106199

Last change on this file since 106199 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.9 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: winbase.py 106061 2024-09-16 14:03:52Z vboxsync $
3
4"""
5This module is here to externalize some Windows specifics that gives pychecker
6a hard time when running on non-Windows systems.
7"""
8
9__copyright__ = \
10"""
11Copyright (C) 2010-2024 Oracle and/or its affiliates.
12
13This file is part of VirtualBox base platform packages, as
14available from https://www.virtualbox.org.
15
16This program is free software; you can redistribute it and/or
17modify it under the terms of the GNU General Public License
18as published by the Free Software Foundation, in version 3 of the
19License.
20
21This program is distributed in the hope that it will be useful, but
22WITHOUT ANY WARRANTY; without even the implied warranty of
23MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24General Public License for more details.
25
26You should have received a copy of the GNU General Public License
27along with this program; if not, see <https://www.gnu.org/licenses>.
28
29The contents of this file may alternatively be used under the terms
30of the Common Development and Distribution License Version 1.0
31(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
32in the VirtualBox distribution, in which case the provisions of the
33CDDL are applicable instead of those of the GPL.
34
35You may elect to license modified versions of this file under the
36terms and conditions of either the GPL or the CDDL or both.
37
38SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
39"""
40__version__ = "$Revision: 106061 $"
41
42
43# Standard Python imports.
44import ctypes;
45import os;
46import sys;
47
48# Windows specific imports.
49import pywintypes; # pylint: disable=import-error
50import winerror; # pylint: disable=import-error
51import win32con; # pylint: disable=import-error
52import win32api; # pylint: disable=import-error
53import win32console; # pylint: disable=import-error
54import win32event; # pylint: disable=import-error
55import win32process; # pylint: disable=import-error
56
57# Validation Kit imports.
58from testdriver import reporter;
59
60# Python 3 hacks:
61if sys.version_info[0] >= 3:
62 long = int; # pylint: disable=redefined-builtin,invalid-name
63
64
65#
66# Windows specific implementation of base functions.
67#
68
69def processInterrupt(uPid):
70 """
71 The Windows version of base.processInterrupt
72
73 Note! This doesn't work terribly well with a lot of processes.
74 """
75 try:
76 # pylint: disable=no-member
77 win32console.GenerateConsoleCtrlEvent(win32con.CTRL_BREAK_EVENT, uPid); # pylint: disable=c-extension-no-member
78 #GenerateConsoleCtrlEvent = ctypes.windll.kernel32.GenerateConsoleCtrlEvent
79 #rc = GenerateConsoleCtrlEvent(1, uPid);
80 #reporter.log('GenerateConsoleCtrlEvent -> %s' % (rc,));
81 fRc = True;
82 except:
83 reporter.logXcpt('uPid=%s' % (uPid,));
84 fRc = False;
85 return fRc;
86
87def postThreadMesssageClose(uTid):
88 """ Posts a WM_CLOSE message to the specified thread."""
89 fRc = False;
90 try:
91 win32api.PostThreadMessage(uTid, win32con.WM_CLOSE, 0, 0); # pylint: disable=no-member,c-extension-no-member
92 fRc = True;
93 except:
94 reporter.logXcpt('uTid=%s' % (uTid,));
95 return fRc;
96
97def postThreadMesssageQuit(uTid):
98 """ Posts a WM_QUIT message to the specified thread."""
99 fRc = False;
100 try:
101 win32api.PostThreadMessage(uTid, win32con.WM_QUIT, # pylint: disable=no-member,c-extension-no-member
102 0x40010004, 0); # DBG_TERMINATE_PROCESS
103 fRc = True;
104 except:
105 reporter.logXcpt('uTid=%s' % (uTid,));
106 return fRc;
107
108def processTerminate(uPid):
109 """ The Windows version of base.processTerminate """
110 # pylint: disable=no-member
111 fRc = False;
112 try:
113 hProcess = win32api.OpenProcess(win32con.PROCESS_TERMINATE, # pylint: disable=no-member,c-extension-no-member
114 False, uPid);
115 except:
116 reporter.logXcpt('uPid=%s' % (uPid,));
117 else:
118 try:
119 win32process.TerminateProcess(hProcess, # pylint: disable=no-member,c-extension-no-member
120 0x40010004); # DBG_TERMINATE_PROCESS
121 fRc = True;
122 except:
123 reporter.logXcpt('uPid=%s' % (uPid,));
124 hProcess.Close(); #win32api.CloseHandle(hProcess)
125 return fRc;
126
127def processKill(uPid):
128 """ The Windows version of base.processKill """
129 return processTerminate(uPid);
130
131def processExists(uPid):
132 """ The Windows version of base.processExists """
133 # We try open the process for waiting since this is generally only forbidden in a very few cases.
134 try:
135 hProcess = win32api.OpenProcess(win32con.SYNCHRONIZE, False, uPid); # pylint: disable=no-member,c-extension-no-member
136 except pywintypes.error as oXcpt: # pylint: disable=no-member
137 if oXcpt.winerror == winerror.ERROR_INVALID_PARAMETER:
138 return False;
139 if oXcpt.winerror != winerror.ERROR_ACCESS_DENIED:
140 reporter.logXcpt('uPid=%s oXcpt=%s' % (uPid, oXcpt));
141 return False;
142 reporter.logXcpt('uPid=%s oXcpt=%s' % (uPid, oXcpt));
143 except Exception as oXcpt:
144 reporter.logXcpt('uPid=%s oXcpt=%s' % (uPid, oXcpt));
145 return False;
146 else:
147 hProcess.Close(); #win32api.CloseHandle(hProcess)
148 return True;
149
150def processCheckPidAndName(uPid, sName):
151 """ The Windows version of base.processCheckPidAndName """
152 fRc = processExists(uPid);
153 if fRc is True:
154 try:
155 from win32com.client import GetObject; # pylint: disable=import-error
156 oWmi = GetObject('winmgmts:');
157 aoProcesses = oWmi.InstancesOf('Win32_Process');
158 for oProcess in aoProcesses:
159 if long(oProcess.Properties_("ProcessId").Value) == uPid:
160 sCurName = oProcess.Properties_("Name").Value;
161 reporter.log2('uPid=%s sName=%s sCurName=%s' % (uPid, sName, sCurName));
162 sName = sName.lower();
163 sCurName = sCurName.lower();
164 if os.path.basename(sName) == sName:
165 sCurName = os.path.basename(sCurName);
166
167 if sCurName == sName \
168 or sCurName + '.exe' == sName \
169 or sCurName == sName + '.exe':
170 fRc = True;
171 break;
172 except:
173 reporter.logXcpt('uPid=%s sName=%s' % (uPid, sName));
174 return fRc;
175
176#
177# Some helper functions.
178#
179def processCreate(sName, asArgs):
180 """
181 Returns a (pid, handle, tid) tuple on success. (-1, None) on failure (logged).
182 """
183
184 # Construct a command line.
185 sCmdLine = '';
186 for sArg in asArgs:
187 if sCmdLine == '':
188 sCmdLine += '"';
189 else:
190 sCmdLine += ' "';
191 sCmdLine += sArg;
192 sCmdLine += '"';
193
194 # Try start the process.
195 # pylint: disable=no-member
196 dwCreationFlags = win32con.CREATE_NEW_PROCESS_GROUP;
197 oStartupInfo = win32process.STARTUPINFO(); # pylint: disable=c-extension-no-member
198 try:
199 (hProcess, hThread, uPid, uTid) = win32process.CreateProcess(sName, # pylint: disable=c-extension-no-member
200 sCmdLine, # CommandLine
201 None, # ProcessAttributes
202 None, # ThreadAttibutes
203 1, # fInheritHandles
204 dwCreationFlags,
205 None, # Environment
206 None, # CurrentDirectory.
207 oStartupInfo);
208 except:
209 reporter.logXcpt('sName="%s" sCmdLine="%s"' % (sName, sCmdLine));
210 return (-1, None, -1);
211
212 # Dispense with the thread handle.
213 try:
214 hThread.Close(); # win32api.CloseHandle(hThread);
215 except:
216 reporter.logXcpt();
217
218 # Try get full access to the process.
219 try:
220 hProcessFullAccess = win32api.DuplicateHandle( # pylint: disable=c-extension-no-member
221 win32api.GetCurrentProcess(), # pylint: disable=c-extension-no-member
222 hProcess,
223 win32api.GetCurrentProcess(), # pylint: disable=c-extension-no-member
224 win32con.PROCESS_TERMINATE
225 | win32con.PROCESS_QUERY_INFORMATION
226 | win32con.SYNCHRONIZE
227 | win32con.DELETE,
228 False,
229 0);
230 hProcess.Close(); # win32api.CloseHandle(hProcess);
231 hProcess = hProcessFullAccess;
232 except:
233 reporter.logXcpt();
234 reporter.log2('processCreate -> %#x, hProcess=%s %#x' % (uPid, hProcess, hProcess.handle,));
235 return (uPid, hProcess, uTid);
236
237def processPollByHandle(hProcess):
238 """
239 Polls the process handle to see if it has finished (True) or not (False).
240 """
241 try:
242 dwWait = win32event.WaitForSingleObject(hProcess, 0); # pylint: disable=no-member,c-extension-no-member
243 except:
244 reporter.logXcpt('hProcess=%s %#x' % (hProcess, hProcess.handle,));
245 return True;
246 return dwWait != win32con.WAIT_TIMEOUT; #0x102; #
247
248
249def processTerminateByHandle(hProcess):
250 """
251 Terminates the process.
252 """
253 try:
254 win32api.TerminateProcess(hProcess, # pylint: disable=no-member,c-extension-no-member
255 0x40010004); # DBG_TERMINATE_PROCESS
256 except:
257 reporter.logXcpt('hProcess=%s %#x' % (hProcess, hProcess.handle,));
258 return False;
259 return True;
260
261#
262# Misc
263#
264
265def logMemoryStats():
266 """
267 Logs windows memory stats.
268 """
269 class MemoryStatusEx(ctypes.Structure):
270 """ MEMORYSTATUSEX """
271 kaFields = [
272 ( 'dwLength', ctypes.c_ulong ),
273 ( 'dwMemoryLoad', ctypes.c_ulong ),
274 ( 'ullTotalPhys', ctypes.c_ulonglong ),
275 ( 'ullAvailPhys', ctypes.c_ulonglong ),
276 ( 'ullTotalPageFile', ctypes.c_ulonglong ),
277 ( 'ullAvailPageFile', ctypes.c_ulonglong ),
278 ( 'ullTotalVirtual', ctypes.c_ulonglong ),
279 ( 'ullAvailVirtual', ctypes.c_ulonglong ),
280 ( 'ullAvailExtendedVirtual', ctypes.c_ulonglong ),
281 ];
282 _fields_ = kaFields; # pylint: disable=invalid-name
283
284 def __init__(self):
285 super(MemoryStatusEx, self).__init__();
286 self.dwLength = ctypes.sizeof(self);
287
288 try:
289 oStats = MemoryStatusEx();
290 ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(oStats));
291 except:
292 reporter.logXcpt();
293 return False;
294
295 reporter.log('Memory statistics:');
296 for sField, _ in MemoryStatusEx.kaFields:
297 reporter.log(' %32s: %s' % (sField, getattr(oStats, sField)));
298 return True;
299
300def checkProcessHeap():
301 """
302 Calls HeapValidate(GetProcessHeap(), 0, NULL);
303 """
304
305 # Get the process heap.
306 try:
307 hHeap = ctypes.windll.kernel32.GetProcessHeap();
308 except:
309 reporter.logXcpt();
310 return False;
311
312 # Check it.
313 try:
314 fIsOkay = ctypes.windll.kernel32.HeapValidate(hHeap, 0, None);
315 except:
316 reporter.logXcpt();
317 return False;
318
319 if fIsOkay == 0:
320 reporter.log('HeapValidate failed!');
321
322 # Try trigger a dump using c:\utils\procdump64.exe.
323 from common import utils;
324
325 iPid = os.getpid();
326 asArgs = [ 'e:\\utils\\procdump64.exe', '-ma', '%s' % (iPid,), 'c:\\CrashDumps\\python.exe-%u-heap.dmp' % (iPid,)];
327 if utils.getHostArch() != 'amd64':
328 asArgs[0] = 'c:\\utils\\procdump.exe'
329 reporter.log('Trying to dump this process using: %s' % (asArgs,));
330 utils.processCall(asArgs);
331
332 # Generate a crash exception.
333 ctypes.windll.msvcrt.strcpy(None, None, 1024);
334
335 return True;
336
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette