How to use DwmRegisterThumbnail with child windows? - c++

I'm 'casting' the screen of window1 to window2 using the WINAPI DwmRegisterThumbnail
but as soon I set the window2 child of another window the image disappears.
After reading the docs I found this mention:
Setting the destination window handle to anything other than a
top-level window type will result in a return value of E_INVALIDARG.
HWND dest = (HWND)this->winId();
HWND source = ...
hr = DwmRegisterThumbnail(dest, source, &thumbnail_id);
DWORD err = GetLastError();
qDebug() << "hr: " << hr;
if (SUCCEEDED(hr) && NULL != thumbnail_id)
{
prop.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_RECTSOURCE | DWM_TNP_OPACITY
| DWM_TNP_VISIBLE | DWM_TNP_SOURCECLIENTAREAONLY;
prop.rcSource = { 0, 0, 1200, 600 };
prop.rcDestination = { 0, 0, 1200, 600 };
prop.opacity = 255;
prop.fVisible = TRUE;
prop.fSourceClientAreaOnly = FALSE;
hr = DwmUpdateThumbnailProperties(thumbnail_id, &prop);
qDebug() << "hr: " << hr;
}
I also tried using a QDockWidget but the image is visible only when the widget is not docked to the MainWindow, as soon I dock the widget, the image disappears, sad.
There's something else I could try to be able to 'cast' the image to a child window?
or maybe another winapi I could use?

Related

How can I get icon of Windows app in CPP?

I'm trying to build an File Manager with in Win32, and I have a problem with the icons. Whenever I trying to get icon that an windows 10 app is associated with it like .png (Photos app), the icon is blank paper. What I'm doing wrong? Thanks in advance and please answer :)
BOOL InitTreeViewImageLists(HWND hwndTV) {
HIMAGELIST himl; // handle to image list
HBITMAP hbmp; // handle to bitmap
// Create the image list.
if ((himl = ImageList_Create(16,
16,
ILC_COLOR16 | ILC_MASK,
3, 0)) == NULL)
return FALSE;
// Add the open file, closed file, and document bitmaps.
HICON hIcon;
SHFILEINFO sfi;
LPCWSTR path = L"C:\\Users\\Shalev\\Desktop\\WhatsApp.lnk";
sfi = GetShellInfo(path);
HICON* iconHandles = new HICON;
hIcon = sfi.hIcon;
cout << hIcon << endl;
g_nOpen = sfi.iIcon;
ImageList_AddIcon(himl, hIcon);
sfi = GetShellInfo(L"C:\\");
hIcon = sfi.hIcon;
g_nClosed = sfi.iIcon;
ImageList_AddIcon(himl, hIcon);
sfi = GetShellInfo(L"C:\\");
hIcon = sfi.hIcon;
g_nDocument = sfi.iIcon;
ImageList_AddIcon(himl, hIcon);
// Associate the image list with the tree-view control.
TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL);
return TRUE;
}
SHFILEINFO GetShellInfo(LPCWSTR path) {
SHFILEINFO sfi;
SecureZeroMemory(&sfi, sizeof(sfi));
SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SHELLICONSIZE | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
return sfi;
}
You can use the IShellItemImageFactory interface, something like this:
...
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // need this somewhere when your thread begins, not for every call
...
IShellItemImageFactory* factory;
if (SUCCEEDED(SHCreateItemFromParsingName(path, nullptr, IID_PPV_ARGS(&factory))))
{
// the GetImage method defines a required size and multiple flags
// with which you can specify you want the icon only or the thumbnail, etc.
HBITMAP bmp;
if (SUCCEEDED(factory->GetImage(SIZE{ 256, 256 }, SIIGBF_ICONONLY, &bmp)))
{
... // do something with the HBITMAP
DeleteObject(bmp);
}
factory->Release();
}
...
CoUninitialize(); // call this each time you successfully called CoInitializeEx

How change resolution and update window without flickering

