I'm using CreateProcess() with startup flags set to STARTF_USESHOWWINDOW and SW_HIDE to start an application in the background with its window hidden.
I'm doing this to run a scheduled maintenance tasks and i don't want to be bothered with windows.
In most cases the windows are hidden but there are cases where the program's window pops right out in front of you (for example Google's Chrome - i started testing with different apps to see whether this was a once time problem but nope...).
This happens less in Windows XP, but it happens a lot on Vista.
Is there a flag that I am missing? Is there any other way to create a process with its window hidden?
Thanks!
my sample code is:
char *ProgramName
STARTUPINFO StartupInfoF;
PROCESS_INFORMATION ProcessInfoF;
memset(&StartupInfoF, 0, sizeof(StartupInfoF));
memset(&ProcessInfoF, 0, sizeof(ProcessInfoF));
StartupInfoF.cb = sizeof(StartupInfoF);
StartupInfoF.wShowWindow = SW_HIDE;
StartupInfoF.dwFlags = STARTF_USESHOWWINDOW;
if (CreateProcess(ProgramName,
"",
0,
0,
FALSE,
DETACHED_PROCESS,
0,
0,
&StartupInfoF,
&ProcessInfoF) == FALSE)
{
// error
}
else
{
// OK
}
You can start the process on another desktop, using the lpDesktop member of the STARTUPINFO structure passed to CreateProcess. This way the process will have all its windows shown, but on another desktop, so you (or your users) won't be bothered with it.
I've never worked with multiple desktops so I can't say what would be the side effects, but I think it's doable. Start by looking into CreateDesktop and move onward.
I don't remember the answer to your question, but I'd like to suggest that maybe you shouldn't keep the window totally hidden? If you want the window out of the way, minimizing it will suffice; hiding it completely only removes the ability to check on your scheduled maintenance tasks.
Some programs could ignore/override SW_HIDE flag. You could try to hide window after child process started.
Another option is to try to use CreateProcessAsUser to run processes in Session 0 which has isolated desktop (starting from Vista version).
I'd suggest making it a service. For one thing, that will allow it to run your scheduled maintanence even when nobody is logged in. For another, it is fairly easy to set services up so that they don't have access to the desktop.
Related
I have an unrepeatable bug of unknown origin in my single threaded window manager that occurs fairly infrequently (once every 2-3 weeks). Something happens that causes me to lose keyboard input. Mouse events are still handled properly so I know the event loop is still running, but the key press event is no longer triggered. Actually, the key is no longer grabbed. When I press XCB_MOD_MASK_4+2 to switch to desktop 2, the 2 will show up in the text editor or terminal that currently has the input focus, instead of being grabbed by the window manager. I thought maybe it was related to xcb_allow_events, so via IPC I can execute these three tests (from within the window manager, cmd is received from an external process):
if (strcmp(cmd,"test0")==0)
xcb_allow_events(wm.conn, XCB_ALLOW_ASYNC_KEYBOARD, XCB_CURRENT_TIME);
else if (strcmp(cmd,"test1")==0)
xcb_allow_events(wm.conn, XCB_ALLOW_SYNC_KEYBOARD, XCB_CURRENT_TIME);
else if (strcmp(cmd,"test2")==0)
keyboard();
void keyboard()
{
int i,m,k;
xcb_void_cookie_t cookie;
spawn("/usr/bin/xmodmap -e 'keycode 108 = Super_L'");
spawn("/usr/bin/xmodmap -e 'remove mod1 = Super_L'");
for (i=0; i<LENGTH(key_bindings); i++)
{
m = key_bindings[i].mod;
k = keysc(key_bindings[i].keysym);
info("grabbing key: %s (%d), mod: %d",key_bindings[i].keysym,k,m);
cookie = xcb_grab_key_checked(wm.conn, 0, wm.root, m, k, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
if (xcb_request_check (wm.conn, cookie))
error("can't grab key");
}
}
None of these tests help. I know the keyboard function works properly because it works on window manager startup. Also I can see in the log file that the key grabs in the keyboard function are actually being executed (without error) when prompted via IPC. The current workaround is to send sigterm to the window manager process, and then restart the wm. At that point everything works fine again.
I'm looking for techniques that might be helpful in tracking down the source of this problem, or in correcting the problem once it occurs (another test). Unfortunately, since I have no clue of the source of this problem, or what triggers it, I cannot make a simple test case to demonstrate. BTW I check the log files when this happens, and I don't see any pattern leading up to the problem. Each function logs an entry on entrance and exit.
Update 2021-02-12: I thought a restart would be a good workaround until I found the root cause of this problem. My restart function contains only one line:
execvp(lwm_argv[0], lwm_argv);
where lwm_argv is the argv provided as an argument to main.
I was very surprised to see that this did not alleviate the problem. I have to completely kill the old process then launch an new one to alleviate the problem. So this problem is PID dependant??? Further, I'm fairly convinced that this problem is somehow related to the stdout/stderr output of other applications launched from within the window manager using execvp. I've stopped launching applications from within the window manager and the problem went away. Any ideas of how launching other applications (and their output) could be affecting the keygrabs within the window manager would be appreciated.
You could try using strace or perf trace on the X server to see what it is doing with the key events. It ought to read them from somewhere in /dev/input and send them as events to connected clients.
If it isn't sending you events, then you might need to dig into its internal state, perhaps by building a debug server and connecting to it with GDB, to see why it isn't sending those events.
But if it is sending events to your WM then they're getting lost somewhere in the library stack.
I am launching a WPF application from a MFC Application. Sometimes it happens that when I Launch the WPF Applciation, the applciation does get launched but it does not appear in the taskbar. And stays behind the main application. So I keep waiting that the application has not yet launched. When I minimize the main Application, I see it was already launched. Can anyone please identify whats going on?
Thanks
You are using ShellExecute incorrectly. Please have a look here. The last parameter, nShowCmd, is:
The flags that specify how an application is to be displayed when it is opened. If lpFile specifies a document file, the flag is simply passed to the associated application. It is up to the application to decide how to handle it. These values are defined in Winuser.h.
Therefore, you need to specify the desired ShowWindow flag. I recommend using either SW_SHOWNORMAL or SW_MAXIMIZE:
int nResult = (int)::ShellExecute(NULL, _T("open"), sExePath, NULL, NULL, SW_SHOWNORMAL);
or
int nResult = (int)::ShellExecute(NULL, _T("open"), sExePath, NULL, NULL, SW_MAXIMIZE);
It is also a good idea to check the return code of the function. If it succeeds the value in nReturn should be greater than 32.
I've been experiencing some problems with the ReportViewer. Basically the code is the following:
public void Display(object dataSource, ReportViewer viewer)
{
currentDs = dataSource as MyTypes;
if (currentDs != null)
{
var param = new LinkedList<ReportParameter>();
param.AddFirst(new ReportParameter("Title", "Title"));
viewer.ProcessingMode = ProcessingMode.Local;
viewer.LocalReport.ReportEmbeddedResource = ReportName;
viewer.LocalReport.EnableExternalImages = true;
viewer.LocalReport.DataSources.Add(new ReportDataSource(DataSourceName + "_Header", currentDs.Header));
viewer.LocalReport.DataSources.Add(new ReportDataSource(DataSourceName + "_Footer", currentDs.Footer));
viewer.LocalReport.DataSources.Add(new ReportDataSource(DataSourceName + "_Lines", currentDs.Lines));
viewer.LocalReport.SetParameters(param);
viewer.RefreshReport();
}
}
The problem is that sometimes it generates the rdlc report but others it just hangs the application. Specifically, it stays in viewer.RefreshReport(); forever.
The corresponding parameters and datasets are correctly set on the rdlc file.
Has anyone experienced a similar behavior?
Thanks in advance.
I suppose you have your viewer configured correctly.
Does the first time generation usually succeed? You could try calling viewer.Reset() after each report generation, that might solve some compounding issues.
There is a post from 2006 that on the surface appears to be relevant and might give you a workaround, although I have to admit I haven't done this myself because it would be almost impossible for me to recreate the problem you're seeing and so it would be equally impossible to see if any workaround would fix it. It's not ideal, but I'm hoping there no such thing as useless information :-)
The relevant info is at the bottom of the linked thread and for the sake of clarity, I've quoted it below.
The ReportViewer control is broken up into two components - the report objects (exposed as .ServerReport and .LocalReport) and the UI (the actual ReportViewer class). The report objects store all of the state about your report. The UI component simply calls into them to get the information it needs to display the report, parameter prompts, toolbar, etc.
The UI component is not thread-safe, just like most controls. But the report objects are thread safe. When you call RefreshReport, the viewer uses a background thread to call Render on the report object. But this is not the only time that the control calls into the report object. The first time it needs to compile the report definition (local report) or create a session (server report) can take a long time. If this "first time" is during RefreshReport, it will happen on the background thread. But as you have seen, it can happen at other times. Populating the parameters UI, for example, requires calling GetParameters, which also requires this startup penalty.
If you want to guarantee this "first time" penalty is on a background thread, then after setting the report path and other connection/data source information, call GetParameters from a background thread.
This seems to suggest that you make some calls to your ReportViewer always from a background thread rather than from the UI thread, so that any delays are not affecting the UI. It sounds like a bit of a bodged design to me though!
Is this of any help to you?
I may have fixed it. This page helped me figure it out: http://ikriv.com/dev/dotnet/MysteriousHang.html
So, it seems that a) report viewer needs to be created on the UI thread, and that b) that wasn't always happening reliably (see link for details). The report viewer is a .NET 2 component, and the behavior documented in the link applies to .NET 2.
To fix it, I employed the following tricks:
first trick: name the UI thread at start up
second trick: force a handle early on, then get a reference to the synchronization context
third trick: use the thread name and sync context to effect the invoke required -> invoke idiom.
If it all holds together, I will come back and post w/ more details.
I encountered the issue in Windows XP with .Net 4.0 and Report Viewer 2010. Yes the OS is end of support but Windows Embedded POSReady 2009 (Windows XP SP3), it's still in the extended support until April 2019.
To workaround the hang, call deprecated API to render the report
rptviewer.LocalReport.ExecuteReportInSandboxAppDomain();
and when exit or rerun the report e.g. report's parameters changed, the report need to clean up properly by
rptviewer.LocalReport.DataSources.Clear();
rptviewer.LocalReport.ReportEmbeddedResource = null;
rptviewer.LocalReport.Dispose();
// release sandbox is required to prevent the lock up, see below note on display report
rptviewer.LocalReport.ReleaseSandboxAppDomain();
// clean up report viewer
rptviewer.Clear();
rptviewer.Reset();
Note on Windows 7, 8, 8.1 and 10. The hang issue is not occurred.
Almost every tutorial I find tells me to do this for my event loop:
XEvent event;
while (true)
{
XNextEvent(display, &event);
switch (event.type)
{
case Expose:
printf("Expose\n");
break;
default:
break;
}
}
However, clicking the X to close the program results in this message.
XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
after 10 requests (10 known processed) with 0 events remaining.
It is indeed strange to me that the examples suggest using an infinite loop. That doesn't sound natural, and my other X11 programs don't do that. So I searched around. I found out how to capture the window close event.
Atom wmDeleteMessage = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wmDeleteMessage, 1);
XEvent event;
bool running = true;
while (running)
{
XNextEvent(display, &event);
switch (event.type)
{
case Expose:
printf("Expose\n");
break;
case ClientMessage:
if (event.xclient.data.l[0] == wmDeleteMessage)
running = false;
break;
default:
break;
}
}
That works. It exits without errors. ... But I refuse to believe this is the normal way to do things. I mean, is this the only way to properly exit an X11 app? It seems like a lot of work just to capture the close event. How do I make a 'proper' event loop? Why is the close event so deeply buried? What am I missing?
The problem lays in the communication between X Server and the Window Manager.
When you call XCreateWindow or XCreateSimpleWindow, the X Server creates your window (not showing it until you explicitly map it on the screen by calling XMapWindow), and then the Window Manager is responsible for attaching all the decorations and buttons and system menu around your window.
You can call XDestroyWindow on your own to remove the window, and this usually means it just disappears from the screen, but your program is still running and the connection to the X Server is still open, so you can send it some more requests.
The problem begins when the user clicks that little X button attached to your window by the Window Manager, because it is not created by the X Server and it is not his business to decide what to do then. Now it's all in hands of Window Manager.
If the Window Manager simply called XDestroyWindow on your window, it would cause a problem if your application wanted to capture the closing event to do something before the window gets destroyed. So the convention has been established between the X Server and the Window Managers to handle this process.
The default behavior of most Window Managers is to destroy the window and close the connection with the X server, because this is what most users of Window Managers would expect: that when they close the window, the program will end (and the connection to the X Server will close with the closed window). And then, when you try to call XCloseDisplay(display), it will cause the IO error you've mentioned, because the connection to the server is already closed and the display structure is invalid.
Here's an excerpt from the Xlib documentation which explains this:
Clients that choose not to include WM_DELETE_WINDOW in the WM_PROTOCOLS property may be disconnected from the server if the user asks for one of the client's top-level windows to be deleted.
Yeah, it would be great if they didn't hide it so deep in their docs, though :-P
But when you already find it, fortunately it also hints for the solution.
If you want a different behavior (that is, to capture the closing event from the Window Manager), you need to use the WM_DESTROY_WINDOW protocol.
Another excerpt from the docs:
Clients, usually those with multiple top-level windows, whose server connection must survive the deletion of some of their top-level windows, should include the atom WM_DELETE_WINDOW in the WM_PROTOCOLS property on each such window. They will receive a ClientMessage event as described above whose data[0] field is WM_DELETE_WINDOW.
I had the same error and I wanted to know exactly what causes it and why. It took me some time to figure it out and find the proper explanation in the doc, so I put my explanation here to save the time of others uninformed.
There are no such things as "exit button" or "application" or "close event" in X11. This is by design.
Window decorations, exit buttons and many the other things we depend upon are not built into X11. They are implemented on top of the core X11 instead. The name of the particular set of conventions responsible for wmDeleteMessage is ICCCM, look it up.
Xlib only deals with the core X11 protocol. No built-in close event there.
There are toolkits that make dealing with ICCCM and all other things that are not built into X11 easier (GTK, wxWindows, Qt, ...) You probably want to use one of those.
I'd like to intercept the WM_DELETE_WINDOW message that is posted to a certain selection of windows that an application I'm writing (AllTray), so that I can act on it instead of the application receiving it. I'm currently looking at trying this at the GDK level via gdk_display_add_client_message_filter if possible, but I'd be happy with an Xlib solution if there is one as well; it seems to be possible, but I just don't seem to be understanding how I am to do it successfully.
Currently, I have two programs (written in C) that I am trying to use to get this figured out, the first one does nothing but create a window and register that it knows about WM_DELETE_WINDOW, and the second one attempts to catch that message, but seems to fail in doing so; it appears to do precisely nothing. Am I understanding the documentation wrong on this, or is there something additional that I need to be doing (or do I need to avoid using GDK entirely for this)?
The background is this: Prior to my re-write of AllTray, the way it would do things appears to be to try to intercept a mouse-click on the X button itself. For some window managers, this worked properly, for others it didn't work at all, and for others, the user had to configure it manually and instruct AllTray where the button for closing the window was. What I am looking for is a solution that doesn't involve a LD_LIBRARY_PRELOAD and will work for any window manager/application combination that conforms to the current standards and sends a WM_DELETE_WINDOW ClientMessage when the window is closed.
UPDATE: I'm still looking for an answer. The route that I am taking at the moment is to try to reparent the window and manage it myself, but I just cannot make it work. Upon reparenting, I don't seem to be able to get it back in any way. I may be missing something very fundamental, but I can't figure out how to actually make it appear it my own window again, to bring it back on the screen.
UPDATE 2: Alright, so I've hit another brick wall. The X server documentation says to set the StructureNotifyMask on the window's event mask to receive both MapNotify and ReparentNotify events. I'd be interested in receiving either. My current thinking was to create a window that served just as an event receiver, and then when I get events for interesting things, act on them by creating and reparenting. However, this simply doesn't seem to be working. The only events I actually receive are PropertyNotify events. So, this route doesn't seem to be doing very much good, either.
I don't know X11, but I googled using "Intercept WM_DELETE_WINDOW X11" as keywords. Found 17k - MarkMail and Mplayer-commits r154 - trunk/libvo. In both cases they are doing the same thing.
/* This is used to intercept window closing requests. */
static Atom wm_delete_window;
within static void x11_init(),
XMapWindow(display, win);
wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, win, &wm_delete_window, 1);
then, within static int x11_check_events(),
XEvent Event;
while (XPending(display)) {
XNextEvent(display, &Event);
if (Event.type == ClientMessage) {
if ((Atom)Event.xclient.data.l[0] == wm_delete_window) {
/* your code here */
}
}
}
See XInternAtom, XSetWMProtocols and XNextEvent.
After I wrote the above, I found Handling window close in an X11 app:
When a user clicks the close button
[x] on our X11 application we want it
to pop a a dialog asking “do you
really want to quit?”. This is a plain
X app. No fancy GTK or QT widgets
here. So how to catch the “window is
being closed” message?
The answer is to tell the Window
Manager we are interested in these
event by calling XSetWMProtocols and
registering a WM_DELETE_WINDOW message
with it. Then we’ll get a client
message from the Window Manager if
someone tries to close the window, and
it won’t close it, it’ll leave that us
up to us. Here’s an example….
// example.cpp
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <iostream>
int main()
{
Display* display = XOpenDisplay(NULL);
Window window = XCreateSimpleWindow(display,
DefaultRootWindow(display),
0, 0,
500, 400,
0,
0, 0);
// register interest in the delete window message
Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(display, window, &wmDeleteMessage, 1);
std::cout << "Starting up..." << std::endl;
XMapWindow(display, window);
while (true) {
XEvent event;
XNextEvent(display, &event);
if (event.type == ClientMessage &&
event.xclient.data.l[0] == wmDeleteMessage) {
std::cout << "Shutting down now!!!" << std::endl;
break;
}
}
XCloseDisplay(display);
return 0;
}
Unfortunately, the best answer to this question is a series of non-answers; there are technically ways to accomplish it, but they all have downfalls that make them extremely impractical:
Create an X11 proxy for an application, passing all X11 protocol messages back and forth between the application and the X server. The proxy would then filter out any interesting messages. The downside to this is that this is an awful lot of overhead for a single little tiny feature, and the X11 protocol is complex. There could also be unintended consequences, which makes this an even more unattractive option.
Launch as a standard application that acts as an intermediary between the window manager and “interesting” client applications. This breaks some things, such as XDnD. In effect, it is not unlike the first option, except that the proxy is at the Window level as opposed to the X11 protocol level.
Use the non-portable LD_PRELOAD library trick. This has several downsides:
It is non-portable across dynamic linkers: not all dynamic linkers support LD_PRELOAD, even among UNIX-like systems.
It is non-portable across operating systems: not all operating systems support featureful dynamic linkers.
It breaks network-transparency: the shared object/dynamic link library must reside on the host as the child process that is being executed.
Not all X11 applications use Xlib; it would be necessary to write one LD_PRELOAD module for each of the libraries that an application might use to talk with X11.
In addition to the last point, not all applications would be susceptible to LD_PRELOAD even if they ran under a linker that supported it, because they may not use a shared object or DLL in order to communicate with X; consider, for example, a Java application which uses an X11 protocol library written in Java itself.
On some UNIX-like operating systems, LD_PRELOAD libraries must be setuid/setgid if they are to be used with setuid/setgid programs. This is, of course, a potential security vulnerability.
I am quite sure that are more downsides that I cannot think of.
Implement an extension to the X Window system. Non-portable among X11 implementations, complex and convoluted as all get out, and absolutely out of the question.
Implement extensions or plug-ins to window managers. There are as many window managers as there are opinions on window managers, and therefore this is utterly infeasible.
Ultimately, I was able to finally accomplish my goal by using a completely separate mechanism; anyone who is interested, please see the Close-to-Tray support in AllTray 0.7.5.1dev and later, including the git master branch available on github.
Ok, to elaborate on my earlier suggestion, you might want to investigate XEmbed. At the least, that might give you some ideas to try.
Failing that, I'd have a look at how other similar software might be working (e.g. wmdock, or how GtkPlug/GtkSocket is implemented), though I believe in both those cases explicit support is required in the applications.
Hope that is more helpful.
You should read ICCCM that tells you how window manager communicates with client. Most of WM will create a frame window to contain your top-level window via reparenting. Thus, if your reparent may break the relationship known by WM and your client window.