I'm making an SDL2 application to draw on a separate processes window. The process doesn't use SDL but I can get the HWND of the process window. Is it possible to get an SDL_Window from the HWND?
It's as simple as:
SDL_Window *window = SDL_CreateWindowFrom(my_hwnd);
But as noted in comments, rendering into such window may or may not work properly.
Related
I have a window which serves as an overlay, and only has some part of it non-transparent. The window has extended styles
WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED
And the transparency is set with:
SetLayeredWindowAttributes(hwnd, RGB(255, 255, 255), 0, LWA_COLORKEY);
I do want to read the mouse events to implement the interactive part of the overlay.
So far i tried catching messages like
WM_MOUSEMOVE,
WM_KEYDOWN,
WM_NCLBUTTONDOWN,
in my WNDPROC and there they didn't fire. I assumed that was due to some of the window extended styles, and by removing one at a time i found out that it was layered window attribute which caused it. Sadly my app does depend on this attribute for its transparency.
Then i tried registering a windows hook for that very process and thread to intercept the mouse events. I don't know the internals of hooks at all - but i thought they get access to the messages before they enter the application's queue hence i hoped i could read them before whatever interferes passes them on. That didn't work sadly.
I registered the hook like so:
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetCurrentThreadId();
And the actual HOOKPROC was defined like this:
pub unsafe extern "system" fn HOOKPROC(ncode: c_int, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
println!("fired!");
CallNextHookEx(null_mut(), ncode, wparam, lparam)
}
Sadly this didn't output anything to STDOUT, but I do think that hook was registered as unhook function didn't return 0.
My next idea was to put the hook in the process which manages the previous window. However the below doesn't work.
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetWindowThreadProcessId(
GetWindow(hwnd, GW_HWNDPREV), null_mut())
);
I think that it's due to the fact that i need to place the hook in a separate dll but event if it does work - this solution seem to be very dirty and will probably work in very few cases without requiring elevated privileges. What can i do to achieve the desired via accepted and cohesive code?
Just get rid of the WS_EX_TRANSPARENT style and use WS_EX_LAYERED by itself, and let the OS handle mouse input normally (no hook needed). Fully transparent pixels will fall-through as expected, and the window will receive input messages on non-transparent pixels.
I've tried to draw any thing on Desktop window using GetDC(GetDesktopWindow), like the following simple program:
#include <windows.h>
int main()
{
TextOut(GetDC(GetDesktopWindow()), 10, 10, TEXT("Test TextOut Tester!!"), 21);
return 0;
}
It seems that my current user privileges affect the drawing behavior, I am not admin on my PC, is this the reason for that? is there any documentation for this issue ?
Thanks in advance
The simple reason you can't draw on the desktop window like this is you cannot actually see the desktop window. Since Windows 95 the desktop window has been completely obscured by a cluster of windows owned by explorer.
The DC you get when you call GetDC(GetDesktopWindow()) will thus be completely clipped.
If you want to draw directly on the display GetDC(NULL) will give you a DC that you can use to draw all over the desktop and visible windows. But that, as has been mentioned, will be operating entirely outside Windows' repainting logic and the results will be, well, ugly and unsuited to any real purpose (other than, say, getting some kind of debug feedback from a windowless app you are in the process of developing).
Most applications that want do "display something on the desktop" do so by creating a window and drawing on that. Why is that not appropriate here?
This is what you should do:
HDC hdc = ::GetDC(NULL);
//draw on the desktop using the hdc
::ReleaseDC(NULL, hdc);
I'm writing a small Windows application in Visual C++ without MVC. Its really small, it just contains one textfield, an OK-Button and an Cancel-Button.
The application is started by a background-process when user starts printing. When opening the application doesn't get focus, isn't even visible.
For the user it's importend that the application is directly in focus, so they have as lease clicks as possible to use it.
I tried many many things to get the application in focus:
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(hWnd);
ShowWindow(hWnd, SW_RESTORE);
SetFocus(hWnd);
I even repeated this calls in a timer. All of this doesn't work. Now I found some remarks on MSDN:
The system restricts which processes can set the foreground window. A
process can set the foreground window only if one of the following
conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
Anybody knows a workaround for this?
There is no workaround for this. The whole point of this new Windows behavior is to prevent applications from bringing themselves to the foreground on their own and being a nuisance. In your case, I would suggest using a notification icon and showing a balloon message when necessary instead of a window. However, even in this case your notification icon can be hidden by the user and there is no workaround, for the same reason as above.
Now, this is coming from a Java developer and not a Visual C++ developer, but can you maybe set the frame/window/whatever-its-called-in-visual-c to be always on top? In Java, if you have a JFrame, say myJFrame, you can call myJFrame.setAlwaysOnTop(true) and it stays on top of all other windows. This seems to be a simple workaround to your problem, however it may not be desirable for the user if it's blocking something of theirs on screen.
http://www.thescarms.com/vbasic/alttab.aspx seems to do the job
void forceToFront(HWND hWnd) {
HWND foregroundWindow = GetForegroundWindow();
if (foregroundWindow == hWnd) {
// Window is already Foreground-window
return;
}
if (SetForegroundWindow(hWnd)) {
// could set window to foreground without any tricks
return;
}
// attach thread of foreground-window to this window
DWORD foregroundThread = GetWindowThreadProcessId(foregroundWindow, NULL);
DWORD myThread = GetWindowThreadProcessId(hWnd, NULL);
AttachThreadInput(foregroundThread, myThread, true);
SetForegroundWindow(hWnd);
AttachThreadInput(foregroundThread, myThread, false);
}
I have an non read only edit control for which I need to change colors so I handle WM_CTLCOLOREDIT. It works well when I am typing continuously but the problem is when I hit backspace or delete or even start typing from the middle of an existing text, the display is all junked up. That remains untill I cause a repaint by resizing the parent etc. How to fix this?
Edit: Some detail. The problem seems only when the background color is set and not when just the text color is set. The code looks like this
ON_MESSAGE(WM_CTLCOLOREDIT, OnEditColor)
LRESULT CMyWindow::OnEditColor(WPARAM wp, LPARAM lp)
{
HDC hdc = (HDC)wp;
HWND hwnd = (HWND)lp;
if(hwnd == m_edit.GetSafeHwnd())
{
// SetBkMode(hdc, TRANSPARENT);
MyControlInfo*pcti;// accessed from somewhere
SetTextColor(hdc, pcti->theme.clrText);
// return (LRESULT)pcti->brush.GetSafeHandle();
}
return 0;
}
Thanks
I rather doubt that this is caused by this code. It is the kind of problem you get when you try to subclass the edit control and override painting. Windows version 2 having to run on a 386SUX and 20 years of appcompat prevented Microsoft from fixing this control so it only draws itself in the WM_PAINT message handler. It indeed draws directly to the screen when you backspace. There's no workaround for it.
Same comment applies as in your previous question, use a real edit control.
You should set a background color with SetBkColor (And don't use SetBkMode) and return a valid brush. (You don't know how the control does its painting, it is free to use ExtTextOut with ETO_OPAQUE etc)
http://msdn.microsoft.com/en-us/library/bb761691(v=vs.85).aspx
Return Value
If an application processes this
message, it must return the handle of
a brush. The system uses the brush to
paint the background of the edit
control.
So try something like:
return static_cast<LRESULT>(::GetSysColorBrush(COLOR_WINDOW));
How can I get the icon of a running application provided I know the Hwnd?
If you have the handle to the window, you can use GetClassLong:
HICON icon = (HICON)GetClassLong(window, GCL_HICON);
I you have the hwnd you can get the process ID by using the WINAPI GetWindowThreadProcessId.
With that you can create a C# Process object. Next, you can iterate through the process' ProcessModule Collection to get the filename of the executable. Finally, you can use the WINAPI function ExtractIconEx to get the icon from the path
Pinvoke has information on the two WINAPI methods
http://www.pinvoke.net/default.aspx/user32/GetWindowThreadProcessId.html
http://www.pinvoke.net/default.aspx/shell32/ExtractIconEx.html