I need to change the resolution different times and keep update the windows.
Actually I use this code:
bool SetDiplayResolution(int Width, int Height, int Refresh = 0)
{
LONG Outout;
DEVMODE desiredMode;
memset(&desiredMode, 0, sizeof(desiredMode));
desiredMode.dmSize = sizeof(desiredMode);
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &desiredMode) != 0)
{
desiredMode.dmSize = sizeof(DEVMODE);
desiredMode.dmPelsWidth = Width;
desiredMode.dmPelsHeight = Height;
if (Refresh > 0)
{
desiredMode.dmDisplayFrequency = Refresh;
desiredMode.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH | DM_DISPLAYFREQUENCY;
}
else
{
desiredMode.dmFields = DM_PELSHEIGHT | DM_PELSWIDTH;
}
Outout = ChangeDisplaySettings(&desiredMode, 0);
}
return Outout;
}
void myfunction
{
HWND hWnd = GetActiveWindow();
SetDiplayResolution(1920, 1080);
SetWindowPos(hWnd, 0, 0, 0, 1920, 1080, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
UpdateWindow(hWnd);
}
This code work fine but unfortunatenly the transaction beetween the old and new resolution produce some very short, but visble annoyng effects:
Temporary presence of the windows bar.
The screen flash for one instant.
I don't known if exist a way to solve. I have seen in some forum that other create a secondary top most window in order to avoid these side effects and then destroy this secondary window.
I don't sure if this is a good way.
Unfortunatenly I don't have access to window events becouse my is a dll (I have not create the window, but I have the handle).
Can you please help me ?
Thanks !

SetWindowPos() cross-process DPI aware

I am creating a program that moves/resizes windows from another process with SetWindowPos(). My own program is PROCESS_PER_MONITOR_DPI_AWARE. The other programs could be anything from PROCESS_DPI_UNAWARE, PROCESS_SYSTEM_DPI_AWARE or PROCESS_PER_MONITOR_DPI_AWARE.
Because my own program is PROCESS_PER_MONITOR_DPI_AWARE, the coordinates I pass to SetWindowPos() are in physical coordinates. What I now want to do is resize the client area to a specific size in logical coordinates.
What I have tried to do is
Get the DPI of the monitor where the window is placed as screenDPI.
Get the DPI of the target window as windowDPI.
Get scaleFactor as screenDPI / windowDPI.
Scale the desired client area size by scaleFactor
Calculated the extra size for the window frame by subtracting the current client rect size from the window rect size.
This works for the most part, but when I am using two screens with different display scaling, then
the calculation of the window frame size is off if I move the window from one screen to the next.
this fails for an application that uses PROCESS_SYSTEM_DPI_AWARE, when the window is located on the secondary screen (which uses 96dpi compared to the primary screen with 120dpi). This has nothing to do with the window frame size and I am not yet sure why exactly it fails, but the target x and y coordinates are scaled up so that the window is moved offscreen.
what happens if, because of the resize, the center of the window changes the screen? Then the screenDPI will no longer be correct, right? How would I handle that case?
I know that there is also the function AdjustWindowRectExForDpi, but somehow I can't get it to work properly. What is the dpi value I am supposed to pass to it? The dpi of the target screen, the dpi of the target window or the dpi of my own program? Additionally, this function is only available from Windows 10 onwards, so how would I handle it on an older Windows client?
I would appreciate some help with this. Thanks!
What is the dpi value I am supposed to pass to it? The dpi of the target screen, the dpi of the target window or the dpi of my own program?
The DPI of the window you need to move from one screen to the next.
code sample:
#include <Windows.h>
LRESULT CALLBACK startup_window_procedure(HWND window, UINT message, WPARAM w_param, LPARAM l_param)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_DPICHANGED:
{
// Resize the window
RECT* new_rect = reinterpret_cast<RECT*>(l_param);
if (!SetWindowPos(window, nullptr, new_rect->left, new_rect->top, new_rect->right - new_rect->left, new_rect->bottom - new_rect->top, SWP_NOZORDER | SWP_NOACTIVATE))
{
return 1;
}
return 0;
}
}
return DefWindowProcW(window, message, w_param, l_param);
}
int CALLBACK wWinMain(HINSTANCE instance, HINSTANCE prev_instance, PWSTR cmd_line, int cmd_show)
{
constexpr auto window_class_name = L"example_dialog";
constexpr auto window_style = WS_OVERLAPPEDWINDOW;
// Enable per-monitor DPI-awareness version 2
if (!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2))
{
return 1;
}
// Create the window
WNDCLASSEXW window_class;
window_class.cbSize = sizeof(window_class);
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpfnWndProc = startup_window_procedure;
window_class.cbClsExtra = 0;
window_class.cbWndExtra = 0;
window_class.hInstance = instance;
window_class.hIcon = nullptr;
window_class.hCursor = nullptr;
window_class.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
window_class.lpszMenuName = nullptr;
window_class.lpszClassName = window_class_name;
window_class.hIconSm = nullptr;
if (!RegisterClassExW(&window_class))
{
return 1;
}
HWND window = CreateWindowExW(0, window_class_name, L"Example window", window_style, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, nullptr, nullptr, instance, nullptr);
if (!window)
{
return 1;
}
UINT dpi = GetDpiForWindow(window);
float scaling_factor = static_cast<float>(dpi) / 96;
// Actually set the appropriate window size
RECT scale;
scale.left = 0;
scale.top = 0;
scale.right = static_cast<LONG>(300 * scaling_factor);
scale.bottom = static_cast<LONG>(150 * scaling_factor);
if (!AdjustWindowRectExForDpi(&scale, window_style, false, 0, dpi))
{
return 1;
}
if (!SetWindowPos(window, nullptr, 0, 0, scale.right - scale.left, scale.bottom - scale.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE))
{
return 1;
}
ShowWindow(window, SW_SHOWNORMAL);
// Message loop
MSG message;
int result;
while ((result = GetMessageW(&message, nullptr, 0, 0)) != 0)
{
if (result == -1)
{
return 1;
}
else
{
TranslateMessage(&message);
DispatchMessageW(&message);
}
}
return static_cast<int>(message.wParam);
}
The windows can move from one screen to the next and recalculate window size successfully.

