Updating the Z-Order of Many Windows Using Win32 API - windows

The scenario is that I have a list of window handles to top level windows and I want to shift them around so they are arranged in the z-order of my choosing. I started off by iterating the list (with the window I want to end up on top last), calling SetForegroundWindow on each one. This seemed to work some of the time but not always, improving a little when I paused slightly in between each call.
Is there a better way to do this?
Edit:
It looks like the BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos route is the way to go. However, I can't seem to get it to work with more than one window at a time. When I limit the window list to a single window, it works correctly. When the list has multiple windows, it only seems to get one of them. Here is pseudo code of what I'm doing:
HWND[] windows;
HWND lastWindowHandle = 0;
HDWP positionStructure = BeginDeferWindowPos(windows.length);
for (int i = 0; i < windows.length; i++)
{
positionStructure = DeferWindowPos(positionStructure, windows[i],
lastWindowHandle, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
EndDeferWindowPos(positionStructure);
I'm sure it's something small/obvious I'm missing here but I'm just not seeing it.

There is a special set of api's for setting window positions for multiple windows: BeginDeferWindowPos + DeferWindowPos + EndDeferWindowPos (SetWindowPos in a loop will also work of course, but it might have more flicker)

You can use SetWindowPos to order your top-level windows.
// Hypothetical function to get an array of handles to top-level windows
// sorted with the window that's supposed to be topmost at the end of array.
HWND* windows = GetTopLevelWindowsInOrder();
int numWindows = GetTopLevelWindowCount();
for(int i = 0; i < numWindows; ++i)
{
::SetWindowPos(windows[i], HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

Related

Getting the exact edit box dimensions for the given text

I need to be able to determine the size of the edit box according to the text I have, and a maximum width.
There are similar questions and answers, which suggest GetTextExtentPoint32 or DrawTextEx.
GetTextExtentPoint32 doesn't support multiline edit controls, so it doesn't fit.
DrawTextEx kind of works, but sometimes the edit box turns out to be larger than necessary, and, what's worse, sometimes it's too small.
Then there's EM_GETRECT and EM_GETMARGINS. I'm not sure whether I should use one of them, or maybe both.
What is the most accurate method for calculating the size? This stuff is more complicated then it should be... and I prefer not to resort to reading the source code of Wine or ReactOS.
Thanks.
Edit
Here's my code and a concrete example:
bool AutoSizeEditControl(CEdit window, LPCTSTR lpszString, int *pnWidth, int *pnHeight, int nMaxWidth = INT_MAX)
{
CFontHandle pEdtFont = window.GetFont();
if(!pEdtFont)
return false;
CClientDC oDC{ window };
CFontHandle pOldFont = oDC.SelectFont(pEdtFont);
CRect rc{ 0, 0, nMaxWidth, 0 };
oDC.DrawTextEx((LPTSTR)lpszString, -1, &rc, DT_CALCRECT | DT_EDITCONTROL | DT_WORDBREAK);
oDC.SelectFont(pOldFont);
::AdjustWindowRectEx(&rc, window.GetStyle(), (!(window.GetStyle() & WS_CHILD) && (window.GetMenu() != NULL)), window.GetExStyle());
UINT nLeftMargin, nRightMargin;
window.GetMargins(nLeftMargin, nRightMargin);
if(pnWidth)
*pnWidth = rc.Width() + nLeftMargin + nRightMargin;
if(pnHeight)
*pnHeight = rc.Height();
return true;
}
I call it with nMaxWidth = 143 and the following text (below), and get nHeight = 153, nWidth = 95. But the numbers are too small for the text to fit, on both axes.
The text (two lines):
Shopping
https://encrypted.google.com/search?q=winapi+resize+edit+control+to+text+size&source=lnms&tbm=shop&sa=X&ved=0ahUKEwiMyNaWxZjLAhUiLZoKHQcoDqUQ_AUICigE
Edit 2
I found out that the word wrapping algorithm of DrawTextEx and of the exit control are different. For example, the edit control wraps on ?, DrawTextEx doesn't. What can be done about it?

How to get inner and outer window dimensions with Xlib/XCB?

Is there a reliable way to get the inner and outer rectangle of a top
level window with XCB/Xlib? (IOW frame and client rectangle).
Here's what I tried:
xcb_get_geometry always returns the initial dimensions even after
the window gets resized (what gives?)
I figured I would call xcb_query_tree repeatedly until I find the
window's frame window - is this the way to do it? I figure ICCCM/EWMH
should provide this but couldn't find anything. Is there any other
standard/non-standard for this? Anyway that doesn't work with
compiz/ubuntu10 because xcb_query_tree reports the client window as
having root = parent (under normal ubuntu wm the window gets properly
reparented).
xcb_translate_coordinates() seemed to be the only reliable way to
get root-based coords[1] in 2007 -- is this still the case? I.e. is
XCB_CONFIGURE_NOTIFY non-standard with WMs?
[1] http://fixunix.com/xwindows/91652-finding-position-top-level-windows.html
This is a partial answer as it only explains how to find the inner dimensions of a window. Also I am not sure if this is the canonical way to go but it works for me.
You can subscribe to the XCB_EVENT_MASK_RESIZE_REDIRECT event when creating a window:
xcb_window_t window = xcb_generate_id (connection);
const xcb_setup_t *setup = xcb_get_setup (connection);
xcb_screen_t *screen = xcb_setup_roots_iterator (setup).data;
uint32_t mask = XCB_CW_EVENT_MASK;
uint32_t valwin[1] = { XCB_EVENT_MASK_EXPOSURE
| XCB_EVENT_MASK_RESIZE_REDIRECT };
xcb_create_window(
connection,
XCB_COPY_FROM_PARENT,
window,
screen->root,
0, 0,
800, 600,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
mask, valwin);
xcb_map_window(connection, window);
xcb_flush(connection);
In the event loop you can then keep track of resizes:
xcb_generic_event_t *event;
uint16_t width = 0, height = 0;
while ((event = xcb_wait_for_event(connection)) != NULL) {
switch (event->response_type & ~0x80) {
case XCB_EXPOSE: {
/* ... */
break;
}
case XCB_RESIZE_REQUEST: {
auto resize = (xcb_resize_request_event_t*) event;
if (resize->width > 0) width = resize->width;
if (resize->height > 0) height = resize->height;
break;
}
default:
break;
}
free(event);
xcb_flush(connection);
}
Note that I am not sure whether this event is emitted when you initiate the resize from your application code using xcb_configure_window for example. I never tested it and just update the width and height in a wrapper function for xcb_configure_window.

webcam, Video Source dialog comes up

So have seen a ton of people with the same issue's but no answers. My SendMessage pop's up the "Video Source" dialog box on a windows 7 laptop with one camera. I have Cyber Link YouCam installed.
If I uninstall Cyber Link YouCam the "Video Source" dialog goes away. It appears to be the OS is acting as though YouCam is a second driver for the same device. My question is how do I stop the dialog box for "Video Source" from appearing? Once I choose an option in the dialog I don't get the dialog box (until I restart the application) so there must be a setting somewhere being set.
Though debugging found this bit of code (see whole section below) is the one that seems to be the one that calls the dialog box - SendMessage (deviceHandle, WM_CAP_CONNECT, deviceno, ((IntPtr) 0).ToInt32 ())
public void StartWebCam (int height, int width, int handleofthepicturebox, int deviceno)
{
string deviceIndex = "" + deviceno;
deviceHandle = capCreateCaptureWindowA (ref deviceIndex, WS_VISIBLE | WS_CHILD, 0, 0, width, height, handleofthepicturebox, 0);
if (SendMessage (deviceHandle, WM_CAP_CONNECT, deviceno, ((IntPtr) 0).ToInt32 ()) > 0)
{
SendMessage (deviceHandle, WM_CAP_SET_SCALE, -1, 0);
SendMessage (deviceHandle, WM_CAP_SET_PREVIEWRATE, 0x42, 0);
SendMessage (deviceHandle, WM_CAP_SET_PREVIEW, -1, 0);
}
else
{
// nothing failed maybe some clean up needed
}
}
So again the question is - how do I stop the dialog box for "Video Source" from appearing?
I developed a form to display two live captures with avicap32 on Windows XP. There is a chance the fix I found in my case also applies to yours.
In the case of avicap, it is possible to programmatically manage your webcams, and all that is registry-based. Here is the thread I found to guide me and achieve what I wanted.
In this thread, the role of the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\MediaResources\msvideo\MSVideo.VFWWDM\DevicePath registry key is highlighted for the selection of the active webcam.
And here is maybe a helpful piece of info: I had to set the value in lowercase to avoid the Video Source dialog popping up.
I determined it by monitoring the registry key before and after the call to SendMessage with WM_CAP_CONNECT.
To the best of my knowledge (and googling), nobody else has offered a fix, so even though I might be answering a little late, it would be great if you could tell us whether it worked for you as well.
Finally I Found a solution for this.
The problem happens in Windows 7 / 8
First you need this API function
Private Declare Function GetTickCount Lib "kernel32" () As Long
Then... after you call capCreateCaptureWindowA() you have to wait 1 second processing events, (note: sleep don't work the same)
IniTime = GetTickCount()
While GetTickCount() < (IniTime + 1000)
DoEvents
Wend
then you call WM_CAP_DRIVER_CONNECT (maybe a couple of times).. and THAT's IT ... no more video source dialog
With this solution it works perfect. The GetTickCount() waiting for events worked along with calling the function until it returned true.
Private Sub PreviewVideo(ByVal pbCtrl As PictureBox)
hWnd = capCreateCaptureWindowA(VideoSource, WS_VISIBLE Or WS_CHILD, 0, 0, 0,
0, pbCtrl.Handle.ToInt64, 0)
Dim IniTime As Long = GetTickCount()
While GetTickCount() < (IniTime + 1000)
Application.DoEvents()
End While
Dim OKAnswer As Boolean = False
For xretries As Integer = 1 To 10
' I'll give you Only 10 tries to connect, otherwise I AM LEAVING MICROSOFT!
OKAnswer = SendMessage(hWnd, WM_CAP_DRIVER_CONNECT, VideoSource, 0)
If OKAnswer Then
Exit For
End If
Next
If okanswer Then
SendMessage(hWnd, WM_CAP_SET_SCALE, True, 0)
SendMessage(hWnd, WM_CAP_SET_PREVIEWRATE, 30, 0)
SendMessage(hWnd, WM_CAP_SET_PREVIEW, True, 0)
SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, pbCtrl.Width, pbCtrl.Height, SWP_NOMOVE Or SWP_NOZORDER)
Else
DestroyWindow(hWnd)
End If
End Sub
I had the same issue. Make sure you call capDriverDisconnect once you no longer need the webcam. Note that I'm using Logitech C110, but I suppose it should work in your case too.
Came over here searching for a solution for the "WM_CAP_DRIVER_CONNECT" and "Video Setup" dialog popup Error.
FOUND the solution:
It's a driver problem. Use the OEM's driver, because the Generic Microsoft Drivers are NOT working for your camera.
Use www.astra32.com to find out the USB camera's device info: Manufacturer or Model; then google for the correct drivers.
Good Luck!

ExtCreatePen and Windows 7 GDI

I created DIBPATTERN pens with ExtCreatePen API for custom pattern pens.
It sucessfully draws desired lines on Windows XP,
But on Windows 7 (x64 for my case), it does not draw any lines; no changes on screen.
(Other simply created pens, for example CreatePen(PS_DOT,1,0), are working.)
I found that calling SetROP2(hdc, R2_XORPEN) makes the following line-drawing API calls draw something but with XOR operation. I don't want XOR drawing.
Here is my code to create the pen. It has no problem on Windows XP:
LOGBRUSH lb;
lb.lbStyle = BS_DIBPATTERN;
lb.lbColor = DIB_RGB_COLORS;
int cb = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2 + 8*4;
HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, cb);
BITMAPINFO* pbmi = (BITMAPINFO*) GlobalLock(hg);
ZeroMemory(pbmi, cb);
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = 8;
pbmi->bmiHeader.biHeight = 8;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 1;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 8;
pbmi->bmiHeader.biClrUsed = 2;
pbmi->bmiHeader.biClrImportant = 2;
pbmi->bmiColors[1].rgbBlue =
pbmi->bmiColors[1].rgbGreen =
pbmi->bmiColors[1].rgbRed = 0xFF;
DWORD* p = (DWORD*) &pbmi->bmiColors[2];
for(int k=0; k<8; k++) *p++ = patterns[k];
GlobalUnlock(hg);
lb.lbHatch = (LONG) hg;
s_aSelectionPens[i] = ExtCreatePen(PS_GEOMETRIC, 1, &lb, 0, NULL);
ASSERT(s_aSelectionPens[i]); // success on both XP and Win7
GlobalFree(hg);
Is it bug only on my PC? Please check this problem.
Thank you.
This is a known bug with the Windows 7 GDI, though good luck getting Microsoft to acknowledge it.
http://social.technet.microsoft.com/Forums/en-US/w7itproappcompat/thread/a70ab0d5-e404-4e5e-b510-892b0094caa3
-Noel
I will admit, I was dubious as first, but I compiled and ran your program, and it does indeed fail to draw the second line on Windows 7, buy only in aero mode
By switching to Windows basic or classic mode, all four lines are drawn, as expected.
I can only assume that this is some kind of bad interaction with your custom pen and the new way aero mode implements GDI calls. This seems like it might be a Microsoft bug, perhaps you can post this question on one of their message boards?
So you are creating an 8x8 black/white (monochrome) bitmap as a DIB, and then using that to create a pen. I see nothing wrong with this code. this definitely looks like a windows bug, but there may be a workaround.
Try setting
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
In this context, setting the values to 0 should mean the same thing as setting them to 2, but 0 is more standard behavior for situations where you have are using the full palette. You still need two entries in your palette, 0 just means "full size based on biBitCount".
Also, each palette entrie is a RGBQUAD, which means there is room for alpha, and your alpha is set to 0, which should be ignored, but maybe it isn't. so try setting the high byte of your two palette entries to 0xFF or 0x80.
Finally, it's possible that your palette is being ignored entirely, and Windows is using the BkMode, BkColor and TextColor of the destination DC for everything, so you need to make sure that they are set to values that you can see.
My guess is that this has something to do with alpha transparency, since GDI ignores alpha entirely, but Aero doesn't.

Capturing a Window that is hidden or minimized

I followed this tutorial (there's a bit more than what's listed here because in my code I get a window via mouse click) for grabbing a window as a bitmap and then rendering that bitmap in a different window.
My question:
When that window is minimized or hidden (SW_HIDE) my screen capture doesn't work, so is it possible to capture a window when it is minimized or hidden?
The PrintWindow api works well, I use it for capturing thumbnails for hidden windows. Despite the name, it is different than WM_PRINT and WM_PRINTCLIENT, it works with pretty much every window except for Direct X / WPF windows.
I added some code (C#) but after reviewing how I used the code, I realized that the window isn't actually hidden when I capture its bitmap, its just off screen so this may not work for your case. Could you show the window off screen, do a print and then hide it again?
public static Bitmap PrintWindow(IntPtr hwnd)
{
RECT rc;
WinUserApi.GetWindowRect(hwnd, out rc);
Bitmap bmp = new Bitmap(rc.Width, rc.Height, PixelFormat.Format32bppArgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
bool succeeded = WinUserApi.PrintWindow(hwnd, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
if (!succeeded)
{
gfxBmp.FillRectangle(new SolidBrush(Color.Gray), new Rectangle(Point.Empty, bmp.Size));
}
IntPtr hRgn = WinGdiApi.CreateRectRgn(0, 0, 0, 0);
WinUserApi.GetWindowRgn(hwnd, hRgn);
Region region = Region.FromHrgn(hRgn);
if (!region.IsEmpty(gfxBmp))
{
gfxBmp.ExcludeClip(region);
gfxBmp.Clear(Color.Transparent);
}
gfxBmp.Dispose();
return bmp;
}
There are WM_PRINT and WM_PRINTCLIENT messages you can send to the window, which cause its contents to be rendered into the HDC of your choice.
However, these aren't perfect: while the standard Win32 controls handle these correctly, any custom controls in the app might not.
I am trying to get the bitmap of partially hidden controls.
I used code before that did the drawing, but included windows overlapping it. So.. maybe you want to try this.
The WM_PRINTCLIENT should (in my understanding) redraw all inside the control, even if it is not really visible.
const int WM_PRINT = 0x317, WM_PRINTCLIENT = 0x318, PRF_CLIENT = 4,
PRF_CHILDREN = 0x10, PRF_NON_CLIENT = 2,
COMBINED_PRINTFLAGS = PRF_CLIENT | PRF_CHILDREN | PRF_NON_CLIENT;
SendMessage(handle, WM_PRINTCLIENT, (int)hdc, COMBINED_PRINTFLAGS);
//GDIStuff.BitBlt(hdc, 0, 0, width, height, hdcControl, 0, 0, (int)GDIStuff.TernaryRasterOperations.SRCCOPY);
The before code is commented out now. It is based on the code found here: Pocket PC: Draw control to bitmap (accepted answer). It is basically the same as Tim Robinson suggests in this thread.
Also, have a look here
http://www.tcx.be/blog/2004/paint-control-onto-graphics/

Resources