ShowWindow within WM_CREATE - c

The way I see it, one use of a Window Procedure's WM_CREATE message is to relieve the caller of the burden of executing static code at window initialization. My window is to execute some code in the WM_CREATE message, including the ShowWindow function. I also want the ShowWindow to behave properly according to the nCmdShow parameter in WinMain. So here is pseudo-code to show how I have things set up:
int g_nCmdShow;
WinMain(..., int nCmdShow)
{
g_nCmdShow = nCmdShow;
...
CreateWindow(..., WM_OVERLAPPEDWINDOW, ...)
...
}
WndProc()
{
...
WM_CREATE:
...
ShowWindow(hWnd, g_nCmdShow);
...
...
}
So I set up the program to run Minimized (using Windows XP I created a shortcut to the .exe, and set up the properties of it accordingly), and it displays on the taskbar minimized but it does not restore when I click on it. Likewise, if I run it Maximized, it does not behave correctly when I click the maximize button (to un-maximize it).
What is the correct way to use nCmdShow-compatible ShowWindow within the WM_CREATE message?

The problem is that the window's restore bounds get affected by this. They become the size of the window after WM_CREATE returns. You would have to modify your code to re-establish those restore bounds:
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 300, 200, NULL, NULL, hInstance, NULL);
WINDOWPLACEMENT wp;
GetWindowPlacement(hWnd, &wp); // <= Note wp.rcNormalPosition after this call!
RECT rc = {100, 100, 400, 300};
wp.rcNormalPosition = rc;
SetWindowPlacement(hWnd, &wp);
You're not ahead by doing it this way.

If you absolutely have to keep it in the WndProc, try
case WM_CREATE:
PostMessage(hwnd,WM_APP,0,0);
break;
case WM_APP:
ShowWindow(hwnd,SW_SHOW);
break;
But if this is so important, why not just have a helper function that creates the window and calls ShowWindow? MyWindowType_Create(...) etc

Having the window show itself, or set its own position, is a bad design choice that goes against how WinAPI was meant to be used. The right place to do these decisions is in the code that creates the window. It's already reflected in the fact that the CreateWindow is responsible for the initial window placement and WS_VISIBLE style.
In your code you should call ShowWindow in WinMain, which will also eliminate the need for the g_nCmdShow global:
WinMain(..., int nCmdShow)
{
...
hWnd = CreateWindow(..., WM_OVERLAPPEDWINDOW, ...)
ShowWindow(hWnd, nCmdShow);
...
}
WndProc()
{
...
WM_CREATE:
...
...
}
WM_CREATE is rather responsible for initializing window-class specific behavior. Creating child windows or initializing internal data structures and the cbWndExtra slots are examples of that (e.g. think of implementing a list-box).

Can you handle WM_WINDOWPOSCHANGED and override the window size the first time the window is restored? Use GetWindowPlacement to find out if the window got restored.

Related

gtk_container_add function crashes

I have the following line in my GTK code:
gtk_container_add(GTK_CONTAINER(main_wind_ob->stack),
GTK_WIDGET(main_wind_ob->product_ob->swindow));
Where main_wind_on->stack is a GtkStack acquired this way
main_wind_ob->stack = GTK_STACK(
gtk_builder_get_object (
main_wind_ob->builder,
"stack"
)
);
Where main_wind_ob->builder is a GtkBuilder object associated with a .ui file where a GtkStack container is declared with the ID stack.
main_wind_ob->product_ob->swindow is a GtkScrolledWindow acquired like this:
main_wind_ob->product_ob->swindow =
gtk_scrolled_window_new(NULL, NULL);
I know neither main_wind_ob->product_ob->swindow or main_wind_ob->stack are not null as I've debugged and checked them.
What I wanted to do was make swindow be the child of the stack, but it just crashes when it reaches the gtk_container_add function call. I am not really sure why. Let me know if there is any extra details I can add to the post, thanks.

Win32 edit control default text

