win32 (Desktop Duplication API) IDXGIOutput1::DuplicateOutput() results in Access Violation within dxgi.dll - winapi

I'm writing a small c++ app that uses Desktop Duplication API to get the display output. I've never done c programming before, and I got to where I am by staring at the win32 API documentation. https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_2/
#include <iostream>
#pragma comment(lib, "windowsapp")
#include <roapi.h>
//#pragma comment(lib, "dxgi")
#include <dxgi1_2.h>
using namespace std;
int main()
{
cout << RoInitialize(RO_INIT_SINGLETHREADED);
// intermediate variables for casting
IDXGIOutput* pDisplay_old;
IDXGIFactory1* pFactory;
IDXGIAdapter1* pGPU;
IDXGIOutput1* pDisplay;
IDXGIOutputDuplication* pCapture;
DXGI_OUTDUPL_DESC captureDesc;
// create factory
if (CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory) != S_OK) return 1;
// get GPU
if (pFactory -> EnumAdapters1(0, &pGPU) != S_OK) return 1;
// get display
if (pGPU -> EnumOutputs(0, &pDisplay_old) != S_OK) return 1;
pDisplay = (IDXGIOutput1*)pDisplay_old;
DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResource* pFrame;
HRESULT captureResult;
do
{
// create capture
// cout << pDisplay -> DuplicateOutput(pGPU, &pCapture);
//return 0;
if (pDisplay -> DuplicateOutput(pGPU, &pCapture) != S_OK) return 1;
pCapture -> GetDesc(&captureDesc);
cout << captureDesc.ModeDesc.Width << ' ' << captureDesc.ModeDesc.Height;
do
{
captureResult = pCapture -> AcquireNextFrame(2000, &frameInfo, &pFrame);
if (captureResult == S_OK)
{
cout << "HI";
captureResult = pCapture -> ReleaseFrame();
}
else if (captureResult == DXGI_ERROR_ACCESS_LOST) break;
else return 1;
}
while (true);
}
while (true);
}
I'm using visual studio 2022 witn only "desktop development with c++" enabled, on windows 11 insider build: 22623.1037 ni_release on a regular home PC with display, beyboard, mouse, etc
The code worked fine until DuplicateOutput(), when it complained E_NOINTERFACE. I'm certain there is an interface since index 0 for EnumAdapters1 and EnumOutputs are where the desktop is displayed, and I obviously have a display attached with the desktop. According to this guy https://devblogs.microsoft.com/oldnewthing/20041213-00/?p=37043, I need marshalling and apartments or something, so after more research, I tried RoInitialize() with both RO_INIT_SINGLETHREADED and RO_INIT_MULTITHREADED. Now, DuplicateOutput throws this exception
It seems to happen within the library itself, which makes me think that it's either not my fault or I really messed something up, probably the latter.
I'm really confused now, and would like some assistance, thanks!
EDIT: I replaced "pDisplay = (IDXGIOutput1*)pDisplay_old;" with "pDisplay_old -> QueryInterface(&pDisplay);", and I'm back to E_NOINTERFACE, but I think I'm on the right track, how do I fix this error?
EDIT2: I looked at a related question AcquireNextFrame not working (Desktop Duplication API & D3D11), and followed the answer to add D3D11CreateDevice to my code:
#include <iostream>
#pragma comment(lib, "dxgi")
#pragma comment(lib, "d3d11")
#include <d3d11.h>
#include <dxgi1_2.h>
using namespace std;
int main()
{
// intermediate variables for casting
IDXGIOutput* pDisplay_old;
IDXGIFactory1* pFactory;
IDXGIAdapter* pGPU;
ID3D11Device* pD3DDevice;
IDXGIDevice* pDevice;
IDXGIOutput1* pDisplay;
IDXGIOutputDuplication* pCapture;
DXGI_OUTDUPL_DESC captureDesc;
// create DXGI factory
if (CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory) != S_OK) return 1;
// get GPU adapter
if (pFactory -> EnumAdapters(0, &pGPU) != S_OK) return 2;
// create D3D11 device
D3D_FEATURE_LEVEL D3DFeatures [6]
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
cout << D3D11CreateDevice(pGPU, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, D3DFeatures, sizeof(D3DFeatures), D3D11_SDK_VERSION, &pD3DDevice, NULL, NULL); //!= S_OK) return 3;
return 0;
// get DXGI device from that
pD3DDevice -> QueryInterface(&pDevice);
// get display
if (pGPU -> EnumOutputs(0, &pDisplay_old) != S_OK) return 4;
pDisplay_old -> QueryInterface(&pDisplay);
DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResource* pFrame;
HRESULT captureResult;
do
{
// create capture
cout << pDisplay -> DuplicateOutput(pD3DDevice, &pCapture);
return 0;
if (pDisplay -> DuplicateOutput(pGPU, &pCapture) != S_OK) return 5;
pCapture -> GetDesc(&captureDesc);
cout << captureDesc.ModeDesc.Width << ' ' << captureDesc.ModeDesc.Height;
do
{
captureResult = pCapture -> AcquireNextFrame(2000, &frameInfo, &pFrame);
if (captureResult == S_OK)
{
cout << "HI";
captureResult = pCapture -> ReleaseFrame();
}
else if (captureResult == DXGI_ERROR_ACCESS_LOST) break;
else return 6;
}
while (true);
}
while (true);
D3D11CreateDevice seems like a complex function and for me it keeps complaining invalid_arg. I'm not sure how to fix that

