Suppose that a process calls the SetThreadDesktop()
API to capture the screen of a specific desktop.
Is it possible to identify this thread inside of the desktop and know the caller process?
If yes, could you provide a code example for it?
Edition:
With reference to Remy's answer i have this following code, but GetLastError()
to GetThreadDesktop()
is ERROR_ACCESS_DENIED.
function GetProcessNameByID(ProcessID: DWORD): string;
var
hProcess: THandle;
ProcessName: array[0..MAX_PATH] of Char;
begin
Result := '';
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessID);
if hProcess <> 0 then
begin
if GetModuleBaseName(hProcess, 0, ProcessName, MAX_PATH) > 0 then
Result := ProcessName;
CloseHandle(hProcess);
end;
end;
function GetUserObjectName(hUserObject: THandle): string;
var
Count: DWORD;
begin
GetUserObjectInformation(hUserObject, UOI_NAME, PChar(Result), 0, Count);
SetLength(Result, Count + 1);
if GetUserObjectInformation(hUserObject, UOI_NAME, PChar(Result), Count, Count) then
StrResetLength(Result)
else
Result := '';
end;
function SetUserObjectAllAccess(hUserObject: THandle): Boolean;
var
Sd: PSecurity_Descriptor;
Si: Security_Information;
begin
Sd := PSecurity_Descriptor(LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
InitializeSecurityDescriptor(Sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(Sd, True, nil, False);
Si := DACL_SECURITY_INFORMATION;
Result := SetUserObjectSecurity(hUserObject, Si, Sd);
LocalFree(HLOCAL(Sd));
end;
function GetThreadsList(PID: Cardinal): Boolean;
var
SnapProcHandle: THandle;
NextProc: Boolean;
TThreadEntry: TThreadEntry32;
SessionID: Cardinal;
DeskObj: HDESK;
begin
SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
Result := (SnapProcHandle <> INVALID_HANDLE_VALUE);
if Result then
try
TThreadEntry.dwSize := SizeOf(TThreadEntry);
NextProc := Thread32First(SnapProcHandle, TThreadEntry);
while NextProc do
begin
//if TThreadEntry.th32OwnerProcessID = PID then
if GetProcessNameByID(TThreadEntry.th32OwnerProcessID) = 'Project2.exe' then
begin
Writeln('Thread ID: ' + {IntToHex(TThreadEntry.th32ThreadID, 8))}IntToStr(TThreadEntry.th32ThreadID));
Writeln('Process ID: ' + Inttostr(GetProcessIdOfThread(TThreadEntry.th32ThreadID)));
ProcessIdToSessionId(TThreadEntry.th32OwnerProcessID, SessionID);
Writeln('Session ID: ' + IntToStr(SessionID));
Writeln('Window Station: ' + GetUserObjectName(GetProcessWindowStation));
Writeln('Process Name: ' + GetProcessNameByID(TThreadEntry.th32OwnerProcessID));
DeskObj := GetThreadDesktop(TThreadEntry.th32ThreadID);
SetUserObjectAllAccess(DeskObj);
Writeln('Desktop Name: ' + GetUserObjectName(DeskObj));
Writeln('Base Priority ' + inttostr(TThreadEntry.tpBasePri));
Writeln('');
end;
NextProc := Thread32Next(SnapProcHandle, TThreadEntry);
end;
finally
CloseHandle(SnapProcHandle);
end;
end;
There is not a specific API to enumerate threads in a desktop. You will have to enumerate all available threads using CreateToolhelp32Snapshot()
and Thread32(First|Next)()
(see Enumerating threads in Windows), and then filter them using GetThreadDesktop()
.