HtmlHelp MS API search string

Does any one in 2017 knows how to implement calling HtmlHelp function that will open .chm file with "Search" pane and query string in it's listbox and will be able to execute this query?
I try following:
HH_FTS_QUERY query;
query.cbStruct = sizeof(HH_FTS_QUERY);
query.fUniCodeStrings = TRUE;
query.pszSearchQuery = szSearchStr;
query.iProximity = HH_FTS_DEFAULT_PROXIMITY;
query.fStemmedSearch = TRUE;
query.fTitleOnly = TRUE;
query.fExecute = TRUE;
query.pszWindow = NULL;
HWND hHelpWnd = ::HtmlHelp(m_hWnd, szFile, HH_DISPLAY_SEARCH, (DWORD_PTR)&query);
but the query in query.pszSearchQuery won't be executed. I have opened .chm file with query.pszSearchQuery in "Search" pane's listbox on my screen, but I have to click "List Topics" myself to show results of search.
With the help of HTMLHelp API - VBA, VB6 and VB2003, i will try to reply.
I believe there no API function to list topics in vc++. You have send button click event to launched help window.
LRESULT OnSearch(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
TCHAR szBuf[128];
GetDlgItem(IDC_EDIT1).GetWindowText(szBuf, sizeof(szBuf));
if (!_tcslen(szBuf))
return 0;
//
// First, invoke HtmlHelp with HH_DISPLAY_SEARCH.
// It doesn't execute search, but it's need for showing 'search' tab.
//
HH_FTS_QUERY fq;
ZeroMemory(&fq, sizeof(fq));
fq.cbStruct = sizeof(fq);
fq.fUniCodeStrings = FALSE;
fq.pszSearchQuery = (LPCTSTR)szBuf;
fq.iProximity = HH_FTS_DEFAULT_PROXIMITY;
fq.fStemmedSearch = FALSE;
fq.fTitleOnly = FALSE;
fq.fExecute = FALSE;
fq.pszWindow = NULL;
HWND hwndHelp = ::HtmlHelp(NULL, _T("realplay.chm"), HH_DISPLAY_SEARCH, (DWORD)&fq);
//
// Find query combobox and set query text.
//
HWND hPaneWnd, hPaneLast, hTabWnd, hDlgWnd, hCtlWnd;
hPaneWnd = FindWindowEx(hwndHelp, NULL, _T("HH Child"), NULL);
for (;;) // last HH Child
{
hPaneLast = FindWindowEx(hwndHelp, hPaneWnd, _T("HH Child"), NULL); // last HH Child
if (!hPaneLast)
break;
hPaneWnd = hPaneLast;
}
ATLTRACE("hPaneWnd == %x", hPaneWnd);
hCtlWnd = FindWindowEx(hPaneWnd, NULL, _T("Button"), NULL); // skip Tab Control
//
// There are two types of interfaces:
//
// 1.
// Window hierarchy:
// + Main window
// + HH Child
// + Browser ...
// + HH Child <- second "HH Child" window
// - Edit <- we have to fill this edit
// - Buttons <- and press this buttons
// ...
if (hCtlWnd)
{
hCtlWnd = FindWindowEx(hPaneWnd, NULL, _T("Edit"), NULL); // skip Tab Control
// Set window text
ATLASSERT(hCtlWnd != NULL);
::SendMessage(hCtlWnd, WM_SETTEXT, 0, (LPARAM)szBuf); // fill it by our query
::SendMessage(hwndHelp, WM_COMMAND, 0xbc7, 0); // 0x3ee -- 'List Topics' button, it runs search
if (::SendMessage(GetDlgItem(IDC_CHECK1), BM_GETCHECK, 0, 0) == BST_CHECKED)
::SendMessage(hwndHelp, WM_COMMAND, 0xbbe, 0); // 0x3f1 -- 'Display' button, it shows first item
}
//2.
// Window hierarchy:
// + Main window
// + HH Child
// + Browser ...
// + HH Child <- second "HH Child" window
// + Tab Control
// + Dialog
// - Combobox <- we have to fill this combo
// - Buttons <- and press this buttons
// ...
else
{
hTabWnd = FindWindowEx(hPaneWnd, NULL, _T("SysTabControl32"), NULL); // skip Tab Control
hDlgWnd = FindWindowEx(hTabWnd, NULL, NULL, NULL); // skip dialog
TCHAR szClass[64];
GetClassName(hDlgWnd, szClass, sizeof(szClass));
ATLTRACE("hDlgWnd(1) == %x", hDlgWnd);
if (!_tcsstr(szClass, "#")) // Is it dialog?
hDlgWnd = FindWindowEx(hTabWnd, hDlgWnd, NULL, NULL); // skip dialog
hCtlWnd = FindWindowEx(hDlgWnd, NULL, _T("ComboBox"), NULL); // well, it's combobox
// Set window text
ATLASSERT(hCtlWnd != NULL);
::SendMessage(hCtlWnd, WM_SETTEXT, 0, (LPARAM)szBuf); // fill it by our query
//
// Run search and show first finded page
//
::SendMessage(hwndHelp, WM_COMMAND, 0x3ee, 0); // 0x3ee -- 'List Topics' button, it runs search
if (::SendMessage(GetDlgItem(IDC_CHECK1), BM_GETCHECK, 0, 0) == BST_CHECKED)
::SendMessage(hwndHelp, WM_COMMAND, 0x3f1, 0); // 0x3f1 -- 'Display' button, it shows first item
}
return 0;
}
EDIT:
You can get control ID of List Topic by spy++