The solution was provided in the comments:
pDisplay = (IDXGIOutput1*)pDisplay_old; is wrong, you must always use QueryInterface to get an interface from another. And you don't need RoInitialize. –
Simon Mourier Jan 1 at 9:11
I replaced it with "pDisplay_old -> QueryInterface(&pDisplay);", and I'm back to E_NOINTERFACE, but I think I'm on the right track, how do I fix this error? –
Tiger Yang Jan 4 at 16:54
I don't get E_NOINTERFACE (you shouldn't) on this QueryInterface call. What is wrong then is DuplicateOutput expects a Direct3D device, not an adapter interface reference. –
Simon Mourier Jan 4 at 17:18
I've worked on it and updated the post above –
Tiger Yang Jan 7 at 1:51
Your code is wrong again, use D3D_DRIVER_TYPE_UNKNOWN if you pass an adapter as 1st arg (or ask for hardware and pass nullptr as 1st arg) and use ARRAYSIZE(D3DFeatures), not sizeof(D3DFeatures) as 6th arg. Use DirectX Debug Layer learn.microsoft.com/en-us/windows/win32/direct3d11/… walbourn.github.io/direct3d-sdk-debug-layer-tricks to ease debugging –
Simon Mourier Jan 7 at 7:36

Related

Programmatically Change Windows Laptop's Refresh Rate

