Re: destroying a window on windows

eryk sun <[email protected]> Thu, 18 May 2017 05:03:31 +0000
Newsgroups gmane.comp.python.ctypes
Message-ID <CACL+1aub8h-3U2Zcv_mEz79t_LAKJ4wZT86L34qwQC6xko+oCg@mail.gmail.com>
On Thu, May 18, 2017 at 2:14 AM, Michael C
<[email protected]> wrote:
> where can i read up on what a thread is and what it does?

A book on operating systems would be a good place to start.

A Thread is a CPU execution context. A Process can and generally will
have multiple threads executing code concurrently. A Process is a like
a container for threads, i.e. the virtual address space and security
context in which they execute (and a Windows Job is a container for
processes, and they're all contained in an NT Session).

The operating system preemptively dispatches threads to give each a
time slice (quantum) that fairly distributes execution across the
available CPUs based on a combination of thread priority, process
priority, and CPU affinity (i.e. whether the process/thread has been
set to run on a subset of the available CPUs). A CPU context switch to
another thread is expensive, so the scheduler needs to strike a
balance between fairness and performance.

With all of these threads executing concurrently, it's important to be
able to synchronize their operation. That's where dispatcher
(synchronization) objects come into play -- e.g. timers, events,
mutexes, semaphores, and even threads themselves (i.e. have one thread
wait for another thread to terminate). In Windows a thread can wait on
a dispatcher object using the *WaitFor*Object* family of wait
functions. A waiting thread doesn't get scheduled to execute until the
object its waiting for becomes signaled. However, an alertable wait
can be interrupted by posting an APC routine to the waiting thread's
APC queue, e.g. via QueueUserAPC.

That said, a thread in Windows is more than just a CPU execution
context. For example, a thread can have an impersonation token to act
on behalf of another user on the system. This feature is typically
used by threads in service processes that are running as LocalSystem
(SYSTEM), LocalService, or NetworkService. That said, it's far more
common for a thread to implicitly operate in the security context of
the primary token of its owning process.

(The user's access token is created by the Local Security Authority
(LSA) and kernel security reference monitor when the user is logged
on. The access token gets duplicated for every process, which allows
groups and privileges in the token to me enabled and disabled
separately in each process. All copies share the same logon session --
e.g. for cached network credentials and for the object manager's
per-logon DosDevice directory.)

Threads also own windows and receive window messages that are
sent/posted to their message queue -- such as WM_CREATE, WM_CLOSE,
WM_DESTROY, WM_QUIT, WM_KEYDOWN, WM_KEYUP, WM_CHAR, WM_HOTKEY,
WM_PAINT, WM_COPY, WM_CUT, WM_PASTE, WM_COPYDATA, WM_TIMER,
WM_SETTINGCHANGE, WM_DEVICECHANGE, WM_POWERBROADCAST,
WM_QUERYENDSESSION, WM_WTSSESSION_CHANGE, etc (way too many to list
them all).

Also, I/O requests have thread affinity. In this case it's via the
thread's APC (asynchronous procedure call) queue and list of pending
IRPs (I/O request packets). I/O thread affinity is great for a client
application that's requesting I/O, but servers that have to maintain
throughput for thousands of I/O requests need to instead use a pool of
many threads to service requests. In this case I/O thread affinity is
a detriment, which is why Windows has an alternative: I/O completion
ports. When I/O completes via IOCP, it can be handled by the first
available thread in the pool.

> more importantly, how do i switch to the proper thread?

That's not something you should do. It may be possible to inject code
into the address space of another process and forcibly cause a given
thread in that process to execute it. But that's a rude thing to do
and would devolve into chaos if everyone wrote code like that. Just
send a WM_CLOSE message to the window. The window manager (implemented
in the win32k.sys kernel module) will send it to the message queue of
the owning thread, which can decide for itself whether it should call
DestroyWindow -- e.g. by asking the user if it's ok to close the
window.

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot