Setting a child window under Progman window to show video ender desktop icon - c++

I'm trying to make a function similar to the wallpaper engine, by adding a child window to the Progman window. The function did allow me to add the video, however, the window size is fixed, which made me unable to fit the video to the entire desktop.
I tried to change the window size, but neither MoveWindow nor SetWindowPos worked. The Progman's hwnd Rect is just screen size (1920x1080), so it's not a boundary issue. The video window size is 640x480. I'm able to change the location of the window, meaning no permission issue, just can't change the size of it.
Here is the code.
LPCWSTR lpParam = L" videoTest2.mp4 -noborder -fs -loop 0";
STARTUPINFO si{ 0 };
PROCESS_INFORMATION pi{ 0 };
if (CreateProcess(L"ffplay.exe", (LPWSTR)lpParam, 0, 0, 0, 0, 0, 0, &si, &pi)) {
Sleep(200);
HWND hProgram = FindWindow(_T("Progman"), _T("Program Manager"));
HWND hFfplay = FindWindow(L"SDL_app", 0);
SetParent(hFfplay, hProgram);
// MoveWindow(hFfplay, 0, 0, 3840, 1080, true);
SetWindowPos(hFfplay, NULL, 0, 0, 3840, 1080, SWP_NOZORDER);
ShowWindow(hFfplay, SW_MAXIMIZE);
EnumWindows(EnumWindowProc, (LPARAM)SW_HIDE);
Sleep(1000);
EnumWindows(EnumWindowProc, (LPARAM)SW_SHOW);
}
else {
std::cout << GetLastError() << std::endl;
}
EnumWindowProc is just for showing and hiding system background images.

Related

Capturing a specific window using BitBlt return the black or transparent border which represent the classic gui layer

I tried to capture a screenshot of specific window using BitBlt and save it to clipboard, but it returns the screenshot with the content inside window border only while the window border itself is remain transparent or blacked out with many weird behaviors.
The expected result should be the full window border with the full content:
This is the actual result:
This is what I tried:
Comment the SetLayeredWindowAttributes function before performing BitBlt but the result is the entire black screenshot.
Tried to set the delay after UpdateWindow function but the weird border remains the same.
Disabling some coded option but it didn't help...
Use PrintWindow but the result is the classic gui border, which is not the intended goal (and many article indicate about the problem with this function).
I don't have any idea why this happened nor able to find out due to lack of information of this command when searching Internet.
Is there anything wrong with my code?
void QuickScreenshot()
{
HWND windowHandle(::FindWindowW(0, L"Internet Download Manager 6.41"));
ANIMATIONINFO AnimationInfo{};
SystemParametersInfoW(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, NULL);
auto DefaultAnimationInfo(AnimationInfo);
AnimationInfo.iMinAnimate = 0;
DefaultAnimationInfo.cbSize = sizeof(ANIMATIONINFO);
SystemParametersInfoW(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &AnimationInfo, WM_SETTINGCHANGE);
auto originalExstyle(GetWindowLongW(windowHandle, GWL_EXSTYLE));
SetWindowLongW(windowHandle, GWL_EXSTYLE, WS_EX_LAYERED);
COLORREF windowColor;
BYTE windowAlpha, customAlpha(1);
DWORD flag;
WINDOWPLACEMENT windowState{};
windowState.length = sizeof(WINDOWPLACEMENT);
GetLayeredWindowAttributes(windowHandle, &windowColor, &windowAlpha, &flag);
SetLayeredWindowAttributes(windowHandle, windowColor, customAlpha, flag);
GetWindowPlacement(windowHandle, &windowState);
if (windowState.showCmd == SW_SHOWMINIMIZED)
{
if ((windowState.flags & WPF_RESTORETOMAXIMIZED) == WPF_RESTORETOMAXIMIZED)
{
ShowWindow(windowHandle, SW_MAXIMIZE);
}
else
{
ShowWindow(windowHandle, SW_SHOWNORMAL);
}
}
else
{
ShowWindow(windowHandle, windowState.showCmd);
}
RECT windowRectangleCoordinates;
GetWindowRect(windowHandle, &windowRectangleCoordinates);
InvalidateRect(windowHandle, &windowRectangleCoordinates, TRUE);
UpdateWindow(windowHandle);
Sleep(100);
HDC ScreenContentHandle(GetWindowDC(windowHandle));
HDC DestinationContentHandle(CreateCompatibleDC(ScreenContentHandle));
auto cx(windowRectangleCoordinates.right - windowRectangleCoordinates.left);
auto cy(windowRectangleCoordinates.bottom - windowRectangleCoordinates.top);
HBITMAP BitmapHandle(CreateCompatibleBitmap(ScreenContentHandle, cx, cy));
HGDIOBJ oldObject(SelectObject(DestinationContentHandle, BitmapHandle));
//PrintWindow(windowHandle, ScreenContentHandle, NULL);
BitBlt
(
DestinationContentHandle,
0, 0, cx, cy,
ScreenContentHandle,
0, 0,
SRCCOPY | CAPTUREBLT
);
SaveToClipboard(BitmapHandle);
SelectObject(DestinationContentHandle, oldObject);
DeleteDC(DestinationContentHandle));
ReleaseDC(NULL, ScreenContentHandle));
DeleteObject(BitmapHandle));
ShowWindow(windowHandle, SW_MINIMIZE);
SetLayeredWindowAttributes(windowHandle, windowColor, windowAlpha, flag);
SetWindowLongW(windowHandle, GWL_EXSTYLE, originalExstyle);
SystemParametersInfoW(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &DefaultAnimationInfo, WM_SETTINGCHANGE);
}

Resize cursor is showing on the border of a fixed dialog frame

It is a bit difficult to provide you with a minimal working example here but I am going to try and explain this issue that I have only just noticed.
The Context
So, I have a regular CDialogEx derived class, defined like this:
class CChristianLifeMinistryStudentsDlg : public CDialogEx
I have set it up so that the borders will not resize:
The main application (also CDialogEx based) has a fixed window. That behaves correct.
From the menu the user displays a resizable dialogue (an editor).
On this dialog is a button the user can press which will in turn display the popup modal dialog I am referring to.
What Happens
When this dialog is displayed I have noticed this when you hover the mouse over the dialog borders:
I don't understand why this is happening.
Cursor Management
In the "editor" that spawns this popup window I do have some cursor management like this:
BOOL CChristianLifeMinistryEditorDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (CPersistentWaitCursor::WaitCursorShown())
{
RestoreWaitCursor();
return TRUE;
}
return CDialogEx::OnSetCursor(pWnd, nHitTest, message);
}
But, I have tried temporarily to invoke this popup from my main application dialog which does not have an cursor management and the result is still the same.
Spy Results
As requested I have just used Spy to examine the window styles:
As anticipated we suddenly have WS_THICKFRAME set, when it was not in the resource editor!
So
In my RC file the dialog has the DS_MODALFRAME flag set but at runtime it ends up having the WS_THICKFRAME set. As far as I am aware I never make these changes for these affected dialog objects.
Update
I have found out the following:
BOOL CChristianLifeMinistryStudentsDlg::OnInitDialog()
{
LONG_PTR lStyle = GetWindowLongPtr(GetSafeHwnd(), GWL_STYLE);
if (lStyle & WS_THICKFRAME)
AfxMessageBox(_T("Thick"));
else if (lStyle & DS_MODALFRAME)
AfxMessageBox(_T("Modal"));
CDialogEx::OnInitDialog();
If I put the check code before the CDialogEx::OnInitDialog(); call the style is set as DS_MODALFRAME. But if I put the same check code after the CDialogEx::OnInitDialog(); call it is then changed to WS_THICKFRAME. Why?
OK
So, the CDialogEx::OnInitDialog method calls CWnd::LoadDynamicLayoutResource(LPCTSTR lpszResourceName). This in turn calls CWnd::InitDynamicLayout(). And in that method it does this:
if (!bIsChild && (pDialog != NULL || pPropSheet != NULL))
{
CRect rect;
GetClientRect(&rect);
ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
::AdjustWindowRectEx(&rect, GetStyle(), ::IsMenu(GetMenu()->GetSafeHmenu()), GetExStyle());
SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
}
There we go. So it is because I am using CDialogEx as my base class. Is this a bug in MFC?
Clarification
The "Editor" (parent window of the popup that owns the button) does use dynamic layout functonality:
But in this instance the popup does not need to. But it is because my popup is derived from CDialogEx that this is happening.
The plot thickens
So this is the MFC code that is always called with CDialog::OnInitDialog:
BOOL CWnd::LoadDynamicLayoutResource(LPCTSTR lpszResourceName)
{
if (GetSafeHwnd() == NULL || !::IsWindow(GetSafeHwnd()) || lpszResourceName == NULL)
{
return FALSE;
}
// find resource handle
DWORD dwSize = 0;
LPVOID lpResource = NULL;
HGLOBAL hResource = NULL;
if (lpszResourceName != NULL)
{
HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_DIALOG_LAYOUT);
HRSRC hDlgLayout = ::FindResource(hInst, lpszResourceName, RT_DIALOG_LAYOUT);
if (hDlgLayout != NULL)
{
// load it
dwSize = SizeofResource(hInst, hDlgLayout);
hResource = LoadResource(hInst, hDlgLayout);
if (hResource == NULL)
return FALSE;
// lock it
lpResource = LockResource(hResource);
ASSERT(lpResource != NULL);
}
}
// Use lpResource
BOOL bResult = CMFCDynamicLayout::LoadResource(this, lpResource, dwSize);
// cleanup
if (lpResource != NULL && hResource != NULL)
{
UnlockResource(hResource);
FreeResource(hResource);
}
if (bResult)
{
InitDynamicLayout();
}
return bResult;
}
For some reason this call BOOL bResult = CMFCDynamicLayout::LoadResource(this, lpResource, dwSize); is return TRUE. As a result the dialog eventually calls InitDynamicLayout. In my other dialogs that are popups this does not happen. Instead, bResult ends up as FALSE and thus the frame is not resized.
So why does it think it worked?
Worked it out. I don't remember doing this but for some reason some of my controls on the dialog had dynamic properties set. For example:
I had to set all of these properties back to None. Then it behaved.
You can easily tell if a given dialog resource has any dynamic properties by opening your resource file in a text editor. For example:
IDD_DIALOG_OUR_CHRISTIAN_LIFE_AND_MINISTRY_MATERIAL AFX_DIALOG_LAYOUT
BEGIN
0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 10, 0,
0, 0, 0, 0,
50, 0, 0, 0,
50, 0, 0, 0,
0, 0, 0, 0,
0, 0, 10, 0,
0, 0, 0, 0,
50, 0, 0, 0,
50, 0, 0, 0,
0, 0, 0, 0,
0, 0, 10, 0,
0, 0, 0, 0,
50, 0, 0, 0,
50, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
END
If something like the above is present then your dialog will be deemed as having a dynamic layout, and thus the settings for the dialog are modified:
ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
The resource will look like this when it has no dynamic control properties:
IDD_DIALOG_OUR_CHRISTIAN_LIFE_AND_MINISTRY_MATERIAL AFX_DIALOG_LAYOUT
BEGIN
0
END
I chose to manually reset each control via the IDE. However, I guess you could modify the text file manually.
As to why I had controls with dynamic properties in the first place, well, I can't tell you. I might have been fiddling in the past with the dialog and not realised the side effect to the border frame. Or, possibly, I may have copied controls from one resource on to another and it carried the dyanmic values.
The interesing side note is that whilst the MFC code set the border as thick, it did not change it sufficiently to enable dialog resizing. But that is another matter!
At least we now know the cause of the issue and how to easily identify the dialogs in the resource that have dynamic layouts.