I'm thinking of coding something up that will change a laptop's refresh rate based on whether or not the device is plugged in.
From my research, these are two links I came across. One is 20 years old and the other is from Microsoft, but I don't see any mentions of refresh rate specifically.
https://www.codeproject.com/Articles/558/Changing-your-monitor-s-refresh-rate
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-changedisplaysettingsa?redirectedfrom=MSDN
Does anyone have any insight into how to do this? I'm not too particular about what language would have to be used for it, so let me know whatever would be most viable. Of course I'd also have to be able to check a change in state for plugged in/unplugged, but I haven't gotten to that point yet.
I'm mostly targeting Windows 10 since that's what my device is on.
You can use EnumDisplaySettings to enumerate the information of the current display device, and then set the display by ChangeDisplaySettingsA.
If you want to modify the refresh rate, you only need to modify the dmDisplayFrequency parameter of DEVMODEA.
Here is the sample:
#include <Windows.h>
#include <iostream>
using namespace std;
int main(int argc, const char* argv[])
{
DEVMODE dm;
ZeroMemory(&dm, sizeof(dm));
dm.dmSize = sizeof(dm);
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
{
cout << "DisplayFrequency before setting = " << dm.dmDisplayFrequency << endl;
dm.dmDisplayFrequency = 60; //set the DisplayFrequency
LONG ret = ChangeDisplaySettingsEx(NULL, &dm, NULL, 0, NULL);
std::cout << "ChangeDisplaySettingsEx returned " << ret << '\n';
if (0 != EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
{
cout << "DisplayFrequency after setting = " << dm.dmDisplayFrequency << endl;
}
switch (ret)
{
case DISP_CHANGE_SUCCESSFUL:
std::cout << "display successfully changed\n";
break;
case DISP_CHANGE_BADDUALVIEW:
std::cout << "The settings change was unsuccessful because the system is DualView capable\n";
break;
case DISP_CHANGE_BADFLAGS:
std::cout << "An invalid set of flags was passed in.\n";
break;
case DISP_CHANGE_BADMODE:
std::cout << "The graphics mode is not supported.\n";
break;
case DISP_CHANGE_BADPARAM:
std::cout << "An invalid parameter was passed in. This can include an invalid flag or combination of flags.\n";
break;
case DISP_CHANGE_FAILED:
std::cout << "The display driver failed the specified graphics mode.\n";
break;
case DISP_CHANGE_NOTUPDATED:
std::cout << "Unable to write settings to the registry.\n";
break;
case DISP_CHANGE_RESTART:
std::cout << "The computer must be restarted for the graphics mode to work.\n";
break;
}
}
system("pause");
}
This example is not always successful. Whether you can modify the refresh rate depends on whether your monitor supports it. This is the output of successful setup:

Protobuf exception when allocating memory for string in dll

I am using protobuf 3 to serialize a simple message.
I get a bad alloc when i set a string value for one of the memebers of my protobuf message like so.
std::string a("eeee");
hello_in.set_name(a);
The bad alloc exception happens in the libprotobuf.dll in this function...
void CreateInstance(Arena* arena, const ::std::string* initial_value) {
GOOGLE_DCHECK(initial_value != NULL);
// uses "new ::std::string" when arena is nullptr
ptr_ = Arena::Create< ::std::string>(arena, *initial_value);
}
But i think the real problem is that initial_value has been corrupted somehow and has a size of [size] = 3435973836.
Not sure how this is being corrupted. CreateInstance does get called a few times prior to this but its the first time it is called from main.cpp. Which leads me to believe that it has something to do with dll's and ownership of memeory.
Using any of the other set_name functions also cause a bad alloc exception.
Setting the bool or int in the message works fine.
Here is the message and the main.cpp. I didnt include the hello.pb.h/pb.cc as they are quite big but can if it helps.
// See README.txt for information and build instructions.
//
// Note: START and END tags are used in comments to define sections used in
// tutorials. They are not part of the syntax for Protocol Buffers.
//
// To get an in-depth walkthrough of this file and the related examples, see:
// https://developers.google.com/protocol-buffers/docs/tutorials
// [START declaration]
syntax = "proto3";
package commands;
import "google/protobuf/timestamp.proto";
// [END declaration]
// [START messages]
message Hello {
string name = 1;
int32 id = 2; // Unique ID number for this person.
bool on = 3;
google.protobuf.Timestamp last_updated = 4;
}
// [END messages]
#include "hello.pb.h"
// stl
#include <fstream>
#include <iostream>
int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
commands::Hello hello_in;
hello_in.set_id(2);
std::string a("eeee");
hello_in.set_name(a);
hello_in.set_on(false);
{
// Write the new address book back to disk.
std::fstream output("hello.txt", std::ios::out | std::ios::trunc | std::ios::binary);
if (!hello_in.SerializeToOstream(&output)) {
std::cerr << "Failed to write address book." << std::endl;
return -1;
}
}
commands::Hello hello_out;
{
// Read the existing address book.
std::fstream input("hello.txt", std::ios::in | std::ios::binary);
if (!input) {
std::cout << "hello.txt" << ": File not found. Creating a new file." << std::endl;
}
else if (!hello_out.ParseFromIstream(&input)) {
std::cerr << "Failed to parse address book." << std::endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
I have observed same behavior (Visual Studio 2019 C++ project). The solution which helped me: libprotobuf.lib and libprotobuf.dll were replaced in debug/x86 mode by its debug version, libprotobufd.lib and libprotobufd.dll.

Running an opencd function (VideoWriter) in Debug mode and Release mode

I was trying to build and run the code below (Visual Studio 2013). Building is fine, but the code runs only in Debug mode, but fails in Release mode. I can see that the code stops when it tries to call the VideoWriter function, and I assume that it might be related to the file permission. But, why is it okay in Debug mode? It's a bit confusing.. Can somebody tell what's happening here or what I can further try to nail down the problem?
Thanks.
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
VideoCapture cap(0);
// Get size of frames
Size S = Size((int)cap.get(CV_CAP_PROP_FRAME_WIDTH), (int)
cap.get(CV_CAP_PROP_FRAME_HEIGHT));
// Make a video writer object and initialize it at 30 FPS
VideoWriter put("output.mpg", CV_FOURCC('M', 'P', 'E', 'G'), 30, S);
if (!put.isOpened())
{
cout << "File could not be created for writing. Check permissions" << endl;
return -1;
}
namedWindow("Video");
// Play the video in a loop till it ends
while (char(waitKey(1)) != 'q' && cap.isOpened())
{
Mat frame;
cap >> frame;
// Check if the video is over
if (frame.empty())
{
cout << "Video over" << endl;
break;
}
imshow("Video", frame);
put << frame;
}
return 0;
}

Cause of serial port transmitting bad data and WriteFile return wrong number of bytes written?

Bugfix update:
As of Jun, 2013 FTDI did acknowledge to me that the bug was real. They have since released a new version of their driver (2.8.30.0, dated 2013-July-12) that fixes the problem. The driver made it through WHQL around the first of August, 2013 and is available via Windows Update at this time.
I've re-tested running the same test code and am not able to reproduce the problem with the new driver, so at the moment the fix seems to be 'upgrade the driver'.
The original question:
I've got an 8 port USB-serial device (from VsCOM) that is based on the FTDI FT2232D chip. When I transmit at certain settings from one of the ports, AND I use the hardware handshaking to stop and start the data flow from the other end, I get two symptoms:
1) The output data sometimes becomes garbage. There will be NUL characters, and pretty much any random thing you can think of.
2) The WriteFile call will sometimes return a number of bytes GREATER than the number I asked it to write. That's not a typo. I ask for 30 bytes to be transmitted and the number of bytes sent comes back 8192 (and yes, I do clear the number sent to 0 before I make the call).
Relevant facts:
Using FTDI drivers 2.8.24.0, which is the latest as of today.
Serial port settings are 19200, 7 data bits, odd parity, 1 stop bit.
I get this same behavior with another FTDI based serial device, this time a single port one.
I get the same behavior with another 8 port device of the same type.
I do NOT get this behavior when transmitting on the built-in serial ports (COM1).
I have a very simple 'Writer' program that just transmits continuously and a very simple 'Toggler' program that toggles RTS once per second. Together these seem to trigger the issue within 60 seconds.
I have put an issue into the manufacturer of the device, but they've not yet had much time to respond.
Compiler is mingw32, the one included with the Qt installer for Qt 4.8.1 (gcc 4.4.0)
I'd like to know first off, if there's anything that anyone can think of that I could possibly do to trigger this behavior. I can't conceive of anything, but there's always things I don't know.
Secondly, I've attached the Writer and Toggler test programs. If anyone can spot some issue that might trigger the program, I'd love to hear about it. I have a lot of trouble thinking that there is a driver bug (especially from something as mature as the FTDI chip), but the circumstances force me to think that there's at least SOME driver involvement. At the least, no matter what I do to it, it shouldn't be returning a number of bytes written greater than what I asked it to write.
Writer program:
#include <iostream>
#include <string>
using std::cerr;
using std::endl;
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
cerr << "COM Writer, ctrl-c to end" << endl;
if (argc != 2) {
cerr << "Please specify a COM port for parameter 2";
return 1;
}
char fixedbuf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
std::string portName = "\\\\.\\";
portName += argv[1];
cerr << "Transmitting on port " << portName << endl;
HANDLE ph = CreateFileA( portName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if (ph == INVALID_HANDLE_VALUE) {
cerr << "CreateFile " << portName << " failed, error " << GetLastError() << endl;
return 1;
}
COMMCONFIG ccfg;
DWORD ccfgSize = sizeof(COMMCONFIG);
ccfg.dwSize = ccfgSize;
GetCommConfig(ph, &ccfg, &ccfgSize);
GetCommState(ph, &(ccfg.dcb));
ccfg.dcb.fBinary=TRUE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
ccfg.dcb.fAbortOnError=FALSE;
ccfg.dcb.fNull=FALSE;
// Camino is 19200 7-O-1
ccfg.dcb.BaudRate = 19200;
ccfg.dcb.Parity = ODDPARITY;
ccfg.dcb.fParity = TRUE;
ccfg.dcb.ByteSize = 7;
ccfg.dcb.StopBits = ONESTOPBIT;
// HW flow control
ccfg.dcb.fOutxCtsFlow=TRUE;
ccfg.dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
COMMTIMEOUTS ctimeout;
DWORD tout = 10;// 10 ms
ctimeout.ReadIntervalTimeout = tout;
ctimeout.ReadTotalTimeoutConstant = tout;
ctimeout.ReadTotalTimeoutMultiplier = 0;
ctimeout.WriteTotalTimeoutMultiplier = tout;
ctimeout.WriteTotalTimeoutConstant = 0;
SetCommConfig(ph, &ccfg, sizeof(COMMCONFIG));
SetCommTimeouts(ph, &ctimeout);
DWORD nwrite = 1;
for(;;) {
nwrite++;
if (nwrite > 30) nwrite = 1;
DWORD nwritten = 0;
if (!WriteFile(ph, fixedbuf, nwrite, &nwritten, NULL)) {
cerr << "f" << endl;
}
if ((nwritten != 0) && (nwritten != nwrite)) {
cerr << "nwrite: " << nwrite << " written: " << nwritten << endl;
}
}
return 0;
}
Toggler program:
#include <iostream>
#include <string>
using std::cerr;
using std::endl;
#include <stdio.h>
#include <windows.h>
int main(int argc, char **argv)
{
cerr << "COM Toggler, ctrl-c to end" << endl;
cerr << "Flips the RTS line every second." << endl;
if (argc != 2) {
cerr << "Please specify a COM port for parameter 2";
return 1;
}
std::string portName = "\\\\.\\";
portName += argv[1];
cerr << "Toggling RTS on port " << portName << endl;
HANDLE ph = CreateFileA( portName.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // must be opened with exclusive-access
NULL, // default security attributes
OPEN_EXISTING, // must use OPEN_EXISTING
0, // overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if (ph == INVALID_HANDLE_VALUE) {
cerr << "CreateFile " << portName << " failed, error " << GetLastError() << endl;
return 1;
}
COMMCONFIG ccfg;
DWORD ccfgSize = sizeof(COMMCONFIG);
ccfg.dwSize = ccfgSize;
GetCommConfig(ph, &ccfg, &ccfgSize);
GetCommState(ph, &(ccfg.dcb));
ccfg.dcb.fBinary=TRUE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
ccfg.dcb.fAbortOnError=FALSE;
ccfg.dcb.fNull=FALSE;
// Camino is 19200 7-O-1
ccfg.dcb.BaudRate = 19200;
ccfg.dcb.Parity = ODDPARITY;
ccfg.dcb.fParity = TRUE;
ccfg.dcb.ByteSize = 7;
ccfg.dcb.StopBits = ONESTOPBIT;
// no flow control (so we can do manually)
ccfg.dcb.fOutxCtsFlow=FALSE;
ccfg.dcb.fRtsControl=RTS_CONTROL_DISABLE;
ccfg.dcb.fInX=FALSE;
ccfg.dcb.fOutX=FALSE;
COMMTIMEOUTS ctimeout;
DWORD tout = 10;// 10 ms
ctimeout.ReadIntervalTimeout = tout;
ctimeout.ReadTotalTimeoutConstant = tout;
ctimeout.ReadTotalTimeoutMultiplier = 0;
ctimeout.WriteTotalTimeoutMultiplier = tout;
ctimeout.WriteTotalTimeoutConstant = 0;
SetCommConfig(ph, &ccfg, sizeof(COMMCONFIG));
SetCommTimeouts(ph, &ctimeout);
bool rts = true;// true for set
for(;;) {
if (rts)
EscapeCommFunction(ph, SETRTS);
else
EscapeCommFunction(ph, CLRRTS);
rts = !rts;
Sleep(1000);// 1 sec wait.
}
return 0;
}
I don't have a good answer yet from FTDI, but I've got the following suggestions for anyone dealing with this issue:
1) Consider switching to a non-FTDI usb-serial converter. This is what my company did, but certainly this isn't an option for everyone (we're putting the chip in our own product). We're using Silicon Labs chips now, but I think there are one or two other vendors as well.
2) Per Hans Passant in the comments - reconsider the use of RTS/CTS signalling. If the writes don't fail due to blocking, then you shouldn't trigger this bug.
3) Set all writes to infinite timeout. Again, no fail due to blocking, no triggering of the bug. This may not be appropriate for all applications, of course.
Note that if pursuing strategy #3, if Overlapped IO is used for writes, then CancelIo and it's newer cousin CancelIoEx could be used to kill off the writes if necessary. I have NOT tried doing so, but I suspect that such cancels might also result in triggering this bug. If they were only used when closing the port anyway, then it might be you could get away with it, even if they do trigger the bug.
If anyone else is still seeing this -- update your FTDI driver to 2.8.30.0 or later, as this is caused by a driver bug in earlier versions of the FTDI driver.

How to get an X11 Window from a Process ID?

Under Linux, my C++ application is using fork() and execv() to launch multiple instances of OpenOffice so as to view some powerpoint slide shows. This part works.
Next I want to be able to move the OpenOffice windows to specific locations on the display. I can do that with the XMoveResizeWindow() function but I need to find the Window for each instance.
I have the process ID of each instance, how can I find the X11 Window from that ?
UPDATE - Thanks to Andy's suggestion, I have pulled this off. I'm posting the code here to share it with the Stack Overflow community.
Unfortunately Open Office does not seem to set the _NET_WM_PID property so this doesn't ultimately solve my problem but it does answer the question.
// Attempt to identify a window by name or attribute.
// by Adam Pierce <adam#doctort.org>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <list>
using namespace std;
class WindowsMatchingPid
{
public:
WindowsMatchingPid(Display *display, Window wRoot, unsigned long pid)
: _display(display)
, _pid(pid)
{
// Get the PID property atom.
_atomPID = XInternAtom(display, "_NET_WM_PID", True);
if(_atomPID == None)
{
cout << "No such atom" << endl;
return;
}
search(wRoot);
}
const list<Window> &result() const { return _result; }
private:
unsigned long _pid;
Atom _atomPID;
Display *_display;
list<Window> _result;
void search(Window w)
{
// Get the PID for the current Window.
Atom type;
int format;
unsigned long nItems;
unsigned long bytesAfter;
unsigned char *propPID = 0;
if(Success == XGetWindowProperty(_display, w, _atomPID, 0, 1, False, XA_CARDINAL,
&type, &format, &nItems, &bytesAfter, &propPID))
{
if(propPID != 0)
{
// If the PID matches, add this window to the result set.
if(_pid == *((unsigned long *)propPID))
_result.push_back(w);
XFree(propPID);
}
}
// Recurse into child windows.
Window wRoot;
Window wParent;
Window *wChild;
unsigned nChildren;
if(0 != XQueryTree(_display, w, &wRoot, &wParent, &wChild, &nChildren))
{
for(unsigned i = 0; i < nChildren; i++)
search(wChild[i]);
}
}
};
int main(int argc, char **argv)
{
if(argc < 2)
return 1;
int pid = atoi(argv[1]);
cout << "Searching for windows associated with PID " << pid << endl;
// Start with the root window.
Display *display = XOpenDisplay(0);
WindowsMatchingPid match(display, XDefaultRootWindow(display), pid);
// Print the result.
const list<Window> &result = match.result();
for(list<Window>::const_iterator it = result.begin(); it != result.end(); it++)
cout << "Window #" << (unsigned long)(*it) << endl;
return 0;
}
The only way I know to do this is to traverse the tree of windows until you find what you're looking for. Traversing isn't hard (just see what xwininfo -root -tree does by looking at xwininfo.c if you need an example).
But how do you identify the window you are looking for? Some applications set a window property called _NET_WM_PID.
I believe that OpenOffice is one of the applications that sets that property (as do most Gnome apps), so you're in luck.
Check if /proc/PID/environ contains a variable called WINDOWID
Bit late to the party. However:
Back in 2004, Harald Welte posted a code snippet that wraps the XCreateWindow() call via LD_PRELOAD and stores the process id in _NET_WM_PID. This makes sure that each window created has a PID entry.
http://www.mail-archive.com/devel#xfree86.org/msg05806.html
Try installing xdotool, then:
#!/bin/bash
# --any and --name present only as a work-around, see: https://github.com/jordansissel/xdotool/issues/14
ids=$(xdotool search --any --pid "$1" --name "dummy")
I do get a lot of ids. I use this to set a terminal window as urgent when it is done with a long command, with the program seturgent. I just loop through all the ids I get from xdotool and run seturgent on them.
There is no good way. The only real options I see, are:
You could look around in the process's address space to find the connection information and window ID.
You could try to use netstat or lsof or ipcs to map the connections to the Xserver, and then (somehow! you'll need root at least) look at its connection info to find them.
When spawning an instance you can wait until another window is mapped, assume it's the right one, and `move on.
I took the freedom to re-implement the OP's code using some modern C++ features. It maintains the same functionalities but I think that it reads a bit better. Also it does not leak even if the vector insertion happens to throw.
// Attempt to identify a window by name or attribute.
// originally written by Adam Pierce <adam#doctort.org>
// revised by Dario Pellegrini <pellegrini.dario#gmail.com>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
#include <vector>
std::vector<Window> pid2windows(pid_t pid, Display* display, Window w) {
struct implementation {
struct FreeWrapRAII {
void * data;
FreeWrapRAII(void * data): data(data) {}
~FreeWrapRAII(){ XFree(data); }
};
std::vector<Window> result;
pid_t pid;
Display* display;
Atom atomPID;
implementation(pid_t pid, Display* display): pid(pid), display(display) {
// Get the PID property atom
atomPID = XInternAtom(display, "_NET_WM_PID", True);
if(atomPID == None) {
throw std::runtime_error("pid2windows: no such atom");
}
}
std::vector<Window> getChildren(Window w) {
Window wRoot;
Window wParent;
Window *wChild;
unsigned nChildren;
std::vector<Window> children;
if(0 != XQueryTree(display, w, &wRoot, &wParent, &wChild, &nChildren)) {
FreeWrapRAII tmp( wChild );
children.insert(children.end(), wChild, wChild+nChildren);
}
return children;
}
void emplaceIfMatches(Window w) {
// Get the PID for the given Window
Atom type;
int format;
unsigned long nItems;
unsigned long bytesAfter;
unsigned char *propPID = 0;
if(Success == XGetWindowProperty(display, w, atomPID, 0, 1, False, XA_CARDINAL,
&type, &format, &nItems, &bytesAfter, &propPID)) {
if(propPID != 0) {
FreeWrapRAII tmp( propPID );
if(pid == *reinterpret_cast<pid_t*>(propPID)) {
result.emplace_back(w);
}
}
}
}
void recurse( Window w) {
emplaceIfMatches(w);
for (auto & child: getChildren(w)) {
recurse(child);
}
}
std::vector<Window> operator()( Window w ) {
result.clear();
recurse(w);
return result;
}
};
//back to pid2windows function
return implementation{pid, display}(w);
}
std::vector<Window> pid2windows(const size_t pid, Display* display) {
return pid2windows(pid, display, XDefaultRootWindow(display));
}
int main(int argc, char **argv) {
if(argc < 2)
return 1;
int pid = atoi(argv[1]);
std::cout << "Searching for windows associated with PID " << pid << std::endl;
// Start with the root window.
Display *display = XOpenDisplay(0);
auto res = pid2windows(pid, display);
// Print the result.
for( auto & w: res) {
std::cout << "Window #" << static_cast<unsigned long>(w) << std::endl;
}
XCloseDisplay(display);
return 0;
}
Are you sure you have the process ID of each instance? My experience with OOo has been that trying to run a second instance of OOo merely converses with the first instance of OOo, and tells that to open the additional file.
I think you're going to need to use the message-sending capabilities of X to ask it nicely for its window. I would hope that OOo documents its coversations somewhere.
If you use python, I found a way here, the idea is from BurntSushi
If you launched the application, then you should know its cmd string, with which you can reduce calls to xprop, you can always loop through all the xids and check if the pid is the same as the pid you want
import subprocess
import re
import struct
import xcffib as xcb
import xcffib.xproto
def get_property_value(property_reply):
assert isinstance(property_reply, xcb.xproto.GetPropertyReply)
if property_reply.format == 8:
if 0 in property_reply.value:
ret = []
s = ''
for o in property_reply.value:
if o == 0:
ret.append(s)
s = ''
else:
s += chr(o)
else:
ret = str(property_reply.value.buf())
return ret
elif property_reply.format in (16, 32):
return list(struct.unpack('I' * property_reply.value_len,
property_reply.value.buf()))
return None
def getProperty(connection, ident, propertyName):
propertyType = eval(' xcb.xproto.Atom.%s' % propertyName)
try:
return connection.core.GetProperty(False, ident, propertyType,
xcb.xproto.GetPropertyType.Any,
0, 2 ** 32 - 1)
except:
return None
c = xcb.connect()
root = c.get_setup().roots[0].root
_NET_CLIENT_LIST = c.core.InternAtom(True, len('_NET_CLIENT_LIST'),
'_NET_CLIENT_LIST').reply().atom
raw_clientlist = c.core.GetProperty(False, root, _NET_CLIENT_LIST,
xcb.xproto.GetPropertyType.Any,
0, 2 ** 32 - 1).reply()
clientlist = get_property_value(raw_clientlist)
cookies = {}
for ident in clientlist:
wm_command = getProperty(c, ident, 'WM_COMMAND')
cookies[ident] = (wm_command)
xids=[]
for ident in cookies:
cmd = get_property_value(cookies[ident].reply())
if cmd and spref in cmd:
xids.append(ident)
for xid in xids:
pid = subprocess.check_output('xprop -id %s _NET_WM_PID' % xid, shell=True)
pid = re.search('(?<=\s=\s)\d+', pid).group()
if int(pid) == self.pid:
print 'found pid:', pid
break
print 'your xid:', xid

Resources