Use Quarz Window Services API in XPC service - macos

I have an App which does screen scrape and window scrape, both are working pretty well in the application, later I decided to move both screen scrape and window scrape into the XPC service which belongs to this App, the display scrape works ok, but window scrape malfunction:
My first try is that the host app pass the CGWindowID to the XPC, in the XPC, I use
CGWindowListCreateImage and CGWindowListCreateImageFromArray, both them always return null.
Then I try to pass the pid of the window to be scrape from the host, and In the XPC
I use CGWindowListCopyWindowInfo to enumerate Windows to match the pid to find the related CGWindowID inside the XPC service process, anyway, CGWindowListCopyWindowInfo always return null
My next try is to use
auto findWindowIds = [](uint32_t pId) -> CFArrayRef
{
auto appRef = AXUIElementCreateApplication(pId);
CFMutableArrayRef idArray = CFArrayCreateMutable(0, 0, nullptr);
CFIndex count = 0;
CFArrayRef windowArray = NULL;
auto err = AXUIElementGetAttributeValueCount(appRef,
CFSTR("AXWindows"), &count);
if (err == kAXErrorSuccess && count)
{
AXUIElementCopyAttributeValues(appRef, CFSTR("AXWindows"), 0, count, &windowArray);
for (int idx = 0; idx < count; idx ++)
{
AXUIElementRef element = (AXUIElementRef)
CFArrayGetValueAtIndex(windowArray, idx);
CGWindowID temp = 0;
_AXUIElementGetWindow(element, &temp);
LOGEX("windowId: %u", temp);
CFArrayAppendValue(idArray, reinterpret_cast<void*>(temp));
}
SAFE_CFRELEASE(windowArray);
}
SAFE_CFRELEASE(appRef);
return idArray;
};
to reverse the Pid to WindowID, the above code works as expected (the CGWindowID is exactly the same as the host app) according what I debugged into the code, anyway,
CGWindowListCreateImage and CGWindowListCreateImageFromArray are still return null.
Since host app is using Quartz Window Services APIs to enumerate windows, the window server is running, and the XPC inherit the host App's GUI security session, beside that,
Quartz Display Streaming are working pretty well inside XPC service, don't why this is happening.
Could we use Quartz Window Service API inside XPC service?

It turns out I need to add joinExistingSession in XPC settings so that it could access Windows Server.

Related

Getting process information of every process

