Win32 Programming Lesson 8: Processes
Feb 26, 2016
Win32 ProgrammingLesson 8: Processes
Where are we? We’re starting to have some foundational
understanding of Windows But really, we don’t know how to get any
work done (doesn’t that sound like your Sophomore year?)
Executing Code The Operating System organizes executing
code into a logical hierarchy Processes Threads Fibers
Definition A Process is defined as
An instance of a running program, which consists of two components: A kernel object used by the operating system to
manage the process An address space which contains all the DLLs,
executable code and data used by the process Processes are inert: to accomplish anything, a
process must have at least one thread that runs in its context
Threads Each thread executes “simultaneously” (in
some sense of the word… why, why not?) Each thread has its own stack frame, and set
of CPU registers
Scheduling The OS schedules some time for each thread Each thread gets a time slice or quantum from the
CPU which provides the illusion of concurrency We can think of it as a “round robin” scheduler…
but it is significantly much more complicated When a process is created, it is generally created
with one thread, called the primary thread – this thread can create other threads
Windows Applications Two flavors
GUI (all that Windowsy stuff) CUI (command line – the One True Way™)
Of course, life isn’t so simple – it’s not a binary decision
Every program needs an entry point – WinMain, wWinMain etc.
The Operating System doesn’t call this – it calls a special startup function
Startup Code The Runtime Libraries do a number of things
Retrieve a pointer to the command line parameters of the process
Retrieve a pointer to the new environment variables of the process
Initialize the RTL’s global variables Initialize the heap for the RTL Call constructors for global and static objects
A Process’ Instance Handle Every DLL or executable gets its own
Instance Handle, which is unique Used when we load resources (like icons) Can get the handle of a DLL with something
like: HMODULE GetModuleHandle(PCTSTR
pszModule);
The Command Line Can use the global variables __argv Can call down to PTSTR GetCommandLine() Can go from here to an argv-like structure
using: PWSTR CommandLineToArgvW(
PWSTR pszCmdLine, int* pNumArgs
);
Free alloced memory int nNumArgs;
PWSTR *ppArgv = CommandLineToArgvW(GetCommandLineW(), &nNumArgs);
// Use the arguments… if (*ppArgv[1] == L'x') { }
// Free the memory block HeapFree(GetProcessHeap(), 0, ppArgv);
Environment Variables Associated on a per-process basis Stored in the environment block Stored in the form:
VarName1=Value1\0VarName2=Value2\0…VarNameX=ValueX\0\0
Associated Functions GetEnvironmentVariable(
PCTSTR pszName,PTSTR pszValue,DWORD dwSize);
Often in the form “%USERPROFILE%\My Documents”
Windows supplies a helper function for this case
ExpandEnvironmentString ExpandEnvironmentStrings(
PCTSTR pszSrc,PTSTR pszDst,DWORD nSize);
Where nSize is the maximum space available for expansion
ErrorModes A process can choose to trap certain errors
itself instead of having the Operating System trap those errors
UINT SetErrorMode(UINT fuErrorMode)
CurrentDirectory and Directory Example: CreateFile DWORD GetCurrentDirectory (
DWORD cchCurDir,PTSTR pszCurDir);
BOOL SetCurrentDirectory(PCTSTR pszCurDir);
Current Directories are also stored in the environment variables
Finally… GetVersion and GetVersionEx Read the history, it’s somewhat amusing
Creating a Process Simple: use CreateProcess:
BOOL CreateProcess(PCTSTR pszApplicationName,PTSTR pszCommandLine,PSECURITY_ATTRIBUTES psaProcess,PSECURITY_ATTRIBUTES psaThread,BOOL bInheritHandles,DWORD fdwCreate,PVOID pvEnvironment,PCTSTR pszCurDir,PSTARTUPINFO psaStartInfo,PPROCESS_INFORMATION
ppiProcInfo); I could write out the usage, but let’s just look it up…
Terminating a Process Four ways
The primary thread’s entry-point function returns (YES)
One thread in the process calls ExitProcess (NO) A thread in another process calls
TerminateProcess (NO) All the threads just happen to die on their own
(Never happens)
Entry point returns When the primary thread dies
Any C++ objects are destroyed using destructors Memory from the stack is correctly freed The process’ exit code is set The process’ kernel object is decremented
ExitProcess Fine from an OS perspective Horrible from the RTL perspective as
Destructors aren’t called – you can prove this to yourself if you want to
ChildProcessesPROCESS_INFORMATION pi; DWORD dwExitCode; // Spawn the child process. BOOL fSuccess = CreateProcess(..., &pi); if (fSuccess) {
// Close the thread handle as // soon as it is no longer needed! CloseHandle(pi.hThread); // Suspend our execution until // the child has terminated. WaitForSingleObject(pi.hProcess, INFINITE); // The child process terminated; //get its exit code. GetExitCodeProcess(pi.hProcess, &dwExitCode); // Close the process handle as soon as it// is no longer needed. CloseHandle(pi.hProcess);
}
Detaching a Process In the previous example, the processes are
linked – the child process won’t be destroyed until the Parent reads the exit code
However, you can detach a process by closing the associated handles in the parent process
Enumerating Processes Assignment time! Easily create a simple application which enumerates
all the processes on a machine. You may use a command-line application if you wish, or a GUI. Print out as much information about each process as you can.
This looks really nice in .NET… but that’s a little more tricky.
Your call – CLI is okay, but a nice GUI gets you extra marks…