I'm making a simple text editor win32 application for fun. I'm having a peculiar problem with my program. It seems that my program is not returning zero when it exits. Instead, it is returning 1385929. When my main GUI window is destroyed, I use PostQuitMessage( 0 ), but it seems that is not what is being returned in my main function's message.wParam. Here is my code thus far,
#define WIDTH 500
#define HEIGHT 400
#define EDIT_ID 10
LRESULT CALLBACK windowProc( HWND window, UINT message, WPARAM wParam, LPARAM lParam )
{
static HDC deviceContext = INVALID_HANDLE_VALUE;
static HWND editControl = INVALID_HANDLE_VALUE;
switch ( message )
{
case WM_CREATE :
deviceContext = GetDC( window );
if ( !deviceContext )
{
showWindowsError( "Creating Device Context", FALSE );
DestroyWindow( window );
}
editControl = CreateWindow(
"EDIT",
NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT |
ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL,
0,
0,
0,
0,
window,
( HMENU )EDIT_ID,
( HINSTANCE )GetWindowLong( window, GWL_HINSTANCE ),
NULL
);
if ( !editControl )
{
showWindowsError( "Creating Edit Control", TRUE );
DestroyWindow( window );
}
return 0;
break;
case WM_COMMAND :
switch ( wParam )
{
case WM_UNDO :
SendMessage( editControl, WM_UNDO, 0, 0 );
break;
case WM_CUT :
SendMessage( editControl, WM_CUT, 0, 0 );
break;
case WM_COPY :
SendMessage( editControl, WM_COPY, 0, 0 );
break;
case WM_PASTE :
SendMessage( editControl, WM_PASTE, 0, 0 );
break;
case WM_CLEAR :
SendMessage( editControl, WM_CLEAR, 0, 0 );
break;
default:
return DefWindowProc( window, message, wParam, lParam );
}
case WM_SIZE :
MoveWindow( editControl, 0, 0, LOWORD( lParam ), HIWORD( lParam ), TRUE );
return 0;
break;
case WM_DESTROY :
ReleaseDC( window, deviceContext );
DestroyWindow( editControl );
PostQuitMessage( 0 );
return 0;
break;
}
return DefWindowProc( window, message, wParam, lParam );
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR CmdArgs, int nCmdShow )
{
WNDCLASSEX windowClass = { 0 };
HWND window = INVALID_HANDLE_VALUE;
MSG message = { 0 };
HBRUSH windowColor = CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
windowClass.cbSize = sizeof( windowClass );
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = windowProc;
windowClass.hInstance = hInstance;
windowClass.hCursor = LoadCursor( NULL, IDC_ARROW );
windowClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
windowClass.hbrBackground = windowColor;
windowClass.lpszClassName = "TextEditorWindow";
if ( !RegisterClassEx( &windowClass ) )
{
DeleteObject( windowColor );
showWindowsError( "Registering Windows Class", TRUE );
}
window = CreateWindow(
"TextEditorWindow",
"Text Editor",
WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
WIDTH,
HEIGHT,
NULL,
NULL,
hInstance,
NULL
);
if ( !window )
{
DeleteObject( windowColor );
showWindowsError( "Creating GUI", TRUE );
}
ShowWindow( window, SW_SHOW );
UpdateWindow( window );
do
{
TranslateMessage( &message );
DispatchMessage( &message );
} while ( GetMessage( &message, window, 0, 0 ) > 0 );
DeleteObject( windowColor );
return message.wParam;
}
Your call to GetMessage() has the 2nd parameter set to your window's HWND, which limits the messages received only to those sent to that window - see the documentation of the API function.
WM_QUIT is, on the other hand, a message sent to the thread running the message pump, without any particular window. Because of that filter, you don't receive it and message.wParam is never set to that 0.
But why does the loop end and the program shuts down anyway? Because that HWND in window gets invalid after the window is closed, therefore GetMessage() ends with an error and returns -1.
Additionally, you are currently calling TranslateMessage() and DispatchMessage() with message before it is filled with any correct data, on the first iteration. The loop should rather be like this:
while ( GetMessage( &message, NULL, 0, 0 ) > 0 )
{
TranslateMessage( &message );
DispatchMessage( &message );
}
Related
I want to implement a listbox and a slider in my window.
I use devcpp, not visual studio.
I have looked up for a way to do that and i have found nothing, except theoritical stuff like msdn.microsoft.com provides.
I want an example, the smallest kind of code to implement listbox and slider.
This is the closer and most helpfull link, but still, it uses visual studio.
Thanks.
I found what i was looking for, it seems that this is the only example code on the entire internet on making listboxes. In order to run it: download and open devc++ (which I use) or any other kind of compiler, open a new Windows application project (otherwise it won't work), erase any default code, paste this code and run it.
And this, is how you help others learn code.
http://www.dreamincode.net/forums/topic/291276-win32-listbox/
#include <Windows.h>
#define IDC_MAIN_BUTTON 101 // Button identifier
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND hWndListL;
HWND hWndListR;
HWND hWndButton;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG Msg;
HWND hWnd;
//Settings All Window Class Variables
WNDCLASSEX WndClsEx;
WndClsEx.cbSize = sizeof(WNDCLASSEX);
WndClsEx.style = CS_HREDRAW | CS_VREDRAW;
WndClsEx.lpfnWndProc = WndProcedure;
WndClsEx.cbClsExtra = 0;
WndClsEx.cbWndExtra = 0;
WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClsEx.hInstance = hInstance;
WndClsEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClsEx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
WndClsEx.lpszMenuName = NULL;
WndClsEx.lpszClassName = "My Window";
//Register Window Class
RegisterClassEx(&WndClsEx);
//Create Window
hWnd = CreateWindowEx(NULL, "My Window", "Windows Application", WS_OVERLAPPEDWINDOW, 200, 200, 640, 480, NULL, NULL, hInstance, NULL);
SendMessage(hWndListL, LB_ADDSTRING, NULL, (LPARAM)"one");
SendMessage(hWndListL, LB_ADDSTRING, NULL, (LPARAM)"two");
//Show Window
ShowWindow(hWnd, SW_SHOWNORMAL);
while(GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0;
}
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
char buffer[50] = "";
switch(Msg)
{
case WM_CREATE:
//Create Listbox's
hWndListL = CreateWindowEx(NULL, "LISTBOX", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | LBS_NOTIFY, 50, 35, 200, 100, hWnd, NULL, GetModuleHandle(NULL), NULL);
hWndListR = CreateWindowEx(NULL, "LISTBOX", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | LBS_NOTIFY, 350, 35, 200, 100, hWnd, NULL, GetModuleHandle(NULL), NULL);
//Create Button
hWndButton = CreateWindowEx(NULL, "BUTTON", "OK", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_DISABLED, 50, 220, 100, 24, hWnd, (HMENU)IDC_MAIN_BUTTON, GetModuleHandle(NULL), NULL);
break;
case WM_COMMAND:
switch(HIWORD(wParam))
{
case LBN_SELCHANGE:
{
//EnableWindow( GetDlgItem( hWnd, (HMENU)IDC_BUTTON_MAIN ), TRUE );
EnableWindow(hWndButton, true);
break;
}
}
switch(LOWORD(wParam))
{
case IDC_MAIN_BUTTON:
{
//length = SendMessage(hWndListL, LB_GETTEXTLEN, NULL, NULL);
SendMessage(hWndListL, LB_GETTEXT, NULL, (LPARAM)buffer);
SendMessage(hWndListR, LB_ADDSTRING, NULL, (LPARAM)buffer);
SendMessage(hWndListL, LB_DELETESTRING, NULL, NULL);
EnableWindow(hWndButton, false);
break;
}
}
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
Here is example code of window with listbox:
#include <Windows.h>
/// unique class name
#define CLASS_NAME "MyWinapiClassNameWithUniqeSetOfCharactersThatAreNotMyPassword_50kz5S99g2Q88bTi3ne"
/// unique ID of our listbox command
#define IDC_LISTBOX_ID 123
static LRESULT WINAPI wndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ){
switch(msg){
case WM_CREATE:{
HWND listboxHwnd= CreateWindow( "LISTBOX", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD | LBS_NOTIFY, 10, 10, 200, 100, hwnd, (HMENU)IDC_LISTBOX_ID, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 0" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 1" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 2" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 3" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 4" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 5" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 6" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 7" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 8" );
SendMessage( listboxHwnd, LB_ADDSTRING, 0, (LPARAM)"List Item 9" );
}break;
case WM_COMMAND:{
switch( LOWORD(wParam) ){
case IDC_LISTBOX_ID:{
switch(HIWORD(wParam)){
case LBN_SELCHANGE:{ /// user have selected item in our listbox
int id= SendMessage( (HWND)lParam, LB_GETCARETINDEX, 0, 0 ); /// id of seleted item, starting from 0
char text[]= "Item 0 selected";
text[5] += id; /// thats one way of converting int to string :D
MessageBox( NULL, text, "Debug", MB_OK );
}break;
}
}break;
}
}break;
case WM_DESTROY:{
::PostQuitMessage(0);
}break;
}
return DefWindowProc( hwnd, msg, wParam, lParam);
}
int WINAPI WinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd ){
WNDCLASSEX wc= {
sizeof(WNDCLASSEX),
CS_CLASSDC,
wndProc,
0,
0,
hInstance,
LoadIcon( NULL, IDI_APPLICATION ),
LoadCursor( NULL, IDC_ARROW ),
(HBRUSH)(COLOR_WINDOW+0),
NULL,
CLASS_NAME,
NULL
};
if( !RegisterClassEx(&wc) ){
MessageBox( NULL, "Fail to register window class.", "Error - Keyboardlord", MB_ICONERROR );
return -2;
}
HWND hwnd= CreateWindow( CLASS_NAME, "App Browser - Keyboardlord", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 250, 150, NULL, NULL, hInstance, NULL );
if( hwnd==NULL ){
MessageBox( NULL, "Fail to create window", "Error - Keyboardlord", MB_ICONERROR );
return -3;
}
ShowWindow( hwnd, nShowCmd );
MSG msg;
while( 0 < GetMessage( &msg, NULL, 0, 0) ){
TranslateMessage( &msg );
DispatchMessage( &msg );
}
::DestroyWindow( hwnd );
::UnregisterClass( CLASS_NAME, hInstance );
return 0;
}
I have a very specific problem involving a modeless dialog box in my application.
The dialog box freezes and becomes unresponsive to any messages sent to it by other functions in my application. What is interesting is that my debugging tells me that it freezes when the dialog procedure has received just around 5000 messages that it DID NOT handle. The only explanation I can think of is that the Windows Message Queue may be full and it is more or less confirmed by the fact that the stream of messages going through the dialog box seem to tone down immensely.
Now - I've never used dialog boxes in conjunction with an ordinary main window before, and so I may be making illegal moves. By this I mean that I update the dialog box's controls (static texts and a list box) directly by sending the specific controls messages using SendMessage or SetWindowText functions.
What I think is weird is, that this technique works perfectly until 5000 messages have passed.
The main loop sends messages to the dialog box via the parent window handle and use of IsDialogMessage function.
Both the Main window and the dialog box still receives messages, but the dialog box freezes.
Is there a way for me to empty the message queue manually or check its current volume to check if that is actually the problem? I use PeekMessage function to retrieve my messages, which according to MSDN should remove a message from the bottom of the Message queue.
Here is how I've implemented My main loop ( I am pretty sure it's completely legal ):
while (true) //while there is a message
{
//if there was a windows message
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if ( msg.message == WM_QUIT ) //if the message was WM_QUIT
return 0; //Exit the message loop
if ( !IsDialogMessage( m_StatusHwnd, &msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
else
{
advanceFrame();
}
}
I really hope one of you have an idea about what is wrong, because this is REALLY hard hard to debug!
The Dialog procedure is implemented like so: ( Sorry that you have to see my actual code )
First the static dialog procedure redirects the messages to a custom method:
BOOL CALLBACK DXCore::statusDlgProc( HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
if ( msg == WM_INITDIALOG ) SetWindowLongPtr( hwnd, DWLP_USER, lParam);
DXCore * pCore = reinterpret_cast<DXCore*>( GetWindowLongPtr( hwnd, DWLP_USER ) ) ;
if ( pCore ) return pCore->displayStatusDlgProc( hwnd, msg, wParam, lParam );
//return the message for windows to handle it
return FALSE;
}
Then the actual procedure looks like this:
BOOL DXCore::displayStatusDlgProc( HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
HBRUSH brush = CreateSolidBrush( COLORREF( RGB( 255, 0, 0 ) ) ); //red
HPEN blackPen = CreatePen( PS_SOLID, 2, COLORREF( RGB(0,0,0 ) ) );
HDC hdc; PAINTSTRUCT ps;
RECT clientArea;
GetClientRect( hwnd, &clientArea );
int gizmoRadius= 5;
m_GismoOrigon.x = clientArea.left + 150;
m_GismoOrigon.y = clientArea.top + 460;
//OutputDebugString( "Dillermand\n" );
dlgProcCounter += 1;
switch ( msg )
{
case WM_INITDIALOG:
m_FPSCount = GetDlgItem( hwnd, IDC_STATIC_FPS );
if ( !m_FPSCount ) MessageBox( NULL, "ghFPSCount", "DAMN", MB_OK );
m_CamPosX = GetDlgItem( hwnd, IDC_CAMPOSX );
if ( !m_CamPosX ) MessageBox( NULL, "ghCamPosX", "DAMN", MB_OK );
m_CamPosY = GetDlgItem( hwnd, IDC_CAMPOSY );
if ( !m_CamPosY ) MessageBox( NULL, "ghCamPosY", "DAMN", MB_OK );
m_CamPosZ = GetDlgItem( hwnd, IDC_CAMPOSZ );
if ( !m_CamPosZ ) MessageBox( NULL, "ghCamPosZ", "DAMN", MB_OK );
m_hStatusMessages = GetDlgItem( hwnd, IDSTATUS_PROGMSG );
if ( !m_hStatusMessages ) MessageBox( NULL, "ghStatusMessages", "DAMN", MB_OK );
else
{
SetParent( m_hStatusMessages, hwnd );
}
m_RunButton = GetDlgItem( hwnd, IDCSTATUS_RUN_BTN );
if ( !m_RunButton ) MessageBox( NULL, "ghRunButton ", "DAMN", MB_OK );
m_PauseButton = GetDlgItem( hwnd, IDSTATUS_PAUSE_BTN );
if ( !m_PauseButton ) MessageBox( NULL, "ghPauseButton", "DAMN", MB_OK );
SetWindowText( m_CamPosX, "0" );
SetWindowText( m_CamPosY, "0" );
SetWindowText( m_CamPosZ, "0" );
return TRUE;
case WM_PAINT:
hdc = BeginPaint( hwnd, &ps );
SelectObject( hdc, brush );
SelectObject( hdc, blackPen );
Ellipse( hdc, m_GismoOrigon.x - gizmoRadius, m_GismoOrigon.y - gizmoRadius, m_GismoOrigon.x + gizmoRadius, m_GismoOrigon.y + gizmoRadius ) ;
EndPaint( hwnd, &ps );
return TRUE;
case WM_COMMAND:
return TRUE;
case WM_NOTIFY:
return TRUE;
case WM_CTLCOLORSTATIC:
return TRUE;
case WM_TIMER:
return TRUE;
case WM_DESTROY:
if ( MessageBox( hwnd, "Exit Program?", "Do Not Want!", MB_YESNO ) == IDYES )
{
PostQuitMessage( 0 );
}
else ShowWindow(m_StatusHwnd, true );
return TRUE;
case WM_CLOSE:
DestroyWindow( m_StatusHwnd );
return TRUE;
default:
string s = std::to_string( dlgProcCounter ) + " Unhandled Dlg message: " + std::to_string( msg ) + "\n";
OutputDebugString( s.c_str( ) );
return (INT_PTR)FALSE;
}
return FALSE;
}
Your dialog procedure is creating two GDI objects, a brush and pen, every time it's called. It never destroys these objects. By default there's a 10,000 per process limit on GDI objects. Once you reach that limit the calls to create the objects will fail. Your code will then try to draw using invalid handle values, making it appear that your window has frozen.
The solution is to only create the objects once when handling the WM_INITDIALOG message. Also always check the return value of the functions you call for errors. If you had checked the return values to CreateSolidBrush and CreatePen you potentially could have figured this out earlier.
On Code::Blocks 13.12, I used the wizard to create a DX9 project by starting a new project. I specified the DX folder and it doesn't complain. An auto-generated .cpp appears and it's set to GUI application, file is not set to read-only mode, and I hit compile:
||=== Build: Debug in xxxxxxxx (compiler: GNU GCC Compiler) ===|
c:\program files\codeblocks\mingw\bin..\lib\gcc\mingw32\4.7.1......\libmingw32.a(main.o):main.c:(.text.startup+0xa7)||undefined reference to `WinMain#16'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 2 second(s)) ===|
Here's the full code that's auto-generated:
#include <windows.h>
#include <d3d9.h>
#define NOMINMAX
LPDIRECT3D9 g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Our rendering device
HRESULT InitD3D( HWND hWnd )
{
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
return S_OK;
}
VOID Cleanup()
{
if( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
}
VOID Render()
{
if( NULL == g_pd3dDevice )
return;
// Clear the backbuffer to a blue color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 255 ), 1.0f, 0 );
// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// Rendering of scene objects can happen here
// End the scene
g_pd3dDevice->EndScene();
}
// Present the backbuffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
Render();
ValidateRect( hWnd, NULL );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
{
// Register the window class
WNDCLASSEX wc =
{
sizeof( WNDCLASSEX ), CS_CLASSDC, MsgProc, 0, 0,
GetModuleHandle( NULL ), NULL, NULL, NULL, NULL,
"D3D Tutorial", NULL
};
RegisterClassEx( &wc );
// Create the application's window
HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 01: CreateDevice",
WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
NULL, NULL, wc.hInstance, NULL );
// Initialize Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// Enter the message loop
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
UnregisterClass( "D3D Tutorial", wc.hInstance );
return 0;
}
Before the same questions are asked before in answers where this may have been solved, here's what's been tried:
1.Restarted Code::Blocks; still gives the same error.
2.Tried GUI and console; still gives the same error.
3.Tried with a blank application; still gives the same error.
4.Tried with a Windows GUI application; still gives the same error.
I am guaranteed that the DX SDK is setup and the runtime is up-to-date and everything else of the related such. Any other suggestions to this issue?
Replace this Microsoft monstrosity:
INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
with this standard C++ code:
int main()
That's it.
Your code appears to already be written for a standard main, e.g. you're using GetModuleHandle( 0 ) instead of the hInst from wWinMain.
If you want UTF-16 encoded process command line, just call GetCommandLine, and possibly CommandLineToArgvW (IIRC) to parse it. MinGW-64 does support wmain, via a special option. But with the two functions mentioned you can implement the wmain support in five to six lines of code, so it doesn't really matter, and I'd rather write the code than using an obscure option.
I'm new to c / c++ programing language and am following an online tutorial about Win32. When I build and compile my project ( MS VS C++ 2010 Express ), i get this error: 'IDD_ABOUT' : undeclared identifier. I'm not sure how to fix this. :(
Main.cpp:
#include <Windows.h>
#define ID_FILE_EXIT 9001
#define ID_HELP_ABOUT 9002
const char g_szClassName[] = "myWindowClass";
BOOL CALLBACK AboutDlgProc( HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam )
{
switch( Message )
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case IDOK:
EndDialog( hwnd, IDOK );
break;
case IDCANCEL:
EndDialog( hwnd, IDCANCEL );
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_CREATE:
{
HMENU hMenu, hSubMenu;
HICON hIcon, hIconSm;
hMenu = CreateMenu();
hSubMenu = CreatePopupMenu();
AppendMenu( hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit" );
AppendMenu( hMenu, MF_STRING | MF_POPUP, ( UINT )hSubMenu, "&File" );
hSubMenu = CreatePopupMenu();
AppendMenu( hSubMenu, MF_STRING, ID_HELP_ABOUT, "&About" );
AppendMenu( hMenu, MF_STRING | MF_POPUP, ( UINT )hSubMenu, "&Help" );
SetMenu( hwnd, hMenu );
hIcon = ( HICON )LoadImage( NULL, "menu_one.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE );
if( hIcon )
SendMessage( hwnd, WM_SETICON, ICON_BIG, ( LPARAM )hIcon );
else
MessageBox( hwnd, "Could not load large icon!", "ERROR!", MB_OK | MB_ICONERROR );
hIconSm = ( HICON )LoadImage( NULL, "menu_one.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE );
if( hIconSm )
SendMessage( hwnd, WM_SETICON, ICON_SMALL, ( LPARAM )hIconSm );
else
MessageBox( hwnd, "Could not load small icon!", "ERROR!", MB_OK | MB_ICONERROR );
}
break;
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case ID_FILE_EXIT:
PostMessage( hwnd, WM_CLOSE, 0, 0 );
break;
case ID_HELP_ABOUT:
{
int ret = DialogBox( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDD_ABOUT ), hwnd, AboutDlgProc );
if( ret == IDOK )
MessageBox( hwnd, "Dialog exited with IDOK.", "Notice", MB_OK | MB_ICONINFORMATION );
else if( ret == IDCANCEL )
MessageBox( hwnd, "Dialog exited with IDCANCEL.", "Notice", MB_OK | MB_ICONINFORMATION );
else if( ret == -1 )
MessageBox( hwnd, "Dialog failed!", "Error", MB_OK | MB_ICONINFORMATION );
}
break;
}
break;
case WM_LBUTTONDOWN:
break;
case WM_CLOSE:
DestroyWindow( hwnd );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hwnd, msg, wParam, lParam );
}
return 0;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
WNDCLASSEX wc;
HWND hwnd;
MSG msg;
// Step 1: Registering the Window Class
wc.cbSize = sizeof( WNDCLASSEX );
wc.style = 1;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = NULL;
if( !RegisterClassEx( &wc ) )
{
MessageBox( NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK );
return 0;
}
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"The title of my window",
WS_OVERLAPPEDWINDOW,
500, 200, 800, 600,
NULL, NULL, hInstance, NULL );
if( hwnd == NULL )
{
MessageBox( NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK );
return 0;
}
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );
while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam;
}
Resource.rc:
#include <Windows.h>
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
IDD_ABOUT DIALOG DISCARDABLE 0, 0, 239, 66
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "My About Box"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "&OK",IDOK,174,18,50,14
PUSHBUTTON "&Cancel",IDCANCEL,174,35,50,14
GROUPBOX "About this program...",IDC_STATIC,7,7,225,52
CTEXT "An example program showing how to use Dialog Boxes\r\n\r\nby theForger",IDC_STATIC,16,18,144,33
END
I have a feeling that Visual Studio Express doesn't include a proper resource editor that auto-generates resource includes, so I'm guessing you've created the .rc file manually. If so, you probably just need to define the symbol. Create an include file called resource.h and add this line to it:
#define IDD_ABOUT 100
Then include it at the top of your .cpp and .rc files:
#include <Windows.h>
#include "resource.h" // add this line
The windows headers define generic certain resource IDs (IDOK, IDCANCEL, IDC_STATIC, etc) but for anything else you'll need to add your own symbol. The values don't really matter - any number up to 65534 is ok as long as it doesn't clash with any other ID in use in the same "scope" (e.g. two controls in the one dialog should have different IDs, but you can re-use the same ID in another dialog).
I want to implement a console inside my C++ application. Like ftp for example. Or (IIRC) sql, once you've connected to a Server.
Does anybody know a library which implements this? Ideally with auto-completion and such? My searches for this only come up with "how to build a C++ console application", which I do know how to do.
GNU Readline implements the features you want. If filename auto-completion is not the sort you need, use a custom auto-complete routine.
For Windows: Use AllocConsole() to attach a text console to your GUI app and freopen( "CON", "w", stdout ) ; to redirect and printf() to output text.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681944(v=vs.85).aspx
Sample code:
#include <stdio.h>
#include <stdlib.h>
// Function prototypes.
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam );
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow );
// In a C++ Windows app, the starting point is WinMain().
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow )
{
// these next few lines create and attach a console
// to this process. note that each process is only allowed one console.
AllocConsole() ;
freopen( "CON", "w", stdout ) ;
printf("HELLO!!! I AM THE CONSOLE!\n" ) ;
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof( WNDCLASSEX ) ;
wc.cbClsExtra = 0; // ignore for now
wc.cbWndExtra = 0; // ignore for now
wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = TEXT(" ");
wc.lpszMenuName = 0;
wc.style = CS_HREDRAW | CS_VREDRAW; // Redraw the window
RegisterClassEx( &wc );
HWND hwnd = CreateWindowEx( 0, TEXT(" "), TEXT("window's title!"), WS_OVERLAPPEDWINDOW, 10, 10, 200, 200, NULL, NULL, hInstance, NULL );
ShowWindow(hwnd, iCmdShow );
UpdateWindow(hwnd);
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam; // return from WinMain
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam )
{
switch( message )
{
case WM_CREATE:
// upon creation, let the speaker beep at 50Hz, for 10ms.
Beep( 50, 10 );
printf("HELLO!!! I AM THE CONSOLE!\n" ) ;
return 0;
break;
case WM_PAINT:
{
// we would place our Windows painting code here.
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint( hwnd, &ps );
// draw a circle and a 2 squares
Ellipse( hdc, 20, 20, 160, 160 );
Rectangle( hdc, 50, 50, 90, 90 );
Rectangle( hdc, 100, 50, 140, 90 );
printf("HELLO!!! I AM THE CONSOLE!\n" ) ;
EndPaint( hwnd, &ps );
}
return 0;
break;
case WM_LBUTTONDOWN:
printf("STOP POKING MEEE!!!\n") ;
break;
case WM_DESTROY:
PostQuitMessage( 0 ) ;
return 0;
break;
}
return DefWindowProc( hwnd, message, wparam, lparam );
}
If you want also autocomplete you could
check the example of linenoise (a lightweight readline alternative).
Basically you have to parse the Userinput Line in a Loop.
Example for a very basic CommadLineInterface :
show prompt and read input in a while loop,
call something like parseLine() on \n
split the Line in Tokens by at least Space (then ;) take the first String as Command cmd and the rest as args.
call dispatch(cmd, args);