I am trying to create a program that any normal user can run on windows and generate a process list of all processes, including the executable location. I have used CreateToolhelp32Snapshot() to get all process names, pid, ppid. But having issues getting the image path. Everything I do results in pretty much Access Denied.
I have tried ZwQueryInformationProcess, GetProcessImageFileName, etc. and also using OpenProcess to get the handle to each process. I can get the handle by using PROCESS_QUERY_LIMITED_INFORMATION, but any other option doesn't work. I am lost and have been at this for a few days. Can anyone point me in the right direction?
This is the code that works for non-admin user on Windows. Use the szExeFile member of PROCESSENTRY32 to get the path:
HANDLE hProcessSnap = NULL;
HANDLE hProcess = NULL;
PROCESSENTRY32 pe32;
DWORD dwPriorityClass = 0;
// Take a snapshot of all processes in the system.
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return;
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof(PROCESSENTRY32);
// Retrieve information about the first process,
// and exit if unsuccessful
if (!Process32First(hProcessSnap, &pe32))
{
CloseHandle(hProcessSnap); // clean the snapshot object
return;
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
// do something with the pe32 struct.
// pe32.szExeFile -> path of the file
} while (Process32Next(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);

Detecting if laptop lid is closed/integrated screen is off

Is there a Windows API to detect if a laptop lid is closed (= integrated laptop screen is off)?
There's already the "same" question asked:
Get current laptop lid state
Though the (self-)accepted answer relies on an integrated screen "device" being removed, when the lid closes. But that does not happen on all laptops. Some keep the screen "available" to the system (while not displaying anything actually), even when the lid is closed. This means that the Windows desktop still stretches over the closed screen (if the "Multiple Displays" settings is set to "Extend these displays").
I have not determined yet, if this behavior can be configured or if it is driver-specific:
Remove closed laptop screen from Windows desktop
But even on such systems, the OS knows that the lid closes, as it can shutdown/sleep the machine when it does. And it broadcasts a notification (WM_POWERBROADCAST):
Detect laptop lid closure and opening
Background: I have an application that starts on the same display, where it was closed the last time. If it was closed on the integrated laptop screen and the lid is closed the next time the application starts (because the user is now using an external monitor), my application starts on the now-invisible integrated laptop screen.
Hence I want to detect that the lid is closed and force the application onto an external monitor.
So I'm looking either for a way to detect, if lid is closed. Or for a way to detect, that a particular screen is off (what would be a cleaner solution).
Sounds like you don't really care if the lid is closed or not and just want to know if the screen area where you are about to launch your application is available or not.
If the OS "still uses the shut off screen for its extended desktop" then that means (from the OS's point of view) that the screen is available to be used for applications. In other words - your application would not be the only one suffering from that issue. Though I have to say I have never observed that particular behavior first-hand.
If you need to move your application while it is running then you can register for the RegisterPowerSettingNotification and act on it.
However if you are launching and need to know if the screen is on or off you have two options:
EnumDisplayDevices
This will provide you with the information on whether your screen is attached to a desktop and is active. This is "system info" that you get from the API in User32.dll
DISPLAY_DEVICE ddi;
ddi.cb = sizeof(ddi);
DWORD iDevNum = 0; // or iterate 0..15
EnumDisplayDevices(NULL, iDevNum, &ddi, /*EDD_GET_DEVICE_INTERFACE_NAME*/0);
if( (ddi.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 &&
(ddi.StateFlags & DISPLAY_DEVICE_ACTIVE) != 0 ){...}
DXGI (DX11)
This gives you basically the same info as above but with a more modern approach (and potentially fewer false positives). Of course that would require you to link-in DXGI for this to work and include the header which will increase your application size:
#include <atltypes.h>
IDXGIAdapter * pAdapter;
std::vector <IDXGIAdapter*> vAdapters;
IDXGIFactory* pFactory = NULL;
// Create a DXGIFactory object.
if(FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory) ,(void**)&pFactory)))
{
return;
}
for(UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i){
DXGI_ADAPTER_DESC ad = {0};
if(SUCCEEDED(pAdapter->GetDesc(&ad))){
UINT j = 0;
IDXGIOutput * pOutput;
while(pAdapter->EnumOutputs(j, &pOutput) != DXGI_ERROR_NOT_FOUND)
{
DXGI_OUTPUT_DESC od = {0};
if(SUCCEEDED(pOutput->GetDesc(&od))){
// in here you can access od.DesktopCoordinates
// od.AttachedToDesktop tells you if the screen is attached
}
pOutput->Release();
++j;
}
}
pAdapter->Release();
}
if(pFactory)
{
pFactory->Release();
}
Hope that helps.
Direct3D9
This method also provides display information but in a slightly different way - via a list of adapters and monitors attached to those adapters. Remember to link-in d3d9 library for this to work:
void d3d_adapterInfo(IDirect3D9 * _pD3D9, UINT _n)
{
D3DADAPTER_IDENTIFIER9 id;
const DWORD flags = 0;
if(SUCCEEDED(_pD3D9->GetAdapterIdentifier(_n, flags, &id))){
// id provides info on Driver, Description, Name
HMONITOR hm = _pD3D9->GetAdapterMonitor(_n);
// and based on that hm you get the same monitor info as
// with the first method
}
}
void d3d_enumDisplays()
{
cout << endl << "--- Information by Direct3D9 ---" << endl;
IDirect3D9 * pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
const auto nAdapters = pD3D9->GetAdapterCount();
cout << "A total of " << nAdapters << " adapters are listed by Direct3D9" << endl;
for(UINT i = 0; i < nAdapters; ++i){
d3d_adapterInfo(pD3D9, i);
}
pD3D9->Release();
}
All 3 code snippets are from some of my projects so you can just copy-paste the code and it should work (baring some minor fixes for missing functions or variables as I was modifying the code on-the-fly to reduce its size when posted it here)

FindFirstPrinterChangeNotification with network printer fails with ERROR_INVALID_HANDLE (called from service)