how to change the position of the child window inside the parent window and show the toolbar?

I have the following code which passes a window handler form OpenCV window to win32 handler, therefore I can show the grabbed images from camera to the screen and the images will show as a child window of my main API.
but the problem is that when I want to add a tooldbar to my program, the image window handler comes at the top of the toolbar. how can I sort this out?
//create a window and set the handler from openCV to win32
cv::namedWindow("test",cv::WINDOW_AUTOSIZE);
hWnd2 = (HWND) cvGetWindowHandle("test");
hParent = ::GetParent(hWnd2);
::SetParent(hWnd2, hWnd);
::ShowWindow(hParent, SW_HIDE);
_liveCapturing=true;
lastPicNr = 0;
SetWindowTextW(hStatus, L"Live Capturing ... ");
if(FullScreen()){
::ShowWindow(hWnd, SW_MAXIMIZE);
}
code for the toolbar :
HWND CreateToolbar(HWND hwnd){
HWND hTbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | CCS_TOP , 0, 0, 0, 0, hwnd, (HMENU)12, GetModuleHandle(NULL), NULL);
SendMessage(hTbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
TBBUTTON tbb[3];
TBADDBITMAP tbab;
tbab.hInst = HINST_COMMCTRL;
tbab.nID = IDB_STD_SMALL_COLOR;
SendMessage(hTbar, TB_ADDBITMAP, 0, (LPARAM)&tbab);
return hTbar;
}
Probably you have found the solution a long time ago, but i want to post my anwers in case other users need it.
You can simply add the OpenCV window with the same code you have to a child window in your window (which you set it position in advance). For example you can add it to a static text window (label) ...
If you want to move the OpenCV window, call SetWindowPos() with the desired coordinates.
SetWindowPos(hWnd2, 0, 0, 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER);

how to stretch a background image in win32 using visual studio c

I'm trying to create an application in Win32 api with c++ and I want to make it FullScreen without any bar , i succeeded but i still have a problem in the background image. The image is repeated but i want it to be stretched. Have you any idea?
below part from the code :
int WINAPI WinMain (HINSTANCE cetteInstance, HINSTANCE precedenteInstance,
LPSTR lignesDeCommande, int modeDAffichage)
{
HWND fenetrePrincipale;
MSG message;
WNDCLASS classeFenetre;
instance = cetteInstance;
classeFenetre.style = 0;
classeFenetre.lpfnWndProc = procedureFenetrePrincipale;
classeFenetre.cbClsExtra = 0;
classeFenetre.cbWndExtra = 0;
classeFenetre.hInstance = NULL;
classeFenetre.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
classeFenetre.hCursor = LoadCursor(NULL, IDC_ARROW);
// classeFenetre.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
//classeFenetre.hbrBackground = CreatePatternBrush(LoadBitmap( instance, MAKEINTRESOURCE("images\Image1.bmp" ) ) );
HBITMAP hbmp = LoadBitmap(instance,MAKEINTRESOURCE(IDB_BITMAP1));
if(NULL == hbmp)
{
MessageBox(NULL,L"BitMap Loading Failed.",L"Error",MB_ICONEXCLAMATION | MB_OK);
}
else
{
HBRUSH hbr = CreatePatternBrush(hbmp);
if(NULL == hbr)
{
MessageBox(NULL,L"Brush Creation Failed.",L"Error",MB_ICONEXCLAMATION | MB_OK);
}
else
{
//StretchBlt();
HDC hdcMem = GetDC (NULL) ;
HDC wndHDC = GetDC (fenetrePrincipale) ;
StretchBlt(hdcMem, 0, 0, 800, 600, wndHDC, 0, 0, 1280, 1024, SRCCOPY);
classeFenetre.hbrBackground = hbr ;
}
}
classeFenetre.lpszMenuName = NULL;
classeFenetre.lpszClassName = L"classeF";
//fullscreen mode and delete minimize and max buttons
// On prévoit quand même le cas où ça échoue
if(!RegisterClass(&classeFenetre)) return FALSE;
//WS_OVERLAPPEDWINDOW
fenetrePrincipale = CreateWindow(L"classeF", L"Ma premiere fenetre winAPI !",WS_MAXIMIZE|WS_POPUP ,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 630,
NULL,
NULL,//LoadMenu(instance, L"ID_MENU"),
cetteInstance,
NULL);
if (!fenetrePrincipale) return FALSE;
//ShowWindow(fenetrePrincipale, modeDAffichage);
ShowWindow(fenetrePrincipale,SW_MAXIMIZE);
UpdateWindow(fenetrePrincipale);
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
return message.wParam;
}
thanks
You haven't shown the exact code, but it appears that you load a bitmap, create a brush from it, and then set that brush as the brush for your window. Brushes would indeed lead to the repeating-image behavior you report. To get a stretched bitmap, you may skip any brush-related code. Instead, handle the WM_ERASEBKGND message sent to your window. In it, call StretchBlt to paint your bitmap onto the client area of your window. The HDC to paint to is given in the message's wParam argument.
Steps
1, CreateWindowEx to create the window
2, SetWindowPos to place your window on top of all windows and Fullscreen
3, On your windows's WindowProce handle WM_PAINT message
4, Load your bitmap
5, Create a memory dc using CreateCompatibleDC
6, Selet your bitmap into memory dc by calling SelectObject
7, Do the StretchBlt to your actual dc, using the prepared memory dc as the source, you should know the actual width and height of the bitmap for proper stretching

Can't change position of button

In a C++ app I create a button using CreateWindowEx and later try to change its position using SetWindowPos, but the button doesn't appear where I want it.
What's interesting is that when I resize the window (with the mouse, not programatically), I can see for a split second a blank silhouette the same size of the button where the button is supposed to appear. This must be because I also call SetWindowPos in response to window resizing events. However the actual button stays at the same location. I'd post a screenshot but for some reason the silhouette never shows up in screenshots.
This is the code that changes the X position (the code that changes the Y position is almost identical):
HRESULT Control::put_Left(float left)
{
RECT windowRect;
::GetWindowRect(m_hWnd, &windowRect);
if (m_isTopLevel)
{
BOOL bResult = ::SetWindowPos(
m_hWnd,
nullptr,
static_cast<int>(DesktopDpi::GetInstance().DipsToPixelsX(left)),
windowRect.top,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOREPOSITION
);
if (!bResult)
return HRESULT_FROM_WIN32(::GetLastError());
}
else
{
// NOTE: for a button this is the code that will execute, because a
// button is not a top-level window
HWND hWndParent = ::GetParent(m_hWnd);
if (hWndParent == nullptr)
return HRESULT_FROM_WIN32(::GetLastError());
POINT parentPos = {0, 0};
if (!::ClientToScreen(hWndParent, &parentPos))
return E_FAIL;
BOOL bResult = ::SetWindowPos(
m_hWnd,
nullptr,
static_cast<int>(DesktopDpi::GetInstance().DipsToPixelsX(left)),
windowRect.top - parentPos.y,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOREPOSITION
);
if (!bResult)
return HRESULT_FROM_WIN32(::GetLastError());
}
return S_OK;
}
Are you sure the parent of the button isn't moving it back to the old position when it handles WM_SIZE? It sure sounds like it from your description.