C
Cantankerous Old Git
I am trying to write a program that I hope to get working as a
command-line app to start with, and then eventually use a windows
service wrapper to call it as a service. Its purpose is to attach
to an already running (not ours) service using an API DLL, where
it will do houskeeping and monitoring tasks.
This is where it all gets strange. Although I can make calls into
the API and do things proactively, when I register a callback for
event notification, this callback doesn't get called. I am told
that if I want event notifications, I must create a window and
run a "message pump" on it, and pass the window handle to the API
when I register my callback function. This is despite the fact
that I don't want my service to ever display a window. I gather I
don't have to act on any messages either, but somehow the API
won't tell me about any events unless I do this.
So I am trying to create a skeleton that will create a window and
run a "Message Pump". This is fairly succesful, in that I can
create the window and the API then magically calls my event handler.
But I want to be able to stop my service on demand, and this
involved killing the message pump loop and destroying the window.
I can't figure out how to do that.
Problem 1:
If I have another thread call DestroyWindow after a delay, it
gets an error "permission denied". I really can't see why.
Problem 2:
I thought that maybe catching some kind of message might help. I
have tried registering both a message-map and a wndProc handler.
In both instances (see the code below) I don't get the WM_CREATE
message that I hope to see first. Also, if I use the wndProc
method, the CPU slams to 100% and I seem to receive an infinite
number of messages of some sort.
Problem 3:
I thought if I pump the messages using GetMessage and
DispatchMessage in my own loop, I might be able to check a flag
and exit the loop when required. But I can't figure out the
callling arguments to these calls.
Below is the code I have done so far. I have stripped to as
simple as I can make it. I would really appreciate some guidance
or links to articles. I am struggling to understand even the
basics, I think.
The Cog.
import win32gui
import win32api
import win32con
import traceback, time, threading
def onCreate():
print 'GOT WM_CREATE'
def onDestroy():
print 'GOT WM_DESTROY'
def wndProc(hwnd, msg, wparam, lparam):
#print '~~~wndProc get a message'
if msg == win32con.WM_CREATE:
onCreate()
if msg == win32con.WM_DESTROY:
onDestroy()
return 0
def registerWindowClass():
wc = win32gui.WNDCLASS()
wc.hInstance = hinst
wc.lpszClassName = "Eric the half-a-bee"
messageMap = {win32con.WM_CREATE : onCreate ,
win32con.WM_DESTROY : onDestroy }
wc.lpfnWndProc = messageMap # no messages if I do this
#wc.lpfnWndProc = wndProc # infinite stream of
messages if I do this
return win32gui.RegisterClass(wc)
def createWindow(registeredClassAtom):
return win32gui.CreateWindow(
registeredClassAtom, "This is a window",
0, 0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,
0, 0, hinst, None)
hinst = win32api.GetModuleHandle(None)
hwnd = createWindow(registerWindowClass())
win32gui.ShowWindow(hwnd, True) # I'll try hide it later
win32gui.UpdateWindow(hwnd)
# wait 10 secs then kill the window
def timeKill():
print 'sleeping...'
time.sleep(10)
print 'killing'
win32gui.DestroyWindow(hwnd)
print 'starting killer timer'
threading.Thread(target=timeKill).start()
# This message pump traps the thread and never returns
win32gui.PumpMessages()
command-line app to start with, and then eventually use a windows
service wrapper to call it as a service. Its purpose is to attach
to an already running (not ours) service using an API DLL, where
it will do houskeeping and monitoring tasks.
This is where it all gets strange. Although I can make calls into
the API and do things proactively, when I register a callback for
event notification, this callback doesn't get called. I am told
that if I want event notifications, I must create a window and
run a "message pump" on it, and pass the window handle to the API
when I register my callback function. This is despite the fact
that I don't want my service to ever display a window. I gather I
don't have to act on any messages either, but somehow the API
won't tell me about any events unless I do this.
So I am trying to create a skeleton that will create a window and
run a "Message Pump". This is fairly succesful, in that I can
create the window and the API then magically calls my event handler.
But I want to be able to stop my service on demand, and this
involved killing the message pump loop and destroying the window.
I can't figure out how to do that.
Problem 1:
If I have another thread call DestroyWindow after a delay, it
gets an error "permission denied". I really can't see why.
Problem 2:
I thought that maybe catching some kind of message might help. I
have tried registering both a message-map and a wndProc handler.
In both instances (see the code below) I don't get the WM_CREATE
message that I hope to see first. Also, if I use the wndProc
method, the CPU slams to 100% and I seem to receive an infinite
number of messages of some sort.
Problem 3:
I thought if I pump the messages using GetMessage and
DispatchMessage in my own loop, I might be able to check a flag
and exit the loop when required. But I can't figure out the
callling arguments to these calls.
Below is the code I have done so far. I have stripped to as
simple as I can make it. I would really appreciate some guidance
or links to articles. I am struggling to understand even the
basics, I think.
The Cog.
import win32gui
import win32api
import win32con
import traceback, time, threading
def onCreate():
print 'GOT WM_CREATE'
def onDestroy():
print 'GOT WM_DESTROY'
def wndProc(hwnd, msg, wparam, lparam):
#print '~~~wndProc get a message'
if msg == win32con.WM_CREATE:
onCreate()
if msg == win32con.WM_DESTROY:
onDestroy()
return 0
def registerWindowClass():
wc = win32gui.WNDCLASS()
wc.hInstance = hinst
wc.lpszClassName = "Eric the half-a-bee"
messageMap = {win32con.WM_CREATE : onCreate ,
win32con.WM_DESTROY : onDestroy }
wc.lpfnWndProc = messageMap # no messages if I do this
#wc.lpfnWndProc = wndProc # infinite stream of
messages if I do this
return win32gui.RegisterClass(wc)
def createWindow(registeredClassAtom):
return win32gui.CreateWindow(
registeredClassAtom, "This is a window",
0, 0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,
0, 0, hinst, None)
hinst = win32api.GetModuleHandle(None)
hwnd = createWindow(registerWindowClass())
win32gui.ShowWindow(hwnd, True) # I'll try hide it later
win32gui.UpdateWindow(hwnd)
# wait 10 secs then kill the window
def timeKill():
print 'sleeping...'
time.sleep(10)
print 'killing'
win32gui.DestroyWindow(hwnd)
print 'starting killer timer'
threading.Thread(target=timeKill).start()
# This message pump traps the thread and never returns
win32gui.PumpMessages()