I want to monitor print jobs on remote (shared) printers from service. I have impersonation access token for user who connects printer (e.g. \PC-PRINTER\Canon Printer).
After impersonation as the user I call OpenPrinter to printer and then FindFirstPrinterChangeNotification. OpenPrinter succeeded but FindFirstPrinterChangeNotification failed with ERROR_INVALID_HANDLE error.
If I try it as normal user (owner of printer - not a service), all succeeded and notification are functional. Also if I try it on Windows XP it succeeded, it fails only on Windows 7 and probably Windows Vista.
I suppose that I have to set some security attributes for impersonation token or pass some other attributes to OpenPrinter. I have tried many things, but I didn't find solution.
My code example:
PRINTER_NOTIFY_OPTIONS_TYPE optionsType;
unsigned short jobFields[] = {JOB_NOTIFY_FIELD_PRINTER_NAME};
optionsType.Type = JOB_NOTIFY_TYPE;
optionsType.Count = 1;
optionsType.pFields = &jobFields[0];
PRINTER_NOTIFY_OPTIONS options;
options.Version = 2;
options.Count = 1;
options.pTypes = &optionsType;
options.Flags = 0;
DWORD dwFilter = PRINTER_CHANGE_DELETE_JOB | PRINTER_CHANGE_SET_JOB ;
HANDLE hPrinterHandle = NULL;
ImpersonateLoggedOnUser(hUserToken); //I retrieve token from printer owner's process (I try every process for this user)
OpenPrinter(L"\\\\PC-PRINTER\\Canon Printer", &hPrinterHandle, NULL); \\it succeeded and I try many other parameters as well
HANDLE hNotification = FindFirstPrinterChangeNotification(hPrinterHandle, dwFilter, 0, (LPVOID) &options);
if (hNotification == INVALID_HANDLE_VALUE)
{//it comes here, GetLastError() == ERROR_INVALID_HANDLE (Windows 7, process runs as service)
//it succeded on Windows XP or when process runs in printer owner context
}
RevertToSelf();
Thanks for any solution!

Symbol Device Kill Process

I'm trying to see how many instances of an application are running on a MC65 device, a Windows Mobile 6.5 device. Then if there is more than one instance of the application running kill all instances and run the application. I've tried that code here. But it doesn't work on the MC65 device. I believe this is because it is a symbol device and I've read somewhere that they act differently than non-symbol devices.
Does anyone know how to find out what processes are running on a symbol device programatically?
Update: Upon further testing the device is having problems creating a snapshot of the running processes. Still haven't found a solution.
Taking a snapshot should work fine BUT you have to use a flag to avoid memory limitations throwing an exception:
[Flags]
private enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
Inherit = 0x80000000,
All = 0x0000001F,
NoHeaps = 0x40000000
}
Then in a normal call to CreateToolhelp32Snapshot you can get a list of processes:
public static Dictionary<UInt32, process> getProcessNameList()
{
int iCnt = 0;
//List<processnames> name_list = new List<processnames>();
Dictionary<UInt32, process> _pList = new Dictionary<uint, process>();
uint procID = 0;
IntPtr pHandle = CreateToolhelp32Snapshot(SnapshotFlags.Process | SnapshotFlags.NoHeaps, procID);
if ((Int32)pHandle == INVALID_HANDLE_VALUE)
throw new Exception("CreateToolhelp32Snapshot error: " + Marshal.GetLastWin32Error().ToString());
if ((int)pHandle != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pEntry = new PROCESSENTRY32();
pEntry.dwSize = (uint)Marshal.SizeOf(pEntry);
if (Process32First(pHandle, ref pEntry) == 1)
{
do
{
//name_list.Add(new processnames(pEntry.th32ProcessID, pEntry.szExeFile));
_pList[pEntry.th32ProcessID] = new process(pEntry.th32ProcessID, pEntry.szExeFile, new List<thread>());
iCnt++;
} while (Process32Next(pHandle, ref pEntry) == 1);
}
else
System.Diagnostics.Debug.WriteLine("Process32First error: " + Marshal.GetLastWin32Error().ToString());
CloseToolhelp32Snapshot(pHandle);
}
return _pList;
}
The above code is part of my remote ProcessorUsage test application.
Nevertheless normal windows mobile application will terminate them self if a previous instance is already running. That is also the default when you create and run a SmartDevice project in CSharp or CPP targetting "Windows Mobile ...".
If you target a Standard Windows CE based SDK, there is no automatic code generated to prevent multiple instances in the start code of the app.
Let us know, if you still need assistance.

How to determine if an process is the currently active / foreground application

I'd like to be able to query some function and give it a processID or processName - It then should return true or false on wether that process is in the foreground or not.
So i.e. the query for Firefox would return true (because right now I'm in FireFox, typing this) and everything else should return false.
Is that even possible for every type of application (.net, java/swing, pure c++/win32-ui)?
This question is for Windows only.
GetForegroundWindow and GetWindowThreadProcessId should let you get this information.
i.e., if you know the pid just check it against a function like this:
bool IsForegroundProcess(DWORD pid)
{
HWND hwnd = GetForegroundWindow();
if (hwnd == NULL) return false;
DWORD foregroundPid;
if (GetWindowThreadProcessId(hwnd, &foregroundPid) == 0) return false;
return (foregroundPid == pid);
}
This will work for any application that uses the core Win32 library at some level - this'll include Windows Forms, WPF, native Win32 applications, etc. Note this'll only work for applications running on the calling desktop and session - you can't use this to determine if another user's application is in the foreground, for instance.

Resources