(NB: This is probably more of a programming style / architecture question)
When the main window is created (but not yet shown), my window procedure receives WM_CREATE; this is where I call CreateWindow for the edit control:
case WM_CREATE:
hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("edit"), L"Default text",
WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
10, 10, 150, 24, hWnd, (HMENU)ID_EDIT,
hInst, NULL);
break;
and as expected "Default text" shows up in the edit control.
I know I can also use SendMessage or SetWindowText.
So, I have three API calls to do what I want - which one should I be using?
best,
Chris
If it is easy and convenient to set the text in CreateWindowEx, then do so.
If, for some reason, it is not convenient, then use SetWindowText.
In this case you probably don't want to use L"Default Text" as the default text in CreateWindowEx.
Since lpWindowName is optional, you may pass NULL to leave it blank.
Alternatively, you might use something which makes more sense for your application, such as L"(Loading...)".

Processing WM_PAINT

I have read many examples on the internet but I'm still stuck. I'm trying to process the WM_PAINT message sent to my application.
In my application, I always draw in the same DC, named g_hDC. It works perfectly. When WM_PAINT is received, I just try to draw the content of my g_hDC into the DC returned by BeginPaint. I guess g_hDC contains the last bitmap that I drawn. So I just want to restore it.
case WM_PAINT:
PAINTSTRUCT ps;
int ret;
HDC compatDC;
HDC currentDC;
HDC paintDC;
HBITMAP compatBitmap;
HGDIOBJ oldBitmap;
paintDC = BeginPaint(g_hWnd, &ps);
currentDC = GetDC(g_hWnd);
compatDC = CreateCompatibleDC(paintDC);
compatBitmap=CreateCompatibleBitmap(paintDC, CONFIG_WINDOW_WIDTH, CONFIG_WINDOW_HEIGHT);
oldBitmap=SelectObject(compatDC, compatBitmap);
ret = BitBlt(compatDC,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top,
currentDC,
ps.rcPaint.left,
ps.rcPaint.top,
SRCCOPY);
ret = BitBlt(paintDC,
ps.rcPaint.left,
ps.rcPaint.top,
ps.rcPaint.right - ps.rcPaint.left,
ps.rcPaint.bottom - ps.rcPaint.top,
compatDC,
ps.rcPaint.left,
ps.rcPaint.top,
SRCCOPY);
DeleteObject(SelectObject(compatDC, oldBitmap));
DeleteDC(compatDC);
DeleteDC(currentDC);
EndPaint(g_hWnd, &ps);
break;
But it just draws a white rectangle ... I tried many possibilities and nothing works. Can you please help me?
There are a number of things you are doing wrong.
First, your saving g_hDC is relying on an implementation detail: you notice that the pointers are the same, and thus save the pointer. This may work in the short term for a variety of reasons related to optimization on GDI's part (for instance, there is DC cache), but will stop working eventually, when it is least convenient. Or you may be tempted to use the DC pointer when you don't have the DC, and will scribble over something else (or fail to do so due to GDI object thread affinity).
The correct way to access the DC of a window outside its WM_PAINT is by calling GetDC(hwnd).
CreateCompatibleDC() creates an in-memory DC compatible with hdc. Drawing to compatDC is not enough to draw to hdc; you need to draw back to hdc after you draw to compatDC. For your case, you will need to have two BitBlt() calls; the second one will blit back from compatDC onto hdc. See this sample code for details.
You cannot DeleteObject() a bitmap while you have it selected into a DC. Your SelectObject(compatDC, oldBitmap) call needs to come before DeleteObject(compatBitmap). (This is what i486 was trying to get at in his answer.)
(I'm sure this answer is misleading or incomplete in some places; please let me know if it is.)
Use this to delete bitmat: DeleteObject( SelectObject(compatDC,oldBitmap) ); - without DeleteBitmap on prev line. SelectObject returns current (old) selection as return value - and you delete it. In your case you are trying to delete still selected bitmap.
PS: I don't see CreateCompatibleDC - where you are creating compatDC? Add compatDC = CreateCompatibleDC( hdc ); before CreateCompatibleBitmap.

Win32 Make menu non-global but accessible by all childprocs

I'm making a paint program where I have MDI and multiple dialogs that need to access menu items.
Right now, I stick the menu in global so everything can see it. However, I'd like to use
typedef struct datastruct
{
DWORD currentTool;
POINT start, end;
DWORD lastShape;
HINSTANCE hInst;
HMENU hMenuInit, hMenuHello;
HMENU hMenuInitWindow, hMenuHelloWindow;
}
DATA, *PDATA;
This struct, along with PDATA pdata = 0, pglobaldata=0;
To access the following items:
HINSTANCE hInst;
HMENU hMenuInit, hMenu;
HMENU hMenuInitWindow, hMenuWindow;
For example, when I need to access hMenuInit in a MDI child window, I would do this: pglobaldata->hMenuInit and I'd be able to access the same one WinMain is using: hMenuInit = LoadMenu (hInstance, MAKEINTRESOURCE(IDR_MENU));
How can I accomplish this?
Having issues pasting all the code here. I've put it on pastebin: http://pastebin.com/z9tKSwhG
It sounds like you want to associate some instance specific data with the window. You do that by specifying the size of the extra data in the cbWndExtra member of WNDCLASSEX when you register the window class. And then access that extra data call GetWindowLongPtr and SetWindowLongPtr passing 0 for nIndex. That index identifies the slow where your instance data is stored.

simple c programming gui

I developed the steam table equation solver in C language...but the inputing the values in black screen console is boring.
So I strictly wanted to create simple GUI in C.
I searched for hello world codes, all were pretty long. But this was the only one I understood.
#include <windows.h>
int main()
{
MessageBoxA( NULL, "Hello World!", "Hello", MB_OK );
}
By using a gui builder for C, i got this code, now I was thinking how to scan values from TEXTBOX1 and TEXTBOX2 on Clicking of COMMANDBUTTON1 and display the output in TEXTBOX3?
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "hello.auto.h"
HWND hwnd_Label1, hwnd_Label2, hwnd_TextBox1, hwnd_TextBox2, hwnd_CommandButton1,
hwnd_TextBox3;
HFONT MSSansSerif_8pt;
void CreateChildWindows(HWND hwndMainWindow, HINSTANCE hInstance)
{
InitCommonControls();
MSSansSerif_8pt = CreateFont(-11,0,0,0,FW_NORMAL,0,0,0,0,0,0,0,0,"MS Sans Serif");
hwnd_Label1 = CreateWindowEx(0, "Static", "Pressure",
WS_CHILD | WS_VISIBLE,
11, 55, 95, 38, hwndMainWindow,
(HMENU)Label1, hInstance, NULL);
SetWindowFont(hwnd_Label1, MSSansSerif_8pt, TRUE);
hwnd_Label2 = CreateWindowEx(0, "Static", "Temperature",
WS_CHILD | WS_VISIBLE,
11, 110, 95, 38, hwndMainWindow,
(HMENU)Label2, hInstance, NULL);
SetWindowFont(hwnd_Label2, MSSansSerif_8pt, TRUE);
hwnd_TextBox1 = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit" , NULL,
WS_CHILD | ES_WANTRETURN | WS_VISIBLE,
187, 55, 83, 35, hwndMainWindow,
(HMENU)TextBox1, hInstance, NULL);
SetWindowFont(hwnd_TextBox1, MSSansSerif_8pt, TRUE);
hwnd_TextBox2 = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit" , NULL,
WS_CHILD | ES_WANTRETURN | WS_VISIBLE,
187, 99, 83, 35, hwndMainWindow,
(HMENU)TextBox2, hInstance, NULL);
SetWindowFont(hwnd_TextBox2, MSSansSerif_8pt, TRUE);
hwnd_CommandButton1 = CreateWindowEx(0, "Button", "CommandButton1",
WS_CHILD | BS_MULTILINE | BS_PUSHBUTTON | WS_VISIBLE,
308, 77, 117, 52, hwndMainWindow,
(HMENU)CommandButton1, hInstance, NULL);
SetWindowFont(hwnd_CommandButton1, MSSansSerif_8pt, TRUE);
hwnd_TextBox3 = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit" , NULL,
WS_CHILD | ES_WANTRETURN | WS_VISIBLE,
66, 220, 385, 35, hwndMainWindow,
(HMENU)TextBox3, hInstance, NULL);
SetWindowFont(hwnd_TextBox3, MSSansSerif_8pt, TRUE);
return;
}
HWND GetItem(int nIDDlgItem)
{
switch(nIDDlgItem)
{
case -1:
return GetParent(hwnd_Label1);
case Label1:
return hwnd_Label1;
case Label2:
return hwnd_Label2;
case TextBox1:
return hwnd_TextBox1;
case TextBox2:
return hwnd_TextBox2;
case CommandButton1:
return hwnd_CommandButton1;
case TextBox3:
return hwnd_TextBox3;
default: return NULL;
}
}
void Form_Unload(HWND hMainWnd)
{
DeleteFont(MSSansSerif_8pt);
return;
}
I tried many times, but failed. Even if you people give me links of good sites, then I will be greatful.
You're looking for a good book on Win32 API programming using C. And you're in luck, there's a great book that pretty much everyone uses to learn it. It's written by Charles Petzold, and it's called (aptly enough) Programming Windows. You want the 5th edition, which is the most recent version that discusses Win32 programming.
There are also various tutorials available online if you search for "Win32 programming". However, a number of them contain some errors and misunderstandings (like the difference between ANSI and Unicode strings), and the good ones are rather short and incomplete. You won't learn everything you need to know to write a non-trivial program from online tutorials, but you should be able to get something really simple up on the screen. This one by theForger is one I've seen recommended many times.
Be warned, though, that writing GUI code (especially at such a low level) tends to be a lot more verbose than simply getting text onto the screen for a console program. You're going to end up writing a bunch of code that is used only to make the GUI work and has nothing to do with the logic of your program. It's much easier if you learn the C language first, and that's best done through simple console-type, text-only programs.
As for your specific question, you've created three textbox controls on the screen, named hwnd_TextBoxX, where X is a number between 1 and 3. As you probably already know, hwnd indicates a handle to a window (wnd), and so those variables hold handles to the textbox windows.
The Win32 API provides a GetWindowText function, which you can use to retrieve the text from a particular window. You pass it a handle to the desired window (hWnd), a pointer to a character buffer, and an integer value indicating the length of your buffer. Already, the ugly nature of the C language crops up—you have to understand how strings work in C in order to call the function correctly.
Once you've retrieved the string displayed in one of the textboxes, you can display it in another textbox window using the similar SetWindowText function, which takes only the window handle (hWnd) and a pointer to the buffer containing the string.
The code would look something like this:
// Get the text displayed in textbox 1
TCHAR szBuffer[100];
GetWindowText(hwnd_TextBox1, szBuffer, 100);
// Display that text in textbox 3
SetWindowText(hwnd_TextBox3, szBuffer);
To do this in response to a click on a button, you'll need to learn about the Win32 equivalent of "events"—window messages. Child windows, like button controls, send notification messages to their parent window (i.e., a dialog) when something potentially interesting happens, like the user clicks on them.
In particular, a button control sends its parent a BN_CLICKED notification through the WM_COMMAND message. By handling the WM_COMMAND message in your main window's window procedure (WndProc) method, you can check that the lParam parameter matches your button control's window handle (hWnd) and that the HIWORD(wParam) matches the BN_CLICKED notification code.
You definitely need a good book that contains step-by-step sample code for that one. It's a bit too difficult to explain thoroughly in a Stack Overflow answer.
Writing a GUI application using just the Win32 API is somewhat fun, but also tedious. It is much easier to use a framework of some sort. This doesn't mean it's impossible though. Here's a quick overview of how you do it.
First, you replace the main routine with WinMain. This routine is the new entry point of your application. It will be responsible for creating the windows and setting up a message dispatch loop.
Notice that I said "windows" and not just a "window". In WinAPI, every "control" you see on the "form" is a "window". The "form" itself is a window also. Every window has a window handle (HWND). You can make an application window using CreateWindow. This gets you a window handle that you can pass to the CreateChildWindows function that the GUI builder made for you. This will add child windows (the controls) to the application window.
Now you need to program all these windows. You do that by processing messages. When you create your application window, you need to supply a window procedure. This procedure will respond to messages as they come in. For example, a button click results in a WM_COMMAND message that you will have to handle. The last thing WinMain does is start a message processing loop that repeatedly calls your WndProc for any incoming message.
This will all start to make sense once you work through the tutorial linked in the other answer. Then you will probably get tired of this and pick up a GUI toolkit :)

Resources