how to stretch a background image in win32 using visual studio c - 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

Related

Why can't i set a thumbnail on the Taskbar using DwmSetIconicThumbnail?

I need your help for a project at my job.
The main software, using 4D language, works as a MDI, it creates many windows included in the main window. The main issue is that we have a lot of windows and we need an easy way to switch from a window to another.
We decided to create a little c++ plugin which is a dll to resolve this issue.
This plugin will create a tab on the taskbar for each window opened like Windows Explorer. The creation and the deletion of tabs already works.
But the current problem is that no thumbnail is set on the Tab.
The parameter given is the ID of the window from the main software. The method called PA_GetHWND is the method given by 4D to obtain the handle of the window using the windowID.
I have already check where is the problem. The bitmap created from the window already exists and is good. For this test, i put the bitmap in the clipboard and paste it on Paint and the Bitmap was good.
Here is the code introducing the method to refresh the bitmap on the tab.
bool CManageTaskBar::UpdateWindow(long WindowID)
{
HRESULT res;
HDC hdcScreen;
HDC hdcWindow;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;
//Get the Handle from 4D
HWND nHandle = (HWND)(PA_GetHWND((PA_WindowRef)(WindowID)));
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = GetDC(NULL);
hdcWindow = GetDC(nHandle);
// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcWindow);
// Get the client area for size calculation
RECT rcClient;
GetClientRect(nHandle, &rcClient);
// Create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcWindow,rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC, hbmScreen);
// Bit block transfer into our compatible memory DC.
if (!BitBlt(hdcMemDC,
0, 0,
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
hdcWindow,
0, 0,
SRCCOPY))
{
MessageBox(nHandle, L"BitBlt has failed", L"Failed", MB_OK);
//goto done;
}
ITaskbarList3* ptbl = NULL;
HRESULT hr = CoCreateInstance(my_CLSID_TaskbarList, NULL, CLSCTX_ALL, my_IID_ITaskbarList3, (LPVOID*)&ptbl);
BOOL fForceIconic = TRUE;
BOOL fHasIconic = TRUE;
res = DwmSetWindowAttribute(nHandle, DWMWA_FORCE_ICONIC_REPRESENTATION, &fForceIconic, sizeof(fForceIconic));
res = DwmSetWindowAttribute(nHandle, DWMWA_HAS_ICONIC_BITMAP, &fHasIconic, sizeof(fHasIconic));
if (hbmScreen)
{
res = DwmSetIconicThumbnail(nHandle, hbmScreen,0);//DWM_SIT_DISPLAYFRAME);
}
DeleteObject(hbmScreen);
DeleteObject(hdcMemDC);
ReleaseDC(NULL, hdcScreen);
ReleaseDC(nHandle, hdcWindow);
return true;
}
The calls to DwmSetWindowAttribute return Invalid Handle. This handle works to get a bitmap but not to set an attribute.
And the call to DwmSetIconicThumbnail returns E_INVALIDARG maybe because the handle given is wrong.
Why cannot I set an attribute to this handle and why the call to set the thumbnail returns E_INVALIDARG ?
Thanks to everyone who will take care of my problem.
It's my first question, be friendly please :)

in direct2d drawing dimensions change after window resizing

I am a beginner, and I have made a program in direct2d using c++ in visual studio 2015, just a very basic program that draws a white square on a black background , and it does show the square in a small window. But the problem is that if the user maximizes that window the vertical dimension of the drawing becomes elongated and the square becomes rectangle.
This is the screenshot of the window before maximizing it:
enter image description here
And this is the screenshot of the window after maximizing it:
enter image description here
What am I doing wrong ?
here is my code and thanks in advance:
ID2D1HwndRenderTarget* pRT = NULL;
ID2D1Factory* pD2DFactory = NULL;
ID2D1SolidColorBrush* pBlackBrush = NULL;
ID2D1SolidColorBrush* pRedBrush = NULL;
HRESULT hr;
RECT rc;
POINT pt;
void draw(){
pRT->BeginDraw();
pRT->FillRectangle( D2D1::RectF((FLOAT)rc.left,
(FLOAT)rc.top,(FLOAT)rc.right, (FLOAT)rc.bottom),pBlackBrush);
pRT->FillRectangle( D2D1::RectF((FLOAT)pt.x,
(FLOAT)pt.y,pt.x + 50.0f ,pt.y + 50.0f),pRedBrush);
hr = pRT->EndDraw();
}
int APIENTRY wWinMain(/* wWinMain parameters */){
/*
...
window making
...
*/
hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,&pD2DFactory );
// Obtain the size of the drawing area.
GetClientRect(hWnd, &rc);
// Create a Direct2D render target
hr =pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hWnd,D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)
),
&pRT
);
if (SUCCEEDED(hr)){
pRT->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::White),
&pRedBrush
);
pRT->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
);
}
pt.x = 0;
pt.y = 0;
while (1) {
PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE);
if (msg.message == WM_QUIT) break;
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
draw();
}
}
It seems like you don't resize the render target when your window resizes. I expect you run into similar problems not just from maximizing, but when you resize your window too? See https://learn.microsoft.com/en-us/windows/desktop/LearnWin32/dpi-and-device-independent-pixels#resizing-the-render-target.
Code snippet from the linked document:
void Resize()
{
if (pRenderTarget != NULL)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
pRenderTarget->Resize(size);
InvalidateRect(m_hwnd, NULL, FALSE);
}
}
You'll want to call this by catching WM_SIZE.

