Related
I recently finished an introductory lesson on C++ and decided to jump into Visual C++ to try to make a little application.
So far, all I want is to at least create and show a window, didn't go any further.
I used many Microsoft Tutorials to get the code I have.
Please note that I have many comments to help me understand what I am doing.
I`m using Microsoft Visual Studio 2015
#include <tchar.h> //A Win32 character string that can be used to describe ANSI, DBCS, or Unicode strings
//Enclose the strings in _T() if an incompatibility error occures or (LPCWSTR)L""
#include <windows.h>
// Global variable
HINSTANCE hinst;
//Function prototype for the window procedure so the inside of the program knows wazup
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
//Instead of your usual console program, you get WinMain() instead of int main(int argc,char *argv[])
INT WINAPI wWinMain(HINSTANCE hInst, //Instance of the program being executed
HINSTANCE hPrevInst, //Previous instance, not used much anymore
LPWSTR lpCmdLine, //Holds command line arguments
INT nShowCmd) //Tells how the program should start(minumised, maximised...)
{
/*Steps to create a window:
- Register a window class
- Create the window
- Show the window
- Setup a callback procedure
*/
//We can tell if the window class has failed if RegisterClassEx() returns 0.
//Fortunatley, there is another handy function, namely GetLastError().
//GetLastError() will return an error code, which can then be used to track down the cause of the error.
//https://msdn.microsoft.com/en-us/library/ms681381.aspx
if (!InitApplication(hInst))
{
int nResult = GetLastError();
MessageBox(NULL,
_T("Window class creation failed"),
_T("Window Class Failed"),
MB_ICONERROR);
return 1;
}
//Window creation & display:
if (!InitInstance(hInst, nShowCmd)){
int nResult = GetLastError();
MessageBox(NULL,
_T("Window creation failed"),
_T("Window Creation Failed"),
MB_ICONERROR);
return 1;
}
//The windows 'callback procedure' is necessary to continue
MSG msg; //Message handler
ZeroMemory(&msg, sizeof(MSG));
//Main loop for the program
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);//translates virtual key messages to character messages
DispatchMessage(&msg); //Sends any messages to the callvack procedure, so it can be handled
}
//Still returns an int!
return 0;
}
BOOL InitApplication(HINSTANCE hinstance)
{
//The window class defines the overall 'look and feel' of the window that we want to create.
//First we create an instance of a window class
WNDCLASSEX wClass;
//For more about WNDCLASSEX: https://msdn.microsoft.com/en-us/library/ms633577(VS.85).aspx
//Clearing all the parameters of the WNDCLASSEX instance wClass to zero
ZeroMemory(&wClass, sizeof(WNDCLASSEX));
//Now we are setting up all sotrts of parameters for our instance:
wClass.cbClsExtra = NULL; // cbClsExtra Additional parameters
wClass.cbSize = sizeof(WNDCLASSEX); // cbSize Specifies the size of the window class
wClass.cbWndExtra = NULL; // cbWndExtra Additional parameters
wClass.hbrBackground = (HBRUSH)COLOR_WINDOW; // hbrBackground Sets background color for the window
wClass.hCursor = LoadCursor(NULL, IDC_ARROW); // hCursor The cursor that will appear in the window
wClass.hIcon = NULL; // hIcon Icon for the window
wClass.hIconSm = NULL; // hIconSm Small icon for the window
wClass.hInstance = hinstance; // hInstance Handle to the application instance
wClass.lpfnWndProc = (WNDPROC)WinProc; // lpfnWndProc The callback procedure (more on that later)
wClass.lpszClassName = _T("Window Class"); // lpszClassName The unique name of the window class
wClass.lpszMenuName = NULL; // lpszMenuName Used for menus
wClass.style = CS_HREDRAW | CS_VREDRAW; // style The look and feel of the window
// Register the window class.
return RegisterClassEx(&wClass);
}
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow)
{
// Save the application-instance handle.
hinst = hinstance;
// Create the main window.
//CreateWindowEx returns a HWND
HWND hwnd = CreateWindowEx( // A "handle" is a generic identifier + like "new"
0, // DWORD, extended window style of the window being created https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
_T("MainsWClass"), // LPCTSTR, A null-terminated string or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
_T("Sample"), // LPCTSTR, The window name.
WS_OVERLAPPEDWINDOW, // DWORD, Style of the window created
CW_USEDEFAULT, // int, X - default horizontal position
CW_USEDEFAULT, // int, Y - default vertical position
CW_USEDEFAULT, // int, nWidth - default width
CW_USEDEFAULT, // int, nHeight - default height
(HWND)NULL, // HWND, hWndParent - handle to the parrent or owner window of the window being created (opptional for pop-up)
(HMENU)NULL, // HMENU, hMenu
hinstance, // HINSTANCE, hInstance - A handle to the instance of the module to be associated with the window.
(LPVOID)NULL); // LPVOID, Pointer to a value to be passed to the window through the CREATESTRUCT structure
//If the creation fails, returns FALSE
if (!hwnd)
return FALSE;
else{
// Show the window and send a WM_PAINT message to the window procedure.
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return TRUE;
}
}
//callback procedure
LRESULT CALLBACK WinProc(
HWND hWnd, //Handle of the window that we want to monitor
UINT msg, //Message we are receiving
WPARAM wParam, //Additionnal info for the received message
LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY: //Message sent to the application if the program was closed using the X on the top of the window
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
You are registering a window class named "Window Class", but try to create a window of class "MainsWClass". That class is unknown. You need to create window of a window class that has previously been registered (either by yourself, or one of the pre-defined window classes like "BUTTON").
Is there a way to set true full focus on a push button (button window class) in WinAPI?
SetFocus() somewhat sets focus (the button gets an inner dotted border), but the button is actually partially focused and still cannot be pressed with the Enter key, only the Spacebar key works. At the same time, if I move focus to a sibling button with the Tab key, then this sibling button (as well as the first button if I then return focus to it using Shift+Tab) gets a true focus (visually, not just inner dotted focus border is added to the really focused button, but its main outer border becomes blue [Windows 7]), and now it reacts to Enter as intended.
How to make a button such fully focused programmatically?
Screenshot of the three button states:
Some background for clarity: there is a window (created with the regular combination of WNDCLASSEX / RegisterClassEx / CreateWindowEx() with WS_OVERLAPPEDWINDOW as its style) with a multiline edit box (edit window class with ES_MULTILINE style) and several push buttons. To implement keyboard navigation using the Tab key, I process the WM_KEYDOWN event in the edit box's procedure (subclassed via SetWindowLong()), otherwise I could navigate between buttons and from buttons to the edit box, but not from the edit box to a button. All the controls have WS_TABSTOP style. The issue with the button focus takes place when I set focus using SetFocus() when the Tab key is pressed on the edit box having focus and caret.
Minimal relevant C++ code:
HWND mainWindow;
WNDPROC defaultEditCallback = NULL;
int WINAPI WinMain(HINSTANCE instance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEXW wc;
wchar_t windowClass[] = L"testcase";
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = 0;
wc.lpfnWndProc = mainWindowCallback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = instance;
wc.hIcon = NULL;
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCWSTR)windowClass;
wc.hIconSm = NULL;
RegisterClassExW(&wc);
mainWindow = CreateWindowW(
(LPCWSTR)windowClass, (LPCWSTR)windowClass, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, instance, NULL
);
HWND edit = CreateWindowExW(
WS_EX_CLIENTEDGE, (LPCWSTR)L"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | WS_TABSTOP,
0, 0, 0, 0, mainWindow, (HMENU) 10,
(HINSTANCE) GetWindowLongPtrW(mainWindow, GWLP_HINSTANCE),
NULL
);
defaultEditCallback = (WNDPROC)SetWindowLongPtrW(edit, GWLP_WNDPROC, (LONG)editCallback);
HWND firstButton = createButton(mainWindow, 20, L"First", buttonWidth, buttonHeight);
HWND secondButton = createButton(mainWindow, 30, L"Second", buttonWidth, buttonHeight);
HWND thirdButton = createButton(mainWindow, 40, L"Third", buttonWidth, buttonHeight);
// [Skipped] Sizing and positioning controls.
ShowWindow(mainWindow, nCmdShow);
UpdateWindow(mainWindow);
MSG msg;
while (GetMessageW(&msg, NULL, 0, 0) > 0) {
if (!IsDialogMessage(mainWindow, &msg)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return (int)msg.wParam;
}
LRESULT CALLBACK mainWindowCallback(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_DESTROY == msg) {
PostQuitMessage(0);
}
return DefWindowProcW(window, msg, wParam, lParam);
}
LRESULT CALLBACK editCallback(HWND control, UINT msg, WPARAM wParam, LPARAM lParam) {
if (WM_KEYDOWN == msg && VK_TAB == wParam) {
HWND next = GetNextDlgTabItem(mainWindow, control, (int)(GetKeyState(VK_SHIFT) & 0x8000));
SetFocus(next);
return 0;
}
return CallWindowProc(defaultEditCallback, control, msg, wParam, lParam);
}
HWND createButton(HWND parentWindow, int id, wchar_t* caption, int width, int height) {
return CreateWindowW(
(LPCWSTR)L"button", (LPCWSTR)caption, WS_VISIBLE | WS_CHILD | WS_TABSTOP,
0, 0, width, height, parentWindow, (HMENU)id, NULL, NULL
);
}
Thanks.
The question does not make it clear whether the WS_OVERLAPPEDWINDOW main window is either a dialog, or subclassed to work like a dialog (i.e. based on DefDlgProc). Some hints about TAB navigation and DM_SETDEFID in the OP and following comments appear to indicate that it's a dialog(-styled) window.
For dialogs, the correct way to move the input focus between child controls is by sending the WM_NEXTDLGCTL message, rather than calling SetFocus directly. As noted in the docs:
This message performs additional dialog box management operations beyond those performed by the SetFocus function WM_NEXTDLGCTL updates the default pushbutton border, sets the default control identifier, and automatically selects the text of an edit control (if the target window is an edit control).
More details at How to set focus in a dialog box, including this part:
As the remarks to the DM_SETDEFID function note, messing directly with the default ID carelessly can lead to odd cases like a dialog box with two default buttons. Fortunately, you rarely need to change the default ID for a dialog.
A bigger problem is using SetFocus to shove focus around a dialog. If you do this, you are going directly to the window manager, bypassing the dialog manager. This means that you can create “impossible” situations like having focus on a pushbutton without that button being the default!
To avoid this problem, don’t use SetFocus to change focus on a dialog. Instead, use the WM_NEXTDLGCTL message.
[EDIT] After the OP edit, the main window turns out to be a regular window, not a dialog. The newly posted code, however, does not remember the focused child (nor does it remove/restore the default pushbutton style) after the main window is deactivated and reactivated, relegates keyboard navigation such as VK_TAB to child controls etc. Those introduce inconsistencies with the default dialog-like behaviors.
In order to make the main window behave like a dialog (and do it right), the WNDPROC would need to mimic the relevant parts of DefDlgProc, at least those that pertain to navigation. From Dialog Box Programming Considerations, among the messages such a WNDPROC would need special handling for are DM_GETDEFID, DM_SETDEFID, WM_ACTIVATE, WM_NEXTDLGCTL, WM_SHOWWINDOW, WM_SYSCOMMAND. Once that's done, my original answer still applies.
I am writing the beginnings of a game as a Win32 application. Everything worked fine when I registered the class within Main.cpp, but now I'm trying to move it to a Game class to make the code easier for me to use.
Since I have moved the code into the Game class, window class registration fails. Here is my code, please note that some functions are empty simply because I haven't got that far yet.
GetLastError() returns 87.
Main.cpp
#include "Main.h"
// entry point for the program, see Game for explanation of parameters
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
game = std::unique_ptr<Game>(new Game(hInstance, hPrevInstance, lpCmdLine, nCmdShow));
game->Init();
// main game loop
while(game->IsRunning())
{
game->HandleMessages();
game->Update(0.0f);
game->Render();
}
return EXIT_SUCCESS;
}
Game.cpp
#include "Game.h"
#include <Windows.h>
LPCWSTR g_szClassName = L"Life Simulator Window Class";
Game::Game(HINSTANCE _hInstance, // handle to an instance of the application
HINSTANCE _hPrevInstance, // handle to previous instance of the application
LPSTR _lpCmdLine, // command line parameters
int _nCmdShow) // controls how the window is show)
{
hInstance = _hInstance;
hPrevInstance = _hPrevInstance;
lpCmdLine = _lpCmdLine;
nCmdShow = _nCmdShow;
return;
}
Game::~Game(void)
{
}
bool
Game::Init()
{
// set paramaters for window class
wc.cbClsExtra = 0; // number of extra bytes to allocate after window class, not needed but showing for verbosity
wc.cbSize = sizeof(WNDCLASSEX); // stores the size of the WNDCLASSEX structure, helping future proof your application in case new fields are added
wc.cbWndExtra = 0; // similar to cbClsExtra, but refers to the window itself rather than the window class
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); // handle to a background brush, in this case it's simply a colour cast into a brush handle
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // handle to cursor, first paramater is a handle to the instance of the application containing the cursor (not needed in this case), second is the resource identifier
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // similar to hCursor, but for the application icon instead
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // as above, but for the smaller version of the icon
wc.hInstance = hInstance; // handle to the instance of the application that contains the window procedure
wc.lpfnWndProc = Game::WndProc; // a pointer to the window procedure
wc.lpszClassName = g_szClassName; // the window class name (see global variables)
wc.lpszMenuName = NULL; // specifies the resource name of the menu, which isn't used in this case
wc.style = CS_HREDRAW | CS_VREDRAW; // style for the window class, which in this case means to redraw if it's affected (i.e. resized or moved) vertically or horizontally
// register the window class
if(!RegisterClassEx(&wc))
{
// this code is executed if the window class fails to register successfully
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Class Registation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
// create the window
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, // extended window style
g_szClassName, // class of window to be created (this is the window class created earlier)
L"Life Simulator", // title of the window
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // x position of the window, here default values are used
CW_USEDEFAULT, // as above, but for the y position
wndWidth, // width of the window
wndHeight, // height of the window
NULL, // parent window, if it has one
NULL, // handle to the menu for the window
hInstance, // handle to the instance of the application
NULL); // lpParam can be passed on here
if(hWnd == NULL)
{
// this code is executed if the creating the window failed
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Creation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
ShowWindow(hWnd, // handle to the window to be shown
nCmdShow); // passed on from WinMain, controls how the window should be shown (i.e. minimised or maximised)
UpdateWindow(hWnd); // forces the window the be updated by forcing a WM_PAINT message past the application queue
}
// window procedure for the game
LRESULT CALLBACK
Game::WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam) // even more additional message information
{
switch(msg)
{
case WM_CLOSE: // red X has been clicked
DestroyWindow(hWnd); // sends WM_DESTROY to the window
break;
case WM_DESTROY: // some part of the program has requested the window to be destroyed
PostQuitMessage(0); // sends quit message to window
break;
default: // unhandled messages
return DefWindowProc(hWnd, msg, wParam, lParam);// windows will handle any messages that haven't been handled explicitly
}
return 0;
}
void
Game::HandleMessages()
{
while(PeekMessage(&msg, // container for the message
NULL, // when multiple windows are used, you can specify which one here
0, // used to filter messages, not needed here
0, // as above
PM_REMOVE)) // remove messages after they've been processed
{
TranslateMessage(&msg); // turns virtual key messages into character messages
DispatchMessage(&msg); // sends the message on to its window procedure (i.e. WndProc)
}
return;
}
void
Game::Update(float elapsedTime)
{
return;
}
void
Game::Render()
{
return;
}
Previously working Main.cpp
#include <Windows.h>
// global variables
LPCWSTR g_szClassName = L"Life Simulator Window Class"; // the L casts the string to a wide string and it is called g_szClassName by convention, making the code easier to read for others
static const int wndHeight = 800;
static const int wndWidth = 600;
// window procedure for the program
LRESULT CALLBACK WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam) // even more additional message information
{
switch(msg)
{
case WM_CLOSE: // red X has been clicked
DestroyWindow(hWnd); // sends WM_DESTROY to the window
break;
case WM_DESTROY: // some part of the program has requested the window to be destroyed
PostQuitMessage(0); // sends quit message to window
break;
default: // unhandled messages
return DefWindowProc(hWnd, msg, wParam, lParam);// windows will handle any messages that haven't been handled explicitly
}
}
// entry point for the program
int WINAPI WinMain(HINSTANCE hInstance, // handle to an instance of the application
HINSTANCE hPrevInstance, // handle to previous instance of the application
LPSTR lpCmdLine, // command line parameters
int nCmdShow) // controls how the window is show
{
// initialise variables
HWND hWnd; // handle to window
WNDCLASSEX wc; // window class container
MSG msg; // window message container
// set paramaters for window class
wc.cbClsExtra = 0; // number of extra bytes to allocate after window class, not needed but showing for verbosity
wc.cbSize = sizeof(WNDCLASSEX); // stores the size of the WNDCLASSEX structure, helping future proof your application in case new fields are added
wc.cbWndExtra = 0; // similar to cbClsExtra, but refers to the window itself rather than the window class
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW); // handle to a background brush, in this case it's simply a colour cast into a brush handle
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // handle to cursor, first paramater is a handle to the instance of the application containing the cursor (not needed in this case), second is the resource identifier
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // similar to hCursor, but for the application icon instead
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // as above, but for the smaller version of the icon
wc.hInstance = hInstance; // handle to the instance of the application that contains the window procedure
wc.lpfnWndProc = WndProc; // a pointer to the window procedure
wc.lpszClassName = g_szClassName; // the window class name (see global variables)
wc.lpszMenuName = NULL; // specifies the resource name of the menu, which isn't used in this case
wc.style = CS_HREDRAW | CS_VREDRAW; // style for the window class, which in this case means to redraw if it's affected (i.e. resized or moved) vertically or horizontally
// register the window class
if(!RegisterClassEx(&wc))
{
// this code is executed if the window class fails to register successfully
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Class Registation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
// create the window
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, // extended window style
g_szClassName, // class of window to be created (this is the window class created earlier)
L"Life Simulator", // title of the window
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // x position of the window, here default values are used
CW_USEDEFAULT, // as above, but for the y position
wndWidth, // width of the window
wndHeight, // height of the window
NULL, // parent window, if it has one
NULL, // handle to the menu for the window
hInstance, // handle to the instance of the application
NULL); // lpParam can be passed on here
if(hWnd == NULL)
{
// this code is executed if the creating the window failed
MessageBox(NULL, // an owner for the message box can be specified here
L"Window Creation Failed.", // message to be displayed
L"Fatal Error", // title of the message box
MB_ICONEXCLAMATION | MB_OK); // type of message box, in this case it has an exclamation icon and an OK button
return EXIT_FAILURE; // return EXIT_FAILURE to indicate that the program closed due to a runtime error
}
ShowWindow(hWnd, // handle to the window to be shown
nCmdShow); // passed on from WinMain, controls how the window should be shown (i.e. minimised or maximised)
UpdateWindow(hWnd); // forces the window the be updated by forcing a WM_PAINT message past the application queue
// message loop
while(true){ // program closes instantly otherwise
while(PeekMessage(&msg, // container for the message
NULL, // when multiple windows are used, you can specify which one here
0, // used to filter messages, not needed here
0, // as above
PM_REMOVE)) // remove messages after they've been processed
{
TranslateMessage(&msg); // turns virtual key messages into character messages
DispatchMessage(&msg); // sends the message on the its window procedure (i.e. WndProc)
}
}
return msg.wParam; // contains the exit code from the last message, most likely WM_QUIT
}
Game.h
#pragma once
#include <Windows.h>
class Game
{
public:
Game(HINSTANCE hInstance, // handle to an instance of the application
HINSTANCE hPrevInstance, // handle to previous instance of the application
LPSTR lpCmdLine, // command line parameters
int nCmdShow); // controls how the window is show
~Game(void);
bool Init();
bool IsRunning(){return isRunning;}
// window procedure for the game
static LRESULT CALLBACK WndProc(HWND hWnd, // handle to the window
UINT msg, // message to be processed
WPARAM wParam, // additional message information
LPARAM lParam); // even more additional message information
void HandleMessages(); // messages are translated and dispatched here
void Update(float elapsedTime); // game logic
void Render(); // display results
public: // changed to public until I can get it all working
bool isRunning;
HINSTANCE hInstance;
HINSTANCE hPrevInstance;
LPSTR lpCmdLine;
int nCmdShow;
LPCWSTR g_szClassName; // the L casts the string to a wide string and it is called g_szClassName by convention, making the code easier to read for others
static const int wndHeight = 600; // window height
static const int wndWidth = 800; // window width
HWND hWnd; // handle to window
WNDCLASSEX wc; // window class container
MSG msg; // window message container
};
The problem is that you have g_szClassName declared as both a member variable and a global variable. The member variable g_szClassName is not initialized anywhere and can point to anything.
There is also no reason to have wc and msg declared as member variables as they do not need to persist throughout the lifetime of the object. Make them local variables instead.
Hello Everyone,
I want to know if there is an image control in VC++ like there is one in VB. Actually using the picture box i face the problem of not being able to re size the image at design time for my dialog. But in image control this is possible. I there is no image control is there a way to check the height and width of a dialog from the dialog editor at design time ???
If you're writing an unmanaged C or C++ project it's a little bit more difficult than using the PictureBox control that would be available when designing managed Windows Forms application, but still doable.
If you are using a DialogBox resource for the window (note: I wrote this part using Visual Studio 2015 as a reference, not 2008, but the general process should be the same):
Insert the image as a resource in your project. Let's say we named the resource for the bitmap IDB_BITMAP1 for simplicity.
Create a new Static child window in the dialog box.
Right click on the new Static window and select Properties.
Under the Misc subheading in Properties, change Type to Bitmap.
Under the Misc subheading in Properties, change Image to IDB_BITMAP1.
If you are hand-coding the window (i.e. manually writing calls to CreateWindow and CreateWindowEx to create the window):
Insert the image as a resource in your project. Make sure to add the line #include "resource.h" to your code.
Get a handle to the bitmap using the LoadBitmap function.
Create the static window as a child window of the main window, and specify the SS_BITMAP window style.
Send the STM_SETIMAGE message to the window using the previously identified handle to the bitmap resource.
Example code, assuming your image is IDB_BITMAP1:
#include <Windows.h>
#include <tchar.h>
#include "resource.h"
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
{
HWND hWnd, hStcImage;
MSG Msg;
HBITMAP hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
// ... register the window class etc
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, _T("ExampleClassName"), _T("Simple Window"), WS_VISIBLE | WS_SYSMENU, 100, 100, 350, 370, NULL, NULL, hInstance, NULL);
hStcImage = CreateWindow(_T("Static"), NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 10, 10, 0, 0, hWnd, NULL, hInstance, NULL);
SendMessage(hStcImage, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
I'v created a window after creating my main one but calling DestroyWindow on its handle closes the entire application, how can I simply get rid of it?
it looks like this:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
HWND fakehandle;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_EX_LAYERED,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
fakehandle = CreateWindow(szWindowClass, "FAKE WINDOW", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd || !fakehandle)
{
return FALSE;
}
//some code
DestroyWindow(fakehandle);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
how can I destroy this window without destroying my main one? I'm creating a dummy window to check for multisampling in OpenGL.
Thanks
I've just found this comment:
If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.
on the DestroyWindow MSDN page.
Could this have some bearing on your problem? Could you be setting the parent of hWnd where you've got //some code?
DestroyWindow() sends a WM_DESTROY to the window in question. If the WndProc passes WM_DESTROY on to DefWindowProc(), then DefWindowProc() will kill your app.
So, in your WndProc, create a handler for WM_DESTROY (if you don't already have one), and check the window handle. You should be able to differentiate between the two and take action from there.
// assuming you have the two window handles as hwnd1 and hwnd2
case WM_DESTROY:
if( hwnd == hwnd1 ) {
// this will kill the app
PostQuitMessage(0);
} else if( hwnd == hwnd2 ) {
// chucking WM_DESTROY on the floor
// means this window will just close,
// and the other one will stay up.
return;
}
break;
Be aware that if you do PostQuitMessage() on behalf of either window, it will take down your application, because PostQuitMessage() will terminate the message loop.
I suspect that specifying a parent (Fourth param from the end) for the "fakehandle" window instead of NULL, may help.
Also, you might check whether or not this quote "If the window being destroyed is a child window that does not have the WS_EX_NOPARENTNOTIFY style, a WM_PARENTNOTIFY message is sent to the parent." (From: msdn.microsoft.com) applies to your case.
Does the class referred to by szWindowClass call PostQuitMessage on receipt of WM_CLOSE or WM_DESTROY? That would stop your message loop first time round, I should think. (But if you're using the debugger, presumably you'd have spotted this?)
In any event, for your dumb window, for best results you'd need a second window class with a dumb WndProc. (I think DefWindowProc would be suitable.)