News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Finding the PID from hProcess

Started by donkey, April 19, 2011, 03:54:45 PM

Previous topic - Next topic

donkey

I am using ShellExecuteEx to open documents using the "open" verb. The function will return a process handle in the structure when it returns. For my application the following is true:

1) I have no idea at compile time which application will open the document
2) There can be multiple instances of the same application
3) All window names and classes for the instances can be identical
4) I have no handle to the main window
5) I have no handle to the primary thread

I have the problem of having to directly identify the process to the exclusion of all other processes. In order to get a handle to the primary thread I can walk the desktop windows and check to see if the Process Id matches the one I'm looking for then get the thread handle using GetWindowThreadProcessId. Problem is that I have a Process Handle and not an ID. From XPSP1 there is a function GetProcessId that I could use but that would limit the OS versions available to the application. Using the PSAPI/ToolHelp functions is fine but when walking the processes the PID is returned but there is no way to map it directly to my hProcess. Since the process is external to my application, I cannot guarantee that I can read the process memory so even if I could find an entry in the PDB/PEB that contained the Process ID I am not sure I could read it. The only other option is NtQueryInformationProcess but that limits me to WinNT and precludes all Win9x OSes. For now I've decided on NtQueryInformationProcess but I was hoping someone might know of a 9x solution.

This is an experimental application, I have no real place to use it as of right now but it could be very useful. In NT the solution is:

pbi PROCESS_BASIC_INFORMATION <>

GetPIDFromhProcess FRAME hProcess
LOCAL retlen :D

mov D[pbi.UniqueProcessId],0

invoke NtQueryInformationProcess ,[hProcess], ProcessBasicInformation, offset pbi,\
sizeof PROCESS_BASIC_INFORMATION, offset retlen

mov eax,[pbi.UniqueProcessId]
RET
ENDF


However, I can't think of a way to get the same information from 9x.

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

baltoro

That's the way I have done it also for Operating Systems for which NtQueryInformationProcess can be invoked. NtQuerySystemInformation also works well,...it's undocumented,...and, I'm sure you are familiar with it,...
Windows 98 (and, earlier) is rarely encountered nowadays,...but, of course, you know that,...
...I'm assuming that you aren't doing any of this remotely,...because, the security requirements would be very annoying,... :eek

Quote from: NOT MEI think you should cheat,...but, then, we CAN'T TALK ABOUT IT. :eek

The obvious suggestion for Windows 98 and earlier systems is to write a completely new function that does NOT use ShellExecuteEx as your primary technique. The MSDN documentation says that the minimum supported client for ShellExecute is Windows XP, anyway,...so, you don't have much choice in the matter. This makes the potential solution much more tedious. :eek
Baltoro

donkey

Quote from: baltoro on April 19, 2011, 04:08:02 PM
The MSDN documentation says that the minimum supported client for ShellExecute is Windows XP, anyway,...so, you don't have much choice in the matter. This makes the potential solution much more tedious. :eek


That's a supported client, ShellExecute has been part of the API as a named export since Shell32 version 1.30 in Win32s, it predates Windows 95, even WinNT 3.51. It is one of the original 50 or so Shell API functions (I believe a 16 bit version was actually exported in Windows 1.0 but I can't be sure).

BTW NtQueryInformationProcess is documented.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

baltoro

...I wondered about that, as I can remember using ShellExecute successfully on Windows 98,...
...So,...what does the phrase 'minimum supported client' mean ???
Anyway. this does not solve your problem. How are the original files indicated in your program ? The Open File Dialog ? Is it possible to present a dialog that lists all possible applications that might be used to open the file ? This is a crappy idea, of course,...
Baltoro

oex

Quote from: baltoro on April 19, 2011, 05:09:00 PM
...So,...what does the phrase 'minimum supported client' mean ???

Microsoft supports as in customer support not as in technically supports (even though it is on a documentation page where knowing *real* information is handy)
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

baltoro

 :eek ...Oh,...well,...that's embarrassing,...I should have known that,... :eek
You'd think the official Microsoft documentation would mention the earliest DLL version that exports the described function,...

<JUST KIDDING>
...Anyway, back to the EDGAR,...you could, of course, use the same technique that Mark Russinovich uses in ProcessExplorer to determine the PID of a running application,...
<\JUST KIDDING>
Baltoro

donkey

Quote from: baltoro on April 19, 2011, 05:09:00 PM
Anyway. this does not solve your problem. How are the original files indicated in your program ? The Open File Dialog ? Is it possible to present a dialog that lists all possible applications that might be used to open the file ? This is a crappy idea, of course,...