SelectObject returns NULL with hbitmap created in constructor

I have a bitmap class that has a load function for loading the bitmap from either file path or resource ID. This part works fine.
void GtBitmap::Load()
{
LPTSTR szFileName;
szFileName = (LPTSTR)m_strPath.c_str();
// Check for valid .BMP file path
if (m_strPath.size() > 0)
{
// Open .BMP file
m_pFile = fopen(m_strPath.c_str(), ("rb"));
if (m_pFile != NULL)
{
m_hBitmap = (HBITMAP)LoadImage (GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_SHARED | LR_LOADFROMFILE);
GetObject(m_hBitmap, sizeof(m_bmap), &m_bmap);
int i = 1;
}
}
else if (m_intResourceID != 0)
{
m_hBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(m_intResourceID), IMAGE_BITMAP, 0, 0, LR_SHARED);
GetObject(m_hBitmap, sizeof(m_bmap), &m_bmap);
int i = 1;
}
}
However, when I try to render it in my code block, the SelectObject returns null. Here is the code for that section of the painter class.
void GtPainterGDI::GtDrawBitmap(GtRectI & target, GtBitmap & bitmap, bool blnOffset)
{
GtCanvas topCv = m_arrCanvas.back();
HDC hdcMem = CreateCompatibleDC(topCv.m_hdcParent);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, bitmap.m_hBitmap);
DWORD lastError = GetLastError();
bool success = BitBlt(hdcMem, target.GetLeft(), target.GetTop(),
target.Width(), target.Height(), hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, bitmap.m_hBitmap);
DeleteDC(hdcMem);
};
The SelectObject() returns null and the image is not drawn. I can only get the image to show up if I use a LoadImage() in that paint function. However I don't want to load the image every time I want to paint. I should be able to load the image once in the Load function or constructor of the bitmap, then use the handle in the paint function.
If anyone could please provide an example of loading an image in a constructor and then painting it elsewhere in the codes WM_PAINT or equivalent painting function I would appreciate it. The code is a new version of the GT graphical user interface library. I plan on posting a new version on codeproject in the next few days or so. I have to do some cleanup first...
Thanks in advance.
HINSTANCE parameter in LoadImage should be NULL when loading the image from file. Use GetModuleHandle(NULL) only when loading from resource.
m_hBitmap = (HBITMAP)LoadImage(NULL, m_strPath.c_str(),
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!m_hBitmap)
{
//report error
}
Also LR_SHARED is not necessary here.
When testing for file's exist, you can use std::ifstream. Example:
#include <fstream>
...
bool test = std::ifstream(m_strPath).good();
This will test for file and close the file handle right away.
Make sure to select hbmOld before deleting hdcMem:
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, bitmap.m_hBitmap);
BitBlt(...)
//SelectObject(hdcMem, bitmap.m_hBitmap); <<= remove this
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);

DrawIconEx leaving mask artifacts

I'm extracting jumbo icons for any given path using IImageList and SHGetFileInfo. Once I have that, I then render the HICON into a HBITMAP using DrawIconEx for eventual rendering with GDI+ Bitmap and Graphics objects.
Now, this all works great, except that when I do the final rendering of the bitmap, the very left edge always has a black artifact on it. This is true for pretty much any icon I get, and is always the left edge.
Any ideas where the dark line could be coming from?
The code I'm using is roughly:
1. Extract Icon:
// Get the image list index of the icon
SHFILEINFO sfi;
if (!SHGetFileInfo(pszPath, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX)) return NULL;
// Get the jumbo image list
IImageList *piml;
if (FAILED(SHGetImageList(SHIL_JUMBO, IID_PPV_ARGS(&piml)))) return NULL;
// Extract an icon
HICON hicon;
piml->GetIcon(sfi.iIcon, ILD_SCALE|ILD_TRANSPARENT, &hicon);
return hicon;
2. Generate Bitmap
HDC hDC = GetDC(NULL);
HDC hMemDC = CreateCompatibleDC(hDC);
HBITMAP hMemBmp = CreateCompatibleBitmap(hDC, x, y);
HBITMAP hResultBmp = NULL;
HGDIOBJ hOrgBMP = SelectObject(hMemDC, hMemBmp);
HBRUSH hbr = CreateSolidBrush(bg);
RECT rr = { 0, 0, 256, 256 }; // jumbo icons
FillRect(hMemDC, &rr, hbr);
DeleteBrush(hbr);
DrawIconEx(hMemDC, 0, 0, hicon, size, size, 0, NULL, DI_NORMAL);
hResultBmp = hMemBmp;
hMemBmp = NULL;
SelectObject(hMemDC, hOrgBMP);
return hResultBitmap;
3. Render GDI+ Bitmap to "window bitmap":
Bitmap *b = ::New Bitmap(hResultBitmap, NULL);
Graphics graphics(hdc);
graphics.SetTextRenderingHint(TextRenderingHintClearTypeGridFit);
SolidBrush bgbrush(Color(255, 255, 255, 255));
Rect r(0, 0, hwnd_w, hwnd_h);
graphics.FillRectangle(&bgbrush, r);
graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
Rect r(5, 5, 128, 128);
graphics.DrawImage(dpd->image_to_draw, r);
Wow, I spent another while last night playing with it. It's the ILD_SCALE in IImageList::GetIcon.
Get rid of that and it all works perfectly fine again. Go figure …
1. Extract Icon:
// Get the image list index of the icon
SHFILEINFO sfi;
if (!SHGetFileInfo(pszPath, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX)) return NULL;
// Get the jumbo image list
IImageList *piml;
if (FAILED(SHGetImageList(SHIL_JUMBO, IID_PPV_ARGS(&piml)))) return NULL;
// Extract an icon
HICON hicon;
piml->GetIcon(sfi.iIcon, ILD_TRANSPARENT, &hicon);
return hicon;

Render to Desktop

I want to be able to render a thing as if it was a wallpaper. I use Windows, and I prefer DirectX. I know that VLC can render the video has a wallpaper in DirectX mode, so it's possible.
So, a quick question, How could I set the rendertarget to render like if it was a wallpaper in Windows?
Here is some code which will get you a handle (HWND) to a window that can be used to draw over top of the windows Desktop. The main issue with how this works is that the desktop icons are still present but this will allow you to draw over top of them. If you want the icons to appear as normal (with your stuff behind them) you need to redraw them after you've drawn your stuff, or find a way to avoid drawing over them in the first place. This is fairly non-trivial and something I never completely solved.
This definitely works on XP and Windows 7 (with Areo) for getting something that normal GDI drawing can use. I've never tested it with DirectX but I suspect it would work if you used hMainWnd as your presentation window.
HWND hProgMan = NULL;
HWND hShell = NULL;
HWND hMainWnd = NULL;
unsigned int ScreenWidth = 0;
unsigned int ScreenHeight = 0;
int ScreenTop = 0;
int ScreenLeft = 0;
HRGN ValidRGN = NULL;
// ...
ScreenWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN);
if ( ScreenWidth == 0 )
ScreenWidth = GetSystemMetrics( SM_CXSCREEN );
ScreenHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN);
if ( ScreenHeight == 0 )
ScreenHeight = GetSystemMetrics(SM_CYSCREEN);
ScreenTop = GetSystemMetrics(SM_YVIRTUALSCREEN);
ScreenLeft = GetSystemMetrics(SM_XVIRTUALSCREEN);
ValidRGN = CreateRectRgn(0,0,ScreenWidth,ScreenHeight);
hProgMan = FindWindow("Progman", "Program Manager");
if(hProgMan != NULL)
{
hShell = FindWindowEx(hProgMan, 0, "SHELLDLL_DefView", NULL);
}
else
{
hProgMan = FindWindow("DesktopBackgroundClass", NULL);
if(hProgMan != NULL)
hShell = FindWindowEx(hProgMan, 0, "DeskFolder", NULL);
}
hMainWnd = CreateWindowEx( WS_EX_TRANSPARENT, "MyWindowClass", "Window Title", WS_CHILDWINDOW | WS_OVERLAPPED | WS_CLIPCHILDREN, 0,0,ScreenWidth,ScreenHeight, hShell,NULL,hInstance,NULL );
EnableWindow(hMainWnd,FALSE);
SetWindowPos(hMainWnd,HWND_BOTTOM,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
... and then for drawing (using GDI), something like this...
HDC hDC = GetDC( hMainWnd );
SelectClipRgn(hDC,ValidRGN);
BitBlt( hDC, 0, 0, ScreenX, ScreenY, hBackBuffer, 0, 0, SRCCOPY );
ReleaseDC( hMainWnd, hDC );
... and update ValidRGN with the regions of the Desktop icons. Those can be found with a bit of work with the Desktop's listview control window. That is fairly complicated and maybe off topic for this question.