I am having a hard time finding out how to load my .bmp image into the background.
Here is my code:
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreatePatternBrush(LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1)));
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
Though the problem is not entirely code related. I simply have a file x.bmp, and I have the IDB_BITMAP1 defined in my resource.rc file and included with an identifier in resource.h -- but when I run it I just get a white screen. The question here is, how can I upload my .bmp image to the .rc file? I am using MSVS20124. When I right click the .rc file add>bitmap>import...>x.bmp I get an error "could not load file". Why is this? I just want to set that x.bmp as the background in my window.
thanks
You are not performing any error checking in the call to LoadBitmap and the call to CreatePatternBrush. Very likely one of these calls fails and so hbrBackground is set to NULL, which results in a white background.
Your next step is to do some debugging to work out which call fails. Quite likely is that the bitmap file that you are linking as a resource uses a format that is not supported by LoadBitmap. Or perhaps the bitmap file is somehow not being linked. But so long as you actually manage to create a bitmap and then a brush, the system will use that brush to paint the background.
Related
SOLVED: I've posted my solution as an answer.
Here's my problem: (gif) (Sort of solved if I reload the bitmaps for painting the background image when unminimizing before any WM_PAINT message.)
It happens whenever I unminimize the application, time when the app first displays OK (for a brief split second unless you are stepping with the debugger), and suddenly turns black (or whatever color has been set as hbrBackground in the app window classes). I can prevent this behaviour by reloading the HBITMAPs used in WM_PAINT, which are global variables and initialised with their corresponding values at app startup.
The gif starts showing the app reopened after a minimize, with the debugger stepping through the parent window of the Rich Edit Control message loop, the moments just before and after the background of all windows turns black, and then stepping into the Rich Edit Control subclass message loop, into WM_PAINT.
This never happens if I'm switching between apps without the app in question never having been minimized before.
This never happens if the Rich Edit Control (RICHEDIT50W) hasn't displayed any text before, ie. the app works OK if no text is ever displayed.
This is the window tree:
Main Window
Some Child Windows
Child Window 1
Rich Edit Control
The stepping goes out of the Child Window 1 WndProc; into the WM_PAINT of the Rich Edit Control inside the WndSubclassProcWhatever callback.
Some of the things I've done before realizing that a call to LoadImage() just after unminimize could fix the background issue:
Intercept the message loop of the Rich Edit Control with a subclass, and handle (as well as in every other window) messages as: WM_COMMAND, WM_IME_NOTIFY, WM_NCPAINT, WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_ERASEBKGND... Mainly returning something different than the DefSubclassProc/DefWindowProcW.
Calling ValidateRect() as soon as the app is reopened...
It has happened before that instead of the whole app turning black, only the text "highlighting" or the Rich Edit Control parent turned black, with the whole app turning black after another minimize unminimize cycle.
I'm using Visual Studio Community 2019 with default settings in an updated Windows 10, and seeing this problem both in release and debug builds.
I'm now looking forward to prevent the bitmaps from "unloading", thus saving many seemingly unnecessary LoadImage() calls. SOLVED
I tried uploading a minimal version of the code, yet the behaviour turned out not to be exactly the same, so thanks for the answer given before!
This has nothing to do with Rich Edit Control , even if you delete all of the controls, this will happen.
All you have to do is add a default color to the window background when you register the window.
Here:
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL; // Procesás WM_GETICON
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"mainWindowClass";
wcex.hIconSm = NULL; // Procesás WM_GETICON
return RegisterClassExW(&wcex);
}
Click again after minimize the window will cause it to redraw with the default background color, But you set the background color to NULL here. So try to change wcex.hbrBackground = NULL to wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1)
Updated:
It sounds like you have the same problem as I have encountered before.
Here is my previous code:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
hdcMem = CreateCompatibleDC(hdc);
HGDIOBJ previousbit = SelectObject(hdcMem, hBmp);
AlphaBlend(hdc, 0, 0, width_1, height_1, hdcMem, 0, 0, width_1, height_1, bf);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
}
break;
case WM_MOUSEWHEEL:
{
if (GET_WHEEL_DELTA_WPARAM(wParam) > 0 && bTrans <= 234)
{
bTrans += 20;
bf.SourceConstantAlpha = bTrans;
InvalidateRect(hWnd, NULL, TRUE);
}
if (GET_WHEEL_DELTA_WPARAM(wParam) < 0 && bTrans >= 20)
{
bTrans -= 20;
bf.SourceConstantAlpha = bTrans;
InvalidateRect(hWnd, NULL, TRUE);
}
return 0;
}
I slide the mouse wheel, it will trigger the InvalidateRect(hWnd, NULL, TRUE);
But if I delete DeleteDC(hdcMem), it will return a main window without a picture.
The debug snapshot is :
Yes, you can find previousbit == NULL.
As #Remy Lebeau said that, you are leaking the HBITMAP that SelectObject() returns, and giving the HDC permission to potentially destroy your bitmapBackgroundMainWindow behind your back.
This is the main cause.
A call to DeleteObject() fixed the issue.
This is the code from one of the bitmap-background window WM_PAINT messages fixed with the corresponding DeleteObject() call:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
HDC temporaryDC = CreateCompatibleDC(hdc);
BITMAP bitmapToBitBlt;
HGDIOBJ hgdiobjToBitBlt = SelectObject(temporaryDC, bitmapBackgroundMainWindow);
GetObjectW(bitmapBackgroundMainWindow, sizeof(BITMAP), &bitmapToBitBlt);
BitBlt(hdc, 0, 0, bitmapToBitBlt.bmWidth, bitmapToBitBlt.bmHeight, temporaryDC, 0, 0, SRCCOPY);
DeleteObject(temporaryDC); // This fixes the app.
EndPaint(hWnd, &ps);
return 0;
As Windows Docs state, after calling CreateCompatibleDC():
When you no longer need the memory DC, call the DeleteDC function. We recommend that you call DeleteDC to delete the DC. However, you can also call DeleteObject with the HDC to delete the DC.
How does this translate to my app unexpected behaviour, I don't know, feel free to clarify in the comments!
I need to find a way to remove this button:
I already tried to put the CS_NOCLOSE flag into the WNDCLASS, but this is not working.
WNDCLASS wc;
wc.style = CS_OWNDC | CS_NOCLOSE;
wc.lpfnWndProc = (WNDPROC)staticWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
I also have this code inside the callback:
case WM_INITMENU:
EnableMenuItem((HMENU)wParam, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
break
I didn't find a way to disable the close button but I have hidden my window from the taskbar as explained here https://msdn.microsoft.com/en-us/library/windows/desktop/cc144179(v=vs.85).aspx#tbnotify_Taskbar_Display_Options (section Managing Taskbar Buttons)) using the WS_EX_TOOLWINDOW flag.
Thx for help
GetOpenFileName fails with access violation. File must be on DESKTOP and have long name.
Problem occurs only after first successful open of the file. Problem occurs when mouse cursor hovers over file as tool tip about to be displayed.
See the answer below. I'm leaving the original problem description below.
Mike D.
=======================
I'm using GetOpenFileName. I sometimes get a access violation deep inside shell32. The violation never occurs the first time this code is used, it often takes five or six tries. Also it appears that if one selects a file in second or two after the open file window pops up, the violation does not occur. Also, the call stack displayed when I debug this does not include any of my code. It's as if some independent thread is waking up to do something.
Any insights into how I might debug this greatly appreciated!
I made a "hello" world app exhibiting the same behavior. It, however, requires many more tries before it fails. It also seems that one has to switch directories before it will fail.
The GOFN is done from a thread created just for that purpose. Below is the code from the "hello world" app.
typedef struct
{
public:
HWND hWnd;
HINSTANCE hInst;
} def_params, *p_params;
DWORD WINAPI ReadLogFile_DataRecorderThread (PVOID pvoid);
void ReadLogFile_DataRecorder (HWND hWnd, HINSTANCE hInst) // ***************************
{
static def_params Params;
Params.hWnd = hWnd;
Params.hInst = hInst;
HANDLE T = CreateThread (NULL,0,ReadLogFile_DataRecorderThread,&Params,0,NULL);
CloseHandle (T);
return;
}
DWORD WINAPI ReadLogFile_DataRecorderThread (PVOID pvoid)
{
p_params P = (p_params) pvoid;
HWND hWnd = P->hWnd;
HINSTANCE hInst = P->hInst;
char ReadLogFileLastDir[256];
// static def_OpenFileHook Hook;
OPENFILENAME ofn;
char fn[MAX_PATH]="\0";
char filter[32]="Text Files\0*.TXT;\0\0";
char title[]="Open IMC Data Recorder Log File";
char defext[]="TXT";
int status;
// Get File Name
fn[0] = '\0';
ReadLogFileLastDir[0] = '\0';
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.hInstance = hInst;
ofn.hInstance = (HINSTANCE) GetWindowLong (hWnd, GWL_HINSTANCE);
ofn.lpstrFilter = filter;
ofn.nFilterIndex = 0;
ofn.lpstrCustomFilter = NULL ;
ofn.nMaxCustFilter = 0 ;
ofn.lpstrFile = fn;
ofn.nMaxFile = sizeof(fn);
ofn.lpstrFileTitle = NULL;
if (ReadLogFileLastDir[0] == '\0')
{
SHGetSpecialFolderPath (NULL,ReadLogFileLastDir,0x0005,false);
};
ofn.lpstrInitialDir = ReadLogFileLastDir;
ofn.lpstrTitle = title;
ofn.Flags = OFN_FILEMUSTEXIST |
OFN_PATHMUSTEXIST |
OFN_EXPLORER |
// OFN_ENABLETEMPLATE |
OFN_ENABLESIZING |
// OFN_ENABLEHOOK |
OFN_READONLY;
ofn.lpstrDefExt = NULL;
ofn.lpfnHook = NULL; // Hook.DialogHook; // hook routine
ofn.lCustData = NULL; // (long) &Hook; // data for hook routine
ofn.lpTemplateName = NULL; // MAKEINTRESOURCE(IDD_HOOKFILEOPEN);
ofn.nFileOffset = 0 ;
ofn.nFileExtension = 0 ;
ofn.lpstrDefExt = defext;
status = GetOpenFileName (&ofn);
int S;
S = CommDlgExtendedError();
return 0;
}
When it fails, the call stack looks like this...
SHELL32! 7ca4e035()
SHELL32! 7cb2dc16()
SHELL32! 7cb2dd5a()
SHELL32! 7cb27361()
SHELL32! 7c9f40a3()
BROWSEUI! 75f81b9a()
SHLWAPI! 77f69548()
NTDLL! 7c927545()
NTDLL! 7c927583()
NTDLL! 7c927645()
NTDLL! 7c92761c()
KERNEL32! 7c80b50b()
Sorry but I am unable to get symbols for these as I have an old Visual C++ :-(
It appears to me that the problem occurs when the GOFN stuff is about to open the popup describing the file as the mouse cursor hovers over the file name.
The set of circumstances causing the problem are somewhat weird. Experiments show one has to do the following in the GOFN window:
Open a file on the DESKTOP
Hover over a long file name
If I do this twice, it always fails. The file name I used was
IMCLOG_20120323_1658_-_20120324_0653_CST_+DST_E2_2_second.TXT
I tried the same thing with NOTEPAD and the same problem occurs!
I found numerous reports of the same problem. For example:
Social.MSDN Problem report
CodeProject question
CodeGuru thread
There was also a Google cached link to a since-deleted MS Connect bug report. As you discovered, the problem seems to be particular to files in the Desktop.
The only suggested solution I found is to call CoInitializeEx(NULL) at the start of the thread, and call CoUninitialize() at the end, so that's worth trying.
Also, the MSDN documentation for GetOpenFileName() says:
Starting with Windows Vista, the Open and Save As common dialog boxes have been superseded by the Common Item Dialog.
So it may be worth discarding GetOpenFileName() completely.
I'm trying to open a simple window through the Win32 API, using the VC++ compiler and in Visual Studio. I'd like to know why the class fails; I've tried allocating it without a pointer, along with allocating it as a pointer and sending it to the function as a reference. Yet, no matter what I try, the RegisterClassEx function refuses to return true.
Why is this, and what can be done about it?
From WinMain
WNDCLASSEX* wc = new WNDCLASSEX;
HWND hwnd;
MSG msg;
bool done;
wc->style = CS_HREDRAW | CS_VREDRAW;
wc->lpfnWndProc = WndProc;
wc->cbClsExtra = 0;
wc->cbWndExtra = 0;
wc->hInstance = hInstance;
wc->hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc->hCursor = LoadCursor(NULL, IDC_ARROW);
wc->hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc->lpszClassName = L"someclass";
if (!RegisterClassEx(wc)) {
MessageBox(NULL, L"Class registration has failed!", L"Error!", MB_OK | MB_ICONINFORMATION);
return 0;
}
You have to tell Windows how large your WNDCLASSEX structure is by filling in the cbSize member. You failed to initialize this member before calling RegisterClassEx, which is presumably why that function is failing. The sizeof operator is all you need.
You also failed to initialize some of the other members of the structure, like lpszMenuName. If you don't explicitly initialize them, they contain garbage data, which is probably causing the RegisterClassEx function to fail. If you're not using them, you need to explicitly set them to 0.
Furthermore, just because the RegisterClassEx argument accepts a pointer to a WNDCLASSEX structure doesn't mean that you have to create the structure as a pointer. You can create a regular object on the stack and use the address-of operator (&) to pass a pointer to the function.
Note that, as per the documentation, you can also call the GetLastError function to get more details on what went wrong when calling the RegisterClassEx function. This will help you to debug problems when you encounter them.
Working sample code:
WNDCLASSEX wc = {0}; // make sure all the members are zero-ed out to start
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszClassName = L"someclass";
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, L"Class registration has failed!",
L"Error!", MB_OK | MB_ICONERROR);
return 0;
}
I know I am probably missing something, but I can't seem to get windows to show the live thumbnail preview correctly when using a window that has a region. When hitting the minimize button the preview will clip to the minimized size (160x25) rather than showing the full preview (like it does with other windows).
Few points to make:
1) The preview works fine in Windows Live Messenger, so Microsoft figured out a way to do it.
2) If I call SetWindowRgn only before a window is visible, it works fine (so its not a fault of the DWM not knowing how to deal with regioned windows.) I can call SetWindowRgn many times before the window is visible and it works great.
3) I need to set the window region after I show the window in case of a resize. So a fix to just set it before will not work.
4) Even when using the default window procedure, the bug still happens. So it is not a fault of processing a message incorrectly (but could be a fault of 'not processing' one :) )
5) When minimizing by clicking the taskbar button (instead of the minimize button in the window), the preview normally works fine (even after setting the region when visible). Again proving that it does not how to deal with the preview.
The bug happens if I set a region after I have shown the window. Code to follow:
void create(HINSTANCE hInst)
{
char* className = "default";
/* Register
*/
WNDCLASSEX wcex;
memset(&wcex,0,sizeof(wcex));
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DefWindowProc;
wcex.hInstance = hInst;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszClassName = className;
RegisterClassEx(&wcex);
/* Create
*/
HWND hwnd = CreateWindow(className, className, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
/*
* Set the region
* If set before the window is shown for the first time, minimize preview on vista works
*/
RECT rect;
GetWindowRect(hwnd,&rect);
HRGN rgn = CreateRoundRectRgn(0,0,rect.right-rect.left,rect.bottom-rect.top,15,15);
SetWindowRgn(hwnd,rgn,TRUE);
/* Show the window
*/
ShowWindow(hwnd,SW_SHOW);
/*
* Set the region a second time.
* Doing this will break minimize preview on vista
*/
rgn = CreateRoundRectRgn(0,0,rect.right-rect.left,rect.bottom-rect.top,35,35);
SetWindowRgn(hwnd,rgn,TRUE);
}
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
create(hInstance);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
Microsoft responded to a tech support incident and listed this as a bug within Vista.