OpenGL context creation never chooses pixel format

I'm trying to create an OpenGL context inside a Win32 window for a library I'm writing. I've boiled it down to a small example which will compile to help debug it. For some reason, it never chooses a pixel format properly. Here's the code:
#include <iostream>
#include <windows.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/wglew.h>
HWND handle;
HDC deviceContext;
HGLRC context;
int resolutionX = 1280;
int resolutionY = 720;
std::string title = "Test Window";
LRESULT CALLBACK eventCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int main()
{
// Register the window class
WNDCLASSA windowClass;
windowClass.style = 0;
windowClass.lpfnWndProc = &eventCallback;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = GetModuleHandle(nullptr);
windowClass.hIcon = nullptr;
windowClass.hCursor = nullptr;
windowClass.hbrBackground = nullptr;
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = "Test_Window";
RegisterClassA(&windowClass);
// Compute position and size
HDC screenDC = GetDC(nullptr);
int left = (GetDeviceCaps(screenDC, HORZRES) - static_cast<int>(resolutionX)) / 2;
int top = (GetDeviceCaps(screenDC, VERTRES) - static_cast<int>(resolutionY)) / 2;
int width = resolutionX;
int height = resolutionY;
ReleaseDC(nullptr, screenDC);
// Set window style
DWORD win32Style = WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_SYSMENU;
// In windowed mode, adjust width and height so that window will have the requested client area
RECT rectangle = {0, 0, width, height};
AdjustWindowRect(&rectangle, win32Style, false);
width = rectangle.right - rectangle.left;
height = rectangle.bottom - rectangle.top;
// Create the window
handle = CreateWindowA("Test_Window", title.c_str(), win32Style, left, top, width, height, NULL, NULL, GetModuleHandle(nullptr), nullptr);
if(handle == NULL)
{
std::cout << "Failed to create window" << std::endl;
return 1;
}
// Setup a pixel format descriptor from the rendering settings
PIXELFORMATDESCRIPTOR descriptor;
ZeroMemory(&descriptor, sizeof(descriptor));
descriptor.nSize = sizeof(descriptor);
descriptor.nVersion = 1;
descriptor.iLayerType = PFD_MAIN_PLANE;
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
descriptor.iPixelType = PFD_TYPE_RGBA;
descriptor.cColorBits = static_cast<BYTE>(32);
descriptor.cDepthBits = static_cast<BYTE>(24);
descriptor.cStencilBits = static_cast<BYTE>(8);
descriptor.cAlphaBits = 8;
// Get the pixel format that best matches our requirements
int bestFormat = ChoosePixelFormat(deviceContext, &descriptor);
if(bestFormat == 0)
{
std::cout << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << std::endl;
return 1;
}
// Extract the depth and stencil bits from the chosen format
PIXELFORMATDESCRIPTOR actualFormat;
actualFormat.nSize = sizeof(actualFormat);
actualFormat.nVersion = 1;
DescribePixelFormat(deviceContext, bestFormat, sizeof(actualFormat), &actualFormat);
// Set the chosen pixel format
if(!SetPixelFormat(deviceContext, bestFormat, &actualFormat))
{
std::cout << "Failed to set pixel format for device context -- cannot create OpenGL context" << std::endl;
return 1;
}
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(wglGetProcAddress("wglCreateContextAttribsARB"));
if(wglCreateContextAttribsARB)
{
int attributes[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, static_cast<int>(3),
WGL_CONTEXT_MINOR_VERSION_ARB, static_cast<int>(0),
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, 0
};
context = wglCreateContextAttribsARB(deviceContext, nullptr, attributes);
}
if(!context)
{
context = wglCreateContext(deviceContext);
if(!context)
{
std::cout << "Failed to create the OpenGL context" << std::endl;
return 1;
}
}
// Destroy the OpenGL context
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(context);
// Destroy the device context
ReleaseDC(handle, deviceContext);
// Destroy the window handle
DestroyWindow(handle);
// Unregister the window
UnregisterClassA("Test_Window", GetModuleHandle(nullptr));
std::cout << "Window created" << std::endl;
return 0;
}
LRESULT CALLBACK eventCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// Associate handle and Window instance when the creation message is received
if(message == WM_CREATE)
{
LONG_PTR window = (LONG_PTR)reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams;
// Set as the "user data" parameter of the window
SetWindowLongPtr(hwnd, GWLP_USERDATA, window);
}
return DefWindowProcA(hwnd, message, wParam, lParam);
}
You never initialize deviceContext, which means that it will have a garbage value. If you call GetLastError after trying ChoosePixelFormat, I imagine that you'll find that it's telling you that you have an invalid handle.
wglGetProcAddress needs a valid OpenGL context being created and bound to yield a sensible result. Which means that in order to use wglCreateContextAttribsARB you first have to create an intermediary helper OpenGL context that gives you access to that function.
Update
As it happens I recently wrote some small helper to deal with this. Available under the terms of the MIT license at https://github.com/datenwolf/wglarb
Try to add this on the initialization of pixel format descriptor:
descriptor.cRedBits = 8;
descriptor.cGreenBits = 8;
descriptor.cBlueBits = 8;