The application that opens a given document is listed in the registry in HKEY_CLASSES_ROOT. It is possible to rewrite the ShellExecuteEx function however, it is not a huge task and will solve my problem. When I get some time I will write ShellExecuteExEx I guess. I wanted to avoid the issues involved with doing that but I can make one that returns the process handle and id as well as the primary threads handle and id. I am beginning to believe it is the only solution.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

baltoro

You know, Edgar, you're probably the best Windows programmer here. Whenever you come up with something that mystifies you, I always study the thread carefully, ...because, it's usually something that has NEVER EVEN OCCURRED TO ME. :bg
...But, I think you are just making it TOO easy for the users of your applications. My applications are just the opposite,...they just provide alot of useless information and annoy people. Of course, I get alot of death threats,...people spray paint ugly remarks on the side of my house,...and, call me up in the middle of the night screaming like demons,... :eek
Baltoro

oex

Quote from: baltoro on April 19, 2011, 05:46:08 PM
Of course, I get alot of death threats,...people spray paint ugly remarks on the side of my house,...and, call me up in the middle of the night screaming like demons,... :eek

:lol that's just me
We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

dedndave

maybe some of this info will help, Edgar
http://vb.mvps.org/hardcore/html/moreabouthandlesprocessids.htm
http://www.woodmann.com/fravia/natz_mp2.htm

it doesn't look to bad for 32-bit apps
under win95 with 16-bit - a different subject   :P

if you have the hWnd....
GetWindowThreadProcessId
http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx

baltoro

EDGAR,
Found this article at Microsoft Support: SAMPLE: MODLIST.EXE Shows How to Enumerate Processes and Modules.
It mentions using the Toolhelp32 APIs for Windows 95 and 98, just as you did above. The article describes the method for obtaining the Process ID, which is then passed to the OpenProcess() API to get a handle to the process. The Toolhelp32 APIs used under Windows 95, Windows 98, and Windows Me reside in the KERNEL32.DLL. These API functions are available only under Windows 95, Windows 98, and Windows Me. This is from the article:

Quote from: Microsoft SupportThe first step is to create a "snapshot" of the information in the system using the CreateToolhelp32Snapshot() function. This function allows you to choose what type of information is stored in the snapshot. The Modlist sample initially specifies the TH32CS_SNAPPROCESS flag because you are interested in process information. This function returns a handle to a PROCESSENTRY32 structure, and it is important to remember to pass the handle to CloseHandle() when processing is complete. To iterate through the list of processes in the snapshot, call Process32First once, followed by repeated calls to Process32Next, until one of these functions returns FALSE. Both of these functions take the handle to the snapshot and a pointer to a PROCESSENTRY32 structure as parameters. Process32First and Process32Next fill a PROCESSENTRY32 structure with useful information about a process in the system.
The process ID is in the th32ProcessID member of the structure. The process' executable file and path are stored in the szExeFile member of the structure. Other useful information is also available in the structure. The Modlist sample only retrieves the EXE name and adds it to a listbox. The process ID can be passed to the OpenProcess() API to get a handle to the process.

From the remarks section of OpenProcess(): To open a handle to another local process and obtain full access rights, you must enable the SeDebugPrivilege privilege.

I'm guessing that you already know all this,...so, the problem is what? That the two handle values can't be compared to determine if they are from the same process?

I got your message: For now though I have decided to support no OS versions lower than XP.
Baltoro

donkey

Hi all,

As I said I have a hProcess, no other information, the process can be one of any number of a given executable that is running and has the same document open. Walking the processes will return a PID, that can be used with OpenProcess to get information about the process. However, the handle returned from OpenProcess is not going to match the handle I have, it will be a pseudo-handle for use by the current process. Matching the executable path does not allow me to know the exact copy I want except when there is only one running copy, otherwise it will return one of any number and there is still no way to match it to the handle I have.

Enumerating processes and threads is a trivial task, I've used the toolhelp API a lot, however it will not return any information useful to my problem. I'm still looking though, I am currently trying to see if the handle value can be found in the system handle heap, (PDB offset 0x44 points to a processes entry). If it does I may be able to use Toolhelp32ReadProcessMemory to find the pointer and get a handle list to check against. In that way I may be able to write a GetProcessId function for Win9x. However its a big job (probably in Ring0) for very little gain and its on the backburner for now since I have solutions all the way back to NT4 already.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable