I am writing a win32 application by C++, and I want it to do something when all iexplorer.exe were closed.
I know that SetWindowsHook() may be useful in my case.
But if I have no idea about the process or thread ID of IE, because every time open IE would get a different thread ID.
If I do not use timer to check the process list to get the ID of iexplorer, does there have another approach to listen close event of IE in my win32 application?
The object for IE is called InternetExplorer. TheShellWindows object is a collection of InternetExplorer objects. But here it gets complicated. Not all InternetExplorer objects are what you would call an IE window. Some of them are "Windows Explorer" windows. See About the Browser (Internet Explorer).
The following is a managed C++ console program that lists the existing windows and sets a count of the number of existing windows. Then it uses WindowRegistered and WindowRevoked events to monitor creation and closing of windows. Those event are not documented very well. The sample below uses the Document member of each InternetExplorer object to determine if the window has HTML. However see the comment in c# - Distinguishing IE windows from other windows when using SHDocVw; it is possible for a IE window to not have HTML in it.
Note that the following sample is using an AutoResetEvent to keep the program going since it is a console program.
The following is the header:
#pragma once
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <ShlObj.h>
#include <comdef.h>
#include <vcclr.h>
The following is the program:
#include "stdafx.h"
using namespace System;
using namespace System::Threading;
static int Browsers = 0;
static gcroot<AutoResetEvent^> Event;
bool IsBrowser(SHDocVw::InternetExplorer ^ ie)
{
MSHTML::IHTMLDocument2^ Document;
try { Document = (MSHTML::IHTMLDocument2^)ie->Document; }
catch (Exception^ ex)
{
return false;
}
return Document != nullptr;
}
static void WindowRegistered(int lCookie) {
++Browsers;
Console::WriteLine("WindowRegistered");
}
static void WindowRevoked(int lCookie) {
--Browsers;
Console::WriteLine("WindowRevoked");
if (Browsers <= 0)
Event->Set();
}
int main(array<System::String ^> ^args)
{
SHDocVw::ShellWindows^ swList = gcnew SHDocVw::ShellWindowsClass();
Console::WriteLine(L"{0} instances", swList->Count);
for each (SHDocVw::InternetExplorer ^ ie in swList) {
Console::WriteLine(ie->LocationURL);
if (IsBrowser(ie)) {
Console::WriteLine("HTML document");
++Browsers;
}
else
Console::WriteLine("Not HTML");
}
if (Browsers == 0)
{
Console::WriteLine("No browsers");
return 0;
}
Event = gcnew AutoResetEvent(false);
swList->WindowRegistered += gcnew SHDocVw::DShellWindowsEvents_WindowRegisteredEventHandler(WindowRegistered);
swList->WindowRevoked += gcnew SHDocVw::DShellWindowsEvents_WindowRevokedEventHandler(WindowRevoked);
Event->WaitOne();
Console::WriteLine("No more browsers");
return 0;
}
Now I just realized that there is a problem with the way this works. The WindowRegistered and WindowRevoked handlers are incrementing the Browsers count even if the window is not an IE window. I don't know how to determine what window that the cookie passed to WindowRegistered and WindowRevoked represents. A few years ago I spent a couple of days or more tryinig to figure that out. So what you should do is to somehow re-list all the windows after each WindowRegistered and WindowRevoked event.
You need to add references for "Microsoft Internet Controls" (SHDocVw.dll) and "Microsoft HTML Object Library" (mshtml.dll) to the project. They are COM objects that should be in your "C:\Windows\System32" directory.
I am currently trying to find if one of my Windows is underneath the Mouse cursor. This is not done in my process that creates the window, but in another process.
What I am currently doing is finding the Window via the process PID (and I made sure _NET_WM_PID is set correctly by my program). This basically works via XQueryTree and XGetWindowProperty. This works fine and is not the problem.
The problem is that XQueryPointer gives me fuzzy Windows back. I wrote a simple test program to show what I mean. First gather an ID from any Window you like using the command xprop via bash. It will give you the Window ID.
Then run this simple test program I wrote (quick and dirty), it gives you every 0,5s the current ID from the Window underneath the mouse cursor:
#include <X11/Xlib.h>
#include <iostream>
#include <unistd.h>
#include <stdint.h>
int main()
{
Display *display = XOpenDisplay(0);
Window root = XDefaultRootWindow(display);
Window root_return;
Window child_return;
int root_x_return;
int root_y_return;
int win_x_return;
int win_y_return;
uint32_t mask_return;
while (true)
{
if (::XQueryPointer(display, root, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return) == True)
{
std::cout << "Window ID: " << child_return << std::endl;
}
usleep(500000);
}
return 0;
}
Can somebody tell me what the problem is?
And here is my example output:
My program finds Window ID 73400324
xprop finds Window ID 73400324
The test program finds Window ID 20996726
Could be child windows, or the decoration that the window manager adds to a plain window.
By the way, the normal way to detect if your window is under the mouse is by catching the XEnterWindowEvent and XLeaveWindowEvent, but this is normally done within the program itself, not externally.
I have this code to listen to keyboard events of the active window:
#include<X11/Xlib.h>
#include<stdio.h>
#include<stdlib.h>
#include <iostream>
#include <thread>
using namespace std;
#define IR_MODE 8192
#define SHIFT_MODE 16
#define US_MODE 0
static int ErrorHandler (Display *display, XErrorEvent *error)
{
cout<< "An error ocurred. We don't know anything.";
return 0;
}
int main()
{
Display *d = XOpenDisplay(0);
if(d == 0)
{
cout<< "Cannot open display\n";
exit(0);
}
Window root = DefaultRootWindow(d);
XSetErrorHandler(ErrorHandler);
Window current_window;
int rev;
XGetInputFocus(d,¤t_window,&rev);
XSelectInput(d,current_window, KeyPressMask | KeyReleaseMask | FocusChangeMask);
while(true)
{
XEvent e;
XNextEvent(d, &e);
switch(e.type)
{
case FocusOut:
XGetInputFocus(d,¤t_window,&rev);
if(current_window == PointerRoot || current_window == None)
{
current_window = root;
}
XSelectInput(d,current_window, KeyPressMask | KeyReleaseMask | FocusChangeMask);
break;
case KeyPress:
{
cout<< "key pressed\n";
break;
}
case KeyRelease:
cout<< "key released\n";
break;
}
}
XCloseDisplay(d);//*/
}
It works for many windows. But it fails for some windows, specially for gnome applications, e.g. nautilus. Why does this happen and how can I solve the problem?
The program just tries to listen to keyboard without interfering anything. As if the keyboard is being tapped with a difference: the program doesn't intend to lose language layout info. When a key is pressed, some information including ASCII codes are chosen and attached to the key event according to language layout and then the key event is sent. The program needs the key event with the information attached to it. So The program does not intend to Grab keyboard. It does not care for active or focused window. It just tries to listen to keys even if the program's window is not active. There are programs which check regularly with XQueryKeymap, but I'm not going to use that. Because it uses up CPU and then it will be more than just a fair listener. Also if checking is not frequent some keys may escape.
I guess your program does not work with GTK3 windows which uses xinput2. This is true if GTK3 was built without --disable-xinput.
AFAIK XSelectInput() won't work with xinput2, you need XISelectEvents() for such windows.
Look at meta_core_select_events() function from Mutter sources. It works both for xinput2 and traditional windows. This patch may be also helpful.
Hello I'm writing a c++ program and I need to get what's on clipboard into a string variable. I found a lot of solutions but all of them were written for windows. Is there any method without using the QT libraries? I found something related to X11 but not very explicit aswell.
Thank you very much
X11 uses a flexible multi-buffer multi-format asynchronous application-side clipboard protocol.
Most toolkits have it implemented (GTK's gtk_clipboard_get(), Qt's QApplication::clipboard(), Tk's clipboard_get). But you can do it manually with X11 API, for example, if you're not using toolkits, or if you must pass large amount of data through clipboard buffer without keeping it all in memory at the same time.
Theory
There may be many buffers, but you only need to know about two:
CLIPBOARD is the usual explicit buffer: you copy things there with Edit/Copy menu, and paste it with Edit/Paste menu.
PRIMARY selection is an implicit mouse selection feature: text gets in it when selected with mouse cursor, and gets pasted from it on middle-click in text input fields.
Primary selection needs no keypresses, so it's useful for copying small fragments between windows that are next to each other. This feature is mostly unix-specific, but I've seen putty, trillian and some gtk apps emulating it on Windows OS. Also firefox has "Paste & Go" feature when middle-clicking empty non-interactive space of the page.
To optimize things those are application-side buffers: instead of pushing entire clipboard/selection to the server every time it changes, application just tells the server "I own it". To get the buffer you ask the owner to give you its content. This way even a large buffer takes no resources until its actually requested.
When requesting the buffer you ask the owner for a specific format you need. For example an image copied from seamonkey browser (right-click an image and press "Copy Image") can be represented in different formats. It would appear as image URL if you paste it in terminal. It would become a picture loaded from that URL if you paste it in libreoffice writer. And it'd be the image itself if pasted in gimp. That works because seamonkey is smart and provides each application with format it asks for: text string for terminal, html for libreoffice and image data for gimp. To request text format you'd ask for UTF8_STRING format with fallback to STRING.
As you ask another application to prepare the buffer, and that may take some time, the request is asynchronous: the owner prepares the buffer, saves it in a specified location (window property is used as a temporary storage) and notifies you with SelectionNotify event when it's done.
So to get the buffer:
choose buffer name (CLIPBOARD, PRIMARY), format
(UTF8_STRING, STRING) and a window property to store result to
call XConvertSelection() to request the buffer
wait for SelectionNotify event
read buffer content from window property
Naive implementation
// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>
Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
char *result;
unsigned long ressize, restail;
int resbits;
Atom bufid = XInternAtom(display, bufname, False),
fmtid = XInternAtom(display, fmtname, False),
propid = XInternAtom(display, "XSEL_DATA", False),
incrid = XInternAtom(display, "INCR", False);
XEvent event;
XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
do {
XNextEvent(display, &event);
} while (event.type != SelectionNotify || event.xselection.selection != bufid);
if (event.xselection.property)
{
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, False, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
if (fmtid == incrid)
printf("Buffer is too large and INCR reading is not implemented yet.\n");
else
printf("%.*s", (int)ressize, result);
XFree(result);
return True;
}
else // request failed, e.g. owner can't convert to the target format
return False;
}
int main()
{
Display *display = XOpenDisplay(NULL);
unsigned long color = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
PrintSelection(display, window, "CLIPBOARD", "STRING");
XDestroyWindow(display, window);
XCloseDisplay(display);
return !result;
}
This will work for many simple cases. One thing missing here is support for incremental reading of large buffers. Let's add it!
Large buffers
Some apps may want to copy/paste 100 gigabytes of text logs. And X11 allows that! But the data must be passed incrementally, split into chunks.
If the requested buffer is too large, instead of storing it into the window property, owner sets a property of format INCR. If you delete it, owner assumes you've read it, and puts next chunk in the same property. That continues until the last chunk is read and deleted. Finally owner sets property of size 0 to mark the end of data.
So to read large buffer you delete INCR property and wait for the property to appear again (PropertyNotify event, state == PropertyNewValue), read and delete it, wait for it to appear again, and so on until it appears with zero size.
// gcc -o xclipget xclipget.c -lX11
#include <stdio.h>
#include <limits.h>
#include <X11/Xlib.h>
Bool PrintSelection(Display *display, Window window, const char *bufname, const char *fmtname)
{
char *result;
unsigned long ressize, restail;
int resbits;
Atom bufid = XInternAtom(display, bufname, False),
fmtid = XInternAtom(display, fmtname, False),
propid = XInternAtom(display, "XSEL_DATA", False),
incrid = XInternAtom(display, "INCR", False);
XEvent event;
XSelectInput (display, window, PropertyChangeMask);
XConvertSelection(display, bufid, fmtid, propid, window, CurrentTime);
do {
XNextEvent(display, &event);
} while (event.type != SelectionNotify || event.xselection.selection != bufid);
if (event.xselection.property)
{
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
if (fmtid != incrid)
printf("%.*s", (int)ressize, result);
XFree(result);
if (fmtid == incrid)
do {
do {
XNextEvent(display, &event);
} while (event.type != PropertyNotify || event.xproperty.atom != propid || event.xproperty.state != PropertyNewValue);
XGetWindowProperty(display, window, propid, 0, LONG_MAX/4, True, AnyPropertyType,
&fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
printf("%.*s", (int)ressize, result);
XFree(result);
} while (ressize > 0);
return True;
}
else // request failed, e.g. owner can't convert to the target format
return False;
}
int main()
{
Display *display = XOpenDisplay(NULL);
unsigned long color = BlackPixel(display, DefaultScreen(display));
Window window = XCreateSimpleWindow(display, DefaultRootWindow(display), 0,0, 1,1, 0, color, color);
Bool result = PrintSelection(display, window, "CLIPBOARD", "UTF8_STRING") ||
PrintSelection(display, window, "CLIPBOARD", "STRING");
XDestroyWindow(display, window);
XCloseDisplay(display);
return !result;
}
For example xsel tool uses INCR transfer for buffers larger than 4000. According to ICCCM, it's up to the application to choose a reasonable size limit.
The same code works for PRIMARY selection. Replace "CLIPBOARD" with "PRIMARY" to print PRIMARY selection contents.
References
X Selections summary by Jamie Zawinski
Xlib Programming Manual - Selections
ICCCM - Large Data Transfers and INCR protocol
https://github.com/exebook/x11clipboard - minimal XCopy() and XPaste() implementations
xsel and xclip sources
The Secondary Selection - history and ideas by Charles Lindsey
Did you try to find not a code first but a program with an implementation ? I did it for you and found a lot of implementations which use direct X11 calls. I think the most valuable is this but also you may read this. Just find any program and look for the sources. Try to look on wikipedia what applications use x11 clipboard/selection system.
The following programs specifically operate on data transfer
mechanisms:
xcutsel transfers data from selections to cut buffers or vice versa
xclipboard, glipper (Gnome), parcellite (LXDE), and klipper (KDE) are
clipboard managers, maybe wmcliphist as well xcb shows the content of
the cut buffers and allows the user to manipulate them xselection,
xclip, xsel and xcopy are command line programs that copy data to or
from the X selection. xcopy has a verbosity option that helps debug X
selection issues. parcellite also has the ability to read from and
write to specific X selections from the command line.
synergy is a cross platform tool that allows you to share a clipboard across
multiple computers running multiple operating systems
xfce4-clipman-plugin is a "clipboard history plugin for the Xfce4
panel" and also a clipboard manager xtranslate looks up words in the
Xselection in a multi-lingual dictionary autocutsel syncs cut buffer
and selection buffer
Shortly, in theory, X11 has 2 "clipboards": actually a keyboard and for selections - the text you selected immediately can be pasted anywhere you want by pressing middle-mouse button while actual "keyboard" is made for main/default clipboard purposes as exchange by different kind of objects.
P.S. I'd not work with x11 anymore after my experience. Enjoy :)
I am trying to temporarily install a font to use in the win32 console with
int AddFontResource(LPCTSTR lpszFilename);
and
BOOL WINAPI SetConsoleFont(HANDLE hOutput, DWORD fontIndex)
I got hold of this function from this site.
Although both functions seem to work fine I have no idea how to find the added font index to use with SetConsoleFont.
AddFontResource returns no index value or key to the temporary font.
Here is my relevant code:
#include "Level.h"
#include "ConsoleFont.h" //acquired from above mentioned site
#include <Windows.h>
//-------------------------------------------------------------------------------
void init();
void cleanup();
int main()
{
FileManager *pFileManager = new FileManager(); //unrelated
Level *lvl1 = new Level("filename",pFileManager); //unrelated
///TEMPORARY PLANNING
// using add font resource. how can i get this fonts index value?
int err = AddFontResource(L"Files/gamefont.fnt");
if (err == 0)
{
MessageBox(NULL,L"loading font failed",L"Error",0);
}
else
{
wchar_t message[100];
swprintf_s(message,100,L"AddFontResource returned: %d",err);
MessageBox(NULL,LPTSTR(message),L"error",0);
}
SendMessage(HWND_BROADCAST, WM_FONTCHANGE,0,0);
//acquiring handle to current active screen buffer
HANDLE tempHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (tempHandle == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,L"Failed to aquire Screen Buffer handle",L"Error",0);
}
//I dont know what to set this to. this is the crux of the problem.
DWORD fontIndex = 1;
if (FALSE == SetConsoleFont(tempHandle,fontIndex))
{
MessageBox(NULL,L"loading console font failed",L"Error",0);
}
//draws a house when in correct font
std::cout<<"!!!!!!!!#\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !#\n"
<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<std::endl;
///PLANNING OVERS
bool quit = false;
while(!quit)
{
//still to be implemented
}
err = RemoveFontResource(L"Files/gamefont.fnt");
if (err==0)
{
MessageBox(NULL,L"removing font failed",L"Error",0);
}
return 0;
}
I don't know how to go about finding my new font's index value or even if this is possible using my current method.
If someone knows or has a better method please help me out.
any help or hints are appreciated. It must possible to use a custom font in the win32 Console without fiddling with the registry. I'm sure of it :)
Unfortunately you entered the dark world on Win APIs. There is no documentation (or atleast I could never find it) for a console font table lookup. You can try the method "GetNumberOfConsoleFonts()" to see what is returned. I think the font at index 10 is Lucida Console. You'll have to play around a little. Also, this may not work for the OS version you have. Worked for me on XP. Never had to try on anything else. And honestly, never got it fully working on XP too.
For the registry,
Fonts registries are here:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
Console registries are here:
HKEY_CURRENT_USER\Console
If you end up modifying the registry, the changes may not be reflected immediately. You need to either restart the console or send a special WM_* message (sorry don't remember the name).
Will be great if you can find a solution/workaround :)
int err = AddFontResource(L"Files/gamefont.fnt");
if (err == 0)
{
MessageBox(NULL,L"loading font failed",L"Error",0);
}
else
{
wchar_t message[100];
swprintf_s(message,100,L"AddFontResource returned: %d",err);
MessageBox(NULL,LPTSTR(message),L"error",0);
}
this is wrong AddFontResource returns the number of fonts loaded, so the code in the ELSE doesn't make sense.